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.
168 lines
4.8 KiB
TypeScript
168 lines
4.8 KiB
TypeScript
import { afterEach, describe, expect, test } from "bun:test"
|
|
import path from "path"
|
|
import { pathToFileURL } from "url"
|
|
import type { Permission } from "../../src/permission"
|
|
import type { Tool } from "../../src/tool/tool"
|
|
import { Instance } from "../../src/project/instance"
|
|
import { SkillTool } from "../../src/tool/skill"
|
|
import { tmpdir } from "../fixture/fixture"
|
|
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: () => {},
|
|
}
|
|
|
|
afterEach(async () => {
|
|
await Instance.disposeAll()
|
|
})
|
|
|
|
describe("tool.skill", () => {
|
|
test("description lists skill location URL", async () => {
|
|
await using tmp = await tmpdir({
|
|
git: true,
|
|
init: async (dir) => {
|
|
const skillDir = path.join(dir, ".opencode", "skill", "tool-skill")
|
|
await Bun.write(
|
|
path.join(skillDir, "SKILL.md"),
|
|
`---
|
|
name: tool-skill
|
|
description: Skill for tool tests.
|
|
---
|
|
|
|
# Tool Skill
|
|
`,
|
|
)
|
|
},
|
|
})
|
|
|
|
const home = process.env.OPENCODE_TEST_HOME
|
|
process.env.OPENCODE_TEST_HOME = tmp.path
|
|
|
|
try {
|
|
await Instance.provide({
|
|
directory: tmp.path,
|
|
fn: async () => {
|
|
const tool = await SkillTool.init()
|
|
const skillPath = path.join(tmp.path, ".opencode", "skill", "tool-skill", "SKILL.md")
|
|
expect(tool.description).toContain(`**tool-skill**: Skill for tool tests.`)
|
|
},
|
|
})
|
|
} finally {
|
|
process.env.OPENCODE_TEST_HOME = home
|
|
}
|
|
})
|
|
|
|
test("description sorts skills by name and is stable across calls", async () => {
|
|
await using tmp = await tmpdir({
|
|
git: true,
|
|
init: async (dir) => {
|
|
for (const [name, description] of [
|
|
["zeta-skill", "Zeta skill."],
|
|
["alpha-skill", "Alpha skill."],
|
|
["middle-skill", "Middle skill."],
|
|
]) {
|
|
const skillDir = path.join(dir, ".opencode", "skill", name)
|
|
await Bun.write(
|
|
path.join(skillDir, "SKILL.md"),
|
|
`---
|
|
name: ${name}
|
|
description: ${description}
|
|
---
|
|
|
|
# ${name}
|
|
`,
|
|
)
|
|
}
|
|
},
|
|
})
|
|
|
|
const home = process.env.OPENCODE_TEST_HOME
|
|
process.env.OPENCODE_TEST_HOME = tmp.path
|
|
|
|
try {
|
|
await Instance.provide({
|
|
directory: tmp.path,
|
|
fn: async () => {
|
|
const first = await SkillTool.init()
|
|
const second = await SkillTool.init()
|
|
|
|
expect(first.description).toBe(second.description)
|
|
|
|
const alpha = first.description.indexOf("**alpha-skill**: Alpha skill.")
|
|
const middle = first.description.indexOf("**middle-skill**: Middle skill.")
|
|
const zeta = first.description.indexOf("**zeta-skill**: Zeta skill.")
|
|
|
|
expect(alpha).toBeGreaterThan(-1)
|
|
expect(middle).toBeGreaterThan(alpha)
|
|
expect(zeta).toBeGreaterThan(middle)
|
|
},
|
|
})
|
|
} finally {
|
|
process.env.OPENCODE_TEST_HOME = home
|
|
}
|
|
})
|
|
|
|
test("execute returns skill content block with files", async () => {
|
|
await using tmp = await tmpdir({
|
|
git: true,
|
|
init: async (dir) => {
|
|
const skillDir = path.join(dir, ".opencode", "skill", "tool-skill")
|
|
await Bun.write(
|
|
path.join(skillDir, "SKILL.md"),
|
|
`---
|
|
name: tool-skill
|
|
description: Skill for tool tests.
|
|
---
|
|
|
|
# Tool Skill
|
|
|
|
Use this skill.
|
|
`,
|
|
)
|
|
await Bun.write(path.join(skillDir, "scripts", "demo.txt"), "demo")
|
|
},
|
|
})
|
|
|
|
const home = process.env.OPENCODE_TEST_HOME
|
|
process.env.OPENCODE_TEST_HOME = tmp.path
|
|
|
|
try {
|
|
await Instance.provide({
|
|
directory: tmp.path,
|
|
fn: async () => {
|
|
const tool = await SkillTool.init()
|
|
const requests: Array<Omit<Permission.Request, "id" | "sessionID" | "tool">> = []
|
|
const ctx: Tool.Context = {
|
|
...baseCtx,
|
|
ask: async (req) => {
|
|
requests.push(req)
|
|
},
|
|
}
|
|
|
|
const result = await tool.execute({ name: "tool-skill" }, ctx)
|
|
const dir = path.join(tmp.path, ".opencode", "skill", "tool-skill")
|
|
const file = path.resolve(dir, "scripts", "demo.txt")
|
|
|
|
expect(requests.length).toBe(1)
|
|
expect(requests[0].permission).toBe("skill")
|
|
expect(requests[0].patterns).toContain("tool-skill")
|
|
expect(requests[0].always).toContain("tool-skill")
|
|
|
|
expect(result.metadata.dir).toBe(dir)
|
|
expect(result.output).toContain(`<skill_content name="tool-skill">`)
|
|
expect(result.output).toContain(`Base directory for this skill: ${pathToFileURL(dir).href}`)
|
|
expect(result.output).toContain(`<file>${file}</file>`)
|
|
},
|
|
})
|
|
} finally {
|
|
process.env.OPENCODE_TEST_HOME = home
|
|
}
|
|
})
|
|
})
|