fix(skill): pass directory to getAllSkills and fix async test timing

This commit is contained in:
Sami Jawhar
2026-04-03 20:43:18 +00:00
parent f540249838
commit d2d1541377
5 changed files with 27 additions and 7 deletions
@@ -12,7 +12,8 @@ export function clearSkillCache(): void {
export async function getAllSkills(options?: SkillResolutionOptions): Promise<LoadedSkill[]> { export async function getAllSkills(options?: SkillResolutionOptions): Promise<LoadedSkill[]> {
const browserProvider = options?.browserProvider ?? "playwright" const browserProvider = options?.browserProvider ?? "playwright"
const teamModeEnabled = options?.teamModeEnabled ?? false 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 const hasDisabledSkills = options?.disabledSkills && options.disabledSkills.size > 0
// Skip cache if disabledSkills is provided (varies between calls) // Skip cache if disabledSkills is provided (varies between calls)
+1
View File
@@ -273,6 +273,7 @@ export function createToolRegistry(args: {
enabledPluginsOverride: pluginConfig.claude_code?.plugins_override, enabledPluginsOverride: pluginConfig.claude_code?.plugins_override,
}) })
const skillTool = factories.createSkillTool({ const skillTool = factories.createSkillTool({
directory: ctx.directory,
commands, commands,
skills: skillContext.mergedSkills, skills: skillContext.mergedSkills,
mcpManager: managers.skillMcpManager, mcpManager: managers.skillMcpManager,
@@ -1,6 +1,10 @@
/// <reference types="bun-types" /> /// <reference types="bun-types" />
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" import type { LoadedSkill } from "../../features/opencode-skill-loader/types"
function requireFresh<T>(modulePath: string): T { function requireFresh<T>(modulePath: string): T {
@@ -11,7 +15,7 @@ function requireFresh<T>(modulePath: string): T {
return require(modulePath) as T return require(modulePath) as T
} }
function createSkillTool(...args: Parameters<typeof import("./tools").createSkillTool>): ReturnType<typeof import("./tools").createSkillTool> { function createFreshSkillTool(...args: Parameters<typeof import("./tools").createSkillTool>): ReturnType<typeof import("./tools").createSkillTool> {
return requireFresh<typeof import("./tools")>("./tools").createSkillTool(...args) return requireFresh<typeof import("./tools")>("./tools").createSkillTool(...args)
} }
@@ -35,17 +39,28 @@ async function waitForRefresh(predicate: () => boolean): Promise<void> {
return return
} }
await new Promise<void>((resolve) => setTimeout(resolve, 10)) await new Promise<void>((resolve) => setTimeout(resolve, 50))
} }
throw new Error("Timed out waiting for async skill description refresh") throw new Error("Timed out waiting for async skill description refresh")
} }
describe("skill tool - async native 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 () => { it("updates description after async native skills resolve", async () => {
//#given //#given
let allCallCount = 0 let allCallCount = 0
const tool = createSkillTool({ const tool = createFreshSkillTool({
directory: testDir,
skills: [createMockSkill("seeded-skill")], skills: [createMockSkill("seeded-skill")],
commands: [], commands: [],
nativeSkills: { nativeSkills: {
+3 -2
View File
@@ -25,7 +25,7 @@ import {
mergeNativeSkills, mergeNativeSkills,
} from "./native-skills" } from "./native-skills"
export function createSkillTool(options: SkillLoadOptions = {}): ToolDefinition { export function createSkillTool(options: SkillLoadOptions): ToolDefinition {
let cachedDescription: string | null = null let cachedDescription: string | null = null
const getSkills = async (context?: ToolContext): Promise<LoadedSkill[]> => { const getSkills = async (context?: ToolContext): Promise<LoadedSkill[]> => {
@@ -37,6 +37,7 @@ export function createSkillTool(options: SkillLoadOptions = {}): ToolDefinition
disabledSkills: options?.disabledSkills, disabledSkills: options?.disabledSkills,
browserProvider: options?.browserProvider, browserProvider: options?.browserProvider,
teamModeEnabled: options?.teamModeEnabled, teamModeEnabled: options?.teamModeEnabled,
directory: options.directory,
})) ?? [] })) ?? []
const allSkills = options.skills ? [...options.skills] : discovered 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() })
+2
View File
@@ -33,6 +33,8 @@ export interface SkillLoadOptions {
/** Git master configuration for watermark/co-author settings */ /** Git master configuration for watermark/co-author settings */
gitMasterConfig?: GitMasterConfig gitMasterConfig?: GitMasterConfig
disabledSkills?: Set<string> disabledSkills?: Set<string>
/** 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 */ /** Browser automation provider for provider-gated skill filtering */
browserProvider?: BrowserAutomationProvider browserProvider?: BrowserAutomationProvider
/** Whether team mode built-in docs should be exposed */ /** Whether team mode built-in docs should be exposed */