@claude-collective/cli 0.29.4 → 0.30.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 (175) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/config/skills-matrix.yaml +1 -1
  3. package/config/stacks.yaml +1 -1
  4. package/dist/{chunk-XPMEGGJK.js → chunk-34E7MWJI.js} +13 -38
  5. package/dist/chunk-34E7MWJI.js.map +1 -0
  6. package/dist/{chunk-IFODQTCX.js → chunk-52XVP55K.js} +6 -3
  7. package/dist/chunk-52XVP55K.js.map +1 -0
  8. package/dist/{chunk-N73GQTCK.js → chunk-5P6RUVA7.js} +6 -6
  9. package/dist/{chunk-ZX5DM4D5.js → chunk-AGNT3FUE.js} +3 -3
  10. package/dist/{chunk-A4T4YSV4.js → chunk-AGQRRJSY.js} +2 -2
  11. package/dist/{chunk-6F3ZKDVE.js → chunk-AXND7NCM.js} +3 -3
  12. package/dist/{chunk-EP6J44I4.js → chunk-DH6F7EOJ.js} +5 -5
  13. package/dist/{chunk-AG5YGYJT.js → chunk-DTFEFLUU.js} +2 -2
  14. package/dist/chunk-EOJTMX7T.js +183 -0
  15. package/dist/chunk-EOJTMX7T.js.map +1 -0
  16. package/dist/{chunk-AJFSCLJ7.js → chunk-F23LEXMC.js} +2 -2
  17. package/dist/{chunk-G5WXKKQM.js → chunk-FFZSN5C5.js} +5 -5
  18. package/dist/chunk-FFZSN5C5.js.map +1 -0
  19. package/dist/{chunk-FY5D4KIC.js → chunk-H2NM6BDH.js} +2 -2
  20. package/dist/{chunk-56ERY7H7.js → chunk-HMZPUOWU.js} +4 -4
  21. package/dist/{chunk-RI5QEK5W.js → chunk-I6YQDA2J.js} +2 -2
  22. package/dist/{chunk-MQAYAISQ.js → chunk-JWIH7YQE.js} +2 -2
  23. package/dist/{chunk-VTUPUKFD.js → chunk-KFL72CWK.js} +2 -2
  24. package/dist/{chunk-OA5RCL2L.js → chunk-LY5HM34M.js} +2 -2
  25. package/dist/{chunk-XZKVOPCR.js → chunk-MYLRA7NI.js} +4 -4
  26. package/dist/{chunk-EUPMWSM3.js → chunk-QR2ONHDW.js} +5 -5
  27. package/dist/{chunk-SSHG7MEE.js → chunk-QUL7R35E.js} +307 -504
  28. package/dist/chunk-QUL7R35E.js.map +1 -0
  29. package/dist/{chunk-7UKQZSWT.js → chunk-RFW2RIM7.js} +2 -2
  30. package/dist/{chunk-PNXFJPXF.js → chunk-URUSBWWI.js} +2 -2
  31. package/dist/{chunk-GVVEPVR7.js → chunk-VHVRPLDY.js} +4 -4
  32. package/dist/{chunk-IRG52AN5.js → chunk-VIBOSHRL.js} +2 -2
  33. package/dist/{chunk-IQUBOWWU.js → chunk-WWLEF4MQ.js} +3 -3
  34. package/dist/{chunk-WLQUQXWO.js → chunk-WXW6SQ5K.js} +3 -3
  35. package/dist/{chunk-DUIYVKFK.js → chunk-X5AD7WWC.js} +12 -12
  36. package/dist/commands/build/marketplace.js +1 -1
  37. package/dist/commands/build/plugins.js +3 -3
  38. package/dist/commands/build/stack.js +3 -3
  39. package/dist/commands/compile.js +21 -70
  40. package/dist/commands/compile.js.map +1 -1
  41. package/dist/commands/config/get.js +2 -2
  42. package/dist/commands/config/index.js +3 -3
  43. package/dist/commands/config/path.js +2 -2
  44. package/dist/commands/config/set-project.js +2 -2
  45. package/dist/commands/config/show.js +3 -3
  46. package/dist/commands/config/unset-project.js +2 -2
  47. package/dist/commands/diff.js +2 -2
  48. package/dist/commands/doctor.js +2 -2
  49. package/dist/commands/edit.js +40 -71
  50. package/dist/commands/edit.js.map +1 -1
  51. package/dist/commands/eject.js +2 -2
  52. package/dist/commands/import/skill.js +2 -2
  53. package/dist/commands/info.js +2 -2
  54. package/dist/commands/init.js +79 -109
  55. package/dist/commands/init.js.map +1 -1
  56. package/dist/commands/list.js +2 -2
  57. package/dist/commands/new/agent.js +5 -3
  58. package/dist/commands/new/agent.js.map +1 -1
  59. package/dist/commands/new/skill.js +2 -2
  60. package/dist/commands/outdated.js +2 -2
  61. package/dist/commands/search.js +4 -4
  62. package/dist/commands/uninstall.js +41 -29
  63. package/dist/commands/uninstall.js.map +1 -1
  64. package/dist/commands/update.js +4 -6
  65. package/dist/commands/update.js.map +1 -1
  66. package/dist/commands/validate.js +2 -2
  67. package/dist/commands/version/bump.js +2 -2
  68. package/dist/commands/version/index.js +2 -2
  69. package/dist/commands/version/set.js +2 -2
  70. package/dist/commands/version/show.js +2 -2
  71. package/dist/components/skill-search/skill-search.js +3 -3
  72. package/dist/components/wizard/category-grid.js +2 -2
  73. package/dist/components/wizard/category-grid.test.js +2 -2
  74. package/dist/components/wizard/domain-selection.js +4 -4
  75. package/dist/components/wizard/help-modal.js +2 -2
  76. package/dist/components/wizard/menu-item.js +2 -2
  77. package/dist/components/wizard/search-modal.js +2 -2
  78. package/dist/components/wizard/search-modal.test.js +2 -2
  79. package/dist/components/wizard/section-progress.js +2 -2
  80. package/dist/components/wizard/section-progress.test.js +2 -2
  81. package/dist/components/wizard/source-grid.js +3 -3
  82. package/dist/components/wizard/source-grid.test.js +3 -3
  83. package/dist/components/wizard/stack-selection.js +6 -6
  84. package/dist/components/wizard/step-approach.js +6 -6
  85. package/dist/components/wizard/step-approach.test.js +6 -6
  86. package/dist/components/wizard/step-build.js +5 -5
  87. package/dist/components/wizard/step-build.test.js +5 -5
  88. package/dist/components/wizard/step-confirm.js +2 -2
  89. package/dist/components/wizard/step-confirm.test.js +4 -4
  90. package/dist/components/wizard/step-refine.js +2 -2
  91. package/dist/components/wizard/step-refine.test.js +2 -2
  92. package/dist/components/wizard/step-settings.js +4 -4
  93. package/dist/components/wizard/step-settings.test.js +8 -8
  94. package/dist/components/wizard/step-settings.test.js.map +1 -1
  95. package/dist/components/wizard/step-sources.js +7 -7
  96. package/dist/components/wizard/step-sources.test.js +7 -7
  97. package/dist/components/wizard/step-stack.js +8 -8
  98. package/dist/components/wizard/step-stack.test.js +8 -8
  99. package/dist/components/wizard/view-title.js +2 -2
  100. package/dist/components/wizard/wizard-layout.js +6 -6
  101. package/dist/components/wizard/wizard-tabs.js +2 -2
  102. package/dist/components/wizard/wizard-tabs.test.js +2 -2
  103. package/dist/components/wizard/wizard.js +21 -21
  104. package/dist/config/skills-matrix.yaml +1 -1
  105. package/dist/config/stacks.yaml +1 -1
  106. package/dist/hooks/init.js +2 -2
  107. package/dist/{source-manager-TV2YGPAN.js → source-manager-S5XTC6RW.js} +3 -3
  108. package/dist/src/agents/developer/api-developer/agent.yaml +1 -1
  109. package/dist/src/agents/developer/cli-developer/agent.yaml +1 -1
  110. package/dist/src/agents/developer/web-architecture/agent.yaml +1 -1
  111. package/dist/src/agents/developer/web-developer/agent.yaml +1 -1
  112. package/dist/src/agents/meta/agent-summoner/agent.yaml +1 -1
  113. package/dist/src/agents/meta/documentor/agent.yaml +1 -1
  114. package/dist/src/agents/meta/skill-summoner/agent.yaml +1 -1
  115. package/dist/src/agents/meta/skill-summoner/output-format.md +1 -1
  116. package/dist/src/agents/migration/cli-migrator/agent.yaml +1 -1
  117. package/dist/src/agents/pattern/pattern-scout/agent.yaml +1 -1
  118. package/dist/src/agents/pattern/web-pattern-critique/agent.yaml +1 -1
  119. package/dist/src/agents/planning/web-pm/agent.yaml +1 -1
  120. package/dist/src/agents/researcher/api-researcher/agent.yaml +1 -1
  121. package/dist/src/agents/researcher/web-researcher/agent.yaml +1 -1
  122. package/dist/src/agents/reviewer/api-reviewer/agent.yaml +1 -1
  123. package/dist/src/agents/reviewer/cli-reviewer/agent.yaml +1 -1
  124. package/dist/src/agents/reviewer/web-reviewer/agent.yaml +1 -1
  125. package/dist/src/agents/tester/cli-tester/agent.yaml +1 -1
  126. package/dist/src/agents/tester/web-tester/agent.yaml +1 -1
  127. package/dist/stores/wizard-store.js +3 -3
  128. package/dist/stores/wizard-store.test.js +3 -3
  129. package/package.json +1 -1
  130. package/src/agents/developer/api-developer/agent.yaml +1 -1
  131. package/src/agents/developer/cli-developer/agent.yaml +1 -1
  132. package/src/agents/developer/web-architecture/agent.yaml +1 -1
  133. package/src/agents/developer/web-developer/agent.yaml +1 -1
  134. package/src/agents/meta/agent-summoner/agent.yaml +1 -1
  135. package/src/agents/meta/documentor/agent.yaml +1 -1
  136. package/src/agents/meta/skill-summoner/agent.yaml +1 -1
  137. package/src/agents/meta/skill-summoner/output-format.md +1 -1
  138. package/src/agents/migration/cli-migrator/agent.yaml +1 -1
  139. package/src/agents/pattern/pattern-scout/agent.yaml +1 -1
  140. package/src/agents/pattern/web-pattern-critique/agent.yaml +1 -1
  141. package/src/agents/planning/web-pm/agent.yaml +1 -1
  142. package/src/agents/researcher/api-researcher/agent.yaml +1 -1
  143. package/src/agents/researcher/web-researcher/agent.yaml +1 -1
  144. package/src/agents/reviewer/api-reviewer/agent.yaml +1 -1
  145. package/src/agents/reviewer/cli-reviewer/agent.yaml +1 -1
  146. package/src/agents/reviewer/web-reviewer/agent.yaml +1 -1
  147. package/src/agents/tester/cli-tester/agent.yaml +1 -1
  148. package/src/agents/tester/web-tester/agent.yaml +1 -1
  149. package/dist/chunk-G5WXKKQM.js.map +0 -1
  150. package/dist/chunk-IFODQTCX.js.map +0 -1
  151. package/dist/chunk-SSHG7MEE.js.map +0 -1
  152. package/dist/chunk-XPMEGGJK.js.map +0 -1
  153. /package/dist/{chunk-N73GQTCK.js.map → chunk-5P6RUVA7.js.map} +0 -0
  154. /package/dist/{chunk-ZX5DM4D5.js.map → chunk-AGNT3FUE.js.map} +0 -0
  155. /package/dist/{chunk-A4T4YSV4.js.map → chunk-AGQRRJSY.js.map} +0 -0
  156. /package/dist/{chunk-6F3ZKDVE.js.map → chunk-AXND7NCM.js.map} +0 -0
  157. /package/dist/{chunk-EP6J44I4.js.map → chunk-DH6F7EOJ.js.map} +0 -0
  158. /package/dist/{chunk-AG5YGYJT.js.map → chunk-DTFEFLUU.js.map} +0 -0
  159. /package/dist/{chunk-AJFSCLJ7.js.map → chunk-F23LEXMC.js.map} +0 -0
  160. /package/dist/{chunk-FY5D4KIC.js.map → chunk-H2NM6BDH.js.map} +0 -0
  161. /package/dist/{chunk-56ERY7H7.js.map → chunk-HMZPUOWU.js.map} +0 -0
  162. /package/dist/{chunk-RI5QEK5W.js.map → chunk-I6YQDA2J.js.map} +0 -0
  163. /package/dist/{chunk-MQAYAISQ.js.map → chunk-JWIH7YQE.js.map} +0 -0
  164. /package/dist/{chunk-VTUPUKFD.js.map → chunk-KFL72CWK.js.map} +0 -0
  165. /package/dist/{chunk-OA5RCL2L.js.map → chunk-LY5HM34M.js.map} +0 -0
  166. /package/dist/{chunk-XZKVOPCR.js.map → chunk-MYLRA7NI.js.map} +0 -0
  167. /package/dist/{chunk-EUPMWSM3.js.map → chunk-QR2ONHDW.js.map} +0 -0
  168. /package/dist/{chunk-7UKQZSWT.js.map → chunk-RFW2RIM7.js.map} +0 -0
  169. /package/dist/{chunk-PNXFJPXF.js.map → chunk-URUSBWWI.js.map} +0 -0
  170. /package/dist/{chunk-GVVEPVR7.js.map → chunk-VHVRPLDY.js.map} +0 -0
  171. /package/dist/{chunk-IRG52AN5.js.map → chunk-VIBOSHRL.js.map} +0 -0
  172. /package/dist/{chunk-IQUBOWWU.js.map → chunk-WWLEF4MQ.js.map} +0 -0
  173. /package/dist/{chunk-WLQUQXWO.js.map → chunk-WXW6SQ5K.js.map} +0 -0
  174. /package/dist/{chunk-DUIYVKFK.js.map → chunk-X5AD7WWC.js.map} +0 -0
  175. /package/dist/{source-manager-TV2YGPAN.js.map → source-manager-S5XTC6RW.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -5,6 +5,41 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.30.0] - 2026-02-16
9
+
10
+ ### Added
11
+
12
+ - **Settings.json-based plugin discovery** — New plugin discovery system that reads `.claude/settings.json` to find enabled plugins and resolves their install paths from the global plugin registry (`~/.claude/plugins/installed_plugins.json`). Replaces project-local `.claude/plugins/` directory scanning.
13
+ - **plugin-settings.ts module** — Core module providing `getEnabledPluginKeys`, `resolvePluginInstallPaths`, and `getVerifiedPluginInstallPaths` for settings.json-based plugin resolution with Zod validation and size limits.
14
+ - **plugin-discovery.ts module** — Provides `discoverAllPluginSkills`, `hasIndividualPlugins`, and `listPluginNames` for discovering skills from enabled plugins via the global cache.
15
+ - **Comprehensive test coverage** — 37 new tests covering all plugin discovery scenarios, edge cases, and error handling.
16
+
17
+ ### Changed
18
+
19
+ - **Plugin discovery mechanism** — All commands and library code migrated from collective plugin mode to individual plugin discovery via settings.json.
20
+ - `compile`: Uses `discoverAllPluginSkills` instead of local directory scan
21
+ - `uninstall`: Supports multiple individual plugins with updated messaging
22
+ - `multi-source-loader`: Uses settings.json-based discovery for skill source tagging
23
+ - `plugin-info`: Uses `discoverAllPluginSkills` for skill counting
24
+ - `local-installer`: Added `installPluginConfig` for plugin-only setup
25
+ - **Plugin reference formats clarified** — `@` format (`plugin-name@marketplace`) for installation/registry, `:` format (`skill-id:skill-id`) for runtime skill invocation.
26
+ - **Resolution priority** — Project-scoped plugin installations take precedence over user-scoped installations.
27
+
28
+ ### Removed
29
+
30
+ - **Collective plugin mode** — Removed `getCollectivePluginDir`, `collectPluginSkillIds`, and related collective plugin infrastructure. All plugin discovery now uses individual plugins via settings.json.
31
+ - **DEFAULT_PLUGIN_NAME constant** — Removed from uninstall command as it's no longer needed for individual plugin management.
32
+
33
+ ### Fixed
34
+
35
+ - **Plugin.json path verification** — Fixed verification to check `.claude-plugin/plugin.json` subdirectory instead of root directory.
36
+
37
+ ## [0.29.5] - 2026-02-15
38
+
39
+ ### Fixed
40
+
41
+ - **Local yaml-language-server schema paths** — All 22 YAML/MD files with `$schema` comments pointed to relative local paths (e.g. `../../../schemas/agent.schema.json`) which only resolve inside this repo. Replaced with `raw.githubusercontent.com` URLs so schemas resolve in any consumer project. Added `agent`, `skillsMatrix`, and `stacks` entries to `SCHEMA_PATHS` constant.
42
+
8
43
  ## [0.29.4] - 2026-02-15
9
44
 
10
45
  ### Fixed
@@ -1,4 +1,4 @@
1
- # yaml-language-server: $schema=../src/schemas/skills-matrix.schema.json
1
+ # yaml-language-server: $schema=https://raw.githubusercontent.com/claude-collective/cli/main/src/schemas/skills-matrix.schema.json
2
2
  # =============================================================================
3
3
  # skills-matrix.yaml
4
4
  # Full skills matrix for CLI data-driven architecture
@@ -1,4 +1,4 @@
1
- # yaml-language-server: $schema=../src/schemas/stacks.schema.json
1
+ # yaml-language-server: $schema=https://raw.githubusercontent.com/claude-collective/cli/main/src/schemas/stacks.schema.json
2
2
  # Stack definitions - agent groupings with technology mappings for different workflows
3
3
 
4
4
  stacks:
@@ -5,13 +5,13 @@ import {
5
5
  computeStringHash,
6
6
  createLiquidEngine,
7
7
  determinePluginVersion,
8
+ discoverAllPluginSkills,
8
9
  extractFrontmatter,
9
10
  fetchFromSource,
10
11
  generateAgentPluginManifest,
11
12
  getPluginAgentsDir,
12
13
  getPluginManifestPath,
13
14
  loadAllAgents,
14
- loadPluginSkills,
15
15
  loadProjectAgents,
16
16
  loadProjectConfig,
17
17
  resolveAgents,
@@ -19,18 +19,16 @@ import {
19
19
  typedKeys,
20
20
  writeContentHash,
21
21
  writePluginManifest
22
- } from "./chunk-SSHG7MEE.js";
22
+ } from "./chunk-QUL7R35E.js";
23
23
  import {
24
24
  agentFrontmatterValidationSchema,
25
25
  copy,
26
26
  directoryExists,
27
27
  ensureDir,
28
- fileExists,
29
28
  formatZodErrors,
30
29
  getErrorMessage,
31
30
  glob,
32
31
  log,
33
- projectConfigLoaderSchema,
34
32
  readFile,
35
33
  verbose,
36
34
  warn,
@@ -39,9 +37,8 @@ import {
39
37
  import {
40
38
  CLAUDE_DIR,
41
39
  DIRS,
42
- PROJECT_ROOT,
43
- STANDARD_FILES
44
- } from "./chunk-IFODQTCX.js";
40
+ PROJECT_ROOT
41
+ } from "./chunk-52XVP55K.js";
45
42
  import {
46
43
  init_esm_shims
47
44
  } from "./chunk-AWKZ5BDL.js";
@@ -106,36 +103,11 @@ async function fetchAgentDefinitionsFromRemote(source, options = {}) {
106
103
  // src/cli/lib/agents/agent-recompiler.ts
107
104
  init_esm_shims();
108
105
  import path2 from "path";
109
- import { parse as parseYaml } from "yaml";
110
106
  async function getExistingAgentNames(pluginDir) {
111
107
  const agentsDir = getPluginAgentsDir(pluginDir);
112
108
  const files = await glob("*.md", agentsDir);
113
109
  return files.map((f) => path2.basename(f, ".md"));
114
110
  }
115
- async function loadConfigWithFallback(pluginDir) {
116
- const legacyConfigPath = path2.join(pluginDir, STANDARD_FILES.CONFIG_YAML);
117
- if (await fileExists(legacyConfigPath)) {
118
- try {
119
- const content = await readFile(legacyConfigPath);
120
- const parsed = parseYaml(content);
121
- const result = projectConfigLoaderSchema.safeParse(parsed);
122
- if (result.success) {
123
- verbose(`Loaded config.yaml from ${legacyConfigPath}`);
124
- return {
125
- // Loader schema validates field types but allows partial configs;
126
- // required field validation happens in validateProjectConfig()
127
- config: result.data,
128
- configPath: legacyConfigPath
129
- };
130
- } else {
131
- verbose(`Invalid config.yaml at ${legacyConfigPath}: ${result.error.message}`);
132
- }
133
- } catch (error) {
134
- verbose(`Failed to parse config.yaml: ${error}`);
135
- }
136
- }
137
- return loadProjectConfig(pluginDir);
138
- }
139
111
  async function resolveAgentNames(params) {
140
112
  const { specifiedAgents, projectConfig, allAgents, outputDir, pluginDir } = params;
141
113
  if (specifiedAgents) {
@@ -192,10 +164,8 @@ async function recompileAgents(options) {
192
164
  failed: [],
193
165
  warnings: []
194
166
  };
195
- let loadedConfig = await loadConfigWithFallback(pluginDir);
196
- if (!loadedConfig && projectDir) {
197
- loadedConfig = await loadConfigWithFallback(projectDir);
198
- }
167
+ const configDir = projectDir ?? pluginDir;
168
+ const loadedConfig = await loadProjectConfig(configDir);
199
169
  const projectConfig = loadedConfig?.config ?? null;
200
170
  const builtinAgents = await loadAllAgents(sourcePath);
201
171
  const projectAgents = projectDir ? await loadProjectAgents(projectDir) : {};
@@ -215,7 +185,12 @@ async function recompileAgents(options) {
215
185
  return result;
216
186
  }
217
187
  verbose(`Recompiling ${agentNames.length} agents in ${outputDir ?? pluginDir}`);
218
- const pluginSkills = providedSkills ?? await loadPluginSkills(pluginDir);
188
+ let pluginSkills;
189
+ if (providedSkills) {
190
+ pluginSkills = providedSkills;
191
+ } else {
192
+ pluginSkills = await discoverAllPluginSkills(projectDir ?? pluginDir);
193
+ }
219
194
  const { compileConfig, warnings } = buildCompileConfig({
220
195
  agentNames,
221
196
  allAgents,
@@ -329,4 +304,4 @@ export {
329
304
  compileAllAgentPlugins,
330
305
  printAgentCompilationSummary
331
306
  };
332
- //# sourceMappingURL=chunk-XPMEGGJK.js.map
307
+ //# sourceMappingURL=chunk-34E7MWJI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/lib/agents/agent-fetcher.ts","../src/cli/lib/agents/agent-recompiler.ts","../src/cli/lib/agents/agent-plugin-compiler.ts","../src/cli/lib/agents/index.ts"],"sourcesContent":["import path from \"path\";\nimport { directoryExists } from \"../../utils/fs\";\nimport { verbose } from \"../../utils/logger\";\nimport { PROJECT_ROOT, DIRS, CLAUDE_DIR } from \"../../consts\";\nimport { fetchFromSource, type FetchOptions } from \"../loading\";\nimport type { AgentSourcePaths } from \"../../types\";\n\nexport type AgentDefinitionOptions = FetchOptions & {\n projectDir?: string;\n};\n\nexport async function getAgentDefinitions(\n remoteSource?: string,\n options: AgentDefinitionOptions = {},\n): Promise<AgentSourcePaths> {\n if (remoteSource) {\n return fetchAgentDefinitionsFromRemote(remoteSource, options);\n }\n return getLocalAgentDefinitions(options);\n}\n\nexport async function getLocalAgentDefinitions(\n options: AgentDefinitionOptions = {},\n): Promise<AgentSourcePaths> {\n const agentsDir = path.join(PROJECT_ROOT, DIRS.agents);\n let templatesDir = path.join(PROJECT_ROOT, DIRS.templates);\n\n if (!(await directoryExists(agentsDir))) {\n throw new Error(\n `Agent partials not found at '${agentsDir}'. Ensure the CLI is properly installed.`,\n );\n }\n\n if (options.projectDir) {\n const localTemplatesDir = path.join(options.projectDir, CLAUDE_DIR, \"templates\");\n if (await directoryExists(localTemplatesDir)) {\n verbose(`Using local templates from: ${localTemplatesDir}`);\n templatesDir = localTemplatesDir;\n }\n }\n\n if (!(await directoryExists(templatesDir))) {\n verbose(`Templates directory not found: ${templatesDir}`);\n }\n\n verbose(`Agent partials loaded from CLI: ${agentsDir}`);\n verbose(`Templates directory: ${templatesDir}`);\n\n return {\n agentsDir,\n templatesDir,\n sourcePath: PROJECT_ROOT,\n };\n}\n\nexport async function fetchAgentDefinitionsFromRemote(\n source: string,\n options: FetchOptions & { agentsDir?: string } = {},\n): Promise<AgentSourcePaths> {\n verbose(`Fetching agent partials from remote: ${source}`);\n\n const result = await fetchFromSource(source, {\n forceRefresh: options.forceRefresh,\n subdir: \"\",\n });\n\n const agentsDir = path.join(result.path, options.agentsDir ?? DIRS.agents);\n const templatesDir = path.join(agentsDir, \"_templates\");\n\n if (!(await directoryExists(agentsDir))) {\n throw new Error(`Agent partials not found at '${agentsDir}'`);\n }\n\n if (!(await directoryExists(templatesDir))) {\n verbose(`Templates directory not found: ${templatesDir}`);\n }\n\n verbose(`Agent partials fetched from: ${result.path}`);\n\n return {\n agentsDir,\n templatesDir,\n sourcePath: result.path,\n };\n}\n","import type { Liquid } from \"liquidjs\";\nimport path from \"path\";\n\nimport { getErrorMessage } from \"../../utils/errors\";\nimport type {\n AgentConfig,\n AgentDefinition,\n AgentName,\n CompileAgentConfig,\n CompileConfig,\n ProjectConfig,\n SkillDefinition,\n SkillId,\n} from \"../../types\";\nimport { glob, writeFile, ensureDir } from \"../../utils/fs\";\nimport { verbose } from \"../../utils/logger\";\nimport { typedEntries, typedKeys } from \"../../utils/typed-object\";\nimport { createLiquidEngine } from \"../compiler\";\nimport { loadProjectConfig } from \"../configuration\";\nimport { loadAllAgents, loadProjectAgents } from \"../loading\";\nimport { getPluginAgentsDir } from \"../plugins\";\nimport { discoverAllPluginSkills } from \"../plugins/plugin-discovery\";\nimport { resolveAgents, buildSkillRefsFromConfig } from \"../resolver\";\nimport { compileAgentForPlugin } from \"../stacks\";\n\nexport type RecompileAgentsOptions = {\n pluginDir: string;\n sourcePath: string;\n agents?: AgentName[];\n skills?: Partial<Record<SkillId, SkillDefinition>>;\n projectDir?: string;\n outputDir?: string;\n};\n\nexport type RecompileAgentsResult = {\n compiled: AgentName[];\n failed: AgentName[];\n warnings: string[];\n};\n\nasync function getExistingAgentNames(pluginDir: string): Promise<AgentName[]> {\n const agentsDir = getPluginAgentsDir(pluginDir);\n const files = await glob(\"*.md\", agentsDir);\n // Boundary cast: directory names from filesystem are agent names by convention\n return files.map((f) => path.basename(f, \".md\") as AgentName);\n}\n\ntype ResolveAgentNamesParams = {\n specifiedAgents?: AgentName[];\n projectConfig: ProjectConfig | null;\n allAgents: Record<AgentName, AgentDefinition>;\n outputDir?: string;\n pluginDir: string;\n};\n\nasync function resolveAgentNames(params: ResolveAgentNamesParams): Promise<AgentName[]> {\n const { specifiedAgents, projectConfig, allAgents, outputDir, pluginDir } = params;\n\n if (specifiedAgents) {\n return specifiedAgents;\n }\n\n if (projectConfig?.agents) {\n verbose(`Using agents from config.yaml: ${projectConfig.agents.join(\", \")}`);\n return projectConfig.agents;\n }\n\n if (outputDir) {\n const names = typedKeys<AgentName>(allAgents);\n verbose(`Using all available agents from source: ${names.join(\", \")}`);\n return names;\n }\n\n return getExistingAgentNames(pluginDir);\n}\n\ntype BuildCompileConfigParams = {\n agentNames: AgentName[];\n allAgents: Record<AgentName, AgentDefinition>;\n projectConfig: ProjectConfig | null;\n pluginDir: string;\n};\n\ntype BuildCompileConfigResult = {\n compileConfig: CompileConfig;\n warnings: string[];\n};\n\nfunction buildCompileConfig(params: BuildCompileConfigParams): BuildCompileConfigResult {\n const { agentNames, allAgents, projectConfig, pluginDir } = params;\n const warnings: string[] = [];\n\n // Store initialization: accumulator filled below for each agent in agentNames\n const compileAgents = {} as Record<AgentName, CompileAgentConfig>;\n for (const agentName of agentNames) {\n if (allAgents[agentName]) {\n const agentStack = projectConfig?.stack?.[agentName];\n compileAgents[agentName] = agentStack ? { skills: buildSkillRefsFromConfig(agentStack) } : {};\n } else {\n warnings.push(`Agent \"${agentName}\" not found in source definitions`);\n }\n }\n\n const compileConfig: CompileConfig = {\n name: projectConfig?.name || path.basename(pluginDir),\n description: projectConfig?.description || \"Recompiled plugin\",\n agents: compileAgents,\n };\n\n return { compileConfig, warnings };\n}\n\ntype CompileAndWriteParams = {\n resolvedAgents: Record<AgentName, AgentConfig>;\n agentsDir: string;\n sourcePath: string;\n engine: Liquid;\n installMode: ProjectConfig[\"installMode\"];\n};\n\nasync function compileAndWriteAgents(\n params: CompileAndWriteParams,\n result: RecompileAgentsResult,\n): Promise<void> {\n const { resolvedAgents, agentsDir, sourcePath, engine, installMode } = params;\n\n for (const [agentName, agent] of typedEntries<AgentName, AgentConfig>(resolvedAgents)) {\n try {\n const output = await compileAgentForPlugin(agentName, agent, sourcePath, engine, installMode);\n await writeFile(path.join(agentsDir, `${agentName}.md`), output);\n result.compiled.push(agentName);\n verbose(` Recompiled: ${agentName}`);\n } catch (error) {\n result.failed.push(agentName);\n result.warnings.push(`Failed to compile ${agentName}: ${getErrorMessage(error)}`);\n }\n }\n}\n\nexport async function recompileAgents(\n options: RecompileAgentsOptions,\n): Promise<RecompileAgentsResult> {\n const { pluginDir, sourcePath, skills: providedSkills, projectDir, outputDir } = options;\n\n const result: RecompileAgentsResult = {\n compiled: [],\n failed: [],\n warnings: [],\n };\n\n const configDir = projectDir ?? pluginDir;\n const loadedConfig = await loadProjectConfig(configDir);\n const projectConfig = loadedConfig?.config ?? null;\n\n const builtinAgents = await loadAllAgents(sourcePath);\n const projectAgents = projectDir ? await loadProjectAgents(projectDir) : {};\n\n // Boundary cast: loadAllAgents returns Record<string, AgentDefinition>, agent dirs are AgentName by convention\n // Priority: project agents > built-in agents\n const allAgents = {\n ...builtinAgents,\n ...projectAgents,\n } as Record<AgentName, AgentDefinition>;\n\n const agentNames = await resolveAgentNames({\n specifiedAgents: options.agents,\n projectConfig,\n allAgents,\n outputDir,\n pluginDir,\n });\n\n if (agentNames.length === 0) {\n result.warnings.push(\"No agents found to recompile\");\n return result;\n }\n\n verbose(`Recompiling ${agentNames.length} agents in ${outputDir ?? pluginDir}`);\n\n // When skills are not provided, discover from all plugin directories.\n let pluginSkills: Partial<Record<SkillId, SkillDefinition>>;\n if (providedSkills) {\n pluginSkills = providedSkills;\n } else {\n pluginSkills = await discoverAllPluginSkills(projectDir ?? pluginDir);\n }\n\n const { compileConfig, warnings } = buildCompileConfig({\n agentNames,\n allAgents,\n projectConfig,\n pluginDir,\n });\n result.warnings.push(...warnings);\n\n const engine = await createLiquidEngine(projectDir);\n const resolvedAgents = await resolveAgents(allAgents, pluginSkills, compileConfig, sourcePath);\n\n const agentsDir = outputDir ?? getPluginAgentsDir(pluginDir);\n await ensureDir(agentsDir);\n\n await compileAndWriteAgents(\n {\n resolvedAgents,\n agentsDir,\n sourcePath,\n engine,\n installMode: projectConfig?.installMode,\n },\n result,\n );\n\n return result;\n}\n","import path from \"path\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { readFile, ensureDir, glob, copy } from \"../../utils/fs\";\nimport { log, verbose, warn } from \"../../utils/logger\";\nimport {\n generateAgentPluginManifest,\n writePluginManifest,\n getPluginManifestPath,\n} from \"../plugins\";\nimport { computeStringHash, determinePluginVersion, writeContentHash } from \"../versioning\";\nimport { extractFrontmatter } from \"../../utils/frontmatter\";\nimport type { PluginManifest } from \"../../types\";\nimport { agentFrontmatterValidationSchema, formatZodErrors } from \"../schemas\";\n\nexport type AgentPluginOptions = {\n agentPath: string;\n outputDir: string;\n};\n\nexport type CompiledAgentPlugin = {\n pluginPath: string;\n manifest: PluginManifest;\n agentName: string;\n};\n\nfunction parseAgentFrontmatter(\n content: string,\n filePath: string,\n): { name: string; description: string } | null {\n const raw = extractFrontmatter(content);\n if (!raw) {\n return null;\n }\n\n const result = agentFrontmatterValidationSchema.safeParse(raw);\n if (!result.success) {\n warn(`Invalid agent frontmatter in ${filePath}: ${formatZodErrors(result.error.issues)}`);\n return null;\n }\n\n return { name: result.data.name, description: result.data.description };\n}\n\nexport async function compileAgentPlugin(\n options: AgentPluginOptions,\n): Promise<CompiledAgentPlugin> {\n const { agentPath, outputDir } = options;\n const fileName = path.basename(agentPath);\n\n const content = await readFile(agentPath);\n const frontmatter = parseAgentFrontmatter(content, agentPath);\n\n if (!frontmatter) {\n throw new Error(\n `Agent '${fileName}' has invalid or missing YAML frontmatter. ` +\n `Required fields: 'name' and 'description'. File: ${agentPath}`,\n );\n }\n\n const agentName = frontmatter.name;\n\n verbose(`Compiling agent plugin: ${agentName} from ${agentPath}`);\n\n const pluginDir = path.join(outputDir, `agent-${agentName}`);\n const agentsDir = path.join(pluginDir, \"agents\");\n\n await ensureDir(pluginDir);\n await ensureDir(agentsDir);\n\n const newHash = computeStringHash(content);\n const { version, contentHash } = await determinePluginVersion(\n newHash,\n pluginDir,\n getPluginManifestPath,\n );\n\n const manifest = generateAgentPluginManifest({\n agentName,\n description: frontmatter.description,\n version,\n });\n\n await writePluginManifest(pluginDir, manifest);\n\n await writeContentHash(pluginDir, contentHash, getPluginManifestPath);\n\n verbose(` Wrote plugin.json for ${agentName} (v${version})`);\n\n await copy(agentPath, path.join(agentsDir, `${agentName}.md`));\n verbose(` Copied agent ${fileName} -> agents/${agentName}.md`);\n\n return {\n pluginPath: pluginDir,\n manifest,\n agentName,\n };\n}\n\nexport async function compileAllAgentPlugins(\n agentsDir: string,\n outputDir: string,\n): Promise<CompiledAgentPlugin[]> {\n const results: CompiledAgentPlugin[] = [];\n\n const agentMdFiles = await glob(\"*.md\", agentsDir);\n\n for (const agentFile of agentMdFiles) {\n const agentPath = path.join(agentsDir, agentFile);\n\n try {\n const result = await compileAgentPlugin({\n agentPath,\n outputDir,\n });\n results.push(result);\n log(` [OK] agent-${result.agentName}`);\n } catch (error) {\n const errorMessage = getErrorMessage(error);\n warn(`Failed to compile agent from '${agentFile}': ${errorMessage}`);\n }\n }\n\n return results;\n}\n\nexport function printAgentCompilationSummary(results: CompiledAgentPlugin[]): void {\n log(`\\nCompiled ${results.length} agent plugins:`);\n for (const result of results) {\n log(` - agent-${result.agentName} (v${result.manifest.version})`);\n }\n}\n","export {\n type AgentDefinitionOptions,\n getAgentDefinitions,\n getLocalAgentDefinitions,\n fetchAgentDefinitionsFromRemote,\n} from \"./agent-fetcher\";\n\nexport {\n type RecompileAgentsOptions,\n type RecompileAgentsResult,\n recompileAgents,\n} from \"./agent-recompiler\";\n\nexport {\n type AgentPluginOptions,\n type CompiledAgentPlugin,\n compileAgentPlugin,\n compileAllAgentPlugins,\n printAgentCompilationSummary,\n} from \"./agent-plugin-compiler\";\n"],"mappings":"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","names":["path","path","path","path"]}
@@ -57,10 +57,13 @@ var DEFAULT_VERSION = "1.0.0";
57
57
  var DEFAULT_DISPLAY_VERSION = "0.0.0";
58
58
  var SCHEMA_PKG_PREFIX = "https://raw.githubusercontent.com/claude-collective/cli/main/src/schemas";
59
59
  var SCHEMA_PATHS = {
60
+ agent: `${SCHEMA_PKG_PREFIX}/agent.schema.json`,
61
+ metadata: `${SCHEMA_PKG_PREFIX}/metadata.schema.json`,
62
+ marketplace: `${SCHEMA_PKG_PREFIX}/marketplace.schema.json`,
60
63
  projectConfig: `${SCHEMA_PKG_PREFIX}/project-config.schema.json`,
61
64
  projectSourceConfig: `${SCHEMA_PKG_PREFIX}/project-source-config.schema.json`,
62
- metadata: `${SCHEMA_PKG_PREFIX}/metadata.schema.json`,
63
- marketplace: `${SCHEMA_PKG_PREFIX}/marketplace.schema.json`
65
+ skillsMatrix: `${SCHEMA_PKG_PREFIX}/skills-matrix.schema.json`,
66
+ stacks: `${SCHEMA_PKG_PREFIX}/stacks.schema.json`
64
67
  };
65
68
  function yamlSchemaComment(schemaPath) {
66
69
  return `# yaml-language-server: $schema=${schemaPath}`;
@@ -159,4 +162,4 @@ export {
159
162
  CLI_COLORS,
160
163
  DEFAULT_PRESELECTED_SKILLS
161
164
  };
162
- //# sourceMappingURL=chunk-IFODQTCX.js.map
165
+ //# sourceMappingURL=chunk-52XVP55K.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/consts.ts"],"sourcesContent":["import path from \"path\";\nimport os from \"os\";\nimport { fileURLToPath } from \"url\";\nimport type { SkillId } from \"./types/index.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n// After tsup build, dist/ is flat, so we go up one level from dist/ to get CLI root\n// In development (src/cli/consts.ts), we go up two levels\nconst isInDist = __dirname.includes(\"/dist\");\nconst CLI_ROOT = isInDist ? path.resolve(__dirname, \"..\") : path.resolve(__dirname, \"../..\");\nexport const PROJECT_ROOT = CLI_ROOT;\n\nexport const CLAUDE_DIR = \".claude\";\nexport const CLAUDE_SRC_DIR = \".claude-src\";\nexport const PLUGINS_SUBDIR = \"plugins\";\nexport const PLUGIN_MANIFEST_DIR = \".claude-plugin\";\nexport const PLUGIN_MANIFEST_FILE = \"plugin.json\";\nexport const DEFAULT_PLUGIN_NAME = \"claude-collective\";\n\nexport const CACHE_DIR = path.join(os.homedir(), \".cache\", DEFAULT_PLUGIN_NAME);\n\nexport const SKILLS_MATRIX_PATH = \"config/skills-matrix.yaml\";\nexport const SKILLS_DIR_PATH = \"src/skills\";\nexport const LOCAL_SKILLS_PATH = \".claude/skills\";\nexport const ARCHIVED_SKILLS_DIR_NAME = \"_archived\";\n\nexport const DIRS = {\n agents: \"src/agents\",\n skills: \"src/skills\",\n stacks: \"src/stacks\",\n templates: \"src/agents/_templates\",\n commands: \"src/commands\",\n} as const;\n\nexport const STANDARD_FILES = {\n SKILL_MD: \"SKILL.md\",\n METADATA_YAML: \"metadata.yaml\",\n METADATA_JSON: \"metadata.json\",\n CONFIG_YAML: \"config.yaml\",\n SKILLS_MATRIX_YAML: \"skills-matrix.yaml\",\n AGENT_YAML: \"agent.yaml\",\n PLUGIN_JSON: \"plugin.json\",\n CLAUDE_MD: \"CLAUDE.md\",\n REFERENCE_MD: \"reference.md\",\n INTRO_MD: \"intro.md\",\n WORKFLOW_MD: \"workflow.md\",\n EXAMPLES_MD: \"examples.md\",\n OUTPUT_FORMAT_MD: \"output-format.md\",\n CRITICAL_REQUIREMENTS_MD: \"critical-requirements.md\",\n CRITICAL_REMINDERS_MD: \"critical-reminders.md\",\n} as const;\n\nexport const STANDARD_DIRS = {\n EXAMPLES: \"examples\",\n SCRIPTS: \"scripts\",\n SKILLS: \"skills\",\n} as const;\n\nexport const DEFAULT_VERSION = \"1.0.0\";\n\n// \"0.0.0\" indicates no version was explicitly set\nexport const DEFAULT_DISPLAY_VERSION = \"0.0.0\";\n\n// JSON Schema URLs for yaml-language-server $schema comments.\n// Uses raw.githubusercontent.com so schemas resolve without requiring the CLI as a dependency.\nconst SCHEMA_PKG_PREFIX =\n \"https://raw.githubusercontent.com/claude-collective/cli/main/src/schemas\";\n\nexport const SCHEMA_PATHS = {\n agent: `${SCHEMA_PKG_PREFIX}/agent.schema.json`,\n metadata: `${SCHEMA_PKG_PREFIX}/metadata.schema.json`,\n marketplace: `${SCHEMA_PKG_PREFIX}/marketplace.schema.json`,\n projectConfig: `${SCHEMA_PKG_PREFIX}/project-config.schema.json`,\n projectSourceConfig: `${SCHEMA_PKG_PREFIX}/project-source-config.schema.json`,\n skillsMatrix: `${SCHEMA_PKG_PREFIX}/skills-matrix.schema.json`,\n stacks: `${SCHEMA_PKG_PREFIX}/stacks.schema.json`,\n} as const;\n\n/** Generates a yaml-language-server schema comment for the top of YAML files. */\nexport function yamlSchemaComment(schemaPath: string): string {\n return `# yaml-language-server: $schema=${schemaPath}`;\n}\n\nexport const YAML_FORMATTING = {\n INDENT: 2,\n LINE_WIDTH: 120,\n /** lineWidth: 0 disables wrapping — used for metadata files */\n LINE_WIDTH_NONE: 0,\n} as const;\n\nexport const UI_SYMBOLS = {\n CHECKBOX_CHECKED: \"[x]\",\n CHECKBOX_UNCHECKED: \"[ ]\",\n CHEVRON: \"\\u276F\",\n CHEVRON_SPACER: \" \",\n SELECTED: \"\\u2713\",\n UNSELECTED: \"\\u25CB\",\n CURRENT: \"\\u25CF\",\n SKIPPED: \"\\u2013\",\n DISCOURAGED: \"!\",\n DISABLED: \"\\u2013\",\n} as const;\n\nexport const UI_LAYOUT = {\n MAX_VISIBLE_RESULTS: 10,\n DESCRIPTION_WIDTH: 30,\n COPIED_MESSAGE_TIMEOUT_MS: 2000,\n FALLBACK_MESSAGE_TIMEOUT_MS: 3000,\n} as const;\n\nexport const GITHUB_SOURCE = {\n HTTPS_PREFIX: \"https://github.com/\",\n GITHUB_PREFIX: \"github:\",\n GH_PREFIX: \"gh:\",\n} as const;\n\nexport const DEFAULT_SKILLS_SUBDIR = \"skills\";\n\nexport const HASH_PREFIX_LENGTH = 7;\n\n/** Hex chars from SHA-256 hash used in cache directory names (64 bits of collision resistance) */\nexport const CACHE_HASH_LENGTH = 16;\n\n/** Max chars of human-readable prefix in cache directory names (for debugging) */\nexport const CACHE_READABLE_PREFIX_LENGTH = 32;\n\n// File size limits for parsing boundaries (DoS prevention)\nconst ONE_MB = 1024 * 1024;\nexport const MAX_MARKETPLACE_FILE_SIZE = 10 * ONE_MB;\nexport const MAX_PLUGIN_FILE_SIZE = ONE_MB;\nexport const MAX_CONFIG_FILE_SIZE = ONE_MB;\n\n// JSON/YAML structural complexity limits\nexport const MAX_JSON_NESTING_DEPTH = 10;\nexport const MAX_MARKETPLACE_PLUGINS = 10_000;\n\nexport const CLI_COLORS = {\n PRIMARY: \"cyan\",\n SUCCESS: \"green\",\n ERROR: \"red\",\n WARNING: \"yellow\",\n INFO: \"blue\",\n NEUTRAL: \"gray\",\n FOCUS: \"cyan\",\n UNFOCUSED: \"white\",\n} as const;\n\n// Foundational methodology skills preselected by default in the wizard\nexport const DEFAULT_PRESELECTED_SKILLS: readonly SkillId[] = [\n \"meta-methodology-anti-over-engineering\",\n \"meta-methodology-context-management\",\n \"meta-methodology-improvement-protocol\",\n \"meta-methodology-investigation-requirements\",\n \"meta-methodology-success-criteria\",\n \"meta-methodology-write-verification\",\n];\n"],"mappings":"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","names":[]}
@@ -1,20 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ViewTitle
4
- } from "./chunk-FY5D4KIC.js";
4
+ } from "./chunk-H2NM6BDH.js";
5
5
  import {
6
6
  SourceGrid
7
- } from "./chunk-ZX5DM4D5.js";
7
+ } from "./chunk-AGNT3FUE.js";
8
8
  import {
9
9
  useWizardStore
10
- } from "./chunk-IQUBOWWU.js";
10
+ } from "./chunk-WWLEF4MQ.js";
11
11
  import {
12
12
  resolveAllSources,
13
13
  searchExtraSources
14
- } from "./chunk-SSHG7MEE.js";
14
+ } from "./chunk-QUL7R35E.js";
15
15
  import {
16
16
  CLI_COLORS
17
- } from "./chunk-IFODQTCX.js";
17
+ } from "./chunk-52XVP55K.js";
18
18
  import {
19
19
  init_esm_shims
20
20
  } from "./chunk-AWKZ5BDL.js";
@@ -181,4 +181,4 @@ var StepSources = ({
181
181
  export {
182
182
  StepSources
183
183
  };
184
- //# sourceMappingURL=chunk-N73GQTCK.js.map
184
+ //# sourceMappingURL=chunk-5P6RUVA7.js.map
@@ -4,14 +4,14 @@ import {
4
4
  } from "./chunk-DIRH4PDF.js";
5
5
  import {
6
6
  SearchModal
7
- } from "./chunk-VTUPUKFD.js";
7
+ } from "./chunk-KFL72CWK.js";
8
8
  import {
9
9
  useFocusedListItem
10
10
  } from "./chunk-WPED6CL3.js";
11
11
  import {
12
12
  CLI_COLORS,
13
13
  UI_SYMBOLS
14
- } from "./chunk-IFODQTCX.js";
14
+ } from "./chunk-52XVP55K.js";
15
15
  import {
16
16
  init_esm_shims
17
17
  } from "./chunk-AWKZ5BDL.js";
@@ -231,4 +231,4 @@ var SourceGrid = ({
231
231
  export {
232
232
  SourceGrid
233
233
  };
234
- //# sourceMappingURL=chunk-ZX5DM4D5.js.map
234
+ //# sourceMappingURL=chunk-AGNT3FUE.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CLI_COLORS
4
- } from "./chunk-IFODQTCX.js";
4
+ } from "./chunk-52XVP55K.js";
5
5
  import {
6
6
  init_esm_shims
7
7
  } from "./chunk-AWKZ5BDL.js";
@@ -45,4 +45,4 @@ var SectionProgress = ({
45
45
  export {
46
46
  SectionProgress
47
47
  };
48
- //# sourceMappingURL=chunk-A4T4YSV4.js.map
48
+ //# sourceMappingURL=chunk-AGQRRJSY.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  cliTheme
4
- } from "./chunk-AJFSCLJ7.js";
4
+ } from "./chunk-F23LEXMC.js";
5
5
  import {
6
6
  useTextInput
7
7
  } from "./chunk-RXC7AF7N.js";
@@ -9,7 +9,7 @@ import {
9
9
  CLI_COLORS,
10
10
  UI_LAYOUT,
11
11
  UI_SYMBOLS
12
- } from "./chunk-IFODQTCX.js";
12
+ } from "./chunk-52XVP55K.js";
13
13
  import {
14
14
  init_esm_shims
15
15
  } from "./chunk-AWKZ5BDL.js";
@@ -343,4 +343,4 @@ var SkillSearch = ({
343
343
  export {
344
344
  SkillSearch
345
345
  };
346
- //# sourceMappingURL=chunk-6F3ZKDVE.js.map
346
+ //# sourceMappingURL=chunk-AXND7NCM.js.map
@@ -2,16 +2,16 @@
2
2
  import {
3
3
  WIZARD_STEPS,
4
4
  WizardTabs
5
- } from "./chunk-7UKQZSWT.js";
5
+ } from "./chunk-RFW2RIM7.js";
6
6
  import {
7
7
  HelpModal
8
- } from "./chunk-MQAYAISQ.js";
8
+ } from "./chunk-JWIH7YQE.js";
9
9
  import {
10
10
  useWizardStore
11
- } from "./chunk-IQUBOWWU.js";
11
+ } from "./chunk-WWLEF4MQ.js";
12
12
  import {
13
13
  CLI_COLORS
14
- } from "./chunk-IFODQTCX.js";
14
+ } from "./chunk-52XVP55K.js";
15
15
  import {
16
16
  init_esm_shims
17
17
  } from "./chunk-AWKZ5BDL.js";
@@ -139,4 +139,4 @@ var WizardLayout = ({
139
139
  export {
140
140
  WizardLayout
141
141
  };
142
- //# sourceMappingURL=chunk-EP6J44I4.js.map
142
+ //# sourceMappingURL=chunk-DH6F7EOJ.js.map
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-V2ZIH7HV.js";
5
5
  import {
6
6
  CLI_COLORS
7
- } from "./chunk-IFODQTCX.js";
7
+ } from "./chunk-52XVP55K.js";
8
8
  import {
9
9
  init_esm_shims
10
10
  } from "./chunk-AWKZ5BDL.js";
@@ -75,4 +75,4 @@ var StepConfirm = ({
75
75
  export {
76
76
  StepConfirm
77
77
  };
78
- //# sourceMappingURL=chunk-AG5YGYJT.js.map
78
+ //# sourceMappingURL=chunk-DTFEFLUU.js.map
@@ -0,0 +1,183 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ getErrorMessage,
4
+ warn
5
+ } from "./chunk-5WIHSJRO.js";
6
+ import {
7
+ init_esm_shims
8
+ } from "./chunk-AWKZ5BDL.js";
9
+
10
+ // src/cli/utils/exec.ts
11
+ init_esm_shims();
12
+ import { spawn } from "child_process";
13
+ var MAX_PLUGIN_PATH_LENGTH = 1024;
14
+ var MAX_PLUGIN_NAME_LENGTH = 256;
15
+ var MAX_MARKETPLACE_SOURCE_LENGTH = 1024;
16
+ var SAFE_NAME_PATTERN = /^[a-zA-Z0-9._@/-]+$/;
17
+ var SAFE_PLUGIN_PATH_PATTERN = /^[a-zA-Z0-9._@/:~-]+$/;
18
+ var CONTROL_CHAR_PATTERN = /[\x00-\x08\x0E-\x1F\x7F]/u;
19
+ function validatePluginPath(pluginPath) {
20
+ if (!pluginPath || pluginPath.trim().length === 0) {
21
+ throw new Error("Plugin path must not be empty.");
22
+ }
23
+ if (pluginPath.length > MAX_PLUGIN_PATH_LENGTH) {
24
+ throw new Error(
25
+ `Plugin path is too long (${pluginPath.length} characters, max ${MAX_PLUGIN_PATH_LENGTH}).`
26
+ );
27
+ }
28
+ if (CONTROL_CHAR_PATTERN.test(pluginPath)) {
29
+ throw new Error("Plugin path contains invalid control characters.");
30
+ }
31
+ if (!SAFE_PLUGIN_PATH_PATTERN.test(pluginPath)) {
32
+ throw new Error(
33
+ `Plugin path contains invalid characters: "${pluginPath}"
34
+ Plugin paths may only contain alphanumeric characters, dashes, underscores, dots, slashes, @, and colons.`
35
+ );
36
+ }
37
+ }
38
+ function validateMarketplaceSource(source) {
39
+ if (!source || source.trim().length === 0) {
40
+ throw new Error("Marketplace source must not be empty.");
41
+ }
42
+ if (source.length > MAX_MARKETPLACE_SOURCE_LENGTH) {
43
+ throw new Error(
44
+ `Marketplace source is too long (${source.length} characters, max ${MAX_MARKETPLACE_SOURCE_LENGTH}).`
45
+ );
46
+ }
47
+ if (CONTROL_CHAR_PATTERN.test(source)) {
48
+ throw new Error("Marketplace source contains invalid control characters.");
49
+ }
50
+ if (!SAFE_PLUGIN_PATH_PATTERN.test(source)) {
51
+ throw new Error(
52
+ `Marketplace source contains invalid characters: "${source}"
53
+ Source may only contain alphanumeric characters, dashes, underscores, dots, slashes, @, and colons.`
54
+ );
55
+ }
56
+ }
57
+ function validatePluginName(pluginName) {
58
+ if (!pluginName || pluginName.trim().length === 0) {
59
+ throw new Error("Plugin name must not be empty.");
60
+ }
61
+ if (pluginName.length > MAX_PLUGIN_NAME_LENGTH) {
62
+ throw new Error(
63
+ `Plugin name is too long (${pluginName.length} characters, max ${MAX_PLUGIN_NAME_LENGTH}).`
64
+ );
65
+ }
66
+ if (CONTROL_CHAR_PATTERN.test(pluginName)) {
67
+ throw new Error("Plugin name contains invalid control characters.");
68
+ }
69
+ if (!SAFE_NAME_PATTERN.test(pluginName)) {
70
+ throw new Error(
71
+ `Plugin name contains invalid characters: "${pluginName}"
72
+ Names may only contain alphanumeric characters, dashes, underscores, dots, @, and slashes.`
73
+ );
74
+ }
75
+ }
76
+ async function execCommand(command, args, options) {
77
+ return new Promise((resolve, reject) => {
78
+ const proc = spawn(command, args, {
79
+ cwd: options?.cwd,
80
+ env: { ...process.env, ...options?.env },
81
+ stdio: ["ignore", "pipe", "pipe"]
82
+ });
83
+ let stdout = "";
84
+ let stderr = "";
85
+ proc.stdout.on("data", (data) => {
86
+ stdout += data.toString();
87
+ });
88
+ proc.stderr.on("data", (data) => {
89
+ stderr += data.toString();
90
+ });
91
+ proc.on("close", (code) => {
92
+ resolve({
93
+ stdout,
94
+ stderr,
95
+ exitCode: code ?? 1
96
+ });
97
+ });
98
+ proc.on("error", (err) => {
99
+ reject(err);
100
+ });
101
+ });
102
+ }
103
+ async function claudePluginInstall(pluginPath, scope, projectDir) {
104
+ validatePluginPath(pluginPath);
105
+ const args = ["plugin", "install", pluginPath, "--scope", scope];
106
+ const result = await execCommand("claude", args, { cwd: projectDir });
107
+ if (result.exitCode !== 0) {
108
+ const errorMessage = result.stderr || result.stdout || "Unknown error";
109
+ throw new Error(`Plugin installation failed: ${errorMessage.trim()}`);
110
+ }
111
+ }
112
+ async function isClaudeCLIAvailable() {
113
+ try {
114
+ const result = await execCommand("claude", ["--version"], {});
115
+ return result.exitCode === 0;
116
+ } catch {
117
+ return false;
118
+ }
119
+ }
120
+ async function claudePluginMarketplaceList() {
121
+ try {
122
+ const result = await execCommand("claude", ["plugin", "marketplace", "list", "--json"], {});
123
+ if (result.exitCode !== 0) {
124
+ return [];
125
+ }
126
+ let parsed;
127
+ try {
128
+ parsed = JSON.parse(result.stdout);
129
+ } catch {
130
+ warn("Failed to parse marketplace list output as JSON");
131
+ return [];
132
+ }
133
+ if (!Array.isArray(parsed)) {
134
+ warn("Unexpected marketplace list format \u2014 expected an array");
135
+ return [];
136
+ }
137
+ return parsed;
138
+ } catch {
139
+ return [];
140
+ }
141
+ }
142
+ async function claudePluginMarketplaceExists(name) {
143
+ const marketplaces = await claudePluginMarketplaceList();
144
+ return marketplaces.some((m) => m.name === name);
145
+ }
146
+ async function claudePluginMarketplaceAdd(source) {
147
+ validateMarketplaceSource(source);
148
+ const args = ["plugin", "marketplace", "add", source];
149
+ let result;
150
+ try {
151
+ result = await execCommand("claude", args, {});
152
+ } catch (err) {
153
+ throw new Error(`Failed to add marketplace: ${getErrorMessage(err)}`);
154
+ }
155
+ if (result.exitCode !== 0) {
156
+ const errorMessage = result.stderr || result.stdout || "Unknown error";
157
+ if (errorMessage.includes("already installed")) {
158
+ return;
159
+ }
160
+ throw new Error(`Failed to add marketplace: ${errorMessage.trim()}`);
161
+ }
162
+ }
163
+ async function claudePluginUninstall(pluginName, scope, projectDir) {
164
+ validatePluginName(pluginName);
165
+ const args = ["plugin", "uninstall", pluginName, "--scope", scope];
166
+ const result = await execCommand("claude", args, { cwd: projectDir });
167
+ if (result.exitCode !== 0) {
168
+ const errorMessage = result.stderr || result.stdout || "Unknown error";
169
+ if (errorMessage.includes("not installed") || errorMessage.includes("not found")) {
170
+ return;
171
+ }
172
+ throw new Error(`Plugin uninstall failed: ${errorMessage.trim()}`);
173
+ }
174
+ }
175
+
176
+ export {
177
+ claudePluginInstall,
178
+ isClaudeCLIAvailable,
179
+ claudePluginMarketplaceExists,
180
+ claudePluginMarketplaceAdd,
181
+ claudePluginUninstall
182
+ };
183
+ //# sourceMappingURL=chunk-EOJTMX7T.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/utils/exec.ts"],"sourcesContent":["import { spawn } from \"child_process\";\nimport { getErrorMessage } from \"./errors\";\nimport { warn } from \"./logger\";\n\n// Argument length limits to prevent oversized CLI arguments\nconst MAX_PLUGIN_PATH_LENGTH = 1024;\nconst MAX_PLUGIN_NAME_LENGTH = 256;\nconst MAX_MARKETPLACE_SOURCE_LENGTH = 1024;\n\n// Marketplace/plugin names: alphanumeric, dashes, underscores, dots, @\nconst SAFE_NAME_PATTERN = /^[a-zA-Z0-9._@/-]+$/;\n\n// Plugin path/ref: alphanumeric, dashes, underscores, dots, slashes, @, colons (for marketplace refs like skill@marketplace)\nconst SAFE_PLUGIN_PATH_PATTERN = /^[a-zA-Z0-9._@/:~-]+$/;\n\n// eslint-disable-next-line no-control-regex\nconst CONTROL_CHAR_PATTERN = /[\\x00-\\x08\\x0E-\\x1F\\x7F]/u;\n\nfunction validatePluginPath(pluginPath: string): void {\n if (!pluginPath || pluginPath.trim().length === 0) {\n throw new Error(\"Plugin path must not be empty.\");\n }\n\n if (pluginPath.length > MAX_PLUGIN_PATH_LENGTH) {\n throw new Error(\n `Plugin path is too long (${pluginPath.length} characters, max ${MAX_PLUGIN_PATH_LENGTH}).`,\n );\n }\n\n if (CONTROL_CHAR_PATTERN.test(pluginPath)) {\n throw new Error(\"Plugin path contains invalid control characters.\");\n }\n\n if (!SAFE_PLUGIN_PATH_PATTERN.test(pluginPath)) {\n throw new Error(\n `Plugin path contains invalid characters: \"${pluginPath}\"\\n` +\n \"Plugin paths may only contain alphanumeric characters, dashes, underscores, dots, slashes, @, and colons.\",\n );\n }\n}\n\nfunction validateMarketplaceSource(source: string): void {\n if (!source || source.trim().length === 0) {\n throw new Error(\"Marketplace source must not be empty.\");\n }\n\n if (source.length > MAX_MARKETPLACE_SOURCE_LENGTH) {\n throw new Error(\n `Marketplace source is too long (${source.length} characters, max ${MAX_MARKETPLACE_SOURCE_LENGTH}).`,\n );\n }\n\n if (CONTROL_CHAR_PATTERN.test(source)) {\n throw new Error(\"Marketplace source contains invalid control characters.\");\n }\n\n if (!SAFE_PLUGIN_PATH_PATTERN.test(source)) {\n throw new Error(\n `Marketplace source contains invalid characters: \"${source}\"\\n` +\n \"Source may only contain alphanumeric characters, dashes, underscores, dots, slashes, @, and colons.\",\n );\n }\n}\n\nfunction validatePluginName(pluginName: string): void {\n if (!pluginName || pluginName.trim().length === 0) {\n throw new Error(\"Plugin name must not be empty.\");\n }\n\n if (pluginName.length > MAX_PLUGIN_NAME_LENGTH) {\n throw new Error(\n `Plugin name is too long (${pluginName.length} characters, max ${MAX_PLUGIN_NAME_LENGTH}).`,\n );\n }\n\n if (CONTROL_CHAR_PATTERN.test(pluginName)) {\n throw new Error(\"Plugin name contains invalid control characters.\");\n }\n\n if (!SAFE_NAME_PATTERN.test(pluginName)) {\n throw new Error(\n `Plugin name contains invalid characters: \"${pluginName}\"\\n` +\n \"Names may only contain alphanumeric characters, dashes, underscores, dots, @, and slashes.\",\n );\n }\n}\n\nexport type ExecResult = {\n stdout: string;\n stderr: string;\n exitCode: number;\n};\n\nexport async function execCommand(\n command: string,\n args: string[],\n options?: { cwd?: string; env?: NodeJS.ProcessEnv },\n): Promise<ExecResult> {\n return new Promise((resolve, reject) => {\n const proc = spawn(command, args, {\n cwd: options?.cwd,\n env: { ...process.env, ...options?.env },\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n let stdout = \"\";\n let stderr = \"\";\n\n proc.stdout.on(\"data\", (data) => {\n stdout += data.toString();\n });\n\n proc.stderr.on(\"data\", (data) => {\n stderr += data.toString();\n });\n\n proc.on(\"close\", (code) => {\n resolve({\n stdout,\n stderr,\n exitCode: code ?? 1,\n });\n });\n\n proc.on(\"error\", (err) => {\n reject(err);\n });\n });\n}\n\nexport async function claudePluginInstall(\n pluginPath: string,\n scope: \"project\" | \"user\",\n projectDir: string,\n): Promise<void> {\n validatePluginPath(pluginPath);\n\n const args = [\"plugin\", \"install\", pluginPath, \"--scope\", scope];\n const result = await execCommand(\"claude\", args, { cwd: projectDir });\n\n if (result.exitCode !== 0) {\n const errorMessage = result.stderr || result.stdout || \"Unknown error\";\n throw new Error(`Plugin installation failed: ${errorMessage.trim()}`);\n }\n}\n\nexport async function isClaudeCLIAvailable(): Promise<boolean> {\n try {\n const result = await execCommand(\"claude\", [\"--version\"], {});\n return result.exitCode === 0;\n } catch {\n return false;\n }\n}\n\nexport type MarketplaceInfo = {\n name: string;\n source: string;\n repo?: string;\n path?: string;\n};\n\nexport async function claudePluginMarketplaceList(): Promise<MarketplaceInfo[]> {\n try {\n const result = await execCommand(\"claude\", [\"plugin\", \"marketplace\", \"list\", \"--json\"], {});\n\n if (result.exitCode !== 0) {\n return [];\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(result.stdout);\n } catch {\n warn(\"Failed to parse marketplace list output as JSON\");\n return [];\n }\n\n if (!Array.isArray(parsed)) {\n warn(\"Unexpected marketplace list format — expected an array\");\n return [];\n }\n\n return parsed as MarketplaceInfo[];\n } catch {\n return [];\n }\n}\n\nexport async function claudePluginMarketplaceExists(name: string): Promise<boolean> {\n const marketplaces = await claudePluginMarketplaceList();\n return marketplaces.some((m) => m.name === name);\n}\n\nexport async function claudePluginMarketplaceAdd(source: string): Promise<void> {\n validateMarketplaceSource(source);\n\n const args = [\"plugin\", \"marketplace\", \"add\", source];\n let result;\n try {\n result = await execCommand(\"claude\", args, {});\n } catch (err) {\n throw new Error(`Failed to add marketplace: ${getErrorMessage(err)}`);\n }\n\n if (result.exitCode !== 0) {\n const errorMessage = result.stderr || result.stdout || \"Unknown error\";\n if (errorMessage.includes(\"already installed\")) {\n return;\n }\n throw new Error(`Failed to add marketplace: ${errorMessage.trim()}`);\n }\n}\n\nexport async function claudePluginUninstall(\n pluginName: string,\n scope: \"project\" | \"user\",\n projectDir: string,\n): Promise<void> {\n validatePluginName(pluginName);\n\n const args = [\"plugin\", \"uninstall\", pluginName, \"--scope\", scope];\n const result = await execCommand(\"claude\", args, { cwd: projectDir });\n\n if (result.exitCode !== 0) {\n const errorMessage = result.stderr || result.stdout || \"Unknown error\";\n // Ignore \"not installed\" errors - plugin may already be removed\n if (errorMessage.includes(\"not installed\") || errorMessage.includes(\"not found\")) {\n return;\n }\n throw new Error(`Plugin uninstall failed: ${errorMessage.trim()}`);\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CLI_COLORS
4
- } from "./chunk-IFODQTCX.js";
4
+ } from "./chunk-52XVP55K.js";
5
5
  import {
6
6
  init_esm_shims
7
7
  } from "./chunk-AWKZ5BDL.js";
@@ -78,4 +78,4 @@ var cliTheme = extendTheme(defaultTheme, {
78
78
  export {
79
79
  cliTheme
80
80
  };
81
- //# sourceMappingURL=chunk-AJFSCLJ7.js.map
81
+ //# sourceMappingURL=chunk-F23LEXMC.js.map