From 499952826fc14fd92e5dbf9e332c81eccc6c7c86 Mon Sep 17 00:00:00 2001 From: Railly Date: Tue, 7 Apr 2026 10:18:26 -0500 Subject: [PATCH] fix(init): delegate skills scope + agent picker to skills CLI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The skills CLI already auto-detects installed agents and shows a scope picker (project vs global) when run interactively. We were stomping on both by passing `--agent '*' -y`, which forced install to all 45 supported agents non-interactively and dropped the user into a project-scoped install with 30+ agent folders cluttering the repo and ~25 lines added to .gitignore. Fix: - In interactive human mode, drop both `--agent` and `-y` so the skills CLI's native UX takes over (auto-detect + scope picker + agent multi-select). - In non-interactive mode (agent mode or `clerk init -y`), pass `-y -g` so it runs unattended with global scope and only the agents the user actually has installed. - Inherit stdin so the picker actually works in interactive mode. `clerk init` keeps its single opt-in prompt upfront. Everything past that — scope, agents — is the user's call via the skills CLI's native interface. Extracted `buildSkillsArgs` as a pure function so the flag logic is unit-testable without mocking Bun.spawn. Reported by Rafa. Closes AIE-791 --- .../cli-core/src/commands/init/skills.test.ts | 37 +++++++++++++++++++ packages/cli-core/src/commands/init/skills.ts | 33 ++++++++++++----- 2 files changed, 61 insertions(+), 9 deletions(-) create mode 100644 packages/cli-core/src/commands/init/skills.test.ts diff --git a/packages/cli-core/src/commands/init/skills.test.ts b/packages/cli-core/src/commands/init/skills.test.ts new file mode 100644 index 00000000..5690b44b --- /dev/null +++ b/packages/cli-core/src/commands/init/skills.test.ts @@ -0,0 +1,37 @@ +import { test, expect, describe } from "bun:test"; +import { buildSkillsArgs } from "./skills.ts"; + +describe("buildSkillsArgs", () => { + const skills = ["clerk", "clerk-setup", "clerk-nextjs-patterns"]; + + test("interactive mode: no -y or -g, lets skills CLI take over", () => { + const args = buildSkillsArgs(skills, true); + expect(args).toEqual([ + "npx", + "skills", + "add", + "clerk/skills", + "--skill", + "clerk", + "--skill", + "clerk-setup", + "--skill", + "clerk-nextjs-patterns", + ]); + expect(args).not.toContain("-y"); + expect(args).not.toContain("-g"); + expect(args).not.toContain("--agent"); + }); + + test("non-interactive mode: includes -y and -g for global auto-detect", () => { + const args = buildSkillsArgs(skills, false); + expect(args).toContain("-y"); + expect(args).toContain("-g"); + expect(args).not.toContain("--agent"); + }); + + test("never passes --agent (lets skills CLI auto-detect)", () => { + expect(buildSkillsArgs(skills, true)).not.toContain("--agent"); + expect(buildSkillsArgs(skills, false)).not.toContain("--agent"); + }); +}); diff --git a/packages/cli-core/src/commands/init/skills.ts b/packages/cli-core/src/commands/init/skills.ts index 7f818ddd..6f29fd1f 100644 --- a/packages/cli-core/src/commands/init/skills.ts +++ b/packages/cli-core/src/commands/init/skills.ts @@ -36,6 +36,21 @@ function resolveSkills(frameworkDep: string | undefined): string[] { return skills; } +/** + * Build the argv for `npx skills add`. + * + * Interactive mode: hand off to the skills CLI's native UX (auto-detect + * installed agents, scope picker). Non-interactive: pass `-y -g` so it + * runs unattended with global scope and auto-detected agents. + * + * Exported for tests. + */ +export function buildSkillsArgs(skills: string[], interactive: boolean): string[] { + const skillFlags = skills.flatMap((s) => ["--skill", s]); + const extraFlags = interactive ? [] : ["-y", "-g"]; + return ["npx", "skills", "add", SKILLS_SOURCE, ...skillFlags, ...extraFlags]; +} + export async function installSkills( cwd: string, frameworkDep: string | undefined, @@ -54,15 +69,15 @@ export async function installSkills( console.log(`\nInstalling skills: ${cyan(skillList)}`); - const skillFlags = skills.flatMap((s) => ["--skill", s]); - const proc = Bun.spawn( - ["npx", "skills", "add", SKILLS_SOURCE, ...skillFlags, "--agent", "*", "-y"], - { - cwd, - stdout: "inherit", - stderr: "inherit", - }, - ); + const interactive = isHuman() && !skipPrompt; + const args = buildSkillsArgs(skills, interactive); + + const proc = Bun.spawn(args, { + cwd, + stdin: "inherit", + stdout: "inherit", + stderr: "inherit", + }); const exitCode = await proc.exited; if (exitCode !== 0) {