@claude-collective/cli 0.29.5 → 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.
- package/CHANGELOG.md +29 -0
- package/dist/{chunk-4DX47646.js → chunk-34E7MWJI.js} +12 -37
- package/dist/chunk-34E7MWJI.js.map +1 -0
- package/dist/{chunk-J3J2WPI2.js → chunk-5P6RUVA7.js} +3 -3
- package/dist/{chunk-73E5CQUK.js → chunk-DH6F7EOJ.js} +2 -2
- package/dist/chunk-EOJTMX7T.js +183 -0
- package/dist/chunk-EOJTMX7T.js.map +1 -0
- package/dist/{chunk-Z6UK6MI2.js → chunk-FFZSN5C5.js} +3 -3
- package/dist/chunk-FFZSN5C5.js.map +1 -0
- package/dist/{chunk-VBOBVQQW.js → chunk-HMZPUOWU.js} +4 -4
- package/dist/{chunk-HJS2FWLA.js → chunk-MYLRA7NI.js} +2 -2
- package/dist/{chunk-PRY6MLN3.js → chunk-QR2ONHDW.js} +2 -2
- package/dist/{chunk-ABK6CSWI.js → chunk-QUL7R35E.js} +306 -503
- package/dist/chunk-QUL7R35E.js.map +1 -0
- package/dist/{chunk-ZCIWRQQ4.js → chunk-URUSBWWI.js} +2 -2
- package/dist/{chunk-4JSKL5SD.js → chunk-VHVRPLDY.js} +2 -2
- package/dist/{chunk-DDNK5UNE.js → chunk-WWLEF4MQ.js} +2 -2
- package/dist/{chunk-DALU3Y3U.js → chunk-WXW6SQ5K.js} +2 -2
- package/dist/{chunk-JDQDYGGC.js → chunk-X5AD7WWC.js} +9 -9
- package/dist/commands/build/plugins.js +2 -2
- package/dist/commands/build/stack.js +2 -2
- package/dist/commands/compile.js +20 -69
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/config/get.js +1 -1
- package/dist/commands/config/index.js +2 -2
- package/dist/commands/config/path.js +1 -1
- package/dist/commands/config/set-project.js +1 -1
- package/dist/commands/config/show.js +2 -2
- package/dist/commands/config/unset-project.js +1 -1
- package/dist/commands/diff.js +1 -1
- package/dist/commands/doctor.js +1 -1
- package/dist/commands/edit.js +30 -61
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +1 -1
- package/dist/commands/import/skill.js +1 -1
- package/dist/commands/info.js +1 -1
- package/dist/commands/init.js +69 -99
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list.js +1 -1
- package/dist/commands/new/agent.js +4 -2
- package/dist/commands/new/agent.js.map +1 -1
- package/dist/commands/new/skill.js +1 -1
- package/dist/commands/outdated.js +1 -1
- package/dist/commands/search.js +1 -1
- package/dist/commands/uninstall.js +40 -28
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +3 -5
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/validate.js +1 -1
- package/dist/commands/version/bump.js +1 -1
- package/dist/commands/version/index.js +1 -1
- package/dist/commands/version/set.js +1 -1
- package/dist/commands/version/show.js +1 -1
- package/dist/components/wizard/domain-selection.js +3 -3
- package/dist/components/wizard/stack-selection.js +3 -3
- package/dist/components/wizard/step-approach.js +3 -3
- package/dist/components/wizard/step-approach.test.js +3 -3
- package/dist/components/wizard/step-build.js +2 -2
- package/dist/components/wizard/step-build.test.js +2 -2
- package/dist/components/wizard/step-confirm.test.js +2 -2
- package/dist/components/wizard/step-settings.js +2 -2
- package/dist/components/wizard/step-settings.test.js +6 -6
- package/dist/components/wizard/step-settings.test.js.map +1 -1
- package/dist/components/wizard/step-sources.js +3 -3
- package/dist/components/wizard/step-sources.test.js +3 -3
- package/dist/components/wizard/step-stack.js +5 -5
- package/dist/components/wizard/step-stack.test.js +5 -5
- package/dist/components/wizard/wizard-layout.js +3 -3
- package/dist/components/wizard/wizard.js +11 -11
- package/dist/hooks/init.js +1 -1
- package/dist/{source-manager-JUPEIBMY.js → source-manager-S5XTC6RW.js} +2 -2
- package/dist/stores/wizard-store.js +2 -2
- package/dist/stores/wizard-store.test.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-4DX47646.js.map +0 -1
- package/dist/chunk-ABK6CSWI.js.map +0 -1
- package/dist/chunk-Z6UK6MI2.js.map +0 -1
- /package/dist/{chunk-J3J2WPI2.js.map → chunk-5P6RUVA7.js.map} +0 -0
- /package/dist/{chunk-73E5CQUK.js.map → chunk-DH6F7EOJ.js.map} +0 -0
- /package/dist/{chunk-VBOBVQQW.js.map → chunk-HMZPUOWU.js.map} +0 -0
- /package/dist/{chunk-HJS2FWLA.js.map → chunk-MYLRA7NI.js.map} +0 -0
- /package/dist/{chunk-PRY6MLN3.js.map → chunk-QR2ONHDW.js.map} +0 -0
- /package/dist/{chunk-ZCIWRQQ4.js.map → chunk-URUSBWWI.js.map} +0 -0
- /package/dist/{chunk-4JSKL5SD.js.map → chunk-VHVRPLDY.js.map} +0 -0
- /package/dist/{chunk-DDNK5UNE.js.map → chunk-WWLEF4MQ.js.map} +0 -0
- /package/dist/{chunk-DALU3Y3U.js.map → chunk-WXW6SQ5K.js.map} +0 -0
- /package/dist/{chunk-JDQDYGGC.js.map → chunk-X5AD7WWC.js.map} +0 -0
- /package/dist/{source-manager-JUPEIBMY.js.map → source-manager-S5XTC6RW.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,35 @@ 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
|
+
|
|
8
37
|
## [0.29.5] - 2026-02-15
|
|
9
38
|
|
|
10
39
|
### Fixed
|
|
@@ -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-
|
|
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,8 +37,7 @@ import {
|
|
|
39
37
|
import {
|
|
40
38
|
CLAUDE_DIR,
|
|
41
39
|
DIRS,
|
|
42
|
-
PROJECT_ROOT
|
|
43
|
-
STANDARD_FILES
|
|
40
|
+
PROJECT_ROOT
|
|
44
41
|
} from "./chunk-52XVP55K.js";
|
|
45
42
|
import {
|
|
46
43
|
init_esm_shims
|
|
@@ -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
|
-
|
|
196
|
-
|
|
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
|
-
|
|
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-
|
|
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"]}
|
|
@@ -7,11 +7,11 @@ import {
|
|
|
7
7
|
} from "./chunk-AGNT3FUE.js";
|
|
8
8
|
import {
|
|
9
9
|
useWizardStore
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-WWLEF4MQ.js";
|
|
11
11
|
import {
|
|
12
12
|
resolveAllSources,
|
|
13
13
|
searchExtraSources
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-QUL7R35E.js";
|
|
15
15
|
import {
|
|
16
16
|
CLI_COLORS
|
|
17
17
|
} from "./chunk-52XVP55K.js";
|
|
@@ -181,4 +181,4 @@ var StepSources = ({
|
|
|
181
181
|
export {
|
|
182
182
|
StepSources
|
|
183
183
|
};
|
|
184
|
-
//# sourceMappingURL=chunk-
|
|
184
|
+
//# sourceMappingURL=chunk-5P6RUVA7.js.map
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "./chunk-JWIH7YQE.js";
|
|
9
9
|
import {
|
|
10
10
|
useWizardStore
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-WWLEF4MQ.js";
|
|
12
12
|
import {
|
|
13
13
|
CLI_COLORS
|
|
14
14
|
} from "./chunk-52XVP55K.js";
|
|
@@ -139,4 +139,4 @@ var WizardLayout = ({
|
|
|
139
139
|
export {
|
|
140
140
|
WizardLayout
|
|
141
141
|
};
|
|
142
|
-
//# sourceMappingURL=chunk-
|
|
142
|
+
//# sourceMappingURL=chunk-DH6F7EOJ.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":[]}
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
addSource,
|
|
17
17
|
getSourceSummary,
|
|
18
18
|
removeSource
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-QUL7R35E.js";
|
|
20
20
|
import {
|
|
21
21
|
getErrorMessage
|
|
22
22
|
} from "./chunk-5WIHSJRO.js";
|
|
@@ -220,7 +220,7 @@ var StepSettings = ({ projectDir, onClose }) => {
|
|
|
220
220
|
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
221
221
|
"Plugins: ",
|
|
222
222
|
summary?.pluginSkillCount ?? 0,
|
|
223
|
-
"
|
|
223
|
+
" from installed plugins"
|
|
224
224
|
] })
|
|
225
225
|
] }),
|
|
226
226
|
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: addModal.isOpen ? "ENTER submit ESC cancel" : "A add DEL remove ESC close" }) })
|
|
@@ -230,4 +230,4 @@ var StepSettings = ({ projectDir, onClose }) => {
|
|
|
230
230
|
export {
|
|
231
231
|
StepSettings
|
|
232
232
|
};
|
|
233
|
-
//# sourceMappingURL=chunk-
|
|
233
|
+
//# sourceMappingURL=chunk-FFZSN5C5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/components/wizard/step-settings.tsx","../src/cli/components/hooks/use-source-operations.ts"],"sourcesContent":["import React, { useState, useEffect, useCallback } from \"react\";\nimport { Box, Text, useInput } from \"ink\";\nimport { CLI_COLORS } from \"../../consts.js\";\nimport { ViewTitle } from \"./view-title.js\";\nimport { getSourceSummary, type SourceSummary } from \"../../lib/configuration/source-manager.js\";\nimport { DEFAULT_SOURCE } from \"../../lib/configuration/config.js\";\nimport { useKeyboardNavigation } from \"../hooks/use-keyboard-navigation.js\";\nimport { useModalState } from \"../hooks/use-modal-state.js\";\nimport { useSourceOperations } from \"../hooks/use-source-operations.js\";\nimport { useTextInput } from \"../hooks/use-text-input.js\";\n\nconst DEFAULT_SOURCE_NAME = \"public\";\n\nexport type StepSettingsProps = {\n projectDir: string;\n onClose: () => void;\n};\n\nexport const StepSettings: React.FC<StepSettingsProps> = ({ projectDir, onClose }) => {\n const [summary, setSummary] = useState<SourceSummary | null>(null);\n const addModal = useModalState();\n const {\n value: addSourceInput,\n setValue: setAddSourceInput,\n handleInput: handleTextInput,\n } = useTextInput(\"\");\n const [isLoading, setIsLoading] = useState(true);\n\n const loadSummary = useCallback(async () => {\n try {\n const result = await getSourceSummary(projectDir);\n setSummary(result);\n } catch {\n setSummary({\n sources: [{ name: DEFAULT_SOURCE_NAME, url: DEFAULT_SOURCE, enabled: true }],\n localSkillCount: 0,\n pluginSkillCount: 0,\n });\n }\n setIsLoading(false);\n }, [projectDir]);\n\n useEffect(() => {\n void loadSummary();\n }, [loadSummary]);\n\n const { handleAdd, handleRemove, statusMessage, clearStatus } = useSourceOperations(\n projectDir,\n loadSummary,\n );\n\n const sourceCount = summary?.sources.length ?? 0;\n\n const { focusedIndex, setFocusedIndex } = useKeyboardNavigation(\n sourceCount,\n { onEscape: onClose },\n { wrap: false, vimKeys: false, active: !addModal.isOpen },\n );\n\n useInput((input, key) => {\n if (statusMessage) {\n clearStatus();\n }\n\n if (addModal.isOpen) {\n if (key.escape) {\n addModal.close();\n setAddSourceInput(\"\");\n return;\n }\n\n if (key.return) {\n if (addSourceInput.trim()) {\n addModal.close();\n setAddSourceInput(\"\");\n void handleAdd(addSourceInput.trim());\n }\n return;\n }\n\n handleTextInput(input, key);\n return;\n }\n\n // Non-adding mode: up/down/escape handled by useKeyboardNavigation hook\n\n if (key.return) {\n // Toggle enabled/disabled is a placeholder for future enabledSources store integration\n return;\n }\n\n if (key.backspace || key.delete) {\n if (summary?.sources[focusedIndex]) {\n const source = summary.sources[focusedIndex];\n if (source.name !== DEFAULT_SOURCE_NAME) {\n void handleRemove(source.name).then((success) => {\n if (success) {\n setFocusedIndex((prev) => Math.max(0, prev - 1));\n }\n });\n }\n }\n return;\n }\n\n if (input === \"a\" || input === \"A\") {\n addModal.open(true);\n setAddSourceInput(\"\");\n }\n });\n\n if (isLoading) {\n return (\n <Box flexDirection=\"column\" paddingX={2}>\n <ViewTitle>Skill Sources</ViewTitle>\n <Text dimColor>Loading sources...</Text>\n </Box>\n );\n }\n\n return (\n <Box flexDirection=\"column\" paddingX={2}>\n <ViewTitle>Skill Sources</ViewTitle>\n <Box marginTop={1} />\n\n <Text bold>Configured marketplaces:</Text>\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={CLI_COLORS.NEUTRAL}\n paddingX={1}\n marginTop={1}\n >\n {summary?.sources.map((source, index) => {\n const isFocused = index === focusedIndex && !addModal.isOpen;\n const isDefault = source.name === DEFAULT_SOURCE_NAME;\n const checkmark = source.enabled ? \"\\u2713\" : \" \";\n const displayName = isDefault ? \"Public\" : source.name;\n const suffix = isDefault ? \" (default)\" : \"\";\n\n return (\n <Box key={source.name}>\n <Text color={isFocused ? CLI_COLORS.PRIMARY : undefined} bold={isFocused}>\n {isFocused ? \">\" : \" \"} {checkmark} {displayName}\n </Text>\n <Text dimColor>\n {\" \"}\n {source.url}\n {suffix}\n </Text>\n </Box>\n );\n })}\n </Box>\n\n <Box\n flexDirection=\"column\"\n borderStyle=\"round\"\n borderColor={addModal.isOpen ? CLI_COLORS.PRIMARY : CLI_COLORS.NEUTRAL}\n paddingX={1}\n marginTop={1}\n >\n <Text color={addModal.isOpen ? CLI_COLORS.PRIMARY : undefined}>\n + Add source: {addModal.isOpen ? addSourceInput : \"\"}\n {addModal.isOpen ? \"\\u2588\" : \"\"}\n </Text>\n </Box>\n\n {statusMessage && (\n <Box marginTop={1}>\n <Text color={statusMessage.color as \"red\" | \"green\"}>{statusMessage.text}</Text>\n </Box>\n )}\n\n <Box marginTop={1} flexDirection=\"column\">\n <Text dimColor>Local skills: {summary?.localSkillCount ?? 0} in .claude/skills/</Text>\n <Text dimColor>Plugins: {summary?.pluginSkillCount ?? 0} from installed plugins</Text>\n </Box>\n\n <Box marginTop={1}>\n <Text dimColor>\n {addModal.isOpen ? \"ENTER submit ESC cancel\" : \"A add DEL remove ESC close\"}\n </Text>\n </Box>\n </Box>\n );\n};\n","import { useState, useCallback } from \"react\";\nimport { CLI_COLORS } from \"../../consts.js\";\nimport { getErrorMessage } from \"../../utils/errors.js\";\nimport { addSource, removeSource } from \"../../lib/configuration/source-manager.js\";\n\ntype StatusMessage = { text: string; color: string } | null;\n\ntype UseSourceOperationsResult = {\n handleAdd: (url: string) => Promise<void>;\n handleRemove: (name: string) => Promise<boolean>;\n statusMessage: StatusMessage;\n clearStatus: () => void;\n};\n\nexport function useSourceOperations(\n projectDir: string,\n onReload: () => Promise<void>,\n): UseSourceOperationsResult {\n const [statusMessage, setStatusMessage] = useState<StatusMessage>(null);\n\n const handleAdd = useCallback(\n async (url: string) => {\n try {\n const result = await addSource(projectDir, url);\n setStatusMessage({\n text: `Added \"${result.name}\" (${result.skillCount} skills)`,\n color: CLI_COLORS.SUCCESS,\n });\n await onReload();\n } catch (error) {\n const message = getErrorMessage(error);\n setStatusMessage({ text: `Failed to add source: ${message}`, color: CLI_COLORS.ERROR });\n }\n },\n [projectDir, onReload],\n );\n\n const handleRemove = useCallback(\n async (name: string): Promise<boolean> => {\n try {\n await removeSource(projectDir, name);\n setStatusMessage({ text: `Removed \"${name}\"`, color: CLI_COLORS.SUCCESS });\n await onReload();\n return true;\n } catch (error) {\n const message = getErrorMessage(error);\n setStatusMessage({ text: `Failed to remove: ${message}`, color: CLI_COLORS.ERROR });\n return false;\n }\n },\n [projectDir, onReload],\n );\n\n const clearStatus = useCallback(() => {\n setStatusMessage(null);\n }, []);\n\n return { handleAdd, handleRemove, statusMessage, clearStatus };\n}\n"],"mappings":"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","names":["useState","useCallback","useState","useCallback"]}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
StackSelection
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-MYLRA7NI.js";
|
|
5
5
|
import {
|
|
6
6
|
DomainSelection
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-WXW6SQ5K.js";
|
|
8
8
|
import {
|
|
9
9
|
useWizardStore
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-WWLEF4MQ.js";
|
|
11
11
|
import {
|
|
12
12
|
init_esm_shims
|
|
13
13
|
} from "./chunk-AWKZ5BDL.js";
|
|
@@ -26,4 +26,4 @@ var StepStack = ({ matrix }) => {
|
|
|
26
26
|
export {
|
|
27
27
|
StepStack
|
|
28
28
|
};
|
|
29
|
-
//# sourceMappingURL=chunk-
|
|
29
|
+
//# sourceMappingURL=chunk-HMZPUOWU.js.map
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "./chunk-LY5HM34M.js";
|
|
8
8
|
import {
|
|
9
9
|
useWizardStore
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-WWLEF4MQ.js";
|
|
11
11
|
import {
|
|
12
12
|
init_esm_shims
|
|
13
13
|
} from "./chunk-AWKZ5BDL.js";
|
|
@@ -72,4 +72,4 @@ var StackSelection = ({ matrix }) => {
|
|
|
72
72
|
export {
|
|
73
73
|
StackSelection
|
|
74
74
|
};
|
|
75
|
-
//# sourceMappingURL=chunk-
|
|
75
|
+
//# sourceMappingURL=chunk-MYLRA7NI.js.map
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
import {
|
|
12
12
|
getAvailableSkills,
|
|
13
13
|
resolveAlias
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-QUL7R35E.js";
|
|
15
15
|
import {
|
|
16
16
|
CLI_COLORS,
|
|
17
17
|
UI_SYMBOLS
|
|
@@ -280,4 +280,4 @@ export {
|
|
|
280
280
|
getSkillDisplayLabel,
|
|
281
281
|
StepBuild
|
|
282
282
|
};
|
|
283
|
-
//# sourceMappingURL=chunk-
|
|
283
|
+
//# sourceMappingURL=chunk-QR2ONHDW.js.map
|