mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-04-07 17:28:53 +00:00
refactor: apply minimal tfcode branding
- 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.
This commit is contained in:
392
packages/tfcode/test/skill/skill.test.ts
Normal file
392
packages/tfcode/test/skill/skill.test.ts
Normal file
@@ -0,0 +1,392 @@
|
||||
import { afterEach, test, expect } from "bun:test"
|
||||
import { Skill } from "../../src/skill"
|
||||
import { Instance } from "../../src/project/instance"
|
||||
import { tmpdir } from "../fixture/fixture"
|
||||
import path from "path"
|
||||
import fs from "fs/promises"
|
||||
|
||||
afterEach(async () => {
|
||||
await Instance.disposeAll()
|
||||
})
|
||||
|
||||
async function createGlobalSkill(homeDir: string) {
|
||||
const skillDir = path.join(homeDir, ".claude", "skills", "global-test-skill")
|
||||
await fs.mkdir(skillDir, { recursive: true })
|
||||
await Bun.write(
|
||||
path.join(skillDir, "SKILL.md"),
|
||||
`---
|
||||
name: global-test-skill
|
||||
description: A global skill from ~/.claude/skills for testing.
|
||||
---
|
||||
|
||||
# Global Test Skill
|
||||
|
||||
This skill is loaded from the global home directory.
|
||||
`,
|
||||
)
|
||||
}
|
||||
|
||||
test("discovers skills from .opencode/skill/ directory", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
git: true,
|
||||
init: async (dir) => {
|
||||
const skillDir = path.join(dir, ".opencode", "skill", "test-skill")
|
||||
await Bun.write(
|
||||
path.join(skillDir, "SKILL.md"),
|
||||
`---
|
||||
name: test-skill
|
||||
description: A test skill for verification.
|
||||
---
|
||||
|
||||
# Test Skill
|
||||
|
||||
Instructions here.
|
||||
`,
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const skills = await Skill.all()
|
||||
expect(skills.length).toBe(1)
|
||||
const testSkill = skills.find((s) => s.name === "test-skill")
|
||||
expect(testSkill).toBeDefined()
|
||||
expect(testSkill!.description).toBe("A test skill for verification.")
|
||||
expect(testSkill!.location).toContain(path.join("skill", "test-skill", "SKILL.md"))
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("returns skill directories from Skill.dirs", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
git: true,
|
||||
init: async (dir) => {
|
||||
const skillDir = path.join(dir, ".opencode", "skill", "dir-skill")
|
||||
await Bun.write(
|
||||
path.join(skillDir, "SKILL.md"),
|
||||
`---
|
||||
name: dir-skill
|
||||
description: Skill for dirs test.
|
||||
---
|
||||
|
||||
# Dir 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 dirs = await Skill.dirs()
|
||||
const skillDir = path.join(tmp.path, ".opencode", "skill", "dir-skill")
|
||||
expect(dirs).toContain(skillDir)
|
||||
expect(dirs.length).toBe(1)
|
||||
},
|
||||
})
|
||||
} finally {
|
||||
process.env.OPENCODE_TEST_HOME = home
|
||||
}
|
||||
})
|
||||
|
||||
test("discovers multiple skills from .opencode/skill/ directory", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
git: true,
|
||||
init: async (dir) => {
|
||||
const skillDir1 = path.join(dir, ".opencode", "skill", "skill-one")
|
||||
const skillDir2 = path.join(dir, ".opencode", "skill", "skill-two")
|
||||
await Bun.write(
|
||||
path.join(skillDir1, "SKILL.md"),
|
||||
`---
|
||||
name: skill-one
|
||||
description: First test skill.
|
||||
---
|
||||
|
||||
# Skill One
|
||||
`,
|
||||
)
|
||||
await Bun.write(
|
||||
path.join(skillDir2, "SKILL.md"),
|
||||
`---
|
||||
name: skill-two
|
||||
description: Second test skill.
|
||||
---
|
||||
|
||||
# Skill Two
|
||||
`,
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const skills = await Skill.all()
|
||||
expect(skills.length).toBe(2)
|
||||
expect(skills.find((s) => s.name === "skill-one")).toBeDefined()
|
||||
expect(skills.find((s) => s.name === "skill-two")).toBeDefined()
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("skips skills with missing frontmatter", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
git: true,
|
||||
init: async (dir) => {
|
||||
const skillDir = path.join(dir, ".opencode", "skill", "no-frontmatter")
|
||||
await Bun.write(
|
||||
path.join(skillDir, "SKILL.md"),
|
||||
`# No Frontmatter
|
||||
|
||||
Just some content without YAML frontmatter.
|
||||
`,
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const skills = await Skill.all()
|
||||
expect(skills).toEqual([])
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("discovers skills from .claude/skills/ directory", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
git: true,
|
||||
init: async (dir) => {
|
||||
const skillDir = path.join(dir, ".claude", "skills", "claude-skill")
|
||||
await Bun.write(
|
||||
path.join(skillDir, "SKILL.md"),
|
||||
`---
|
||||
name: claude-skill
|
||||
description: A skill in the .claude/skills directory.
|
||||
---
|
||||
|
||||
# Claude Skill
|
||||
`,
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const skills = await Skill.all()
|
||||
expect(skills.length).toBe(1)
|
||||
const claudeSkill = skills.find((s) => s.name === "claude-skill")
|
||||
expect(claudeSkill).toBeDefined()
|
||||
expect(claudeSkill!.location).toContain(path.join(".claude", "skills", "claude-skill", "SKILL.md"))
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("discovers global skills from ~/.claude/skills/ directory", async () => {
|
||||
await using tmp = await tmpdir({ git: true })
|
||||
|
||||
const originalHome = process.env.OPENCODE_TEST_HOME
|
||||
process.env.OPENCODE_TEST_HOME = tmp.path
|
||||
|
||||
try {
|
||||
await createGlobalSkill(tmp.path)
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const skills = await Skill.all()
|
||||
expect(skills.length).toBe(1)
|
||||
expect(skills[0].name).toBe("global-test-skill")
|
||||
expect(skills[0].description).toBe("A global skill from ~/.claude/skills for testing.")
|
||||
expect(skills[0].location).toContain(path.join(".claude", "skills", "global-test-skill", "SKILL.md"))
|
||||
},
|
||||
})
|
||||
} finally {
|
||||
process.env.OPENCODE_TEST_HOME = originalHome
|
||||
}
|
||||
})
|
||||
|
||||
test("returns empty array when no skills exist", async () => {
|
||||
await using tmp = await tmpdir({ git: true })
|
||||
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const skills = await Skill.all()
|
||||
expect(skills).toEqual([])
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("discovers skills from .agents/skills/ directory", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
git: true,
|
||||
init: async (dir) => {
|
||||
const skillDir = path.join(dir, ".agents", "skills", "agent-skill")
|
||||
await Bun.write(
|
||||
path.join(skillDir, "SKILL.md"),
|
||||
`---
|
||||
name: agent-skill
|
||||
description: A skill in the .agents/skills directory.
|
||||
---
|
||||
|
||||
# Agent Skill
|
||||
`,
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const skills = await Skill.all()
|
||||
expect(skills.length).toBe(1)
|
||||
const agentSkill = skills.find((s) => s.name === "agent-skill")
|
||||
expect(agentSkill).toBeDefined()
|
||||
expect(agentSkill!.location).toContain(path.join(".agents", "skills", "agent-skill", "SKILL.md"))
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("discovers global skills from ~/.agents/skills/ directory", async () => {
|
||||
await using tmp = await tmpdir({ git: true })
|
||||
|
||||
const originalHome = process.env.OPENCODE_TEST_HOME
|
||||
process.env.OPENCODE_TEST_HOME = tmp.path
|
||||
|
||||
try {
|
||||
const skillDir = path.join(tmp.path, ".agents", "skills", "global-agent-skill")
|
||||
await fs.mkdir(skillDir, { recursive: true })
|
||||
await Bun.write(
|
||||
path.join(skillDir, "SKILL.md"),
|
||||
`---
|
||||
name: global-agent-skill
|
||||
description: A global skill from ~/.agents/skills for testing.
|
||||
---
|
||||
|
||||
# Global Agent Skill
|
||||
|
||||
This skill is loaded from the global home directory.
|
||||
`,
|
||||
)
|
||||
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const skills = await Skill.all()
|
||||
expect(skills.length).toBe(1)
|
||||
expect(skills[0].name).toBe("global-agent-skill")
|
||||
expect(skills[0].description).toBe("A global skill from ~/.agents/skills for testing.")
|
||||
expect(skills[0].location).toContain(path.join(".agents", "skills", "global-agent-skill", "SKILL.md"))
|
||||
},
|
||||
})
|
||||
} finally {
|
||||
process.env.OPENCODE_TEST_HOME = originalHome
|
||||
}
|
||||
})
|
||||
|
||||
test("discovers skills from both .claude/skills/ and .agents/skills/", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
git: true,
|
||||
init: async (dir) => {
|
||||
const claudeDir = path.join(dir, ".claude", "skills", "claude-skill")
|
||||
const agentDir = path.join(dir, ".agents", "skills", "agent-skill")
|
||||
await Bun.write(
|
||||
path.join(claudeDir, "SKILL.md"),
|
||||
`---
|
||||
name: claude-skill
|
||||
description: A skill in the .claude/skills directory.
|
||||
---
|
||||
|
||||
# Claude Skill
|
||||
`,
|
||||
)
|
||||
await Bun.write(
|
||||
path.join(agentDir, "SKILL.md"),
|
||||
`---
|
||||
name: agent-skill
|
||||
description: A skill in the .agents/skills directory.
|
||||
---
|
||||
|
||||
# Agent Skill
|
||||
`,
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const skills = await Skill.all()
|
||||
expect(skills.length).toBe(2)
|
||||
expect(skills.find((s) => s.name === "claude-skill")).toBeDefined()
|
||||
expect(skills.find((s) => s.name === "agent-skill")).toBeDefined()
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("properly resolves directories that skills live in", async () => {
|
||||
await using tmp = await tmpdir({
|
||||
git: true,
|
||||
init: async (dir) => {
|
||||
const opencodeSkillDir = path.join(dir, ".opencode", "skill", "agent-skill")
|
||||
const opencodeSkillsDir = path.join(dir, ".opencode", "skills", "agent-skill")
|
||||
const claudeDir = path.join(dir, ".claude", "skills", "claude-skill")
|
||||
const agentDir = path.join(dir, ".agents", "skills", "agent-skill")
|
||||
await Bun.write(
|
||||
path.join(claudeDir, "SKILL.md"),
|
||||
`---
|
||||
name: claude-skill
|
||||
description: A skill in the .claude/skills directory.
|
||||
---
|
||||
|
||||
# Claude Skill
|
||||
`,
|
||||
)
|
||||
await Bun.write(
|
||||
path.join(agentDir, "SKILL.md"),
|
||||
`---
|
||||
name: agent-skill
|
||||
description: A skill in the .agents/skills directory.
|
||||
---
|
||||
|
||||
# Agent Skill
|
||||
`,
|
||||
)
|
||||
await Bun.write(
|
||||
path.join(opencodeSkillDir, "SKILL.md"),
|
||||
`---
|
||||
name: opencode-skill
|
||||
description: A skill in the .opencode/skill directory.
|
||||
---
|
||||
|
||||
# OpenCode Skill
|
||||
`,
|
||||
)
|
||||
await Bun.write(
|
||||
path.join(opencodeSkillsDir, "SKILL.md"),
|
||||
`---
|
||||
name: opencode-skill
|
||||
description: A skill in the .opencode/skills directory.
|
||||
---
|
||||
|
||||
# OpenCode Skill
|
||||
`,
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
await Instance.provide({
|
||||
directory: tmp.path,
|
||||
fn: async () => {
|
||||
const dirs = await Skill.dirs()
|
||||
expect(dirs.length).toBe(4)
|
||||
},
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user