@agents-inc/cli 0.72.0 → 0.74.1
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.
- package/CHANGELOG.md +36 -0
- package/dist/{chunk-ZEJIEC2A.js → chunk-4CRWKTNQ.js} +66 -261
- package/dist/chunk-4CRWKTNQ.js.map +1 -0
- package/dist/{chunk-V2XIWRHP.js → chunk-ANUYSHQA.js} +6 -7
- package/dist/chunk-ANUYSHQA.js.map +1 -0
- package/dist/{chunk-URAXGHF2.js → chunk-B7KVPY3Z.js} +20 -15
- package/dist/chunk-B7KVPY3Z.js.map +1 -0
- package/dist/{chunk-ZYUASJUN.js → chunk-BH4LN7XV.js} +8 -6
- package/dist/chunk-BH4LN7XV.js.map +1 -0
- package/dist/{chunk-J4TVAB5H.js → chunk-BM5Y6LIC.js} +2 -2
- package/dist/{chunk-6YMW4HMX.js → chunk-DNPJ5GUK.js} +6 -6
- package/dist/chunk-DNPJ5GUK.js.map +1 -0
- package/dist/chunk-E74Q7GUE.js +5132 -0
- package/dist/chunk-E74Q7GUE.js.map +1 -0
- package/dist/chunk-EMX7PA2I.js +39 -0
- package/dist/chunk-EMX7PA2I.js.map +1 -0
- package/dist/chunk-GDUOOT3J.js +689 -0
- package/dist/chunk-GDUOOT3J.js.map +1 -0
- package/dist/{chunk-MGQVO357.js → chunk-IJLAVOKZ.js} +2 -2
- package/dist/chunk-IJLAVOKZ.js.map +1 -0
- package/dist/{chunk-G3LNIYZG.js → chunk-J5T7M2CS.js} +2 -2
- package/dist/{chunk-FKRYJOPC.js → chunk-J6SHWAS6.js} +5 -5
- package/dist/chunk-J6SHWAS6.js.map +1 -0
- package/dist/{chunk-RJOLQ7EK.js → chunk-JWZLVWTX.js} +4 -4
- package/dist/{chunk-CKPJTMNC.js → chunk-KSMT5FVM.js} +4 -4
- package/dist/chunk-KSMT5FVM.js.map +1 -0
- package/dist/{chunk-OODTDGEM.js → chunk-KTF5RKKP.js} +6 -6
- package/dist/{chunk-SEAL43IR.js → chunk-NTVY4G35.js} +3 -3
- package/dist/{chunk-52THXN5G.js → chunk-NUJHWYCR.js} +2 -2
- package/dist/{chunk-HJVWBSLM.js → chunk-QJUPZPXO.js} +4 -4
- package/dist/chunk-QJUPZPXO.js.map +1 -0
- package/dist/{chunk-F43WGOGN.js → chunk-RRBWNEG3.js} +2 -2
- package/dist/chunk-RRBWNEG3.js.map +1 -0
- package/dist/chunk-SRIH4U5Y.js +159 -0
- package/dist/chunk-SRIH4U5Y.js.map +1 -0
- package/dist/{chunk-Q3YMO5YG.js → chunk-TNSVPZHP.js} +20 -2
- package/dist/chunk-TNSVPZHP.js.map +1 -0
- package/dist/{chunk-UQTG4ZBA.js → chunk-UFAP6GHD.js} +18 -20
- package/dist/chunk-UFAP6GHD.js.map +1 -0
- package/dist/{chunk-WWHDP5CP.js → chunk-V5HR77EY.js} +94 -13
- package/dist/chunk-V5HR77EY.js.map +1 -0
- package/dist/{chunk-ZFRALAK5.js → chunk-VOYGRNLS.js} +4 -5
- package/dist/chunk-VOYGRNLS.js.map +1 -0
- package/dist/{chunk-LM5YQUBR.js → chunk-WQRFVEAA.js} +6 -6
- package/dist/{chunk-LBTW5HSY.js → chunk-XP7BXHFG.js} +11 -11
- package/dist/chunk-XP7BXHFG.js.map +1 -0
- package/dist/{chunk-AHZ34QVK.js → chunk-ZCJ4YYWL.js} +40 -35
- package/dist/chunk-ZCJ4YYWL.js.map +1 -0
- package/dist/{chunk-HMJGSAKV.js → chunk-ZLMKEYDF.js} +2514 -2687
- package/dist/chunk-ZLMKEYDF.js.map +1 -0
- package/dist/{chunk-3SLO2QPW.js → chunk-ZO7C5WMJ.js} +12 -14
- package/dist/chunk-ZO7C5WMJ.js.map +1 -0
- package/dist/commands/build/marketplace.js +4 -3
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +8 -7
- package/dist/commands/build/plugins.js.map +1 -1
- package/dist/commands/build/stack.js +8 -7
- package/dist/commands/build/stack.js.map +1 -1
- package/dist/commands/compile.js +13 -9
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/config/index.js +8 -7
- package/dist/commands/config/index.js.map +1 -1
- package/dist/commands/config/path.js +7 -6
- package/dist/commands/config/path.js.map +1 -1
- package/dist/commands/config/show.js +8 -7
- package/dist/commands/diff.js +7 -6
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/doctor.js +12 -13
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +32 -36
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +15 -13
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/import/skill.js +7 -6
- package/dist/commands/import/skill.js.map +1 -1
- package/dist/commands/info.js +11 -10
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/init.js +27 -26
- package/dist/commands/list.js +7 -6
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/new/agent.js +8 -7
- package/dist/commands/new/agent.js.map +1 -1
- package/dist/commands/new/marketplace.js +11 -14
- package/dist/commands/new/marketplace.js.map +1 -1
- package/dist/commands/new/skill.js +8 -7
- package/dist/commands/outdated.js +7 -6
- package/dist/commands/outdated.js.map +1 -1
- package/dist/commands/search.js +8 -9
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/uninstall.js +10 -7
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +9 -9
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/validate.js +15 -17
- package/dist/commands/validate.js.map +1 -1
- package/dist/components/wizard/category-grid.js +2 -2
- package/dist/components/wizard/category-grid.test.js +16 -65
- package/dist/components/wizard/category-grid.test.js.map +1 -1
- package/dist/components/wizard/domain-selection.js +9 -8
- package/dist/components/wizard/source-grid.js +4 -4
- package/dist/components/wizard/source-grid.test.js +18 -16
- package/dist/components/wizard/source-grid.test.js.map +1 -1
- package/dist/components/wizard/stack-selection.js +8 -7
- package/dist/components/wizard/step-agents.js +9 -8
- package/dist/components/wizard/step-agents.test.js +14 -13
- package/dist/components/wizard/step-agents.test.js.map +1 -1
- package/dist/components/wizard/step-build.js +10 -9
- package/dist/components/wizard/step-build.test.js +16 -15
- package/dist/components/wizard/step-build.test.js.map +1 -1
- package/dist/components/wizard/step-confirm.js +5 -4
- package/dist/components/wizard/step-confirm.test.js +10 -9
- package/dist/components/wizard/step-confirm.test.js.map +1 -1
- package/dist/components/wizard/step-settings.js +8 -7
- package/dist/components/wizard/step-settings.test.js +11 -10
- package/dist/components/wizard/step-settings.test.js.map +1 -1
- package/dist/components/wizard/step-sources.js +13 -12
- package/dist/components/wizard/step-sources.test.js +18 -17
- package/dist/components/wizard/step-sources.test.js.map +1 -1
- package/dist/components/wizard/step-stack.js +11 -10
- package/dist/components/wizard/step-stack.test.js +15 -14
- package/dist/components/wizard/step-stack.test.js.map +1 -1
- package/dist/components/wizard/wizard-layout.js +8 -7
- package/dist/components/wizard/wizard.js +25 -24
- package/dist/hooks/init.js +27 -26
- package/dist/hooks/init.js.map +1 -1
- package/dist/{loader-KVKSTKWX.js → loader-NHUCFMFQ.js} +4 -3
- package/dist/{source-loader-65IAJPNV.js → source-loader-RTG42MWG.js} +7 -6
- package/dist/source-manager-NCOFHYHD.js +20 -0
- package/dist/stores/wizard-store.js +7 -6
- package/dist/stores/wizard-store.test.js +29 -28
- package/dist/stores/wizard-store.test.js.map +1 -1
- package/package.json +1 -1
- package/src/schemas/custom-metadata.schema.json +81 -0
- package/src/schemas/metadata.schema.json +127 -41
- package/src/schemas/stacks.schema.json +3 -45
- package/dist/chunk-3SLO2QPW.js.map +0 -1
- package/dist/chunk-6YMW4HMX.js.map +0 -1
- package/dist/chunk-AHZ34QVK.js.map +0 -1
- package/dist/chunk-BKL3DF2Q.js +0 -45
- package/dist/chunk-BKL3DF2Q.js.map +0 -1
- package/dist/chunk-CKPJTMNC.js.map +0 -1
- package/dist/chunk-D7FEORKC.js +0 -253
- package/dist/chunk-D7FEORKC.js.map +0 -1
- package/dist/chunk-F43WGOGN.js.map +0 -1
- package/dist/chunk-FKRYJOPC.js.map +0 -1
- package/dist/chunk-HJVWBSLM.js.map +0 -1
- package/dist/chunk-HMJGSAKV.js.map +0 -1
- package/dist/chunk-LBTW5HSY.js.map +0 -1
- package/dist/chunk-MGQVO357.js.map +0 -1
- package/dist/chunk-Q3YMO5YG.js.map +0 -1
- package/dist/chunk-T4EXUIBY.js +0 -19
- package/dist/chunk-T4EXUIBY.js.map +0 -1
- package/dist/chunk-UQTG4ZBA.js.map +0 -1
- package/dist/chunk-URAXGHF2.js.map +0 -1
- package/dist/chunk-V2XIWRHP.js.map +0 -1
- package/dist/chunk-WWHDP5CP.js.map +0 -1
- package/dist/chunk-ZEJIEC2A.js.map +0 -1
- package/dist/chunk-ZFRALAK5.js.map +0 -1
- package/dist/chunk-ZYUASJUN.js.map +0 -1
- package/dist/source-manager-LJH225GA.js +0 -19
- package/dist/stores/matrix-store.js +0 -15
- package/dist/stores/matrix-store.js.map +0 -1
- package/dist/stores/matrix-store.test.js +0 -127
- package/dist/stores/matrix-store.test.js.map +0 -1
- /package/dist/{chunk-J4TVAB5H.js.map → chunk-BM5Y6LIC.js.map} +0 -0
- /package/dist/{chunk-G3LNIYZG.js.map → chunk-J5T7M2CS.js.map} +0 -0
- /package/dist/{chunk-RJOLQ7EK.js.map → chunk-JWZLVWTX.js.map} +0 -0
- /package/dist/{chunk-OODTDGEM.js.map → chunk-KTF5RKKP.js.map} +0 -0
- /package/dist/{chunk-SEAL43IR.js.map → chunk-NTVY4G35.js.map} +0 -0
- /package/dist/{chunk-52THXN5G.js.map → chunk-NUJHWYCR.js.map} +0 -0
- /package/dist/{chunk-LM5YQUBR.js.map → chunk-WQRFVEAA.js.map} +0 -0
- /package/dist/{loader-KVKSTKWX.js.map → loader-NHUCFMFQ.js.map} +0 -0
- /package/dist/{source-loader-65IAJPNV.js.map → source-loader-RTG42MWG.js.map} +0 -0
- /package/dist/{source-manager-LJH225GA.js.map → source-manager-NCOFHYHD.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/lib/__tests__/test-fixtures.ts","../src/cli/lib/__tests__/helpers.ts","../src/cli/lib/__tests__/content-generators.ts"],"sourcesContent":["import type { ResolvedSkill } from \"../../types\";\nimport { createMockSkill, createMockCategory } from \"./helpers\";\n\n// ---------------------------------------------------------------------------\n// Canonical SKILLS registry — single source of truth for all test ResolvedSkills.\n// Use SKILLS.react, SKILLS.hono etc. directly in new test code.\n// ---------------------------------------------------------------------------\n\nexport const SKILLS = {\n // Web domain\n react: createMockSkill(\"web-framework-react\"),\n vue: createMockSkill(\"web-framework-vue-composition-api\"),\n zustand: createMockSkill(\"web-state-zustand\", {\n compatibleWith: [\"web-framework-react\"],\n }),\n pinia: createMockSkill(\"web-state-pinia\", {\n compatibleWith: [\"web-framework-vue-composition-api\"],\n }),\n scss: createMockSkill(\"web-styling-scss-modules\"),\n tailwind: createMockSkill(\"web-styling-tailwind\"),\n vitest: createMockSkill(\"web-testing-vitest\"),\n // API domain\n hono: createMockSkill(\"api-framework-hono\"),\n drizzle: createMockSkill(\"api-database-drizzle\"),\n // Methodology\n antiOverEng: createMockSkill(\"meta-methodology-anti-over-engineering\", {\n description: \"Surgical implementation, not architectural innovation\",\n }),\n} satisfies Record<string, ResolvedSkill>;\n\n// ---------------------------------------------------------------------------\n// Shared base category fixtures — canonical defaults with no overrides.\n// Use spread for per-test customization: `{ ...TEST_CATEGORIES.framework, required: true }`\n// ---------------------------------------------------------------------------\n\nexport const TEST_CATEGORIES = {\n // Web domain\n framework: createMockCategory(\"web-framework\", \"Framework\"),\n clientState: createMockCategory(\"web-client-state\", \"Client State\"),\n styling: createMockCategory(\"web-styling\", \"Styling\"),\n testing: createMockCategory(\"web-testing\", \"Testing\"),\n serverState: createMockCategory(\"web-server-state\", \"Server State\"),\n animation: createMockCategory(\"web-animation\", \"Animation\"),\n accessibility: createMockCategory(\"web-accessibility\", \"Accessibility\"),\n // API domain\n api: createMockCategory(\"api-api\", \"Backend Framework\"),\n database: createMockCategory(\"api-database\", \"Database\"),\n observability: createMockCategory(\"api-observability\", \"Observability\"),\n // Shared domain\n methodology: createMockCategory(\"shared-methodology\", \"Methodology\"),\n tooling: createMockCategory(\"shared-tooling\", \"Tooling\"),\n security: createMockCategory(\"shared-security\", \"Security\"),\n // CLI domain\n cliFramework: createMockCategory(\"cli-framework\", \"CLI Framework\"),\n // Mobile domain\n mobileFramework: createMockCategory(\"mobile-framework\", \"Mobile Framework\"),\n};\n","import path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport { mkdir, writeFile, readFile } from \"fs/promises\";\nimport { parse as parseYaml, stringify as stringifyYaml } from \"yaml\";\nimport { run, Errors } from \"@oclif/core\";\nimport ansis from \"ansis\";\nimport { createJiti } from \"jiti\";\nimport {\n CLAUDE_DIR,\n CLAUDE_SRC_DIR,\n DEFAULT_PLUGIN_NAME,\n PLUGINS_SUBDIR,\n STANDARD_DIRS,\n STANDARD_FILES,\n} from \"../../consts\";\nimport { matrix } from \"../matrix/matrix-provider\";\nimport { typedEntries } from \"../../utils/typed-object\";\nimport { computeSkillFolderHash } from \"../versioning\";\nimport { renderSkillMd, renderAgentYaml, renderConfigTs } from \"./content-generators\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport const CLI_ROOT = path.resolve(__dirname, \"../../../..\");\n\n/** Resolve @agents-inc/cli/config to the source config-exports.ts so jiti can load it in dev. */\nconst CONFIG_EXPORTS_PATH = path.resolve(__dirname, \"../../config-exports.ts\");\n\n/**\n * Run a CLI command and capture its output.\n *\n * Bun's `console.log` does not go through `process.stdout.write`, so\n * `@oclif/test`'s `runCommand` (which only intercepts `process.stdout.write`)\n * returns empty stdout/stderr in bun. This helper intercepts both layers\n * to work correctly in both Node.js and bun environments.\n */\nexport async function runCliCommand(args: string[]) {\n const origStdoutWrite = process.stdout.write;\n const origStderrWrite = process.stderr.write;\n const origLog = console.log;\n const origWarn = console.warn;\n const origError = console.error;\n\n const stdoutBuf: string[] = [];\n const stderrBuf: string[] = [];\n\n // Intercept process.stdout/stderr.write (Node.js path)\n process.stdout.write = function (str: unknown, encoding?: unknown, cb?: unknown): boolean {\n stdoutBuf.push(String(str));\n if (typeof encoding === \"function\") {\n (encoding as () => void)();\n } else if (typeof cb === \"function\") {\n (cb as () => void)();\n }\n return true;\n } as typeof process.stdout.write;\n\n process.stderr.write = function (str: unknown, encoding?: unknown, cb?: unknown): boolean {\n stderrBuf.push(String(str));\n if (typeof encoding === \"function\") {\n (encoding as () => void)();\n } else if (typeof cb === \"function\") {\n (cb as () => void)();\n }\n return true;\n } as typeof process.stderr.write;\n\n // Intercept console methods (bun path — console.log bypasses process.stdout.write)\n console.log = (...logArgs: unknown[]) => {\n stdoutBuf.push(logArgs.map(String).join(\" \") + \"\\n\");\n };\n console.warn = (...warnArgs: unknown[]) => {\n stderrBuf.push(warnArgs.map(String).join(\" \") + \"\\n\");\n };\n console.error = (...errArgs: unknown[]) => {\n stderrBuf.push(errArgs.map(String).join(\" \") + \"\\n\");\n };\n\n let error: (Error & Partial<Errors.CLIError>) | undefined;\n try {\n await run(args, { root: CLI_ROOT });\n } catch (e) {\n if (e instanceof Error) {\n error = Object.assign(e, { message: ansis.strip(e.message) }) as Error &\n Partial<Errors.CLIError>;\n }\n } finally {\n process.stdout.write = origStdoutWrite;\n process.stderr.write = origStderrWrite;\n console.log = origLog;\n console.warn = origWarn;\n console.error = origError;\n }\n\n return {\n stdout: stdoutBuf.map((s) => ansis.strip(s)).join(\"\"),\n stderr: stderrBuf.map((s) => ansis.strip(s)).join(\"\"),\n error,\n };\n}\nimport type {\n AgentConfig,\n AgentDefinition,\n AgentName,\n AgentScopeConfig,\n CategoryDefinition,\n CategoryPath,\n CompiledAgentData,\n CompileAgentConfig,\n CompileConfig,\n CompileContext,\n Domain,\n DomainSelections,\n ExtractedSkillMetadata,\n Marketplace,\n MarketplacePlugin,\n MergedSkillsMatrix,\n ProjectConfig,\n ResolvedSkill,\n ResolvedStack,\n Skill,\n SkillAssignment,\n SkillConfig,\n SkillDefinition,\n SkillSlug,\n SkillSlugMap,\n SkillId,\n SkillSource,\n SkillSourceType,\n RelationshipDefinitions,\n RawStacksConfig,\n Stack,\n StackAgentConfig,\n Category,\n} from \"../../types\";\nimport type { CompiledStackPlugin } from \"../stacks/stack-plugin-compiler\";\nimport type { WizardResultV2 } from \"../../components/wizard/wizard\";\nimport type { SourceLoadResult } from \"../loading/source-loader\";\nimport type { ResolvedConfig } from \"../configuration/config\";\nimport { useWizardStore } from \"../../stores/wizard-store\";\nimport { resolveAlias, validateSelection } from \"../matrix\";\nimport type { TestProjectConfig, TestSkill } from \"./fixtures/create-test-source\";\nimport { SKILLS, TEST_CATEGORIES } from \"./test-fixtures\";\n\nexport { fileExists, directoryExists } from \"./test-fs-utils\";\n\nexport async function readTestYaml<T>(filePath: string): Promise<T> {\n const content = await readFile(filePath, \"utf-8\");\n // Boundary cast: YAML parse returns `unknown`, caller provides expected type\n return parseYaml(content) as T;\n}\n\n/**\n * Load a config file using jiti. Handles defineConfig(), satisfies, and plain exports.\n */\nexport async function readTestTsConfig<T>(filePath: string): Promise<T> {\n const jiti = createJiti(import.meta.url, {\n moduleCache: false,\n interopDefault: true,\n alias: { \"@agents-inc/cli/config\": CONFIG_EXPORTS_PATH },\n });\n // Boundary cast: jiti returns unknown, caller provides expected type\n const result = await jiti.import(filePath, { default: true });\n return result as T;\n}\n\n/** Writes a config file with the given object into the given subdirectory (defaults to CLAUDE_SRC_DIR) */\nexport async function writeTestTsConfig(\n projectDir: string,\n config: Record<string, unknown>,\n configSubdir: string = CLAUDE_SRC_DIR,\n): Promise<void> {\n const configDir = path.join(projectDir, configSubdir);\n await mkdir(configDir, { recursive: true });\n await writeFile(path.join(configDir, STANDARD_FILES.CONFIG_TS), renderConfigTs(config));\n}\n\nexport function buildSourceConfig(overrides?: Record<string, unknown>): Record<string, unknown> {\n return {\n source: \"github:test-org/skills\",\n ...overrides,\n };\n}\n\nexport function buildProjectConfig(overrides?: Partial<ProjectConfig>): ProjectConfig {\n return {\n name: \"test-project\",\n agents: [{ name: \"web-developer\", scope: \"project\" }],\n skills: buildSkillConfigs([\"web-framework-react\"]),\n ...overrides,\n };\n}\n\nexport function buildWizardResult(\n skills: SkillConfig[],\n overrides?: Partial<WizardResultV2>,\n): WizardResultV2 {\n return {\n skills,\n selectedAgents: [],\n agentConfigs: [],\n selectedStackId: null,\n domainSelections: {} as DomainSelections,\n selectedDomains: [],\n cancelled: false,\n validation: { valid: true, errors: [], warnings: [] },\n ...overrides,\n };\n}\n\n/** Build a SkillConfig array from skill IDs with default scope and source */\nexport function buildSkillConfigs(\n skillIds: SkillId[],\n overrides?: Partial<Omit<SkillConfig, \"id\">>,\n): SkillConfig[] {\n return skillIds.map((id) => ({\n id,\n scope: overrides?.scope ?? \"project\",\n source: overrides?.source ?? \"local\",\n }));\n}\n\nexport function buildAgentConfigs(\n agentNames: string[],\n overrides?: Partial<Omit<AgentScopeConfig, \"name\">>,\n): AgentScopeConfig[] {\n return agentNames.map((name) => ({\n // Boundary cast: test factory accepts arbitrary agent names for test isolation\n name: name as AgentName,\n scope: overrides?.scope ?? \"project\",\n }));\n}\n\nexport function buildSourceResult(\n matrix: MergedSkillsMatrix,\n sourcePath: string,\n overrides?: Partial<SourceLoadResult>,\n): SourceLoadResult {\n const sourceConfig: ResolvedConfig = {\n source: sourcePath,\n sourceOrigin: \"flag\",\n };\n return {\n matrix,\n sourceConfig,\n sourcePath,\n isLocal: true,\n ...overrides,\n };\n}\n\n/**\n * Lightweight frontmatter parser for test assertions.\n * Returns raw key-value pairs (unlike the production parseFrontmatter which\n * returns typed SkillFrontmatter with Zod validation).\n */\nexport function parseTestFrontmatter(content: string): Record<string, unknown> | null {\n if (!content.startsWith(\"---\")) {\n return null;\n }\n\n const endIndex = content.indexOf(\"---\", 3);\n if (endIndex === -1) {\n return null;\n }\n\n const yamlContent = content.slice(3, endIndex).trim();\n try {\n // Boundary cast: YAML parse returns `unknown`\n return parseYaml(yamlContent) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\nimport { createTempDir, cleanupTempDir } from \"./test-fs-utils\";\nexport { createTempDir, cleanupTempDir };\n\nexport interface PluginTestDirs {\n tempDir: string;\n projectDir: string;\n pluginDir: string;\n skillsDir: string;\n agentsDir: string;\n}\n\nexport async function createTestDirs(prefix = \"ai-test-\"): Promise<PluginTestDirs> {\n const tempDir = await createTempDir(prefix);\n const projectDir = path.join(tempDir, \"project\");\n const pluginDir = path.join(projectDir, CLAUDE_DIR, PLUGINS_SUBDIR, DEFAULT_PLUGIN_NAME);\n const skillsDir = path.join(pluginDir, STANDARD_DIRS.SKILLS);\n const agentsDir = path.join(pluginDir, \"agents\");\n\n await mkdir(skillsDir, { recursive: true });\n await mkdir(agentsDir, { recursive: true });\n\n return { tempDir, projectDir, pluginDir, skillsDir, agentsDir };\n}\n\nexport async function cleanupTestDirs(dirs: PluginTestDirs): Promise<void> {\n await cleanupTempDir(dirs.tempDir);\n}\n\n/**\n * Canonical category for known test skills.\n * createMockSkill() looks up from here when no category override is provided.\n * Custom/novel skills must pass { category } in overrides.\n *\n * Uses a lazy singleton to avoid circular initialization issues:\n * test-fixtures.ts calls createMockSkill() at module level during import,\n * and ESM hoists all imports before evaluating any `const` declarations.\n */\n// eslint-disable-next-line no-var -- `var` avoids TDZ in circular ESM imports (let/const would throw)\n// Boundary cast: test factory maps arbitrary skill IDs to category strings (not all are valid Category union members)\nvar _canonicalSkillCategories: Record<string, string> | undefined;\nfunction getCanonicalSkillCategories(): Record<string, string> {\n if (!_canonicalSkillCategories) {\n _canonicalSkillCategories = {\n \"web-framework-react\": \"web-framework\",\n \"web-framework-vue-composition-api\": \"web-framework\",\n \"web-framework-original\": \"web-framework\",\n \"web-framework-simple\": \"web-framework\",\n \"web-framework-arbitrary\": \"web-framework\",\n \"web-framework-unknown\": \"web-framework\",\n \"web-styling-tailwind\": \"web-styling\",\n \"web-styling-scss-modules\": \"web-styling\",\n \"web-styling-custom\": \"web-styling\",\n \"web-state-zustand\": \"web-client-state\",\n \"web-state-pinia\": \"web-client-state\",\n \"web-state-mobx\": \"web-client-state\",\n \"web-testing-vitest\": \"web-testing\",\n \"web-testing-copier\": \"web-testing\",\n \"web-testing-metadata\": \"web-testing\",\n \"web-testing-playwright\": \"web-testing\",\n \"web-testing-cypress-e2e\": \"web-testing\",\n \"web-testing-playwright-e2e\": \"web-testing\",\n \"web-server-state-react-query\": \"web-server-state\",\n \"web-data-fetching-react-query\": \"web-server-state\",\n \"web-tooling-vite\": \"shared-tooling\",\n \"web-tooling-acme\": \"web-tooling\",\n \"web-tooling-custom\": \"web-tooling\",\n \"web-tooling-nometadata\": \"web-tooling\",\n \"web-tooling-personal\": \"web-tooling\",\n \"web-tooling-valid\": \"web-tooling\",\n \"web-tooling-incomplete\": \"web-tooling\",\n \"web-tooling-my-skill\": \"web-tooling\",\n \"web-tooling-forked-skill\": \"web-tooling\",\n \"web-tooling-test-minimal\": \"web-tooling\",\n \"web-tooling-local-skill\": \"web-tooling\",\n \"web-skill-a\": \"web-framework\",\n \"web-skill-a-v\": \"web-framework\",\n \"web-skill-b\": \"web-framework\",\n \"web-skill-b-v\": \"web-framework\",\n \"web-skill-c\": \"web-framework\",\n \"web-skill-d\": \"web-framework\",\n \"web-skill-setup\": \"web-framework\",\n \"web-skill-usage\": \"web-framework\",\n \"web-local-skill\": \"local\",\n \"web-custom-skill\": \"web-framework\",\n \"web-missing-skill\": \"web-framework\",\n \"web-unknown-skill\": \"web-framework\",\n \"web-nonexistent-skill\": \"web-framework\",\n \"api-framework-hono\": \"api-api\",\n \"api-framework-express\": \"api-api\",\n \"api-database-drizzle\": \"api-database\",\n \"api-security-auth-patterns\": \"api-security\",\n \"api-observability-datadog\": \"api-observability\",\n \"cli-framework-commander\": \"cli-framework\",\n \"infra-setup-env\": \"shared-tooling\",\n \"infra-tooling-linter\": \"unmapped-category\",\n \"infra-tooling-docker\": \"shared-tooling\",\n \"infra-ci-cd-github-actions\": \"shared-ci-cd\",\n \"infra-ci-cd-gitlab-ci\": \"shared-ci-cd\",\n \"web-accessibility-a11y\": \"web-accessibility\",\n \"web-animation-framer\": \"web-animation\",\n \"meta-methodology-investigation\": \"shared-methodology\",\n \"meta-methodology-success-criteria\": \"shared-methodology\",\n \"meta-methodology-investigation-requirements\": \"shared-methodology\",\n \"meta-methodology-anti-over-engineering\": \"shared-methodology\",\n \"meta-methodology-write-verification\": \"shared-methodology\",\n \"meta-methodology-improvement-protocol\": \"shared-methodology\",\n \"meta-methodology-context-management\": \"shared-methodology\",\n \"meta-company-patterns\": \"local\",\n \"meta-test-skill\": \"shared-methodology\",\n \"web-framework-nonexistent\": \"web-framework\",\n \"web-framework-react-pro\": \"web-framework\",\n \"web-framework-react-strict\": \"web-framework\",\n \"web-framework-react-minimal\": \"web-framework\",\n };\n }\n return _canonicalSkillCategories;\n}\n\n/** Maps non-domain SkillIdPrefix values to their corresponding Domain */\nconst DOMAIN_PREFIX_MAP: Record<string, Domain> = {\n meta: \"shared\",\n infra: \"shared\",\n security: \"shared\",\n};\n\n/**\n * Creates a TestSkill for disk-based integration tests (createTestSource).\n * Derives slug, displayName, domain, and category from the skill ID,\n * using the canonical category registry for correct category mapping.\n */\nexport function createTestSkill(\n id: SkillId,\n description: string,\n overrides?: Partial<TestSkill>,\n): TestSkill {\n const segments = id.split(\"-\");\n const rawPrefix = segments[0] ?? \"web\";\n const domain = (DOMAIN_PREFIX_MAP[rawPrefix] ?? rawPrefix) as Domain;\n const canonicalCategories = getCanonicalSkillCategories();\n // Boundary cast: category registry returns arbitrary strings for non-canonical IDs\n const category = (canonicalCategories[id] ?? `${segments[0]}-${segments[1]}`) as CategoryPath;\n const slug = (segments.length >= 3 ? segments.slice(2).join(\"-\") : id) as SkillSlug;\n const displayName = slug\n .split(\"-\")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n\n return {\n id,\n slug,\n displayName,\n description,\n category,\n author: \"@test\",\n domain,\n tags: [],\n ...overrides,\n };\n}\n\nexport function createMockSkill(id: SkillId, overrides?: Partial<ResolvedSkill>): ResolvedSkill {\n // Boundary cast: category registry returns arbitrary strings for non-canonical IDs\n const category = (overrides?.category ?? getCanonicalSkillCategories()[id]) as\n | CategoryPath\n | undefined;\n\n if (!category) {\n throw new Error(\n `createMockSkill: \"${id}\" not in canonical registry — provide { category } in overrides`,\n );\n }\n\n // Derive slug from skill ID: strip domain-category prefix to get the last segment(s)\n // e.g., \"web-framework-react\" -> \"react\", \"meta-methodology-anti-over-engineering\" -> \"anti-over-engineering\"\n const segments = id.split(\"-\");\n const defaultSlug = (segments.length >= 3 ? segments.slice(2).join(\"-\") : id) as SkillSlug;\n\n // Derive display name from slug: title-case each segment\n const defaultDisplayName = defaultSlug\n .split(\"-\")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n\n return {\n id,\n slug: defaultSlug,\n displayName: defaultDisplayName,\n description: `${id} skill`,\n category,\n tags: [],\n author: \"@test\",\n conflictsWith: [],\n isRecommended: false,\n requires: [],\n alternatives: [],\n discourages: [],\n compatibleWith: [],\n path: `skills/${category}/${id}/`,\n ...overrides,\n };\n}\n\nexport function createMockSkillSource(\n type: SkillSourceType,\n overrides?: Partial<SkillSource>,\n): SkillSource {\n const defaults: Record<SkillSourceType, SkillSource> = {\n public: { name: \"public\", type: \"public\", installed: false },\n private: {\n name: \"private-source\",\n type: \"private\",\n url: \"github:org/skills\",\n installed: false,\n },\n local: { name: \"local\", type: \"local\", installed: true, installMode: \"local\" },\n };\n return { ...defaults[type], ...overrides };\n}\n\n/**\n * Creates a mock ExtractedSkillMetadata for testing.\n * Used when mocking extractAllSkills() return values.\n */\nexport function createMockExtractedSkill(\n id: SkillId,\n overrides?: Partial<ExtractedSkillMetadata>,\n): ExtractedSkillMetadata {\n // Derive directory path and category from the skill ID convention: \"domain-category-name\"\n const segments = id.split(\"-\");\n const domain = segments[0] ?? \"web\";\n const category = segments[1] ?? \"framework\";\n const name = segments.slice(2).join(\"-\") || \"skill\";\n const directoryPath = `${domain}/${category}/${name}`;\n\n return {\n id,\n directoryPath,\n description: `${id} skill`,\n category: `${domain}-${category}` as CategoryPath,\n author: \"@test\",\n tags: [],\n path: `skills/${directoryPath}/`,\n domain: domain as Domain,\n displayName: name,\n slug: name as SkillSlug,\n ...overrides,\n };\n}\n\nexport function createMockMatrix(\n skillsOrFirstSkill?: Record<string, ResolvedSkill> | ResolvedSkill,\n ...rest: (ResolvedSkill | Partial<MergedSkillsMatrix>)[]\n): MergedSkillsMatrix {\n let skillsRecord: Record<string, ResolvedSkill>;\n let overrides: Partial<MergedSkillsMatrix> | undefined;\n\n if (skillsOrFirstSkill === undefined) {\n // Empty call: createMockMatrix()\n skillsRecord = {};\n } else if (\n \"id\" in skillsOrFirstSkill &&\n typeof (skillsOrFirstSkill as ResolvedSkill).id === \"string\" &&\n \"slug\" in skillsOrFirstSkill\n ) {\n // New spread syntax: createMockMatrix(skill1, skill2, ..., optionalOverrides?)\n const allArgs = [skillsOrFirstSkill, ...rest];\n const lastArg = allArgs[allArgs.length - 1];\n\n // Detect if last arg is overrides (has no 'id' + 'slug' properties)\n if (lastArg && !(\"id\" in lastArg && \"slug\" in lastArg)) {\n overrides = lastArg as Partial<MergedSkillsMatrix>;\n const skills = allArgs.slice(0, -1) as ResolvedSkill[];\n skillsRecord = {};\n for (const skill of skills) {\n skillsRecord[skill.id] = skill;\n }\n } else {\n const skills = allArgs as ResolvedSkill[];\n skillsRecord = {};\n for (const skill of skills) {\n skillsRecord[skill.id] = skill;\n }\n }\n } else {\n // Old record syntax: createMockMatrix({ \"id\": skill }, overrides?)\n skillsRecord = skillsOrFirstSkill as Record<string, ResolvedSkill>;\n overrides = rest[0] as Partial<MergedSkillsMatrix> | undefined;\n }\n\n // Boundary cast: empty objects are populated in the loop below\n const autoSlugToId = {} as Record<SkillSlug, SkillId>;\n const autoIdToSlug = {} as Record<SkillId, SkillSlug>;\n for (const [, skill] of typedEntries(skillsRecord)) {\n if (skill.slug) {\n autoSlugToId[skill.slug] = skill.id;\n autoIdToSlug[skill.id] = skill.slug;\n }\n }\n\n return {\n version: \"1.0.0\",\n categories: {} as Record<Category, import(\"../../types\").CategoryDefinition>,\n skills: skillsRecord,\n suggestedStacks: [],\n slugMap: { slugToId: autoSlugToId, idToSlug: autoIdToSlug },\n generatedAt: new Date().toISOString(),\n ...overrides,\n };\n}\n\nexport function createMockAgent(\n name: string,\n overrides?: Partial<AgentDefinition>,\n): AgentDefinition {\n return {\n title: name,\n description: `${name} agent`,\n tools: [\"Read\", \"Write\", \"Edit\", \"Grep\", \"Glob\", \"Bash\"],\n model: \"opus\",\n permissionMode: \"default\",\n ...overrides,\n };\n}\n\nexport function createMockAgentConfig(\n name: string,\n skills: Skill[] = [],\n overrides?: Partial<AgentConfig>,\n): AgentConfig {\n return {\n name,\n title: `${name} agent`,\n description: `Test ${name}`,\n tools: [\"Read\", \"Write\"],\n skills,\n path: name,\n ...overrides,\n };\n}\n\nexport function createMockSkillEntry(\n id: SkillId,\n preloaded = false,\n overrides?: Partial<Skill>,\n): Skill {\n return {\n id,\n path: `skills/${id}/`,\n description: `${id} skill`,\n usage: `when working with ${id}`,\n preloaded,\n ...overrides,\n };\n}\n\nexport function createCompileContext(overrides?: Partial<CompileContext>): CompileContext {\n return {\n stackId: \"test-stack\",\n verbose: false,\n projectRoot: \"/project\",\n outputDir: `/project/${CLAUDE_DIR}/${PLUGINS_SUBDIR}/${DEFAULT_PLUGIN_NAME}`,\n ...overrides,\n };\n}\n\nexport async function writeTestSkill(\n skillsDir: string,\n skillId: SkillId,\n options?: {\n /** Extra fields to merge into metadata.yaml (e.g., forkedFrom, displayName) */\n extraMetadata?: Record<string, unknown>;\n /** Skip metadata.yaml creation entirely */\n skipMetadata?: boolean;\n /** Custom SKILL.md content (overrides default generated content) */\n skillContent?: string;\n },\n): Promise<string> {\n const skill = matrix.skills[skillId];\n\n if (!options?.skipMetadata && !skill) {\n throw new Error(\n `writeTestSkill: \"${skillId}\" not found in matrix store — populate the store in beforeEach`,\n );\n }\n\n const skillDir = path.join(skillsDir, skillId);\n await mkdir(skillDir, { recursive: true });\n\n await writeFile(\n path.join(skillDir, STANDARD_FILES.SKILL_MD),\n options?.skillContent ?? renderSkillMd(skillId, skill?.description),\n );\n\n if (!options?.skipMetadata && skill) {\n const { slug, category, author } = skill;\n const domain = category.split(\"-\")[0];\n\n const contentHash = await computeSkillFolderHash(skillDir);\n const baseMetadata = {\n author,\n category,\n domain,\n slug,\n contentHash,\n };\n await writeFile(\n path.join(skillDir, STANDARD_FILES.METADATA_YAML),\n stringifyYaml({ ...baseMetadata, ...options?.extraMetadata }),\n );\n }\n\n return skillDir;\n}\n\n/**\n * Creates a source-level skill directory with SKILL.md and rich metadata.yaml.\n * Use this when testing `extractAllSkills()` and `mergeMatrixWithSkills()`.\n *\n * Unlike `writeTestSkill()` which creates installed skills, this writes skills\n * in the source directory layout (under `src/skills/<domain>/<category>/<name>/`).\n */\nexport async function writeSourceSkill(\n skillsDir: string,\n directoryPath: string,\n config: TestSkill,\n): Promise<string> {\n const skillDir = path.join(skillsDir, directoryPath);\n await mkdir(skillDir, { recursive: true });\n\n await writeFile(\n path.join(skillDir, STANDARD_FILES.SKILL_MD),\n renderSkillMd(config.id, config.description),\n );\n\n const domain = config.domain;\n const slug = config.slug;\n const metadata: Record<string, unknown> = {\n displayName: config.id,\n slug,\n category: config.category,\n domain,\n author: config.author ?? \"@test\",\n ...(config.tags && { tags: config.tags }),\n };\n\n await writeFile(path.join(skillDir, STANDARD_FILES.METADATA_YAML), stringifyYaml(metadata));\n\n return skillDir;\n}\n\nexport async function writeTestAgent(\n agentsDir: string,\n agentName: string,\n options?: { description?: string },\n): Promise<string> {\n const agentDir = path.join(agentsDir, agentName);\n await mkdir(agentDir, { recursive: true });\n\n await writeFile(\n path.join(agentDir, STANDARD_FILES.AGENT_METADATA_YAML),\n renderAgentYaml(agentName, options?.description),\n );\n\n return agentDir;\n}\n\nexport function createMockCategory(\n id: string,\n displayName: string,\n overrides?: Partial<CategoryDefinition>,\n): CategoryDefinition {\n // Boundary cast: test factory accepts arbitrary category IDs for test isolation\n return {\n id: id as Category,\n displayName,\n description: `${displayName} category`,\n domain: \"web\",\n exclusive: true,\n required: false,\n order: 0,\n ...overrides,\n };\n}\n\nexport function createMockResolvedStack(\n id: string,\n name: string,\n overrides?: Partial<ResolvedStack>,\n): ResolvedStack {\n return {\n id,\n name,\n description: `${name} stack`,\n skills: {},\n allSkillIds: [],\n philosophy: \"\",\n ...overrides,\n };\n}\n\n/**\n * Builds a comprehensive test matrix with 8 skills across 7 categories,\n * 2 suggested stacks, display name mappings, and relationship data\n * (conflicts, recommends). Includes anti-over-engineering methodology skill.\n * @returns A fully populated MergedSkillsMatrix with realistic test data\n */\nexport function createComprehensiveMatrix(\n overrides?: Partial<MergedSkillsMatrix>,\n): MergedSkillsMatrix {\n // Skill categories use domain-prefixed Category IDs (matching production\n // metadata.yaml and the categories map keys, e.g., \"web-framework\", \"api-api\").\n const skills = {\n \"web-framework-react\": SKILLS.react,\n \"web-framework-vue-composition-api\": {\n ...SKILLS.vue,\n conflictsWith: [{ skillId: \"web-framework-react\", reason: \"Choose one framework\" }],\n } satisfies ResolvedSkill,\n \"web-state-zustand\": SKILLS.zustand,\n \"web-styling-scss-modules\": SKILLS.scss,\n \"api-framework-hono\": SKILLS.hono,\n \"api-database-drizzle\": SKILLS.drizzle,\n \"web-testing-vitest\": SKILLS.vitest,\n // Methodology skill\n \"meta-methodology-anti-over-engineering\": SKILLS.antiOverEng,\n };\n\n const categories = {\n \"web-framework\": {\n ...TEST_CATEGORIES.framework,\n domain: \"web\",\n exclusive: true,\n required: true,\n },\n \"web-client-state\": { ...TEST_CATEGORIES.clientState, domain: \"web\", order: 1 },\n \"web-styling\": { ...TEST_CATEGORIES.styling, domain: \"web\", order: 2 },\n \"api-api\": { ...TEST_CATEGORIES.api, domain: \"api\", exclusive: true, required: true },\n \"api-database\": { ...TEST_CATEGORIES.database, domain: \"api\", order: 1 },\n \"web-testing\": {\n ...TEST_CATEGORIES.testing,\n domain: \"shared\",\n exclusive: false,\n order: 10,\n },\n \"shared-methodology\": {\n ...TEST_CATEGORIES.methodology,\n domain: \"shared\",\n exclusive: false,\n required: false,\n order: 11,\n },\n } as Record<Category, CategoryDefinition>;\n\n const suggestedStacks: ResolvedStack[] = [\n createMockResolvedStack(\"nextjs-fullstack\", \"Next.js Fullstack\", {\n description: \"Complete Next.js stack with React and Hono\",\n skills: {\n \"web-developer\": {\n \"web-framework\": [\"web-framework-react\"],\n \"web-client-state\": [\"web-state-zustand\"],\n \"web-styling\": [\"web-styling-scss-modules\"],\n },\n \"api-developer\": {\n \"api-api\": [\"api-framework-hono\"],\n \"api-database\": [\"api-database-drizzle\"],\n },\n } as ResolvedStack[\"skills\"],\n allSkillIds: [\n \"web-framework-react\",\n \"web-state-zustand\",\n \"web-styling-scss-modules\",\n \"api-framework-hono\",\n \"api-database-drizzle\",\n ],\n philosophy: \"Modern, type-safe fullstack development\",\n }),\n createMockResolvedStack(\"vue-stack\", \"Vue Stack\", {\n description: \"Vue.js frontend stack\",\n skills: {\n \"web-developer\": {\n \"web-framework\": [\"web-framework-vue-composition-api\"],\n },\n } as ResolvedStack[\"skills\"],\n allSkillIds: [\"web-framework-vue-composition-api\"],\n philosophy: \"Progressive framework approach\",\n }),\n ];\n\n // Boundary cast: test matrix only contains a subset of all possible slugs\n const slugToId = {\n react: \"web-framework-react\",\n \"vue-composition-api\": \"web-framework-vue-composition-api\",\n zustand: \"web-state-zustand\",\n \"scss-modules\": \"web-styling-scss-modules\",\n hono: \"api-framework-hono\",\n drizzle: \"api-database-drizzle\",\n vitest: \"web-testing-vitest\",\n \"anti-over-engineering\": \"meta-methodology-anti-over-engineering\",\n } as unknown as Record<SkillSlug, SkillId>;\n\n // Boundary cast: Object.fromEntries returns { [k: string]: string }\n const idToSlug = Object.fromEntries(\n typedEntries(slugToId).map(([slug, fullId]) => [fullId, slug]),\n ) as SkillSlugMap[\"idToSlug\"];\n\n return createMockMatrix(skills, {\n categories,\n suggestedStacks,\n slugMap: { slugToId, idToSlug },\n ...overrides,\n });\n}\n\n/**\n * Builds a lightweight test matrix with 5 skills, 5 categories, and 2 stacks.\n * Use instead of createComprehensiveMatrix when relationship data is not needed.\n * @returns A minimal MergedSkillsMatrix for basic integration tests\n */\nexport function createBasicMatrix(overrides?: Partial<MergedSkillsMatrix>): MergedSkillsMatrix {\n // Domain-prefixed Category IDs — see createComprehensiveMatrix comment\n const skills = {\n \"web-framework-react\": SKILLS.react,\n \"web-state-zustand\": SKILLS.zustand,\n \"api-framework-hono\": SKILLS.hono,\n \"web-testing-vitest\": SKILLS.vitest,\n // Methodology skill\n \"meta-methodology-anti-over-engineering\": SKILLS.antiOverEng,\n };\n\n const suggestedStacks: ResolvedStack[] = [\n createMockResolvedStack(\"react-fullstack\", \"React Fullstack\", {\n allSkillIds: [\"web-framework-react\", \"web-state-zustand\", \"api-framework-hono\"],\n }),\n createMockResolvedStack(\"testing-stack\", \"Testing Stack\", {\n allSkillIds: [\"web-testing-vitest\"],\n }),\n ];\n\n return createMockMatrix(skills, {\n suggestedStacks,\n categories: {\n \"web-framework\": {\n ...TEST_CATEGORIES.framework,\n domain: \"web\",\n exclusive: true,\n required: true,\n },\n \"web-client-state\": { ...TEST_CATEGORIES.clientState, domain: \"web\", order: 1 },\n \"api-api\": {\n ...TEST_CATEGORIES.api,\n domain: \"api\",\n exclusive: true,\n required: true,\n },\n \"web-testing\": {\n ...TEST_CATEGORIES.testing,\n displayName: \"Testing Framework\",\n domain: \"shared\",\n exclusive: false,\n },\n \"shared-methodology\": {\n ...TEST_CATEGORIES.methodology,\n domain: \"shared\",\n exclusive: false,\n required: false,\n },\n } as Record<Category, CategoryDefinition>,\n ...overrides,\n });\n}\n\n/**\n * Replicates `handleComplete` from wizard.tsx for the \"customize\" path.\n *\n * Given the wizard store state (after simulated user selections), this\n * builds the same WizardResultV2 that the real wizard produces:\n * 1. Collects all selected technologies from domainSelections\n * 2. Resolves aliases to canonical skill IDs\n * 3. Runs validation\n */\nexport function buildWizardResultFromStore(\n matrix: MergedSkillsMatrix,\n overrides?: Partial<WizardResultV2>,\n): WizardResultV2 {\n const store = useWizardStore.getState();\n\n let allSkills: SkillId[];\n\n if (store.selectedStackId && store.stackAction === \"defaults\") {\n const stack = matrix.suggestedStacks.find((s) => s.id === store.selectedStackId);\n allSkills = [...(stack?.allSkillIds || [])];\n } else {\n const techNames = store.getAllSelectedTechnologies();\n allSkills = techNames.map((tech) => resolveAlias(tech));\n }\n\n const validation = validateSelection(allSkills);\n\n return {\n skills: store.skillConfigs.length > 0 ? store.skillConfigs : buildSkillConfigs(allSkills),\n selectedAgents: store.selectedAgents,\n agentConfigs: store.agentConfigs,\n selectedStackId: store.selectedStackId,\n domainSelections: store.domainSelections,\n selectedDomains: store.selectedDomains,\n cancelled: false,\n validation,\n ...overrides,\n };\n}\n\n/**\n * Simulates a user selecting specific skills via the wizard store.\n *\n * Sets up domainSelections as if the user toggled each skill in the build step,\n * using the matrix to look up the correct domain and category per skill.\n */\nexport function simulateSkillSelections(\n skillIds: SkillId[],\n matrix: MergedSkillsMatrix,\n selectedDomains: string[],\n): void {\n const domainSelections = skillIds.reduce<DomainSelections>((acc, skillId) => {\n const skill = matrix.skills[skillId];\n if (!skill) return acc;\n // Boundary cast: skill.category is a Category at runtime\n const category = skill.category as Category;\n const domain = matrix.categories[category]?.domain;\n if (!domain) return acc;\n const domainObj = acc[domain] ?? {};\n const subcatList = domainObj[category] ?? [];\n if (subcatList.includes(skillId)) return acc;\n return {\n ...acc,\n [domain]: { ...domainObj, [category]: [...subcatList, skillId] },\n };\n }, {});\n\n useWizardStore.setState({\n domainSelections,\n selectedDomains: selectedDomains as Domain[],\n approach: \"scratch\",\n step: \"confirm\",\n });\n}\n\n/**\n * Extracts skill IDs from a stack assignment value, which may be:\n * - A bare string (e.g., \"web-framework-react\")\n * - An object with .id (e.g., { id: \"web-framework-react\", preloaded: true })\n * - An array of strings or objects\n */\nexport function extractSkillIdsFromAssignment(assignment: unknown): string[] {\n if (typeof assignment === \"string\") {\n return [assignment];\n }\n if (Array.isArray(assignment)) {\n return assignment.flatMap((item) => extractSkillIdsFromAssignment(item));\n }\n if (typeof assignment === \"object\" && assignment !== null && \"id\" in assignment) {\n return [String((assignment as { id: string }).id)];\n }\n return [];\n}\n\nexport function buildTestProjectConfig(\n agents: string[],\n skills: Array<string | { id: string }>,\n overrides?: Partial<TestProjectConfig>,\n): TestProjectConfig {\n return {\n name: \"test-project\",\n description: \"Test project\",\n agents,\n skills,\n ...overrides,\n };\n}\n\nexport function createMockSkillDefinition(\n id: SkillId,\n overrides?: Partial<SkillDefinition>,\n): SkillDefinition {\n return {\n id,\n path: `skills/${id}/`,\n description: `${id} skill`,\n ...overrides,\n };\n}\n\n/** Decomposed matrix config returned by createMockMatrixConfig (replaces SkillsMatrixConfig) */\nexport type MockMatrixConfig = {\n categories: Record<string, CategoryDefinition>;\n relationships: RelationshipDefinitions;\n};\n\nexport function createMockMatrixConfig(\n categories: Record<string, CategoryDefinition>,\n overrides?: {\n relationships?: Partial<RelationshipDefinitions>;\n },\n): MockMatrixConfig {\n const defaultRelationships: RelationshipDefinitions = {\n conflicts: [],\n discourages: [],\n recommends: [],\n requires: [],\n alternatives: [],\n };\n return {\n categories,\n relationships: overrides?.relationships\n ? { ...defaultRelationships, ...overrides.relationships }\n : defaultRelationships,\n };\n}\n\nexport function createMockStack(\n id: string,\n config: {\n name: string;\n description?: string;\n agents: Record<string, StackAgentConfig>;\n philosophy?: string;\n },\n): Stack {\n return {\n id,\n name: config.name,\n description: config.description ?? \"\",\n // Boundary cast: test callers may pass arbitrary agent names (e.g., \"nonexistent-agent\")\n agents: config.agents as Stack[\"agents\"],\n philosophy: config.philosophy,\n };\n}\n\nexport function createMockCompileConfig(\n agents: Record<string, CompileAgentConfig>,\n overrides?: Partial<CompileConfig>,\n): CompileConfig {\n return {\n name: \"Test Plugin\",\n description: \"Test description\",\n agents,\n ...overrides,\n };\n}\n\nexport function createMockCompiledStackPlugin(\n overrides?: Partial<CompiledStackPlugin>,\n): CompiledStackPlugin {\n return {\n pluginPath: \"/tmp/cc-stack-123456/test-stack\",\n manifest: { name: \"test-stack\", version: \"1.0.0\" },\n stackName: \"Test Stack\",\n agents: [\"web-developer\"],\n skillPlugins: [\"web-framework-react\"],\n hasHooks: false,\n ...overrides,\n };\n}\n\nexport function createMockSkillAssignment(id: SkillId, preloaded = false): SkillAssignment {\n return { id, preloaded };\n}\n\nexport function createMockRawStacksConfig(): RawStacksConfig {\n return {\n stacks: [\n {\n id: \"nextjs-fullstack\",\n name: \"Next.js Fullstack\",\n description: \"Full-stack Next.js with Hono API\",\n agents: {\n \"web-developer\": {\n \"web-framework\": \"web-framework-react\",\n \"web-styling\": \"web-styling-scss-modules\",\n },\n \"api-developer\": {\n \"api-api\": \"api-framework-hono\",\n \"api-database\": \"api-database-drizzle\",\n },\n },\n },\n {\n id: \"vue-spa\",\n name: \"Vue SPA\",\n description: \"Vue single-page application\",\n agents: {\n \"web-developer\": {\n \"web-framework\": \"web-framework-vue-composition-api\",\n \"web-styling\": \"web-styling-tailwind\",\n },\n },\n },\n ],\n };\n}\n\nexport function createMockRawStacksConfigWithArrays(): RawStacksConfig {\n return {\n stacks: [\n {\n id: \"multi-select-stack\",\n name: \"Multi-Select Stack\",\n description: \"Stack with array-valued categories\",\n agents: {\n \"web-developer\": {\n \"web-framework\": \"web-framework-react\",\n \"shared-methodology\": [\n \"meta-methodology-investigation-requirements\",\n \"meta-methodology-anti-over-engineering\",\n \"meta-methodology-success-criteria\",\n ],\n },\n \"pattern-scout\": {\n \"shared-methodology\": [\n \"meta-methodology-investigation-requirements\",\n \"meta-methodology-anti-over-engineering\",\n ],\n \"shared-research\": \"meta-research-research-methodology\",\n },\n },\n },\n ],\n };\n}\n\nexport function createMockRawStacksConfigWithObjects(): RawStacksConfig {\n return {\n stacks: [\n {\n id: \"object-stack\",\n name: \"Object Stack\",\n description: \"Stack with object-form skill assignments\",\n agents: {\n \"web-developer\": {\n \"web-framework\": [{ id: \"web-framework-react\", preloaded: true }],\n \"web-styling\": \"web-styling-scss-modules\",\n \"shared-methodology\": [\n { id: \"meta-methodology-investigation-requirements\", preloaded: true },\n \"meta-methodology-anti-over-engineering\",\n ],\n },\n },\n },\n ],\n };\n}\n\nexport function createMockMarketplace(plugins: MarketplacePlugin[] = []): Marketplace {\n return {\n name: \"test-marketplace\",\n version: \"1.0.0\",\n owner: { name: \"Test Owner\" },\n plugins,\n };\n}\n\nexport function createMockMarketplacePlugin(\n name: string,\n source: MarketplacePlugin[\"source\"] = \"local\",\n): MarketplacePlugin {\n return {\n name,\n source,\n };\n}\n\n/** Convert a TestSkill (disk-based) to a ResolvedSkill (in-memory) for matrix creation. */\nexport function testSkillToResolvedSkill(\n skill: TestSkill,\n overrides?: Partial<ResolvedSkill>,\n): ResolvedSkill {\n // Boundary cast: TestSkill.id is string, but in practice always a valid SkillId\n return createMockSkill(skill.id as SkillId, {\n description: skill.description,\n ...(skill.tags?.length ? { tags: skill.tags } : {}),\n ...overrides,\n });\n}\n\n/**\n * Creates a ResolvedSkill with availableSources annotation for multi-source testing.\n * Simulates what multi-source-loader.ts does after tagging.\n */\nexport function createMockMultiSourceSkill(\n id: SkillId,\n sources: SkillSource[],\n overrides?: Partial<ResolvedSkill>,\n): ResolvedSkill {\n const activeSource = sources.find((s) => s.installed) ?? sources[0];\n return createMockSkill(id, {\n availableSources: sources,\n activeSource,\n ...overrides,\n });\n}\n\nexport function createMockCompiledAgentData(overrides?: Partial<AgentConfig>): CompiledAgentData {\n const agent = createMockAgentConfig(\"test-agent\", [], {\n title: \"Test Agent\",\n description: \"A test agent\",\n ...overrides,\n });\n\n return {\n agent,\n intro: \"Test intro\",\n workflow: \"Test workflow\",\n examples: \"Test examples\",\n criticalRequirementsTop: \"\",\n criticalReminders: \"\",\n outputFormat: \"\",\n skills: agent.skills,\n preloadedSkills: [],\n dynamicSkills: [],\n preloadedSkillIds: [],\n };\n}\n\nexport { SKILLS, TEST_CATEGORIES } from \"./test-fixtures\";\n","/**\n * Pure content renderers for test file generation.\n * Single source of truth for all test content templates.\n */\n\nexport function renderSkillMd(id: string, description?: string, body?: string): string {\n const desc = description ?? `${id} skill`;\n const content = body ?? `# ${id}\\n\\n${desc}`;\n return `---\nname: ${id}\ndescription: ${desc}\n---\n\n${content}\n`;\n}\n\nexport function renderConfigTs(config: Record<string, unknown>): string {\n return `export default ${JSON.stringify(config, null, 2)};\\n`;\n}\n\nexport function renderAgentYaml(\n name: string,\n description?: string,\n options?: { title?: string; tools?: string[] },\n): string {\n const desc = description ?? `Test ${name} agent`;\n const title = options?.title ?? `${name} Agent`;\n const tools = options?.tools ?? [\"Read\", \"Write\"];\n return `id: ${name}\ntitle: ${title}\ndescription: ${desc}\ntools:\n${tools.map((t) => ` - ${t}`).join(\"\\n\")}`;\n}\n\nexport function renderCategoriesTs(categories: Record<string, unknown>): string {\n return renderConfigTs(categories);\n}\n\nexport function renderRulesTs(rules: Record<string, unknown>): string {\n return renderConfigTs(rules);\n}\n"],"mappings":"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","names":["__filename","__dirname"]}
|
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
} from "./chunk-AUNBGZS4.js";
|
|
8
8
|
import {
|
|
9
9
|
useWizardStore
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-B7KVPY3Z.js";
|
|
11
11
|
import {
|
|
12
|
-
|
|
13
|
-
} from "./chunk-
|
|
12
|
+
matrix
|
|
13
|
+
} from "./chunk-E74Q7GUE.js";
|
|
14
14
|
import {
|
|
15
15
|
DEFAULT_SCRATCH_DOMAINS
|
|
16
16
|
} from "./chunk-EGMQ3SXN.js";
|
|
@@ -32,7 +32,6 @@ var StackSelection = ({
|
|
|
32
32
|
onCancel
|
|
33
33
|
}) => {
|
|
34
34
|
const { selectStack, setApproach, setStackAction, populateFromSkillIds, toggleDomain } = useWizardStore();
|
|
35
|
-
const matrix = useMatrixStore((s) => s.matrix);
|
|
36
35
|
const [focusedIndex, setFocusedIndex] = useState(INITIAL_FOCUSED_INDEX);
|
|
37
36
|
const stacks = matrix.suggestedStacks;
|
|
38
37
|
const stackCount = stacks.length;
|
|
@@ -111,4 +110,4 @@ var StackSelection = ({
|
|
|
111
110
|
export {
|
|
112
111
|
StackSelection
|
|
113
112
|
};
|
|
114
|
-
//# sourceMappingURL=chunk-
|
|
113
|
+
//# sourceMappingURL=chunk-VOYGRNLS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/components/wizard/stack-selection.tsx"],"sourcesContent":["import { Box, useInput } from \"ink\";\nimport React, { useState } from \"react\";\nimport { DEFAULT_SCRATCH_DOMAINS } from \"../../consts.js\";\nimport { useWizardStore } from \"../../stores/wizard-store.js\";\nimport { matrix } from \"../../lib/matrix/matrix-provider.js\";\nimport { useSectionScroll } from \"../hooks/use-section-scroll.js\";\nimport { SelectionCard } from \"./selection-card.js\";\n\nconst INITIAL_FOCUSED_INDEX = 0;\nconst SCRATCH_LABEL = \"Start from scratch\";\nconst SCRATCH_DESCRIPTION = \"Select domains and skills manually\";\n\n/** Number of extra items after the stack list (scratch option) */\nconst EXTRA_ITEMS_COUNT = 1;\n\nexport type StackSelectionProps = {\n /** Available height in terminal lines for the scrollable viewport. 0 = no constraint. */\n availableHeight?: number;\n onCancel?: () => void;\n};\n\nexport const StackSelection: React.FC<StackSelectionProps> = ({\n availableHeight = 0,\n onCancel,\n}) => {\n const { selectStack, setApproach, setStackAction, populateFromSkillIds, toggleDomain } =\n useWizardStore();\n\n const [focusedIndex, setFocusedIndex] = useState(INITIAL_FOCUSED_INDEX);\n\n const stacks = matrix.suggestedStacks;\n const stackCount = stacks.length;\n const scratchIndex = stackCount;\n const totalItems = stackCount + EXTRA_ITEMS_COUNT;\n\n const { setSectionRef, scrollEnabled, scrollTopPx } = useSectionScroll({\n sectionCount: totalItems,\n focusedIndex,\n availableHeight,\n });\n\n useInput((input, key) => {\n if (key.escape) {\n if (onCancel) {\n onCancel();\n }\n return;\n }\n\n if (key.return) {\n if (focusedIndex === scratchIndex) {\n selectStack(null);\n setApproach(\"scratch\");\n\n for (const domain of DEFAULT_SCRATCH_DOMAINS) {\n toggleDomain(domain);\n }\n return;\n }\n\n const focusedStack = stacks[focusedIndex];\n if (focusedStack) {\n selectStack(focusedStack.id);\n setStackAction(\"customize\");\n populateFromSkillIds(focusedStack.allSkillIds);\n setApproach(\"stack\");\n }\n return;\n }\n\n if (key.upArrow || input === \"k\") {\n setFocusedIndex((prev) => Math.max(0, prev - 1));\n return;\n }\n if (key.downArrow || input === \"j\") {\n setFocusedIndex((prev) => Math.min(totalItems - 1, prev + 1));\n }\n });\n\n const noShrink = scrollEnabled ? { flexShrink: 0 } : {};\n\n const sectionElements = stacks.map((stack, index) => (\n <Box key={stack.id} ref={(el) => setSectionRef(index, el)} width=\"100%\" {...noShrink}>\n <SelectionCard\n label={stack.name}\n description={stack.description}\n isFocused={index === focusedIndex}\n marginBottom={1}\n />\n </Box>\n ));\n\n const scratchElement = (\n <Box ref={(el) => setSectionRef(scratchIndex, el)} width=\"100%\" {...noShrink}>\n <SelectionCard\n label={SCRATCH_LABEL}\n description={SCRATCH_DESCRIPTION}\n isFocused={focusedIndex === scratchIndex}\n />\n </Box>\n );\n\n return (\n <Box\n flexDirection=\"column\"\n width=\"100%\"\n {...(scrollEnabled\n ? { height: availableHeight, overflow: \"hidden\" as const }\n : { flexGrow: 1 })}\n >\n <Box flexDirection=\"column\" marginTop={scrollTopPx > 0 ? -scrollTopPx : 0} {...noShrink}>\n {sectionElements}\n {scratchElement}\n </Box>\n </Box>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA,SAAS,KAAK,gBAAgB;AAC9B,SAAgB,gBAAgB;AAkF1B,cA2BA,YA3BA;AA3EN,IAAM,wBAAwB;AAC9B,IAAM,gBAAgB;AACtB,IAAM,sBAAsB;AAG5B,IAAM,oBAAoB;AAQnB,IAAM,iBAAgD,CAAC;AAAA,EAC5D,kBAAkB;AAAA,EAClB;AACF,MAAM;AACJ,QAAM,EAAE,aAAa,aAAa,gBAAgB,sBAAsB,aAAa,IACnF,eAAe;AAEjB,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,qBAAqB;AAEtE,QAAM,SAAS,OAAO;AACtB,QAAM,aAAa,OAAO;AAC1B,QAAM,eAAe;AACrB,QAAM,aAAa,aAAa;AAEhC,QAAM,EAAE,eAAe,eAAe,YAAY,IAAI,iBAAiB;AAAA,IACrE,cAAc;AAAA,IACd;AAAA,IACA;AAAA,EACF,CAAC;AAED,WAAS,CAAC,OAAO,QAAQ;AACvB,QAAI,IAAI,QAAQ;AACd,UAAI,UAAU;AACZ,iBAAS;AAAA,MACX;AACA;AAAA,IACF;AAEA,QAAI,IAAI,QAAQ;AACd,UAAI,iBAAiB,cAAc;AACjC,oBAAY,IAAI;AAChB,oBAAY,SAAS;AAErB,mBAAW,UAAU,yBAAyB;AAC5C,uBAAa,MAAM;AAAA,QACrB;AACA;AAAA,MACF;AAEA,YAAM,eAAe,OAAO,YAAY;AACxC,UAAI,cAAc;AAChB,oBAAY,aAAa,EAAE;AAC3B,uBAAe,WAAW;AAC1B,6BAAqB,aAAa,WAAW;AAC7C,oBAAY,OAAO;AAAA,MACrB;AACA;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,UAAU,KAAK;AAChC,sBAAgB,CAAC,SAAS,KAAK,IAAI,GAAG,OAAO,CAAC,CAAC;AAC/C;AAAA,IACF;AACA,QAAI,IAAI,aAAa,UAAU,KAAK;AAClC,sBAAgB,CAAC,SAAS,KAAK,IAAI,aAAa,GAAG,OAAO,CAAC,CAAC;AAAA,IAC9D;AAAA,EACF,CAAC;AAED,QAAM,WAAW,gBAAgB,EAAE,YAAY,EAAE,IAAI,CAAC;AAEtD,QAAM,kBAAkB,OAAO,IAAI,CAAC,OAAO,UACzC,oBAAC,OAAmB,KAAK,CAAC,OAAO,cAAc,OAAO,EAAE,GAAG,OAAM,QAAQ,GAAG,UAC1E;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,MAAM;AAAA,MACb,aAAa,MAAM;AAAA,MACnB,WAAW,UAAU;AAAA,MACrB,cAAc;AAAA;AAAA,EAChB,KANQ,MAAM,EAOhB,CACD;AAED,QAAM,iBACJ,oBAAC,OAAI,KAAK,CAAC,OAAO,cAAc,cAAc,EAAE,GAAG,OAAM,QAAQ,GAAG,UAClE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,MACP,aAAa;AAAA,MACb,WAAW,iBAAiB;AAAA;AAAA,EAC9B,GACF;AAGF,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAc;AAAA,MACd,OAAM;AAAA,MACL,GAAI,gBACD,EAAE,QAAQ,iBAAiB,UAAU,SAAkB,IACvD,EAAE,UAAU,EAAE;AAAA,MAElB,+BAAC,OAAI,eAAc,UAAS,WAAW,cAAc,IAAI,CAAC,cAAc,GAAI,GAAG,UAC5E;AAAA;AAAA,QACA;AAAA,SACH;AAAA;AAAA,EACF;AAEJ;","names":[]}
|
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
import {
|
|
3
3
|
useModalState
|
|
4
4
|
} from "./chunk-7SOPVGDV.js";
|
|
5
|
-
import {
|
|
6
|
-
useKeyboardNavigation
|
|
7
|
-
} from "./chunk-KUV24B5M.js";
|
|
8
5
|
import {
|
|
9
6
|
useRowScroll
|
|
10
7
|
} from "./chunk-XMLCXRTS.js";
|
|
11
8
|
import {
|
|
12
9
|
ViewTitle
|
|
13
10
|
} from "./chunk-AQYAVLZK.js";
|
|
11
|
+
import {
|
|
12
|
+
useKeyboardNavigation
|
|
13
|
+
} from "./chunk-KUV24B5M.js";
|
|
14
14
|
import {
|
|
15
15
|
useTextInput
|
|
16
16
|
} from "./chunk-U3IGFMCY.js";
|
|
@@ -27,11 +27,11 @@ import {
|
|
|
27
27
|
addSource,
|
|
28
28
|
getSourceSummary,
|
|
29
29
|
removeSource
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-ZLMKEYDF.js";
|
|
31
31
|
import {
|
|
32
32
|
getErrorMessage,
|
|
33
33
|
verbose
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-4CRWKTNQ.js";
|
|
35
35
|
import {
|
|
36
36
|
CLI_COLORS
|
|
37
37
|
} from "./chunk-EGMQ3SXN.js";
|
|
@@ -270,4 +270,4 @@ var StepSettings = ({
|
|
|
270
270
|
export {
|
|
271
271
|
StepSettings
|
|
272
272
|
};
|
|
273
|
-
//# sourceMappingURL=chunk-
|
|
273
|
+
//# sourceMappingURL=chunk-WQRFVEAA.js.map
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-K77I4XGL.js";
|
|
5
5
|
import {
|
|
6
6
|
getDomainDisplayName
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-BH4LN7XV.js";
|
|
8
8
|
import {
|
|
9
9
|
useRowScroll
|
|
10
10
|
} from "./chunk-XMLCXRTS.js";
|
|
@@ -13,13 +13,14 @@ import {
|
|
|
13
13
|
} from "./chunk-AQYAVLZK.js";
|
|
14
14
|
import {
|
|
15
15
|
useWizardStore
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-B7KVPY3Z.js";
|
|
17
17
|
import {
|
|
18
|
+
isAgentName,
|
|
18
19
|
typedKeys
|
|
19
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-EMX7PA2I.js";
|
|
20
21
|
import {
|
|
21
|
-
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
matrix
|
|
23
|
+
} from "./chunk-E74Q7GUE.js";
|
|
23
24
|
import {
|
|
24
25
|
CLI_COLORS,
|
|
25
26
|
UI_SYMBOLS
|
|
@@ -110,9 +111,9 @@ var BUILT_IN_AGENT_IDS = new Set(
|
|
|
110
111
|
function agentIdToLabel(id) {
|
|
111
112
|
return id.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
112
113
|
}
|
|
113
|
-
function buildAgentGroups(
|
|
114
|
+
function buildAgentGroups(matrix2) {
|
|
114
115
|
const customAgentIds = [];
|
|
115
|
-
for (const stack of
|
|
116
|
+
for (const stack of matrix2.suggestedStacks) {
|
|
116
117
|
for (const agentName of typedKeys(stack.skills)) {
|
|
117
118
|
if (!BUILT_IN_AGENT_IDS.has(agentName) && !customAgentIds.includes(agentName)) {
|
|
118
119
|
customAgentIds.push(agentName);
|
|
@@ -122,7 +123,7 @@ function buildAgentGroups(matrix) {
|
|
|
122
123
|
if (customAgentIds.length === 0) return BUILT_IN_AGENT_GROUPS;
|
|
123
124
|
const customGroupMap = /* @__PURE__ */ new Map();
|
|
124
125
|
for (const agentId of customAgentIds) {
|
|
125
|
-
const explicitDomain =
|
|
126
|
+
const explicitDomain = isAgentName(agentId) ? matrix2.agentDefinedDomains?.[agentId] : void 0;
|
|
126
127
|
const domainKey = explicitDomain ?? (agentId.split("-")[0] || "custom");
|
|
127
128
|
const groupLabel = getDomainDisplayName(domainKey);
|
|
128
129
|
if (!customGroupMap.has(groupLabel)) {
|
|
@@ -153,8 +154,7 @@ function buildFocusableIds(groups) {
|
|
|
153
154
|
var StepAgents = () => {
|
|
154
155
|
const selectedAgents = useWizardStore((s) => s.selectedAgents);
|
|
155
156
|
const agentConfigs = useWizardStore((s) => s.agentConfigs);
|
|
156
|
-
const
|
|
157
|
-
const agentGroups = useMemo(() => buildAgentGroups(matrix), [matrix]);
|
|
157
|
+
const agentGroups = useMemo(() => buildAgentGroups(matrix), []);
|
|
158
158
|
const flatRows = useMemo(() => buildFlatRows(agentGroups), [agentGroups]);
|
|
159
159
|
const focusableIds = useMemo(() => buildFocusableIds(agentGroups), [agentGroups]);
|
|
160
160
|
const [focusedId, setFocusedId] = useState(focusableIds[0]);
|
|
@@ -268,4 +268,4 @@ var StepAgents = () => {
|
|
|
268
268
|
export {
|
|
269
269
|
StepAgents
|
|
270
270
|
};
|
|
271
|
-
//# sourceMappingURL=chunk-
|
|
271
|
+
//# sourceMappingURL=chunk-XP7BXHFG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/components/wizard/step-agents.tsx"],"sourcesContent":["import { Box, Text, useInput } from \"ink\";\nimport React, { useMemo, useState } from \"react\";\nimport { CLI_COLORS, UI_SYMBOLS } from \"../../consts.js\";\nimport { useRowScroll } from \"../hooks/use-row-scroll.js\";\nimport { useWizardStore } from \"../../stores/wizard-store.js\";\nimport { matrix } from \"../../lib/matrix/matrix-provider.js\";\nimport type { AgentName, MergedSkillsMatrix } from \"../../types/index.js\";\nimport { typedKeys } from \"../../utils/typed-object.js\";\nimport { isAgentName } from \"../../utils/type-guards.js\";\nimport { useMeasuredHeight } from \"../hooks/use-measured-height.js\";\nimport { getDomainDisplayName } from \"./utils.js\";\nimport { ViewTitle } from \"./view-title.js\";\n\ntype AgentItem = {\n id: AgentName;\n label: string;\n description: string;\n};\n\ntype AgentGroup = {\n label: string;\n items: AgentItem[];\n};\n\nconst BUILT_IN_AGENT_GROUPS: AgentGroup[] = [\n {\n label: \"Web\",\n items: [\n {\n id: \"web-developer\",\n label: \"Web Developer\",\n description: \"Frontend features, components, TypeScript\",\n },\n { id: \"web-reviewer\", label: \"Web Reviewer\", description: \"UI component code review\" },\n { id: \"web-researcher\", label: \"Web Researcher\", description: \"Frontend pattern discovery\" },\n {\n id: \"web-tester\",\n label: \"Web Tester\",\n description: \"Frontend tests, E2E, component tests\",\n },\n { id: \"web-pm\", label: \"Web PM\", description: \"Implementation specs and planning\" },\n {\n id: \"web-architecture\",\n label: \"Web Architecture\",\n description: \"App scaffolding, foundational patterns\",\n },\n {\n id: \"web-pattern-critique\",\n label: \"Web Pattern Critique\",\n description: \"Critique patterns against industry standards\",\n },\n ],\n },\n {\n label: \"API\",\n items: [\n {\n id: \"api-developer\",\n label: \"API Developer\",\n description: \"Backend routes, database, middleware\",\n },\n { id: \"api-reviewer\", label: \"API Reviewer\", description: \"Backend and config code review\" },\n { id: \"api-researcher\", label: \"API Researcher\", description: \"Backend pattern discovery\" },\n ],\n },\n {\n label: \"CLI\",\n items: [\n {\n id: \"cli-developer\",\n label: \"CLI Developer\",\n description: \"CLI commands, interactive prompts\",\n },\n { id: \"cli-tester\", label: \"CLI Tester\", description: \"CLI application tests\" },\n { id: \"cli-reviewer\", label: \"CLI Reviewer\", description: \"CLI code review\" },\n ],\n },\n {\n label: \"Meta\",\n items: [\n {\n id: \"pattern-scout\",\n label: \"Pattern Scout\",\n description: \"Extract codebase patterns and standards\",\n },\n { id: \"agent-summoner\", label: \"Agent Summoner\", description: \"Create and improve agents\" },\n {\n id: \"skill-summoner\",\n label: \"Skill Summoner\",\n description: \"Create technology-specific skills\",\n },\n { id: \"documentor\", label: \"Documentor\", description: \"AI-focused documentation\" },\n ],\n },\n];\n\n/** IDs of all built-in agents for fast lookup. */\nconst BUILT_IN_AGENT_IDS = new Set<string>(\n BUILT_IN_AGENT_GROUPS.flatMap((group) => group.items.map((a) => a.id)),\n);\n\n/** Convert a kebab-case agent ID to a title-case label. */\nfunction agentIdToLabel(id: string): string {\n return id\n .split(\"-\")\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(\" \");\n}\n\ntype FocusId = AgentName | \"continue\";\n\ntype ListRow =\n | { type: \"header\"; label: string }\n | { type: \"spacer\" }\n | { type: \"agent\"; agent: AgentItem };\n\nfunction buildAgentGroups(matrix: MergedSkillsMatrix): AgentGroup[] {\n const customAgentIds: string[] = [];\n for (const stack of matrix.suggestedStacks) {\n for (const agentName of typedKeys(stack.skills)) {\n if (!BUILT_IN_AGENT_IDS.has(agentName) && !customAgentIds.includes(agentName)) {\n customAgentIds.push(agentName);\n }\n }\n }\n\n if (customAgentIds.length === 0) return BUILT_IN_AGENT_GROUPS;\n\n // Group custom agents by explicit domain (from metadata.yaml) or kebab prefix fallback\n const customGroupMap = new Map<string, AgentItem[]>();\n for (const agentId of customAgentIds) {\n const explicitDomain = isAgentName(agentId) ? matrix.agentDefinedDomains?.[agentId] : undefined;\n const domainKey = explicitDomain ?? (agentId.split(\"-\")[0] || \"custom\");\n const groupLabel = getDomainDisplayName(domainKey);\n if (!customGroupMap.has(groupLabel)) {\n customGroupMap.set(groupLabel, []);\n }\n // Boundary cast: custom agent names from marketplace stacks are not in the AgentName union\n customGroupMap.get(groupLabel)!.push({\n id: agentId as AgentName,\n label: agentIdToLabel(agentId),\n description: \"Custom agent\",\n });\n }\n\n const customGroups: AgentGroup[] = [];\n for (const [label, items] of customGroupMap) {\n customGroups.push({ label, items });\n }\n\n return [...BUILT_IN_AGENT_GROUPS, ...customGroups];\n}\n\nfunction buildFlatRows(groups: AgentGroup[]): ListRow[] {\n return groups.flatMap((group, groupIndex): ListRow[] => [\n ...(groupIndex > 0 ? [{ type: \"spacer\" as const }] : []),\n { type: \"header\" as const, label: group.label },\n ...group.items.map((agent): ListRow => ({ type: \"agent\", agent })),\n ]);\n}\n\nfunction buildFocusableIds(groups: AgentGroup[]): FocusId[] {\n return [...groups.flatMap((group) => group.items.map((a) => a.id)), \"continue\"];\n}\n\nexport const StepAgents: React.FC = () => {\n const selectedAgents = useWizardStore((s) => s.selectedAgents);\n const agentConfigs = useWizardStore((s) => s.agentConfigs);\n const agentGroups = useMemo(() => buildAgentGroups(matrix), []);\n const flatRows = useMemo(() => buildFlatRows(agentGroups), [agentGroups]);\n const focusableIds = useMemo(() => buildFocusableIds(agentGroups), [agentGroups]);\n\n const [focusedId, setFocusedId] = useState<FocusId>(focusableIds[0]!);\n const { ref: listRef, measuredHeight: listHeight } = useMeasuredHeight();\n\n const focusedRowIndex =\n focusedId !== \"continue\"\n ? flatRows.findIndex((row) => row.type === \"agent\" && row.agent.id === focusedId)\n : -1;\n const { scrollEnabled, scrollTop } = useRowScroll({\n focusedIndex: Math.max(0, focusedRowIndex),\n itemCount: flatRows.length,\n availableHeight: listHeight,\n });\n\n useInput((input, key) => {\n if (key.escape) {\n useWizardStore.getState().goBack();\n return;\n }\n\n const currentIdx = focusableIds.indexOf(focusedId);\n\n if (key.upArrow || input === \"k\") {\n const nextIdx = currentIdx <= 0 ? focusableIds.length - 1 : currentIdx - 1;\n setFocusedId(focusableIds[nextIdx]!);\n return;\n }\n\n if (key.downArrow || input === \"j\") {\n const nextIdx = currentIdx >= focusableIds.length - 1 ? 0 : currentIdx + 1;\n setFocusedId(focusableIds[nextIdx]!);\n return;\n }\n\n if (key.return) {\n useWizardStore.getState().setStep(\"confirm\");\n return;\n }\n\n if (input === \" \" && focusedId !== \"continue\") {\n useWizardStore.getState().toggleAgent(focusedId);\n }\n });\n\n // Sync focusedAgentId so the wizard-level S key handler can toggle agent scope\n React.useEffect(() => {\n useWizardStore.getState().setFocusedAgentId(focusedId === \"continue\" ? null : focusedId);\n }, [focusedId]);\n\n const selectedCount = selectedAgents.length;\n const continueLabel =\n selectedCount > 0 ? `Continue with ${selectedCount} agent(s)` : \"Continue without agents\";\n\n const isContinueFocused = focusedId === \"continue\";\n\n const rowElements = flatRows.map((row, index) => {\n switch (row.type) {\n case \"header\":\n return (\n <Box key={`header-${row.label}`} flexShrink={0}>\n <Text dimColor bold>\n {\" \"}\n {row.label}\n </Text>\n </Box>\n );\n case \"spacer\":\n return (\n <Box key={`spacer-${index}`} flexShrink={0}>\n <Text> </Text>\n </Box>\n );\n case \"agent\": {\n const isFocused = row.agent.id === focusedId;\n const isSelected = selectedAgents.includes(row.agent.id);\n const checkbox = isSelected ? \"[\\u2713]\" : \"[ ]\";\n const pointer = isFocused ? UI_SYMBOLS.CURRENT : \" \";\n const agentConfig = agentConfigs.find((ac) => ac.name === row.agent.id);\n const scope = agentConfig?.scope ?? \"global\";\n const scopeBadge = scope === \"global\" ? \" [G]\" : \" [P]\";\n return (\n <Box key={row.agent.id} flexShrink={0}>\n <Text>\n <Text color={isFocused ? CLI_COLORS.PRIMARY : undefined}>{pointer}</Text>\n <Text\n color={isSelected || isFocused ? CLI_COLORS.PRIMARY : undefined}\n bold={isFocused}\n >\n {\" \"}\n {checkbox} {row.agent.label}\n </Text>\n <Text color={scope === \"global\" ? CLI_COLORS.WARNING : CLI_COLORS.INFO}>\n {scopeBadge}\n </Text>\n <Text dimColor> - {row.agent.description}</Text>\n </Text>\n </Box>\n );\n }\n }\n });\n\n return (\n <Box flexDirection=\"column\" width=\"100%\" flexGrow={1} flexBasis={0}>\n <ViewTitle>Select agents to compile:</ViewTitle>\n\n <Box ref={listRef} flexDirection=\"column\" flexGrow={1} flexBasis={0}>\n <Box\n flexDirection=\"column\"\n flexGrow={1}\n {...(scrollEnabled && { overflow: \"hidden\" as const })}\n >\n <Box\n flexDirection=\"column\"\n marginTop={scrollTop > 0 ? -scrollTop : 0}\n {...(scrollEnabled && { flexShrink: 0 })}\n >\n {rowElements}\n </Box>\n </Box>\n </Box>\n\n <Text color={isContinueFocused ? CLI_COLORS.PRIMARY : undefined} bold={isContinueFocused}>\n {isContinueFocused ? UI_SYMBOLS.CURRENT : \" \"} {\"\\u2192\"} {continueLabel}\n </Text>\n </Box>\n );\n};\n"],"mappings":"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","names":["matrix"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
Wizard
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-UFAP6GHD.js";
|
|
5
5
|
import {
|
|
6
6
|
SelectList
|
|
7
7
|
} from "./chunk-WF5PMBIR.js";
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
detectGlobalInstallation,
|
|
23
23
|
detectProjectInstallation,
|
|
24
24
|
ensureBlankGlobalConfig,
|
|
25
|
+
fetchMarketplace,
|
|
25
26
|
getInstallationInfo,
|
|
26
27
|
getMarketplaceLabel,
|
|
27
28
|
hasIndividualPlugins,
|
|
@@ -29,15 +30,14 @@ import {
|
|
|
29
30
|
installPluginConfig,
|
|
30
31
|
loadProjectConfig,
|
|
31
32
|
loadSkillsMatrixFromSource
|
|
32
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-ZLMKEYDF.js";
|
|
33
34
|
import {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
} from "./chunk-BKL3DF2Q.js";
|
|
35
|
+
getSkillById
|
|
36
|
+
} from "./chunk-E74Q7GUE.js";
|
|
37
37
|
import {
|
|
38
38
|
BaseCommand,
|
|
39
39
|
EXIT_CODES
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-IJLAVOKZ.js";
|
|
41
41
|
import {
|
|
42
42
|
disableBuffering,
|
|
43
43
|
drainBuffer,
|
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
settingsFileSchema,
|
|
49
49
|
warn,
|
|
50
50
|
warnUnknownFields
|
|
51
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-4CRWKTNQ.js";
|
|
52
52
|
import {
|
|
53
53
|
ASCII_LOGO,
|
|
54
54
|
CLAUDE_DIR,
|
|
@@ -338,10 +338,14 @@ var Init = class _Init extends BaseCommand {
|
|
|
338
338
|
await waitForPrompt();
|
|
339
339
|
clearTerminalOutput();
|
|
340
340
|
if (globalChoice === "edit-global") {
|
|
341
|
-
const
|
|
342
|
-
if (
|
|
343
|
-
|
|
341
|
+
const editArgs = [];
|
|
342
|
+
if (flags.source) {
|
|
343
|
+
editArgs.push("--source", flags.source);
|
|
344
344
|
}
|
|
345
|
+
if (flags.refresh) {
|
|
346
|
+
editArgs.push("--refresh");
|
|
347
|
+
}
|
|
348
|
+
await this.config.runCommand("edit", editArgs);
|
|
345
349
|
return;
|
|
346
350
|
}
|
|
347
351
|
if (globalChoice === null) {
|
|
@@ -374,7 +378,6 @@ var Init = class _Init extends BaseCommand {
|
|
|
374
378
|
disableBuffering();
|
|
375
379
|
let wizardResult = null;
|
|
376
380
|
const marketplaceLabel = getMarketplaceLabel(sourceResult);
|
|
377
|
-
useMatrixStore.getState().setMatrix(sourceResult.matrix);
|
|
378
381
|
const { waitUntilExit } = render(
|
|
379
382
|
/* @__PURE__ */ jsx2(
|
|
380
383
|
Wizard,
|
|
@@ -412,37 +415,39 @@ var Init = class _Init extends BaseCommand {
|
|
|
412
415
|
`Install mode: ${installMode === "plugin" ? "Plugin (native install)" : "Local (copy to .claude/skills/)"}`
|
|
413
416
|
);
|
|
414
417
|
if (installMode === "plugin") {
|
|
415
|
-
|
|
416
|
-
await this.installIndividualPlugins(result, sourceResult, flags, projectDir);
|
|
417
|
-
} else {
|
|
418
|
-
this.warn("Plugin Mode requires a marketplace for individual skill installation.");
|
|
419
|
-
this.log(`Falling back to Local Mode (copying to .claude/skills/)...`);
|
|
420
|
-
this.log("To use Plugin Mode, either select a stack or configure a marketplace source.\n");
|
|
421
|
-
await this.installLocalMode(result, sourceResult, flags, projectDir);
|
|
422
|
-
}
|
|
418
|
+
await this.installIndividualPlugins(result, sourceResult, flags, projectDir);
|
|
423
419
|
return;
|
|
424
420
|
}
|
|
425
421
|
await this.installLocalMode(result, sourceResult, flags, projectDir);
|
|
426
422
|
}
|
|
427
423
|
async installIndividualPlugins(result, sourceResult, flags, projectDir) {
|
|
428
|
-
if (sourceResult.marketplace) {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
424
|
+
if (!sourceResult.marketplace) {
|
|
425
|
+
try {
|
|
426
|
+
const marketplaceResult = await fetchMarketplace(sourceResult.sourceConfig.source, {});
|
|
427
|
+
sourceResult.marketplace = marketplaceResult.marketplace.name;
|
|
428
|
+
} catch {
|
|
429
|
+
this.warn("Could not resolve marketplace. Falling back to Local Mode...");
|
|
430
|
+
await this.installLocalMode(result, sourceResult, flags, projectDir);
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
const marketplace = sourceResult.marketplace;
|
|
435
|
+
const marketplaceExists = await claudePluginMarketplaceExists(marketplace);
|
|
436
|
+
if (!marketplaceExists) {
|
|
437
|
+
this.log(`Registering marketplace "${marketplace}"...`);
|
|
438
|
+
try {
|
|
439
|
+
const marketplaceSource = sourceResult.sourceConfig.source.replace(/^github:/, "");
|
|
440
|
+
await claudePluginMarketplaceAdd(marketplaceSource);
|
|
441
|
+
this.log(`Registered marketplace: ${marketplace}`);
|
|
442
|
+
} catch (error) {
|
|
443
|
+
this.error(getErrorMessage(error), {
|
|
444
|
+
exit: EXIT_CODES.ERROR
|
|
445
|
+
});
|
|
441
446
|
}
|
|
442
447
|
}
|
|
443
448
|
this.log("Installing skill plugins...");
|
|
444
449
|
for (const skill of result.skills.filter((s) => s.source !== "local")) {
|
|
445
|
-
const pluginRef = `${skill.id}@${
|
|
450
|
+
const pluginRef = `${skill.id}@${marketplace}`;
|
|
446
451
|
const pluginScope = skill.scope === "global" ? "user" : "project";
|
|
447
452
|
try {
|
|
448
453
|
await claudePluginInstall(pluginRef, pluginScope, projectDir);
|
|
@@ -521,7 +526,7 @@ var Init = class _Init extends BaseCommand {
|
|
|
521
526
|
this.log("Skills copied to:");
|
|
522
527
|
this.log(` ${installResult.skillsDir}`);
|
|
523
528
|
for (const copiedSkill of installResult.copiedSkills) {
|
|
524
|
-
const displayName =
|
|
529
|
+
const displayName = getSkillById(copiedSkill.skillId).displayName;
|
|
525
530
|
this.log(` ${displayName}/`);
|
|
526
531
|
}
|
|
527
532
|
this.log("");
|
|
@@ -555,4 +560,4 @@ export {
|
|
|
555
560
|
showDashboard,
|
|
556
561
|
Init
|
|
557
562
|
};
|
|
558
|
-
//# sourceMappingURL=chunk-
|
|
563
|
+
//# sourceMappingURL=chunk-ZCJ4YYWL.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/init.tsx","../src/cli/lib/permission-checker.tsx"],"sourcesContent":["import React from \"react\";\n\nimport { Flags } from \"@oclif/core\";\nimport { render, Box, Text, useApp } from \"ink\";\nimport os from \"os\";\nimport path from \"path\";\n\nimport { BaseCommand } from \"../base-command.js\";\nimport { Wizard, type WizardResultV2 } from \"../components/wizard/wizard.js\";\nimport {\n loadSkillsMatrixFromSource,\n getMarketplaceLabel,\n fetchMarketplace,\n type SourceLoadResult,\n} from \"../lib/loading/index.js\";\nimport {\n installLocal,\n installPluginConfig,\n detectGlobalInstallation,\n detectProjectInstallation,\n deriveInstallMode,\n} from \"../lib/installation/index.js\";\nimport { checkPermissions } from \"../lib/permission-checker.js\";\nimport { getInstallationInfo } from \"../lib/plugins/plugin-info.js\";\nimport { hasIndividualPlugins } from \"../lib/plugins/index.js\";\nimport {\n claudePluginInstall,\n claudePluginMarketplaceExists,\n claudePluginMarketplaceAdd,\n} from \"../utils/exec.js\";\nimport {\n ASCII_LOGO,\n CLAUDE_SRC_DIR,\n CLI_BIN_NAME,\n DEFAULT_BRANDING,\n GLOBAL_INSTALL_ROOT,\n} from \"../consts.js\";\nimport { SelectList, type SelectListItem } from \"../components/common/select-list.js\";\nimport {\n KEY_LABEL_ARROWS_VERT,\n KEY_LABEL_ENTER,\n KEY_LABEL_ESC,\n} from \"../components/wizard/hotkeys.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { getSkillById } from \"../lib/matrix/matrix-provider\";\nimport { loadProjectConfig } from \"../lib/configuration/project-config.js\";\nimport {\n enableBuffering,\n drainBuffer,\n disableBuffering,\n type StartupMessage,\n} from \"../utils/logger.js\";\nimport { SUCCESS_MESSAGES, STATUS_MESSAGES } from \"../utils/messages.js\";\nimport { ensureBlankGlobalConfig } from \"../lib/configuration/config-writer.js\";\n\n/** Clears the visible terminal area so the next render starts clean. */\nfunction clearTerminalOutput(): void {\n process.stdout.write(\"\\x1b[2J\\x1b[H\");\n}\n\nconst DASHBOARD_OPTIONS: SelectListItem<string>[] = [\n { label: \"Edit\", value: \"edit\" },\n { label: \"Compile\", value: \"compile\" },\n { label: \"Doctor\", value: \"doctor\" },\n { label: \"List\", value: \"list\" },\n];\n\ntype DashboardProps = {\n onSelect: (command: string) => void;\n onCancel: () => void;\n};\n\nconst Dashboard: React.FC<DashboardProps> = ({ onSelect, onCancel }) => {\n const { exit } = useApp();\n\n return (\n <Box flexDirection=\"column\">\n <Text bold>{DEFAULT_BRANDING.NAME}</Text>\n <Text> </Text>\n <SelectList\n items={DASHBOARD_OPTIONS}\n onSelect={(command) => {\n onSelect(command);\n exit();\n }}\n onCancel={() => {\n onCancel();\n exit();\n }}\n />\n <Text> </Text>\n <Text dimColor>\n {\" \"}\n {KEY_LABEL_ARROWS_VERT} Navigate {\" \"}\n {KEY_LABEL_ENTER} Confirm {\" \"}\n {KEY_LABEL_ESC} Exit\n </Text>\n </Box>\n );\n};\n\ntype GlobalConfigChoice = \"edit-global\" | \"create-project\";\n\nconst GLOBAL_CONFIG_OPTIONS: SelectListItem<GlobalConfigChoice>[] = [\n { label: \"Edit global installation\", value: \"edit-global\" },\n { label: \"Create new project installation\", value: \"create-project\" },\n];\n\ntype GlobalConfigPromptProps = {\n globalConfigDir: string;\n onSelect: (choice: GlobalConfigChoice) => void;\n onCancel: () => void;\n};\n\nconst GlobalConfigPrompt: React.FC<GlobalConfigPromptProps> = ({\n globalConfigDir,\n onSelect,\n onCancel,\n}) => {\n const { exit } = useApp();\n\n return (\n <Box flexDirection=\"column\">\n <Text>A global installation was found at {globalConfigDir}</Text>\n <Text> </Text>\n <SelectList\n items={GLOBAL_CONFIG_OPTIONS}\n onSelect={(choice) => {\n onSelect(choice);\n exit();\n }}\n onCancel={() => {\n onCancel();\n exit();\n }}\n />\n <Text> </Text>\n <Text dimColor>\n {\" \"}\n {KEY_LABEL_ARROWS_VERT} Navigate {\" \"}\n {KEY_LABEL_ENTER} Confirm {\" \"}\n {KEY_LABEL_ESC} Exit\n </Text>\n </Box>\n );\n};\n\nexport type DashboardData = {\n skillCount: number;\n agentCount: number;\n mode: string;\n source?: string;\n};\n\n/** Gathers dashboard data from the installation and project config. */\nexport async function getDashboardData(projectDir: string): Promise<DashboardData> {\n const [info, loaded] = await Promise.all([getInstallationInfo(), loadProjectConfig(projectDir)]);\n\n // Skill count from config (canonical source of truth for installed skills)\n const skillCount = loaded?.config?.skills?.length ?? 0;\n // Agent count from filesystem (compiled .md files in agents dir)\n const agentCount = info?.agentCount ?? 0;\n const mode =\n info?.mode ?? (loaded?.config?.skills ? deriveInstallMode(loaded.config.skills) : \"local\");\n const source = loaded?.config?.source;\n\n return { skillCount, agentCount, mode, source };\n}\n\n/** Formats the dashboard summary as plain text lines (for non-interactive/test output). */\nexport function formatDashboardText(data: DashboardData): string {\n const modeLabel = data.mode === \"plugin\" ? \"Plugin\" : \"Local\";\n const lines = [\n DEFAULT_BRANDING.NAME,\n \"\",\n ` Skills: ${data.skillCount} installed`,\n ` Agents: ${data.agentCount} compiled`,\n ` Mode: ${modeLabel}`,\n ];\n if (data.source) {\n lines.push(` Source: ${data.source}`);\n }\n lines.push(\"\");\n lines.push(` [Edit] [Compile] [Doctor] [List]`);\n return lines.join(\"\\n\");\n}\n\n/**\n * Shows the project dashboard and returns the selected command (or null if cancelled).\n * In non-interactive environments (no TTY), prints the summary text and returns null.\n */\nexport async function showDashboard(\n projectDir: string,\n log?: (message: string) => void,\n): Promise<string | null> {\n const data = await getDashboardData(projectDir);\n\n // Non-interactive: print text summary and exit (CI, piped, tests)\n if (!process.stdin.isTTY) {\n const output = log ?? console.log;\n output(formatDashboardText(data));\n return null;\n }\n\n let selectedCommand: string | null = null;\n\n const { waitUntilExit } = render(\n <Dashboard\n onSelect={(command) => {\n selectedCommand = command;\n }}\n onCancel={() => {\n selectedCommand = null;\n }}\n />,\n );\n\n await waitUntilExit();\n clearTerminalOutput();\n\n return selectedCommand;\n}\n\nexport default class Init extends BaseCommand {\n static summary = `Initialize ${DEFAULT_BRANDING.NAME} in this project`;\n static description =\n \"Interactive wizard to set up skills and agents. Supports Plugin Mode (native install) and Local Mode (copy to .claude/).\";\n\n static examples = [\n {\n description: \"Start the setup wizard\",\n command: \"<%= config.bin %> <%= command.id %>\",\n },\n {\n description: \"Initialize from a custom marketplace\",\n command: \"<%= config.bin %> <%= command.id %> --source github:org/marketplace\",\n },\n {\n description: \"Force refresh skills from remote\",\n command: \"<%= config.bin %> <%= command.id %> --refresh\",\n },\n ];\n\n static flags = {\n ...BaseCommand.baseFlags,\n refresh: Flags.boolean({\n description: \"Force refresh from remote source\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(Init);\n const projectDir = process.cwd();\n\n // For \"already initialized\" check, only look at the target directory (no global fallback)\n const individualPluginsExist = await hasIndividualPlugins(projectDir);\n const existingInstallation = await detectProjectInstallation(projectDir);\n\n if (individualPluginsExist || existingInstallation) {\n const selectedCommand = await showDashboard(projectDir, (msg) => this.log(msg));\n if (selectedCommand) {\n await this.config.runCommand(selectedCommand);\n }\n return;\n }\n\n // No project config exists: check if a global installation exists\n const globalInstallation = await detectGlobalInstallation();\n if (globalInstallation) {\n const globalConfigDir = path.join(os.homedir(), CLAUDE_SRC_DIR);\n\n // Non-interactive: skip prompt and fall through to wizard\n if (process.stdin.isTTY) {\n let globalChoice: GlobalConfigChoice | null = null;\n\n const { waitUntilExit: waitForPrompt } = render(\n <GlobalConfigPrompt\n globalConfigDir={globalConfigDir}\n onSelect={(choice) => {\n globalChoice = choice;\n }}\n onCancel={() => {\n globalChoice = null;\n }}\n />,\n );\n\n await waitForPrompt();\n clearTerminalOutput();\n\n if (globalChoice === \"edit-global\") {\n const editArgs: string[] = [];\n if (flags.source) {\n editArgs.push(\"--source\", flags.source);\n }\n if (flags.refresh) {\n editArgs.push(\"--refresh\");\n }\n await this.config.runCommand(\"edit\", editArgs);\n return;\n }\n\n // User cancelled (Esc)\n if (globalChoice === null) {\n return;\n }\n\n // \"create-project\" falls through to wizard below\n }\n }\n\n // Auto-create blank global config on first init from a project directory.\n // This ensures the project config can always import from global.\n if (projectDir !== GLOBAL_INSTALL_ROOT) {\n const created = await ensureBlankGlobalConfig();\n if (created) {\n this.log(\"Created blank global config at ~/\" + CLAUDE_SRC_DIR);\n }\n }\n\n enableBuffering();\n\n let sourceResult: SourceLoadResult;\n let startupMessages: StartupMessage[] = [];\n try {\n sourceResult = await loadSkillsMatrixFromSource({\n sourceFlag: flags.source,\n projectDir,\n forceRefresh: flags.refresh,\n });\n } catch (error) {\n disableBuffering();\n this.error(getErrorMessage(error), {\n exit: EXIT_CODES.ERROR,\n });\n }\n\n startupMessages = drainBuffer();\n disableBuffering();\n\n let wizardResult: WizardResultV2 | null = null;\n\n const marketplaceLabel = getMarketplaceLabel(sourceResult);\n const { waitUntilExit } = render(\n <Wizard\n version={this.config.version}\n marketplaceLabel={marketplaceLabel}\n logo={ASCII_LOGO}\n projectDir={projectDir}\n startupMessages={startupMessages}\n onComplete={(result) => {\n wizardResult = result;\n }}\n onCancel={() => {\n this.log(\"Setup cancelled\");\n }}\n />,\n );\n\n await waitUntilExit();\n\n // TypeScript can't track that onComplete callback mutates wizardResult before waitUntilExit resolves\n const result = wizardResult as WizardResultV2 | null;\n\n if (!result || result.cancelled) {\n this.exit(EXIT_CODES.CANCELLED);\n }\n\n if (result.skills.length === 0) {\n this.error(\"No skills selected\", { exit: EXIT_CODES.ERROR });\n }\n\n await this.handleInstallation(result, sourceResult, flags);\n }\n\n private async handleInstallation(\n result: WizardResultV2,\n sourceResult: SourceLoadResult,\n flags: { source?: string; refresh: boolean },\n ): Promise<void> {\n const projectDir = process.cwd();\n const installMode = deriveInstallMode(result.skills);\n\n this.log(\"\\n\");\n this.log(`Selected ${result.skills.length} skills`);\n this.log(\n `Install mode: ${installMode === \"plugin\" ? \"Plugin (native install)\" : \"Local (copy to .claude/skills/)\"}`,\n );\n\n if (installMode === \"plugin\") {\n await this.installIndividualPlugins(result, sourceResult, flags, projectDir);\n return;\n }\n\n await this.installLocalMode(result, sourceResult, flags, projectDir);\n }\n\n private async installIndividualPlugins(\n result: WizardResultV2,\n sourceResult: SourceLoadResult,\n flags: { source?: string },\n projectDir: string,\n ): Promise<void> {\n // Lazily resolve marketplace name if not already set (e.g. BUILT_IN_MATRIX skips fetch)\n if (!sourceResult.marketplace) {\n try {\n const marketplaceResult = await fetchMarketplace(sourceResult.sourceConfig.source, {});\n sourceResult.marketplace = marketplaceResult.marketplace.name;\n } catch {\n this.warn(\"Could not resolve marketplace. Falling back to Local Mode...\");\n await this.installLocalMode(result, sourceResult, flags, projectDir);\n return;\n }\n }\n\n // After lazy resolution, marketplace is guaranteed to be set (or we returned above)\n const marketplace = sourceResult.marketplace;\n\n const marketplaceExists = await claudePluginMarketplaceExists(marketplace);\n\n if (!marketplaceExists) {\n this.log(`Registering marketplace \"${marketplace}\"...`);\n try {\n const marketplaceSource = sourceResult.sourceConfig.source.replace(/^github:/, \"\");\n await claudePluginMarketplaceAdd(marketplaceSource);\n this.log(`Registered marketplace: ${marketplace}`);\n } catch (error) {\n this.error(getErrorMessage(error), {\n exit: EXIT_CODES.ERROR,\n });\n }\n }\n\n this.log(\"Installing skill plugins...\");\n for (const skill of result.skills.filter((s) => s.source !== \"local\")) {\n const pluginRef = `${skill.id}@${marketplace}`;\n const pluginScope = skill.scope === \"global\" ? \"user\" : \"project\";\n try {\n await claudePluginInstall(pluginRef, pluginScope, projectDir);\n this.log(` Installed ${pluginRef}`);\n } catch (error) {\n this.error(`Failed to install plugin ${pluginRef}: ${getErrorMessage(error)}`, {\n exit: EXIT_CODES.ERROR,\n });\n }\n }\n\n const pluginSkillCount = result.skills.filter((s) => s.source !== \"local\").length;\n this.log(`Installed ${pluginSkillCount} skill plugins\\n`);\n\n this.log(\"Generating configuration...\");\n try {\n const configResult = await installPluginConfig({\n wizardResult: result,\n sourceResult,\n projectDir,\n sourceFlag: flags.source,\n });\n\n if (configResult.wasMerged) {\n this.log(`Merged with existing config at ${configResult.mergedConfigPath}`);\n }\n\n this.log(`Configuration saved (${configResult.config.agents.length} agents)\\n`);\n this.log(STATUS_MESSAGES.COMPILING_AGENTS);\n this.log(`Compiled ${configResult.compiledAgents.length} agents to .claude/agents/\\n`);\n\n this.log(`${SUCCESS_MESSAGES.INIT_SUCCESS}\\n`);\n this.log(\"Agents compiled to:\");\n this.log(` ${configResult.agentsDir}`);\n for (const agentName of configResult.compiledAgents) {\n this.log(` ${agentName}.md`);\n }\n this.log(\"\");\n this.log(\"Configuration:\");\n this.log(` ${configResult.configPath}`);\n this.log(\"\");\n this.log(\"To customize agent-skill assignments:\");\n this.log(` 1. Edit .claude-src/config.ts`);\n this.log(` 2. Run '${CLI_BIN_NAME} compile' to regenerate agents`);\n this.log(\"\");\n\n const permissionWarning = await checkPermissions(projectDir);\n if (permissionWarning) {\n const { waitUntilExit } = render(permissionWarning);\n await waitUntilExit();\n }\n } catch (error) {\n this.handleError(error);\n }\n }\n\n private async installLocalMode(\n result: WizardResultV2,\n sourceResult: SourceLoadResult,\n flags: { source?: string },\n projectDir: string,\n ): Promise<void> {\n this.log(\"Copying skills to local directory...\");\n try {\n const installResult = await installLocal({\n wizardResult: result,\n sourceResult,\n projectDir,\n sourceFlag: flags.source,\n });\n\n this.log(`Copied ${installResult.copiedSkills.length} skills to .claude/skills/\\n`);\n this.log(\"Generating configuration...\");\n\n if (installResult.wasMerged) {\n this.log(`Merged with existing config at ${installResult.mergedConfigPath}`);\n }\n\n this.log(`Configuration saved (${installResult.config.agents.length} agents)\\n`);\n this.log(STATUS_MESSAGES.COMPILING_AGENTS);\n this.log(`Compiled ${installResult.compiledAgents.length} agents to .claude/agents/\\n`);\n\n this.log(`${SUCCESS_MESSAGES.INIT_SUCCESS}\\n`);\n this.log(\"Skills copied to:\");\n this.log(` ${installResult.skillsDir}`);\n for (const copiedSkill of installResult.copiedSkills) {\n const displayName = getSkillById(copiedSkill.skillId).displayName;\n this.log(` ${displayName}/`);\n }\n this.log(\"\");\n this.log(\"Agents compiled to:\");\n this.log(` ${installResult.agentsDir}`);\n for (const agentName of installResult.compiledAgents) {\n this.log(` ${agentName}.md`);\n }\n this.log(\"\");\n this.log(\"Configuration:\");\n this.log(` ${installResult.configPath}`);\n this.log(\"\");\n this.log(\"To customize agent-skill assignments:\");\n this.log(` 1. Edit .claude-src/config.ts`);\n this.log(` 2. Run '${CLI_BIN_NAME} compile' to regenerate agents`);\n this.log(\"\");\n\n const permissionWarning = await checkPermissions(projectDir);\n if (permissionWarning) {\n const { waitUntilExit } = render(permissionWarning);\n await waitUntilExit();\n }\n } catch (error) {\n this.handleError(error);\n }\n }\n}\n","import React from \"react\";\n\nimport { Text, Box } from \"ink\";\nimport path from \"path\";\n\nimport { CLAUDE_DIR, CLI_COLORS, MAX_CONFIG_FILE_SIZE } from \"../consts\";\nimport { fileExists, readFileSafe } from \"../utils/fs\";\nimport { warn } from \"../utils/logger\";\nimport { settingsFileSchema, warnUnknownFields } from \"./schemas\";\n\ntype PermissionConfig = {\n allow?: string[];\n deny?: string[];\n};\n\ntype SettingsFile = {\n permissions?: PermissionConfig;\n};\n\nexport async function checkPermissions(projectRoot: string): Promise<React.ReactElement | null> {\n const settingsPath = path.join(projectRoot, CLAUDE_DIR, \"settings.json\");\n const localSettingsPath = path.join(projectRoot, CLAUDE_DIR, \"settings.local.json\");\n\n let permissions: PermissionConfig | undefined;\n\n for (const filePath of [localSettingsPath, settingsPath]) {\n if (await fileExists(filePath)) {\n try {\n const content = await readFileSafe(filePath, MAX_CONFIG_FILE_SIZE);\n const raw = JSON.parse(content);\n if (typeof raw === \"object\" && raw !== null && !Array.isArray(raw)) {\n // Known Claude CLI settings.json fields (permissions is ours; the rest are managed by Claude CLI)\n const EXPECTED_SETTINGS_KEYS = [\n \"permissions\",\n \"enabledPlugins\",\n \"env\",\n \"allowedTools\",\n \"customInstructions\",\n \"defaultModel\",\n ] as const;\n warnUnknownFields(\n raw as Record<string, unknown>,\n EXPECTED_SETTINGS_KEYS,\n `settings file '${filePath}'`,\n );\n }\n const result = settingsFileSchema.safeParse(raw);\n const parsed: SettingsFile = result.success ? (result.data as SettingsFile) : {};\n if (parsed.permissions) {\n permissions = parsed.permissions;\n break;\n }\n } catch {\n warn(`Malformed settings file at '${filePath}' — skipping`);\n }\n }\n }\n\n if (!permissions) {\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor={CLI_COLORS.WARNING} padding={1}>\n <Text bold color={CLI_COLORS.WARNING}>\n Permission Notice\n </Text>\n <Text>No permissions configured in .claude/settings.json</Text>\n <Text>Agents will prompt for approval on each tool use.</Text>\n <Text> </Text>\n <Text>For autonomous operation, add to .claude/settings.json:</Text>\n <Text> </Text>\n <Text color=\"dim\">{\"{\"}</Text>\n <Text color=\"dim\">{' \"permissions\": {'}</Text>\n <Text color=\"dim\">{' \"allow\": ['}</Text>\n <Text color=\"dim\">{' \"Read(*)\",'}</Text>\n <Text color=\"dim\">{' \"Bash(git *)\",'}</Text>\n <Text color=\"dim\">{' \"Bash(bun *)\"'}</Text>\n <Text color=\"dim\">{\" ]\"}</Text>\n <Text color=\"dim\">{\" }\"}</Text>\n <Text color=\"dim\">{\"}\"}</Text>\n </Box>\n );\n }\n\n const hasRestrictiveBash = permissions.deny?.some(\n (rule) => rule === \"Bash(*)\" || rule === \"Bash\",\n );\n const hasNoAllows = !permissions.allow || permissions.allow.length === 0;\n\n if (hasRestrictiveBash || hasNoAllows) {\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor={CLI_COLORS.WARNING} padding={1}>\n <Text bold color={CLI_COLORS.WARNING}>\n Permission Warnings\n </Text>\n {hasRestrictiveBash && (\n <Text>\n ⚠ Bash is denied in permissions. Some agents require Bash for git, testing, and build\n commands.\n </Text>\n )}\n {hasNoAllows && (\n <Text>⚠ No allow rules configured. Agents will prompt for each tool use.</Text>\n )}\n </Box>\n );\n }\n\n return null;\n}\n"],"mappings":"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","names":["Box","Text","path","jsx","jsxs","Box","Text","path","result"]}
|