@agents-inc/cli 0.87.0 → 0.90.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/{chunk-O27WJ5KS.js → chunk-2RFE7LTV.js} +3 -3
  3. package/dist/{chunk-7FFNNDJQ.js → chunk-3T5XT2VU.js} +7 -7
  4. package/dist/{chunk-ANXHMG32.js → chunk-47HMJ4BY.js} +28 -1
  5. package/dist/chunk-47HMJ4BY.js.map +1 -0
  6. package/dist/{chunk-5UJJQFET.js → chunk-4DZNTUK7.js} +23 -10
  7. package/dist/chunk-4DZNTUK7.js.map +1 -0
  8. package/dist/{chunk-HSLVCKVQ.js → chunk-4ITKYWVG.js} +5 -4
  9. package/dist/{chunk-HSLVCKVQ.js.map → chunk-4ITKYWVG.js.map} +1 -1
  10. package/dist/{chunk-Q4DMIPZB.js → chunk-7AUGC7PK.js} +2 -2
  11. package/dist/{chunk-MMTMXLI4.js → chunk-7K7SA4TZ.js} +2 -2
  12. package/dist/{chunk-HZQOFFKA.js → chunk-BO4JY7BT.js} +22 -14
  13. package/dist/chunk-BO4JY7BT.js.map +1 -0
  14. package/dist/{chunk-BEZ6ZPDS.js → chunk-D254XO7K.js} +2 -2
  15. package/dist/{chunk-FBZR46GC.js → chunk-DZ2IQERZ.js} +5 -5
  16. package/dist/{chunk-SGZOFIFF.js → chunk-FGVCQBXH.js} +3 -3
  17. package/dist/{chunk-TMTUTUEV.js → chunk-FVBSRBU3.js} +37 -23
  18. package/dist/chunk-FVBSRBU3.js.map +1 -0
  19. package/dist/{chunk-BEFYAFGV.js → chunk-HCSIS35Y.js} +2 -2
  20. package/dist/{chunk-NPMMU4GY.js → chunk-IR7ADPAZ.js} +56 -1
  21. package/dist/chunk-IR7ADPAZ.js.map +1 -0
  22. package/dist/{chunk-HU6XQVZL.js → chunk-JBS4CCJG.js} +2 -2
  23. package/dist/{chunk-HU6XQVZL.js.map → chunk-JBS4CCJG.js.map} +1 -1
  24. package/dist/{chunk-CKZ65VFJ.js → chunk-JI44SVMW.js} +4 -4
  25. package/dist/chunk-JI44SVMW.js.map +1 -0
  26. package/dist/{chunk-CXWBVBDM.js → chunk-O423DMUE.js} +2 -2
  27. package/dist/{chunk-NUU3U43A.js → chunk-OOHPUT5M.js} +3 -3
  28. package/dist/chunk-OOHPUT5M.js.map +1 -0
  29. package/dist/{chunk-ANZV33N5.js → chunk-OVY7IV3C.js} +2 -2
  30. package/dist/{chunk-C5IYJ42F.js → chunk-OWPIGGPP.js} +5 -5
  31. package/dist/chunk-OWPIGGPP.js.map +1 -0
  32. package/dist/{chunk-HZ2IBXVQ.js → chunk-Q3NIGPRZ.js} +3 -3
  33. package/dist/{chunk-HH3AWXF4.js → chunk-TP6BX5M2.js} +4 -4
  34. package/dist/{chunk-ZOWRO7UQ.js → chunk-TWOHWCKS.js} +3 -3
  35. package/dist/{chunk-I44YG6VI.js → chunk-UCORQ7YO.js} +5 -19
  36. package/dist/chunk-UCORQ7YO.js.map +1 -0
  37. package/dist/{chunk-NL5EB57E.js → chunk-UHARXISZ.js} +4 -4
  38. package/dist/chunk-UHARXISZ.js.map +1 -0
  39. package/dist/{chunk-UNEJKTLP.js → chunk-VJBCOPMG.js} +4 -4
  40. package/dist/{chunk-LZ7XQ3IU.js → chunk-VYLF4IIK.js} +4 -4
  41. package/dist/{chunk-6XWHJHNZ.js → chunk-WEYWZ7UE.js} +4 -1
  42. package/dist/chunk-WEYWZ7UE.js.map +1 -0
  43. package/dist/{chunk-B6MYECV6.js → chunk-XM2Y5AFQ.js} +2 -2
  44. package/dist/{chunk-5M6Q5UQO.js → chunk-Z5FXZFX2.js} +3 -3
  45. package/dist/commands/build/marketplace.js +4 -4
  46. package/dist/commands/build/plugins.js +8 -8
  47. package/dist/commands/build/stack.js +8 -8
  48. package/dist/commands/compile.js +9 -9
  49. package/dist/commands/config/index.js +8 -8
  50. package/dist/commands/config/path.js +7 -7
  51. package/dist/commands/config/show.js +8 -8
  52. package/dist/commands/diff.js +9 -9
  53. package/dist/commands/doctor.js +9 -9
  54. package/dist/commands/edit.js +24 -24
  55. package/dist/commands/eject.js +9 -9
  56. package/dist/commands/import/skill.js +7 -7
  57. package/dist/commands/info.js +9 -9
  58. package/dist/commands/init.js +25 -25
  59. package/dist/commands/list.js +7 -7
  60. package/dist/commands/new/agent.js +8 -8
  61. package/dist/commands/new/marketplace.js +8 -8
  62. package/dist/commands/new/skill.js +7 -7
  63. package/dist/commands/outdated.js +9 -9
  64. package/dist/commands/search.js +9 -9
  65. package/dist/commands/uninstall.js +9 -8
  66. package/dist/commands/uninstall.js.map +1 -1
  67. package/dist/commands/update.js +9 -9
  68. package/dist/commands/validate.js +7 -7
  69. package/dist/components/wizard/category-grid.js +2 -2
  70. package/dist/components/wizard/category-grid.test.js +11 -11
  71. package/dist/components/wizard/domain-selection.js +9 -9
  72. package/dist/components/wizard/help-modal.js +8 -8
  73. package/dist/components/wizard/source-grid.js +2 -2
  74. package/dist/components/wizard/source-grid.test.js +11 -11
  75. package/dist/components/wizard/stack-selection.js +8 -8
  76. package/dist/components/wizard/step-agents.js +9 -9
  77. package/dist/components/wizard/step-agents.test.js +12 -12
  78. package/dist/components/wizard/step-build.js +9 -9
  79. package/dist/components/wizard/step-build.test.js +12 -12
  80. package/dist/components/wizard/step-confirm.js +4 -4
  81. package/dist/components/wizard/step-confirm.test.js +10 -10
  82. package/dist/components/wizard/step-settings.js +7 -7
  83. package/dist/components/wizard/step-settings.test.js +10 -10
  84. package/dist/components/wizard/step-sources.js +9 -9
  85. package/dist/components/wizard/step-sources.test.js +12 -12
  86. package/dist/components/wizard/step-stack.js +9 -9
  87. package/dist/components/wizard/step-stack.test.js +10 -10
  88. package/dist/components/wizard/wizard-layout.js +10 -10
  89. package/dist/components/wizard/wizard.js +21 -21
  90. package/dist/config-exports.js +1 -1
  91. package/dist/hooks/init.js +25 -25
  92. package/dist/{loader-GSEGPK64.js → loader-D5VE56SI.js} +4 -4
  93. package/dist/{source-loader-OGFTIRIX.js → source-loader-INCCYL5P.js} +7 -7
  94. package/dist/source-manager-TEOUO734.js +19 -0
  95. package/dist/stores/wizard-store.js +7 -7
  96. package/dist/stores/wizard-store.test.js +10 -10
  97. package/package.json +1 -1
  98. package/dist/chunk-5UJJQFET.js.map +0 -1
  99. package/dist/chunk-6XWHJHNZ.js.map +0 -1
  100. package/dist/chunk-ANXHMG32.js.map +0 -1
  101. package/dist/chunk-C5IYJ42F.js.map +0 -1
  102. package/dist/chunk-CKZ65VFJ.js.map +0 -1
  103. package/dist/chunk-HZQOFFKA.js.map +0 -1
  104. package/dist/chunk-I44YG6VI.js.map +0 -1
  105. package/dist/chunk-NL5EB57E.js.map +0 -1
  106. package/dist/chunk-NPMMU4GY.js.map +0 -1
  107. package/dist/chunk-NUU3U43A.js.map +0 -1
  108. package/dist/chunk-TMTUTUEV.js.map +0 -1
  109. package/dist/plugins/dummy-skill/.claude-plugin/.content-hash +0 -1
  110. package/dist/plugins/dummy-skill/.claude-plugin/plugin.json +0 -13
  111. package/dist/source-manager-FMMDDVZA.js +0 -19
  112. /package/dist/{chunk-O27WJ5KS.js.map → chunk-2RFE7LTV.js.map} +0 -0
  113. /package/dist/{chunk-7FFNNDJQ.js.map → chunk-3T5XT2VU.js.map} +0 -0
  114. /package/dist/{chunk-Q4DMIPZB.js.map → chunk-7AUGC7PK.js.map} +0 -0
  115. /package/dist/{chunk-MMTMXLI4.js.map → chunk-7K7SA4TZ.js.map} +0 -0
  116. /package/dist/{chunk-BEZ6ZPDS.js.map → chunk-D254XO7K.js.map} +0 -0
  117. /package/dist/{chunk-FBZR46GC.js.map → chunk-DZ2IQERZ.js.map} +0 -0
  118. /package/dist/{chunk-SGZOFIFF.js.map → chunk-FGVCQBXH.js.map} +0 -0
  119. /package/dist/{chunk-BEFYAFGV.js.map → chunk-HCSIS35Y.js.map} +0 -0
  120. /package/dist/{chunk-CXWBVBDM.js.map → chunk-O423DMUE.js.map} +0 -0
  121. /package/dist/{chunk-ANZV33N5.js.map → chunk-OVY7IV3C.js.map} +0 -0
  122. /package/dist/{chunk-HZ2IBXVQ.js.map → chunk-Q3NIGPRZ.js.map} +0 -0
  123. /package/dist/{chunk-HH3AWXF4.js.map → chunk-TP6BX5M2.js.map} +0 -0
  124. /package/dist/{chunk-ZOWRO7UQ.js.map → chunk-TWOHWCKS.js.map} +0 -0
  125. /package/dist/{chunk-UNEJKTLP.js.map → chunk-VJBCOPMG.js.map} +0 -0
  126. /package/dist/{chunk-LZ7XQ3IU.js.map → chunk-VYLF4IIK.js.map} +0 -0
  127. /package/dist/{chunk-B6MYECV6.js.map → chunk-XM2Y5AFQ.js.map} +0 -0
  128. /package/dist/{chunk-5M6Q5UQO.js.map → chunk-Z5FXZFX2.js.map} +0 -0
  129. /package/dist/{loader-GSEGPK64.js.map → loader-D5VE56SI.js.map} +0 -0
  130. /package/dist/{source-loader-OGFTIRIX.js.map → source-loader-INCCYL5P.js.map} +0 -0
  131. /package/dist/{source-manager-FMMDDVZA.js.map → source-manager-TEOUO734.js.map} +0 -0
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  getAgentDefinitions,
7
7
  recompileAgents
8
- } from "./chunk-FBZR46GC.js";
8
+ } from "./chunk-DZ2IQERZ.js";
9
9
  import {
10
10
  buildAgentScopeMap,
11
11
  buildAndMergeConfig,
@@ -28,15 +28,15 @@ import {
28
28
  loadSkillsMatrixFromSource,
29
29
  resolveInstallPaths,
30
30
  writeScopedConfigs
31
- } from "./chunk-TMTUTUEV.js";
31
+ } from "./chunk-FVBSRBU3.js";
32
32
  import {
33
33
  loadAllAgents,
34
34
  parseFrontmatter
35
- } from "./chunk-B6MYECV6.js";
35
+ } from "./chunk-XM2Y5AFQ.js";
36
36
  import {
37
37
  typedEntries,
38
38
  typedKeys
39
- } from "./chunk-ANXHMG32.js";
39
+ } from "./chunk-47HMJ4BY.js";
40
40
  import {
41
41
  directoryExists,
42
42
  disableBuffering,
@@ -50,7 +50,7 @@ import {
50
50
  readFile,
51
51
  verbose,
52
52
  warn
53
- } from "./chunk-NUU3U43A.js";
53
+ } from "./chunk-OOHPUT5M.js";
54
54
  import {
55
55
  GLOBAL_INSTALL_ROOT,
56
56
  LOCAL_SKILLS_PATH,
@@ -63,10 +63,17 @@ import {
63
63
 
64
64
  // src/cli/lib/operations/detect-both-installations.ts
65
65
  init_esm_shims();
66
+ import fs from "fs";
66
67
  import os from "os";
67
68
  async function detectBothInstallations(projectDir) {
68
69
  const global = await detectGlobalInstallation();
69
- const project = projectDir === os.homedir() ? null : await detectProjectInstallation(projectDir);
70
+ let isSameAsHome;
71
+ try {
72
+ isSameAsHome = fs.realpathSync(projectDir) === fs.realpathSync(os.homedir());
73
+ } catch {
74
+ isSameAsHome = projectDir === os.homedir();
75
+ }
76
+ const project = isSameAsHome ? null : await detectProjectInstallation(projectDir);
70
77
  return { global, project, hasBoth: !!global && !!project };
71
78
  }
72
79
 
@@ -278,7 +285,7 @@ async function ensureMarketplace(sourceResult) {
278
285
 
279
286
  // src/cli/lib/operations/write-project-config.ts
280
287
  init_esm_shims();
281
- import fs from "fs";
288
+ import fs2 from "fs";
282
289
  import os4 from "os";
283
290
  import path2 from "path";
284
291
  async function writeProjectConfig(options) {
@@ -295,7 +302,7 @@ async function writeProjectConfig(options) {
295
302
  }
296
303
  const mergeResult = await buildAndMergeConfig(wizardResult, sourceResult, projectDir, sourceFlag);
297
304
  const finalConfig = mergeResult.config;
298
- const isProjectContext = fs.realpathSync(projectDir) !== fs.realpathSync(os4.homedir());
305
+ const isProjectContext = fs2.realpathSync(projectDir) !== fs2.realpathSync(os4.homedir());
299
306
  if (isProjectContext) {
300
307
  await ensureBlankGlobalConfig();
301
308
  }
@@ -353,6 +360,7 @@ async function compileAgents(options) {
353
360
 
354
361
  // src/cli/lib/operations/discover-skills.ts
355
362
  init_esm_shims();
363
+ import fs3 from "fs";
356
364
  import os5 from "os";
357
365
  import path3 from "path";
358
366
  async function loadSkillsFromDir(skillsDir, pathPrefix = "") {
@@ -411,7 +419,12 @@ function mergeSkills(...skillSources) {
411
419
  return merged;
412
420
  }
413
421
  async function discoverInstalledSkills(projectDir) {
414
- const isGlobalProject = projectDir === os5.homedir();
422
+ let isGlobalProject;
423
+ try {
424
+ isGlobalProject = fs3.realpathSync(projectDir) === fs3.realpathSync(os5.homedir());
425
+ } catch {
426
+ isGlobalProject = projectDir === os5.homedir();
427
+ }
415
428
  const globalPluginSkills = isGlobalProject ? {} : await discoverAllPluginSkills(os5.homedir());
416
429
  const globalPluginSkillCount = typedKeys(globalPluginSkills).length;
417
430
  if (globalPluginSkillCount > 0) {
@@ -561,4 +574,4 @@ export {
561
574
  findSkillMatch,
562
575
  resolveSkillInfo
563
576
  };
564
- //# sourceMappingURL=chunk-5UJJQFET.js.map
577
+ //# sourceMappingURL=chunk-4DZNTUK7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/lib/operations/detect-both-installations.ts","../src/cli/lib/operations/load-source.ts","../src/cli/lib/operations/detect-project.ts","../src/cli/lib/operations/load-agent-defs.ts","../src/cli/lib/operations/copy-local-skills.ts","../src/cli/lib/operations/install-plugin-skills.ts","../src/cli/lib/operations/uninstall-plugin-skills.ts","../src/cli/lib/operations/collect-scoped-skill-dirs.ts","../src/cli/lib/operations/compare-skills.ts","../src/cli/lib/operations/ensure-marketplace.ts","../src/cli/lib/operations/write-project-config.ts","../src/cli/lib/operations/compile-agents.ts","../src/cli/lib/operations/discover-skills.ts","../src/cli/lib/operations/find-skill-match.ts","../src/cli/lib/operations/resolve-skill-info.ts","../src/cli/lib/operations/index.ts"],"sourcesContent":["import fs from \"fs\";\nimport os from \"os\";\nimport {\n detectGlobalInstallation,\n detectProjectInstallation,\n type Installation,\n} from \"../installation/index.js\";\n\nexport type BothInstallations = {\n global: Installation | null;\n project: Installation | null;\n hasBoth: boolean;\n};\n\n/**\n * Detects both global and project installations.\n *\n * Skips project detection when projectDir is the home directory\n * to avoid double-compile. Returns a convenience `hasBoth` flag\n * used by callers to set scopeFilter on compile passes.\n */\nexport async function detectBothInstallations(projectDir: string): Promise<BothInstallations> {\n const global = await detectGlobalInstallation();\n\n let isSameAsHome: boolean;\n try {\n isSameAsHome = fs.realpathSync(projectDir) === fs.realpathSync(os.homedir());\n } catch {\n isSameAsHome = projectDir === os.homedir();\n }\n\n const project = isSameAsHome ? null : await detectProjectInstallation(projectDir);\n return { global, project, hasBoth: !!global && !!project };\n}\n","import { loadSkillsMatrixFromSource, type SourceLoadResult } from \"../loading/index.js\";\nimport {\n enableBuffering,\n drainBuffer,\n disableBuffering,\n type StartupMessage,\n} from \"../../utils/logger.js\";\n\nexport type LoadSourceOptions = {\n sourceFlag?: string;\n projectDir: string;\n forceRefresh?: boolean;\n /** When true, enables message buffering and captures startup messages. Default: false. */\n captureStartupMessages?: boolean;\n};\n\nexport type LoadedSource = {\n sourceResult: SourceLoadResult;\n /** Empty array when captureStartupMessages is false. */\n startupMessages: StartupMessage[];\n};\n\n/**\n * Loads the skills matrix from a resolved source.\n *\n * When `captureStartupMessages` is true, wraps the load in buffer mode so\n * warn() calls during loading are captured instead of written to stderr.\n * The caller (init/edit) passes these messages to the Wizard's <Static> block.\n *\n * @throws {Error} If source resolution or fetching fails.\n */\nexport async function loadSource(options: LoadSourceOptions): Promise<LoadedSource> {\n const { sourceFlag, projectDir, forceRefresh, captureStartupMessages } = options;\n\n if (captureStartupMessages) {\n enableBuffering();\n }\n\n let sourceResult: SourceLoadResult;\n try {\n sourceResult = await loadSkillsMatrixFromSource({\n sourceFlag,\n projectDir,\n forceRefresh,\n });\n } catch (error) {\n if (captureStartupMessages) {\n disableBuffering();\n }\n throw error;\n }\n\n let startupMessages: StartupMessage[] = [];\n if (captureStartupMessages) {\n startupMessages = drainBuffer();\n disableBuffering();\n }\n\n return { sourceResult, startupMessages };\n}\n","import { detectInstallation, type Installation } from \"../installation/index.js\";\nimport { loadProjectConfig } from \"../configuration/index.js\";\nimport type { ProjectConfig } from \"../../types/index.js\";\n\nexport type DetectedProject = {\n installation: Installation;\n config: ProjectConfig | null;\n configPath: string | null;\n};\n\n/**\n * Detects an existing CLI installation and loads its project config.\n *\n * Uses detectInstallation() which checks project-level first, then falls back\n * to global. Returns the installation metadata plus the loaded config.\n *\n * Does NOT throw. Returns null if no installation found.\n * Commands decide how to handle null (error out, warn, etc.).\n */\nexport async function detectProject(projectDir?: string): Promise<DetectedProject | null> {\n const resolvedDir = projectDir ?? process.cwd();\n const installation = await detectInstallation(resolvedDir);\n\n if (!installation) {\n return null;\n }\n\n const loaded = await loadProjectConfig(installation.projectDir);\n\n return {\n installation,\n config: loaded?.config ?? null,\n configPath: loaded?.configPath ?? null,\n };\n}\n","import { getAgentDefinitions } from \"../agents/index.js\";\nimport { loadAllAgents } from \"../loading/index.js\";\nimport { PROJECT_ROOT } from \"../../consts.js\";\nimport type { AgentDefinition, AgentName, AgentSourcePaths } from \"../../types/index.js\";\n\nexport type AgentDefs = {\n /** Merged agent definitions (CLI defaults + source overrides). Source takes precedence. */\n agents: Record<AgentName, AgentDefinition>;\n /** The sourcePath used to load agent partials (for compilation). */\n sourcePath: string;\n /** Full agent source paths (agentsDir, templatesDir, sourcePath). */\n agentSourcePaths: AgentSourcePaths;\n};\n\n/**\n * Loads agent definitions from the CLI and optionally from a remote source.\n *\n * Merges CLI built-in agents with source repository agents (source overrides CLI).\n * Returns the merged definitions plus the source path for compilation.\n */\nexport async function loadAgentDefs(\n agentSource?: string,\n options?: { projectDir?: string; forceRefresh?: boolean },\n): Promise<AgentDefs> {\n const agentSourcePaths = await getAgentDefinitions(agentSource, options);\n const cliAgents = await loadAllAgents(PROJECT_ROOT);\n const sourceAgents = await loadAllAgents(agentSourcePaths.sourcePath);\n const agents: Record<AgentName, AgentDefinition> = { ...cliAgents, ...sourceAgents };\n\n return {\n agents,\n sourcePath: agentSourcePaths.sourcePath,\n agentSourcePaths,\n };\n}\n","import { resolveInstallPaths } from \"../installation/index.js\";\nimport { copySkillsToLocalFlattened, type CopiedSkill } from \"../skills/index.js\";\nimport { ensureDir } from \"../../utils/fs.js\";\nimport type { SkillConfig } from \"../../types/config.js\";\nimport type { SourceLoadResult } from \"../loading/source-loader.js\";\n\nexport type SkillCopyResult = {\n projectCopied: CopiedSkill[];\n globalCopied: CopiedSkill[];\n totalCopied: number;\n};\n\n/**\n * Copies local-source skills to their scope-appropriate directories.\n *\n * Splits skills by scope (project vs global), resolves install paths,\n * ensures directories exist, and copies from source.\n */\nexport async function copyLocalSkills(\n skills: SkillConfig[],\n projectDir: string,\n sourceResult: SourceLoadResult,\n): Promise<SkillCopyResult> {\n const projectLocalSkills = skills.filter((s) => s.scope !== \"global\");\n const globalLocalSkills = skills.filter((s) => s.scope === \"global\");\n\n const projectPaths = resolveInstallPaths(projectDir, \"project\");\n const globalPaths = resolveInstallPaths(projectDir, \"global\");\n\n let projectCopied: CopiedSkill[] = [];\n if (projectLocalSkills.length > 0) {\n await ensureDir(projectPaths.skillsDir);\n projectCopied = await copySkillsToLocalFlattened(\n projectLocalSkills.map((s) => s.id),\n projectPaths.skillsDir,\n sourceResult.matrix,\n sourceResult,\n );\n }\n\n let globalCopied: CopiedSkill[] = [];\n if (globalLocalSkills.length > 0) {\n await ensureDir(globalPaths.skillsDir);\n globalCopied = await copySkillsToLocalFlattened(\n globalLocalSkills.map((s) => s.id),\n globalPaths.skillsDir,\n sourceResult.matrix,\n sourceResult,\n );\n }\n\n return {\n projectCopied,\n globalCopied,\n totalCopied: projectCopied.length + globalCopied.length,\n };\n}\n","import { claudePluginInstall } from \"../../utils/exec.js\";\nimport { getErrorMessage } from \"../../utils/errors.js\";\nimport type { SkillId } from \"../../types/index.js\";\nimport type { SkillConfig } from \"../../types/config.js\";\n\nexport type PluginInstallResult = {\n installed: Array<{ id: SkillId; ref: string }>;\n failed: Array<{ id: SkillId; error: string }>;\n};\n\n/**\n * Installs skill plugins via the Claude CLI, routing by scope.\n *\n * For each skill, constructs the plugin ref as `{skillId}@{marketplace}`\n * and invokes `claudePluginInstall` with the correct scope.\n */\nexport async function installPluginSkills(\n skills: SkillConfig[],\n marketplace: string,\n projectDir: string,\n): Promise<PluginInstallResult> {\n const pluginSkills = skills.filter((s) => s.source !== \"local\");\n const installed: PluginInstallResult[\"installed\"] = [];\n const failed: PluginInstallResult[\"failed\"] = [];\n\n for (const skill of pluginSkills) {\n const pluginRef = `${skill.id}@${marketplace}`;\n const pluginScope = skill.scope === \"global\" ? \"user\" : \"project\";\n try {\n await claudePluginInstall(pluginRef, pluginScope, projectDir);\n installed.push({ id: skill.id, ref: pluginRef });\n } catch (error) {\n failed.push({ id: skill.id, error: getErrorMessage(error) });\n }\n }\n\n return { installed, failed };\n}\n","import { claudePluginUninstall } from \"../../utils/exec.js\";\nimport { getErrorMessage } from \"../../utils/errors.js\";\nimport type { SkillId } from \"../../types/index.js\";\nimport type { SkillConfig } from \"../../types/config.js\";\n\nexport type PluginUninstallResult = {\n uninstalled: SkillId[];\n failed: Array<{ id: SkillId; error: string }>;\n};\n\n/**\n * Uninstalls skill plugins via the Claude CLI, using scope from old config.\n */\nexport async function uninstallPluginSkills(\n skillIds: SkillId[],\n oldSkills: SkillConfig[],\n projectDir: string,\n): Promise<PluginUninstallResult> {\n const uninstalled: SkillId[] = [];\n const failed: PluginUninstallResult[\"failed\"] = [];\n\n for (const skillId of skillIds) {\n const oldSkill = oldSkills.find((s) => s.id === skillId);\n const pluginScope = oldSkill?.scope === \"global\" ? \"user\" : \"project\";\n try {\n await claudePluginUninstall(skillId, pluginScope, projectDir);\n uninstalled.push(skillId);\n } catch (error) {\n failed.push({ id: skillId, error: getErrorMessage(error) });\n }\n }\n\n return { uninstalled, failed };\n}\n","import os from \"os\";\nimport path from \"path\";\nimport { fileExists, listDirectories } from \"../../utils/fs.js\";\nimport { LOCAL_SKILLS_PATH } from \"../../consts.js\";\n\nexport type ScopedSkillDir = {\n dirName: string;\n localSkillsPath: string;\n scope: \"project\" | \"global\";\n};\n\nexport type ScopedSkillDirsResult = {\n dirs: ScopedSkillDir[];\n hasProject: boolean;\n hasGlobal: boolean;\n projectLocalPath: string;\n globalLocalPath: string;\n};\n\n/**\n * Collects local skill directories from both project and global scopes.\n * Project-scoped dirs take precedence over global on name conflict.\n *\n * @returns directories with scope annotations, plus path/existence metadata\n */\nexport async function collectScopedSkillDirs(projectDir: string): Promise<ScopedSkillDirsResult> {\n const homeDir = os.homedir();\n const projectLocalPath = path.join(projectDir, LOCAL_SKILLS_PATH);\n const globalLocalPath = path.join(homeDir, LOCAL_SKILLS_PATH);\n const hasProject = await fileExists(projectLocalPath);\n const hasGlobal = projectDir !== homeDir && (await fileExists(globalLocalPath));\n\n const dirs: ScopedSkillDir[] = [];\n\n if (hasProject) {\n for (const dirName of await listDirectories(projectLocalPath)) {\n dirs.push({ dirName, localSkillsPath: projectLocalPath, scope: \"project\" });\n }\n }\n\n if (hasGlobal) {\n const projectDirNames = new Set(dirs.map((d) => d.dirName));\n for (const dirName of await listDirectories(globalLocalPath)) {\n if (!projectDirNames.has(dirName)) {\n dirs.push({ dirName, localSkillsPath: globalLocalPath, scope: \"global\" });\n }\n }\n }\n\n return { dirs, hasProject, hasGlobal, projectLocalPath, globalLocalPath };\n}\n","import os from \"os\";\nimport { compareLocalSkillsWithSource, type SkillComparisonResult } from \"../skills/index.js\";\nimport { typedEntries } from \"../../utils/typed-object.js\";\nimport { collectScopedSkillDirs } from \"./collect-scoped-skill-dirs.js\";\nimport type { MergedSkillsMatrix } from \"../../types/index.js\";\n\nexport type SkillComparisonResults = {\n projectResults: SkillComparisonResult[];\n globalResults: SkillComparisonResult[];\n /** Merged results with project taking precedence over global. */\n merged: SkillComparisonResult[];\n};\n\n/**\n * Builds a map of source skill IDs to their paths, excluding local-only skills.\n * Used by both compareSkillsWithSource and diff command.\n */\nexport function buildSourceSkillsMap(matrix: MergedSkillsMatrix): Record<string, { path: string }> {\n const sourceSkills: Record<string, { path: string }> = {};\n for (const [skillId, skill] of typedEntries(matrix.skills)) {\n if (!skill) continue;\n if (!skill.local) {\n sourceSkills[skillId] = { path: skill.path };\n }\n }\n return sourceSkills;\n}\n\n/**\n * Compares local skills (project + global scope) against their source versions.\n *\n * Builds a source skills map from the matrix (excluding local-only skills),\n * runs compareLocalSkillsWithSource for both project and global scopes,\n * and merges results with project taking precedence.\n */\nexport async function compareSkillsWithSource(\n projectDir: string,\n sourcePath: string,\n matrix: MergedSkillsMatrix,\n): Promise<SkillComparisonResults> {\n const sourceSkills = buildSourceSkillsMap(matrix);\n\n const { hasProject, hasGlobal } = await collectScopedSkillDirs(projectDir);\n const homeDir = os.homedir();\n\n const projectResults = hasProject\n ? await compareLocalSkillsWithSource(projectDir, sourcePath, sourceSkills)\n : [];\n\n const globalResults = hasGlobal\n ? await compareLocalSkillsWithSource(homeDir, sourcePath, sourceSkills)\n : [];\n\n const seenIds = new Set(projectResults.map((r) => r.id));\n const merged = [...projectResults, ...globalResults.filter((r) => !seenIds.has(r.id))];\n\n return { projectResults, globalResults, merged };\n}\n","import {\n claudePluginMarketplaceExists,\n claudePluginMarketplaceAdd,\n claudePluginMarketplaceUpdate,\n} from \"../../utils/exec.js\";\nimport { fetchMarketplace } from \"../loading/index.js\";\nimport { warn } from \"../../utils/logger.js\";\nimport type { SourceLoadResult } from \"../loading/source-loader.js\";\n\nexport type MarketplaceResult = {\n /** The resolved marketplace name, or null if no marketplace is configured. */\n marketplace: string | null;\n /** Whether a new marketplace was registered (vs. updated or already existed). */\n registered: boolean;\n};\n\n/**\n * Ensures the marketplace is registered with the Claude CLI.\n *\n * If the marketplace does not exist, registers it. If it exists, updates it.\n * Handles lazy marketplace name resolution when sourceResult.marketplace is undefined.\n *\n * Operation is intentionally SILENT — commands decide what to log based on the\n * `registered` flag.\n */\nexport async function ensureMarketplace(\n sourceResult: SourceLoadResult,\n): Promise<MarketplaceResult> {\n if (!sourceResult.marketplace) {\n try {\n const marketplaceResult = await fetchMarketplace(sourceResult.sourceConfig.source, {});\n sourceResult.marketplace = marketplaceResult.marketplace.name;\n } catch {\n return { marketplace: null, registered: false };\n }\n }\n\n const marketplace = sourceResult.marketplace;\n const exists = await claudePluginMarketplaceExists(marketplace);\n\n if (!exists) {\n const marketplaceSource = sourceResult.sourceConfig.source.replace(/^github:/, \"\");\n await claudePluginMarketplaceAdd(marketplaceSource);\n return { marketplace, registered: true };\n }\n\n try {\n await claudePluginMarketplaceUpdate(marketplace);\n } catch {\n warn(\"Could not update marketplace — continuing with cached version\");\n }\n\n return { marketplace, registered: false };\n}\n","import fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\nimport {\n buildAndMergeConfig,\n writeScopedConfigs,\n resolveInstallPaths,\n} from \"../installation/index.js\";\nimport { loadAllAgents, type SourceLoadResult } from \"../loading/index.js\";\nimport { ensureBlankGlobalConfig } from \"../configuration/config-writer.js\";\nimport { ensureDir } from \"../../utils/fs.js\";\nimport { PROJECT_ROOT } from \"../../consts.js\";\nimport type { ProjectConfig, AgentDefinition, AgentName } from \"../../types/index.js\";\nimport type { WizardResultV2 } from \"../../components/wizard/wizard.js\";\n\nexport type ConfigWriteOptions = {\n wizardResult: WizardResultV2;\n sourceResult: SourceLoadResult;\n projectDir: string;\n sourceFlag?: string;\n /** Pre-loaded agent definitions. If omitted, loads from CLI + source. */\n agents?: Record<AgentName, AgentDefinition>;\n};\n\nexport type ConfigWriteResult = {\n config: ProjectConfig;\n configPath: string;\n globalConfigPath?: string;\n wasMerged: boolean;\n existingConfigPath?: string;\n filesWritten: number;\n};\n\n/**\n * Builds, merges, and writes project configuration files.\n *\n * Handles the full config pipeline:\n * 1. buildAndMergeConfig() — generates config from wizard result, merges with existing\n * 2. loadAllAgents() — loads agent definitions for config-types generation\n * 3. ensureBlankGlobalConfig() — ensures global config exists (when in project context)\n * 4. writeScopedConfigs() — writes config.ts and config-types.ts split by scope\n */\nexport async function writeProjectConfig(options: ConfigWriteOptions): Promise<ConfigWriteResult> {\n const { wizardResult, sourceResult, projectDir, sourceFlag } = options;\n const projectPaths = resolveInstallPaths(projectDir, \"project\");\n\n await ensureDir(path.dirname(projectPaths.configPath));\n\n let agents: Record<AgentName, AgentDefinition>;\n if (options.agents) {\n agents = options.agents;\n } else {\n const cliAgents = await loadAllAgents(PROJECT_ROOT);\n const sourceAgents = await loadAllAgents(sourceResult.sourcePath);\n agents = { ...cliAgents, ...sourceAgents };\n }\n\n const mergeResult = await buildAndMergeConfig(wizardResult, sourceResult, projectDir, sourceFlag);\n const finalConfig = mergeResult.config;\n\n const isProjectContext = fs.realpathSync(projectDir) !== fs.realpathSync(os.homedir());\n\n if (isProjectContext) {\n await ensureBlankGlobalConfig();\n }\n\n await writeScopedConfigs(\n finalConfig,\n sourceResult.matrix,\n agents,\n projectDir,\n projectPaths.configPath,\n isProjectContext,\n );\n\n return {\n config: finalConfig,\n configPath: projectPaths.configPath,\n wasMerged: mergeResult.merged,\n existingConfigPath: mergeResult.existingConfigPath,\n filesWritten: isProjectContext ? 4 : 2,\n };\n}\n","import { recompileAgents } from \"../agents/index.js\";\nimport { loadProjectConfigFromDir } from \"../configuration/index.js\";\nimport { buildAgentScopeMap } from \"../installation/index.js\";\nimport type { AgentName, SkillDefinitionMap } from \"../../types/index.js\";\nimport type { InstallMode } from \"../installation/index.js\";\n\nexport type CompileAgentsOptions = {\n projectDir: string;\n sourcePath: string;\n pluginDir?: string;\n skills?: SkillDefinitionMap;\n agentScopeMap?: Map<AgentName, \"project\" | \"global\">;\n agents?: AgentName[];\n /** When set, loads config and filters agents to only those matching this scope. */\n scopeFilter?: \"project\" | \"global\";\n outputDir?: string;\n installMode?: InstallMode;\n};\n\nexport type CompilationResult = {\n compiled: AgentName[];\n failed: AgentName[];\n warnings: string[];\n};\n\n/**\n * Compiles agent markdown files from templates + skill content.\n *\n * Thin wrapper around recompileAgents() that standardizes options.\n * The caller invokes this once (edit, update) or twice with scopeFilter (compile).\n */\nexport async function compileAgents(options: CompileAgentsOptions): Promise<CompilationResult> {\n let resolvedAgents = options.agents;\n let resolvedAgentScopeMap = options.agentScopeMap;\n\n if (options.scopeFilter) {\n const loadedConfig = await loadProjectConfigFromDir(options.projectDir);\n\n // Auto-build agentScopeMap from config if not provided\n if (!resolvedAgentScopeMap && loadedConfig?.config) {\n resolvedAgentScopeMap = buildAgentScopeMap(loadedConfig.config);\n }\n\n const filteredAgents = loadedConfig?.config?.agents\n ?.filter((a) => a.scope === options.scopeFilter)\n .map((a) => a.name);\n\n if (resolvedAgents && filteredAgents) {\n const filterSet = new Set(filteredAgents);\n resolvedAgents = resolvedAgents.filter((a) => filterSet.has(a));\n } else if (filteredAgents) {\n resolvedAgents = filteredAgents;\n }\n }\n\n const recompileResult = await recompileAgents({\n pluginDir: options.pluginDir ?? options.projectDir,\n sourcePath: options.sourcePath,\n agents: resolvedAgents,\n skills: options.skills,\n projectDir: options.projectDir,\n outputDir: options.outputDir,\n installMode: options.installMode,\n agentScopeMap: resolvedAgentScopeMap,\n });\n\n return {\n compiled: recompileResult.compiled,\n failed: recompileResult.failed,\n warnings: recompileResult.warnings,\n };\n}\n","import fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\nimport { discoverAllPluginSkills } from \"../plugins/index.js\";\nimport { directoryExists, glob, readFile, fileExists } from \"../../utils/fs.js\";\nimport { parseFrontmatter } from \"../loading/index.js\";\nimport { verbose, warn } from \"../../utils/logger.js\";\nimport { GLOBAL_INSTALL_ROOT, LOCAL_SKILLS_PATH, STANDARD_FILES } from \"../../consts.js\";\nimport { typedEntries, typedKeys } from \"../../utils/typed-object.js\";\nimport type { SkillDefinition, SkillDefinitionMap, SkillId } from \"../../types/index.js\";\n\nexport type DiscoveredSkills = {\n allSkills: SkillDefinitionMap;\n totalSkillCount: number;\n pluginSkillCount: number;\n localSkillCount: number;\n globalPluginSkillCount: number;\n globalLocalSkillCount: number;\n};\n\n/**\n * Loads SKILL.md files from a directory, parsing frontmatter for skill metadata.\n * Returns a map of skillId -> SkillDefinition.\n */\nexport async function loadSkillsFromDir(\n skillsDir: string,\n pathPrefix = \"\",\n): Promise<SkillDefinitionMap> {\n const skills: SkillDefinitionMap = {};\n\n if (!(await directoryExists(skillsDir))) {\n return skills;\n }\n\n const skillFiles = await glob(\"**/SKILL.md\", skillsDir);\n\n for (const skillFile of skillFiles) {\n const skillPath = path.join(skillsDir, skillFile);\n const skillDir = path.dirname(skillPath);\n const relativePath = path.relative(skillsDir, skillDir);\n const skillDirName = path.basename(skillDir);\n\n const metadataPath = path.join(skillDir, STANDARD_FILES.METADATA_YAML);\n if (!(await fileExists(metadataPath))) {\n const displayPath = pathPrefix ? `${pathPrefix}/${relativePath}/` : `${relativePath}/`;\n warn(\n `Skill '${skillDirName}' in '${displayPath}' is missing ${STANDARD_FILES.METADATA_YAML} — skipped. Add ${STANDARD_FILES.METADATA_YAML} to register it with the CLI.`,\n );\n continue;\n }\n\n try {\n const content = await readFile(skillPath);\n const frontmatter = parseFrontmatter(content, skillPath);\n\n if (!frontmatter?.name) {\n warn(`Skipping skill in '${skillDirName}': missing or invalid frontmatter name`);\n continue;\n }\n\n const canonicalId = frontmatter.name;\n\n const skill: SkillDefinition = {\n id: canonicalId,\n path: pathPrefix ? `${pathPrefix}/${relativePath}/` : `${relativePath}/`,\n description: frontmatter?.description || \"\",\n };\n\n skills[canonicalId] = skill;\n verbose(` Loaded skill: ${canonicalId}`);\n } catch (error) {\n verbose(` Failed to load skill: ${skillFile} - ${error}`);\n }\n }\n\n return skills;\n}\n\n/**\n * Discovers local project skills from the .claude/skills/ directory.\n */\nexport async function discoverLocalProjectSkills(projectDir: string): Promise<SkillDefinitionMap> {\n const localSkillsDir = path.join(projectDir, LOCAL_SKILLS_PATH);\n return loadSkillsFromDir(localSkillsDir, LOCAL_SKILLS_PATH);\n}\n\n/** Merges skill maps — later sources take precedence over earlier ones. */\nexport function mergeSkills(...skillSources: SkillDefinitionMap[]): SkillDefinitionMap {\n const merged: SkillDefinitionMap = {};\n\n for (const source of skillSources) {\n for (const [id, skill] of typedEntries<SkillId, SkillDefinition | undefined>(source)) {\n if (skill) {\n merged[id] = skill;\n }\n }\n }\n\n return merged;\n}\n\n/**\n * Discovers all installed skills for a project directory using 4-way merge:\n * 1. Global plugins (from ~/.claude/plugins/)\n * 2. Global local (from ~/.claude/skills/)\n * 3. Project plugins (from <projectDir>/.claude/plugins/)\n * 4. Project local (from <projectDir>/.claude/skills/)\n *\n * Pure function — no user-facing logging. Callers add their own log messages.\n * Uses verbose() for diagnostic output only.\n */\nexport async function discoverInstalledSkills(projectDir: string): Promise<DiscoveredSkills> {\n let isGlobalProject: boolean;\n try {\n isGlobalProject = fs.realpathSync(projectDir) === fs.realpathSync(os.homedir());\n } catch {\n isGlobalProject = projectDir === os.homedir();\n }\n\n // 1. Global plugins\n const globalPluginSkills = isGlobalProject ? {} : await discoverAllPluginSkills(os.homedir());\n const globalPluginSkillCount = typedKeys<SkillId>(globalPluginSkills).length;\n if (globalPluginSkillCount > 0) {\n verbose(` Found ${globalPluginSkillCount} skills from global plugins`);\n }\n\n // 2. Global local skills\n const globalLocalSkillsDir = path.join(GLOBAL_INSTALL_ROOT, LOCAL_SKILLS_PATH);\n const globalLocalSkills = isGlobalProject\n ? {}\n : await loadSkillsFromDir(globalLocalSkillsDir, LOCAL_SKILLS_PATH);\n const globalLocalSkillCount = typedKeys<SkillId>(globalLocalSkills).length;\n if (globalLocalSkillCount > 0) {\n verbose(` Found ${globalLocalSkillCount} global local skills from ~/.claude/skills/`);\n }\n\n // 3. Project plugins\n const pluginSkills = await discoverAllPluginSkills(projectDir);\n const pluginSkillCount = typedKeys<SkillId>(pluginSkills).length;\n verbose(` Found ${pluginSkillCount} skills from installed plugins`);\n\n // 4. Project local skills\n const localSkills = await discoverLocalProjectSkills(projectDir);\n const localSkillCount = typedKeys<SkillId>(localSkills).length;\n verbose(` Found ${localSkillCount} local skills from .claude/skills/`);\n\n // Merge: global first, project second — project wins on conflict\n const allSkills = mergeSkills(globalPluginSkills, globalLocalSkills, pluginSkills, localSkills);\n const totalSkillCount = typedKeys<SkillId>(allSkills).length;\n\n return {\n allSkills,\n totalSkillCount,\n pluginSkillCount: globalPluginSkillCount + pluginSkillCount,\n localSkillCount: globalLocalSkillCount + localSkillCount,\n globalPluginSkillCount,\n globalLocalSkillCount,\n };\n}\n","import type { SkillComparisonResult } from \"../skills/index.js\";\n\nexport type SkillMatchResult = {\n match: SkillComparisonResult | null;\n similar: string[];\n};\n\n/**\n * Finds a skill by exact ID, partial name, or directory name.\n * Falls back to fuzzy matching and returns similar suggestions.\n */\nexport function findSkillMatch(\n skillName: string,\n results: SkillComparisonResult[],\n): SkillMatchResult {\n // Exact match by ID\n const exact = results.find((r) => r.id === skillName);\n if (exact) return { match: exact, similar: [] };\n\n // Partial match (without author suffix)\n const partial = results.find((r) => {\n const nameWithoutAuthor = r.id.replace(/\\s*\\(@\\w+\\)$/, \"\").toLowerCase();\n return nameWithoutAuthor === skillName.toLowerCase();\n });\n if (partial) return { match: partial, similar: [] };\n\n // Match by directory name\n const byDir = results.find((r) => r.dirName.toLowerCase() === skillName.toLowerCase());\n if (byDir) return { match: byDir, similar: [] };\n\n // No match — find similar suggestions\n const lowered = skillName.toLowerCase();\n const similar = results\n .filter((r) => {\n const name = r.id.toLowerCase();\n const dir = r.dirName.toLowerCase();\n return (\n name.includes(lowered) || dir.includes(lowered) || lowered.includes(name.split(\" \")[0])\n );\n })\n .map((r) => r.id)\n .slice(0, 3);\n\n return { match: null, similar };\n}\n","import path from \"path\";\nimport { fileExists, readFile } from \"../../utils/fs.js\";\nimport { discoverLocalSkills } from \"../skills/index.js\";\nimport { STANDARD_FILES } from \"../../consts.js\";\nimport type { ResolvedSkill, SkillId, SkillSlug } from \"../../types/index.js\";\nimport { truncateText } from \"../../utils/string.js\";\n\nconst CONTENT_PREVIEW_LINES = 10;\nconst MAX_LINE_LENGTH = 80;\nconst MAX_SUGGESTIONS = 5;\n\nexport type ResolvedSkillInfo = {\n skill: ResolvedSkill;\n isInstalled: boolean;\n preview: string[];\n};\n\nexport type SkillInfoResult = {\n resolved: ResolvedSkillInfo | null;\n suggestions: string[];\n};\n\nexport type ResolveSkillInfoOptions = {\n /** The skill ID, slug, or search query from user input */\n query: string;\n /** Full skills map from the loaded matrix */\n skills: Partial<Record<SkillId, ResolvedSkill>>;\n /** Slug-to-ID lookup map from the loaded matrix */\n slugToId: Partial<Record<SkillSlug, SkillId>>;\n /** Project directory for local skill discovery */\n projectDir: string;\n /** Resolved source path from loadSource */\n sourcePath: string;\n /** Whether the source is local */\n isLocal: boolean;\n /** Whether to load the content preview */\n includePreview: boolean;\n};\n\n/**\n * Strips YAML frontmatter delimiters and content from markdown.\n */\nfunction stripFrontmatter(content: string): string {\n const lines = content.split(\"\\n\");\n let inFrontmatter = false;\n let frontmatterEndIndex = 0;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n if (line === \"---\") {\n if (!inFrontmatter) {\n inFrontmatter = true;\n } else {\n frontmatterEndIndex = i + 1;\n break;\n }\n }\n }\n\n return lines.slice(frontmatterEndIndex).join(\"\\n\");\n}\n\n/**\n * Extracts the first N non-empty lines from markdown content (after frontmatter).\n */\nfunction getPreviewLines(content: string, maxLines: number): string[] {\n const body = stripFrontmatter(content);\n const lines = body.split(\"\\n\");\n const result: string[] = [];\n\n for (const line of lines) {\n if (result.length >= maxLines) break;\n if (line.trim() || result.length > 0) {\n result.push(truncateText(line, MAX_LINE_LENGTH));\n }\n }\n\n return result;\n}\n\n/**\n * Finds similar skill names for \"did you mean\" suggestions.\n */\nfunction findSuggestions(\n skills: Partial<Record<SkillId, ResolvedSkill>>,\n query: string,\n maxSuggestions: number,\n): string[] {\n const lowerQuery = query.toLowerCase();\n const matches: string[] = [];\n\n for (const skill of Object.values(skills)) {\n if (!skill) continue;\n if (matches.length >= maxSuggestions) break;\n if (\n skill.id.toLowerCase().includes(lowerQuery) ||\n skill.displayName.toLowerCase().includes(lowerQuery) ||\n skill.slug.toLowerCase().includes(lowerQuery)\n ) {\n matches.push(skill.id);\n }\n }\n\n return matches;\n}\n\n/**\n * Resolves complete skill information for display.\n *\n * Looks up the skill by ID or slug, discovers local installation status,\n * and optionally loads a content preview from SKILL.md.\n */\nexport async function resolveSkillInfo(options: ResolveSkillInfoOptions): Promise<SkillInfoResult> {\n const { query, skills, slugToId, projectDir, sourcePath, isLocal, includePreview } = options;\n\n // CLI arg is an untyped string — try as skill ID first, then as slug\n const slugResolvedId = slugToId[query as SkillSlug];\n const skill = skills[query as SkillId] ?? (slugResolvedId ? skills[slugResolvedId] : undefined);\n\n if (!skill) {\n const suggestions = findSuggestions(skills, query, MAX_SUGGESTIONS);\n return { resolved: null, suggestions };\n }\n\n const localSkillsResult = await discoverLocalSkills(projectDir);\n const localSkillIds = localSkillsResult?.skills.map((s) => s.id) || [];\n const isInstalled = localSkillIds.includes(skill.id);\n\n let preview: string[] = [];\n if (includePreview) {\n let skillMdPath: string;\n\n if (skill.local && skill.localPath) {\n skillMdPath = path.join(projectDir, skill.localPath, STANDARD_FILES.SKILL_MD);\n } else {\n const sourceDir = isLocal ? sourcePath : path.dirname(sourcePath);\n skillMdPath = path.join(sourceDir, skill.path, STANDARD_FILES.SKILL_MD);\n }\n\n if (await fileExists(skillMdPath)) {\n const content = await readFile(skillMdPath);\n preview = getPreviewLines(content, CONTENT_PREVIEW_LINES);\n }\n }\n\n return {\n resolved: { skill, isInstalled, preview },\n suggestions: [],\n };\n}\n","// Operations — composable building blocks for CLI commands.\n// Each operation wraps lower-level lib functions into a single typed call.\n\nexport { detectBothInstallations, type BothInstallations } from \"./detect-both-installations.js\";\nexport { loadSource, type LoadSourceOptions, type LoadedSource } from \"./load-source.js\";\nexport { detectProject, type DetectedProject } from \"./detect-project.js\";\nexport { loadAgentDefs, type AgentDefs } from \"./load-agent-defs.js\";\nexport { copyLocalSkills, type SkillCopyResult } from \"./copy-local-skills.js\";\nexport { installPluginSkills, type PluginInstallResult } from \"./install-plugin-skills.js\";\nexport { uninstallPluginSkills, type PluginUninstallResult } from \"./uninstall-plugin-skills.js\";\nexport {\n compareSkillsWithSource,\n buildSourceSkillsMap,\n type SkillComparisonResults,\n} from \"./compare-skills.js\";\nexport { ensureMarketplace, type MarketplaceResult } from \"./ensure-marketplace.js\";\nexport {\n writeProjectConfig,\n type ConfigWriteOptions,\n type ConfigWriteResult,\n} from \"./write-project-config.js\";\nexport {\n compileAgents,\n type CompileAgentsOptions,\n type CompilationResult,\n} from \"./compile-agents.js\";\nexport {\n executeInstallation,\n type ExecuteInstallationOptions,\n type ExecuteInstallationResult,\n} from \"./execute-installation.js\";\nexport {\n recompileProject,\n type RecompileProjectOptions,\n type RecompileProjectResult,\n} from \"./recompile-project.js\";\nexport {\n discoverInstalledSkills,\n loadSkillsFromDir,\n discoverLocalProjectSkills,\n mergeSkills,\n type DiscoveredSkills,\n} from \"./discover-skills.js\";\nexport {\n collectScopedSkillDirs,\n type ScopedSkillDir,\n type ScopedSkillDirsResult,\n} from \"./collect-scoped-skill-dirs.js\";\nexport { findSkillMatch, type SkillMatchResult } from \"./find-skill-match.js\";\nexport {\n resolveSkillInfo,\n type ResolveSkillInfoOptions,\n type ResolvedSkillInfo,\n type SkillInfoResult,\n} from \"./resolve-skill-info.js\";\n"],"mappings":"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","names":["os","os","os","os","fs","os","path","path","fs","os","fs","os","path","path","fs","os","path","path"]}
@@ -4,17 +4,17 @@ import {
4
4
  getAvailableSkills,
5
5
  getUnmetRequiredBy,
6
6
  resolveAlias
7
- } from "./chunk-TMTUTUEV.js";
7
+ } from "./chunk-FVBSRBU3.js";
8
8
  import {
9
9
  getCategoryDomain,
10
10
  getSkillById,
11
11
  matrix,
12
12
  typedEntries,
13
13
  typedKeys
14
- } from "./chunk-ANXHMG32.js";
14
+ } from "./chunk-47HMJ4BY.js";
15
15
  import {
16
16
  warn
17
- } from "./chunk-NUU3U43A.js";
17
+ } from "./chunk-OOHPUT5M.js";
18
18
  import {
19
19
  BUILT_IN_DOMAIN_ORDER,
20
20
  DEFAULT_PUBLIC_SOURCE_NAME
@@ -616,6 +616,7 @@ var useWizardStore = create((set, get) => ({
616
616
  );
617
617
  const options = sortedSources.length > 0 ? sortedSources.map((source) => ({
618
618
  id: source.name,
619
+ displayName: source.displayName,
619
620
  selected: selectedSource === source.name,
620
621
  installed: source.installed
621
622
  })) : [
@@ -643,4 +644,4 @@ export {
643
644
  buildCategoriesForDomain,
644
645
  useWizardStore
645
646
  };
646
- //# sourceMappingURL=chunk-HSLVCKVQ.js.map
647
+ //# sourceMappingURL=chunk-4ITKYWVG.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/stores/wizard-store.ts","../src/cli/lib/wizard/index.ts","../src/cli/lib/wizard/build-step-logic.ts"],"sourcesContent":["import { unique, flatMap } from \"remeda\";\nimport { create } from \"zustand\";\nimport { BUILT_IN_DOMAIN_ORDER, DEFAULT_PUBLIC_SOURCE_NAME } from \"../consts.js\";\nimport type { InstallMode } from \"../lib/installation/index.js\";\nimport { deriveInstallMode as sharedDeriveInstallMode } from \"../lib/installation/installation.js\";\nimport type { AgentScopeConfig, SkillConfig } from \"../types/config.js\";\nimport { resolveAlias } from \"../lib/matrix/index.js\";\nimport { matrix, getSkillById, getCategoryDomain } from \"../lib/matrix/matrix-provider.js\";\nimport { isCompatibleWithSelectedFrameworks } from \"../lib/wizard/index.js\";\nimport type {\n AgentName,\n BoundSkill,\n Domain,\n DomainSelections,\n ResolvedSkill,\n SkillAlias,\n SkillAssignment,\n SkillId,\n SkillSource,\n Category,\n CategoryDomainMap,\n CategorySelections,\n} from \"../types/index.js\";\nimport type { SourceOption } from \"../components/wizard/source-grid.js\";\nimport { warn } from \"../utils/logger.js\";\nimport { typedEntries, typedKeys } from \"../utils/typed-object.js\";\n\nfunction createDefaultSkillConfig(id: SkillId): SkillConfig {\n const skill = matrix.skills[id];\n const primarySource = skill?.availableSources?.find((s) => s.primary)?.name;\n return { id, scope: \"global\", source: primarySource ?? DEFAULT_PUBLIC_SOURCE_NAME };\n}\n\n/** Derive all unique domains from a categories map, preserving built-in order then appending custom. */\nfunction getAllDomainsFromCategories(categories: CategoryDomainMap): Domain[] {\n const allDomains = unique(\n Object.values(categories)\n .map((cat) => cat?.domain)\n .filter((d): d is Domain => d != null),\n );\n return [\n ...BUILT_IN_DOMAIN_ORDER,\n ...allDomains.filter((d) => !BUILT_IN_DOMAIN_ORDER.includes(d)),\n ];\n}\n\n/** Sort domains into canonical order: custom domains first (alphabetically), then built-in domains per BUILT_IN_DOMAIN_ORDER. */\nfunction sortDomainsCanonically(domains: Domain[]): Domain[] {\n const builtInSet = new Set<Domain>(BUILT_IN_DOMAIN_ORDER);\n return [\n ...domains.filter((d) => !builtInSet.has(d)).sort(),\n ...BUILT_IN_DOMAIN_ORDER.filter((d) => domains.includes(d)),\n ];\n}\n\n/** Finds framework-incompatible skill IDs in web domain selections, respecting locked skills. */\nfunction findIncompatibleWebSkills(\n webSelections: CategorySelections,\n lockedSkillIds: SkillId[],\n): Set<SkillId> {\n const frameworkSelections = webSelections[\"web-framework\"] ?? [];\n if (frameworkSelections.length === 0) return new Set();\n\n const selectedFrameworkIds = frameworkSelections.map((alias) => resolveAlias(alias));\n\n return new Set(\n flatMap(typedEntries(webSelections), ([cat, skills]) =>\n cat === \"web-framework\" || !skills\n ? []\n : skills.filter(\n (id) =>\n !lockedSkillIds.includes(id) &&\n !isCompatibleWithSelectedFrameworks(id, selectedFrameworkIds),\n ),\n ),\n );\n}\n\n/** Returns selections with the given skill IDs removed from all categories. */\nfunction removeSkillsFromSelections(\n selections: CategorySelections,\n toRemove: Set<SkillId>,\n): CategorySelections {\n return Object.fromEntries(\n typedEntries(selections).map(([cat, skills]) => [\n cat,\n skills?.filter((id) => !toRemove.has(id)) ?? [],\n ]),\n ) as CategorySelections; // Object.fromEntries widens to Record<string, ...>\n}\n\n/** Built-in agent names grouped by domain prefix. Custom domains return no preselected agents. */\nconst DOMAIN_AGENTS: Partial<Record<string, AgentName[]>> = {\n web: [\n \"web-developer\",\n \"web-reviewer\",\n \"web-researcher\",\n \"web-tester\",\n \"web-pm\",\n \"web-architecture\",\n ],\n api: [\"api-developer\", \"api-reviewer\", \"api-researcher\"],\n cli: [\"cli-developer\", \"cli-tester\", \"cli-reviewer\"],\n};\n\n/**\n * Fixed source sort tiers (lower = higher priority):\n * 1 = local/global (installed on disk -- type \"local\" or installed via plugin)\n * 2 = scoped marketplace (primary source from --source flag)\n * 3 = default public marketplace (Agents Inc)\n * 4 = third-party marketplaces (extra configured sources)\n */\nconst SOURCE_SORT_TIER_LOCAL = 1;\nconst SOURCE_SORT_TIER_SCOPED = 2;\nconst SOURCE_SORT_TIER_PUBLIC = 3;\nconst SOURCE_SORT_TIER_THIRD_PARTY = 4;\n\nfunction getSourceSortTier(source: SkillSource): number {\n if (source.type === \"local\") return SOURCE_SORT_TIER_LOCAL;\n if (source.primary) return SOURCE_SORT_TIER_SCOPED;\n if (source.type === \"public\") return SOURCE_SORT_TIER_PUBLIC;\n return SOURCE_SORT_TIER_THIRD_PARTY;\n}\n\nexport type SkillLookupEntry = Pick<ResolvedSkill, \"category\" | \"displayName\">;\n\nfunction resolveSkillForPopulation(\n skillId: SkillId,\n): { domain: Domain; subcat: Category; techId: SkillId } | null {\n const { skills } = matrix;\n const skill = skills[skillId];\n if (!skill?.category) {\n warn(\n `Installed skill '${skillId}' is missing from the marketplace — it may have been removed or renamed`,\n );\n return null;\n }\n\n const domain = getCategoryDomain(skill.category);\n if (!domain) {\n warn(`Installed skill '${skillId}' has unknown category '${skill.category}' — skipping`);\n return null;\n }\n\n // Boundary cast: domain lookup confirmed category exists in matrix\n const subcat = skill.category as Category;\n return { domain, subcat, techId: skillId };\n}\n\nfunction buildBoundSkillOptions(\n boundSkills: BoundSkill[],\n alias: SkillAlias,\n selectedSource: string,\n): SourceOption[] {\n return boundSkills\n .filter((b) => b.boundTo === alias)\n .map((bound) => ({\n id: bound.sourceName,\n selected: selectedSource === bound.sourceName,\n installed: false,\n }));\n}\n\n/**\n * Wizard step identifiers for the multi-step init/edit flow.\n *\n * Progression: stack -> domains -> build -> sources -> agents -> confirm\n * The \"stack\" step shows all stacks + \"Start from scratch\" in a unified list.\n * The \"domains\" step shows domain selection (web, api, cli, mobile, shared).\n * Navigation is tracked via the `history` stack for goBack() support.\n */\nexport type WizardStep =\n | \"stack\" // Select stack or \"Start from scratch\"\n | \"domains\" // Select domains to configure\n | \"build\" // CategoryGrid for technology selection\n | \"sources\" // Choose skill sources (recommended vs custom)\n | \"agents\" // Select which agents to compile\n | \"confirm\"; // Final confirmation\n\n/**\n * Wizard store state and actions.\n *\n * The store uses a composition pattern: small, focused actions that each mutate\n * one or two state fields. Wizard step components compose these actions to build\n * up the full selection state incrementally (domains -> categories -> skills -> sources).\n *\n * State flow: stack/scratch selection -> domain selection -> per-domain skill\n * selection (build step) -> source customization -> agent selection -> confirmation.\n */\nexport type WizardState = {\n step: WizardStep;\n\n approach: \"stack\" | \"scratch\" | null;\n selectedStackId: string | null;\n stackAction: \"defaults\" | \"customize\" | null;\n\n selectedDomains: Domain[];\n\n currentDomainIndex: number;\n domainSelections: DomainSelections;\n /** Snapshot of stack-provided domain selections for restoration on domain re-toggle */\n _stackDomainSelections: DomainSelections | null;\n\n showLabels: boolean;\n filterIncompatible: boolean;\n\n skillConfigs: SkillConfig[];\n focusedSkillId: SkillId | null;\n\n customizeSources: boolean;\n\n showSettings: boolean;\n showHelp: boolean;\n enabledSources: Record<string, boolean>;\n\n selectedAgents: AgentName[];\n agentConfigs: AgentScopeConfig[];\n focusedAgentId: AgentName | null;\n\n boundSkills: BoundSkill[];\n\n /** Skill IDs that cannot be toggled or removed (D9: existing global items in project context) */\n lockedSkillIds: SkillId[];\n /** Agent names that cannot be toggled or removed (D9: existing global agents in project context) */\n lockedAgentNames: AgentName[];\n\n /** When true, scope toggling is disabled (editing from ~/.claude/ with no project to move items to) */\n isEditingFromGlobalScope: boolean;\n\n history: WizardStep[];\n\n /**\n * Navigate to a wizard step, pushing the current step onto history.\n * @param step - Target step to navigate to\n *\n * Side effects: sets `step`, appends previous step to `history`\n */\n setStep: (step: WizardStep) => void;\n /**\n * Set the wizard approach (stack-based or build-from-scratch).\n * @param approach - \"stack\" to use a pre-built template, \"scratch\" to select skills manually, null to reset\n *\n * Side effects: sets `approach`\n */\n setApproach: (approach: \"stack\" | \"scratch\" | null) => void;\n /**\n * Select a stack by ID, or null to deselect.\n * @param stackId - Stack identifier from suggestedStacks, or null to clear\n *\n * Side effects: sets `selectedStackId`\n */\n selectStack: (stackId: string | null) => void;\n /**\n * Set how to apply the selected stack.\n * @param action - \"defaults\" to use stack as-is, \"customize\" to enter the build step\n *\n * Side effects: sets `stackAction`\n */\n setStackAction: (action: \"defaults\" | \"customize\") => void;\n /**\n * Pre-populate domainSelections from a stack's agent-to-skill mappings.\n *\n * Iterates all agents in the stack, resolving each category's skill assignments\n * to the appropriate domain. Enables all domains and deduplicates skill IDs.\n *\n * @param stack - Stack definition with agent-level skill assignments\n * @param stack.agents - Record of agent name to `{ category: SkillAssignment[] }` mappings\n * @param categories - Category definitions used to resolve category -> domain mapping\n *\n * Side effects: sets `domainSelections`, sets `selectedDomains` to ALL_DOMAINS\n */\n populateFromStack: (stack: {\n agents: Record<string, Partial<Record<Category, SkillAssignment[]>>>;\n }) => void;\n /**\n * Pre-populate domainSelections from a flat list of installed skill IDs.\n *\n * Used by `agentsinc edit` to restore wizard state from existing project config.\n * Looks up each skill's category and domain, warns for unresolvable skills.\n *\n * @param skillIds - Flat array of currently installed skill IDs\n * @param skills - Skill lookup providing category and displayName per skill ID\n * @param categories - Category definitions used to resolve category -> domain mapping\n *\n * Side effects: sets `domainSelections`, sets `selectedDomains` to domains found in the provided skill IDs\n */\n populateFromSkillIds: (skillIds: SkillId[], savedConfigs?: SkillConfig[]) => void;\n /**\n * Toggle a domain on or off in the selectedDomains list.\n * @param domain - Domain to toggle\n *\n * Side effects: adds or removes from `selectedDomains`\n */\n toggleDomain: (domain: Domain) => void;\n /**\n * Toggle a skill selection within a domain's category.\n *\n * When exclusive is true (radio behavior), selecting a new skill replaces any\n * existing selection in that category. When false (checkbox behavior),\n * the skill is added to or removed from the selection array.\n *\n * @param domain - Domain containing the category\n * @param category - Category within the domain\n * @param technology - Skill ID to toggle\n * @param exclusive - If true, only one skill can be selected per category (radio)\n *\n * Side effects: updates `domainSelections[domain][category]`\n */\n toggleTechnology: (\n domain: Domain,\n category: Category,\n technology: SkillId,\n exclusive: boolean,\n ) => void;\n /**\n * Advance to the next domain in the build step.\n * @returns true if advanced, false if already at the last domain\n *\n * Side effects: increments `currentDomainIndex`\n */\n nextDomain: () => boolean;\n /**\n * Go back to the previous domain in the build step.\n * @returns true if moved back, false if already at the first domain\n *\n * Side effects: decrements `currentDomainIndex`\n */\n prevDomain: () => boolean;\n /**\n * Set the current domain index directly.\n * @param index - Index to set (0-based, must be within selectedDomains range)\n *\n * Side effects: sets `currentDomainIndex` if index is valid, otherwise no-op\n */\n setCurrentDomainIndex: (index: number) => void;\n /** Toggle compatibility label visibility on skill tags in the build step grid. */\n toggleShowLabels: () => void;\n /** Toggle filtering of incompatible skills in the build step grid. */\n toggleFilterIncompatible: () => void;\n /**\n * Derive the install mode from skillConfigs source values.\n * If all skills use \"local\" source, returns \"local\". If all use non-local, returns \"plugin\".\n * If mixed, returns \"mixed\". Returns \"local\" when no skills are configured.\n */\n deriveInstallMode: () => InstallMode;\n /**\n * Toggle the scope of a specific skill between \"project\" and \"global\".\n * @param skillId - Skill to toggle scope for\n *\n * Side effects: updates `skillConfigs` entry for the skill\n */\n toggleSkillScope: (skillId: SkillId) => void;\n /**\n * Update the source for a specific skill in skillConfigs.\n * @param skillId - Skill to update\n * @param source - Source identifier (e.g., \"local\", marketplace name)\n *\n * Side effects: updates `skillConfigs` entry for the skill\n */\n setSkillSource: (skillId: SkillId, source: string) => void;\n /**\n * Set the currently focused skill ID in the build step (for S hotkey).\n * @param id - Skill ID to focus, or null to clear\n *\n * Side effects: sets `focusedSkillId`\n */\n setFocusedSkillId: (id: SkillId | null) => void;\n /**\n * Set which source provides a specific skill.\n * @param skillId - Skill to configure the source for\n * @param sourceId - Source identifier (e.g., \"public\", \"local\", marketplace name)\n *\n * Side effects: updates `skillConfigs` entry for the skill. No-op with warning if either param is empty.\n */\n setSourceSelection: (skillId: SkillId, sourceId: string) => void;\n /**\n * Enable or disable source customization on the sources step.\n * @param customize - true to show per-skill source pickers\n *\n * Side effects: sets `customizeSources`\n */\n setCustomizeSources: (customize: boolean) => void;\n /** Toggle the settings overlay (source management). */\n toggleSettings: () => void;\n /** Toggle the help overlay (hotkey reference). */\n toggleHelp: () => void;\n /**\n * Replace the full set of enabled/disabled sources.\n * @param sources - Record of source name to enabled boolean. Empty-string keys are filtered out.\n *\n * Side effects: sets `enabledSources`\n */\n setEnabledSources: (sources: Record<string, boolean>) => void;\n /**\n * Add a bound skill from search to the wizard's bound skills list.\n * Duplicates (same id + sourceUrl) are silently skipped with a warning.\n *\n * @param skill - Bound skill to add (foreign skill tied to a category alias)\n *\n * Side effects: appends to `boundSkills`\n */\n bindSkill: (skill: BoundSkill) => void;\n /**\n * Navigate to the previous wizard step using the history stack.\n * Falls back to \"stack\" if history is empty.\n *\n * Side effects: pops from `history`, sets `step` to the popped value\n */\n goBack: () => void;\n /**\n * Toggle an agent on or off in the selectedAgents list.\n * @param agent - Agent name to toggle\n *\n * Side effects: adds or removes from `selectedAgents`, syncs `agentConfigs`\n */\n toggleAgent: (agent: AgentName) => void;\n /**\n * Toggle the scope of a specific agent between \"project\" and \"global\".\n * @param agentName - Agent to toggle scope for\n *\n * Side effects: updates `agentConfigs` entry for the agent\n */\n toggleAgentScope: (agentName: AgentName) => void;\n /**\n * Set the currently focused agent ID in the agents step (for S hotkey).\n * @param id - Agent name to focus, or null to clear\n *\n * Side effects: sets `focusedAgentId`\n */\n setFocusedAgentId: (id: AgentName | null) => void;\n /**\n * Preselect agents based on selected domains from the first wizard step.\n * Matches domains against DOMAIN_AGENTS mapping.\n * Optional agents (meta/pattern) are excluded.\n *\n * Side effects: replaces `selectedAgents` with computed preselection\n */\n preselectAgentsFromDomains: () => void;\n /** Reset all wizard state to initial values. */\n reset: () => void;\n\n /**\n * Collect all selected skill IDs across all domains and categories.\n * @returns Flat array of every selected SkillId (may contain duplicates if shared across domains)\n */\n getAllSelectedTechnologies: () => SkillId[];\n /**\n * Group selected skill IDs by domain.\n * @returns Partial record mapping each domain with selections to its skill ID array\n */\n getSelectedTechnologiesPerDomain: () => Partial<Record<Domain, SkillId[]>>;\n /**\n * Get the domain currently visible in the build step.\n * @returns The domain at currentDomainIndex, or null if no domains are selected\n */\n getCurrentDomain: () => Domain | null;\n /**\n * Count total selected technologies across all domains.\n * @returns Number of selected skill IDs\n */\n getTechnologyCount: () => number;\n /**\n * Compute which wizard steps are completed and which are skipped.\n * Used by WizardTabs to render step progress indicators.\n * @returns Object with completedSteps and skippedSteps string arrays\n */\n getStepProgress: () => { completedSteps: WizardStep[]; skippedSteps: WizardStep[] };\n /** @returns true if there is a next domain after the current one */\n canGoToNextDomain: () => boolean;\n /** @returns true if there is a previous domain before the current one */\n canGoToPreviousDomain: () => boolean;\n /** Set all selected skills to \"local\" source. */\n setAllSourcesLocal: () => void;\n /** Set all selected skills to their first non-local (marketplace) source. */\n setAllSourcesPlugin: () => void;\n\n /**\n * Build the source selection rows for the sources step UI.\n *\n * For each selected technology, resolves the canonical skill ID, looks up available\n * sources from the matrix, merges in any bound skills from search, and determines\n * which source is currently selected. Sources are sorted: local first, then public,\n * then private/other.\n *\n * @returns Array of row objects, one per selected technology, each containing:\n * - `skillId` - Canonical resolved skill ID\n * - `options` - Available sources with selection state and install status\n */\n buildSourceRows: () => {\n skillId: SkillId;\n options: SourceOption[];\n }[];\n};\n\n/** State-only fields from WizardState (excludes actions/getters). Used to type createInitialState(). */\ntype WizardStateData = Pick<\n WizardState,\n | \"step\"\n | \"approach\"\n | \"selectedStackId\"\n | \"stackAction\"\n | \"selectedDomains\"\n | \"currentDomainIndex\"\n | \"domainSelections\"\n | \"_stackDomainSelections\"\n | \"showLabels\"\n | \"filterIncompatible\"\n | \"skillConfigs\"\n | \"focusedSkillId\"\n | \"customizeSources\"\n | \"showSettings\"\n | \"showHelp\"\n | \"enabledSources\"\n | \"selectedAgents\"\n | \"agentConfigs\"\n | \"focusedAgentId\"\n | \"boundSkills\"\n | \"lockedSkillIds\"\n | \"lockedAgentNames\"\n | \"isEditingFromGlobalScope\"\n | \"history\"\n>;\n\nconst createInitialState = (): WizardStateData => ({\n step: \"stack\",\n approach: null,\n selectedStackId: null,\n stackAction: null,\n selectedDomains: [],\n currentDomainIndex: 0,\n domainSelections: {},\n /** Snapshot of domainSelections from populateFromStack/populateFromSkillIds, used to restore on domain re-toggle */\n _stackDomainSelections: null,\n showLabels: false,\n filterIncompatible: false,\n skillConfigs: [],\n focusedSkillId: null,\n customizeSources: false,\n showSettings: false,\n showHelp: false,\n enabledSources: {},\n selectedAgents: [],\n agentConfigs: [],\n focusedAgentId: null,\n boundSkills: [],\n lockedSkillIds: [],\n lockedAgentNames: [],\n isEditingFromGlobalScope: false,\n history: [],\n});\n\nexport const useWizardStore = create<WizardState>((set, get) => ({\n ...createInitialState(),\n\n setStep: (step) =>\n set((state) => ({\n step,\n history: [...state.history, state.step],\n })),\n\n setApproach: (approach) => set({ approach }),\n\n selectStack: (stackId) =>\n set({\n selectedStackId: stackId,\n domainSelections: {},\n _stackDomainSelections: null,\n selectedDomains: [],\n skillConfigs: [],\n selectedAgents: [],\n agentConfigs: [],\n boundSkills: [],\n currentDomainIndex: 0,\n stackAction: null,\n }),\n\n setStackAction: (action) => set({ stackAction: action }),\n\n populateFromStack: (stack) =>\n set(() => {\n const { categories } = matrix;\n const domainSelections: DomainSelections = {};\n const domains = new Set<Domain>();\n const allSkillIds = new Set<SkillId>();\n\n for (const agentConfig of Object.values(stack.agents)) {\n for (const [subcat, assignments] of typedEntries<Category, SkillAssignment[]>(\n agentConfig,\n )) {\n const category = categories[subcat];\n const domain = category?.domain;\n\n if (!domain || !assignments) {\n continue;\n }\n\n domains.add(domain);\n\n if (!domainSelections[domain]) {\n domainSelections[domain] = {};\n }\n\n if (!domainSelections[domain][subcat]) {\n domainSelections[domain][subcat] = [];\n }\n\n for (const assignment of assignments) {\n if (!domainSelections[domain][subcat].includes(assignment.id)) {\n domainSelections[domain][subcat].push(assignment.id);\n allSkillIds.add(assignment.id);\n }\n }\n }\n }\n\n const skillConfigs: SkillConfig[] = [...allSkillIds].map(createDefaultSkillConfig);\n\n return {\n domainSelections,\n _stackDomainSelections: structuredClone(domainSelections),\n selectedDomains: sortDomainsCanonically([...domains]),\n skillConfigs,\n };\n }),\n\n populateFromSkillIds: (skillIds, savedConfigs) =>\n set(() => {\n const domainSelections: DomainSelections = {};\n const resolvedSkillIds: SkillId[] = [];\n let skippedCount = 0;\n\n for (const skillId of skillIds) {\n const resolved = resolveSkillForPopulation(skillId);\n if (!resolved) {\n skippedCount++;\n continue;\n }\n\n const { domain, subcat, techId } = resolved;\n if (!domainSelections[domain]) domainSelections[domain] = {};\n if (!domainSelections[domain][subcat]) domainSelections[domain][subcat] = [];\n\n if (!domainSelections[domain][subcat].includes(techId)) {\n domainSelections[domain][subcat].push(techId);\n resolvedSkillIds.push(techId);\n }\n }\n\n if (skippedCount > 0) {\n warn(`${skippedCount} installed skill(s) could not be resolved and were skipped`);\n }\n\n const selectedDomains = sortDomainsCanonically(typedKeys<Domain>(domainSelections));\n\n const skillConfigs: SkillConfig[] = resolvedSkillIds.map((id) => {\n const saved = savedConfigs?.find((sc) => sc.id === id);\n const skill = matrix.skills[id];\n const primarySource = skill?.availableSources?.find((s) => s.primary)?.name;\n return {\n id,\n scope: saved?.scope ?? \"global\",\n source: saved?.source ?? primarySource ?? DEFAULT_PUBLIC_SOURCE_NAME,\n };\n });\n\n return {\n domainSelections,\n _stackDomainSelections: structuredClone(domainSelections),\n selectedDomains,\n skillConfigs,\n };\n }),\n\n toggleDomain: (domain) =>\n set((state) => {\n const isSelected = state.selectedDomains.includes(domain);\n if (isSelected) {\n const { [domain]: _removed, ...remainingSelections } = state.domainSelections;\n\n // Collect all skill IDs being removed from this domain\n const removedSkillIds = new Set<SkillId>();\n if (_removed) {\n for (const skills of Object.values(_removed)) {\n if (skills) {\n for (const id of skills) {\n removedSkillIds.add(id);\n }\n }\n }\n }\n\n return {\n selectedDomains: state.selectedDomains.filter((d) => d !== domain),\n domainSelections: remainingSelections,\n skillConfigs: state.skillConfigs.filter((sc) => !removedSkillIds.has(sc.id)),\n };\n }\n\n // Restore stack selections for this domain if a stack snapshot exists\n const stackSelections = state._stackDomainSelections?.[domain];\n if (stackSelections) {\n // Also restore skillConfigs for the restored skills\n const restoredSkillIds: SkillId[] = [];\n for (const skills of Object.values(stackSelections)) {\n if (skills) restoredSkillIds.push(...skills);\n }\n const existingIds = new Set(state.skillConfigs.map((sc) => sc.id));\n const newConfigs = restoredSkillIds\n .filter((id) => !existingIds.has(id))\n .map(createDefaultSkillConfig);\n\n return {\n selectedDomains: sortDomainsCanonically([...state.selectedDomains, domain]),\n domainSelections: {\n ...state.domainSelections,\n [domain]: structuredClone(stackSelections),\n },\n skillConfigs: [...state.skillConfigs, ...newConfigs],\n };\n }\n\n return {\n selectedDomains: sortDomainsCanonically([...state.selectedDomains, domain]),\n };\n }),\n\n toggleTechnology: (domain, category, technology, exclusive) =>\n set((state) => {\n // D9: locked skills cannot be toggled\n if (state.lockedSkillIds.includes(technology)) return state;\n\n const currentSelections = state.domainSelections[domain]?.[category] || [];\n const isSelected = currentSelections.includes(technology);\n\n let newSelections: SkillId[];\n if (exclusive) {\n newSelections = isSelected ? [] : [technology];\n } else {\n newSelections = isSelected\n ? currentSelections.filter((t) => t !== technology)\n : [...currentSelections, technology];\n }\n\n // Sync skillConfigs: add entries for newly selected, remove entries for deselected\n const removed = currentSelections.filter((id) => !newSelections.includes(id));\n const added = newSelections.filter((id) => !currentSelections.includes(id));\n\n let updatedConfigs = state.skillConfigs.filter((sc) => !removed.includes(sc.id));\n for (const id of added) {\n if (!updatedConfigs.some((sc) => sc.id === id)) {\n updatedConfigs = [...updatedConfigs, createDefaultSkillConfig(id)];\n }\n }\n\n return {\n skillConfigs: updatedConfigs,\n domainSelections: {\n ...state.domainSelections,\n [domain]: {\n ...state.domainSelections[domain],\n [category]: newSelections,\n },\n },\n };\n }),\n\n nextDomain: () => {\n const state = get();\n if (state.currentDomainIndex < state.selectedDomains.length - 1) {\n set({\n currentDomainIndex: state.currentDomainIndex + 1,\n });\n return true;\n }\n return false;\n },\n\n prevDomain: () => {\n const state = get();\n if (state.currentDomainIndex > 0) {\n set({\n currentDomainIndex: state.currentDomainIndex - 1,\n });\n return true;\n }\n return false;\n },\n\n setCurrentDomainIndex: (index) => {\n const state = get();\n if (index >= 0 && index < state.selectedDomains.length) {\n set({ currentDomainIndex: index });\n }\n },\n\n toggleShowLabels: () => set((state) => ({ showLabels: !state.showLabels })),\n toggleFilterIncompatible: () =>\n set((state) => {\n if (state.filterIncompatible) return { filterIncompatible: false };\n\n const webSelections = state.domainSelections.web;\n if (!webSelections) return { filterIncompatible: true };\n\n const removed = findIncompatibleWebSkills(webSelections, state.lockedSkillIds);\n if (removed.size === 0) return { filterIncompatible: true };\n\n return {\n filterIncompatible: true,\n domainSelections: {\n ...state.domainSelections,\n web: removeSkillsFromSelections(webSelections, removed),\n },\n skillConfigs: state.skillConfigs.filter((sc) => !removed.has(sc.id)),\n };\n }),\n\n deriveInstallMode: (): InstallMode => {\n const { skillConfigs } = get();\n return sharedDeriveInstallMode(skillConfigs);\n },\n\n toggleSkillScope: (skillId) =>\n set((state) => {\n if (state.isEditingFromGlobalScope) return state;\n // D9: locked skills cannot have their scope toggled\n if (state.lockedSkillIds.includes(skillId)) return state;\n return {\n skillConfigs: state.skillConfigs.map((sc) =>\n sc.id === skillId ? { ...sc, scope: sc.scope === \"project\" ? \"global\" : \"project\" } : sc,\n ),\n };\n }),\n\n setSkillSource: (skillId, source) =>\n set((state) => ({\n skillConfigs: state.skillConfigs.map((sc) => (sc.id === skillId ? { ...sc, source } : sc)),\n })),\n\n setFocusedSkillId: (id) => set({ focusedSkillId: id }),\n\n setSourceSelection: (skillId, sourceId) =>\n set((state) => {\n if (!skillId) {\n warn(\"Ignoring setSourceSelection call with empty skillId\");\n return state;\n }\n if (!sourceId) {\n warn(`Ignoring setSourceSelection call with empty sourceId for skill '${skillId}'`);\n return state;\n }\n return {\n skillConfigs: state.skillConfigs.map((sc) =>\n sc.id === skillId ? { ...sc, source: sourceId } : sc,\n ),\n };\n }),\n\n setCustomizeSources: (customize) => set({ customizeSources: customize }),\n\n toggleSettings: () => set((state) => ({ showSettings: !state.showSettings })),\n\n toggleHelp: () => set((state) => ({ showHelp: !state.showHelp })),\n\n setEnabledSources: (sources) => {\n const invalidKeys = Object.keys(sources).filter((key) => !key.trim());\n if (invalidKeys.length > 0) {\n warn(\"Ignoring setEnabledSources call with empty source name(s)\");\n }\n const validSources = Object.fromEntries(Object.entries(sources).filter(([key]) => key.trim()));\n return set({ enabledSources: validSources });\n },\n\n bindSkill: (skill) =>\n set((state) => {\n const exists = state.boundSkills.some(\n (b) => b.id === skill.id && b.sourceUrl === skill.sourceUrl,\n );\n if (exists) {\n warn(`Skill '${skill.id}' from '${skill.sourceUrl}' is already bound — skipping duplicate`);\n return state;\n }\n return { boundSkills: [...state.boundSkills, skill] };\n }),\n\n goBack: () =>\n set((state) => {\n const history = [...state.history];\n const previousStep = history.pop();\n return {\n step: previousStep || \"stack\",\n history,\n };\n }),\n\n toggleAgent: (agent) =>\n set((state) => {\n // D9: locked agents cannot be toggled\n if (state.lockedAgentNames.includes(agent)) return state;\n\n const isSelected = state.selectedAgents.includes(agent);\n if (isSelected) {\n return {\n selectedAgents: state.selectedAgents.filter((a) => a !== agent),\n agentConfigs: state.agentConfigs.filter((ac) => ac.name !== agent),\n };\n }\n return {\n selectedAgents: [...state.selectedAgents, agent],\n agentConfigs: [...state.agentConfigs, { name: agent, scope: \"global\" as const }],\n };\n }),\n\n toggleAgentScope: (agentName) =>\n set((state) => {\n if (state.isEditingFromGlobalScope) return state;\n // D9: locked agents cannot have their scope toggled\n if (state.lockedAgentNames.includes(agentName)) return state;\n return {\n agentConfigs: state.agentConfigs.map((ac) =>\n ac.name === agentName\n ? { ...ac, scope: ac.scope === \"project\" ? (\"global\" as const) : (\"project\" as const) }\n : ac,\n ),\n };\n }),\n\n setFocusedAgentId: (id) => set({ focusedAgentId: id }),\n\n preselectAgentsFromDomains: () =>\n set(() => {\n const agents: AgentName[] = [];\n for (const domain of get().selectedDomains) {\n const domainAgents = DOMAIN_AGENTS[domain];\n if (domainAgents) {\n agents.push(...domainAgents);\n }\n }\n const sorted = agents.sort();\n return {\n selectedAgents: sorted,\n agentConfigs: sorted.map((name) => ({ name, scope: \"global\" as const })),\n };\n }),\n\n reset: () => set(createInitialState()),\n\n getAllSelectedTechnologies: () => {\n const state = get();\n const technologies: SkillId[] = [];\n for (const domain of typedKeys<Domain>(state.domainSelections)) {\n const domainSel = state.domainSelections[domain];\n if (!domainSel) continue;\n for (const category of typedKeys<Category>(domainSel)) {\n const techs = domainSel[category];\n if (techs) technologies.push(...techs);\n }\n }\n return technologies;\n },\n\n getSelectedTechnologiesPerDomain: () => {\n const state = get();\n const result: Partial<Record<Domain, SkillId[]>> = {};\n for (const domain of typedKeys<Domain>(state.domainSelections)) {\n const domainSel = state.domainSelections[domain];\n if (!domainSel) continue;\n const techs: SkillId[] = [];\n for (const category of typedKeys<Category>(domainSel)) {\n const subTechs = domainSel[category];\n if (subTechs) techs.push(...subTechs);\n }\n if (techs.length > 0) {\n result[domain] = techs;\n }\n }\n return result;\n },\n\n getCurrentDomain: () => {\n const state = get();\n return state.selectedDomains[state.currentDomainIndex] || null;\n },\n\n getTechnologyCount: () => {\n return get().getAllSelectedTechnologies().length;\n },\n\n getStepProgress: () => {\n const state = get();\n const completed: WizardStep[] = [];\n const skipped: WizardStep[] = [];\n\n if (state.step !== \"stack\" && state.step !== \"domains\") {\n completed.push(\"stack\");\n completed.push(\"domains\");\n } else if (state.step === \"domains\") {\n completed.push(\"stack\");\n }\n\n if (state.approach === \"stack\" && state.selectedStackId && state.stackAction === \"defaults\") {\n skipped.push(\"build\");\n skipped.push(\"sources\");\n skipped.push(\"agents\");\n } else if (state.step === \"confirm\") {\n completed.push(\"build\");\n completed.push(\"sources\");\n completed.push(\"agents\");\n } else if (state.step === \"agents\") {\n completed.push(\"build\");\n completed.push(\"sources\");\n } else if (state.step === \"sources\") {\n completed.push(\"build\");\n }\n\n return { completedSteps: completed, skippedSteps: skipped };\n },\n\n canGoToNextDomain: () => {\n const state = get();\n return state.currentDomainIndex < state.selectedDomains.length - 1;\n },\n\n canGoToPreviousDomain: () => {\n const state = get();\n return state.currentDomainIndex > 0;\n },\n\n setAllSourcesLocal: () => {\n set((state) => ({\n skillConfigs: state.skillConfigs.map((sc) => ({ ...sc, source: \"local\" })),\n }));\n },\n\n setAllSourcesPlugin: () => {\n set((state) => ({\n skillConfigs: state.skillConfigs.map((sc) => {\n const skill = getSkillById(sc.id);\n if (skill.availableSources) {\n const marketplaceSource = skill.availableSources.find((s) => s.type !== \"local\");\n if (marketplaceSource) {\n return { ...sc, source: marketplaceSource.name };\n }\n }\n return sc;\n }),\n }));\n },\n\n buildSourceRows: () => {\n const state = get();\n const selectedTechnologies = get().getAllSelectedTechnologies();\n const { skillConfigs, boundSkills } = state;\n\n return selectedTechnologies.map((tech) => {\n const skillId = resolveAlias(tech);\n const skill = getSkillById(skillId);\n const configEntry = skillConfigs.find((sc) => sc.id === skillId);\n const primarySource = skill.availableSources?.find((s) => s.primary)?.name;\n const selectedSource =\n configEntry?.source ||\n skill.activeSource?.name ||\n primarySource ||\n DEFAULT_PUBLIC_SOURCE_NAME;\n const slug = skill.slug;\n\n const sortedSources = [...(skill.availableSources || [])].sort(\n (a, b) => getSourceSortTier(a) - getSourceSortTier(b),\n );\n\n const options =\n sortedSources.length > 0\n ? sortedSources.map((source) => ({\n id: source.name,\n selected: selectedSource === source.name,\n installed: source.installed,\n }))\n : [\n {\n id: DEFAULT_PUBLIC_SOURCE_NAME,\n selected: selectedSource === DEFAULT_PUBLIC_SOURCE_NAME,\n installed: false,\n },\n ];\n\n if (!options.some((o) => o.id === \"local\")) {\n options.unshift({\n id: \"local\",\n selected: selectedSource === \"local\",\n installed: false,\n });\n }\n\n options.push(...buildBoundSkillOptions(boundSkills, slug, selectedSource));\n\n return { skillId, options };\n });\n },\n}));\n","export {\n type BuildStepValidation,\n validateBuildStep,\n buildCategoriesForDomain,\n isCompatibleWithSelectedFrameworks,\n} from \"./build-step-logic\";\n","import { sortBy } from \"remeda\";\nimport type { CategoryDefinition, Domain, SkillId, CategorySelections } from \"../../types/index.js\";\nimport type { SkillConfig } from \"../../types/config.js\";\nimport { getAvailableSkills, getUnmetRequiredBy, resolveAlias } from \"../matrix/index.js\";\nimport { matrix, getSkillById } from \"../matrix/matrix-provider.js\";\nimport type { CategoryRow, CategoryOption } from \"../../components/wizard/category-grid.js\";\n\nconst FRAMEWORK_CATEGORY_ID = \"web-framework\";\nconst WEB_DOMAIN_ID = \"web\";\n\nexport type BuildStepValidation = {\n valid: boolean;\n message?: string;\n};\n\nexport function validateBuildStep(\n categories: CategoryRow[],\n selections: CategorySelections,\n): BuildStepValidation {\n for (const category of categories) {\n if (category.required) {\n const categorySelections = selections[category.id] || [];\n if (categorySelections.length === 0) {\n return {\n valid: true,\n message: `No skills selected in ${category.displayName} (required category)`,\n };\n }\n }\n }\n return { valid: true };\n}\n\nfunction getSelectedFrameworks(selections: CategorySelections): SkillId[] {\n return (selections[FRAMEWORK_CATEGORY_ID] ?? []).map((alias) => resolveAlias(alias));\n}\n\nexport function isCompatibleWithSelectedFrameworks(\n skillId: SkillId,\n selectedFrameworkIds: SkillId[],\n): boolean {\n const skill = getSkillById(skillId);\n if (skill.compatibleWith.length === 0) return true;\n return selectedFrameworkIds.some((frameworkId) => skill.compatibleWith.includes(frameworkId));\n}\n\n// Build CategoryRow[] from matrix for a domain\nexport function buildCategoriesForDomain(\n domain: Domain,\n allSelections: SkillId[],\n selections: CategorySelections,\n installedSkillIds?: SkillId[],\n skillConfigs?: SkillConfig[],\n filterIncompatible?: boolean,\n): CategoryRow[] {\n const selectedFrameworkIds = getSelectedFrameworks(selections);\n const shouldFilter =\n filterIncompatible && domain === WEB_DOMAIN_ID && selectedFrameworkIds.length > 0;\n\n // Object.values() on a Partial record only yields values that exist — all are CategoryDefinition\n const categories = sortBy(\n (Object.values(matrix.categories) as CategoryDefinition[]).filter(\n (cat) => cat.domain === domain,\n ),\n (cat) => cat.order ?? 0,\n );\n\n const categoryRows: CategoryRow[] = categories.map((cat) => {\n const skillOptions = getAvailableSkills(cat.id, allSelections);\n\n const filteredOptions =\n shouldFilter && cat.id !== FRAMEWORK_CATEGORY_ID\n ? skillOptions.filter((skill) =>\n isCompatibleWithSelectedFrameworks(skill.id, selectedFrameworkIds),\n )\n : skillOptions;\n\n const isExclusive = cat.exclusive ?? true;\n\n const options: CategoryOption[] = filteredOptions.map((skill) => ({\n id: skill.id,\n state:\n isExclusive && skill.advisoryState.status === \"incompatible\"\n ? { status: \"normal\" }\n : skill.advisoryState,\n selected: skill.selected,\n local: getSkillById(skill.id).local,\n installed: installedSkillIds?.includes(skill.id) || false,\n scope: skillConfigs?.find((sc) => sc.id === skill.id)?.scope,\n hasUnmetRequirements: skill.hasUnmetRequirements,\n unmetRequirementsReason: skill.unmetRequirementsReason,\n requiredBy: skill.selected ? undefined : getUnmetRequiredBy(skill.id, allSelections),\n }));\n\n return {\n id: cat.id,\n displayName: cat.displayName,\n required: cat.required ?? false,\n exclusive: cat.exclusive ?? true,\n options,\n };\n });\n\n return categoryRows.filter((row) => row.options.length > 0);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/cli/stores/wizard-store.ts","../src/cli/lib/wizard/index.ts","../src/cli/lib/wizard/build-step-logic.ts"],"sourcesContent":["import { unique, flatMap } from \"remeda\";\nimport { create } from \"zustand\";\nimport { BUILT_IN_DOMAIN_ORDER, DEFAULT_PUBLIC_SOURCE_NAME } from \"../consts.js\";\nimport type { InstallMode } from \"../lib/installation/index.js\";\nimport { deriveInstallMode as sharedDeriveInstallMode } from \"../lib/installation/installation.js\";\nimport type { AgentScopeConfig, SkillConfig } from \"../types/config.js\";\nimport { resolveAlias } from \"../lib/matrix/index.js\";\nimport { matrix, getSkillById, getCategoryDomain } from \"../lib/matrix/matrix-provider.js\";\nimport { isCompatibleWithSelectedFrameworks } from \"../lib/wizard/index.js\";\nimport type {\n AgentName,\n BoundSkill,\n Domain,\n DomainSelections,\n ResolvedSkill,\n SkillAlias,\n SkillAssignment,\n SkillId,\n SkillSource,\n Category,\n CategoryDomainMap,\n CategorySelections,\n} from \"../types/index.js\";\nimport type { SourceOption } from \"../components/wizard/source-grid.js\";\nimport { warn } from \"../utils/logger.js\";\nimport { typedEntries, typedKeys } from \"../utils/typed-object.js\";\n\nfunction createDefaultSkillConfig(id: SkillId): SkillConfig {\n const skill = matrix.skills[id];\n const primarySource = skill?.availableSources?.find((s) => s.primary)?.name;\n return { id, scope: \"global\", source: primarySource ?? DEFAULT_PUBLIC_SOURCE_NAME };\n}\n\n/** Derive all unique domains from a categories map, preserving built-in order then appending custom. */\nfunction getAllDomainsFromCategories(categories: CategoryDomainMap): Domain[] {\n const allDomains = unique(\n Object.values(categories)\n .map((cat) => cat?.domain)\n .filter((d): d is Domain => d != null),\n );\n return [\n ...BUILT_IN_DOMAIN_ORDER,\n ...allDomains.filter((d) => !BUILT_IN_DOMAIN_ORDER.includes(d)),\n ];\n}\n\n/** Sort domains into canonical order: custom domains first (alphabetically), then built-in domains per BUILT_IN_DOMAIN_ORDER. */\nfunction sortDomainsCanonically(domains: Domain[]): Domain[] {\n const builtInSet = new Set<Domain>(BUILT_IN_DOMAIN_ORDER);\n return [\n ...domains.filter((d) => !builtInSet.has(d)).sort(),\n ...BUILT_IN_DOMAIN_ORDER.filter((d) => domains.includes(d)),\n ];\n}\n\n/** Finds framework-incompatible skill IDs in web domain selections, respecting locked skills. */\nfunction findIncompatibleWebSkills(\n webSelections: CategorySelections,\n lockedSkillIds: SkillId[],\n): Set<SkillId> {\n const frameworkSelections = webSelections[\"web-framework\"] ?? [];\n if (frameworkSelections.length === 0) return new Set();\n\n const selectedFrameworkIds = frameworkSelections.map((alias) => resolveAlias(alias));\n\n return new Set(\n flatMap(typedEntries(webSelections), ([cat, skills]) =>\n cat === \"web-framework\" || !skills\n ? []\n : skills.filter(\n (id) =>\n !lockedSkillIds.includes(id) &&\n !isCompatibleWithSelectedFrameworks(id, selectedFrameworkIds),\n ),\n ),\n );\n}\n\n/** Returns selections with the given skill IDs removed from all categories. */\nfunction removeSkillsFromSelections(\n selections: CategorySelections,\n toRemove: Set<SkillId>,\n): CategorySelections {\n return Object.fromEntries(\n typedEntries(selections).map(([cat, skills]) => [\n cat,\n skills?.filter((id) => !toRemove.has(id)) ?? [],\n ]),\n ) as CategorySelections; // Object.fromEntries widens to Record<string, ...>\n}\n\n/** Built-in agent names grouped by domain prefix. Custom domains return no preselected agents. */\nconst DOMAIN_AGENTS: Partial<Record<string, AgentName[]>> = {\n web: [\n \"web-developer\",\n \"web-reviewer\",\n \"web-researcher\",\n \"web-tester\",\n \"web-pm\",\n \"web-architecture\",\n ],\n api: [\"api-developer\", \"api-reviewer\", \"api-researcher\"],\n cli: [\"cli-developer\", \"cli-tester\", \"cli-reviewer\"],\n};\n\n/**\n * Fixed source sort tiers (lower = higher priority):\n * 1 = local/global (installed on disk -- type \"local\" or installed via plugin)\n * 2 = scoped marketplace (primary source from --source flag)\n * 3 = default public marketplace (Agents Inc)\n * 4 = third-party marketplaces (extra configured sources)\n */\nconst SOURCE_SORT_TIER_LOCAL = 1;\nconst SOURCE_SORT_TIER_SCOPED = 2;\nconst SOURCE_SORT_TIER_PUBLIC = 3;\nconst SOURCE_SORT_TIER_THIRD_PARTY = 4;\n\nfunction getSourceSortTier(source: SkillSource): number {\n if (source.type === \"local\") return SOURCE_SORT_TIER_LOCAL;\n if (source.primary) return SOURCE_SORT_TIER_SCOPED;\n if (source.type === \"public\") return SOURCE_SORT_TIER_PUBLIC;\n return SOURCE_SORT_TIER_THIRD_PARTY;\n}\n\nexport type SkillLookupEntry = Pick<ResolvedSkill, \"category\" | \"displayName\">;\n\nfunction resolveSkillForPopulation(\n skillId: SkillId,\n): { domain: Domain; subcat: Category; techId: SkillId } | null {\n const { skills } = matrix;\n const skill = skills[skillId];\n if (!skill?.category) {\n warn(\n `Installed skill '${skillId}' is missing from the marketplace — it may have been removed or renamed`,\n );\n return null;\n }\n\n const domain = getCategoryDomain(skill.category);\n if (!domain) {\n warn(`Installed skill '${skillId}' has unknown category '${skill.category}' — skipping`);\n return null;\n }\n\n // Boundary cast: domain lookup confirmed category exists in matrix\n const subcat = skill.category as Category;\n return { domain, subcat, techId: skillId };\n}\n\nfunction buildBoundSkillOptions(\n boundSkills: BoundSkill[],\n alias: SkillAlias,\n selectedSource: string,\n): SourceOption[] {\n return boundSkills\n .filter((b) => b.boundTo === alias)\n .map((bound) => ({\n id: bound.sourceName,\n selected: selectedSource === bound.sourceName,\n installed: false,\n }));\n}\n\n/**\n * Wizard step identifiers for the multi-step init/edit flow.\n *\n * Progression: stack -> domains -> build -> sources -> agents -> confirm\n * The \"stack\" step shows all stacks + \"Start from scratch\" in a unified list.\n * The \"domains\" step shows domain selection (web, api, cli, mobile, shared).\n * Navigation is tracked via the `history` stack for goBack() support.\n */\nexport type WizardStep =\n | \"stack\" // Select stack or \"Start from scratch\"\n | \"domains\" // Select domains to configure\n | \"build\" // CategoryGrid for technology selection\n | \"sources\" // Choose skill sources (recommended vs custom)\n | \"agents\" // Select which agents to compile\n | \"confirm\"; // Final confirmation\n\n/**\n * Wizard store state and actions.\n *\n * The store uses a composition pattern: small, focused actions that each mutate\n * one or two state fields. Wizard step components compose these actions to build\n * up the full selection state incrementally (domains -> categories -> skills -> sources).\n *\n * State flow: stack/scratch selection -> domain selection -> per-domain skill\n * selection (build step) -> source customization -> agent selection -> confirmation.\n */\nexport type WizardState = {\n step: WizardStep;\n\n approach: \"stack\" | \"scratch\" | null;\n selectedStackId: string | null;\n stackAction: \"defaults\" | \"customize\" | null;\n\n selectedDomains: Domain[];\n\n currentDomainIndex: number;\n domainSelections: DomainSelections;\n /** Snapshot of stack-provided domain selections for restoration on domain re-toggle */\n _stackDomainSelections: DomainSelections | null;\n\n showLabels: boolean;\n filterIncompatible: boolean;\n\n skillConfigs: SkillConfig[];\n focusedSkillId: SkillId | null;\n\n customizeSources: boolean;\n\n showSettings: boolean;\n showHelp: boolean;\n enabledSources: Record<string, boolean>;\n\n selectedAgents: AgentName[];\n agentConfigs: AgentScopeConfig[];\n focusedAgentId: AgentName | null;\n\n boundSkills: BoundSkill[];\n\n /** Skill IDs that cannot be toggled or removed (D9: existing global items in project context) */\n lockedSkillIds: SkillId[];\n /** Agent names that cannot be toggled or removed (D9: existing global agents in project context) */\n lockedAgentNames: AgentName[];\n\n /** When true, scope toggling is disabled (editing from ~/.claude/ with no project to move items to) */\n isEditingFromGlobalScope: boolean;\n\n history: WizardStep[];\n\n /**\n * Navigate to a wizard step, pushing the current step onto history.\n * @param step - Target step to navigate to\n *\n * Side effects: sets `step`, appends previous step to `history`\n */\n setStep: (step: WizardStep) => void;\n /**\n * Set the wizard approach (stack-based or build-from-scratch).\n * @param approach - \"stack\" to use a pre-built template, \"scratch\" to select skills manually, null to reset\n *\n * Side effects: sets `approach`\n */\n setApproach: (approach: \"stack\" | \"scratch\" | null) => void;\n /**\n * Select a stack by ID, or null to deselect.\n * @param stackId - Stack identifier from suggestedStacks, or null to clear\n *\n * Side effects: sets `selectedStackId`\n */\n selectStack: (stackId: string | null) => void;\n /**\n * Set how to apply the selected stack.\n * @param action - \"defaults\" to use stack as-is, \"customize\" to enter the build step\n *\n * Side effects: sets `stackAction`\n */\n setStackAction: (action: \"defaults\" | \"customize\") => void;\n /**\n * Pre-populate domainSelections from a stack's agent-to-skill mappings.\n *\n * Iterates all agents in the stack, resolving each category's skill assignments\n * to the appropriate domain. Enables all domains and deduplicates skill IDs.\n *\n * @param stack - Stack definition with agent-level skill assignments\n * @param stack.agents - Record of agent name to `{ category: SkillAssignment[] }` mappings\n * @param categories - Category definitions used to resolve category -> domain mapping\n *\n * Side effects: sets `domainSelections`, sets `selectedDomains` to ALL_DOMAINS\n */\n populateFromStack: (stack: {\n agents: Record<string, Partial<Record<Category, SkillAssignment[]>>>;\n }) => void;\n /**\n * Pre-populate domainSelections from a flat list of installed skill IDs.\n *\n * Used by `agentsinc edit` to restore wizard state from existing project config.\n * Looks up each skill's category and domain, warns for unresolvable skills.\n *\n * @param skillIds - Flat array of currently installed skill IDs\n * @param skills - Skill lookup providing category and displayName per skill ID\n * @param categories - Category definitions used to resolve category -> domain mapping\n *\n * Side effects: sets `domainSelections`, sets `selectedDomains` to domains found in the provided skill IDs\n */\n populateFromSkillIds: (skillIds: SkillId[], savedConfigs?: SkillConfig[]) => void;\n /**\n * Toggle a domain on or off in the selectedDomains list.\n * @param domain - Domain to toggle\n *\n * Side effects: adds or removes from `selectedDomains`\n */\n toggleDomain: (domain: Domain) => void;\n /**\n * Toggle a skill selection within a domain's category.\n *\n * When exclusive is true (radio behavior), selecting a new skill replaces any\n * existing selection in that category. When false (checkbox behavior),\n * the skill is added to or removed from the selection array.\n *\n * @param domain - Domain containing the category\n * @param category - Category within the domain\n * @param technology - Skill ID to toggle\n * @param exclusive - If true, only one skill can be selected per category (radio)\n *\n * Side effects: updates `domainSelections[domain][category]`\n */\n toggleTechnology: (\n domain: Domain,\n category: Category,\n technology: SkillId,\n exclusive: boolean,\n ) => void;\n /**\n * Advance to the next domain in the build step.\n * @returns true if advanced, false if already at the last domain\n *\n * Side effects: increments `currentDomainIndex`\n */\n nextDomain: () => boolean;\n /**\n * Go back to the previous domain in the build step.\n * @returns true if moved back, false if already at the first domain\n *\n * Side effects: decrements `currentDomainIndex`\n */\n prevDomain: () => boolean;\n /**\n * Set the current domain index directly.\n * @param index - Index to set (0-based, must be within selectedDomains range)\n *\n * Side effects: sets `currentDomainIndex` if index is valid, otherwise no-op\n */\n setCurrentDomainIndex: (index: number) => void;\n /** Toggle compatibility label visibility on skill tags in the build step grid. */\n toggleShowLabels: () => void;\n /** Toggle filtering of incompatible skills in the build step grid. */\n toggleFilterIncompatible: () => void;\n /**\n * Derive the install mode from skillConfigs source values.\n * If all skills use \"local\" source, returns \"local\". If all use non-local, returns \"plugin\".\n * If mixed, returns \"mixed\". Returns \"local\" when no skills are configured.\n */\n deriveInstallMode: () => InstallMode;\n /**\n * Toggle the scope of a specific skill between \"project\" and \"global\".\n * @param skillId - Skill to toggle scope for\n *\n * Side effects: updates `skillConfigs` entry for the skill\n */\n toggleSkillScope: (skillId: SkillId) => void;\n /**\n * Update the source for a specific skill in skillConfigs.\n * @param skillId - Skill to update\n * @param source - Source identifier (e.g., \"local\", marketplace name)\n *\n * Side effects: updates `skillConfigs` entry for the skill\n */\n setSkillSource: (skillId: SkillId, source: string) => void;\n /**\n * Set the currently focused skill ID in the build step (for S hotkey).\n * @param id - Skill ID to focus, or null to clear\n *\n * Side effects: sets `focusedSkillId`\n */\n setFocusedSkillId: (id: SkillId | null) => void;\n /**\n * Set which source provides a specific skill.\n * @param skillId - Skill to configure the source for\n * @param sourceId - Source identifier (e.g., \"public\", \"local\", marketplace name)\n *\n * Side effects: updates `skillConfigs` entry for the skill. No-op with warning if either param is empty.\n */\n setSourceSelection: (skillId: SkillId, sourceId: string) => void;\n /**\n * Enable or disable source customization on the sources step.\n * @param customize - true to show per-skill source pickers\n *\n * Side effects: sets `customizeSources`\n */\n setCustomizeSources: (customize: boolean) => void;\n /** Toggle the settings overlay (source management). */\n toggleSettings: () => void;\n /** Toggle the help overlay (hotkey reference). */\n toggleHelp: () => void;\n /**\n * Replace the full set of enabled/disabled sources.\n * @param sources - Record of source name to enabled boolean. Empty-string keys are filtered out.\n *\n * Side effects: sets `enabledSources`\n */\n setEnabledSources: (sources: Record<string, boolean>) => void;\n /**\n * Add a bound skill from search to the wizard's bound skills list.\n * Duplicates (same id + sourceUrl) are silently skipped with a warning.\n *\n * @param skill - Bound skill to add (foreign skill tied to a category alias)\n *\n * Side effects: appends to `boundSkills`\n */\n bindSkill: (skill: BoundSkill) => void;\n /**\n * Navigate to the previous wizard step using the history stack.\n * Falls back to \"stack\" if history is empty.\n *\n * Side effects: pops from `history`, sets `step` to the popped value\n */\n goBack: () => void;\n /**\n * Toggle an agent on or off in the selectedAgents list.\n * @param agent - Agent name to toggle\n *\n * Side effects: adds or removes from `selectedAgents`, syncs `agentConfigs`\n */\n toggleAgent: (agent: AgentName) => void;\n /**\n * Toggle the scope of a specific agent between \"project\" and \"global\".\n * @param agentName - Agent to toggle scope for\n *\n * Side effects: updates `agentConfigs` entry for the agent\n */\n toggleAgentScope: (agentName: AgentName) => void;\n /**\n * Set the currently focused agent ID in the agents step (for S hotkey).\n * @param id - Agent name to focus, or null to clear\n *\n * Side effects: sets `focusedAgentId`\n */\n setFocusedAgentId: (id: AgentName | null) => void;\n /**\n * Preselect agents based on selected domains from the first wizard step.\n * Matches domains against DOMAIN_AGENTS mapping.\n * Optional agents (meta/pattern) are excluded.\n *\n * Side effects: replaces `selectedAgents` with computed preselection\n */\n preselectAgentsFromDomains: () => void;\n /** Reset all wizard state to initial values. */\n reset: () => void;\n\n /**\n * Collect all selected skill IDs across all domains and categories.\n * @returns Flat array of every selected SkillId (may contain duplicates if shared across domains)\n */\n getAllSelectedTechnologies: () => SkillId[];\n /**\n * Group selected skill IDs by domain.\n * @returns Partial record mapping each domain with selections to its skill ID array\n */\n getSelectedTechnologiesPerDomain: () => Partial<Record<Domain, SkillId[]>>;\n /**\n * Get the domain currently visible in the build step.\n * @returns The domain at currentDomainIndex, or null if no domains are selected\n */\n getCurrentDomain: () => Domain | null;\n /**\n * Count total selected technologies across all domains.\n * @returns Number of selected skill IDs\n */\n getTechnologyCount: () => number;\n /**\n * Compute which wizard steps are completed and which are skipped.\n * Used by WizardTabs to render step progress indicators.\n * @returns Object with completedSteps and skippedSteps string arrays\n */\n getStepProgress: () => { completedSteps: WizardStep[]; skippedSteps: WizardStep[] };\n /** @returns true if there is a next domain after the current one */\n canGoToNextDomain: () => boolean;\n /** @returns true if there is a previous domain before the current one */\n canGoToPreviousDomain: () => boolean;\n /** Set all selected skills to \"local\" source. */\n setAllSourcesLocal: () => void;\n /** Set all selected skills to their first non-local (marketplace) source. */\n setAllSourcesPlugin: () => void;\n\n /**\n * Build the source selection rows for the sources step UI.\n *\n * For each selected technology, resolves the canonical skill ID, looks up available\n * sources from the matrix, merges in any bound skills from search, and determines\n * which source is currently selected. Sources are sorted: local first, then public,\n * then private/other.\n *\n * @returns Array of row objects, one per selected technology, each containing:\n * - `skillId` - Canonical resolved skill ID\n * - `options` - Available sources with selection state and install status\n */\n buildSourceRows: () => {\n skillId: SkillId;\n options: SourceOption[];\n }[];\n};\n\n/** State-only fields from WizardState (excludes actions/getters). Used to type createInitialState(). */\ntype WizardStateData = Pick<\n WizardState,\n | \"step\"\n | \"approach\"\n | \"selectedStackId\"\n | \"stackAction\"\n | \"selectedDomains\"\n | \"currentDomainIndex\"\n | \"domainSelections\"\n | \"_stackDomainSelections\"\n | \"showLabels\"\n | \"filterIncompatible\"\n | \"skillConfigs\"\n | \"focusedSkillId\"\n | \"customizeSources\"\n | \"showSettings\"\n | \"showHelp\"\n | \"enabledSources\"\n | \"selectedAgents\"\n | \"agentConfigs\"\n | \"focusedAgentId\"\n | \"boundSkills\"\n | \"lockedSkillIds\"\n | \"lockedAgentNames\"\n | \"isEditingFromGlobalScope\"\n | \"history\"\n>;\n\nconst createInitialState = (): WizardStateData => ({\n step: \"stack\",\n approach: null,\n selectedStackId: null,\n stackAction: null,\n selectedDomains: [],\n currentDomainIndex: 0,\n domainSelections: {},\n /** Snapshot of domainSelections from populateFromStack/populateFromSkillIds, used to restore on domain re-toggle */\n _stackDomainSelections: null,\n showLabels: false,\n filterIncompatible: false,\n skillConfigs: [],\n focusedSkillId: null,\n customizeSources: false,\n showSettings: false,\n showHelp: false,\n enabledSources: {},\n selectedAgents: [],\n agentConfigs: [],\n focusedAgentId: null,\n boundSkills: [],\n lockedSkillIds: [],\n lockedAgentNames: [],\n isEditingFromGlobalScope: false,\n history: [],\n});\n\nexport const useWizardStore = create<WizardState>((set, get) => ({\n ...createInitialState(),\n\n setStep: (step) =>\n set((state) => ({\n step,\n history: [...state.history, state.step],\n })),\n\n setApproach: (approach) => set({ approach }),\n\n selectStack: (stackId) =>\n set({\n selectedStackId: stackId,\n domainSelections: {},\n _stackDomainSelections: null,\n selectedDomains: [],\n skillConfigs: [],\n selectedAgents: [],\n agentConfigs: [],\n boundSkills: [],\n currentDomainIndex: 0,\n stackAction: null,\n }),\n\n setStackAction: (action) => set({ stackAction: action }),\n\n populateFromStack: (stack) =>\n set(() => {\n const { categories } = matrix;\n const domainSelections: DomainSelections = {};\n const domains = new Set<Domain>();\n const allSkillIds = new Set<SkillId>();\n\n for (const agentConfig of Object.values(stack.agents)) {\n for (const [subcat, assignments] of typedEntries<Category, SkillAssignment[]>(\n agentConfig,\n )) {\n const category = categories[subcat];\n const domain = category?.domain;\n\n if (!domain || !assignments) {\n continue;\n }\n\n domains.add(domain);\n\n if (!domainSelections[domain]) {\n domainSelections[domain] = {};\n }\n\n if (!domainSelections[domain][subcat]) {\n domainSelections[domain][subcat] = [];\n }\n\n for (const assignment of assignments) {\n if (!domainSelections[domain][subcat].includes(assignment.id)) {\n domainSelections[domain][subcat].push(assignment.id);\n allSkillIds.add(assignment.id);\n }\n }\n }\n }\n\n const skillConfigs: SkillConfig[] = [...allSkillIds].map(createDefaultSkillConfig);\n\n return {\n domainSelections,\n _stackDomainSelections: structuredClone(domainSelections),\n selectedDomains: sortDomainsCanonically([...domains]),\n skillConfigs,\n };\n }),\n\n populateFromSkillIds: (skillIds, savedConfigs) =>\n set(() => {\n const domainSelections: DomainSelections = {};\n const resolvedSkillIds: SkillId[] = [];\n let skippedCount = 0;\n\n for (const skillId of skillIds) {\n const resolved = resolveSkillForPopulation(skillId);\n if (!resolved) {\n skippedCount++;\n continue;\n }\n\n const { domain, subcat, techId } = resolved;\n if (!domainSelections[domain]) domainSelections[domain] = {};\n if (!domainSelections[domain][subcat]) domainSelections[domain][subcat] = [];\n\n if (!domainSelections[domain][subcat].includes(techId)) {\n domainSelections[domain][subcat].push(techId);\n resolvedSkillIds.push(techId);\n }\n }\n\n if (skippedCount > 0) {\n warn(`${skippedCount} installed skill(s) could not be resolved and were skipped`);\n }\n\n const selectedDomains = sortDomainsCanonically(typedKeys<Domain>(domainSelections));\n\n const skillConfigs: SkillConfig[] = resolvedSkillIds.map((id) => {\n const saved = savedConfigs?.find((sc) => sc.id === id);\n const skill = matrix.skills[id];\n const primarySource = skill?.availableSources?.find((s) => s.primary)?.name;\n return {\n id,\n scope: saved?.scope ?? \"global\",\n source: saved?.source ?? primarySource ?? DEFAULT_PUBLIC_SOURCE_NAME,\n };\n });\n\n return {\n domainSelections,\n _stackDomainSelections: structuredClone(domainSelections),\n selectedDomains,\n skillConfigs,\n };\n }),\n\n toggleDomain: (domain) =>\n set((state) => {\n const isSelected = state.selectedDomains.includes(domain);\n if (isSelected) {\n const { [domain]: _removed, ...remainingSelections } = state.domainSelections;\n\n // Collect all skill IDs being removed from this domain\n const removedSkillIds = new Set<SkillId>();\n if (_removed) {\n for (const skills of Object.values(_removed)) {\n if (skills) {\n for (const id of skills) {\n removedSkillIds.add(id);\n }\n }\n }\n }\n\n return {\n selectedDomains: state.selectedDomains.filter((d) => d !== domain),\n domainSelections: remainingSelections,\n skillConfigs: state.skillConfigs.filter((sc) => !removedSkillIds.has(sc.id)),\n };\n }\n\n // Restore stack selections for this domain if a stack snapshot exists\n const stackSelections = state._stackDomainSelections?.[domain];\n if (stackSelections) {\n // Also restore skillConfigs for the restored skills\n const restoredSkillIds: SkillId[] = [];\n for (const skills of Object.values(stackSelections)) {\n if (skills) restoredSkillIds.push(...skills);\n }\n const existingIds = new Set(state.skillConfigs.map((sc) => sc.id));\n const newConfigs = restoredSkillIds\n .filter((id) => !existingIds.has(id))\n .map(createDefaultSkillConfig);\n\n return {\n selectedDomains: sortDomainsCanonically([...state.selectedDomains, domain]),\n domainSelections: {\n ...state.domainSelections,\n [domain]: structuredClone(stackSelections),\n },\n skillConfigs: [...state.skillConfigs, ...newConfigs],\n };\n }\n\n return {\n selectedDomains: sortDomainsCanonically([...state.selectedDomains, domain]),\n };\n }),\n\n toggleTechnology: (domain, category, technology, exclusive) =>\n set((state) => {\n // D9: locked skills cannot be toggled\n if (state.lockedSkillIds.includes(technology)) return state;\n\n const currentSelections = state.domainSelections[domain]?.[category] || [];\n const isSelected = currentSelections.includes(technology);\n\n let newSelections: SkillId[];\n if (exclusive) {\n newSelections = isSelected ? [] : [technology];\n } else {\n newSelections = isSelected\n ? currentSelections.filter((t) => t !== technology)\n : [...currentSelections, technology];\n }\n\n // Sync skillConfigs: add entries for newly selected, remove entries for deselected\n const removed = currentSelections.filter((id) => !newSelections.includes(id));\n const added = newSelections.filter((id) => !currentSelections.includes(id));\n\n let updatedConfigs = state.skillConfigs.filter((sc) => !removed.includes(sc.id));\n for (const id of added) {\n if (!updatedConfigs.some((sc) => sc.id === id)) {\n updatedConfigs = [...updatedConfigs, createDefaultSkillConfig(id)];\n }\n }\n\n return {\n skillConfigs: updatedConfigs,\n domainSelections: {\n ...state.domainSelections,\n [domain]: {\n ...state.domainSelections[domain],\n [category]: newSelections,\n },\n },\n };\n }),\n\n nextDomain: () => {\n const state = get();\n if (state.currentDomainIndex < state.selectedDomains.length - 1) {\n set({\n currentDomainIndex: state.currentDomainIndex + 1,\n });\n return true;\n }\n return false;\n },\n\n prevDomain: () => {\n const state = get();\n if (state.currentDomainIndex > 0) {\n set({\n currentDomainIndex: state.currentDomainIndex - 1,\n });\n return true;\n }\n return false;\n },\n\n setCurrentDomainIndex: (index) => {\n const state = get();\n if (index >= 0 && index < state.selectedDomains.length) {\n set({ currentDomainIndex: index });\n }\n },\n\n toggleShowLabels: () => set((state) => ({ showLabels: !state.showLabels })),\n toggleFilterIncompatible: () =>\n set((state) => {\n if (state.filterIncompatible) return { filterIncompatible: false };\n\n const webSelections = state.domainSelections.web;\n if (!webSelections) return { filterIncompatible: true };\n\n const removed = findIncompatibleWebSkills(webSelections, state.lockedSkillIds);\n if (removed.size === 0) return { filterIncompatible: true };\n\n return {\n filterIncompatible: true,\n domainSelections: {\n ...state.domainSelections,\n web: removeSkillsFromSelections(webSelections, removed),\n },\n skillConfigs: state.skillConfigs.filter((sc) => !removed.has(sc.id)),\n };\n }),\n\n deriveInstallMode: (): InstallMode => {\n const { skillConfigs } = get();\n return sharedDeriveInstallMode(skillConfigs);\n },\n\n toggleSkillScope: (skillId) =>\n set((state) => {\n if (state.isEditingFromGlobalScope) return state;\n // D9: locked skills cannot have their scope toggled\n if (state.lockedSkillIds.includes(skillId)) return state;\n return {\n skillConfigs: state.skillConfigs.map((sc) =>\n sc.id === skillId ? { ...sc, scope: sc.scope === \"project\" ? \"global\" : \"project\" } : sc,\n ),\n };\n }),\n\n setSkillSource: (skillId, source) =>\n set((state) => ({\n skillConfigs: state.skillConfigs.map((sc) => (sc.id === skillId ? { ...sc, source } : sc)),\n })),\n\n setFocusedSkillId: (id) => set({ focusedSkillId: id }),\n\n setSourceSelection: (skillId, sourceId) =>\n set((state) => {\n if (!skillId) {\n warn(\"Ignoring setSourceSelection call with empty skillId\");\n return state;\n }\n if (!sourceId) {\n warn(`Ignoring setSourceSelection call with empty sourceId for skill '${skillId}'`);\n return state;\n }\n return {\n skillConfigs: state.skillConfigs.map((sc) =>\n sc.id === skillId ? { ...sc, source: sourceId } : sc,\n ),\n };\n }),\n\n setCustomizeSources: (customize) => set({ customizeSources: customize }),\n\n toggleSettings: () => set((state) => ({ showSettings: !state.showSettings })),\n\n toggleHelp: () => set((state) => ({ showHelp: !state.showHelp })),\n\n setEnabledSources: (sources) => {\n const invalidKeys = Object.keys(sources).filter((key) => !key.trim());\n if (invalidKeys.length > 0) {\n warn(\"Ignoring setEnabledSources call with empty source name(s)\");\n }\n const validSources = Object.fromEntries(Object.entries(sources).filter(([key]) => key.trim()));\n return set({ enabledSources: validSources });\n },\n\n bindSkill: (skill) =>\n set((state) => {\n const exists = state.boundSkills.some(\n (b) => b.id === skill.id && b.sourceUrl === skill.sourceUrl,\n );\n if (exists) {\n warn(`Skill '${skill.id}' from '${skill.sourceUrl}' is already bound — skipping duplicate`);\n return state;\n }\n return { boundSkills: [...state.boundSkills, skill] };\n }),\n\n goBack: () =>\n set((state) => {\n const history = [...state.history];\n const previousStep = history.pop();\n return {\n step: previousStep || \"stack\",\n history,\n };\n }),\n\n toggleAgent: (agent) =>\n set((state) => {\n // D9: locked agents cannot be toggled\n if (state.lockedAgentNames.includes(agent)) return state;\n\n const isSelected = state.selectedAgents.includes(agent);\n if (isSelected) {\n return {\n selectedAgents: state.selectedAgents.filter((a) => a !== agent),\n agentConfigs: state.agentConfigs.filter((ac) => ac.name !== agent),\n };\n }\n return {\n selectedAgents: [...state.selectedAgents, agent],\n agentConfigs: [...state.agentConfigs, { name: agent, scope: \"global\" as const }],\n };\n }),\n\n toggleAgentScope: (agentName) =>\n set((state) => {\n if (state.isEditingFromGlobalScope) return state;\n // D9: locked agents cannot have their scope toggled\n if (state.lockedAgentNames.includes(agentName)) return state;\n return {\n agentConfigs: state.agentConfigs.map((ac) =>\n ac.name === agentName\n ? { ...ac, scope: ac.scope === \"project\" ? (\"global\" as const) : (\"project\" as const) }\n : ac,\n ),\n };\n }),\n\n setFocusedAgentId: (id) => set({ focusedAgentId: id }),\n\n preselectAgentsFromDomains: () =>\n set(() => {\n const agents: AgentName[] = [];\n for (const domain of get().selectedDomains) {\n const domainAgents = DOMAIN_AGENTS[domain];\n if (domainAgents) {\n agents.push(...domainAgents);\n }\n }\n const sorted = agents.sort();\n return {\n selectedAgents: sorted,\n agentConfigs: sorted.map((name) => ({ name, scope: \"global\" as const })),\n };\n }),\n\n reset: () => set(createInitialState()),\n\n getAllSelectedTechnologies: () => {\n const state = get();\n const technologies: SkillId[] = [];\n for (const domain of typedKeys<Domain>(state.domainSelections)) {\n const domainSel = state.domainSelections[domain];\n if (!domainSel) continue;\n for (const category of typedKeys<Category>(domainSel)) {\n const techs = domainSel[category];\n if (techs) technologies.push(...techs);\n }\n }\n return technologies;\n },\n\n getSelectedTechnologiesPerDomain: () => {\n const state = get();\n const result: Partial<Record<Domain, SkillId[]>> = {};\n for (const domain of typedKeys<Domain>(state.domainSelections)) {\n const domainSel = state.domainSelections[domain];\n if (!domainSel) continue;\n const techs: SkillId[] = [];\n for (const category of typedKeys<Category>(domainSel)) {\n const subTechs = domainSel[category];\n if (subTechs) techs.push(...subTechs);\n }\n if (techs.length > 0) {\n result[domain] = techs;\n }\n }\n return result;\n },\n\n getCurrentDomain: () => {\n const state = get();\n return state.selectedDomains[state.currentDomainIndex] || null;\n },\n\n getTechnologyCount: () => {\n return get().getAllSelectedTechnologies().length;\n },\n\n getStepProgress: () => {\n const state = get();\n const completed: WizardStep[] = [];\n const skipped: WizardStep[] = [];\n\n if (state.step !== \"stack\" && state.step !== \"domains\") {\n completed.push(\"stack\");\n completed.push(\"domains\");\n } else if (state.step === \"domains\") {\n completed.push(\"stack\");\n }\n\n if (state.approach === \"stack\" && state.selectedStackId && state.stackAction === \"defaults\") {\n skipped.push(\"build\");\n skipped.push(\"sources\");\n skipped.push(\"agents\");\n } else if (state.step === \"confirm\") {\n completed.push(\"build\");\n completed.push(\"sources\");\n completed.push(\"agents\");\n } else if (state.step === \"agents\") {\n completed.push(\"build\");\n completed.push(\"sources\");\n } else if (state.step === \"sources\") {\n completed.push(\"build\");\n }\n\n return { completedSteps: completed, skippedSteps: skipped };\n },\n\n canGoToNextDomain: () => {\n const state = get();\n return state.currentDomainIndex < state.selectedDomains.length - 1;\n },\n\n canGoToPreviousDomain: () => {\n const state = get();\n return state.currentDomainIndex > 0;\n },\n\n setAllSourcesLocal: () => {\n set((state) => ({\n skillConfigs: state.skillConfigs.map((sc) => ({ ...sc, source: \"local\" })),\n }));\n },\n\n setAllSourcesPlugin: () => {\n set((state) => ({\n skillConfigs: state.skillConfigs.map((sc) => {\n const skill = getSkillById(sc.id);\n if (skill.availableSources) {\n const marketplaceSource = skill.availableSources.find((s) => s.type !== \"local\");\n if (marketplaceSource) {\n return { ...sc, source: marketplaceSource.name };\n }\n }\n return sc;\n }),\n }));\n },\n\n buildSourceRows: () => {\n const state = get();\n const selectedTechnologies = get().getAllSelectedTechnologies();\n const { skillConfigs, boundSkills } = state;\n\n return selectedTechnologies.map((tech) => {\n const skillId = resolveAlias(tech);\n const skill = getSkillById(skillId);\n const configEntry = skillConfigs.find((sc) => sc.id === skillId);\n const primarySource = skill.availableSources?.find((s) => s.primary)?.name;\n const selectedSource =\n configEntry?.source ||\n skill.activeSource?.name ||\n primarySource ||\n DEFAULT_PUBLIC_SOURCE_NAME;\n const slug = skill.slug;\n\n const sortedSources = [...(skill.availableSources || [])].sort(\n (a, b) => getSourceSortTier(a) - getSourceSortTier(b),\n );\n\n const options: SourceOption[] =\n sortedSources.length > 0\n ? sortedSources.map((source) => ({\n id: source.name,\n displayName: source.displayName,\n selected: selectedSource === source.name,\n installed: source.installed,\n }))\n : [\n {\n id: DEFAULT_PUBLIC_SOURCE_NAME,\n selected: selectedSource === DEFAULT_PUBLIC_SOURCE_NAME,\n installed: false,\n },\n ];\n\n if (!options.some((o) => o.id === \"local\")) {\n options.unshift({\n id: \"local\",\n selected: selectedSource === \"local\",\n installed: false,\n });\n }\n\n options.push(...buildBoundSkillOptions(boundSkills, slug, selectedSource));\n\n return { skillId, options };\n });\n },\n}));\n","export {\n type BuildStepValidation,\n validateBuildStep,\n buildCategoriesForDomain,\n isCompatibleWithSelectedFrameworks,\n} from \"./build-step-logic\";\n","import { sortBy } from \"remeda\";\nimport type { CategoryDefinition, Domain, SkillId, CategorySelections } from \"../../types/index.js\";\nimport type { SkillConfig } from \"../../types/config.js\";\nimport { getAvailableSkills, getUnmetRequiredBy, resolveAlias } from \"../matrix/index.js\";\nimport { matrix, getSkillById } from \"../matrix/matrix-provider.js\";\nimport type { CategoryRow, CategoryOption } from \"../../components/wizard/category-grid.js\";\n\nconst FRAMEWORK_CATEGORY_ID = \"web-framework\";\nconst WEB_DOMAIN_ID = \"web\";\n\nexport type BuildStepValidation = {\n valid: boolean;\n message?: string;\n};\n\nexport function validateBuildStep(\n categories: CategoryRow[],\n selections: CategorySelections,\n): BuildStepValidation {\n for (const category of categories) {\n if (category.required) {\n const categorySelections = selections[category.id] || [];\n if (categorySelections.length === 0) {\n return {\n valid: true,\n message: `No skills selected in ${category.displayName} (required category)`,\n };\n }\n }\n }\n return { valid: true };\n}\n\nfunction getSelectedFrameworks(selections: CategorySelections): SkillId[] {\n return (selections[FRAMEWORK_CATEGORY_ID] ?? []).map((alias) => resolveAlias(alias));\n}\n\nexport function isCompatibleWithSelectedFrameworks(\n skillId: SkillId,\n selectedFrameworkIds: SkillId[],\n): boolean {\n const skill = getSkillById(skillId);\n if (skill.compatibleWith.length === 0) return true;\n return selectedFrameworkIds.some((frameworkId) => skill.compatibleWith.includes(frameworkId));\n}\n\n// Build CategoryRow[] from matrix for a domain\nexport function buildCategoriesForDomain(\n domain: Domain,\n allSelections: SkillId[],\n selections: CategorySelections,\n installedSkillIds?: SkillId[],\n skillConfigs?: SkillConfig[],\n filterIncompatible?: boolean,\n): CategoryRow[] {\n const selectedFrameworkIds = getSelectedFrameworks(selections);\n const shouldFilter =\n filterIncompatible && domain === WEB_DOMAIN_ID && selectedFrameworkIds.length > 0;\n\n // Object.values() on a Partial record only yields values that exist — all are CategoryDefinition\n const categories = sortBy(\n (Object.values(matrix.categories) as CategoryDefinition[]).filter(\n (cat) => cat.domain === domain,\n ),\n (cat) => cat.order ?? 0,\n );\n\n const categoryRows: CategoryRow[] = categories.map((cat) => {\n const skillOptions = getAvailableSkills(cat.id, allSelections);\n\n const filteredOptions =\n shouldFilter && cat.id !== FRAMEWORK_CATEGORY_ID\n ? skillOptions.filter((skill) =>\n isCompatibleWithSelectedFrameworks(skill.id, selectedFrameworkIds),\n )\n : skillOptions;\n\n const isExclusive = cat.exclusive ?? true;\n\n const options: CategoryOption[] = filteredOptions.map((skill) => ({\n id: skill.id,\n state:\n isExclusive && skill.advisoryState.status === \"incompatible\"\n ? { status: \"normal\" }\n : skill.advisoryState,\n selected: skill.selected,\n local: getSkillById(skill.id).local,\n installed: installedSkillIds?.includes(skill.id) || false,\n scope: skillConfigs?.find((sc) => sc.id === skill.id)?.scope,\n hasUnmetRequirements: skill.hasUnmetRequirements,\n unmetRequirementsReason: skill.unmetRequirementsReason,\n requiredBy: skill.selected ? undefined : getUnmetRequiredBy(skill.id, allSelections),\n }));\n\n return {\n id: cat.id,\n displayName: cat.displayName,\n required: cat.required ?? false,\n exclusive: cat.exclusive ?? true,\n options,\n };\n });\n\n return categoryRows.filter((row) => row.options.length > 0);\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  StackSelection
4
- } from "./chunk-5M6Q5UQO.js";
4
+ } from "./chunk-Z5FXZFX2.js";
5
5
  import {
6
6
  useMeasuredHeight
7
7
  } from "./chunk-K77I4XGL.js";
@@ -21,4 +21,4 @@ var StepStack = ({ onCancel }) => {
21
21
  export {
22
22
  StepStack
23
23
  };
24
- //# sourceMappingURL=chunk-Q4DMIPZB.js.map
24
+ //# sourceMappingURL=chunk-7AUGC7PK.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getErrorMessage
4
- } from "./chunk-NUU3U43A.js";
4
+ } from "./chunk-OOHPUT5M.js";
5
5
  import {
6
6
  init_esm_shims
7
7
  } from "./chunk-DHET7RCE.js";
@@ -49,4 +49,4 @@ export {
49
49
  EXIT_CODES,
50
50
  BaseCommand
51
51
  };
52
- //# sourceMappingURL=chunk-MMTMXLI4.js.map
52
+ //# sourceMappingURL=chunk-7K7SA4TZ.js.map