mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-03-30 13:54:01 +00:00
- Rename packages/opencode → packages/tfcode (directory only) - Rename bin/opencode → bin/tfcode (CLI binary) - Rename .opencode → .tfcode (config directory) - Update package.json name and bin field - Update config directory path references (.tfcode) - Keep internal code references as 'opencode' for easy upstream sync - Keep @opencode-ai/* workspace package names This minimal branding approach allows clean merges from upstream opencode repository while providing tfcode branding for users.
129 lines
3.5 KiB
TypeScript
129 lines
3.5 KiB
TypeScript
import { describe, expect, test } from "bun:test"
|
|
import path from "path"
|
|
import type { Tool } from "../../src/tool/tool"
|
|
import { Instance } from "../../src/project/instance"
|
|
import { assertExternalDirectory } from "../../src/tool/external-directory"
|
|
import type { Permission } from "../../src/permission"
|
|
import { SessionID, MessageID } from "../../src/session/schema"
|
|
|
|
const baseCtx: Omit<Tool.Context, "ask"> = {
|
|
sessionID: SessionID.make("ses_test"),
|
|
messageID: MessageID.make(""),
|
|
callID: "",
|
|
agent: "build",
|
|
abort: AbortSignal.any([]),
|
|
messages: [],
|
|
metadata: () => {},
|
|
}
|
|
|
|
describe("tool.assertExternalDirectory", () => {
|
|
test("no-ops for empty target", async () => {
|
|
const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
|
|
const ctx: Tool.Context = {
|
|
...baseCtx,
|
|
ask: async (req) => {
|
|
requests.push(req)
|
|
},
|
|
}
|
|
|
|
await Instance.provide({
|
|
directory: "/tmp",
|
|
fn: async () => {
|
|
await assertExternalDirectory(ctx)
|
|
},
|
|
})
|
|
|
|
expect(requests.length).toBe(0)
|
|
})
|
|
|
|
test("no-ops for paths inside Instance.directory", async () => {
|
|
const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
|
|
const ctx: Tool.Context = {
|
|
...baseCtx,
|
|
ask: async (req) => {
|
|
requests.push(req)
|
|
},
|
|
}
|
|
|
|
await Instance.provide({
|
|
directory: "/tmp/project",
|
|
fn: async () => {
|
|
await assertExternalDirectory(ctx, path.join("/tmp/project", "file.txt"))
|
|
},
|
|
})
|
|
|
|
expect(requests.length).toBe(0)
|
|
})
|
|
|
|
test("asks with a single canonical glob", async () => {
|
|
const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
|
|
const ctx: Tool.Context = {
|
|
...baseCtx,
|
|
ask: async (req) => {
|
|
requests.push(req)
|
|
},
|
|
}
|
|
|
|
const directory = "/tmp/project"
|
|
const target = "/tmp/outside/file.txt"
|
|
const expected = path.join(path.dirname(target), "*").replaceAll("\\", "/")
|
|
|
|
await Instance.provide({
|
|
directory,
|
|
fn: async () => {
|
|
await assertExternalDirectory(ctx, target)
|
|
},
|
|
})
|
|
|
|
const req = requests.find((r) => r.permission === "external_directory")
|
|
expect(req).toBeDefined()
|
|
expect(req!.patterns).toEqual([expected])
|
|
expect(req!.always).toEqual([expected])
|
|
})
|
|
|
|
test("uses target directory when kind=directory", async () => {
|
|
const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
|
|
const ctx: Tool.Context = {
|
|
...baseCtx,
|
|
ask: async (req) => {
|
|
requests.push(req)
|
|
},
|
|
}
|
|
|
|
const directory = "/tmp/project"
|
|
const target = "/tmp/outside"
|
|
const expected = path.join(target, "*").replaceAll("\\", "/")
|
|
|
|
await Instance.provide({
|
|
directory,
|
|
fn: async () => {
|
|
await assertExternalDirectory(ctx, target, { kind: "directory" })
|
|
},
|
|
})
|
|
|
|
const req = requests.find((r) => r.permission === "external_directory")
|
|
expect(req).toBeDefined()
|
|
expect(req!.patterns).toEqual([expected])
|
|
expect(req!.always).toEqual([expected])
|
|
})
|
|
|
|
test("skips prompting when bypass=true", async () => {
|
|
const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
|
|
const ctx: Tool.Context = {
|
|
...baseCtx,
|
|
ask: async (req) => {
|
|
requests.push(req)
|
|
},
|
|
}
|
|
|
|
await Instance.provide({
|
|
directory: "/tmp/project",
|
|
fn: async () => {
|
|
await assertExternalDirectory(ctx, "/tmp/outside/file.txt", { bypass: true })
|
|
},
|
|
})
|
|
|
|
expect(requests.length).toBe(0)
|
|
})
|
|
})
|