diff --git a/cli/bin/commands/skills.mjs b/cli/bin/commands/skills.mjs index 63e4efc32..a314e239a 100644 --- a/cli/bin/commands/skills.mjs +++ b/cli/bin/commands/skills.mjs @@ -1288,15 +1288,18 @@ function providerAgentsUpToDate(bundleDir, root, provider, scope) { const srcDir = join(bundleDir, provider, 'agents'); if (!existsSync(srcDir)) return true; - const destDir = scope === 'user' - ? artifact.userDir(root) - : join(root, provider, 'agents'); + const projectDir = join(root, provider, 'agents'); + const destDirs = scope === 'user' + ? [artifact.userDir(root)] + : scope === 'project' || !isHomeDir(root) + ? [projectDir] + : [...new Set([artifact.userDir(root), projectDir])]; const agentFiles = readdirSync(srcDir).filter(name => name.endsWith(artifact.ext)); - return agentFiles.every(name => { + return agentFiles.every(name => destDirs.some(destDir => { const localPath = join(destDir, name); return existsSync(localPath) && hashSkillFile(join(srcDir, name)) === hashSkillFile(localPath); - }); + })); } function copyProviderAgents(bundleDir, root, providers, { scope, home = homedir() } = {}) { diff --git a/tests/skills-cli.test.js b/tests/skills-cli.test.js index bda4e03b2..fde99abac 100644 --- a/tests/skills-cli.test.js +++ b/tests/skills-cli.test.js @@ -308,6 +308,23 @@ describe('copyProviderAgents: Claude, Copilot, and Cursor subagents', () => { rmSync(home, { recursive: true, force: true }); }); + test('skills check accepts current Copilot user agents in a home-rooted checkout', () => { + const home = mkdtempSync(join(tmpdir(), 'imp-agents-check-home-')); + execSync('git init', { cwd: home }); + const bundleRoot = createFakeUniversalBundle(home, ['.github']); + const env = { ...process.env, HOME: home, IMPECCABLE_BUNDLE_PATH: bundleRoot }; + + run('skills install -y --scope=global --no-hooks --providers=github', { cwd: home, env }); + expect(existsSync(join(home, '.copilot', 'agents', 'impeccable-finish-reviewer.agent.md'))).toBe(true); + expect(existsSync(join(home, '.github', 'agents'))).toBe(false); + + const output = run('skills check', { cwd: home, env }); + expect(output).toContain('Skills are up to date'); + expect(output).not.toContain('Updates available'); + + rmSync(home, { recursive: true, force: true }); + }, 15000); + test('project scope reports user-level Copilot agents that shadow the installed ones; Cursor never does (project wins there)', () => { const tmp = mkdtempSync(join(tmpdir(), 'imp-agents-shadow-')); const home = mkdtempSync(join(tmpdir(), 'imp-agents-shadow-home-'));