opencode-agent[bot] 1 неделя назад
Родитель
Сommit
577139c626

+ 19 - 19
packages/opencode/src/session/prompt.ts

@@ -106,8 +106,7 @@ export namespace SessionPrompt {
       const run = {
         promise: <A, E>(effect: Effect.Effect<A, E>) =>
           Effect.runPromise(effect.pipe(Effect.provide(EffectLogger.layer))),
-        fork: <A, E>(effect: Effect.Effect<A, E>) =>
-          Effect.runFork(effect.pipe(Effect.provide(EffectLogger.layer))),
+        fork: <A, E>(effect: Effect.Effect<A, E>) => Effect.runFork(effect.pipe(Effect.provide(EffectLogger.layer))),
       }
 
       const cancel = Effect.fn("SessionPrompt.cancel")(function* (sessionID: SessionID) {
@@ -622,23 +621,24 @@ NOTE: At any point in time through this workflow you should feel free to ask the
             }),
             Effect.onInterrupt(() =>
               Effect.gen(function* () {
-              taskAbort.abort()
-              assistantMessage.finish = "tool-calls"
-              assistantMessage.time.completed = Date.now()
-              yield* sessions.updateMessage(assistantMessage)
-              if (part.state.status === "running") {
-                yield* sessions.updatePart({
-                  ...part,
-                  state: {
-                    status: "error",
-                    error: "Cancelled",
-                    time: { start: part.state.time.start, end: Date.now() },
-                    metadata: part.state.metadata,
-                    input: part.state.input,
-                  },
-                } satisfies MessageV2.ToolPart)
-              }
-            })),
+                taskAbort.abort()
+                assistantMessage.finish = "tool-calls"
+                assistantMessage.time.completed = Date.now()
+                yield* sessions.updateMessage(assistantMessage)
+                if (part.state.status === "running") {
+                  yield* sessions.updatePart({
+                    ...part,
+                    state: {
+                      status: "error",
+                      error: "Cancelled",
+                      time: { start: part.state.time.start, end: Date.now() },
+                      metadata: part.state.metadata,
+                      input: part.state.input,
+                    },
+                  } satisfies MessageV2.ToolPart)
+                }
+              }),
+            ),
           )
 
         const attachments = result?.attachments?.map((attachment) => ({

+ 6 - 2
packages/opencode/test/tool/apply_patch.test.ts

@@ -11,7 +11,9 @@ import { Bus } from "../../src/bus"
 import { tmpdir } from "../fixture/fixture"
 import { SessionID, MessageID } from "../../src/session/schema"
 
-const runtime = ManagedRuntime.make(Layer.mergeAll(LSP.defaultLayer, AppFileSystem.defaultLayer, Format.defaultLayer, Bus.layer))
+const runtime = ManagedRuntime.make(
+  Layer.mergeAll(LSP.defaultLayer, AppFileSystem.defaultLayer, Format.defaultLayer, Bus.layer),
+)
 
 const baseCtx = {
   sessionID: SessionID.make("ses_test"),
@@ -57,7 +59,9 @@ const makeCtx = () => {
   const ctx: ToolCtx = {
     ...baseCtx,
     ask: (input) =>
-      Effect.sync(() => { calls.push(input) }),
+      Effect.sync(() => {
+        calls.push(input)
+      }),
   }
 
   return { ctx, calls }

+ 348 - 274
packages/opencode/test/tool/bash.test.ts

@@ -132,13 +132,15 @@ describe("tool.bash", () => {
       directory: projectRoot,
       fn: async () => {
         const bash = await initBash()
-        const result = await Effect.runPromise(bash.execute(
-          {
-            command: "echo test",
-            description: "Echo test message",
-          },
-          ctx,
-        ))
+        const result = await Effect.runPromise(
+          bash.execute(
+            {
+              command: "echo test",
+              description: "Echo test message",
+            },
+            ctx,
+          ),
+        )
         expect(result.metadata.exit).toBe(0)
         expect(result.metadata.output).toContain("test")
       },
@@ -154,13 +156,15 @@ describe("tool.bash permissions", () => {
       fn: async () => {
         const bash = await initBash()
         const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
-        await Effect.runPromise(bash.execute(
-          {
-            command: "echo hello",
-            description: "Echo hello",
-          },
-          capture(requests),
-        ))
+        await Effect.runPromise(
+          bash.execute(
+            {
+              command: "echo hello",
+              description: "Echo hello",
+            },
+            capture(requests),
+          ),
+        )
         expect(requests.length).toBe(1)
         expect(requests[0].permission).toBe("bash")
         expect(requests[0].patterns).toContain("echo hello")
@@ -175,13 +179,15 @@ describe("tool.bash permissions", () => {
       fn: async () => {
         const bash = await initBash()
         const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
-        await Effect.runPromise(bash.execute(
-          {
-            command: "echo foo && echo bar",
-            description: "Echo twice",
-          },
-          capture(requests),
-        ))
+        await Effect.runPromise(
+          bash.execute(
+            {
+              command: "echo foo && echo bar",
+              description: "Echo twice",
+            },
+            capture(requests),
+          ),
+        )
         expect(requests.length).toBe(1)
         expect(requests[0].permission).toBe("bash")
         expect(requests[0].patterns).toContain("echo foo")
@@ -199,13 +205,15 @@ describe("tool.bash permissions", () => {
           fn: async () => {
             const bash = await initBash()
             const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
-            await Effect.runPromise(bash.execute(
-              {
-                command: "Write-Host foo; if ($?) { Write-Host bar }",
-                description: "Check PowerShell conditional",
-              },
-              capture(requests),
-            ))
+            await Effect.runPromise(
+              bash.execute(
+                {
+                  command: "Write-Host foo; if ($?) { Write-Host bar }",
+                  description: "Check PowerShell conditional",
+                },
+                capture(requests),
+              ),
+            )
             const bashReq = requests.find((r) => r.permission === "bash")
             expect(bashReq).toBeDefined()
             expect(bashReq!.patterns).toContain("Write-Host foo")
@@ -227,13 +235,15 @@ describe("tool.bash permissions", () => {
         const file = process.platform === "win32" ? `${process.env.WINDIR!.replaceAll("\\", "/")}/*` : "/etc/*"
         const want = process.platform === "win32" ? glob(path.join(process.env.WINDIR!, "*")) : "/etc/*"
         await expect(
-          Effect.runPromise(bash.execute(
-            {
-              command: `cat ${file}`,
-              description: "Read wildcard path",
-            },
-            capture(requests, err),
-          )),
+          Effect.runPromise(
+            bash.execute(
+              {
+                command: `cat ${file}`,
+                description: "Read wildcard path",
+              },
+              capture(requests, err),
+            ),
+          ),
         ).rejects.toThrow(err.message)
         const extDirReq = requests.find((r) => r.permission === "external_directory")
         expect(extDirReq).toBeDefined()
@@ -258,13 +268,15 @@ describe("tool.bash permissions", () => {
               const bash = await initBash()
               const file = path.join(outerTmp.path, "outside.txt").replaceAll("\\", "/")
               const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
-              await Effect.runPromise(bash.execute(
-                {
-                  command: `echo $(cat "${file}")`,
-                  description: "Read nested bash file",
-                },
-                capture(requests),
-              ))
+              await Effect.runPromise(
+                bash.execute(
+                  {
+                    command: `echo $(cat "${file}")`,
+                    description: "Read nested bash file",
+                  },
+                  capture(requests),
+                ),
+              )
               const extDirReq = requests.find((r) => r.permission === "external_directory")
               const bashReq = requests.find((r) => r.permission === "bash")
               expect(extDirReq).toBeDefined()
@@ -290,13 +302,15 @@ describe("tool.bash permissions", () => {
               const err = new Error("stop after permission")
               const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
               await expect(
-                Effect.runPromise(bash.execute(
-                  {
-                    command: `Copy-Item -PassThru "${process.env.WINDIR!.replaceAll("\\", "/")}/win.ini" ./out`,
-                    description: "Copy Windows ini",
-                  },
-                  capture(requests, err),
-                )),
+                Effect.runPromise(
+                  bash.execute(
+                    {
+                      command: `Copy-Item -PassThru "${process.env.WINDIR!.replaceAll("\\", "/")}/win.ini" ./out`,
+                      description: "Copy Windows ini",
+                    },
+                    capture(requests, err),
+                  ),
+                ),
               ).rejects.toThrow(err.message)
               const extDirReq = requests.find((r) => r.permission === "external_directory")
               expect(extDirReq).toBeDefined()
@@ -317,13 +331,15 @@ describe("tool.bash permissions", () => {
               const bash = await initBash()
               const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
               const file = `${process.env.WINDIR!.replaceAll("\\", "/")}/win.ini`
-              await Effect.runPromise(bash.execute(
-                {
-                  command: `Write-Output $(Get-Content ${file})`,
-                  description: "Read nested PowerShell file",
-                },
-                capture(requests),
-              ))
+              await Effect.runPromise(
+                bash.execute(
+                  {
+                    command: `Write-Output $(Get-Content ${file})`,
+                    description: "Read nested PowerShell file",
+                  },
+                  capture(requests),
+                ),
+              )
               const extDirReq = requests.find((r) => r.permission === "external_directory")
               const bashReq = requests.find((r) => r.permission === "bash")
               expect(extDirReq).toBeDefined()
@@ -348,13 +364,15 @@ describe("tool.bash permissions", () => {
               const err = new Error("stop after permission")
               const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
               await expect(
-                Effect.runPromise(bash.execute(
-                  {
-                    command: 'Get-Content "C:../outside.txt"',
-                    description: "Read drive-relative file",
-                  },
-                  capture(requests, err),
-                )),
+                Effect.runPromise(
+                  bash.execute(
+                    {
+                      command: 'Get-Content "C:../outside.txt"',
+                      description: "Read drive-relative file",
+                    },
+                    capture(requests, err),
+                  ),
+                ),
               ).rejects.toThrow(err.message)
               expect(requests[0]?.permission).toBe("external_directory")
               if (requests[0]?.permission !== "external_directory") return
@@ -376,13 +394,15 @@ describe("tool.bash permissions", () => {
               const err = new Error("stop after permission")
               const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
               await expect(
-                Effect.runPromise(bash.execute(
-                  {
-                    command: 'Get-Content "$HOME/.ssh/config"',
-                    description: "Read home config",
-                  },
-                  capture(requests, err),
-                )),
+                Effect.runPromise(
+                  bash.execute(
+                    {
+                      command: 'Get-Content "$HOME/.ssh/config"',
+                      description: "Read home config",
+                    },
+                    capture(requests, err),
+                  ),
+                ),
               ).rejects.toThrow(err.message)
               expect(requests[0]?.permission).toBe("external_directory")
               if (requests[0]?.permission !== "external_directory") return
@@ -405,13 +425,15 @@ describe("tool.bash permissions", () => {
               const err = new Error("stop after permission")
               const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
               await expect(
-                Effect.runPromise(bash.execute(
-                  {
-                    command: 'Get-Content "$PWD/../outside.txt"',
-                    description: "Read pwd-relative file",
-                  },
-                  capture(requests, err),
-                )),
+                Effect.runPromise(
+                  bash.execute(
+                    {
+                      command: 'Get-Content "$PWD/../outside.txt"',
+                      description: "Read pwd-relative file",
+                    },
+                    capture(requests, err),
+                  ),
+                ),
               ).rejects.toThrow(err.message)
               expect(requests[0]?.permission).toBe("external_directory")
               if (requests[0]?.permission !== "external_directory") return
@@ -433,13 +455,15 @@ describe("tool.bash permissions", () => {
               const err = new Error("stop after permission")
               const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
               await expect(
-                Effect.runPromise(bash.execute(
-                  {
-                    command: 'Get-Content "$PSHOME/outside.txt"',
-                    description: "Read pshome file",
-                  },
-                  capture(requests, err),
-                )),
+                Effect.runPromise(
+                  bash.execute(
+                    {
+                      command: 'Get-Content "$PSHOME/outside.txt"',
+                      description: "Read pshome file",
+                    },
+                    capture(requests, err),
+                  ),
+                ),
               ).rejects.toThrow(err.message)
               expect(requests[0]?.permission).toBe("external_directory")
               if (requests[0]?.permission !== "external_directory") return
@@ -466,13 +490,15 @@ describe("tool.bash permissions", () => {
                 const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
                 const root = path.parse(process.env.WINDIR!).root.replace(/[\\/]+$/, "")
                 await expect(
-                  Effect.runPromise(bash.execute(
-                    {
-                      command: `Get-Content -Path "${root}$env:${key}\\Windows\\win.ini"`,
-                      description: "Read Windows ini with missing env",
-                    },
-                    capture(requests, err),
-                  )),
+                  Effect.runPromise(
+                    bash.execute(
+                      {
+                        command: `Get-Content -Path "${root}$env:${key}\\Windows\\win.ini"`,
+                        description: "Read Windows ini with missing env",
+                      },
+                      capture(requests, err),
+                    ),
+                  ),
                 ).rejects.toThrow(err.message)
                 const extDirReq = requests.find((r) => r.permission === "external_directory")
                 expect(extDirReq).toBeDefined()
@@ -496,13 +522,15 @@ describe("tool.bash permissions", () => {
             fn: async () => {
               const bash = await initBash()
               const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
-              await Effect.runPromise(bash.execute(
-                {
-                  command: "Get-Content $env:WINDIR/win.ini",
-                  description: "Read Windows ini from env",
-                },
-                capture(requests),
-              ))
+              await Effect.runPromise(
+                bash.execute(
+                  {
+                    command: "Get-Content $env:WINDIR/win.ini",
+                    description: "Read Windows ini from env",
+                  },
+                  capture(requests),
+                ),
+              )
               const extDirReq = requests.find((r) => r.permission === "external_directory")
               expect(extDirReq).toBeDefined()
               expect(extDirReq!.patterns).toContain(
@@ -525,13 +553,15 @@ describe("tool.bash permissions", () => {
               const err = new Error("stop after permission")
               const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
               await expect(
-                Effect.runPromise(bash.execute(
-                  {
-                    command: `Get-Content -Path FileSystem::${process.env.WINDIR!.replaceAll("\\", "/")}/win.ini`,
-                    description: "Read Windows ini from FileSystem provider",
-                  },
-                  capture(requests, err),
-                )),
+                Effect.runPromise(
+                  bash.execute(
+                    {
+                      command: `Get-Content -Path FileSystem::${process.env.WINDIR!.replaceAll("\\", "/")}/win.ini`,
+                      description: "Read Windows ini from FileSystem provider",
+                    },
+                    capture(requests, err),
+                  ),
+                ),
               ).rejects.toThrow(err.message)
               expect(requests[0]?.permission).toBe("external_directory")
               if (requests[0]?.permission !== "external_directory") return
@@ -555,13 +585,15 @@ describe("tool.bash permissions", () => {
               const err = new Error("stop after permission")
               const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
               await expect(
-                Effect.runPromise(bash.execute(
-                  {
-                    command: "Get-Content ${env:WINDIR}/win.ini",
-                    description: "Read Windows ini from braced env",
-                  },
-                  capture(requests, err),
-                )),
+                Effect.runPromise(
+                  bash.execute(
+                    {
+                      command: "Get-Content ${env:WINDIR}/win.ini",
+                      description: "Read Windows ini from braced env",
+                    },
+                    capture(requests, err),
+                  ),
+                ),
               ).rejects.toThrow(err.message)
               expect(requests[0]?.permission).toBe("external_directory")
               if (requests[0]?.permission !== "external_directory") return
@@ -583,13 +615,15 @@ describe("tool.bash permissions", () => {
             fn: async () => {
               const bash = await initBash()
               const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
-              await Effect.runPromise(bash.execute(
-                {
-                  command: "Set-Location C:/Windows",
-                  description: "Change location",
-                },
-                capture(requests),
-              ))
+              await Effect.runPromise(
+                bash.execute(
+                  {
+                    command: "Set-Location C:/Windows",
+                    description: "Change location",
+                  },
+                  capture(requests),
+                ),
+              )
               const extDirReq = requests.find((r) => r.permission === "external_directory")
               const bashReq = requests.find((r) => r.permission === "bash")
               expect(extDirReq).toBeDefined()
@@ -612,13 +646,15 @@ describe("tool.bash permissions", () => {
             fn: async () => {
               const bash = await initBash()
               const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
-              await Effect.runPromise(bash.execute(
-                {
-                  command: "Write-Output ('a' * 3)",
-                  description: "Write repeated text",
-                },
-                capture(requests),
-              ))
+              await Effect.runPromise(
+                bash.execute(
+                  {
+                    command: "Write-Output ('a' * 3)",
+                    description: "Write repeated text",
+                  },
+                  capture(requests),
+                ),
+              )
               const bashReq = requests.find((r) => r.permission === "bash")
               expect(bashReq).toBeDefined()
               expect(bashReq!.patterns).not.toContain("a * 3")
@@ -639,13 +675,15 @@ describe("tool.bash permissions", () => {
         const err = new Error("stop after permission")
         const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
         await expect(
-          Effect.runPromise(bash.execute(
-            {
-              command: "cd ../",
-              description: "Change to parent directory",
-            },
-            capture(requests, err),
-          )),
+          Effect.runPromise(
+            bash.execute(
+              {
+                command: "cd ../",
+                description: "Change to parent directory",
+              },
+              capture(requests, err),
+            ),
+          ),
         ).rejects.toThrow(err.message)
         const extDirReq = requests.find((r) => r.permission === "external_directory")
         expect(extDirReq).toBeDefined()
@@ -662,14 +700,16 @@ describe("tool.bash permissions", () => {
         const err = new Error("stop after permission")
         const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
         await expect(
-          Effect.runPromise(bash.execute(
-            {
-              command: "echo ok",
-              workdir: os.tmpdir(),
-              description: "Echo from temp dir",
-            },
-            capture(requests, err),
-          )),
+          Effect.runPromise(
+            bash.execute(
+              {
+                command: "echo ok",
+                workdir: os.tmpdir(),
+                description: "Echo from temp dir",
+              },
+              capture(requests, err),
+            ),
+          ),
         ).rejects.toThrow(err.message)
         const extDirReq = requests.find((r) => r.permission === "external_directory")
         expect(extDirReq).toBeDefined()
@@ -692,14 +732,16 @@ describe("tool.bash permissions", () => {
           for (const dir of forms(outerTmp.path)) {
             const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
             await expect(
-              Effect.runPromise(bash.execute(
-                {
-                  command: "echo ok",
-                  workdir: dir,
-                  description: "Echo from external dir",
-                },
-                capture(requests, err),
-              )),
+              Effect.runPromise(
+                bash.execute(
+                  {
+                    command: "echo ok",
+                    workdir: dir,
+                    description: "Echo from external dir",
+                  },
+                  capture(requests, err),
+                ),
+              ),
             ).rejects.toThrow(err.message)
 
             const extDirReq = requests.find((r) => r.permission === "external_directory")
@@ -725,14 +767,16 @@ describe("tool.bash permissions", () => {
               const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
               const want = glob(path.join(os.tmpdir(), "*"))
               await expect(
-                Effect.runPromise(bash.execute(
-                  {
-                    command: "echo ok",
-                    workdir: "/tmp",
-                    description: "Echo from Git Bash tmp",
-                  },
-                  capture(requests, err),
-                )),
+                Effect.runPromise(
+                  bash.execute(
+                    {
+                      command: "echo ok",
+                      workdir: "/tmp",
+                      description: "Echo from Git Bash tmp",
+                    },
+                    capture(requests, err),
+                  ),
+                ),
               ).rejects.toThrow(err.message)
               expect(requests[0]).toMatchObject({
                 permission: "external_directory",
@@ -755,13 +799,15 @@ describe("tool.bash permissions", () => {
               const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
               const want = glob(path.join(os.tmpdir(), "*"))
               await expect(
-                Effect.runPromise(bash.execute(
-                  {
-                    command: "cat /tmp/opencode-does-not-exist",
-                    description: "Read Git Bash tmp file",
-                  },
-                  capture(requests, err),
-                )),
+                Effect.runPromise(
+                  bash.execute(
+                    {
+                      command: "cat /tmp/opencode-does-not-exist",
+                      description: "Read Git Bash tmp file",
+                    },
+                    capture(requests, err),
+                  ),
+                ),
               ).rejects.toThrow(err.message)
               expect(requests[0]).toMatchObject({
                 permission: "external_directory",
@@ -790,13 +836,15 @@ describe("tool.bash permissions", () => {
         const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
         const filepath = path.join(outerTmp.path, "outside.txt")
         await expect(
-          Effect.runPromise(bash.execute(
-            {
-              command: `cat ${filepath}`,
-              description: "Read external file",
-            },
-            capture(requests, err),
-          )),
+          Effect.runPromise(
+            bash.execute(
+              {
+                command: `cat ${filepath}`,
+                description: "Read external file",
+              },
+              capture(requests, err),
+            ),
+          ),
         ).rejects.toThrow(err.message)
         const extDirReq = requests.find((r) => r.permission === "external_directory")
         const expected = glob(path.join(outerTmp.path, "*"))
@@ -818,13 +866,15 @@ describe("tool.bash permissions", () => {
       fn: async () => {
         const bash = await initBash()
         const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
-        await Effect.runPromise(bash.execute(
-          {
-            command: `rm -rf ${path.join(tmp.path, "nested")}`,
-            description: "Remove nested dir",
-          },
-          capture(requests),
-        ))
+        await Effect.runPromise(
+          bash.execute(
+            {
+              command: `rm -rf ${path.join(tmp.path, "nested")}`,
+              description: "Remove nested dir",
+            },
+            capture(requests),
+          ),
+        )
         const extDirReq = requests.find((r) => r.permission === "external_directory")
         expect(extDirReq).toBeUndefined()
       },
@@ -838,13 +888,15 @@ describe("tool.bash permissions", () => {
       fn: async () => {
         const bash = await initBash()
         const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
-        await Effect.runPromise(bash.execute(
-          {
-            command: "git log --oneline -5",
-            description: "Git log",
-          },
-          capture(requests),
-        ))
+        await Effect.runPromise(
+          bash.execute(
+            {
+              command: "git log --oneline -5",
+              description: "Git log",
+            },
+            capture(requests),
+          ),
+        )
         expect(requests.length).toBe(1)
         expect(requests[0].always.length).toBeGreaterThan(0)
         expect(requests[0].always.some((item) => item.endsWith("*"))).toBe(true)
@@ -859,13 +911,15 @@ describe("tool.bash permissions", () => {
       fn: async () => {
         const bash = await initBash()
         const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
-        await Effect.runPromise(bash.execute(
-          {
-            command: "cd .",
-            description: "Stay in current directory",
-          },
-          capture(requests),
-        ))
+        await Effect.runPromise(
+          bash.execute(
+            {
+              command: "cd .",
+              description: "Stay in current directory",
+            },
+            capture(requests),
+          ),
+        )
         const bashReq = requests.find((r) => r.permission === "bash")
         expect(bashReq).toBeUndefined()
       },
@@ -881,10 +935,12 @@ describe("tool.bash permissions", () => {
         const err = new Error("stop after permission")
         const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
         await expect(
-          Effect.runPromise(bash.execute(
-            { command: "echo test > output.txt", description: "Redirect test output" },
-            capture(requests, err),
-          )),
+          Effect.runPromise(
+            bash.execute(
+              { command: "echo test > output.txt", description: "Redirect test output" },
+              capture(requests, err),
+            ),
+          ),
         ).rejects.toThrow(err.message)
         const bashReq = requests.find((r) => r.permission === "bash")
         expect(bashReq).toBeDefined()
@@ -917,23 +973,25 @@ describe("tool.bash abort", () => {
         const bash = await initBash()
         const controller = new AbortController()
         const collected: string[] = []
-        const res = await Effect.runPromise(bash.execute(
-          {
-            command: `echo before && sleep 30`,
-            description: "Long running command",
-          },
-          {
-            ...ctx,
-            abort: controller.signal,
-            metadata: (input) => {
-              const output = (input.metadata as { output?: string })?.output
-              if (output && output.includes("before") && !controller.signal.aborted) {
-                collected.push(output)
-                controller.abort()
-              }
+        const res = await Effect.runPromise(
+          bash.execute(
+            {
+              command: `echo before && sleep 30`,
+              description: "Long running command",
             },
-          },
-        ))
+            {
+              ...ctx,
+              abort: controller.signal,
+              metadata: (input) => {
+                const output = (input.metadata as { output?: string })?.output
+                if (output && output.includes("before") && !controller.signal.aborted) {
+                  collected.push(output)
+                  controller.abort()
+                }
+              },
+            },
+          ),
+        )
         expect(res.output).toContain("before")
         expect(res.output).toContain("User aborted the command")
         expect(collected.length).toBeGreaterThan(0)
@@ -946,14 +1004,16 @@ describe("tool.bash abort", () => {
       directory: projectRoot,
       fn: async () => {
         const bash = await initBash()
-        const result = await Effect.runPromise(bash.execute(
-          {
-            command: `echo started && sleep 60`,
-            description: "Timeout test",
-            timeout: 500,
-          },
-          ctx,
-        ))
+        const result = await Effect.runPromise(
+          bash.execute(
+            {
+              command: `echo started && sleep 60`,
+              description: "Timeout test",
+              timeout: 500,
+            },
+            ctx,
+          ),
+        )
         expect(result.output).toContain("started")
         expect(result.output).toContain("bash tool terminated command after exceeding timeout")
       },
@@ -965,13 +1025,15 @@ describe("tool.bash abort", () => {
       directory: projectRoot,
       fn: async () => {
         const bash = await initBash()
-        const result = await Effect.runPromise(bash.execute(
-          {
-            command: `echo stdout_msg && echo stderr_msg >&2`,
-            description: "Stderr test",
-          },
-          ctx,
-        ))
+        const result = await Effect.runPromise(
+          bash.execute(
+            {
+              command: `echo stdout_msg && echo stderr_msg >&2`,
+              description: "Stderr test",
+            },
+            ctx,
+          ),
+        )
         expect(result.output).toContain("stdout_msg")
         expect(result.output).toContain("stderr_msg")
         expect(result.metadata.exit).toBe(0)
@@ -984,13 +1046,15 @@ describe("tool.bash abort", () => {
       directory: projectRoot,
       fn: async () => {
         const bash = await initBash()
-        const result = await Effect.runPromise(bash.execute(
-          {
-            command: `exit 42`,
-            description: "Non-zero exit",
-          },
-          ctx,
-        ))
+        const result = await Effect.runPromise(
+          bash.execute(
+            {
+              command: `exit 42`,
+              description: "Non-zero exit",
+            },
+            ctx,
+          ),
+        )
         expect(result.metadata.exit).toBe(42)
       },
     })
@@ -1002,19 +1066,21 @@ describe("tool.bash abort", () => {
       fn: async () => {
         const bash = await initBash()
         const updates: string[] = []
-        const result = await Effect.runPromise(bash.execute(
-          {
-            command: `echo first && sleep 0.1 && echo second`,
-            description: "Streaming test",
-          },
-          {
-            ...ctx,
-            metadata: (input) => {
-              const output = (input.metadata as { output?: string })?.output
-              if (output) updates.push(output)
+        const result = await Effect.runPromise(
+          bash.execute(
+            {
+              command: `echo first && sleep 0.1 && echo second`,
+              description: "Streaming test",
             },
-          },
-        ))
+            {
+              ...ctx,
+              metadata: (input) => {
+                const output = (input.metadata as { output?: string })?.output
+                if (output) updates.push(output)
+              },
+            },
+          ),
+        )
         expect(result.output).toContain("first")
         expect(result.output).toContain("second")
         expect(updates.length).toBeGreaterThan(1)
@@ -1030,13 +1096,15 @@ describe("tool.bash truncation", () => {
       fn: async () => {
         const bash = await initBash()
         const lineCount = Truncate.MAX_LINES + 500
-        const result = await Effect.runPromise(bash.execute(
-          {
-            command: fill("lines", lineCount),
-            description: "Generate lines exceeding limit",
-          },
-          ctx,
-        ))
+        const result = await Effect.runPromise(
+          bash.execute(
+            {
+              command: fill("lines", lineCount),
+              description: "Generate lines exceeding limit",
+            },
+            ctx,
+          ),
+        )
         mustTruncate(result)
         expect(result.output).toContain("truncated")
         expect(result.output).toContain("The tool call succeeded but the output was truncated")
@@ -1050,13 +1118,15 @@ describe("tool.bash truncation", () => {
       fn: async () => {
         const bash = await initBash()
         const byteCount = Truncate.MAX_BYTES + 10000
-        const result = await Effect.runPromise(bash.execute(
-          {
-            command: fill("bytes", byteCount),
-            description: "Generate bytes exceeding limit",
-          },
-          ctx,
-        ))
+        const result = await Effect.runPromise(
+          bash.execute(
+            {
+              command: fill("bytes", byteCount),
+              description: "Generate bytes exceeding limit",
+            },
+            ctx,
+          ),
+        )
         mustTruncate(result)
         expect(result.output).toContain("truncated")
         expect(result.output).toContain("The tool call succeeded but the output was truncated")
@@ -1069,13 +1139,15 @@ describe("tool.bash truncation", () => {
       directory: projectRoot,
       fn: async () => {
         const bash = await initBash()
-        const result = await Effect.runPromise(bash.execute(
-          {
-            command: "echo hello",
-            description: "Echo hello",
-          },
-          ctx,
-        ))
+        const result = await Effect.runPromise(
+          bash.execute(
+            {
+              command: "echo hello",
+              description: "Echo hello",
+            },
+            ctx,
+          ),
+        )
         expect((result.metadata as { truncated?: boolean }).truncated).toBe(false)
         expect(result.output).toContain("hello")
       },
@@ -1088,13 +1160,15 @@ describe("tool.bash truncation", () => {
       fn: async () => {
         const bash = await initBash()
         const lineCount = Truncate.MAX_LINES + 100
-        const result = await Effect.runPromise(bash.execute(
-          {
-            command: fill("lines", lineCount),
-            description: "Generate lines for file check",
-          },
-          ctx,
-        ))
+        const result = await Effect.runPromise(
+          bash.execute(
+            {
+              command: fill("lines", lineCount),
+              description: "Generate lines for file check",
+            },
+            ctx,
+          ),
+        )
         mustTruncate(result)
 
         const filepath = (result.metadata as { outputPath?: string }).outputPath

+ 192 - 154
packages/opencode/test/tool/edit.test.ts

@@ -65,14 +65,16 @@ describe("tool.edit", () => {
         directory: tmp.path,
         fn: async () => {
           const edit = await resolve()
-          const result = await Effect.runPromise(edit.execute(
-            {
-              filePath: filepath,
-              oldString: "",
-              newString: "new content",
-            },
-            ctx,
-          ))
+          const result = await Effect.runPromise(
+            edit.execute(
+              {
+                filePath: filepath,
+                oldString: "",
+                newString: "new content",
+              },
+              ctx,
+            ),
+          )
 
           expect(result.metadata.diff).toContain("new content")
 
@@ -90,14 +92,16 @@ describe("tool.edit", () => {
         directory: tmp.path,
         fn: async () => {
           const edit = await resolve()
-          await Effect.runPromise(edit.execute(
-            {
-              filePath: filepath,
-              oldString: "",
-              newString: "nested file",
-            },
-            ctx,
-          ))
+          await Effect.runPromise(
+            edit.execute(
+              {
+                filePath: filepath,
+                oldString: "",
+                newString: "nested file",
+              },
+              ctx,
+            ),
+          )
 
           const content = await fs.readFile(filepath, "utf-8")
           expect(content).toBe("nested file")
@@ -118,14 +122,16 @@ describe("tool.edit", () => {
           const unsubUpdated = await subscribeBus(FileWatcher.Event.Updated, () => events.push("updated"))
 
           const edit = await resolve()
-          await Effect.runPromise(edit.execute(
-            {
-              filePath: filepath,
-              oldString: "",
-              newString: "content",
-            },
-            ctx,
-          ))
+          await Effect.runPromise(
+            edit.execute(
+              {
+                filePath: filepath,
+                oldString: "",
+                newString: "content",
+              },
+              ctx,
+            ),
+          )
 
           expect(events).toContain("updated")
           unsubUpdated()
@@ -146,14 +152,16 @@ describe("tool.edit", () => {
           await readFileTime(ctx.sessionID, filepath)
 
           const edit = await resolve()
-          const result = await Effect.runPromise(edit.execute(
-            {
-              filePath: filepath,
-              oldString: "old content",
-              newString: "new content",
-            },
-            ctx,
-          ))
+          const result = await Effect.runPromise(
+            edit.execute(
+              {
+                filePath: filepath,
+                oldString: "old content",
+                newString: "new content",
+              },
+              ctx,
+            ),
+          )
 
           expect(result.output).toContain("Edit applied successfully")
 
@@ -174,14 +182,16 @@ describe("tool.edit", () => {
 
           const edit = await resolve()
           await expect(
-            Effect.runPromise(edit.execute(
-              {
-                filePath: filepath,
-                oldString: "old",
-                newString: "new",
-              },
-              ctx,
-            )),
+            Effect.runPromise(
+              edit.execute(
+                {
+                  filePath: filepath,
+                  oldString: "old",
+                  newString: "new",
+                },
+                ctx,
+              ),
+            ),
           ).rejects.toThrow("not found")
         },
       })
@@ -197,14 +207,16 @@ describe("tool.edit", () => {
         fn: async () => {
           const edit = await resolve()
           await expect(
-            Effect.runPromise(edit.execute(
-              {
-                filePath: filepath,
-                oldString: "same",
-                newString: "same",
-              },
-              ctx,
-            )),
+            Effect.runPromise(
+              edit.execute(
+                {
+                  filePath: filepath,
+                  oldString: "same",
+                  newString: "same",
+                },
+                ctx,
+              ),
+            ),
           ).rejects.toThrow("identical")
         },
       })
@@ -222,14 +234,16 @@ describe("tool.edit", () => {
 
           const edit = await resolve()
           await expect(
-            Effect.runPromise(edit.execute(
-              {
-                filePath: filepath,
-                oldString: "not in file",
-                newString: "replacement",
-              },
-              ctx,
-            )),
+            Effect.runPromise(
+              edit.execute(
+                {
+                  filePath: filepath,
+                  oldString: "not in file",
+                  newString: "replacement",
+                },
+                ctx,
+              ),
+            ),
           ).rejects.toThrow()
         },
       })
@@ -245,14 +259,16 @@ describe("tool.edit", () => {
         fn: async () => {
           const edit = await resolve()
           await expect(
-            Effect.runPromise(edit.execute(
-              {
-                filePath: filepath,
-                oldString: "content",
-                newString: "modified",
-              },
-              ctx,
-            )),
+            Effect.runPromise(
+              edit.execute(
+                {
+                  filePath: filepath,
+                  oldString: "content",
+                  newString: "modified",
+                },
+                ctx,
+              ),
+            ),
           ).rejects.toThrow("You must read file")
         },
       })
@@ -277,14 +293,16 @@ describe("tool.edit", () => {
           // Try to edit with the new content
           const edit = await resolve()
           await expect(
-            Effect.runPromise(edit.execute(
-              {
-                filePath: filepath,
-                oldString: "modified externally",
-                newString: "edited",
-              },
-              ctx,
-            )),
+            Effect.runPromise(
+              edit.execute(
+                {
+                  filePath: filepath,
+                  oldString: "modified externally",
+                  newString: "edited",
+                },
+                ctx,
+              ),
+            ),
           ).rejects.toThrow("modified since it was last read")
         },
       })
@@ -301,15 +319,17 @@ describe("tool.edit", () => {
           await readFileTime(ctx.sessionID, filepath)
 
           const edit = await resolve()
-          await Effect.runPromise(edit.execute(
-            {
-              filePath: filepath,
-              oldString: "foo",
-              newString: "qux",
-              replaceAll: true,
-            },
-            ctx,
-          ))
+          await Effect.runPromise(
+            edit.execute(
+              {
+                filePath: filepath,
+                oldString: "foo",
+                newString: "qux",
+                replaceAll: true,
+              },
+              ctx,
+            ),
+          )
 
           const content = await fs.readFile(filepath, "utf-8")
           expect(content).toBe("qux bar qux baz qux")
@@ -333,14 +353,16 @@ describe("tool.edit", () => {
           const unsubUpdated = await subscribeBus(FileWatcher.Event.Updated, () => events.push("updated"))
 
           const edit = await resolve()
-          await Effect.runPromise(edit.execute(
-            {
-              filePath: filepath,
-              oldString: "original",
-              newString: "modified",
-            },
-            ctx,
-          ))
+          await Effect.runPromise(
+            edit.execute(
+              {
+                filePath: filepath,
+                oldString: "original",
+                newString: "modified",
+              },
+              ctx,
+            ),
+          )
 
           expect(events).toContain("updated")
           unsubUpdated()
@@ -361,14 +383,16 @@ describe("tool.edit", () => {
           await readFileTime(ctx.sessionID, filepath)
 
           const edit = await resolve()
-          await Effect.runPromise(edit.execute(
-            {
-              filePath: filepath,
-              oldString: "line2",
-              newString: "new line 2\nextra line",
-            },
-            ctx,
-          ))
+          await Effect.runPromise(
+            edit.execute(
+              {
+                filePath: filepath,
+                oldString: "line2",
+                newString: "new line 2\nextra line",
+              },
+              ctx,
+            ),
+          )
 
           const content = await fs.readFile(filepath, "utf-8")
           expect(content).toBe("line1\nnew line 2\nextra line\nline3")
@@ -387,14 +411,16 @@ describe("tool.edit", () => {
           await readFileTime(ctx.sessionID, filepath)
 
           const edit = await resolve()
-          await Effect.runPromise(edit.execute(
-            {
-              filePath: filepath,
-              oldString: "old",
-              newString: "new",
-            },
-            ctx,
-          ))
+          await Effect.runPromise(
+            edit.execute(
+              {
+                filePath: filepath,
+                oldString: "old",
+                newString: "new",
+              },
+              ctx,
+            ),
+          )
 
           const content = await fs.readFile(filepath, "utf-8")
           expect(content).toBe("line1\r\nnew\r\nline3")
@@ -412,14 +438,16 @@ describe("tool.edit", () => {
         fn: async () => {
           const edit = await resolve()
           await expect(
-            Effect.runPromise(edit.execute(
-              {
-                filePath: filepath,
-                oldString: "",
-                newString: "",
-              },
-              ctx,
-            )),
+            Effect.runPromise(
+              edit.execute(
+                {
+                  filePath: filepath,
+                  oldString: "",
+                  newString: "",
+                },
+                ctx,
+              ),
+            ),
           ).rejects.toThrow("identical")
         },
       })
@@ -437,14 +465,16 @@ describe("tool.edit", () => {
 
           const edit = await resolve()
           await expect(
-            Effect.runPromise(edit.execute(
-              {
-                filePath: dirpath,
-                oldString: "old",
-                newString: "new",
-              },
-              ctx,
-            )),
+            Effect.runPromise(
+              edit.execute(
+                {
+                  filePath: dirpath,
+                  oldString: "old",
+                  newString: "new",
+                },
+                ctx,
+              ),
+            ),
           ).rejects.toThrow("directory")
         },
       })
@@ -461,14 +491,16 @@ describe("tool.edit", () => {
           await readFileTime(ctx.sessionID, filepath)
 
           const edit = await resolve()
-          const result = await Effect.runPromise(edit.execute(
-            {
-              filePath: filepath,
-              oldString: "line2",
-              newString: "new line a\nnew line b",
-            },
-            ctx,
-          ))
+          const result = await Effect.runPromise(
+            edit.execute(
+              {
+                filePath: filepath,
+                oldString: "line2",
+                newString: "new line a\nnew line b",
+              },
+              ctx,
+            ),
+          )
 
           expect(result.metadata.filediff).toBeDefined()
           expect(result.metadata.filediff.file).toBe(filepath)
@@ -530,15 +562,17 @@ describe("tool.edit", () => {
           const edit = await resolve()
           const filePath = path.join(tmp.path, "test.txt")
           await readFileTime(ctx.sessionID, filePath)
-          await Effect.runPromise(edit.execute(
-            {
-              filePath,
-              oldString: input.oldString,
-              newString: input.newString,
-              replaceAll: input.replaceAll,
-            },
-            ctx,
-          ))
+          await Effect.runPromise(
+            edit.execute(
+              {
+                filePath,
+                oldString: input.oldString,
+                newString: input.newString,
+                replaceAll: input.replaceAll,
+              },
+              ctx,
+            ),
+          )
           return await Bun.file(filePath).text()
         },
       })
@@ -675,26 +709,30 @@ describe("tool.edit", () => {
           const edit = await resolve()
 
           // Two concurrent edits
-          const promise1 = Effect.runPromise(edit.execute(
-            {
-              filePath: filepath,
-              oldString: "0",
-              newString: "1",
-            },
-            ctx,
-          ))
+          const promise1 = Effect.runPromise(
+            edit.execute(
+              {
+                filePath: filepath,
+                oldString: "0",
+                newString: "1",
+              },
+              ctx,
+            ),
+          )
 
           // Need to read again since FileTime tracks per-session
           await readFileTime(ctx.sessionID, filepath)
 
-          const promise2 = Effect.runPromise(edit.execute(
-            {
-              filePath: filepath,
-              oldString: "0",
-              newString: "2",
-            },
-            ctx,
-          ))
+          const promise2 = Effect.runPromise(
+            edit.execute(
+              {
+                filePath: filepath,
+                oldString: "0",
+                newString: "2",
+              },
+              ctx,
+            ),
+          )
 
           // Both should complete without error (though one might fail due to content mismatch)
           const results = await Promise.allSettled([promise1, promise2])

+ 4 - 1
packages/opencode/test/tool/external-directory.test.ts

@@ -26,7 +26,10 @@ function makeCtx() {
   const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
   const ctx: Tool.Context = {
     ...baseCtx,
-    ask: (req) => Effect.sync(() => { requests.push(req) }),
+    ask: (req) =>
+      Effect.sync(() => {
+        requests.push(req)
+      }),
   }
   return { requests, ctx }
 }

+ 28 - 22
packages/opencode/test/tool/grep.test.ts

@@ -32,14 +32,16 @@ describe("tool.grep", () => {
       directory: projectRoot,
       fn: async () => {
         const grep = await initGrep()
-        const result = await Effect.runPromise(grep.execute(
-          {
-            pattern: "export",
-            path: path.join(projectRoot, "src/tool"),
-            include: "*.ts",
-          },
-          ctx,
-        ))
+        const result = await Effect.runPromise(
+          grep.execute(
+            {
+              pattern: "export",
+              path: path.join(projectRoot, "src/tool"),
+              include: "*.ts",
+            },
+            ctx,
+          ),
+        )
         expect(result.metadata.matches).toBeGreaterThan(0)
         expect(result.output).toContain("Found")
       },
@@ -56,13 +58,15 @@ describe("tool.grep", () => {
       directory: tmp.path,
       fn: async () => {
         const grep = await initGrep()
-        const result = await Effect.runPromise(grep.execute(
-          {
-            pattern: "xyznonexistentpatternxyz123",
-            path: tmp.path,
-          },
-          ctx,
-        ))
+        const result = await Effect.runPromise(
+          grep.execute(
+            {
+              pattern: "xyznonexistentpatternxyz123",
+              path: tmp.path,
+            },
+            ctx,
+          ),
+        )
         expect(result.metadata.matches).toBe(0)
         expect(result.output).toBe("No files found")
       },
@@ -81,13 +85,15 @@ describe("tool.grep", () => {
       directory: tmp.path,
       fn: async () => {
         const grep = await initGrep()
-        const result = await Effect.runPromise(grep.execute(
-          {
-            pattern: "line",
-            path: tmp.path,
-          },
-          ctx,
-        ))
+        const result = await Effect.runPromise(
+          grep.execute(
+            {
+              pattern: "line",
+              path: tmp.path,
+            },
+            ctx,
+          ),
+        )
         expect(result.metadata.matches).toBeGreaterThan(0)
       },
     })

+ 3 - 1
packages/opencode/test/tool/read.test.ts

@@ -96,7 +96,9 @@ const asks = () => {
     next: {
       ...ctx,
       ask: (req: Omit<Permission.Request, "id" | "sessionID" | "tool">) =>
-        Effect.sync(() => { items.push(req) }),
+        Effect.sync(() => {
+          items.push(req)
+        }),
     },
   }
 }

+ 3 - 1
packages/opencode/test/tool/skill.test.ts

@@ -157,7 +157,9 @@ Use this skill.
           const ctx: Tool.Context = {
             ...baseCtx,
             ask: (req) =>
-              Effect.sync(() => { requests.push(req) }),
+              Effect.sync(() => {
+                requests.push(req)
+              }),
           }
 
           const result = await runtime.runPromise(tool.execute({ name: "tool-skill" }, ctx))

+ 69 - 67
packages/opencode/test/tool/task.test.ts

@@ -195,23 +195,23 @@ describe("tool.task", () => {
         const promptOps = stubOps({ text: "resumed", onPrompt: (input) => (seen = input) })
 
         const result = yield* def.execute(
-            {
-              description: "inspect bug",
-              prompt: "look into the cache key path",
-              subagent_type: "general",
-              task_id: child.id,
-            },
-            {
-              sessionID: chat.id,
-              messageID: assistant.id,
-              agent: "build",
-              abort: new AbortController().signal,
-              extra: { promptOps },
-              messages: [],
-              metadata() {},
-              ask: () => Effect.void,
-            },
-          )
+          {
+            description: "inspect bug",
+            prompt: "look into the cache key path",
+            subagent_type: "general",
+            task_id: child.id,
+          },
+          {
+            sessionID: chat.id,
+            messageID: assistant.id,
+            agent: "build",
+            abort: new AbortController().signal,
+            extra: { promptOps },
+            messages: [],
+            metadata() {},
+            ask: () => Effect.void,
+          },
+        )
 
         const kids = yield* sessions.children(chat.id)
         expect(kids).toHaveLength(1)
@@ -234,23 +234,25 @@ describe("tool.task", () => {
 
         const exec = (extra?: Record<string, any>) =>
           def.execute(
-              {
-                description: "inspect bug",
-                prompt: "look into the cache key path",
-                subagent_type: "general",
-              },
-              {
-                sessionID: chat.id,
-                messageID: assistant.id,
-                agent: "build",
-                abort: new AbortController().signal,
-                extra: { promptOps, ...extra },
-                messages: [],
-                metadata() {},
-                ask: (input) =>
-                  Effect.sync(() => { calls.push(input) }),
-              },
-            )
+            {
+              description: "inspect bug",
+              prompt: "look into the cache key path",
+              subagent_type: "general",
+            },
+            {
+              sessionID: chat.id,
+              messageID: assistant.id,
+              agent: "build",
+              abort: new AbortController().signal,
+              extra: { promptOps, ...extra },
+              messages: [],
+              metadata() {},
+              ask: (input) =>
+                Effect.sync(() => {
+                  calls.push(input)
+                }),
+            },
+          )
 
         yield* exec()
         yield* exec({ bypassAgentCheck: true })
@@ -280,23 +282,23 @@ describe("tool.task", () => {
         const promptOps = stubOps({ text: "created", onPrompt: (input) => (seen = input) })
 
         const result = yield* def.execute(
-            {
-              description: "inspect bug",
-              prompt: "look into the cache key path",
-              subagent_type: "general",
-              task_id: "ses_missing",
-            },
-            {
-              sessionID: chat.id,
-              messageID: assistant.id,
-              agent: "build",
-              abort: new AbortController().signal,
-              extra: { promptOps },
-              messages: [],
-              metadata() {},
-              ask: () => Effect.void,
-            },
-          )
+          {
+            description: "inspect bug",
+            prompt: "look into the cache key path",
+            subagent_type: "general",
+            task_id: "ses_missing",
+          },
+          {
+            sessionID: chat.id,
+            messageID: assistant.id,
+            agent: "build",
+            abort: new AbortController().signal,
+            extra: { promptOps },
+            messages: [],
+            metadata() {},
+            ask: () => Effect.void,
+          },
+        )
 
         const kids = yield* sessions.children(chat.id)
         expect(kids).toHaveLength(1)
@@ -320,22 +322,22 @@ describe("tool.task", () => {
           const promptOps = stubOps({ onPrompt: (input) => (seen = input) })
 
           const result = yield* def.execute(
-              {
-                description: "inspect bug",
-                prompt: "look into the cache key path",
-                subagent_type: "reviewer",
-              },
-              {
-                sessionID: chat.id,
-                messageID: assistant.id,
-                agent: "build",
-                abort: new AbortController().signal,
-                extra: { promptOps },
-                messages: [],
-                metadata() {},
-                ask: () => Effect.void,
-              },
-            )
+            {
+              description: "inspect bug",
+              prompt: "look into the cache key path",
+              subagent_type: "reviewer",
+            },
+            {
+              sessionID: chat.id,
+              messageID: assistant.id,
+              agent: "build",
+              abort: new AbortController().signal,
+              extra: { promptOps },
+              messages: [],
+              metadata() {},
+              ask: () => Effect.void,
+            },
+          )
 
           const child = yield* sessions.get(result.metadata.sessionId)
           expect(child.parentID).toBe(chat.id)

+ 4 - 1
packages/opencode/test/tool/tool-define.test.ts

@@ -32,7 +32,10 @@ describe("Tool.define", () => {
 
   test("function-defined tool returns fresh objects and is unaffected", async () => {
     const info = await Effect.runPromise(
-      Tool.define("test-fn-tool", Effect.succeed(() => Promise.resolve(makeTool("test")))),
+      Tool.define(
+        "test-fn-tool",
+        Effect.succeed(() => Promise.resolve(makeTool("test"))),
+      ),
     )
 
     const first = await info.init()

+ 9 - 6
packages/opencode/test/tool/webfetch.test.ts

@@ -42,10 +42,9 @@ describe("tool.webfetch", () => {
           directory: projectRoot,
           fn: async () => {
             const webfetch = await initTool()
-            const result = await Effect.runPromise(webfetch.execute(
-              { url: new URL("/image.png", url).toString(), format: "markdown" },
-              ctx,
-            ))
+            const result = await Effect.runPromise(
+              webfetch.execute({ url: new URL("/image.png", url).toString(), format: "markdown" }, ctx),
+            )
             expect(result.output).toBe("Image fetched successfully")
             expect(result.attachments).toBeDefined()
             expect(result.attachments?.length).toBe(1)
@@ -74,7 +73,9 @@ describe("tool.webfetch", () => {
           directory: projectRoot,
           fn: async () => {
             const webfetch = await initTool()
-            const result = await Effect.runPromise(webfetch.execute({ url: new URL("/image.svg", url).toString(), format: "html" }, ctx))
+            const result = await Effect.runPromise(
+              webfetch.execute({ url: new URL("/image.svg", url).toString(), format: "html" }, ctx),
+            )
             expect(result.output).toContain("<svg")
             expect(result.attachments).toBeUndefined()
           },
@@ -95,7 +96,9 @@ describe("tool.webfetch", () => {
           directory: projectRoot,
           fn: async () => {
             const webfetch = await initTool()
-            const result = await Effect.runPromise(webfetch.execute({ url: new URL("/file.txt", url).toString(), format: "text" }, ctx))
+            const result = await Effect.runPromise(
+              webfetch.execute({ url: new URL("/file.txt", url).toString(), format: "text" }, ctx),
+            )
             expect(result.output).toBe("hello from webfetch")
             expect(result.attachments).toBeUndefined()
           },

+ 8 - 1
packages/opencode/test/tool/write.test.ts

@@ -31,7 +31,14 @@ afterEach(async () => {
 })
 
 const it = testEffect(
-  Layer.mergeAll(LSP.defaultLayer, AppFileSystem.defaultLayer, FileTime.defaultLayer, Bus.layer, Format.defaultLayer, CrossSpawnSpawner.defaultLayer),
+  Layer.mergeAll(
+    LSP.defaultLayer,
+    AppFileSystem.defaultLayer,
+    FileTime.defaultLayer,
+    Bus.layer,
+    Format.defaultLayer,
+    CrossSpawnSpawner.defaultLayer,
+  ),
 )
 
 const init = Effect.fn("WriteToolTest.init")(function* () {