@claude-collective/cli 0.1.3 → 0.2.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 +20 -0
- package/dist/cli/index.js +219 -158
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,26 @@ 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.2.0] - 2026-01-30
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Marketplace support** - install stack plugins directly from configured marketplaces
|
|
13
|
+
- Marketplace field in project and global config for plugin installation
|
|
14
|
+
- CLI utilities for marketplace management (`marketplace list`, `exists`, `add`)
|
|
15
|
+
- Multi-source agent loading - agents can now be loaded from both CLI and custom sources
|
|
16
|
+
- `sourceRoot` tracking for correct template resolution with multi-source agents
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- Removed skills eject functionality (use marketplace plugins instead)
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- Wizard now preserves approach selection state when toggling Expert Mode or Install Mode
|
|
25
|
+
|
|
26
|
+
[0.2.0]: https://github.com/claude-collective/cli/releases/tag/v0.2.0
|
|
27
|
+
|
|
8
28
|
## [0.1.3] - 2026-01-30
|
|
9
29
|
|
|
10
30
|
### Added
|
package/dist/cli/index.js
CHANGED
|
@@ -209,6 +209,8 @@ function isValidGlobalConfig(obj) {
|
|
|
209
209
|
return false;
|
|
210
210
|
if (config.author !== void 0 && typeof config.author !== "string")
|
|
211
211
|
return false;
|
|
212
|
+
if (config.marketplace !== void 0 && typeof config.marketplace !== "string")
|
|
213
|
+
return false;
|
|
212
214
|
return true;
|
|
213
215
|
}
|
|
214
216
|
function isValidProjectConfig(obj) {
|
|
@@ -216,6 +218,8 @@ function isValidProjectConfig(obj) {
|
|
|
216
218
|
const config = obj;
|
|
217
219
|
if (config.source !== void 0 && typeof config.source !== "string")
|
|
218
220
|
return false;
|
|
221
|
+
if (config.marketplace !== void 0 && typeof config.marketplace !== "string")
|
|
222
|
+
return false;
|
|
219
223
|
return true;
|
|
220
224
|
}
|
|
221
225
|
function getGlobalConfigPath() {
|
|
@@ -279,32 +283,35 @@ async function saveProjectConfig(projectDir, config) {
|
|
|
279
283
|
verbose(`Saved project config to ${configPath}`);
|
|
280
284
|
}
|
|
281
285
|
async function resolveSource(flagValue, projectDir) {
|
|
286
|
+
const projectConfig = projectDir ? await loadProjectConfig(projectDir) : null;
|
|
287
|
+
const globalConfig = await loadGlobalConfig();
|
|
288
|
+
const marketplace = projectConfig?.marketplace || globalConfig?.marketplace;
|
|
282
289
|
if (flagValue !== void 0) {
|
|
283
290
|
if (flagValue === "" || flagValue.trim() === "") {
|
|
284
291
|
throw new Error("--source flag cannot be empty");
|
|
285
292
|
}
|
|
286
293
|
verbose(`Source from --source flag: ${flagValue}`);
|
|
287
|
-
return { source: flagValue, sourceOrigin: "flag" };
|
|
294
|
+
return { source: flagValue, sourceOrigin: "flag", marketplace };
|
|
288
295
|
}
|
|
289
296
|
const envValue = process.env[SOURCE_ENV_VAR];
|
|
290
297
|
if (envValue) {
|
|
291
298
|
verbose(`Source from ${SOURCE_ENV_VAR} env var: ${envValue}`);
|
|
292
|
-
return { source: envValue, sourceOrigin: "env" };
|
|
299
|
+
return { source: envValue, sourceOrigin: "env", marketplace };
|
|
293
300
|
}
|
|
294
|
-
if (
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
301
|
+
if (projectConfig?.source) {
|
|
302
|
+
verbose(`Source from project config: ${projectConfig.source}`);
|
|
303
|
+
return {
|
|
304
|
+
source: projectConfig.source,
|
|
305
|
+
sourceOrigin: "project",
|
|
306
|
+
marketplace
|
|
307
|
+
};
|
|
300
308
|
}
|
|
301
|
-
const globalConfig = await loadGlobalConfig();
|
|
302
309
|
if (globalConfig?.source) {
|
|
303
310
|
verbose(`Source from global config: ${globalConfig.source}`);
|
|
304
|
-
return { source: globalConfig.source, sourceOrigin: "global" };
|
|
311
|
+
return { source: globalConfig.source, sourceOrigin: "global", marketplace };
|
|
305
312
|
}
|
|
306
313
|
verbose(`Using default source: ${DEFAULT_SOURCE}`);
|
|
307
|
-
return { source: DEFAULT_SOURCE, sourceOrigin: "default" };
|
|
314
|
+
return { source: DEFAULT_SOURCE, sourceOrigin: "default", marketplace };
|
|
308
315
|
}
|
|
309
316
|
function formatSourceOrigin(origin) {
|
|
310
317
|
switch (origin) {
|
|
@@ -529,7 +536,8 @@ async function loadAllAgents(projectRoot) {
|
|
|
529
536
|
description: config.description,
|
|
530
537
|
model: config.model,
|
|
531
538
|
tools: config.tools,
|
|
532
|
-
path: agentPath
|
|
539
|
+
path: agentPath,
|
|
540
|
+
sourceRoot: projectRoot
|
|
533
541
|
};
|
|
534
542
|
verbose(`Loaded agent: ${config.id} from ${file}`);
|
|
535
543
|
}
|
|
@@ -794,7 +802,8 @@ async function resolveAgents(agents, skills, compileConfig, projectRoot) {
|
|
|
794
802
|
model: definition.model,
|
|
795
803
|
tools: definition.tools,
|
|
796
804
|
skills: resolvedSkills,
|
|
797
|
-
path: definition.path
|
|
805
|
+
path: definition.path,
|
|
806
|
+
sourceRoot: definition.sourceRoot
|
|
798
807
|
};
|
|
799
808
|
}
|
|
800
809
|
return resolved;
|
|
@@ -1008,9 +1017,10 @@ async function determineStackVersion(stack, pluginDir) {
|
|
|
1008
1017
|
contentHash: newHash
|
|
1009
1018
|
};
|
|
1010
1019
|
}
|
|
1011
|
-
async function compileAgentForPlugin(name, agent,
|
|
1020
|
+
async function compileAgentForPlugin(name, agent, fallbackRoot, engine) {
|
|
1012
1021
|
verbose(`Compiling agent: ${name}`);
|
|
1013
|
-
const
|
|
1022
|
+
const agentSourceRoot = agent.sourceRoot || fallbackRoot;
|
|
1023
|
+
const agentDir = path11.join(agentSourceRoot, DIRS.agents, agent.path || name);
|
|
1014
1024
|
const intro4 = await readFile(path11.join(agentDir, "intro.md"));
|
|
1015
1025
|
const workflow = await readFile(path11.join(agentDir, "workflow.md"));
|
|
1016
1026
|
const examples = await readFileOptional(
|
|
@@ -1027,7 +1037,7 @@ async function compileAgentForPlugin(name, agent, projectRoot, engine) {
|
|
|
1027
1037
|
);
|
|
1028
1038
|
const agentPath = agent.path || name;
|
|
1029
1039
|
const category = agentPath.split("/")[0];
|
|
1030
|
-
const categoryDir = path11.join(
|
|
1040
|
+
const categoryDir = path11.join(agentSourceRoot, DIRS.agents, category);
|
|
1031
1041
|
let outputFormat = await readFileOptional(
|
|
1032
1042
|
path11.join(agentDir, "output-format.md"),
|
|
1033
1043
|
""
|
|
@@ -1129,19 +1139,25 @@ function generateHooksJson(hooks) {
|
|
|
1129
1139
|
}
|
|
1130
1140
|
async function compileStackPlugin(options) {
|
|
1131
1141
|
const { stackId, outputDir, projectRoot, agentSourcePath } = options;
|
|
1132
|
-
const
|
|
1142
|
+
const localAgentRoot = agentSourcePath || projectRoot;
|
|
1133
1143
|
verbose(`Compiling stack plugin: ${stackId}`);
|
|
1134
1144
|
verbose(` Stack/skills source: ${projectRoot}`);
|
|
1135
|
-
verbose(`
|
|
1145
|
+
verbose(` Local agent source: ${localAgentRoot}`);
|
|
1146
|
+
verbose(` CLI agent source: ${PROJECT_ROOT}`);
|
|
1136
1147
|
const stack = await loadStack(stackId, projectRoot, "dev");
|
|
1137
|
-
const
|
|
1148
|
+
const cliAgents = await loadAllAgents(PROJECT_ROOT);
|
|
1149
|
+
const localAgents = await loadAllAgents(localAgentRoot);
|
|
1150
|
+
const agents = { ...cliAgents, ...localAgents };
|
|
1151
|
+
verbose(
|
|
1152
|
+
` Loaded ${Object.keys(localAgents).length} local agents, ${Object.keys(cliAgents).length} CLI agents`
|
|
1153
|
+
);
|
|
1138
1154
|
const skills = await loadSkillsByIds(stack.skills || [], projectRoot);
|
|
1139
1155
|
const compileConfig = stackToCompileConfig(stackId, stack);
|
|
1140
1156
|
const resolvedAgents = await resolveAgents(
|
|
1141
1157
|
agents,
|
|
1142
1158
|
skills,
|
|
1143
1159
|
compileConfig,
|
|
1144
|
-
|
|
1160
|
+
projectRoot
|
|
1145
1161
|
);
|
|
1146
1162
|
const pluginDir = path11.join(outputDir, stackId);
|
|
1147
1163
|
const agentsDir = path11.join(pluginDir, "agents");
|
|
@@ -1168,7 +1184,12 @@ async function compileStackPlugin(options) {
|
|
|
1168
1184
|
const compiledAgentNames = [];
|
|
1169
1185
|
const allSkillPlugins = [];
|
|
1170
1186
|
for (const [name, agent] of Object.entries(resolvedAgents)) {
|
|
1171
|
-
const output = await compileAgentForPlugin(
|
|
1187
|
+
const output = await compileAgentForPlugin(
|
|
1188
|
+
name,
|
|
1189
|
+
agent,
|
|
1190
|
+
PROJECT_ROOT,
|
|
1191
|
+
engine
|
|
1192
|
+
);
|
|
1172
1193
|
await writeFile(path11.join(agentsDir, `${name}.md`), output);
|
|
1173
1194
|
compiledAgentNames.push(name);
|
|
1174
1195
|
for (const skill of agent.skills) {
|
|
@@ -2359,6 +2380,82 @@ import pc7 from "picocolors";
|
|
|
2359
2380
|
import path25 from "path";
|
|
2360
2381
|
import { stringify as stringifyYaml4 } from "yaml";
|
|
2361
2382
|
|
|
2383
|
+
// src/cli/utils/exec.ts
|
|
2384
|
+
import { spawn } from "child_process";
|
|
2385
|
+
async function execCommand(command, args, options) {
|
|
2386
|
+
return new Promise((resolve, reject) => {
|
|
2387
|
+
const proc = spawn(command, args, {
|
|
2388
|
+
cwd: options?.cwd,
|
|
2389
|
+
env: { ...process.env, ...options?.env },
|
|
2390
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
2391
|
+
});
|
|
2392
|
+
let stdout = "";
|
|
2393
|
+
let stderr = "";
|
|
2394
|
+
proc.stdout.on("data", (data) => {
|
|
2395
|
+
stdout += data.toString();
|
|
2396
|
+
});
|
|
2397
|
+
proc.stderr.on("data", (data) => {
|
|
2398
|
+
stderr += data.toString();
|
|
2399
|
+
});
|
|
2400
|
+
proc.on("close", (code) => {
|
|
2401
|
+
resolve({
|
|
2402
|
+
stdout,
|
|
2403
|
+
stderr,
|
|
2404
|
+
exitCode: code ?? 1
|
|
2405
|
+
});
|
|
2406
|
+
});
|
|
2407
|
+
proc.on("error", (err) => {
|
|
2408
|
+
reject(err);
|
|
2409
|
+
});
|
|
2410
|
+
});
|
|
2411
|
+
}
|
|
2412
|
+
async function claudePluginInstall(pluginPath, scope, projectDir) {
|
|
2413
|
+
const args = ["plugin", "install", pluginPath, "--scope", scope];
|
|
2414
|
+
const result = await execCommand("claude", args, { cwd: projectDir });
|
|
2415
|
+
if (result.exitCode !== 0) {
|
|
2416
|
+
const errorMessage = result.stderr || result.stdout || "Unknown error";
|
|
2417
|
+
throw new Error(`Plugin installation failed: ${errorMessage.trim()}`);
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
async function isClaudeCLIAvailable() {
|
|
2421
|
+
try {
|
|
2422
|
+
const result = await execCommand("claude", ["--version"], {});
|
|
2423
|
+
return result.exitCode === 0;
|
|
2424
|
+
} catch {
|
|
2425
|
+
return false;
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
async function claudePluginMarketplaceList() {
|
|
2429
|
+
const result = await execCommand(
|
|
2430
|
+
"claude",
|
|
2431
|
+
["plugin", "marketplace", "list", "--json"],
|
|
2432
|
+
{}
|
|
2433
|
+
);
|
|
2434
|
+
if (result.exitCode !== 0) {
|
|
2435
|
+
return [];
|
|
2436
|
+
}
|
|
2437
|
+
try {
|
|
2438
|
+
return JSON.parse(result.stdout);
|
|
2439
|
+
} catch {
|
|
2440
|
+
return [];
|
|
2441
|
+
}
|
|
2442
|
+
}
|
|
2443
|
+
async function claudePluginMarketplaceExists(name) {
|
|
2444
|
+
const marketplaces = await claudePluginMarketplaceList();
|
|
2445
|
+
return marketplaces.some((m) => m.name === name);
|
|
2446
|
+
}
|
|
2447
|
+
async function claudePluginMarketplaceAdd(githubRepo, name) {
|
|
2448
|
+
const args = ["plugin", "marketplace", "add", githubRepo, "--name", name];
|
|
2449
|
+
const result = await execCommand("claude", args, {});
|
|
2450
|
+
if (result.exitCode !== 0) {
|
|
2451
|
+
const errorMessage = result.stderr || result.stdout || "Unknown error";
|
|
2452
|
+
if (errorMessage.includes("already installed")) {
|
|
2453
|
+
return;
|
|
2454
|
+
}
|
|
2455
|
+
throw new Error(`Failed to add marketplace: ${errorMessage.trim()}`);
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
|
|
2362
2459
|
// src/cli/lib/wizard.ts
|
|
2363
2460
|
import * as p5 from "@clack/prompts";
|
|
2364
2461
|
import pc6 from "picocolors";
|
|
@@ -2790,6 +2887,7 @@ function createInitialState(options = {}) {
|
|
|
2790
2887
|
lastSelectedCategory: null,
|
|
2791
2888
|
lastSelectedSubcategory: null,
|
|
2792
2889
|
lastSelectedSkill: null,
|
|
2890
|
+
lastSelectedApproach: null,
|
|
2793
2891
|
expertMode: options.hasLocalSkills ?? false,
|
|
2794
2892
|
installMode: "plugin"
|
|
2795
2893
|
};
|
|
@@ -2939,7 +3037,8 @@ async function stepApproach(state) {
|
|
|
2939
3037
|
},
|
|
2940
3038
|
formatExpertModeOption(state.expertMode),
|
|
2941
3039
|
formatInstallModeOption(state.installMode)
|
|
2942
|
-
]
|
|
3040
|
+
],
|
|
3041
|
+
initialValue: state.lastSelectedApproach || void 0
|
|
2943
3042
|
});
|
|
2944
3043
|
return result;
|
|
2945
3044
|
}
|
|
@@ -3135,13 +3234,16 @@ async function runWizard(matrix, options = {}) {
|
|
|
3135
3234
|
return null;
|
|
3136
3235
|
}
|
|
3137
3236
|
if (result === EXPERT_MODE_VALUE) {
|
|
3237
|
+
state.lastSelectedApproach = EXPERT_MODE_VALUE;
|
|
3138
3238
|
state.expertMode = !state.expertMode;
|
|
3139
3239
|
break;
|
|
3140
3240
|
}
|
|
3141
3241
|
if (result === INSTALL_MODE_VALUE) {
|
|
3242
|
+
state.lastSelectedApproach = INSTALL_MODE_VALUE;
|
|
3142
3243
|
state.installMode = state.installMode === "plugin" ? "local" : "plugin";
|
|
3143
3244
|
break;
|
|
3144
3245
|
}
|
|
3246
|
+
state.lastSelectedApproach = null;
|
|
3145
3247
|
if (result === "stack") {
|
|
3146
3248
|
pushHistory(state);
|
|
3147
3249
|
state.currentStep = "stack";
|
|
@@ -3826,7 +3928,8 @@ async function loadFromLocal(source, sourceConfig) {
|
|
|
3826
3928
|
matrix: mergedMatrix,
|
|
3827
3929
|
sourceConfig,
|
|
3828
3930
|
sourcePath: skillsPath,
|
|
3829
|
-
isLocal: true
|
|
3931
|
+
isLocal: true,
|
|
3932
|
+
marketplace: sourceConfig.marketplace
|
|
3830
3933
|
};
|
|
3831
3934
|
}
|
|
3832
3935
|
async function loadFromRemote(source, sourceConfig, forceRefresh) {
|
|
@@ -3852,7 +3955,8 @@ async function loadFromRemote(source, sourceConfig, forceRefresh) {
|
|
|
3852
3955
|
matrix: mergedMatrix,
|
|
3853
3956
|
sourceConfig,
|
|
3854
3957
|
sourcePath: fetchResult.path,
|
|
3855
|
-
isLocal: false
|
|
3958
|
+
isLocal: false,
|
|
3959
|
+
marketplace: sourceConfig.marketplace
|
|
3856
3960
|
};
|
|
3857
3961
|
}
|
|
3858
3962
|
var LOCAL_CATEGORY_TOP = {
|
|
@@ -4098,54 +4202,6 @@ For autonomous operation, add to .claude/settings.json:
|
|
|
4098
4202
|
// src/cli/lib/stack-installer.ts
|
|
4099
4203
|
import os3 from "os";
|
|
4100
4204
|
import path24 from "path";
|
|
4101
|
-
|
|
4102
|
-
// src/cli/utils/exec.ts
|
|
4103
|
-
import { spawn } from "child_process";
|
|
4104
|
-
async function execCommand(command, args, options) {
|
|
4105
|
-
return new Promise((resolve, reject) => {
|
|
4106
|
-
const proc = spawn(command, args, {
|
|
4107
|
-
cwd: options?.cwd,
|
|
4108
|
-
env: { ...process.env, ...options?.env },
|
|
4109
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
4110
|
-
});
|
|
4111
|
-
let stdout = "";
|
|
4112
|
-
let stderr = "";
|
|
4113
|
-
proc.stdout.on("data", (data) => {
|
|
4114
|
-
stdout += data.toString();
|
|
4115
|
-
});
|
|
4116
|
-
proc.stderr.on("data", (data) => {
|
|
4117
|
-
stderr += data.toString();
|
|
4118
|
-
});
|
|
4119
|
-
proc.on("close", (code) => {
|
|
4120
|
-
resolve({
|
|
4121
|
-
stdout,
|
|
4122
|
-
stderr,
|
|
4123
|
-
exitCode: code ?? 1
|
|
4124
|
-
});
|
|
4125
|
-
});
|
|
4126
|
-
proc.on("error", (err) => {
|
|
4127
|
-
reject(err);
|
|
4128
|
-
});
|
|
4129
|
-
});
|
|
4130
|
-
}
|
|
4131
|
-
async function claudePluginInstall(pluginPath, scope, projectDir) {
|
|
4132
|
-
const args = ["plugin", "install", pluginPath, "--scope", scope];
|
|
4133
|
-
const result = await execCommand("claude", args, { cwd: projectDir });
|
|
4134
|
-
if (result.exitCode !== 0) {
|
|
4135
|
-
const errorMessage = result.stderr || result.stdout || "Unknown error";
|
|
4136
|
-
throw new Error(`Plugin installation failed: ${errorMessage.trim()}`);
|
|
4137
|
-
}
|
|
4138
|
-
}
|
|
4139
|
-
async function isClaudeCLIAvailable() {
|
|
4140
|
-
try {
|
|
4141
|
-
const result = await execCommand("claude", ["--version"], {});
|
|
4142
|
-
return result.exitCode === 0;
|
|
4143
|
-
} catch {
|
|
4144
|
-
return false;
|
|
4145
|
-
}
|
|
4146
|
-
}
|
|
4147
|
-
|
|
4148
|
-
// src/cli/lib/stack-installer.ts
|
|
4149
4205
|
async function compileStackToTemp(options) {
|
|
4150
4206
|
const tempDir = path24.join(os3.tmpdir(), `cc-stack-${Date.now()}`);
|
|
4151
4207
|
await ensureDir(tempDir);
|
|
@@ -4163,13 +4219,27 @@ async function compileStackToTemp(options) {
|
|
|
4163
4219
|
};
|
|
4164
4220
|
}
|
|
4165
4221
|
async function installStackAsPlugin(options) {
|
|
4166
|
-
const { stackId, projectDir, sourcePath, agentSourcePath } = options;
|
|
4222
|
+
const { stackId, projectDir, sourcePath, agentSourcePath, marketplace } = options;
|
|
4167
4223
|
const claudeAvailable = await isClaudeCLIAvailable();
|
|
4168
4224
|
if (!claudeAvailable) {
|
|
4169
4225
|
throw new Error(
|
|
4170
4226
|
"Claude CLI not found. Please install Claude Code first: https://claude.ai/code"
|
|
4171
4227
|
);
|
|
4172
4228
|
}
|
|
4229
|
+
if (marketplace) {
|
|
4230
|
+
verbose(`Installing from marketplace: ${stackId}@${marketplace}`);
|
|
4231
|
+
const pluginRef = `${stackId}@${marketplace}`;
|
|
4232
|
+
await claudePluginInstall(pluginRef, "project", projectDir);
|
|
4233
|
+
return {
|
|
4234
|
+
pluginName: stackId,
|
|
4235
|
+
stackName: stackId,
|
|
4236
|
+
agents: [],
|
|
4237
|
+
skills: [],
|
|
4238
|
+
pluginPath: pluginRef,
|
|
4239
|
+
fromMarketplace: true
|
|
4240
|
+
};
|
|
4241
|
+
}
|
|
4242
|
+
verbose(`Compiling stack locally: ${stackId}`);
|
|
4173
4243
|
const { result, cleanup } = await compileStackToTemp({
|
|
4174
4244
|
stackId,
|
|
4175
4245
|
projectRoot: sourcePath,
|
|
@@ -4182,7 +4252,8 @@ async function installStackAsPlugin(options) {
|
|
|
4182
4252
|
stackName: result.stackName,
|
|
4183
4253
|
agents: result.agents,
|
|
4184
4254
|
skills: result.skillPlugins,
|
|
4185
|
-
pluginPath: result.pluginPath
|
|
4255
|
+
pluginPath: result.pluginPath,
|
|
4256
|
+
fromMarketplace: false
|
|
4186
4257
|
};
|
|
4187
4258
|
} finally {
|
|
4188
4259
|
await cleanup();
|
|
@@ -4520,21 +4591,35 @@ var initCommand = new Command5("init").description("Initialize Claude Collective
|
|
|
4520
4591
|
);
|
|
4521
4592
|
if (dryRun) {
|
|
4522
4593
|
if (result.installMode === "plugin" && result.selectedStack) {
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4594
|
+
const useMarketplace = !!sourceResult.marketplace;
|
|
4595
|
+
if (useMarketplace) {
|
|
4596
|
+
p7.log.info(
|
|
4597
|
+
pc7.yellow(
|
|
4598
|
+
`[dry-run] Would install stack "${result.selectedStack.id}" from marketplace "${sourceResult.marketplace}"`
|
|
4599
|
+
)
|
|
4600
|
+
);
|
|
4601
|
+
p7.log.info(
|
|
4602
|
+
pc7.yellow(
|
|
4603
|
+
`[dry-run] claude plugin install ${result.selectedStack.id}@${sourceResult.marketplace} --scope project`
|
|
4604
|
+
)
|
|
4605
|
+
);
|
|
4606
|
+
} else {
|
|
4607
|
+
p7.log.info(
|
|
4608
|
+
pc7.yellow(
|
|
4609
|
+
`[dry-run] Would compile and install stack "${result.selectedStack.id}" as a native plugin`
|
|
4610
|
+
)
|
|
4611
|
+
);
|
|
4612
|
+
p7.log.info(
|
|
4613
|
+
pc7.yellow(
|
|
4614
|
+
`[dry-run] claude plugin install ./compiled-stack/${result.selectedStack.id} --scope project`
|
|
4615
|
+
)
|
|
4616
|
+
);
|
|
4617
|
+
p7.log.info(
|
|
4618
|
+
pc7.yellow(
|
|
4619
|
+
`[dry-run] Stack includes ${result.selectedSkills.length} skills and agents bundled together`
|
|
4620
|
+
)
|
|
4621
|
+
);
|
|
4622
|
+
}
|
|
4538
4623
|
} else {
|
|
4539
4624
|
if (result.installMode === "plugin") {
|
|
4540
4625
|
p7.log.info(
|
|
@@ -4563,31 +4648,59 @@ var initCommand = new Command5("init").description("Initialize Claude Collective
|
|
|
4563
4648
|
}
|
|
4564
4649
|
if (result.installMode === "plugin") {
|
|
4565
4650
|
if (result.selectedStack) {
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4651
|
+
if (sourceResult.marketplace) {
|
|
4652
|
+
const marketplaceExists = await claudePluginMarketplaceExists(
|
|
4653
|
+
sourceResult.marketplace
|
|
4654
|
+
);
|
|
4655
|
+
if (!marketplaceExists) {
|
|
4656
|
+
s.start(`Registering marketplace "${sourceResult.marketplace}"...`);
|
|
4657
|
+
try {
|
|
4658
|
+
await claudePluginMarketplaceAdd(
|
|
4659
|
+
sourceResult.sourceConfig.source,
|
|
4660
|
+
sourceResult.marketplace
|
|
4661
|
+
);
|
|
4662
|
+
s.stop(`Registered marketplace: ${sourceResult.marketplace}`);
|
|
4663
|
+
} catch (error) {
|
|
4664
|
+
s.stop("Failed to register marketplace");
|
|
4665
|
+
p7.log.error(
|
|
4666
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
4667
|
+
);
|
|
4668
|
+
process.exit(EXIT_CODES.ERROR);
|
|
4669
|
+
}
|
|
4670
|
+
}
|
|
4671
|
+
}
|
|
4672
|
+
const installMethod = sourceResult.marketplace ? `Installing from marketplace "${sourceResult.marketplace}"` : "Compiling and installing";
|
|
4673
|
+
s.start(`${installMethod} stack "${result.selectedStack.id}"...`);
|
|
4569
4674
|
try {
|
|
4570
4675
|
const installResult = await installStackAsPlugin({
|
|
4571
4676
|
stackId: result.selectedStack.id,
|
|
4572
4677
|
projectDir,
|
|
4573
4678
|
sourcePath: sourceResult.sourcePath,
|
|
4574
|
-
agentSourcePath: sourceResult.sourcePath
|
|
4679
|
+
agentSourcePath: sourceResult.sourcePath,
|
|
4680
|
+
marketplace: sourceResult.marketplace
|
|
4575
4681
|
});
|
|
4576
|
-
|
|
4682
|
+
const installedFrom = installResult.fromMarketplace ? `from marketplace` : `(compiled locally)`;
|
|
4683
|
+
s.stop(
|
|
4684
|
+
`Installed stack plugin: ${installResult.pluginName} ${installedFrom}`
|
|
4685
|
+
);
|
|
4577
4686
|
console.log("");
|
|
4578
4687
|
console.log(pc7.green("Claude Collective initialized successfully!"));
|
|
4579
4688
|
console.log("");
|
|
4580
4689
|
console.log(
|
|
4581
4690
|
`Stack ${pc7.cyan(`"${installResult.stackName}"`)} installed as plugin`
|
|
4582
4691
|
);
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4692
|
+
if (installResult.agents.length > 0) {
|
|
4693
|
+
console.log("");
|
|
4694
|
+
console.log(pc7.dim("Agents included:"));
|
|
4695
|
+
for (const agentName of installResult.agents) {
|
|
4696
|
+
console.log(` ${pc7.cyan(agentName)}`);
|
|
4697
|
+
}
|
|
4698
|
+
console.log("");
|
|
4699
|
+
console.log(
|
|
4700
|
+
pc7.dim(`Skills bundled: ${installResult.skills.length}`)
|
|
4701
|
+
);
|
|
4587
4702
|
}
|
|
4588
4703
|
console.log("");
|
|
4589
|
-
console.log(pc7.dim(`Skills bundled: ${installResult.skills.length}`));
|
|
4590
|
-
console.log("");
|
|
4591
4704
|
p7.outro(pc7.green("Claude Collective is ready to use!"));
|
|
4592
4705
|
await checkPermissions(projectDir);
|
|
4593
4706
|
return;
|
|
@@ -4626,7 +4739,9 @@ var initCommand = new Command5("init").description("Initialize Claude Collective
|
|
|
4626
4739
|
);
|
|
4627
4740
|
s.stop(`Copied ${copiedSkills.length} skills to .claude/skills/`);
|
|
4628
4741
|
s.start("Generating configuration...");
|
|
4629
|
-
const
|
|
4742
|
+
const cliAgents = await loadAllAgents(PROJECT_ROOT);
|
|
4743
|
+
const localAgents = await loadAllAgents(sourceResult.sourcePath);
|
|
4744
|
+
const agents = { ...cliAgents, ...localAgents };
|
|
4630
4745
|
const localSkillsForResolution = {};
|
|
4631
4746
|
for (const copiedSkill of copiedSkills) {
|
|
4632
4747
|
const skill = matrix.skills[copiedSkill.skillId];
|
|
@@ -5938,7 +6053,7 @@ import * as p12 from "@clack/prompts";
|
|
|
5938
6053
|
import pc12 from "picocolors";
|
|
5939
6054
|
import path30 from "path";
|
|
5940
6055
|
import os4 from "os";
|
|
5941
|
-
var EJECT_TYPES = ["templates", "
|
|
6056
|
+
var EJECT_TYPES = ["templates", "config", "all"];
|
|
5942
6057
|
var DEFAULT_CONFIG_CONTENT = `# Claude Collective Configuration
|
|
5943
6058
|
# Agent-skill mappings for this project
|
|
5944
6059
|
|
|
@@ -5964,31 +6079,7 @@ agent_skills:
|
|
|
5964
6079
|
- drizzle
|
|
5965
6080
|
- better-auth
|
|
5966
6081
|
`;
|
|
5967
|
-
var
|
|
5968
|
-
name: example-skill
|
|
5969
|
-
description: Short description of the skill
|
|
5970
|
-
---
|
|
5971
|
-
|
|
5972
|
-
# Example Skill
|
|
5973
|
-
|
|
5974
|
-
## Overview
|
|
5975
|
-
Describe what this skill teaches the agent.
|
|
5976
|
-
|
|
5977
|
-
## Instructions
|
|
5978
|
-
Specific instructions for the agent.
|
|
5979
|
-
|
|
5980
|
-
## Examples
|
|
5981
|
-
\`\`\`typescript
|
|
5982
|
-
// Example code
|
|
5983
|
-
\`\`\`
|
|
5984
|
-
`;
|
|
5985
|
-
var DEFAULT_METADATA_CONTENT = `# yaml-language-server: $schema=../../schemas/metadata.schema.json
|
|
5986
|
-
category: custom
|
|
5987
|
-
author: "@local"
|
|
5988
|
-
cli_name: Example Skill
|
|
5989
|
-
cli_description: Short description for CLI
|
|
5990
|
-
`;
|
|
5991
|
-
var ejectCommand = new Command10("eject").description("Eject bundled content for local customization").argument("[type]", "What to eject: templates, skills, config, all").option("-f, --force", "Overwrite existing files", false).option(
|
|
6082
|
+
var ejectCommand = new Command10("eject").description("Eject bundled content for local customization").argument("[type]", "What to eject: templates, config, all").option("-f, --force", "Overwrite existing files", false).option(
|
|
5992
6083
|
"-o, --output <dir>",
|
|
5993
6084
|
"Output directory (default: .claude/ in current directory)"
|
|
5994
6085
|
).configureOutput({
|
|
@@ -5997,9 +6088,7 @@ var ejectCommand = new Command10("eject").description("Eject bundled content for
|
|
|
5997
6088
|
async (type, options) => {
|
|
5998
6089
|
const projectDir = process.cwd();
|
|
5999
6090
|
if (!type) {
|
|
6000
|
-
p12.log.error(
|
|
6001
|
-
"Please specify what to eject: templates, skills, config, or all"
|
|
6002
|
-
);
|
|
6091
|
+
p12.log.error("Please specify what to eject: templates, config, or all");
|
|
6003
6092
|
process.exit(EXIT_CODES.INVALID_ARGS);
|
|
6004
6093
|
}
|
|
6005
6094
|
if (!EJECT_TYPES.includes(type)) {
|
|
@@ -6029,15 +6118,11 @@ var ejectCommand = new Command10("eject").description("Eject bundled content for
|
|
|
6029
6118
|
case "templates":
|
|
6030
6119
|
await ejectTemplates(outputBase, options.force, directOutput);
|
|
6031
6120
|
break;
|
|
6032
|
-
case "skills":
|
|
6033
|
-
await ejectSkills(outputBase, options.force, directOutput);
|
|
6034
|
-
break;
|
|
6035
6121
|
case "config":
|
|
6036
6122
|
await ejectConfig(outputBase, options.force, directOutput);
|
|
6037
6123
|
break;
|
|
6038
6124
|
case "all":
|
|
6039
6125
|
await ejectTemplates(outputBase, options.force, directOutput);
|
|
6040
|
-
await ejectSkills(outputBase, options.force, directOutput);
|
|
6041
6126
|
await ejectConfig(outputBase, options.force, directOutput);
|
|
6042
6127
|
break;
|
|
6043
6128
|
}
|
|
@@ -6060,30 +6145,6 @@ async function ejectTemplates(outputBase, force, directOutput = false) {
|
|
|
6060
6145
|
pc12.dim("You can now customize agent.liquid and partials locally.")
|
|
6061
6146
|
);
|
|
6062
6147
|
}
|
|
6063
|
-
async function ejectSkills(outputBase, force, directOutput = false) {
|
|
6064
|
-
const destDir = directOutput ? outputBase : path30.join(outputBase, "skill-templates");
|
|
6065
|
-
if (await directoryExists(destDir) && !force) {
|
|
6066
|
-
p12.log.warn(
|
|
6067
|
-
`Skill templates already exist at ${destDir}. Use --force to overwrite.`
|
|
6068
|
-
);
|
|
6069
|
-
return;
|
|
6070
|
-
}
|
|
6071
|
-
await ensureDir(destDir);
|
|
6072
|
-
const exampleSkillDir = path30.join(destDir, "example-skill");
|
|
6073
|
-
await ensureDir(exampleSkillDir);
|
|
6074
|
-
await writeFile(
|
|
6075
|
-
path30.join(exampleSkillDir, "SKILL.md"),
|
|
6076
|
-
DEFAULT_SKILL_MD_CONTENT
|
|
6077
|
-
);
|
|
6078
|
-
await writeFile(
|
|
6079
|
-
path30.join(exampleSkillDir, "metadata.yaml"),
|
|
6080
|
-
DEFAULT_METADATA_CONTENT
|
|
6081
|
-
);
|
|
6082
|
-
p12.log.success(`Skill templates ejected to ${pc12.cyan(destDir)}`);
|
|
6083
|
-
p12.log.info(
|
|
6084
|
-
pc12.dim("Copy example-skill/ to your skills/ directory and customize.")
|
|
6085
|
-
);
|
|
6086
|
-
}
|
|
6087
6148
|
async function ejectConfig(outputBase, force, directOutput = false) {
|
|
6088
6149
|
const destPath = path30.join(outputBase, "config.yaml");
|
|
6089
6150
|
if (await fileExists(destPath) && !force) {
|