Merge pull request #1809 from willy-scr/fix/project-skills-process-cwd

fix(skills): use directory param instead of process.cwd() for project skill discovery
This commit is contained in:
YeonGyu-Kim 2026-02-13 18:18:15 +09:00 committed by GitHub
commit f722fe6877
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 41 additions and 38 deletions

View File

@ -78,8 +78,8 @@ export function loadUserAgents(): Record<string, AgentConfig> {
return result return result
} }
export function loadProjectAgents(): Record<string, AgentConfig> { export function loadProjectAgents(directory?: string): Record<string, AgentConfig> {
const projectAgentsDir = join(process.cwd(), ".claude", "agents") const projectAgentsDir = join(directory ?? process.cwd(), ".claude", "agents")
const agents = loadAgentsFromDir(projectAgentsDir, "project") const agents = loadAgentsFromDir(projectAgentsDir, "project")
const result: Record<string, AgentConfig> = {} const result: Record<string, AgentConfig> = {}

View File

@ -114,8 +114,8 @@ export async function loadUserCommands(): Promise<Record<string, CommandDefiniti
return commandsToRecord(commands) return commandsToRecord(commands)
} }
export async function loadProjectCommands(): Promise<Record<string, CommandDefinition>> { export async function loadProjectCommands(directory?: string): Promise<Record<string, CommandDefinition>> {
const projectCommandsDir = join(process.cwd(), ".claude", "commands") const projectCommandsDir = join(directory ?? process.cwd(), ".claude", "commands")
const commands = await loadCommandsFromDir(projectCommandsDir, "project") const commands = await loadCommandsFromDir(projectCommandsDir, "project")
return commandsToRecord(commands) return commandsToRecord(commands)
} }
@ -127,18 +127,18 @@ export async function loadOpencodeGlobalCommands(): Promise<Record<string, Comma
return commandsToRecord(commands) return commandsToRecord(commands)
} }
export async function loadOpencodeProjectCommands(): Promise<Record<string, CommandDefinition>> { export async function loadOpencodeProjectCommands(directory?: string): Promise<Record<string, CommandDefinition>> {
const opencodeProjectDir = join(process.cwd(), ".opencode", "command") const opencodeProjectDir = join(directory ?? process.cwd(), ".opencode", "command")
const commands = await loadCommandsFromDir(opencodeProjectDir, "opencode-project") const commands = await loadCommandsFromDir(opencodeProjectDir, "opencode-project")
return commandsToRecord(commands) return commandsToRecord(commands)
} }
export async function loadAllCommands(): Promise<Record<string, CommandDefinition>> { export async function loadAllCommands(directory?: string): Promise<Record<string, CommandDefinition>> {
const [user, project, global, projectOpencode] = await Promise.all([ const [user, project, global, projectOpencode] = await Promise.all([
loadUserCommands(), loadUserCommands(),
loadProjectCommands(), loadProjectCommands(directory),
loadOpencodeGlobalCommands(), loadOpencodeGlobalCommands(),
loadOpencodeProjectCommands(), loadOpencodeProjectCommands(directory),
]) ])
return { ...projectOpencode, ...global, ...project, ...user } return { ...projectOpencode, ...global, ...project, ...user }
} }

View File

@ -13,8 +13,8 @@ export async function loadUserSkills(): Promise<Record<string, CommandDefinition
return skillsToCommandDefinitionRecord(skills) return skillsToCommandDefinitionRecord(skills)
} }
export async function loadProjectSkills(): Promise<Record<string, CommandDefinition>> { export async function loadProjectSkills(directory?: string): Promise<Record<string, CommandDefinition>> {
const projectSkillsDir = join(process.cwd(), ".claude", "skills") const projectSkillsDir = join(directory ?? process.cwd(), ".claude", "skills")
const skills = await loadSkillsFromDir({ skillsDir: projectSkillsDir, scope: "project" }) const skills = await loadSkillsFromDir({ skillsDir: projectSkillsDir, scope: "project" })
return skillsToCommandDefinitionRecord(skills) return skillsToCommandDefinitionRecord(skills)
} }
@ -26,21 +26,22 @@ export async function loadOpencodeGlobalSkills(): Promise<Record<string, Command
return skillsToCommandDefinitionRecord(skills) return skillsToCommandDefinitionRecord(skills)
} }
export async function loadOpencodeProjectSkills(): Promise<Record<string, CommandDefinition>> { export async function loadOpencodeProjectSkills(directory?: string): Promise<Record<string, CommandDefinition>> {
const opencodeProjectDir = join(process.cwd(), ".opencode", "skills") const opencodeProjectDir = join(directory ?? process.cwd(), ".opencode", "skills")
const skills = await loadSkillsFromDir({ skillsDir: opencodeProjectDir, scope: "opencode-project" }) const skills = await loadSkillsFromDir({ skillsDir: opencodeProjectDir, scope: "opencode-project" })
return skillsToCommandDefinitionRecord(skills) return skillsToCommandDefinitionRecord(skills)
} }
export interface DiscoverSkillsOptions { export interface DiscoverSkillsOptions {
includeClaudeCodePaths?: boolean includeClaudeCodePaths?: boolean
directory?: string
} }
export async function discoverAllSkills(): Promise<LoadedSkill[]> { export async function discoverAllSkills(directory?: string): Promise<LoadedSkill[]> {
const [opencodeProjectSkills, opencodeGlobalSkills, projectSkills, userSkills] = await Promise.all([ const [opencodeProjectSkills, opencodeGlobalSkills, projectSkills, userSkills] = await Promise.all([
discoverOpencodeProjectSkills(), discoverOpencodeProjectSkills(directory),
discoverOpencodeGlobalSkills(), discoverOpencodeGlobalSkills(),
discoverProjectClaudeSkills(), discoverProjectClaudeSkills(directory),
discoverUserClaudeSkills(), discoverUserClaudeSkills(),
]) ])
@ -49,10 +50,10 @@ export async function discoverAllSkills(): Promise<LoadedSkill[]> {
} }
export async function discoverSkills(options: DiscoverSkillsOptions = {}): Promise<LoadedSkill[]> { export async function discoverSkills(options: DiscoverSkillsOptions = {}): Promise<LoadedSkill[]> {
const { includeClaudeCodePaths = true } = options const { includeClaudeCodePaths = true, directory } = options
const [opencodeProjectSkills, opencodeGlobalSkills] = await Promise.all([ const [opencodeProjectSkills, opencodeGlobalSkills] = await Promise.all([
discoverOpencodeProjectSkills(), discoverOpencodeProjectSkills(directory),
discoverOpencodeGlobalSkills(), discoverOpencodeGlobalSkills(),
]) ])
@ -62,7 +63,7 @@ export async function discoverSkills(options: DiscoverSkillsOptions = {}): Promi
} }
const [projectSkills, userSkills] = await Promise.all([ const [projectSkills, userSkills] = await Promise.all([
discoverProjectClaudeSkills(), discoverProjectClaudeSkills(directory),
discoverUserClaudeSkills(), discoverUserClaudeSkills(),
]) ])
@ -80,8 +81,8 @@ export async function discoverUserClaudeSkills(): Promise<LoadedSkill[]> {
return loadSkillsFromDir({ skillsDir: userSkillsDir, scope: "user" }) return loadSkillsFromDir({ skillsDir: userSkillsDir, scope: "user" })
} }
export async function discoverProjectClaudeSkills(): Promise<LoadedSkill[]> { export async function discoverProjectClaudeSkills(directory?: string): Promise<LoadedSkill[]> {
const projectSkillsDir = join(process.cwd(), ".claude", "skills") const projectSkillsDir = join(directory ?? process.cwd(), ".claude", "skills")
return loadSkillsFromDir({ skillsDir: projectSkillsDir, scope: "project" }) return loadSkillsFromDir({ skillsDir: projectSkillsDir, scope: "project" })
} }
@ -91,7 +92,7 @@ export async function discoverOpencodeGlobalSkills(): Promise<LoadedSkill[]> {
return loadSkillsFromDir({ skillsDir: opencodeSkillsDir, scope: "opencode" }) return loadSkillsFromDir({ skillsDir: opencodeSkillsDir, scope: "opencode" })
} }
export async function discoverOpencodeProjectSkills(): Promise<LoadedSkill[]> { export async function discoverOpencodeProjectSkills(directory?: string): Promise<LoadedSkill[]> {
const opencodeProjectDir = join(process.cwd(), ".opencode", "skills") const opencodeProjectDir = join(directory ?? process.cwd(), ".opencode", "skills")
return loadSkillsFromDir({ skillsDir: opencodeProjectDir, scope: "opencode-project" }) return loadSkillsFromDir({ skillsDir: opencodeProjectDir, scope: "opencode-project" })
} }

View File

@ -20,7 +20,7 @@ export async function getAllSkills(options?: SkillResolutionOptions): Promise<Lo
} }
const [discoveredSkills, builtinSkillDefinitions] = await Promise.all([ const [discoveredSkills, builtinSkillDefinitions] = await Promise.all([
discoverSkills({ includeClaudeCodePaths: true }), discoverSkills({ includeClaudeCodePaths: true, directory: options?.directory }),
Promise.resolve( Promise.resolve(
createBuiltinSkills({ createBuiltinSkills({
browserProvider: options?.browserProvider, browserProvider: options?.browserProvider,

View File

@ -4,4 +4,6 @@ export interface SkillResolutionOptions {
gitMasterConfig?: GitMasterConfig gitMasterConfig?: GitMasterConfig
browserProvider?: BrowserAutomationProvider browserProvider?: BrowserAutomationProvider
disabledSkills?: Set<string> disabledSkills?: Set<string>
/** Project directory to discover project-level skills from. Falls back to process.cwd() if not provided. */
directory?: string
} }

View File

@ -47,10 +47,10 @@ export async function applyAgentConfig(params: {
}), }),
includeClaudeSkillsForAwareness ? discoverUserClaudeSkills() : Promise.resolve([]), includeClaudeSkillsForAwareness ? discoverUserClaudeSkills() : Promise.resolve([]),
includeClaudeSkillsForAwareness includeClaudeSkillsForAwareness
? discoverProjectClaudeSkills() ? discoverProjectClaudeSkills(params.ctx.directory)
: Promise.resolve([]), : Promise.resolve([]),
discoverOpencodeGlobalSkills(), discoverOpencodeGlobalSkills(),
discoverOpencodeProjectSkills(), discoverOpencodeProjectSkills(params.ctx.directory),
]); ]);
const allDiscoveredSkills = [ const allDiscoveredSkills = [
@ -84,7 +84,7 @@ export async function applyAgentConfig(params: {
const includeClaudeAgents = params.pluginConfig.claude_code?.agents ?? true; const includeClaudeAgents = params.pluginConfig.claude_code?.agents ?? true;
const userAgents = includeClaudeAgents ? loadUserAgents() : {}; const userAgents = includeClaudeAgents ? loadUserAgents() : {};
const projectAgents = includeClaudeAgents ? loadProjectAgents() : {}; const projectAgents = includeClaudeAgents ? loadProjectAgents(params.ctx.directory) : {};
const rawPluginAgents = params.pluginComponents.agents; const rawPluginAgents = params.pluginComponents.agents;
const pluginAgents = Object.fromEntries( const pluginAgents = Object.fromEntries(

View File

@ -44,13 +44,13 @@ export async function applyCommandConfig(params: {
configDir: params.ctx.directory, configDir: params.ctx.directory,
}), }),
includeClaudeCommands ? loadUserCommands() : Promise.resolve({}), includeClaudeCommands ? loadUserCommands() : Promise.resolve({}),
includeClaudeCommands ? loadProjectCommands() : Promise.resolve({}), includeClaudeCommands ? loadProjectCommands(params.ctx.directory) : Promise.resolve({}),
loadOpencodeGlobalCommands(), loadOpencodeGlobalCommands(),
loadOpencodeProjectCommands(), loadOpencodeProjectCommands(params.ctx.directory),
includeClaudeSkills ? loadUserSkills() : Promise.resolve({}), includeClaudeSkills ? loadUserSkills() : Promise.resolve({}),
includeClaudeSkills ? loadProjectSkills() : Promise.resolve({}), includeClaudeSkills ? loadProjectSkills(params.ctx.directory) : Promise.resolve({}),
loadOpencodeGlobalSkills(), loadOpencodeGlobalSkills(),
loadOpencodeProjectSkills(), loadOpencodeProjectSkills(params.ctx.directory),
]); ]);
params.config.command = { params.config.command = {

View File

@ -63,8 +63,8 @@ export async function createSkillContext(args: {
}), }),
includeClaudeSkills ? discoverUserClaudeSkills() : Promise.resolve([]), includeClaudeSkills ? discoverUserClaudeSkills() : Promise.resolve([]),
discoverOpencodeGlobalSkills(), discoverOpencodeGlobalSkills(),
includeClaudeSkills ? discoverProjectClaudeSkills() : Promise.resolve([]), includeClaudeSkills ? discoverProjectClaudeSkills(directory) : Promise.resolve([]),
discoverOpencodeProjectSkills(), discoverOpencodeProjectSkills(directory),
]) ])
const mergedSkills = mergeSkills( const mergedSkills = mergeSkills(

View File

@ -101,7 +101,7 @@ export function createToolRegistry(args: {
getSessionID: getSessionIDForMcp, getSessionID: getSessionIDForMcp,
}) })
const commands = discoverCommandsSync() const commands = discoverCommandsSync(ctx.directory)
const slashcommandTool = createSlashcommandTool({ const slashcommandTool = createSlashcommandTool({
commands, commands,
skills: skillContext.mergedSkills, skills: skillContext.mergedSkills,

View File

@ -48,12 +48,12 @@ function discoverCommandsFromDir(commandsDir: string, scope: CommandScope): Comm
return commands return commands
} }
export function discoverCommandsSync(): CommandInfo[] { export function discoverCommandsSync(directory?: string): CommandInfo[] {
const configDir = getOpenCodeConfigDir({ binary: "opencode" }) const configDir = getOpenCodeConfigDir({ binary: "opencode" })
const userCommandsDir = join(getClaudeConfigDir(), "commands") const userCommandsDir = join(getClaudeConfigDir(), "commands")
const projectCommandsDir = join(process.cwd(), ".claude", "commands") const projectCommandsDir = join(directory ?? process.cwd(), ".claude", "commands")
const opencodeGlobalDir = join(configDir, "command") const opencodeGlobalDir = join(configDir, "command")
const opencodeProjectDir = join(process.cwd(), ".opencode", "command") const opencodeProjectDir = join(directory ?? process.cwd(), ".opencode", "command")
const userCommands = discoverCommandsFromDir(userCommandsDir, "user") const userCommands = discoverCommandsFromDir(userCommandsDir, "user")
const opencodeGlobalCommands = discoverCommandsFromDir(opencodeGlobalDir, "opencode") const opencodeGlobalCommands = discoverCommandsFromDir(opencodeGlobalDir, "opencode")