@pasajero_0/agent-stack 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts","../src/commands/init.ts","../src/detect/project.ts","../src/claude/provider.ts","../src/utils/shell.ts","../src/utils/logger.ts","../src/mcp/catalog.ts","../src/mcp/installer.ts","../src/claude/harness.ts","../src/detect/harness-params.ts","../src/commands/detect.ts","../src/commands/mcp.ts","../src/commands/generate.ts","../src/commands/update.ts","../src/commands/sync.ts","../src/index.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { initCommand } from \"./commands/init.js\";\nimport { detectCommand } from \"./commands/detect.js\";\nimport { mcpCommand } from \"./commands/mcp.js\";\nimport { generateCommand } from \"./commands/generate.js\";\nimport { updateCommand } from \"./commands/update.js\";\nimport { syncCommand } from \"./commands/sync.js\";\n\nexport const program = new Command();\n\nprogram\n .name(\"agent-stack\")\n .description(\"CLI that deploys a Claude Code harness and manages MCP servers\")\n .version(\"0.1.0\");\n\nprogram\n .command(\"init\")\n .description(\"Setup wizard: detect Claude Code, deploy the harness, install MCP servers\")\n .action(initCommand);\n\nprogram\n .command(\"detect\")\n .description(\"Detect the project and whether Claude Code is installed\")\n .action(detectCommand);\n\nconst mcp = program\n .command(\"mcp\")\n .description(\"Manage MCP servers\");\n\nmcp\n .command(\"install\")\n .description(\"Install and configure MCP servers for detected providers\")\n .action(() => mcpCommand(\"install\"));\n\nmcp\n .command(\"list\")\n .description(\"List configured MCP servers\")\n .action(() => mcpCommand(\"list\"));\n\nprogram\n .command(\"generate\")\n .description(\"Deploy the Claude harness into the current repo (fresh)\")\n .option(\"-f, --force\", \"Overwrite an existing .claude/ harness\")\n .action(generateCommand);\n\nprogram\n .command(\"update\")\n .description(\"Update an existing harness to the current version (preserves rules/ and tmp/)\")\n .option(\"--dry-run\", \"Show what would change without writing\")\n .action(updateCommand);\n\nprogram\n .command(\"sync\")\n .description(\"Detect Claude Code and generate or update the harness\")\n .action(syncCommand);\n","import { checkbox, input, confirm } from \"@inquirer/prompts\";\nimport chalk from \"chalk\";\nimport { detectProject } from \"../detect/project.js\";\nimport { detect, install } from \"../claude/provider.js\";\nimport { MCP_CATALOG } from \"../mcp/catalog.js\";\nimport type { McpServerDefinition } from \"../mcp/types.js\";\nimport { installMcpServers } from \"../mcp/installer.js\";\nimport { emitHarness } from \"../claude/harness.js\";\nimport { banner, log } from \"../utils/logger.js\";\n\nexport async function initCommand(): Promise<void> {\n banner();\n\n // ── Step 1: detect ────────────────────────────────────────────\n log.step(\"Detecting environment...\");\n\n const project = await detectProject(process.cwd());\n if (project.scenario === \"existing\") {\n const name = project.projectName ? chalk.cyan(project.projectName) : chalk.dim(\"unnamed\");\n log.info(`Existing project: ${name}`);\n } else {\n log.info(\"Empty directory — fresh setup\");\n }\n\n console.log();\n const info = await detect();\n const status = info.installed\n ? chalk.green(\" ✔ \" + info.displayName)\n : chalk.dim(\" ✖ \" + info.displayName);\n const version = info.version ? chalk.dim(` (${info.version})`) : \"\";\n console.log(`${status}${version}`);\n console.log();\n\n if (!info.installed) {\n log.warn(\"Claude Code is not installed.\");\n const doInstall = await confirm({ message: \"Install Claude Code now?\", default: true });\n if (doInstall) {\n await install();\n } else {\n log.error(\"Claude Code is required. Exiting.\");\n process.exit(1);\n }\n }\n\n // ── Step 2: deploy the Claude harness ─────────────────────────\n console.log();\n log.step(\"Generating the Claude harness...\");\n await emitHarness(process.cwd());\n\n // ── Step 3: MCP servers (optional) ────────────────────────────\n const { mcpServers, envValues } = await collectMcpConfig();\n if (mcpServers.length > 0) {\n console.log();\n await installMcpServers(mcpServers, envValues);\n }\n\n // ── Summary ───────────────────────────────────────────────────\n console.log();\n console.log(chalk.bold.green(\" Setup complete!\"));\n console.log();\n log.dim(\" Next steps:\");\n log.dim(\" • Exclude the harness from git: add .claude/, CLAUDE.md, CODEMAP.md to .git/info/exclude\");\n log.dim(\" • Generate rules: open `claude` and run the pattern-scout subagent (.claude/rules/ is empty by design)\");\n log.dim(\" • Smoke-test the guards: a `git push` or foreign package-manager command should block\");\n console.log();\n}\n\nasync function collectMcpConfig(): Promise<{\n mcpServers: McpServerDefinition[];\n envValues: Record<string, string>;\n}> {\n const selectedNames = await checkbox({\n message: \"Select MCP servers to install:\",\n choices: MCP_CATALOG.map((s) => ({\n name: `${s.displayName} — ${s.description}`,\n value: s.name,\n checked: !s.optional,\n })),\n });\n\n const mcpServers = MCP_CATALOG.filter((s) => selectedNames.includes(s.name));\n const envValues: Record<string, string> = {};\n\n for (const server of mcpServers) {\n if (server.envPrompts) {\n for (const [key, prompt] of Object.entries(server.envPrompts)) {\n const value = await input({ message: prompt + chalk.dim(\" (enter to skip)\") });\n envValues[key] = value || \"<your-token-here>\";\n }\n }\n }\n\n return { mcpServers, envValues };\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport interface ProjectContext {\n isExistingProject: boolean;\n hasPackageJson: boolean;\n hasSrcDir: boolean;\n hasGitRepo: boolean;\n projectName?: string;\n scenario: \"existing\" | \"empty\";\n}\n\nexport async function detectProject(dir: string): Promise<ProjectContext> {\n const hasPackageJson = existsSync(join(dir, \"package.json\"));\n const hasSrcDir = existsSync(join(dir, \"src\"));\n const hasGitRepo = existsSync(join(dir, \".git\"));\n\n const isExistingProject = hasPackageJson || hasSrcDir || hasGitRepo;\n\n let projectName: string | undefined;\n if (hasPackageJson) {\n try {\n const raw = await readFile(join(dir, \"package.json\"), \"utf-8\");\n const pkg = JSON.parse(raw);\n projectName = pkg.name;\n } catch {\n // ignore parse errors\n }\n }\n\n return {\n isExistingProject,\n hasPackageJson,\n hasSrcDir,\n hasGitRepo,\n projectName,\n scenario: isExistingProject ? \"existing\" : \"empty\",\n };\n}\n","import { homedir } from \"node:os\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { ProviderInfo } from \"./types.js\";\nimport type { McpServerDefinition, McpServerConfig } from \"../mcp/types.js\";\nimport { commandExists, run, runSilent } from \"../utils/shell.js\";\nimport { log } from \"../utils/logger.js\";\n\nexport const PROVIDER_ID = \"claude-code\";\nexport const PROVIDER_NAME = \"Claude Code\";\n\nexport async function detect(): Promise<ProviderInfo> {\n const home = homedir();\n const configPaths = [join(home, \".claude\"), join(home, \".config\", \"claude\")];\n\n const installed = await commandExists(\"claude\");\n let version: string | undefined;\n if (installed) {\n const result = await runSilent(\"claude\", [\"--version\"]);\n if (result.exitCode === 0) version = result.stdout.trim();\n }\n\n return {\n name: PROVIDER_ID,\n displayName: PROVIDER_NAME,\n installed,\n version,\n configPaths: configPaths.filter((p) => existsSync(p)),\n };\n}\n\nexport async function install(): Promise<void> {\n log.step(\"Installing Claude Code via npm...\");\n const result = await run(\"npm\", [\"install\", \"-g\", \"@anthropic-ai/claude-code\"]);\n if (result.exitCode !== 0) {\n throw new Error(`Failed to install Claude Code: ${result.stderr}`);\n }\n log.success(\"Claude Code installed successfully\");\n}\n\nexport async function configureMcp(\n servers: McpServerDefinition[],\n envValues: Record<string, string>\n): Promise<void> {\n for (const server of servers) {\n const args = [\"mcp\", \"add\", server.name, \"--transport\", server.transport];\n if (server.command) args.push(\"--\", server.command);\n if (server.args) args.push(...server.args);\n\n const env: Record<string, string> = {};\n if (server.env) {\n for (const key of Object.keys(server.env)) {\n if (envValues[key]) env[key] = envValues[key];\n }\n }\n const envArgs: string[] = [];\n for (const [key, value] of Object.entries(env)) {\n envArgs.push(\"-e\", `${key}=${value}`);\n }\n\n const result = await run(\"claude\", [...args, ...envArgs]);\n if (result.exitCode !== 0) {\n log.warn(`Failed to add MCP server \"${server.name}\": ${result.stderr}`);\n } else {\n log.success(`MCP server \"${server.displayName}\" configured`);\n }\n }\n}\n\nexport async function listMcp(): Promise<McpServerConfig[]> {\n const result = await runSilent(\"claude\", [\"mcp\", \"list\"]);\n if (result.exitCode !== 0) return [];\n\n const lines = result.stdout.trim().split(\"\\n\").filter(Boolean);\n return lines.map((line) => {\n const parts = line.split(/\\s+/);\n return { name: parts[0] ?? line, command: parts[1] ?? \"\", args: parts.slice(2) };\n });\n}\n","import { execa } from \"execa\";\n\nexport async function commandExists(cmd: string): Promise<boolean> {\n try {\n await execa(\"which\", [cmd]);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function run(\n cmd: string,\n args: string[],\n options?: { cwd?: string; env?: Record<string, string> }\n): Promise<{ stdout: string; stderr: string; exitCode: number }> {\n const result = await execa(cmd, args, {\n cwd: options?.cwd,\n env: options?.env,\n reject: false,\n });\n return {\n stdout: result.stdout as string,\n stderr: result.stderr as string,\n exitCode: result.exitCode ?? 1,\n };\n}\n\nexport async function runSilent(\n cmd: string,\n args: string[]\n): Promise<{ stdout: string; exitCode: number }> {\n const result = await execa(cmd, args, { reject: false });\n return { stdout: result.stdout as string, exitCode: result.exitCode ?? 1 };\n}\n","import chalk from \"chalk\";\nimport ora, { type Ora } from \"ora\";\n\nexport const log = {\n info: (msg: string) => console.log(chalk.blue(\"ℹ\"), msg),\n success: (msg: string) => console.log(chalk.green(\"✔\"), msg),\n warn: (msg: string) => console.log(chalk.yellow(\"⚠\"), msg),\n error: (msg: string) => console.error(chalk.red(\"✖\"), msg),\n step: (msg: string) => console.log(chalk.cyan(\"→\"), msg),\n dim: (msg: string) => console.log(chalk.dim(msg)),\n};\n\nexport function spinner(text: string): Ora {\n return ora({ text, color: \"cyan\" });\n}\n\nexport function banner(): void {\n console.log();\n console.log(chalk.bold.cyan(\" agent-stack\"));\n console.log(chalk.dim(\" AI coding environment configurator\"));\n console.log();\n}\n","import { readFileSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { McpServerDefinition } from \"./types.js\";\n\nfunction getPackageRoot(): string {\n // In bundled mode (dist/index.js), go up one level\n // In dev mode (src/mcp/catalog.ts), go up two levels\n const thisDir = dirname(fileURLToPath(import.meta.url));\n // Both cases: find mcp/catalog.json relative to package root\n // dist/ → .. is package root\n // src/mcp/ → ../.. is package root\n const candidates = [\n join(thisDir, \"..\", \"mcp\", \"catalog.json\"),\n join(thisDir, \"..\", \"..\", \"mcp\", \"catalog.json\"),\n ];\n for (const candidate of candidates) {\n try {\n return readFileSync(candidate, \"utf-8\");\n } catch {\n continue;\n }\n }\n throw new Error(\"Could not find mcp/catalog.json\");\n}\n\nconst catalogData = JSON.parse(getPackageRoot());\n\nexport const MCP_CATALOG: McpServerDefinition[] = catalogData;\n","import type { McpServerDefinition } from \"./types.js\";\nimport { spinner } from \"../utils/logger.js\";\nimport { configureMcp, PROVIDER_NAME } from \"../claude/provider.js\";\n\nexport async function installMcpServers(\n servers: McpServerDefinition[],\n envValues: Record<string, string>\n): Promise<void> {\n const s = spinner(`Configuring MCP servers for ${PROVIDER_NAME}...`);\n s.start();\n\n try {\n await configureMcp(servers, envValues);\n s.succeed(`MCP servers configured for ${PROVIDER_NAME}`);\n } catch (err) {\n s.fail(`Failed to configure MCP for ${PROVIDER_NAME}`);\n throw err;\n }\n}\n","import { readFileSync, readdirSync, statSync, existsSync } from \"node:fs\";\nimport { writeFile, mkdir, chmod } from \"node:fs/promises\";\nimport { join, dirname, relative, basename } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { GeneratedFile } from \"./types.js\";\nimport type { HarnessParams } from \"../detect/harness-params.js\";\nimport { detectHarnessParams } from \"../detect/harness-params.js\";\nimport { log } from \"../utils/logger.js\";\n\n/** Verbatim hooks block — correct Claude Code schema ({matcher, hooks:[{type,command}]}). */\nconst HOOKS_BLOCK = {\n PreToolUse: [\n {\n matcher: \"Bash\",\n hooks: [{ type: \"command\", command: \"$CLAUDE_PROJECT_DIR/.claude/hooks/guard-bash.sh\" }],\n },\n {\n matcher: \"Edit|Write|MultiEdit\",\n hooks: [{ type: \"command\", command: \"$CLAUDE_PROJECT_DIR/.claude/hooks/guard-file.sh\" }],\n },\n ],\n SessionStart: [\n {\n hooks: [\n { type: \"command\", command: \"$CLAUDE_PROJECT_DIR/.claude/hooks/session-start-context.sh\" },\n ],\n },\n ],\n Stop: [\n {\n hooks: [{ type: \"command\", command: \"$CLAUDE_PROJECT_DIR/.claude/hooks/stop-flag-reflect.sh\" }],\n },\n ],\n PostToolUse: [\n {\n matcher: \"Edit|Write|MultiEdit\",\n hooks: [\n { type: \"command\", command: \"$CLAUDE_PROJECT_DIR/.claude/hooks/post-edit-lint.sh\" },\n { type: \"command\", command: \"$CLAUDE_PROJECT_DIR/.claude/hooks/post-edit-verify.sh\" },\n ],\n },\n ],\n};\n\nfunction templatesRoot(): string {\n const thisDir = dirname(fileURLToPath(import.meta.url));\n const candidates = [\n join(thisDir, \"..\", \"templates\", \"claude\"), // dist/index.js -> ../templates/claude\n join(thisDir, \"..\", \"..\", \"templates\", \"claude\"), // src/claude/ -> ../../templates/claude\n ];\n for (const c of candidates) {\n if (existsSync(c)) return c;\n }\n throw new Error(\"Could not find templates/claude\");\n}\n\n/** agent-stack's own version — stamped into the deployed harness manifest. */\nfunction toolVersion(): string {\n const thisDir = dirname(fileURLToPath(import.meta.url));\n for (const c of [join(thisDir, \"..\", \"package.json\"), join(thisDir, \"..\", \"..\", \"package.json\")]) {\n try {\n return JSON.parse(readFileSync(c, \"utf-8\")).version ?? \"0.0.0\";\n } catch {\n continue;\n }\n }\n return \"0.0.0\";\n}\n\nfunction substitute(text: string, p: HarnessParams): string {\n return text\n .replaceAll(\"{{PM}}\", p.packageManager)\n .replaceAll(\"{{FORBIDDEN_PM}}\", p.forbiddenPms)\n .replaceAll(\"{{GEN_GLOBS}}\", p.generatedGlobs)\n .replaceAll(\"{{LOCKFILE}}\", p.lockfile)\n .replaceAll(\"{{DOCS_DIR}}\", p.docsDir)\n .replaceAll(\"{{MAIN_BRANCH}}\", p.mainBranch);\n}\n\nfunction walk(dir: string): string[] {\n const out: string[] = [];\n for (const name of readdirSync(dir)) {\n const full = join(dir, name);\n if (statSync(full).isDirectory()) out.push(...walk(full));\n else out.push(full);\n }\n return out;\n}\n\nfunction buildSettings(p: HarnessParams): string {\n const allow = [\n ...p.commands.map((c) => `Bash(${c}:*)`),\n \"Bash(git status:*)\",\n \"Bash(git diff:*)\",\n \"Bash(git log:*)\",\n \"Bash(git show:*)\",\n `Bash(${p.forgeCli} api:*)`,\n `Bash(${p.forgeCli} pr view:*)`,\n `Bash(${p.forgeCli} pr diff:*)`,\n \"WebSearch\",\n ];\n const settings = {\n $schema: \"https://json.schemastore.org/claude-code-settings.json\",\n permissions: { allow },\n hooks: HOOKS_BLOCK,\n };\n return JSON.stringify(settings, null, 2) + \"\\n\";\n}\n\nfunction buildSettingsLocal(p: HarnessParams): string {\n const settings = {\n permissions: {\n allow: [\"WebSearch\", `Bash(${p.forgeCli} api:*)`],\n deny: [\n \"Read(./**/dist/**)\",\n \"Read(./**/build/**)\",\n \"Read(./**/coverage/**)\",\n \"Read(./**/*.d.ts)\",\n \"Read(./**/*.map)\",\n \"Read(./**/*.gen.*)\",\n `Read(./**/${p.lockfile})`,\n \"Read(./**/node_modules/**)\",\n ],\n },\n };\n return JSON.stringify(settings, null, 2) + \"\\n\";\n}\n\nfunction buildClaudeMd(p: HarnessParams, root: string): string {\n const normative = readFileSync(join(root, \"_normative.md\"), \"utf-8\").replace(\n /^<!--[\\s\\S]*?-->\\s*/,\n \"\"\n );\n const cmds = p.commands.length\n ? `- Commands: ${p.commands.map((c) => `\\`${c}\\``).join(\", \")}.\\n`\n : \"\";\n const body = `# Project guide\n\n> Generated by agent-stack. Edit freely to describe your project.\n\n## Tooling\n\n- Package manager: **${p.packageManager}** only — other package managers are blocked by the guard-bash hook.\n- Default branch: \\`${p.mainBranch}\\`. \\`git push\\` is manual-only.\n- Never hand-edit generated files: ${p.generatedGlobs.split(\"|\").join(\", \")}, ${p.lockfile}.\n${cmds}\n## Subagent delegation\n\n- **task-analyzer** at the start of a non-trivial task.\n- **code-reviewer** after writing or modifying code.\n- **test-writer** for unit tests.\n- **pattern-scout** to (re)generate \\`.claude/rules/\\` after structural changes.\n\n`;\n return body + normative;\n}\n\nfunction buildCodemap(): string {\n return `# CODEMAP\n\n> Generated by agent-stack — replace with a real map of where things live (apps, packages, entry points).\n\n| Path | What |\n| --- | --- |\n| \\`src/\\` | source |\n| \\`tests/\\` | tests |\n\n## Harness (not committed)\n\n\\`.claude/\\`, \\`CLAUDE.md\\`, \\`CODEMAP.md\\` are git-excluded (\\`.git/info/exclude\\`) — personal harness, not project history.\n`;\n}\n\n/** Build the full harness file set (pure — no IO side effects on the target). */\nexport function buildHarnessFiles(params: HarnessParams): GeneratedFile[] {\n const root = templatesRoot();\n const files: GeneratedFile[] = [];\n\n for (const abs of walk(root)) {\n if (basename(abs).startsWith(\"_\")) continue; // generator input, not deployed\n const rel = relative(root, abs);\n const content = substitute(readFileSync(abs, \"utf-8\"), params);\n files.push({ path: join(\".claude\", rel), content, action: \"create\" });\n }\n\n files.push({ path: \".claude/settings.json\", content: buildSettings(params), action: \"create\" });\n files.push({\n path: \".claude/settings.local.json\",\n content: buildSettingsLocal(params),\n action: \"create\",\n });\n files.push({ path: \"CLAUDE.md\", content: buildClaudeMd(params, root), action: \"create\" });\n files.push({ path: \"CODEMAP.md\", content: buildCodemap(), action: \"create\" });\n files.push({\n path: \".claude/.harness.json\",\n content: JSON.stringify({ templateVersion: toolVersion(), params }, null, 2) + \"\\n\",\n action: \"create\",\n });\n\n return files;\n}\n\n/** Write a harness file set to disk (chmod +x hooks). Only touches the listed\n * (emitter-owned) paths — anything else under .claude/ (rules/, tmp/) is left intact. */\nexport async function writeHarnessFiles(\n projectDir: string,\n files: GeneratedFile[]\n): Promise<void> {\n for (const f of files) {\n const full = join(projectDir, f.path);\n await mkdir(dirname(full), { recursive: true });\n await writeFile(full, f.content, \"utf-8\");\n if (f.path.startsWith(\".claude/hooks/\") && f.path.endsWith(\".sh\")) {\n await chmod(full, 0o755);\n }\n log.success(f.path);\n }\n}\n\n/** Detect params, build the harness, write it to disk. */\nexport async function emitHarness(projectDir: string): Promise<GeneratedFile[]> {\n const params = await detectHarnessParams(projectDir);\n const files = buildHarnessFiles(params);\n await writeHarnessFiles(projectDir, files);\n return files;\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { run } from \"../utils/shell.js\";\n\n/**\n * Values the harness emitter substitutes into templates/claude/ placeholders.\n * MVP heuristics — see templates/claude/_TOKENS.md for the token contract.\n */\nexport interface HarnessParams {\n packageManager: string; // pnpm | npm | yarn | bun\n forbiddenPms: string; // regex alternation of the others, e.g. \"npm|yarn|bun\"\n lockfile: string; // pnpm-lock.yaml | package-lock.json | yarn.lock | bun.lockb\n generatedGlobs: string; // case-glob for guard-file, e.g. \"*/dist/*|dist/*|*.d.ts|*.map\"\n docsDir: string; // \"docs/\"\n mainBranch: string; // main | master | ...\n forgeCli: string; // gh | glab\n commands: string[]; // e.g. [\"pnpm typecheck\", \"pnpm test\", \"pnpm build\"]\n}\n\nconst PM_BY_LOCKFILE: Array<{ lock: string; pm: string }> = [\n { lock: \"pnpm-lock.yaml\", pm: \"pnpm\" },\n { lock: \"yarn.lock\", pm: \"yarn\" },\n { lock: \"bun.lockb\", pm: \"bun\" },\n { lock: \"package-lock.json\", pm: \"npm\" },\n];\n\nconst ALL_PMS = [\"npm\", \"yarn\", \"pnpm\", \"bun\"];\n\nexport function detectPackageManager(dir: string): {\n packageManager: string;\n lockfile: string;\n} {\n for (const { lock, pm } of PM_BY_LOCKFILE) {\n if (existsSync(join(dir, lock))) return { packageManager: pm, lockfile: lock };\n }\n return { packageManager: \"npm\", lockfile: \"package-lock.json\" };\n}\n\nexport function forbiddenPmsFor(pm: string): string {\n return ALL_PMS.filter((p) => p !== pm).join(\"|\");\n}\n\nexport function forgeFromRemote(remoteUrl: string): string {\n return /gitlab/i.test(remoteUrl) ? \"glab\" : \"gh\";\n}\n\nfunction generatedGlobsFor(dir: string): string {\n // TS projects emit .d.ts / .map alongside dist; non-TS just build/dist dirs.\n return existsSync(join(dir, \"tsconfig.json\"))\n ? \"*/dist/*|dist/*|*.d.ts|*.map\"\n : \"*/dist/*|dist/*|*/build/*\";\n}\n\nasync function detectGit(dir: string): Promise<{ mainBranch: string; forgeCli: string }> {\n let mainBranch = \"main\";\n let forgeCli = \"gh\";\n\n const head = await run(\"git\", [\"symbolic-ref\", \"refs/remotes/origin/HEAD\"], { cwd: dir });\n const m = head.exitCode === 0 ? head.stdout.trim().match(/refs\\/remotes\\/origin\\/(.+)$/) : null;\n if (m) {\n mainBranch = m[1];\n } else {\n const cur = await run(\"git\", [\"rev-parse\", \"--abbrev-ref\", \"HEAD\"], { cwd: dir });\n const branch = cur.stdout.trim();\n if (cur.exitCode === 0 && branch && branch !== \"HEAD\") mainBranch = branch;\n }\n\n const remote = await run(\"git\", [\"remote\", \"get-url\", \"origin\"], { cwd: dir });\n if (remote.exitCode === 0 && remote.stdout) forgeCli = forgeFromRemote(remote.stdout);\n\n return { mainBranch, forgeCli };\n}\n\nasync function detectCommands(dir: string, pm: string): Promise<string[]> {\n const cmds: string[] = [];\n try {\n const pkg = JSON.parse(await readFile(join(dir, \"package.json\"), \"utf-8\"));\n const scripts: Record<string, string> = pkg.scripts ?? {};\n for (const name of [\"typecheck\", \"test\", \"build\"]) {\n if (scripts[name]) cmds.push(`${pm} ${name}`);\n }\n } catch {\n // no package.json / unparseable — no commands\n }\n return cmds;\n}\n\nexport async function detectHarnessParams(dir: string): Promise<HarnessParams> {\n const { packageManager, lockfile } = detectPackageManager(dir);\n const { mainBranch, forgeCli } = await detectGit(dir);\n const commands = await detectCommands(dir, packageManager);\n\n return {\n packageManager,\n forbiddenPms: forbiddenPmsFor(packageManager),\n lockfile,\n generatedGlobs: generatedGlobsFor(dir),\n docsDir: \"docs/\",\n mainBranch,\n forgeCli,\n commands,\n };\n}\n","import chalk from \"chalk\";\nimport { detect } from \"../claude/provider.js\";\nimport { detectProject } from \"../detect/project.js\";\nimport { banner, log } from \"../utils/logger.js\";\n\nexport async function detectCommand(): Promise<void> {\n banner();\n\n // Project detection\n const project = await detectProject(process.cwd());\n if (project.scenario === \"existing\") {\n const name = project.projectName\n ? chalk.cyan(project.projectName)\n : chalk.dim(\"unnamed\");\n log.info(`Existing project detected: ${name}`);\n } else {\n log.info(\"Empty directory — no existing project detected\");\n }\n console.log();\n\n // Provider detection\n log.step(\"Detecting Claude Code...\");\n console.log();\n\n const info = await detect();\n const status = info.installed ? chalk.green(\"✔ installed\") : chalk.dim(\"✖ not found\");\n const version = info.version ? chalk.dim(` (${info.version})`) : \"\";\n console.log(` ${info.displayName.padEnd(20)} ${status}${version}`);\n console.log();\n\n if (info.installed) {\n log.success(\"Claude Code detected.\");\n } else {\n log.warn(\"Claude Code not detected.\");\n log.info(\"Run 'agent-stack init' to install and configure it.\");\n }\n}\n","import chalk from \"chalk\";\nimport { checkbox, input } from \"@inquirer/prompts\";\nimport { detect, listMcp } from \"../claude/provider.js\";\nimport { MCP_CATALOG } from \"../mcp/catalog.js\";\nimport { installMcpServers } from \"../mcp/installer.js\";\nimport { banner, log } from \"../utils/logger.js\";\n\nexport async function mcpCommand(action: \"install\" | \"list\"): Promise<void> {\n banner();\n\n const info = await detect();\n if (!info.installed) {\n log.error(\"Claude Code not detected. Run 'agent-stack init' first.\");\n process.exit(1);\n }\n\n if (action === \"list\") {\n console.log();\n log.step(`${info.displayName} MCP servers:`);\n const servers = await listMcp();\n if (servers.length === 0) {\n log.dim(\" No MCP servers configured\");\n } else {\n for (const s of servers) {\n console.log(` ${chalk.cyan(s.name.padEnd(25))} ${chalk.dim(s.command)} ${s.args.join(\" \")}`);\n }\n }\n console.log();\n return;\n }\n\n // install flow\n const selectedServers = await checkbox({\n message: \"Select MCP servers to install:\",\n choices: MCP_CATALOG.map((s) => ({\n name: `${s.displayName} — ${s.description}`,\n value: s.name,\n checked: !s.optional,\n })),\n });\n\n const servers = MCP_CATALOG.filter((s) => selectedServers.includes(s.name));\n\n // Collect env vars\n const envValues: Record<string, string> = {};\n for (const server of servers) {\n if (server.envPrompts) {\n for (const [key, prompt] of Object.entries(server.envPrompts)) {\n const value = await input({ message: prompt });\n envValues[key] = value;\n }\n }\n }\n\n await installMcpServers(servers, envValues);\n\n console.log();\n log.success(\"MCP servers configured successfully!\");\n}\n","import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { emitHarness } from \"../claude/harness.js\";\nimport { banner, log } from \"../utils/logger.js\";\n\nexport async function generateCommand(options: { force?: boolean } = {}): Promise<void> {\n banner();\n\n const projectDir = process.cwd();\n\n if (existsSync(join(projectDir, \".claude\")) && !options.force) {\n log.error(\".claude/ already exists.\");\n log.info(\"Run `agent-stack update` to refresh the harness (preserves rules/ and tmp/),\");\n log.info(\"or pass --force to overwrite from scratch.\");\n process.exit(1);\n }\n\n log.step(\"Detecting project and generating the Claude harness...\");\n const files = await emitHarness(projectDir);\n\n console.log();\n log.success(`Generated ${files.length} harness file(s).`);\n log.dim(\" Next steps:\");\n log.dim(\n \" • Exclude the harness from git: add .claude/, CLAUDE.md, CODEMAP.md to .git/info/exclude\"\n );\n log.dim(\n \" • Generate rules: open `claude` and run the pattern-scout subagent (.claude/rules/ is empty by design)\"\n );\n log.dim(\" • Smoke-test the guards: a `git push` or foreign package-manager command should block\");\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { detectHarnessParams } from \"../detect/harness-params.js\";\nimport { buildHarnessFiles, writeHarnessFiles } from \"../claude/harness.js\";\nimport { banner, log } from \"../utils/logger.js\";\n\nexport async function updateCommand(options: { dryRun?: boolean } = {}): Promise<void> {\n banner();\n\n const projectDir = process.cwd();\n if (!existsSync(join(projectDir, \".claude\"))) {\n log.error(\"No .claude/ found. Run `agent-stack generate` to deploy the harness first.\");\n process.exit(1);\n }\n\n const params = await detectHarnessParams(projectDir);\n const files = buildHarnessFiles(params);\n\n // Classify against what's on disk (emitter-owned files only).\n const created: string[] = [];\n const changed: string[] = [];\n let unchanged = 0;\n for (const f of files) {\n const full = join(projectDir, f.path);\n if (!existsSync(full)) created.push(f.path);\n else if (readFileSync(full, \"utf-8\") !== f.content) changed.push(f.path);\n else unchanged++;\n }\n\n if (options.dryRun) {\n log.step(\"Harness update preview (dry run):\");\n created.forEach((p) => console.log(` + ${p}`));\n changed.forEach((p) => console.log(` ~ ${p}`));\n console.log();\n log.dim(` ${unchanged} unchanged. rules/ and tmp/ are preserved (not emitter-owned).`);\n return;\n }\n\n log.step(\"Updating the Claude harness...\");\n await writeHarnessFiles(projectDir, files);\n\n console.log();\n log.success(\n `Harness updated: ${created.length} added, ${changed.length} changed, ${unchanged} unchanged.`\n );\n log.dim(\" .claude/rules/ and .claude/tmp/ were left untouched.\");\n}\n","import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { detectCommand } from \"./detect.js\";\nimport { generateCommand } from \"./generate.js\";\nimport { updateCommand } from \"./update.js\";\n\nexport async function syncCommand(): Promise<void> {\n await detectCommand();\n console.log();\n if (existsSync(join(process.cwd(), \".claude\"))) {\n await updateCommand();\n } else {\n await generateCommand();\n }\n}\n","import { program } from \"./cli.js\";\n\nprogram.parse();\n"],"mappings":";AAAA,SAAS,eAAe;;;ACAxB,SAAS,UAAU,OAAO,eAAe;AACzC,OAAOA,YAAW;;;ACDlB,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB;AACzB,SAAS,YAAY;AAWrB,eAAsB,cAAc,KAAsC;AACxE,QAAM,iBAAiB,WAAW,KAAK,KAAK,cAAc,CAAC;AAC3D,QAAM,YAAY,WAAW,KAAK,KAAK,KAAK,CAAC;AAC7C,QAAM,aAAa,WAAW,KAAK,KAAK,MAAM,CAAC;AAE/C,QAAM,oBAAoB,kBAAkB,aAAa;AAEzD,MAAI;AACJ,MAAI,gBAAgB;AAClB,QAAI;AACF,YAAM,MAAM,MAAM,SAAS,KAAK,KAAK,cAAc,GAAG,OAAO;AAC7D,YAAM,MAAM,KAAK,MAAM,GAAG;AAC1B,oBAAc,IAAI;AAAA,IACpB,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU,oBAAoB,aAAa;AAAA,EAC7C;AACF;;;ACvCA,SAAS,eAAe;AACxB,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,QAAAC,aAAY;;;ACFrB,SAAS,aAAa;AAEtB,eAAsB,cAAc,KAA+B;AACjE,MAAI;AACF,UAAM,MAAM,SAAS,CAAC,GAAG,CAAC;AAC1B,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,IACpB,KACA,MACA,SAC+D;AAC/D,QAAM,SAAS,MAAM,MAAM,KAAK,MAAM;AAAA,IACpC,KAAK,SAAS;AAAA,IACd,KAAK,SAAS;AAAA,IACd,QAAQ;AAAA,EACV,CAAC;AACD,SAAO;AAAA,IACL,QAAQ,OAAO;AAAA,IACf,QAAQ,OAAO;AAAA,IACf,UAAU,OAAO,YAAY;AAAA,EAC/B;AACF;AAEA,eAAsB,UACpB,KACA,MAC+C;AAC/C,QAAM,SAAS,MAAM,MAAM,KAAK,MAAM,EAAE,QAAQ,MAAM,CAAC;AACvD,SAAO,EAAE,QAAQ,OAAO,QAAkB,UAAU,OAAO,YAAY,EAAE;AAC3E;;;AClCA,OAAO,WAAW;AAClB,OAAO,SAAuB;AAEvB,IAAM,MAAM;AAAA,EACjB,MAAM,CAAC,QAAgB,QAAQ,IAAI,MAAM,KAAK,QAAG,GAAG,GAAG;AAAA,EACvD,SAAS,CAAC,QAAgB,QAAQ,IAAI,MAAM,MAAM,QAAG,GAAG,GAAG;AAAA,EAC3D,MAAM,CAAC,QAAgB,QAAQ,IAAI,MAAM,OAAO,QAAG,GAAG,GAAG;AAAA,EACzD,OAAO,CAAC,QAAgB,QAAQ,MAAM,MAAM,IAAI,QAAG,GAAG,GAAG;AAAA,EACzD,MAAM,CAAC,QAAgB,QAAQ,IAAI,MAAM,KAAK,QAAG,GAAG,GAAG;AAAA,EACvD,KAAK,CAAC,QAAgB,QAAQ,IAAI,MAAM,IAAI,GAAG,CAAC;AAClD;AAEO,SAAS,QAAQ,MAAmB;AACzC,SAAO,IAAI,EAAE,MAAM,OAAO,OAAO,CAAC;AACpC;AAEO,SAAS,SAAe;AAC7B,UAAQ,IAAI;AACZ,UAAQ,IAAI,MAAM,KAAK,KAAK,eAAe,CAAC;AAC5C,UAAQ,IAAI,MAAM,IAAI,sCAAsC,CAAC;AAC7D,UAAQ,IAAI;AACd;;;AFbO,IAAM,cAAc;AACpB,IAAM,gBAAgB;AAE7B,eAAsB,SAAgC;AACpD,QAAM,OAAO,QAAQ;AACrB,QAAM,cAAc,CAACC,MAAK,MAAM,SAAS,GAAGA,MAAK,MAAM,WAAW,QAAQ,CAAC;AAE3E,QAAM,YAAY,MAAM,cAAc,QAAQ;AAC9C,MAAI;AACJ,MAAI,WAAW;AACb,UAAM,SAAS,MAAM,UAAU,UAAU,CAAC,WAAW,CAAC;AACtD,QAAI,OAAO,aAAa,EAAG,WAAU,OAAO,OAAO,KAAK;AAAA,EAC1D;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA,aAAa,YAAY,OAAO,CAAC,MAAMC,YAAW,CAAC,CAAC;AAAA,EACtD;AACF;AAEA,eAAsB,UAAyB;AAC7C,MAAI,KAAK,mCAAmC;AAC5C,QAAM,SAAS,MAAM,IAAI,OAAO,CAAC,WAAW,MAAM,2BAA2B,CAAC;AAC9E,MAAI,OAAO,aAAa,GAAG;AACzB,UAAM,IAAI,MAAM,kCAAkC,OAAO,MAAM,EAAE;AAAA,EACnE;AACA,MAAI,QAAQ,oCAAoC;AAClD;AAEA,eAAsB,aACpB,SACA,WACe;AACf,aAAW,UAAU,SAAS;AAC5B,UAAM,OAAO,CAAC,OAAO,OAAO,OAAO,MAAM,eAAe,OAAO,SAAS;AACxE,QAAI,OAAO,QAAS,MAAK,KAAK,MAAM,OAAO,OAAO;AAClD,QAAI,OAAO,KAAM,MAAK,KAAK,GAAG,OAAO,IAAI;AAEzC,UAAM,MAA8B,CAAC;AACrC,QAAI,OAAO,KAAK;AACd,iBAAW,OAAO,OAAO,KAAK,OAAO,GAAG,GAAG;AACzC,YAAI,UAAU,GAAG,EAAG,KAAI,GAAG,IAAI,UAAU,GAAG;AAAA,MAC9C;AAAA,IACF;AACA,UAAM,UAAoB,CAAC;AAC3B,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC9C,cAAQ,KAAK,MAAM,GAAG,GAAG,IAAI,KAAK,EAAE;AAAA,IACtC;AAEA,UAAM,SAAS,MAAM,IAAI,UAAU,CAAC,GAAG,MAAM,GAAG,OAAO,CAAC;AACxD,QAAI,OAAO,aAAa,GAAG;AACzB,UAAI,KAAK,6BAA6B,OAAO,IAAI,MAAM,OAAO,MAAM,EAAE;AAAA,IACxE,OAAO;AACL,UAAI,QAAQ,eAAe,OAAO,WAAW,cAAc;AAAA,IAC7D;AAAA,EACF;AACF;AAEA,eAAsB,UAAsC;AAC1D,QAAM,SAAS,MAAM,UAAU,UAAU,CAAC,OAAO,MAAM,CAAC;AACxD,MAAI,OAAO,aAAa,EAAG,QAAO,CAAC;AAEnC,QAAM,QAAQ,OAAO,OAAO,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AAC7D,SAAO,MAAM,IAAI,CAAC,SAAS;AACzB,UAAM,QAAQ,KAAK,MAAM,KAAK;AAC9B,WAAO,EAAE,MAAM,MAAM,CAAC,KAAK,MAAM,SAAS,MAAM,CAAC,KAAK,IAAI,MAAM,MAAM,MAAM,CAAC,EAAE;AAAA,EACjF,CAAC;AACH;;;AG9EA,SAAS,oBAAoB;AAC7B,SAAS,QAAAC,OAAM,eAAe;AAC9B,SAAS,qBAAqB;AAG9B,SAAS,iBAAyB;AAGhC,QAAM,UAAU,QAAQ,cAAc,YAAY,GAAG,CAAC;AAItD,QAAM,aAAa;AAAA,IACjBA,MAAK,SAAS,MAAM,OAAO,cAAc;AAAA,IACzCA,MAAK,SAAS,MAAM,MAAM,OAAO,cAAc;AAAA,EACjD;AACA,aAAW,aAAa,YAAY;AAClC,QAAI;AACF,aAAO,aAAa,WAAW,OAAO;AAAA,IACxC,QAAQ;AACN;AAAA,IACF;AAAA,EACF;AACA,QAAM,IAAI,MAAM,iCAAiC;AACnD;AAEA,IAAM,cAAc,KAAK,MAAM,eAAe,CAAC;AAExC,IAAM,cAAqC;;;ACxBlD,eAAsB,kBACpB,SACA,WACe;AACf,QAAM,IAAI,QAAQ,+BAA+B,aAAa,KAAK;AACnE,IAAE,MAAM;AAER,MAAI;AACF,UAAM,aAAa,SAAS,SAAS;AACrC,MAAE,QAAQ,8BAA8B,aAAa,EAAE;AAAA,EACzD,SAAS,KAAK;AACZ,MAAE,KAAK,+BAA+B,aAAa,EAAE;AACrD,UAAM;AAAA,EACR;AACF;;;AClBA,SAAS,gBAAAC,eAAc,aAAa,UAAU,cAAAC,mBAAkB;AAChE,SAAS,WAAW,OAAO,aAAa;AACxC,SAAS,QAAAC,OAAM,WAAAC,UAAS,UAAU,gBAAgB;AAClD,SAAS,iBAAAC,sBAAqB;;;ACH9B,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,YAAAC,iBAAgB;AACzB,SAAS,QAAAC,aAAY;AAkBrB,IAAM,iBAAsD;AAAA,EAC1D,EAAE,MAAM,kBAAkB,IAAI,OAAO;AAAA,EACrC,EAAE,MAAM,aAAa,IAAI,OAAO;AAAA,EAChC,EAAE,MAAM,aAAa,IAAI,MAAM;AAAA,EAC/B,EAAE,MAAM,qBAAqB,IAAI,MAAM;AACzC;AAEA,IAAM,UAAU,CAAC,OAAO,QAAQ,QAAQ,KAAK;AAEtC,SAAS,qBAAqB,KAGnC;AACA,aAAW,EAAE,MAAM,GAAG,KAAK,gBAAgB;AACzC,QAAIC,YAAWC,MAAK,KAAK,IAAI,CAAC,EAAG,QAAO,EAAE,gBAAgB,IAAI,UAAU,KAAK;AAAA,EAC/E;AACA,SAAO,EAAE,gBAAgB,OAAO,UAAU,oBAAoB;AAChE;AAEO,SAAS,gBAAgB,IAAoB;AAClD,SAAO,QAAQ,OAAO,CAAC,MAAM,MAAM,EAAE,EAAE,KAAK,GAAG;AACjD;AAEO,SAAS,gBAAgB,WAA2B;AACzD,SAAO,UAAU,KAAK,SAAS,IAAI,SAAS;AAC9C;AAEA,SAAS,kBAAkB,KAAqB;AAE9C,SAAOD,YAAWC,MAAK,KAAK,eAAe,CAAC,IACxC,iCACA;AACN;AAEA,eAAe,UAAU,KAAgE;AACvF,MAAI,aAAa;AACjB,MAAI,WAAW;AAEf,QAAM,OAAO,MAAM,IAAI,OAAO,CAAC,gBAAgB,0BAA0B,GAAG,EAAE,KAAK,IAAI,CAAC;AACxF,QAAM,IAAI,KAAK,aAAa,IAAI,KAAK,OAAO,KAAK,EAAE,MAAM,8BAA8B,IAAI;AAC3F,MAAI,GAAG;AACL,iBAAa,EAAE,CAAC;AAAA,EAClB,OAAO;AACL,UAAM,MAAM,MAAM,IAAI,OAAO,CAAC,aAAa,gBAAgB,MAAM,GAAG,EAAE,KAAK,IAAI,CAAC;AAChF,UAAM,SAAS,IAAI,OAAO,KAAK;AAC/B,QAAI,IAAI,aAAa,KAAK,UAAU,WAAW,OAAQ,cAAa;AAAA,EACtE;AAEA,QAAM,SAAS,MAAM,IAAI,OAAO,CAAC,UAAU,WAAW,QAAQ,GAAG,EAAE,KAAK,IAAI,CAAC;AAC7E,MAAI,OAAO,aAAa,KAAK,OAAO,OAAQ,YAAW,gBAAgB,OAAO,MAAM;AAEpF,SAAO,EAAE,YAAY,SAAS;AAChC;AAEA,eAAe,eAAe,KAAa,IAA+B;AACxE,QAAM,OAAiB,CAAC;AACxB,MAAI;AACF,UAAM,MAAM,KAAK,MAAM,MAAMC,UAASD,MAAK,KAAK,cAAc,GAAG,OAAO,CAAC;AACzE,UAAM,UAAkC,IAAI,WAAW,CAAC;AACxD,eAAW,QAAQ,CAAC,aAAa,QAAQ,OAAO,GAAG;AACjD,UAAI,QAAQ,IAAI,EAAG,MAAK,KAAK,GAAG,EAAE,IAAI,IAAI,EAAE;AAAA,IAC9C;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEA,eAAsB,oBAAoB,KAAqC;AAC7E,QAAM,EAAE,gBAAgB,SAAS,IAAI,qBAAqB,GAAG;AAC7D,QAAM,EAAE,YAAY,SAAS,IAAI,MAAM,UAAU,GAAG;AACpD,QAAM,WAAW,MAAM,eAAe,KAAK,cAAc;AAEzD,SAAO;AAAA,IACL;AAAA,IACA,cAAc,gBAAgB,cAAc;AAAA,IAC5C;AAAA,IACA,gBAAgB,kBAAkB,GAAG;AAAA,IACrC,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AD7FA,IAAM,cAAc;AAAA,EAClB,YAAY;AAAA,IACV;AAAA,MACE,SAAS;AAAA,MACT,OAAO,CAAC,EAAE,MAAM,WAAW,SAAS,kDAAkD,CAAC;AAAA,IACzF;AAAA,IACA;AAAA,MACE,SAAS;AAAA,MACT,OAAO,CAAC,EAAE,MAAM,WAAW,SAAS,kDAAkD,CAAC;AAAA,IACzF;AAAA,EACF;AAAA,EACA,cAAc;AAAA,IACZ;AAAA,MACE,OAAO;AAAA,QACL,EAAE,MAAM,WAAW,SAAS,6DAA6D;AAAA,MAC3F;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ;AAAA,MACE,OAAO,CAAC,EAAE,MAAM,WAAW,SAAS,yDAAyD,CAAC;AAAA,IAChG;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX;AAAA,MACE,SAAS;AAAA,MACT,OAAO;AAAA,QACL,EAAE,MAAM,WAAW,SAAS,sDAAsD;AAAA,QAClF,EAAE,MAAM,WAAW,SAAS,wDAAwD;AAAA,MACtF;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,gBAAwB;AAC/B,QAAM,UAAUE,SAAQC,eAAc,YAAY,GAAG,CAAC;AACtD,QAAM,aAAa;AAAA,IACjBC,MAAK,SAAS,MAAM,aAAa,QAAQ;AAAA;AAAA,IACzCA,MAAK,SAAS,MAAM,MAAM,aAAa,QAAQ;AAAA;AAAA,EACjD;AACA,aAAW,KAAK,YAAY;AAC1B,QAAIC,YAAW,CAAC,EAAG,QAAO;AAAA,EAC5B;AACA,QAAM,IAAI,MAAM,iCAAiC;AACnD;AAGA,SAAS,cAAsB;AAC7B,QAAM,UAAUH,SAAQC,eAAc,YAAY,GAAG,CAAC;AACtD,aAAW,KAAK,CAACC,MAAK,SAAS,MAAM,cAAc,GAAGA,MAAK,SAAS,MAAM,MAAM,cAAc,CAAC,GAAG;AAChG,QAAI;AACF,aAAO,KAAK,MAAME,cAAa,GAAG,OAAO,CAAC,EAAE,WAAW;AAAA,IACzD,QAAQ;AACN;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,WAAW,MAAc,GAA0B;AAC1D,SAAO,KACJ,WAAW,UAAU,EAAE,cAAc,EACrC,WAAW,oBAAoB,EAAE,YAAY,EAC7C,WAAW,iBAAiB,EAAE,cAAc,EAC5C,WAAW,gBAAgB,EAAE,QAAQ,EACrC,WAAW,gBAAgB,EAAE,OAAO,EACpC,WAAW,mBAAmB,EAAE,UAAU;AAC/C;AAEA,SAAS,KAAK,KAAuB;AACnC,QAAM,MAAgB,CAAC;AACvB,aAAW,QAAQ,YAAY,GAAG,GAAG;AACnC,UAAM,OAAOF,MAAK,KAAK,IAAI;AAC3B,QAAI,SAAS,IAAI,EAAE,YAAY,EAAG,KAAI,KAAK,GAAG,KAAK,IAAI,CAAC;AAAA,QACnD,KAAI,KAAK,IAAI;AAAA,EACpB;AACA,SAAO;AACT;AAEA,SAAS,cAAc,GAA0B;AAC/C,QAAM,QAAQ;AAAA,IACZ,GAAG,EAAE,SAAS,IAAI,CAAC,MAAM,QAAQ,CAAC,KAAK;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,EAAE,QAAQ;AAAA,IAClB,QAAQ,EAAE,QAAQ;AAAA,IAClB,QAAQ,EAAE,QAAQ;AAAA,IAClB;AAAA,EACF;AACA,QAAM,WAAW;AAAA,IACf,SAAS;AAAA,IACT,aAAa,EAAE,MAAM;AAAA,IACrB,OAAO;AAAA,EACT;AACA,SAAO,KAAK,UAAU,UAAU,MAAM,CAAC,IAAI;AAC7C;AAEA,SAAS,mBAAmB,GAA0B;AACpD,QAAM,WAAW;AAAA,IACf,aAAa;AAAA,MACX,OAAO,CAAC,aAAa,QAAQ,EAAE,QAAQ,SAAS;AAAA,MAChD,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAa,EAAE,QAAQ;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO,KAAK,UAAU,UAAU,MAAM,CAAC,IAAI;AAC7C;AAEA,SAAS,cAAc,GAAkB,MAAsB;AAC7D,QAAM,YAAYE,cAAaF,MAAK,MAAM,eAAe,GAAG,OAAO,EAAE;AAAA,IACnE;AAAA,IACA;AAAA,EACF;AACA,QAAM,OAAO,EAAE,SAAS,SACpB,eAAe,EAAE,SAAS,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC;AAAA,IAC3D;AACJ,QAAM,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAMQ,EAAE,cAAc;AAAA,sBACjB,EAAE,UAAU;AAAA,qCACG,EAAE,eAAe,MAAM,GAAG,EAAE,KAAK,IAAI,CAAC,KAAK,EAAE,QAAQ;AAAA,EACxF,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASJ,SAAO,OAAO;AAChB;AAEA,SAAS,eAAuB;AAC9B,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaT;AAGO,SAAS,kBAAkB,QAAwC;AACxE,QAAM,OAAO,cAAc;AAC3B,QAAM,QAAyB,CAAC;AAEhC,aAAW,OAAO,KAAK,IAAI,GAAG;AAC5B,QAAI,SAAS,GAAG,EAAE,WAAW,GAAG,EAAG;AACnC,UAAM,MAAM,SAAS,MAAM,GAAG;AAC9B,UAAM,UAAU,WAAWE,cAAa,KAAK,OAAO,GAAG,MAAM;AAC7D,UAAM,KAAK,EAAE,MAAMF,MAAK,WAAW,GAAG,GAAG,SAAS,QAAQ,SAAS,CAAC;AAAA,EACtE;AAEA,QAAM,KAAK,EAAE,MAAM,yBAAyB,SAAS,cAAc,MAAM,GAAG,QAAQ,SAAS,CAAC;AAC9F,QAAM,KAAK;AAAA,IACT,MAAM;AAAA,IACN,SAAS,mBAAmB,MAAM;AAAA,IAClC,QAAQ;AAAA,EACV,CAAC;AACD,QAAM,KAAK,EAAE,MAAM,aAAa,SAAS,cAAc,QAAQ,IAAI,GAAG,QAAQ,SAAS,CAAC;AACxF,QAAM,KAAK,EAAE,MAAM,cAAc,SAAS,aAAa,GAAG,QAAQ,SAAS,CAAC;AAC5E,QAAM,KAAK;AAAA,IACT,MAAM;AAAA,IACN,SAAS,KAAK,UAAU,EAAE,iBAAiB,YAAY,GAAG,OAAO,GAAG,MAAM,CAAC,IAAI;AAAA,IAC/E,QAAQ;AAAA,EACV,CAAC;AAED,SAAO;AACT;AAIA,eAAsB,kBACpB,YACA,OACe;AACf,aAAW,KAAK,OAAO;AACrB,UAAM,OAAOA,MAAK,YAAY,EAAE,IAAI;AACpC,UAAM,MAAMF,SAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C,UAAM,UAAU,MAAM,EAAE,SAAS,OAAO;AACxC,QAAI,EAAE,KAAK,WAAW,gBAAgB,KAAK,EAAE,KAAK,SAAS,KAAK,GAAG;AACjE,YAAM,MAAM,MAAM,GAAK;AAAA,IACzB;AACA,QAAI,QAAQ,EAAE,IAAI;AAAA,EACpB;AACF;AAGA,eAAsB,YAAY,YAA8C;AAC9E,QAAM,SAAS,MAAM,oBAAoB,UAAU;AACnD,QAAM,QAAQ,kBAAkB,MAAM;AACtC,QAAM,kBAAkB,YAAY,KAAK;AACzC,SAAO;AACT;;;APvNA,eAAsB,cAA6B;AACjD,SAAO;AAGP,MAAI,KAAK,0BAA0B;AAEnC,QAAM,UAAU,MAAM,cAAc,QAAQ,IAAI,CAAC;AACjD,MAAI,QAAQ,aAAa,YAAY;AACnC,UAAM,OAAO,QAAQ,cAAcK,OAAM,KAAK,QAAQ,WAAW,IAAIA,OAAM,IAAI,SAAS;AACxF,QAAI,KAAK,qBAAqB,IAAI,EAAE;AAAA,EACtC,OAAO;AACL,QAAI,KAAK,oCAA+B;AAAA,EAC1C;AAEA,UAAQ,IAAI;AACZ,QAAM,OAAO,MAAM,OAAO;AAC1B,QAAM,SAAS,KAAK,YAChBA,OAAM,MAAM,cAAS,KAAK,WAAW,IACrCA,OAAM,IAAI,cAAS,KAAK,WAAW;AACvC,QAAM,UAAU,KAAK,UAAUA,OAAM,IAAI,KAAK,KAAK,OAAO,GAAG,IAAI;AACjE,UAAQ,IAAI,GAAG,MAAM,GAAG,OAAO,EAAE;AACjC,UAAQ,IAAI;AAEZ,MAAI,CAAC,KAAK,WAAW;AACnB,QAAI,KAAK,+BAA+B;AACxC,UAAM,YAAY,MAAM,QAAQ,EAAE,SAAS,4BAA4B,SAAS,KAAK,CAAC;AACtF,QAAI,WAAW;AACb,YAAM,QAAQ;AAAA,IAChB,OAAO;AACL,UAAI,MAAM,mCAAmC;AAC7C,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AAGA,UAAQ,IAAI;AACZ,MAAI,KAAK,kCAAkC;AAC3C,QAAM,YAAY,QAAQ,IAAI,CAAC;AAG/B,QAAM,EAAE,YAAY,UAAU,IAAI,MAAM,iBAAiB;AACzD,MAAI,WAAW,SAAS,GAAG;AACzB,YAAQ,IAAI;AACZ,UAAM,kBAAkB,YAAY,SAAS;AAAA,EAC/C;AAGA,UAAQ,IAAI;AACZ,UAAQ,IAAIA,OAAM,KAAK,MAAM,mBAAmB,CAAC;AACjD,UAAQ,IAAI;AACZ,MAAI,IAAI,eAAe;AACvB,MAAI,IAAI,iGAA4F;AACpG,MAAI,IAAI,+GAA0G;AAClH,MAAI,IAAI,8FAAyF;AACjG,UAAQ,IAAI;AACd;AAEA,eAAe,mBAGZ;AACD,QAAM,gBAAgB,MAAM,SAAS;AAAA,IACnC,SAAS;AAAA,IACT,SAAS,YAAY,IAAI,CAAC,OAAO;AAAA,MAC/B,MAAM,GAAG,EAAE,WAAW,WAAM,EAAE,WAAW;AAAA,MACzC,OAAO,EAAE;AAAA,MACT,SAAS,CAAC,EAAE;AAAA,IACd,EAAE;AAAA,EACJ,CAAC;AAED,QAAM,aAAa,YAAY,OAAO,CAAC,MAAM,cAAc,SAAS,EAAE,IAAI,CAAC;AAC3E,QAAM,YAAoC,CAAC;AAE3C,aAAW,UAAU,YAAY;AAC/B,QAAI,OAAO,YAAY;AACrB,iBAAW,CAAC,KAAK,MAAM,KAAK,OAAO,QAAQ,OAAO,UAAU,GAAG;AAC7D,cAAM,QAAQ,MAAM,MAAM,EAAE,SAAS,SAASA,OAAM,IAAI,kBAAkB,EAAE,CAAC;AAC7E,kBAAU,GAAG,IAAI,SAAS;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,YAAY,UAAU;AACjC;;;AS7FA,OAAOC,YAAW;AAKlB,eAAsB,gBAA+B;AACnD,SAAO;AAGP,QAAM,UAAU,MAAM,cAAc,QAAQ,IAAI,CAAC;AACjD,MAAI,QAAQ,aAAa,YAAY;AACnC,UAAM,OAAO,QAAQ,cACjBC,OAAM,KAAK,QAAQ,WAAW,IAC9BA,OAAM,IAAI,SAAS;AACvB,QAAI,KAAK,8BAA8B,IAAI,EAAE;AAAA,EAC/C,OAAO;AACL,QAAI,KAAK,qDAAgD;AAAA,EAC3D;AACA,UAAQ,IAAI;AAGZ,MAAI,KAAK,0BAA0B;AACnC,UAAQ,IAAI;AAEZ,QAAM,OAAO,MAAM,OAAO;AAC1B,QAAM,SAAS,KAAK,YAAYA,OAAM,MAAM,kBAAa,IAAIA,OAAM,IAAI,kBAAa;AACpF,QAAM,UAAU,KAAK,UAAUA,OAAM,IAAI,KAAK,KAAK,OAAO,GAAG,IAAI;AACjE,UAAQ,IAAI,KAAK,KAAK,YAAY,OAAO,EAAE,CAAC,IAAI,MAAM,GAAG,OAAO,EAAE;AAClE,UAAQ,IAAI;AAEZ,MAAI,KAAK,WAAW;AAClB,QAAI,QAAQ,uBAAuB;AAAA,EACrC,OAAO;AACL,QAAI,KAAK,2BAA2B;AACpC,QAAI,KAAK,qDAAqD;AAAA,EAChE;AACF;;;ACpCA,OAAOC,YAAW;AAClB,SAAS,YAAAC,WAAU,SAAAC,cAAa;AAMhC,eAAsB,WAAW,QAA2C;AAC1E,SAAO;AAEP,QAAM,OAAO,MAAM,OAAO;AAC1B,MAAI,CAAC,KAAK,WAAW;AACnB,QAAI,MAAM,yDAAyD;AACnE,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,WAAW,QAAQ;AACrB,YAAQ,IAAI;AACZ,QAAI,KAAK,GAAG,KAAK,WAAW,eAAe;AAC3C,UAAMC,WAAU,MAAM,QAAQ;AAC9B,QAAIA,SAAQ,WAAW,GAAG;AACxB,UAAI,IAAI,6BAA6B;AAAA,IACvC,OAAO;AACL,iBAAW,KAAKA,UAAS;AACvB,gBAAQ,IAAI,KAAKC,OAAM,KAAK,EAAE,KAAK,OAAO,EAAE,CAAC,CAAC,IAAIA,OAAM,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,KAAK,KAAK,GAAG,CAAC,EAAE;AAAA,MAC9F;AAAA,IACF;AACA,YAAQ,IAAI;AACZ;AAAA,EACF;AAGA,QAAM,kBAAkB,MAAMC,UAAS;AAAA,IACrC,SAAS;AAAA,IACT,SAAS,YAAY,IAAI,CAAC,OAAO;AAAA,MAC/B,MAAM,GAAG,EAAE,WAAW,WAAM,EAAE,WAAW;AAAA,MACzC,OAAO,EAAE;AAAA,MACT,SAAS,CAAC,EAAE;AAAA,IACd,EAAE;AAAA,EACJ,CAAC;AAED,QAAM,UAAU,YAAY,OAAO,CAAC,MAAM,gBAAgB,SAAS,EAAE,IAAI,CAAC;AAG1E,QAAM,YAAoC,CAAC;AAC3C,aAAW,UAAU,SAAS;AAC5B,QAAI,OAAO,YAAY;AACrB,iBAAW,CAAC,KAAK,MAAM,KAAK,OAAO,QAAQ,OAAO,UAAU,GAAG;AAC7D,cAAM,QAAQ,MAAMC,OAAM,EAAE,SAAS,OAAO,CAAC;AAC7C,kBAAU,GAAG,IAAI;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,kBAAkB,SAAS,SAAS;AAE1C,UAAQ,IAAI;AACZ,MAAI,QAAQ,sCAAsC;AACpD;;;AC1DA,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,QAAAC,aAAY;AAIrB,eAAsB,gBAAgB,UAA+B,CAAC,GAAkB;AACtF,SAAO;AAEP,QAAM,aAAa,QAAQ,IAAI;AAE/B,MAAIC,YAAWC,MAAK,YAAY,SAAS,CAAC,KAAK,CAAC,QAAQ,OAAO;AAC7D,QAAI,MAAM,0BAA0B;AACpC,QAAI,KAAK,8EAA8E;AACvF,QAAI,KAAK,4CAA4C;AACrD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,KAAK,wDAAwD;AACjE,QAAM,QAAQ,MAAM,YAAY,UAAU;AAE1C,UAAQ,IAAI;AACZ,MAAI,QAAQ,aAAa,MAAM,MAAM,mBAAmB;AACxD,MAAI,IAAI,eAAe;AACvB,MAAI;AAAA,IACF;AAAA,EACF;AACA,MAAI;AAAA,IACF;AAAA,EACF;AACA,MAAI,IAAI,8FAAyF;AACnG;;;AC9BA,SAAS,cAAAC,aAAY,gBAAAC,qBAAoB;AACzC,SAAS,QAAAC,aAAY;AAKrB,eAAsB,cAAc,UAAgC,CAAC,GAAkB;AACrF,SAAO;AAEP,QAAM,aAAa,QAAQ,IAAI;AAC/B,MAAI,CAACC,YAAWC,MAAK,YAAY,SAAS,CAAC,GAAG;AAC5C,QAAI,MAAM,4EAA4E;AACtF,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,SAAS,MAAM,oBAAoB,UAAU;AACnD,QAAM,QAAQ,kBAAkB,MAAM;AAGtC,QAAM,UAAoB,CAAC;AAC3B,QAAM,UAAoB,CAAC;AAC3B,MAAI,YAAY;AAChB,aAAW,KAAK,OAAO;AACrB,UAAM,OAAOA,MAAK,YAAY,EAAE,IAAI;AACpC,QAAI,CAACD,YAAW,IAAI,EAAG,SAAQ,KAAK,EAAE,IAAI;AAAA,aACjCE,cAAa,MAAM,OAAO,MAAM,EAAE,QAAS,SAAQ,KAAK,EAAE,IAAI;AAAA,QAClE;AAAA,EACP;AAEA,MAAI,QAAQ,QAAQ;AAClB,QAAI,KAAK,mCAAmC;AAC5C,YAAQ,QAAQ,CAAC,MAAM,QAAQ,IAAI,OAAO,CAAC,EAAE,CAAC;AAC9C,YAAQ,QAAQ,CAAC,MAAM,QAAQ,IAAI,OAAO,CAAC,EAAE,CAAC;AAC9C,YAAQ,IAAI;AACZ,QAAI,IAAI,KAAK,SAAS,gEAAgE;AACtF;AAAA,EACF;AAEA,MAAI,KAAK,gCAAgC;AACzC,QAAM,kBAAkB,YAAY,KAAK;AAEzC,UAAQ,IAAI;AACZ,MAAI;AAAA,IACF,oBAAoB,QAAQ,MAAM,WAAW,QAAQ,MAAM,aAAa,SAAS;AAAA,EACnF;AACA,MAAI,IAAI,wDAAwD;AAClE;;;AC9CA,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,QAAAC,aAAY;AAKrB,eAAsB,cAA6B;AACjD,QAAM,cAAc;AACpB,UAAQ,IAAI;AACZ,MAAIC,YAAWC,MAAK,QAAQ,IAAI,GAAG,SAAS,CAAC,GAAG;AAC9C,UAAM,cAAc;AAAA,EACtB,OAAO;AACL,UAAM,gBAAgB;AAAA,EACxB;AACF;;;AdNO,IAAM,UAAU,IAAI,QAAQ;AAEnC,QACG,KAAK,aAAa,EAClB,YAAY,gEAAgE,EAC5E,QAAQ,OAAO;AAElB,QACG,QAAQ,MAAM,EACd,YAAY,2EAA2E,EACvF,OAAO,WAAW;AAErB,QACG,QAAQ,QAAQ,EAChB,YAAY,yDAAyD,EACrE,OAAO,aAAa;AAEvB,IAAM,MAAM,QACT,QAAQ,KAAK,EACb,YAAY,oBAAoB;AAEnC,IACG,QAAQ,SAAS,EACjB,YAAY,0DAA0D,EACtE,OAAO,MAAM,WAAW,SAAS,CAAC;AAErC,IACG,QAAQ,MAAM,EACd,YAAY,6BAA6B,EACzC,OAAO,MAAM,WAAW,MAAM,CAAC;AAElC,QACG,QAAQ,UAAU,EAClB,YAAY,yDAAyD,EACrE,OAAO,eAAe,wCAAwC,EAC9D,OAAO,eAAe;AAEzB,QACG,QAAQ,QAAQ,EAChB,YAAY,+EAA+E,EAC3F,OAAO,aAAa,wCAAwC,EAC5D,OAAO,aAAa;AAEvB,QACG,QAAQ,MAAM,EACd,YAAY,uDAAuD,EACnE,OAAO,WAAW;;;AepDrB,QAAQ,MAAM;","names":["chalk","existsSync","join","join","existsSync","join","readFileSync","existsSync","join","dirname","fileURLToPath","existsSync","readFile","join","existsSync","join","readFile","dirname","fileURLToPath","join","existsSync","readFileSync","chalk","chalk","chalk","chalk","checkbox","input","servers","chalk","checkbox","input","existsSync","join","existsSync","join","existsSync","readFileSync","join","existsSync","join","readFileSync","existsSync","join","existsSync","join"]}
@@ -0,0 +1,42 @@
1
+ [
2
+ {
3
+ "name": "github",
4
+ "package": "@modelcontextprotocol/server-github",
5
+ "displayName": "GitHub",
6
+ "description": "GitHub API access — issues, PRs, repos",
7
+ "transport": "stdio",
8
+ "command": "npx",
9
+ "args": ["-y", "@modelcontextprotocol/server-github"],
10
+ "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "" },
11
+ "envPrompts": {
12
+ "GITHUB_PERSONAL_ACCESS_TOKEN": "GitHub personal access token (create at https://github.com/settings/tokens)"
13
+ }
14
+ },
15
+ {
16
+ "name": "fetch",
17
+ "package": "mcp-server-fetch",
18
+ "displayName": "Fetch",
19
+ "description": "HTTP fetch — retrieve web content as markdown",
20
+ "transport": "stdio",
21
+ "command": "npx",
22
+ "args": ["-y", "mcp-server-fetch"]
23
+ },
24
+ {
25
+ "name": "memory",
26
+ "package": "@modelcontextprotocol/server-memory",
27
+ "displayName": "Memory",
28
+ "description": "Persistent knowledge graph across sessions",
29
+ "transport": "stdio",
30
+ "command": "npx",
31
+ "args": ["-y", "@modelcontextprotocol/server-memory"]
32
+ },
33
+ {
34
+ "name": "sequential-thinking",
35
+ "package": "@modelcontextprotocol/server-sequential-thinking",
36
+ "displayName": "Sequential Thinking",
37
+ "description": "Step-by-step structured reasoning",
38
+ "transport": "stdio",
39
+ "command": "npx",
40
+ "args": ["-y", "@modelcontextprotocol/server-sequential-thinking"]
41
+ }
42
+ ]
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@pasajero_0/agent-stack",
3
+ "version": "0.1.0",
4
+ "description": "CLI that deploys a Claude Code harness (hooks, subagents, skills, guards) onto your repo and manages MCP servers",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "bin": {
8
+ "agent-stack": "./bin/cli.mjs"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "bin",
13
+ "mcp",
14
+ "templates"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsup",
18
+ "dev": "tsup --watch",
19
+ "test": "vitest run",
20
+ "test:watch": "vitest",
21
+ "typecheck": "tsc --noEmit",
22
+ "prepare": "husky || true",
23
+ "prepublishOnly": "pnpm build && pnpm typecheck && pnpm test"
24
+ },
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "keywords": [
29
+ "ai",
30
+ "claude",
31
+ "claude-code",
32
+ "mcp",
33
+ "hooks",
34
+ "subagents",
35
+ "agent",
36
+ "cli"
37
+ ],
38
+ "license": "MIT",
39
+ "engines": {
40
+ "node": ">=18"
41
+ },
42
+ "pnpm": {
43
+ "onlyBuiltDependencies": ["esbuild"]
44
+ },
45
+ "dependencies": {
46
+ "@inquirer/prompts": "7.5.0",
47
+ "chalk": "5.4.1",
48
+ "commander": "13.1.0",
49
+ "execa": "9.5.2",
50
+ "ora": "8.2.0"
51
+ },
52
+ "devDependencies": {
53
+ "@commitlint/cli": "20.5.0",
54
+ "@commitlint/config-conventional": "20.5.0",
55
+ "@types/node": "22.15.3",
56
+ "husky": "9.1.7",
57
+ "tsup": "8.4.0",
58
+ "typescript": "5.8.3",
59
+ "vitest": "3.1.2"
60
+ }
61
+ }
@@ -0,0 +1,28 @@
1
+ <!--
2
+ Token vocabulary for the harness generator. Files under templates/claude/ contain {{TOKEN}}
3
+ placeholders; the emitter (src/claude/) substitutes them from the detector's output. This file is
4
+ generator input (leading underscore = not copied into the target repo).
5
+ -->
6
+
7
+ # Harness template tokens
8
+
9
+ | Token | Meaning | Example value | Source (detector) |
10
+ | --- | --- | --- | --- |
11
+ | `{{PM}}` | package manager | `pnpm` | lockfile |
12
+ | `{{FORBIDDEN_PM}}` | regex alternation of forbidden PMs | `npm\|yarn\|bun` | lockfile (the others) |
13
+ | `{{GEN_GLOBS}}` | case-glob of generated paths (guard-file) | `*/dist/*\|dist/*\|*.d.ts\|*.map` | build tool |
14
+ | `{{LOCKFILE}}` | lockfile name | `pnpm-lock.yaml` | lockfile |
15
+ | `{{DOCS_DIR}}` | docs directory (trailing slash) | `docs/` | convention / detect |
16
+ | `{{MAIN_BRANCH}}` | default branch | `main` | git |
17
+
18
+ ## Not templated (emitter builds these directly)
19
+
20
+ - `settings.json` — verbatim hooks block + computed `permissions.allow` (commands + forge CLI).
21
+ - `settings.local.json` — computed `permissions.deny` (generated globs + lockfile).
22
+ - `CLAUDE.md` — project body (from detector) + `_normative.md` appended verbatim.
23
+ - `CODEMAP.md` — generated by walking the repo tree.
24
+
25
+ ## Not substituted (verbatim hooks)
26
+
27
+ `session-start-context.sh`, `post-edit-verify.sh`, `post-edit-lint.sh`, `stop-flag-reflect.sh` —
28
+ no project values (the Stop hook self-derives the memory slug from cwd at runtime).
@@ -0,0 +1,24 @@
1
+ <!--
2
+ Normative CLAUDE.md sections — emitted VERBATIM into the target repo's CLAUDE.md by the harness
3
+ generator. Not a deployed file itself (leading underscore = generator input, not copied as-is).
4
+ These two sections are project-agnostic and must transfer unchanged.
5
+ -->
6
+
7
+ ## Multi-step migrations
8
+
9
+ Before any multi-file migration or refactor, write decision invariants to
10
+ `.claude/tmp/<task>-plan.md`. Re-read that plan from disk (not memory) immediately before composing
11
+ each diff preview, and open every diff preview with a compliance header — e.g.
12
+ `Plan check: D1 — ok; D3 — n/a`. Any deviation requires explicit user approval before the diff —
13
+ surface it as `ОТКЛОНЕНИЕ ОТ ПЛАНА` with rationale.
14
+
15
+ ## Scope discipline
16
+
17
+ - **Debug budget for support machinery**: 2 iterations max. On the third, stop and propose to
18
+ simplify or defer the mechanism rather than debug it further.
19
+ - **Nesting limit**: if work is more than 2 levels removed from the user's original task, stop and
20
+ ask — continue / simplify / cut.
21
+ - **Cost/value framing**: when proposing a new support mechanism, lead with one line —
22
+ cost / value / cost-of-not-implementing.
23
+ - **Plan starts with the goal**: the first line of any plan is the user's original goal verbatim; a
24
+ sub-item that does not bring it closer is a candidate for cutting.
@@ -0,0 +1,78 @@
1
+ ---
2
+ name: code-reviewer
3
+ description: Use proactively after writing or modifying code to review for architecture/layering, type safety, data-access patterns, security, and team conventions. Reports issues by severity (critical/warning/suggestion).
4
+ model: sonnet
5
+ tools: Read, Glob, Grep
6
+ ---
7
+
8
+ You are a code reviewer. For each file: run pattern greps → read context → check against Do/Don't → report issues with severity.
9
+
10
+ ## How to review
11
+
12
+ 1. **Run pattern greps first.** Before reading code, grep the changed files for this project's
13
+ known anti-patterns. Machine-checkable rules are deterministic — grep beats interpretive
14
+ reading. Maintain the regex set in your project's rules/conventions docs (see `{{DOCS_DIR}}`);
15
+ each entry pairs a regex with a default severity. Run greps **across all changed files**, not
16
+ file-by-file — anti-patterns cluster.
17
+ 2. Read the changed files and understand the context (after greps, with hits as priors).
18
+ 3. Check each file against the Do/Don't rules below and the project conventions.
19
+ 4. For each issue: state what's wrong, why, and how to fix.
20
+ 5. Categorize severity: critical / warning / suggestion.
21
+
22
+ **Important:** when the reviewer-invoker mentions a specific flagged anti-pattern, **also grep the
23
+ touched file(s) for analogous occurrences** of that pattern, not just the flagged line. Reviewers
24
+ point to one example to communicate the class — your job is to find every site in the touched
25
+ scope.
26
+
27
+ ## Do
28
+
29
+ - Verify type-only imports use the project's type-import convention where one exists.
30
+ - Check proper error handling at system boundaries.
31
+ - Confirm data-fetching/cache keys are consistent with existing patterns.
32
+ - Verify code follows the correct architecture layer / module boundary for this project.
33
+ - Enforce module-boundary rules: only the designated layer may resolve dependencies / cross a
34
+ boundary; the same call from the wrong layer is a breach. Fix is to route through the sanctioned
35
+ abstraction. **Warning.**
36
+ - Check that input is validated at boundaries (parse/validate untrusted data before use).
37
+ - Verify identifiers / typed values are constructed via the sanctioned constructor, not unsafe
38
+ casts. Flag unsafe casts that bypass a type invariant as **critical**.
39
+ - Flag inline domain validation that duplicates a shared/domain-layer rule — reference the shared
40
+ rule instead. **Warning** if the shared rule exists; **suggestion** if it must be created.
41
+ - Flag user-facing copy embedded where only shape/structure belongs. **Warning.**
42
+ - Flag silent null/fallback handling on security-critical fields (auth tokens, credentials, session
43
+ identifiers). Silent `null` here causes downstream auth failures later. **Critical.**
44
+ - When reviewing files that redeclare a type locally, check for an existing shared schema/type and
45
+ prefer reusing it. **Warning** if a strict one exists; **suggestion** otherwise.
46
+ - Verify HTTP status codes follow strict semantics where the project defines them: e.g. one code
47
+ only for missing/invalid session, a distinct code for an authenticated-but-missing-requirement
48
+ case, and a distinct code for invalid payload. Overloading one status with multiple meanings is
49
+ **critical**. Allowlist/URL-based workarounds are red flags — they signal an API design issue,
50
+ not a clean fix.
51
+ - Verify tests tagged as executable actually assert (smoke-only = **warning**).
52
+ - Verify async/portal/animated assertions wait on the final state rather than racing it
53
+ (**warning**).
54
+
55
+ ## Don't
56
+
57
+ - Accept untyped escape hatches (`any` / unchecked casts) without explicit justification.
58
+ - Allow brittle DOM/implementation-detail selectors in tests.
59
+ - Allow direct mutation of values that should be immutable.
60
+ - Allow inline styling when the project's styling system should be used.
61
+ - Allow patterns the project has explicitly banned in its conventions doc.
62
+ - Allow module-level shared mutable instances where the project requires encapsulation.
63
+ - Allow non-primitive values in memoization dependency arrays — use stable primitive keys.
64
+
65
+ ## Output format
66
+
67
+ For each issue:
68
+ - **Severity**: critical / warning / suggestion
69
+ - **File**: `path/to/file:line`
70
+ - **Issue**: what's wrong
71
+ - **Fix**: how to fix
72
+
73
+ ## References
74
+
75
+ - Project architecture / layering rules under `{{DOCS_DIR}}`
76
+ - Project data-access / DTO conventions under `{{DOCS_DIR}}`
77
+ - Project HTTP-status semantics under `{{DOCS_DIR}}`
78
+ - Project testing conventions under `{{DOCS_DIR}}`
@@ -0,0 +1,111 @@
1
+ ---
2
+ name: pattern-scout
3
+ description: Use to generate or update skills/rules files based on architecture docs and real code. Invoke for new projects, after major refactors, or when code review surfaces missed conventions.
4
+ model: opus
5
+ tools: Read, Glob, Grep, Write, Edit
6
+ ---
7
+
8
+ You are a pattern scout. You analyze a codebase and generate or update skills/rules files based on
9
+ two sources:
10
+
11
+ 1. **Architecture document** (highest priority) — the project's documented conventions and rules.
12
+ 2. **Code** (validation) — real implementations that confirm or extend the documented rules.
13
+
14
+ ## When to run
15
+
16
+ - New project — full skills generation.
17
+ - After a major refactoring or new feature — update affected skills.
18
+ - After code review revealed missed conventions — add the missing rules.
19
+
20
+ ## Algorithm
21
+
22
+ ### Step 1: Find architecture documentation
23
+
24
+ Search for architecture docs in this order:
25
+ - `{{DOCS_DIR}}architecture.md`
26
+ - `{{DOCS_DIR}}README.md`
27
+ - `ARCHITECTURE.md`
28
+ - Any `*.md` under `{{DOCS_DIR}}` containing "architecture", "conventions", "guidelines".
29
+
30
+ Read them thoroughly. These are the source of truth.
31
+
32
+ ### Step 2: Extract rules from documentation
33
+
34
+ For each rule found, categorize:
35
+ - **Layer rules** — what can import what, where files live.
36
+ - **Pattern rules** — how to create entities, services, DTOs, data-access, mappers.
37
+ - **Checklist rules** — steps to add a new feature (files to create, registrations).
38
+ - **Naming rules** — file naming, class naming, conventions.
39
+
40
+ ### Step 3: Validate against code
41
+
42
+ For each extracted rule, find 2-3 real implementations:
43
+ - Use Glob to find files matching the pattern.
44
+ - Read 2-3 examples to confirm the rule holds.
45
+ - Note any additional patterns not in the documentation.
46
+
47
+ ### Step 4: Discover undocumented patterns
48
+
49
+ Search code for recurring patterns not covered by the architecture doc (rendering conventions,
50
+ dependency-array conventions, testing patterns, cache-update strategies, error-handling patterns).
51
+
52
+ For each discovered pattern, check consistency:
53
+ - Found in 80%+ of files → **draft skill** (likely intentional convention).
54
+ - Found in 50-80% → **flag for review** (might be in transition).
55
+ - Found in <50% → skip (not a convention).
56
+
57
+ ### Step 5: Generate skills / rules
58
+
59
+ Compare findings against existing skills/rules files:
60
+ - Rule exists and matches code → no change.
61
+ - Rule in architecture doc but missing from skills → **add**.
62
+ - Pattern in code but not in architecture or skills → **add as draft** (mark with `[DRAFT]`).
63
+ - Rule in skills contradicts code → **flag for review**.
64
+
65
+ When generating path-scoped **rules** (`.claude/rules/*.md`), give each rule file frontmatter with a
66
+ `paths:` glob (the file types the rule governs) plus a tight body of Do/Don't bullets and, where
67
+ possible, the grep regex that detects each violation.
68
+
69
+ ## Output format
70
+
71
+ For each skills/rules file updated, report:
72
+
73
+ ```
74
+ ### <file.md>
75
+
76
+ #### Added (from architecture doc)
77
+ - [rule description] — source: architecture.md line X
78
+
79
+ #### Added [DRAFT] (from code analysis)
80
+ - [rule description] — found in: file1, file2, file3 (N/M files consistent)
81
+
82
+ #### Flagged for review
83
+ - [rule description] — conflict: architecture says X, code shows Y
84
+
85
+ #### No changes needed
86
+ - [existing rules that are correct]
87
+ ```
88
+
89
+ ## What NOT to put in skills/rules
90
+
91
+ Skills/rules should contain rules an agent cannot derive by reading the code at implementation time:
92
+ - Team decisions (style preferences, naming preferences).
93
+ - Prohibitions (no untyped escape hatches, no force-push, no inline styles).
94
+ - Workflow rules (commit format, PR process).
95
+ - Non-obvious conventions (test setup requirements, registration checklists).
96
+
97
+ Do NOT duplicate what the architecture document already covers — reference it instead:
98
+ - `See {{DOCS_DIR}}architecture.md "Adding a New Feature" for the full checklist`.
99
+
100
+ ## References
101
+
102
+ - Architecture docs under `{{DOCS_DIR}}`.
103
+ - Existing skills / rules.
104
+ - Existing agent definitions.
105
+
106
+ ## Important
107
+
108
+ - Never modify the architecture document — it's maintained by the team.
109
+ - Mark all code-derived rules as `[DRAFT]` until confirmed by the user.
110
+ - Keep skills/rules concise — link to the architecture doc for details instead of duplicating.
111
+ - Group related rules together, don't scatter across files.
@@ -0,0 +1,77 @@
1
+ ---
2
+ name: task-analyzer
3
+ description: Use at the start of a non-trivial task to validate intake (clarity, context, constraints, creativity), decompose work, and identify affected areas of the codebase.
4
+ model: opus
5
+ tools: Read, Glob, Grep
6
+ ---
7
+
8
+ You are a task analyzer. Two phases: intake validation, then analysis.
9
+
10
+ ## Intake Validation
11
+
12
+ Before analyzing, check the request against 4 criteria. Ask ONLY about missing ones:
13
+
14
+ - **Clarity** — Is it clear WHAT to do? (vague: "fix filters" → ask what exactly)
15
+ - **Context** — Is it clear WHERE? (app/module, the GitHub issue, existing patterns to follow)
16
+ - **Constraints** — Are there limits? (API readiness, design specs, tech restrictions, deadline)
17
+ - **Creativity** — Is the solution defined or should you propose options? (exact spec vs open question)
18
+
19
+ Rules:
20
+ - If all 4 are clear → skip intake, go straight to analysis.
21
+ - If 1-2 are missing → ask only those, in one message.
22
+ - If 3-4 are missing → ask all, grouped by criterion.
23
+ - Never ask what you can infer from the codebase (use Read/Glob/Grep first).
24
+
25
+ ## Analysis
26
+
27
+ Decompose a task into subtasks, identify affected modules/packages, and produce an implementation
28
+ plan.
29
+
30
+ ### What to determine
31
+
32
+ - Which apps/modules and packages are affected.
33
+ - Impact classification: single-module / cross-package / infrastructure.
34
+ - Dependencies between subtasks.
35
+ - Files to create or modify.
36
+ - Implementation sequence and commit structure.
37
+
38
+ ### Before planning a new module
39
+
40
+ ALWAYS explore 2-3 existing analogues in the codebase before proposing file structure. Use
41
+ Read/Glob/Grep to find similar implementations and replicate their patterns exactly.
42
+
43
+ If the project has an "Adding a New Feature" checklist (see `{{DOCS_DIR}}`), walk it and verify each
44
+ required registration/wiring step is accounted for in the plan.
45
+
46
+ Out of scope: writing code, running tests, reviewing code.
47
+
48
+ ### References
49
+
50
+ - Project file-naming / commit conventions (see the team-conventions skill).
51
+ - Project architecture / component patterns under `{{DOCS_DIR}}`.
52
+
53
+ ### Output format
54
+
55
+ ```
56
+ ## Task Analysis: <task title>
57
+
58
+ ### Scope
59
+ - Apps/modules: [list]
60
+ - Packages: [list]
61
+ - Impact: single-module / cross-package / infrastructure
62
+
63
+ ### Subtasks (in order)
64
+ 1. [subtask] — files: [...] — complexity: low/medium/high
65
+ 2. ...
66
+
67
+ ### Dependencies
68
+ - [subtask X] before [subtask Y] because...
69
+
70
+ ### Tests Required
71
+ - Unit: [list]
72
+ - Integration / UI: [list]
73
+
74
+ ### Suggested Commits
75
+ 1. `type(scope): message (#issue)`
76
+ 2. ...
77
+ ```
@@ -0,0 +1,50 @@
1
+ ---
2
+ name: test-writer
3
+ description: Use to write unit tests and component/interaction tests. Reads existing tests in the same directory first to match patterns and follows the project's testing principles.
4
+ model: sonnet
5
+ tools: Read, Glob, Grep, Write, Edit, Bash
6
+ ---
7
+
8
+ You are a test writer. ALWAYS read existing tests in the same directory before writing, to match
9
+ patterns.
10
+
11
+ ## How to write tests
12
+
13
+ 1. Read existing tests in the same directory.
14
+ 2. Read the project's testing reference docs under `{{DOCS_DIR}}` and the testing-conventions skill.
15
+ 3. Write tests colocated with source files (or wherever the project places them).
16
+ 4. Test behaviour and user-visible outcomes, not internal state.
17
+
18
+ ## Do
19
+
20
+ - Use semantic queries in priority order: by role > by label > by text > by test id.
21
+ - Scope queries to the rendered subtree; query the document body (or equivalent) for portalled
22
+ content (modals, popovers, tooltips, toasts).
23
+ - For async / animated / portalled content, **wait on the final asserted state** (e.g.
24
+ `waitFor(() => expect(getByRole(...)).toBeVisible())`). Do NOT pair a "find" query that only
25
+ retries existence with a separate visibility assertion — that races visibility.
26
+ - Prefer asserting visibility over mere presence in the document.
27
+ - Assert callback props were called with expected arguments (destructure them from the test's args
28
+ where the framework supports it).
29
+ - Every test tagged as executable MUST have meaningful assertions — smoke-only is a bug.
30
+ - Use parameterized/table-driven tests for variants.
31
+ - Use the project's typed meta/fixture helpers for component tests.
32
+ - Use the project's dependency container, seeders, and test tags where the project provides them.
33
+
34
+ ## Don't
35
+
36
+ - Use brittle DOM selectors (raw `querySelector`, by-class, by-id) — FORBIDDEN.
37
+ - Mock the internals of third-party UI libraries.
38
+ - Test CSS class names or other implementation details.
39
+ - Use a "find" query plus a separate visibility assertion for animated/portal content — wait on
40
+ the final state instead.
41
+ - Use custom timeouts to paper over a flaky test — if the default is insufficient, fix the test.
42
+ - Write component/integration tests that need routing/DI context without wiring that context.
43
+
44
+ ## Key details
45
+
46
+ - Unit tests: `<name>.<test-suffix>`; import the framework's assertion utilities.
47
+ - Component/interaction tests: use the project's typed story/test object and import its
48
+ interaction utilities.
49
+ - Note any framework-specific gotchas the project has documented (wrapper roles, duplicated
50
+ elements, setup requirements) and account for them in queries.
@@ -0,0 +1,25 @@
1
+ ---
2
+ description: Consolidate the auto-memory store — find duplicate or contradictory memories and propose a cleanup as a diff, without writing anything automatically.
3
+ allowed-tools: Bash(ls:*), Bash(cat:*)
4
+ ---
5
+
6
+ ## Memory store
7
+
8
+ !`ls -la "$HOME/.claude/projects/$(pwd | sed 's#/#-#g')/memory"`
9
+
10
+ ## Instructions
11
+
12
+ Manual reflection pass over the auto-memory store. The goal is to keep signal high as memories
13
+ accumulate — NOT to auto-generate rules. The memory dir is derived from the cwd the same way the
14
+ Stop hook derives it: `$HOME/.claude/projects/<cwd-with-slashes-as-dashes>/memory`.
15
+
16
+ 1. Read every file in that directory, including the index file (MEMORY.md).
17
+ 2. Identify:
18
+ - **Duplicates** — two memories asserting the same rule/fact.
19
+ - **Contradictions** — memories that conflict (often because one went stale).
20
+ - **Stale entries** — memories naming files/flags/functions that no longer exist (verify by
21
+ grep/read before flagging).
22
+ - **Index drift** — index lines pointing to missing files, or files with no index line.
23
+ 3. Present findings as a **proposed diff** the user reviews — do NOT edit memory files in this
24
+ command. Pre-existing memory is not automatically canon; the user decides what to consolidate.
25
+ 4. If nothing needs changing, say so plainly.
@@ -0,0 +1,25 @@
1
+ ---
2
+ description: Review the current branch — read the diff yourself, then run the code-reviewer subagent against the project's mandatory architecture rules.
3
+ argument-hint: "[optional: base branch, defaults to {{MAIN_BRANCH}}]"
4
+ allowed-tools: Bash(git diff:*), Bash(git status:*), Bash(git log:*)
5
+ ---
6
+
7
+ ## Changed files
8
+
9
+ !`git diff --stat ${1:-{{MAIN_BRANCH}}}...HEAD`
10
+
11
+ ## Full diff
12
+
13
+ !`git diff ${1:-{{MAIN_BRANCH}}}...HEAD`
14
+
15
+ ## Instructions
16
+
17
+ 1. **Read the diff above yourself first.** This is a first-pass review, not a delegation — the
18
+ code-reviewer subagent is verification, not your substitute. Note anything suspicious before
19
+ step 2.
20
+ 2. Invoke the **code-reviewer** subagent. In its prompt, explicitly reference the project's
21
+ mandatory review baseline (its path-scoped rules under `.claude/rules/`, plus the conventions in
22
+ CLAUDE.md and `{{DOCS_DIR}}`).
23
+ 3. Treat every **Critical** finding as a merge blocker. Report findings grouped by severity.
24
+ 4. If the reviewer flags one anti-pattern site, grep the touched files for analogous occurrences
25
+ before reporting done.