Normalize instance lifecycle wiring (#25501)
This commit is contained in:
parent
a6464062b7
commit
7d91d3b1ed
71 changed files with 852 additions and 936 deletions
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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" })
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue