Normalize instance lifecycle wiring (#25501)

This commit is contained in:
Kit Langton 2026-05-02 20:39:20 -04:00 committed by GitHub
commit 7d91d3b1ed
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
71 changed files with 852 additions and 936 deletions

View file

@ -4,6 +4,7 @@ import * as fs from "fs/promises"
import { Effect, ManagedRuntime, Layer } from "effect"
import { ApplyPatchTool } from "../../src/tool/apply_patch"
import { Instance } from "../../src/project/instance"
import { WithInstance } from "../../src/project/with-instance"
import { LSP } from "@/lsp/lsp"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { Format } from "../../src/format"
@ -97,7 +98,7 @@ describe("tool.apply_patch freeform", () => {
await using fixture = await tmpdir({ git: true })
const { ctx, calls } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const modifyPath = path.join(fixture.path, "modify.txt")
@ -149,7 +150,7 @@ describe("tool.apply_patch freeform", () => {
await using fixture = await tmpdir({ git: true })
const { ctx, calls } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const original = path.join(fixture.path, "old", "name.txt")
@ -179,7 +180,7 @@ describe("tool.apply_patch freeform", () => {
await using fixture = await tmpdir()
const { ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const target = path.join(fixture.path, "multi.txt")
@ -199,7 +200,7 @@ describe("tool.apply_patch freeform", () => {
await using fixture = await tmpdir()
const { ctx, calls } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const bom = String.fromCharCode(0xfeff)
@ -228,7 +229,7 @@ describe("tool.apply_patch freeform", () => {
await using fixture = await tmpdir()
const { ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const target = path.join(fixture.path, "insert_only.txt")
@ -247,7 +248,7 @@ describe("tool.apply_patch freeform", () => {
await using fixture = await tmpdir()
const { ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const target = path.join(fixture.path, "no_newline.txt")
@ -269,7 +270,7 @@ describe("tool.apply_patch freeform", () => {
await using fixture = await tmpdir()
const { ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const original = path.join(fixture.path, "old", "name.txt")
@ -292,7 +293,7 @@ describe("tool.apply_patch freeform", () => {
await using fixture = await tmpdir()
const { ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const original = path.join(fixture.path, "old", "name.txt")
@ -317,7 +318,7 @@ describe("tool.apply_patch freeform", () => {
await using fixture = await tmpdir()
const { ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const target = path.join(fixture.path, "duplicate.txt")
@ -335,7 +336,7 @@ describe("tool.apply_patch freeform", () => {
await using fixture = await tmpdir()
const { ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const patchText = "*** Begin Patch\n*** Update File: missing.txt\n@@\n-nope\n+better\n*** End Patch"
@ -351,7 +352,7 @@ describe("tool.apply_patch freeform", () => {
await using fixture = await tmpdir()
const { ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const patchText = "*** Begin Patch\n*** Delete File: missing.txt\n*** End Patch"
@ -365,7 +366,7 @@ describe("tool.apply_patch freeform", () => {
await using fixture = await tmpdir()
const { ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const dirPath = path.join(fixture.path, "dir")
@ -382,7 +383,7 @@ describe("tool.apply_patch freeform", () => {
await using fixture = await tmpdir()
const { ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const patchText = "*** Begin Patch\n*** Frobnicate File: foo\n*** End Patch"
@ -396,7 +397,7 @@ describe("tool.apply_patch freeform", () => {
await using fixture = await tmpdir()
const { ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const target = path.join(fixture.path, "modify.txt")
@ -414,7 +415,7 @@ describe("tool.apply_patch freeform", () => {
await using fixture = await tmpdir()
const { ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const patchText =
@ -432,7 +433,7 @@ describe("tool.apply_patch freeform", () => {
await using fixture = await tmpdir()
const { ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const target = path.join(fixture.path, "tail.txt")
@ -450,7 +451,7 @@ describe("tool.apply_patch freeform", () => {
await using fixture = await tmpdir()
const { ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const target = path.join(fixture.path, "two_chunks.txt")
@ -468,7 +469,7 @@ describe("tool.apply_patch freeform", () => {
await using fixture = await tmpdir()
const { ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const target = path.join(fixture.path, "multi_ctx.txt")
@ -486,7 +487,7 @@ describe("tool.apply_patch freeform", () => {
await using fixture = await tmpdir()
const { ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const target = path.join(fixture.path, "eof_anchor.txt")
@ -508,7 +509,7 @@ describe("tool.apply_patch freeform", () => {
await using fixture = await tmpdir()
const { ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const patchText = `cat <<'EOF'
@ -529,7 +530,7 @@ EOF`
await using fixture = await tmpdir()
const { ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const patchText = `<<EOF
@ -550,7 +551,7 @@ EOF`
await using fixture = await tmpdir()
const { ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const target = path.join(fixture.path, "trailing_ws.txt")
@ -570,7 +571,7 @@ EOF`
await using fixture = await tmpdir()
const { ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const target = path.join(fixture.path, "leading_ws.txt")
@ -590,7 +591,7 @@ EOF`
await using fixture = await tmpdir()
const { ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: fixture.path,
fn: async () => {
const target = path.join(fixture.path, "unicode.txt")

View file

@ -4,6 +4,7 @@ import fs from "fs/promises"
import { Effect, Layer, ManagedRuntime } from "effect"
import { EditTool } from "../../src/tool/edit"
import { Instance } from "../../src/project/instance"
import { WithInstance } from "../../src/project/with-instance"
import { disposeAllInstances, tmpdir } from "../fixture/fixture"
import { LSP } from "@/lsp/lsp"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
@ -73,7 +74,7 @@ describe("tool.edit", () => {
await using tmp = await tmpdir()
const filepath = path.join(tmp.path, "newfile.txt")
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const edit = await resolve()
@ -102,7 +103,7 @@ describe("tool.edit", () => {
const bom = String.fromCharCode(0xfeff)
await fs.writeFile(filepath, `${bom}using System;\n`, "utf-8")
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const edit = await resolve()
@ -131,7 +132,7 @@ describe("tool.edit", () => {
await using tmp = await tmpdir()
const filepath = path.join(tmp.path, "nested", "dir", "file.txt")
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const edit = await resolve()
@ -156,7 +157,7 @@ describe("tool.edit", () => {
await using tmp = await tmpdir()
const filepath = path.join(tmp.path, "new.txt")
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const { FileWatcher } = await import("../../src/file/watcher")
@ -191,7 +192,7 @@ describe("tool.edit", () => {
const filepath = path.join(tmp.path, "existing.txt")
await fs.writeFile(filepath, "old content here", "utf-8")
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const edit = await resolve()
@ -220,7 +221,7 @@ describe("tool.edit", () => {
const bom = String.fromCharCode(0xfeff)
await fs.writeFile(filepath, `${bom}using System;\nclass Test {}\n`, "utf-8")
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const edit = await resolve()
@ -250,7 +251,7 @@ describe("tool.edit", () => {
await using tmp = await tmpdir()
const filepath = path.join(tmp.path, "nonexistent.txt")
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const edit = await resolve()
@ -275,7 +276,7 @@ describe("tool.edit", () => {
const filepath = path.join(tmp.path, "file.txt")
await fs.writeFile(filepath, "content", "utf-8")
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const edit = await resolve()
@ -300,7 +301,7 @@ describe("tool.edit", () => {
const filepath = path.join(tmp.path, "file.txt")
await fs.writeFile(filepath, "actual content", "utf-8")
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const edit = await resolve()
@ -325,7 +326,7 @@ describe("tool.edit", () => {
const filepath = path.join(tmp.path, "file.txt")
await fs.writeFile(filepath, "foo bar foo baz foo", "utf-8")
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const edit = await resolve()
@ -352,7 +353,7 @@ describe("tool.edit", () => {
const filepath = path.join(tmp.path, "file.txt")
await fs.writeFile(filepath, "original", "utf-8")
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const { FileWatcher } = await import("../../src/file/watcher")
@ -387,7 +388,7 @@ describe("tool.edit", () => {
const filepath = path.join(tmp.path, "file.txt")
await fs.writeFile(filepath, "line1\nline2\nline3", "utf-8")
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const edit = await resolve()
@ -413,7 +414,7 @@ describe("tool.edit", () => {
const filepath = path.join(tmp.path, "file.txt")
await fs.writeFile(filepath, "line1\r\nold\r\nline3", "utf-8")
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const edit = await resolve()
@ -439,7 +440,7 @@ describe("tool.edit", () => {
const filepath = path.join(tmp.path, "file.txt")
await fs.writeFile(filepath, "content", "utf-8")
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const edit = await resolve()
@ -464,7 +465,7 @@ describe("tool.edit", () => {
const dirpath = path.join(tmp.path, "adir")
await fs.mkdir(dirpath)
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const edit = await resolve()
@ -489,7 +490,7 @@ describe("tool.edit", () => {
const filepath = path.join(tmp.path, "file.txt")
await fs.writeFile(filepath, "line1\nline2\nline3", "utf-8")
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const edit = await resolve()
@ -558,7 +559,7 @@ describe("tool.edit", () => {
},
})
return await Instance.provide({
return await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const edit = await resolve()
@ -702,7 +703,7 @@ describe("tool.edit", () => {
const filepath = path.join(tmp.path, "file.txt")
await fs.writeFile(filepath, "top = 0\nmiddle = keep\nbottom = 0\n", "utf-8")
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const edit = await resolve()

View file

@ -3,6 +3,7 @@ import path from "path"
import { Effect } from "effect"
import type { Tool } from "@/tool/tool"
import { Instance } from "../../src/project/instance"
import { WithInstance } from "../../src/project/with-instance"
import { assertExternalDirectory } from "../../src/tool/external-directory"
import { Filesystem } from "@/util/filesystem"
import { tmpdir } from "../fixture/fixture"
@ -38,7 +39,7 @@ describe("tool.assertExternalDirectory", () => {
test("no-ops for empty target", async () => {
const { requests, ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: "/tmp",
fn: async () => {
await assertExternalDirectory(ctx)
@ -51,7 +52,7 @@ describe("tool.assertExternalDirectory", () => {
test("no-ops for paths inside Instance.directory", async () => {
const { requests, ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: "/tmp/project",
fn: async () => {
await assertExternalDirectory(ctx, path.join("/tmp/project", "file.txt"))
@ -68,7 +69,7 @@ describe("tool.assertExternalDirectory", () => {
const target = "/tmp/outside/file.txt"
const expected = glob(path.join(path.dirname(target), "*"))
await Instance.provide({
await WithInstance.provide({
directory,
fn: async () => {
await assertExternalDirectory(ctx, target)
@ -88,7 +89,7 @@ describe("tool.assertExternalDirectory", () => {
const target = "/tmp/outside"
const expected = glob(path.join(target, "*"))
await Instance.provide({
await WithInstance.provide({
directory,
fn: async () => {
await assertExternalDirectory(ctx, target, { kind: "directory" })
@ -104,7 +105,7 @@ describe("tool.assertExternalDirectory", () => {
test("skips prompting when bypass=true", async () => {
const { requests, ctx } = makeCtx()
await Instance.provide({
await WithInstance.provide({
directory: "/tmp/project",
fn: async () => {
await assertExternalDirectory(ctx, "/tmp/outside/file.txt", { bypass: true })
@ -131,7 +132,7 @@ describe("tool.assertExternalDirectory", () => {
.replaceAll("\\", "/")
.toLowerCase()
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
await assertExternalDirectory(ctx, alt)
@ -152,7 +153,7 @@ describe("tool.assertExternalDirectory", () => {
const root = path.parse(tmp.path).root
const target = path.join(root, "boot.ini")
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
await assertExternalDirectory(ctx, target)

View file

@ -6,6 +6,7 @@ import { Config } from "@/config/config"
import { Shell } from "../../src/shell/shell"
import { ShellTool } from "../../src/tool/shell"
import { Instance } from "../../src/project/instance"
import { WithInstance } from "../../src/project/with-instance"
import { Filesystem } from "@/util/filesystem"
import { tmpdir } from "../fixture/fixture"
import type { Permission } from "../../src/permission"
@ -140,7 +141,7 @@ const mustTruncate = (result: {
describe("tool.shell", () => {
each("basic", async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initShell()
@ -163,7 +164,7 @@ describe("tool.shell", () => {
await using tmp = await tmpdir({
config: { shell: "fish" },
})
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const bash = await initBash()
@ -190,7 +191,7 @@ describe("tool.shell", () => {
describe("tool.shell permissions", () => {
each("asks for bash permission with correct pattern", async () => {
await using tmp = await tmpdir()
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const bash = await initShell()
@ -213,7 +214,7 @@ describe("tool.shell permissions", () => {
each("asks for bash permission with multiple commands", async () => {
await using tmp = await tmpdir()
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const bash = await initShell()
@ -239,7 +240,7 @@ describe("tool.shell permissions", () => {
test(
`parses PowerShell conditionals for permission prompts [${item.label}]`,
withShell(item, async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initShell()
@ -269,7 +270,7 @@ describe("tool.shell permissions", () => {
`uses PowerShell cmdlet prefixes for always-allow prompts [${item.label}]`,
withShell(item, async () => {
await using tmp = await tmpdir()
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const bash = await initShell()
@ -297,7 +298,7 @@ describe("tool.shell permissions", () => {
}
each("asks for external_directory permission for wildcard external paths", async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initShell()
@ -333,7 +334,7 @@ describe("tool.shell permissions", () => {
await Bun.write(path.join(dir, "outside.txt"), "x")
},
})
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initShell()
@ -366,7 +367,7 @@ describe("tool.shell permissions", () => {
test(
`asks for external_directory permission for PowerShell paths after switches [${item.label}]`,
withShell(item, async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initShell()
@ -396,7 +397,7 @@ describe("tool.shell permissions", () => {
test(
`asks for nested PowerShell command permissions [${item.label}]`,
withShell(item, async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initShell()
@ -428,7 +429,7 @@ describe("tool.shell permissions", () => {
`asks for external_directory permission for drive-relative PowerShell paths [${item.label}]`,
withShell(item, async () => {
await using tmp = await tmpdir()
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const bash = await initShell()
@ -458,7 +459,7 @@ describe("tool.shell permissions", () => {
test(
`asks for external_directory permission for $HOME PowerShell paths [${item.label}]`,
withShell(item, async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initShell()
@ -489,7 +490,7 @@ describe("tool.shell permissions", () => {
`asks for external_directory permission for $PWD PowerShell paths [${item.label}]`,
withShell(item, async () => {
await using tmp = await tmpdir()
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const bash = await initBash()
@ -519,7 +520,7 @@ describe("tool.shell permissions", () => {
test(
`asks for external_directory permission for $PSHOME PowerShell paths [${item.label}]`,
withShell(item, async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initBash()
@ -553,7 +554,7 @@ describe("tool.shell permissions", () => {
const prev = process.env[key]
delete process.env[key]
try {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initShell()
@ -588,7 +589,7 @@ describe("tool.shell permissions", () => {
test(
`asks for external_directory permission for PowerShell env paths [${item.label}]`,
withShell(item, async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initBash()
@ -617,7 +618,7 @@ describe("tool.shell permissions", () => {
test(
`asks for external_directory permission for PowerShell FileSystem paths [${item.label}]`,
withShell(item, async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initBash()
@ -649,7 +650,7 @@ describe("tool.shell permissions", () => {
test(
`asks for external_directory permission for braced PowerShell env paths [${item.label}]`,
withShell(item, async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initBash()
@ -681,7 +682,7 @@ describe("tool.shell permissions", () => {
test(
`treats Set-Location like cd for permissions [${item.label}]`,
withShell(item, async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initBash()
@ -712,7 +713,7 @@ describe("tool.shell permissions", () => {
test(
`does not add nested PowerShell expressions to permission prompts [${item.label}]`,
withShell(item, async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initShell()
@ -741,7 +742,7 @@ describe("tool.shell permissions", () => {
test(
"asks for external_directory permission for cmd file commands [cmd]",
withShell(cmdShell, async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initShell()
@ -766,7 +767,7 @@ describe("tool.shell permissions", () => {
each("asks for external_directory permission when cd to parent", async () => {
await using tmp = await tmpdir()
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const bash = await initBash()
@ -791,7 +792,7 @@ describe("tool.shell permissions", () => {
each("asks for external_directory permission when workdir is outside project", async () => {
await using tmp = await tmpdir()
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const bash = await initBash()
@ -821,7 +822,7 @@ describe("tool.shell permissions", () => {
const err = new Error("stop after permission")
await using outerTmp = await tmpdir()
await using tmp = await tmpdir()
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const bash = await initBash()
@ -857,7 +858,7 @@ describe("tool.shell permissions", () => {
test(
"uses Git Bash /tmp semantics for external workdir",
withShell({ label: "bash", shell: bash }, async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initBash()
@ -889,7 +890,7 @@ describe("tool.shell permissions", () => {
test(
"uses Git Bash /tmp semantics for external file paths",
withShell({ label: "bash", shell: bash }, async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initBash()
@ -926,7 +927,7 @@ describe("tool.shell permissions", () => {
},
})
await using tmp = await tmpdir()
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const bash = await initBash()
@ -959,7 +960,7 @@ describe("tool.shell permissions", () => {
await Bun.write(path.join(dir, "tmpfile"), "x")
},
})
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const bash = await initBash()
@ -981,7 +982,7 @@ describe("tool.shell permissions", () => {
each("includes always patterns for auto-approval", async () => {
await using tmp = await tmpdir()
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const bash = await initBash()
@ -1004,7 +1005,7 @@ describe("tool.shell permissions", () => {
each("does not ask for bash permission when command is cd only", async () => {
await using tmp = await tmpdir()
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const bash = await initShell()
@ -1026,7 +1027,7 @@ describe("tool.shell permissions", () => {
each("matches redirects in permission pattern", async () => {
await using tmp = await tmpdir()
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const bash = await initShell()
@ -1049,7 +1050,7 @@ describe("tool.shell permissions", () => {
each("always pattern has space before wildcard to not include different commands", async () => {
await using tmp = await tmpdir()
await Instance.provide({
await WithInstance.provide({
directory: tmp.path,
fn: async () => {
const bash = await initBash()
@ -1065,7 +1066,7 @@ describe("tool.shell permissions", () => {
describe("tool.shell abort", () => {
test("preserves output when aborted", async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initShell()
@ -1099,7 +1100,7 @@ describe("tool.shell abort", () => {
}, 15_000)
test("terminates command on timeout", async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initShell()
@ -1121,7 +1122,7 @@ describe("tool.shell abort", () => {
}, 15_000)
test.skipIf(process.platform === "win32")("captures stderr in output", async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initShell()
@ -1142,7 +1143,7 @@ describe("tool.shell abort", () => {
})
test("returns non-zero exit code", async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initShell()
@ -1161,7 +1162,7 @@ describe("tool.shell abort", () => {
})
test("streams metadata updates progressively", async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initBash()
@ -1192,7 +1193,7 @@ describe("tool.shell abort", () => {
describe("tool.shell truncation", () => {
test("truncates output exceeding line limit", async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initShell()
@ -1214,7 +1215,7 @@ describe("tool.shell truncation", () => {
})
test("truncates output exceeding byte limit", async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initShell()
@ -1236,7 +1237,7 @@ describe("tool.shell truncation", () => {
})
test("does not truncate small output", async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initShell()
@ -1256,7 +1257,7 @@ describe("tool.shell truncation", () => {
})
test("full output is saved to file when truncated", async () => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const bash = await initShell()

View file

@ -5,6 +5,7 @@ import { FetchHttpClient } from "effect/unstable/http"
import { Agent } from "../../src/agent/agent"
import { Truncate } from "@/tool/truncate"
import { Instance } from "../../src/project/instance"
import { WithInstance } from "../../src/project/with-instance"
import { WebFetchTool } from "../../src/tool/webfetch"
import { SessionID, MessageID } from "../../src/session/schema"
@ -41,7 +42,7 @@ describe("tool.webfetch", () => {
await withFetch(
() => new Response(bytes, { status: 200, headers: { "content-type": "IMAGE/PNG; charset=binary" } }),
async (url) => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const result = await exec({ url: new URL("/image.png", url).toString(), format: "markdown" })
@ -69,7 +70,7 @@ describe("tool.webfetch", () => {
headers: { "content-type": "image/svg+xml; charset=UTF-8" },
}),
async (url) => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const result = await exec({ url: new URL("/image.svg", url).toString(), format: "html" })
@ -89,7 +90,7 @@ describe("tool.webfetch", () => {
headers: { "content-type": "text/plain; charset=utf-8" },
}),
async (url) => {
await Instance.provide({
await WithInstance.provide({
directory: projectRoot,
fn: async () => {
const result = await exec({ url: new URL("/file.txt", url).toString(), format: "text" })