Dax Raad 8 месяцев назад
Родитель
Сommit
d334ead84a

+ 83 - 18
packages/opencode/src/index.ts

@@ -76,16 +76,90 @@ cli
       const session = options.session
         ? await Session.get(options.session)
         : await Session.create()
-      console.log("Session:", session.id)
 
-      Bus.subscribe(Message.Event.Updated, async () => {
-        console.log("Thinking...")
-      })
+      const styles = {
+        TEXT_HIGHLIGHT: "\x1b[96m",
+        TEXT_HIGHLIGHT_BOLD: "\x1b[96m\x1b[1m",
+        TEXT_DIM: "\x1b[90m",
+        TEXT_DIM_BOLD: "\x1b[90m\x1b[1m",
+        TEXT_NORMAL: "\x1b[0m",
+        TEXT_NORMAL_BOLD: "\x1b[1m",
+        TEXT_WARNING: "\x1b[93m",
+        TEXT_WARNING_BOLD: "\x1b[93m\x1b[1m",
+        TEXT_DANGER: "\x1b[91m",
+        TEXT_DANGER_BOLD: "\x1b[91m\x1b[1m",
+        TEXT_SUCCESS: "\x1b[92m",
+        TEXT_SUCCESS_BOLD: "\x1b[92m\x1b[1m",
+        TEXT_INFO: "\x1b[94m",
+        TEXT_INFO_BOLD: "\x1b[94m\x1b[1m",
+      }
+
+      let isEmpty = false
+      function stderr(...message: string[]) {
+        isEmpty = true
+        Bun.stderr.write(message.join(" "))
+        Bun.stderr.write("\n")
+      }
+
+      function empty() {
+        stderr("" + styles.TEXT_NORMAL)
+        isEmpty = true
+      }
+
+      stderr(styles.TEXT_HIGHLIGHT_BOLD + "◍  OpenCode", version)
+      empty()
+      stderr(styles.TEXT_NORMAL_BOLD + "> ", message.join(" "))
+      empty()
+
+      function printEvent(color: string, type: string, title: string) {
+        stderr(
+          color + `|`,
+          styles.TEXT_NORMAL + styles.TEXT_DIM + ` ${type.padEnd(7, " ")}`,
+          "",
+          styles.TEXT_NORMAL + title,
+        )
+      }
+
+      Bus.subscribe(Message.Event.PartUpdated, async (message) => {
+        const part = message.properties.part
+        if (
+          part.type === "tool-invocation" &&
+          part.toolInvocation.state === "result"
+        ) {
+          if (part.toolInvocation.toolName === "opencode_todowrite") return
+          const messages = await Session.messages(session.id)
+          const metadata =
+            messages[messages.length - 1].metadata.tool[
+              part.toolInvocation.toolCallId
+            ]
+          const args = part.toolInvocation.args as any
+          const tool = part.toolInvocation.toolName
 
-      const unsub = Bus.subscribe(Session.Event.Updated, async (message) => {
-        if (message.properties.info.share?.url)
-          console.log("Share:", message.properties.info.share.url)
-        unsub()
+          if (tool === "opencode_edit")
+            printEvent(styles.TEXT_SUCCESS_BOLD, "Edit", args.filePath)
+          if (tool === "opencode_bash")
+            printEvent(styles.TEXT_WARNING_BOLD, "Execute", args.command)
+          if (tool === "opencode_read")
+            printEvent(styles.TEXT_INFO_BOLD, "Read", args.filePath)
+          if (tool === "opencode_write")
+            printEvent(styles.TEXT_SUCCESS_BOLD, "Create", args.filePath)
+          if (tool === "opencode_glob")
+            printEvent(
+              styles.TEXT_INFO_BOLD,
+              "Glob",
+              args.pattern + (args.path ? " in " + args.path : ""),
+            )
+        }
+
+        if (part.type === "text") {
+          if (part.text.includes("\n")) {
+            empty()
+            stderr(part.text)
+            empty()
+            return
+          }
+          printEvent(styles.TEXT_NORMAL_BOLD, "Text", part.text)
+        }
       })
 
       const { providerID, modelID } = await Provider.defaultModel()
@@ -100,16 +174,7 @@ cli
           },
         ],
       })
-
-      for (const part of result.parts) {
-        if (part.type === "text") {
-          console.log("opencode:", part.text)
-        }
-      }
-      console.log({
-        cost: result.metadata.assistant?.cost,
-        tokens: result.metadata.assistant?.tokens,
-      })
+      empty()
     })
   })
 

+ 11 - 0
packages/opencode/src/server/server.ts

@@ -20,6 +20,17 @@ export namespace Server {
     const app = new Hono()
 
     const result = app
+      .onError((err, c) => {
+        log.error("error", err)
+        return c.json(
+          {
+            error: err.toString(),
+          },
+          {
+            status: 500,
+          },
+        )
+      })
       .use((c, next) => {
         log.info("request", {
           method: c.req.method,

+ 15 - 2
packages/opencode/src/session/index.ts

@@ -384,6 +384,11 @@ ${app.git ? await ListTool.execute({ path: app.path.cwd }, { sessionID: input.se
         assistant.cost = usage.cost
         assistant.tokens = usage.tokens
         await updateMessage(next)
+        if (text) {
+          Bus.publish(Message.Event.PartUpdated, {
+            part: text,
+          })
+        }
         text = undefined
       },
       async onChunk(input) {
@@ -397,8 +402,7 @@ ${app.git ? await ListTool.execute({ path: app.path.cwd }, { sessionID: input.se
               text = value
               next.parts.push(value)
               break
-            }
-            text.text += value.text
+            } else text.text += value.text
             break
 
           case "tool-call":
@@ -411,6 +415,9 @@ ${app.git ? await ListTool.execute({ path: app.path.cwd }, { sessionID: input.se
                 args: value.args as any,
               },
             })
+            Bus.publish(Message.Event.PartUpdated, {
+              part: next.parts[next.parts.length - 1],
+            })
             break
 
           case "tool-call-streaming-start":
@@ -423,6 +430,9 @@ ${app.git ? await ListTool.execute({ path: app.path.cwd }, { sessionID: input.se
                 args: {},
               },
             })
+            Bus.publish(Message.Event.PartUpdated, {
+              part: next.parts[next.parts.length - 1],
+            })
             break
 
           case "tool-call-delta":
@@ -442,6 +452,9 @@ ${app.git ? await ListTool.execute({ path: app.path.cwd }, { sessionID: input.se
                 state: "result",
                 result: value.result as string,
               }
+              Bus.publish(Message.Event.PartUpdated, {
+                part: match,
+              })
             }
             break
 

+ 1 - 0
packages/opencode/src/session/message.ts

@@ -168,5 +168,6 @@ export namespace Message {
         info: Info,
       }),
     ),
+    PartUpdated: Bus.event("message.part.updated", z.object({ part: Part })),
   }
 }