From d2d154137743356113b3692f8dbfba706cf6668c Mon Sep 17 00:00:00 2001 From: Sami Jawhar Date: Fri, 3 Apr 2026 20:43:18 +0000 Subject: [PATCH] fix(skill): pass directory to getAllSkills and fix async test timing --- .../opencode-skill-loader/skill-discovery.ts | 3 ++- src/plugin/tool-registry.ts | 1 + .../skill/async-description-refresh.test.ts | 23 +++++++++++++++---- src/tools/skill/tools.ts | 5 ++-- src/tools/skill/types.ts | 2 ++ 5 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/features/opencode-skill-loader/skill-discovery.ts b/src/features/opencode-skill-loader/skill-discovery.ts index 954490842..4e3d0c648 100644 --- a/src/features/opencode-skill-loader/skill-discovery.ts +++ b/src/features/opencode-skill-loader/skill-discovery.ts @@ -12,7 +12,8 @@ export function clearSkillCache(): void { export async function getAllSkills(options?: SkillResolutionOptions): Promise { const browserProvider = options?.browserProvider ?? "playwright" const teamModeEnabled = options?.teamModeEnabled ?? false - const cacheKey = `${browserProvider}:${teamModeEnabled ? "team-on" : "team-off"}` + const directory = options?.directory ?? "" + const cacheKey = `${directory}:${browserProvider}:${teamModeEnabled ? "team-on" : "team-off"}` const hasDisabledSkills = options?.disabledSkills && options.disabledSkills.size > 0 // Skip cache if disabledSkills is provided (varies between calls) diff --git a/src/plugin/tool-registry.ts b/src/plugin/tool-registry.ts index 1ad6ced34..936bac67e 100644 --- a/src/plugin/tool-registry.ts +++ b/src/plugin/tool-registry.ts @@ -273,6 +273,7 @@ export function createToolRegistry(args: { enabledPluginsOverride: pluginConfig.claude_code?.plugins_override, }) const skillTool = factories.createSkillTool({ + directory: ctx.directory, commands, skills: skillContext.mergedSkills, mcpManager: managers.skillMcpManager, diff --git a/src/tools/skill/async-description-refresh.test.ts b/src/tools/skill/async-description-refresh.test.ts index 958457b6b..54ef1eeb1 100644 --- a/src/tools/skill/async-description-refresh.test.ts +++ b/src/tools/skill/async-description-refresh.test.ts @@ -1,6 +1,10 @@ /// -import { describe, expect, it } from "bun:test" +import { describe, expect, it, beforeEach, afterEach } from "bun:test" +import { mkdtempSync, rmSync } from "node:fs" +import { join } from "node:path" +import { tmpdir } from "node:os" +import { createSkillTool } from "./tools" import type { LoadedSkill } from "../../features/opencode-skill-loader/types" function requireFresh(modulePath: string): T { @@ -11,7 +15,7 @@ function requireFresh(modulePath: string): T { return require(modulePath) as T } -function createSkillTool(...args: Parameters): ReturnType { +function createFreshSkillTool(...args: Parameters): ReturnType { return requireFresh("./tools").createSkillTool(...args) } @@ -35,17 +39,28 @@ async function waitForRefresh(predicate: () => boolean): Promise { return } - await new Promise((resolve) => setTimeout(resolve, 10)) + await new Promise((resolve) => setTimeout(resolve, 50)) } throw new Error("Timed out waiting for async skill description refresh") } describe("skill tool - async native skill description refresh", () => { + let testDir: string + + beforeEach(() => { + testDir = mkdtempSync(join(tmpdir(), "skill-async-test-")) + }) + + afterEach(() => { + rmSync(testDir, { recursive: true, force: true }) + }) + it("updates description after async native skills resolve", async () => { //#given let allCallCount = 0 - const tool = createSkillTool({ + const tool = createFreshSkillTool({ + directory: testDir, skills: [createMockSkill("seeded-skill")], commands: [], nativeSkills: { diff --git a/src/tools/skill/tools.ts b/src/tools/skill/tools.ts index 0d4067505..0c3bc9fc6 100644 --- a/src/tools/skill/tools.ts +++ b/src/tools/skill/tools.ts @@ -25,7 +25,7 @@ import { mergeNativeSkills, } from "./native-skills" -export function createSkillTool(options: SkillLoadOptions = {}): ToolDefinition { +export function createSkillTool(options: SkillLoadOptions): ToolDefinition { let cachedDescription: string | null = null const getSkills = async (context?: ToolContext): Promise => { @@ -37,6 +37,7 @@ export function createSkillTool(options: SkillLoadOptions = {}): ToolDefinition disabledSkills: options?.disabledSkills, browserProvider: options?.browserProvider, teamModeEnabled: options?.teamModeEnabled, + directory: options.directory, })) ?? [] const allSkills = options.skills ? [...options.skills] : discovered @@ -191,4 +192,4 @@ export function createSkillTool(options: SkillLoadOptions = {}): ToolDefinition }) } -export const skill: ToolDefinition = createSkillTool() +export const skill: ToolDefinition = createSkillTool({ directory: process.cwd() }) diff --git a/src/tools/skill/types.ts b/src/tools/skill/types.ts index 3152a0141..da8739023 100644 --- a/src/tools/skill/types.ts +++ b/src/tools/skill/types.ts @@ -33,6 +33,8 @@ export interface SkillLoadOptions { /** Git master configuration for watermark/co-author settings */ gitMasterConfig?: GitMasterConfig disabledSkills?: Set + /** Project directory for skill discovery and base directory resolution. Must be ctx.directory from PluginContext — process.cwd() is unsafe in OpenCode. */ + directory: string /** Browser automation provider for provider-gated skill filtering */ browserProvider?: BrowserAutomationProvider /** Whether team mode built-in docs should be exposed */