summaryrefslogtreecommitdiffhomepage
path: root/packages
diff options
context:
space:
mode:
authorDax Raad <[email protected]>2025-08-13 13:28:51 -0400
committerDax Raad <[email protected]>2025-08-13 13:29:06 -0400
commit7505fa61b9caa17f1ef358961d7e46beb3276ca9 (patch)
treef4bfe1eda5a4daf44b1f7a1a5e09a5077ea7010c /packages
parent77bb5af09235fcdd57c58a31921d4ea9a1415144 (diff)
downloadopencode-7505fa61b9caa17f1ef358961d7e46beb3276ca9.tar.gz
opencode-7505fa61b9caa17f1ef358961d7e46beb3276ca9.zip
wip: bash commands
Diffstat (limited to 'packages')
-rw-r--r--packages/opencode/src/server/server.ts30
-rw-r--r--packages/opencode/src/session/index.ts92
2 files changed, 122 insertions, 0 deletions
diff --git a/packages/opencode/src/server/server.ts b/packages/opencode/src/server/server.ts
index 79be29d28..ec17ff03f 100644
--- a/packages/opencode/src/server/server.ts
+++ b/packages/opencode/src/server/server.ts
@@ -593,6 +593,36 @@ export namespace Server {
},
)
.post(
+ "/session/:id/command",
+ describeRoute({
+ description: "Run a bash command",
+ operationId: "session.chat",
+ responses: {
+ 200: {
+ description: "Created message",
+ content: {
+ "application/json": {
+ schema: resolver(MessageV2.Assistant),
+ },
+ },
+ },
+ },
+ }),
+ zValidator(
+ "param",
+ z.object({
+ id: z.string().openapi({ description: "Session ID" }),
+ }),
+ ),
+ zValidator("json", Session.CommandInput.omit({ sessionID: true })),
+ async (c) => {
+ const sessionID = c.req.valid("param").id
+ const body = c.req.valid("json")
+ const msg = await Session.command({ ...body, sessionID })
+ return c.json(msg)
+ },
+ )
+ .post(
"/session/:id/revert",
describeRoute({
description: "Revert a message",
diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts
index c0ab7c7db..0957d4057 100644
--- a/packages/opencode/src/session/index.ts
+++ b/packages/opencode/src/session/index.ts
@@ -43,6 +43,8 @@ import { Plugin } from "../plugin"
import { Agent } from "../agent/agent"
import { Permission } from "../permission"
import { Wildcard } from "../util/wildcard"
+import { BashTool } from "../tool/bash"
+import { ulid } from "ulid"
export namespace Session {
const log = Log.create({ service: "session" })
@@ -997,6 +999,96 @@ export namespace Session {
return result
}
+ export const CommandInput = z.object({
+ sessionID: Identifier.schema("session"),
+ agent: z.string(),
+ command: z.string(),
+ })
+ export type CommandInput = z.infer<typeof CommandInput>
+ export async function command(input: CommandInput) {
+ using abort = lock(input.sessionID)
+ const msg: MessageV2.Assistant = {
+ id: Identifier.ascending("message"),
+ sessionID: input.sessionID,
+ system: [],
+ mode: input.agent,
+ cost: 0,
+ path: {
+ cwd: App.info().path.cwd,
+ root: App.info().path.root,
+ },
+ time: {
+ created: Date.now(),
+ },
+ role: "assistant",
+ tokens: {
+ input: 0,
+ output: 0,
+ reasoning: 0,
+ cache: { read: 0, write: 0 },
+ },
+ modelID: "",
+ providerID: "",
+ }
+ await updateMessage(msg)
+ const part: MessageV2.Part = {
+ type: "tool",
+ id: Identifier.ascending("part"),
+ messageID: msg.id,
+ sessionID: input.sessionID,
+ tool: "bash",
+ callID: ulid(),
+ state: {
+ status: "running",
+ time: {
+ start: Date.now(),
+ },
+ input: {
+ command: input.command,
+ },
+ },
+ }
+ await updatePart(part)
+ const tool = await BashTool.init()
+ const result = await tool.execute(
+ {
+ command: input.command,
+ description: "User command",
+ },
+ {
+ messageID: msg.id,
+ sessionID: input.sessionID,
+ abort: abort.signal,
+ callID: part.callID,
+ agent: input.agent,
+ metadata: async (e) => {
+ if (part.state.status === "running") {
+ part.state.title = e.title
+ part.state.metadata = e.metadata
+ await updatePart(part)
+ }
+ },
+ },
+ )
+ msg.time.completed = Date.now()
+ await updateMessage(msg)
+ if (part.state.status === "running") {
+ part.state = {
+ status: "completed",
+ time: {
+ ...part.state.time,
+ end: Date.now(),
+ },
+ input: part.state.input,
+ title: result.title,
+ metadata: result.metadata,
+ output: result.output,
+ }
+ await updatePart(part)
+ }
+ return { info: msg, parts: [part] }
+ }
+
function createProcessor(assistantMsg: MessageV2.Assistant, model: ModelsDev.Model) {
const toolcalls: Record<string, MessageV2.ToolPart> = {}
let snapshot: string | undefined