@claude-collective/cli 0.6.0 → 0.13.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 +192 -0
- package/README.md +26 -9
- package/dist/{chunk-TOPAIL5W.js → chunk-3U3R4NCG.js} +2 -2
- package/dist/chunk-3U3R4NCG.js.map +1 -0
- package/dist/{chunk-TFV6Z7F7.js → chunk-57Y5RALO.js} +10 -10
- package/dist/chunk-57Y5RALO.js.map +1 -0
- package/dist/chunk-66UDJBF6.js +96 -0
- package/dist/chunk-66UDJBF6.js.map +1 -0
- package/dist/chunk-6DCSSORF.js +264 -0
- package/dist/chunk-6DCSSORF.js.map +1 -0
- package/dist/chunk-6Q3Y7KVB.js +31 -0
- package/dist/chunk-6Q3Y7KVB.js.map +1 -0
- package/dist/{chunk-SJYG4EJZ.js → chunk-76DWXGQE.js} +10 -8
- package/dist/chunk-76DWXGQE.js.map +1 -0
- package/dist/{chunk-AZP2AA5M.js → chunk-7Q44DMSP.js} +241 -84
- package/dist/chunk-7Q44DMSP.js.map +1 -0
- package/dist/chunk-ACNBKXXJ.js +321 -0
- package/dist/chunk-ACNBKXXJ.js.map +1 -0
- package/dist/{chunk-JMQGWQZU.js → chunk-B7CCVP6Q.js} +42 -10
- package/dist/chunk-B7CCVP6Q.js.map +1 -0
- package/dist/chunk-BDLUZVKU.js +54 -0
- package/dist/chunk-BDLUZVKU.js.map +1 -0
- package/dist/chunk-CDX4W4DM.js +120 -0
- package/dist/chunk-CDX4W4DM.js.map +1 -0
- package/dist/{chunk-MYAVQ23U.js → chunk-CJEHB4TB.js} +23 -9
- package/dist/chunk-CJEHB4TB.js.map +1 -0
- package/dist/{chunk-6WEQADPL.js → chunk-CPZOTVCI.js} +15 -14
- package/dist/chunk-CPZOTVCI.js.map +1 -0
- package/dist/chunk-D237EVNB.js +187 -0
- package/dist/chunk-D237EVNB.js.map +1 -0
- package/dist/{chunk-UFWNMW3G.js → chunk-DRXPNNPB.js} +19 -18
- package/dist/chunk-DRXPNNPB.js.map +1 -0
- package/dist/chunk-E3FJH4TF.js +80 -0
- package/dist/chunk-E3FJH4TF.js.map +1 -0
- package/dist/{chunk-D4IQAT27.js → chunk-ED4E6Q2T.js} +10 -10
- package/dist/chunk-ED4E6Q2T.js.map +1 -0
- package/dist/{chunk-SYQ7R2JO.js → chunk-EHS3TWWP.js} +3 -3
- package/dist/chunk-EHS3TWWP.js.map +1 -0
- package/dist/{chunk-AU7XVCLO.js → chunk-GDH553MV.js} +6 -6
- package/dist/chunk-GDH553MV.js.map +1 -0
- package/dist/chunk-HLJX2FTL.js +95 -0
- package/dist/chunk-HLJX2FTL.js.map +1 -0
- package/dist/chunk-I2DSLOXZ.js +75 -0
- package/dist/chunk-I2DSLOXZ.js.map +1 -0
- package/dist/{chunk-J2Y4A3LP.js → chunk-I4TPKIYX.js} +33 -18
- package/dist/chunk-I4TPKIYX.js.map +1 -0
- package/dist/{chunk-ZSKHDU5P.js → chunk-IMDW5ZUP.js} +19 -11
- package/dist/chunk-IMDW5ZUP.js.map +1 -0
- package/dist/{chunk-U4VYHKPM.js → chunk-JIPWV2FX.js} +6 -6
- package/dist/chunk-JIPWV2FX.js.map +1 -0
- package/dist/{chunk-OSQDDJXX.js → chunk-K7EVM5LY.js} +5 -10
- package/dist/chunk-K7EVM5LY.js.map +1 -0
- package/dist/{chunk-MJSFR562.js → chunk-KAAEN2PO.js} +3 -3
- package/dist/chunk-KAAEN2PO.js.map +1 -0
- package/dist/{chunk-URDV4OCP.js → chunk-LE6IY6IT.js} +22 -17
- package/dist/chunk-LE6IY6IT.js.map +1 -0
- package/dist/{chunk-FKU7VSUD.js → chunk-NDY25DTL.js} +6 -6
- package/dist/chunk-NDY25DTL.js.map +1 -0
- package/dist/{chunk-UNHCZRO4.js → chunk-P26A2K5N.js} +7 -7
- package/dist/chunk-P26A2K5N.js.map +1 -0
- package/dist/{chunk-DHFFRMF6.js → chunk-RTE64SJA.js} +2 -2
- package/dist/chunk-RTE64SJA.js.map +1 -0
- package/dist/{chunk-6ESUJMM7.js → chunk-SGJ23HIP.js} +14 -11
- package/dist/chunk-SGJ23HIP.js.map +1 -0
- package/dist/{chunk-367K3JB3.js → chunk-SVYPSDWY.js} +10 -10
- package/dist/chunk-SVYPSDWY.js.map +1 -0
- package/dist/{chunk-MMDXNZPF.js → chunk-TKFPKEV3.js} +2 -2
- package/dist/chunk-TKFPKEV3.js.map +1 -0
- package/dist/{chunk-M7YCPFIX.js → chunk-UQTEPWU7.js} +2 -2
- package/dist/chunk-UQTEPWU7.js.map +1 -0
- package/dist/{chunk-QESUUPOE.js → chunk-V46GGCCI.js} +80 -27
- package/dist/chunk-V46GGCCI.js.map +1 -0
- package/dist/chunk-X6QONICW.js +86 -0
- package/dist/chunk-X6QONICW.js.map +1 -0
- package/dist/chunk-XY3XDVMI.js +15599 -0
- package/dist/chunk-XY3XDVMI.js.map +1 -0
- package/dist/chunk-Y2LW7R3Y.js +23 -0
- package/dist/chunk-Y2LW7R3Y.js.map +1 -0
- package/dist/chunk-Z2CWURZ6.js +78 -0
- package/dist/chunk-Z2CWURZ6.js.map +1 -0
- package/dist/chunk-Z7G4B5HJ.js +377 -0
- package/dist/chunk-Z7G4B5HJ.js.map +1 -0
- package/dist/{chunk-ZDQIUHAM.js → chunk-ZENYS6KW.js} +16 -15
- package/dist/chunk-ZENYS6KW.js.map +1 -0
- package/dist/{cli-v2 → cli}/defaults/agent-mappings.yaml +5 -5
- package/dist/commands/build/marketplace.js +19 -60
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +21 -59
- package/dist/commands/build/plugins.js.map +1 -1
- package/dist/commands/build/stack.js +15 -15
- package/dist/commands/build/stack.js.map +1 -1
- package/dist/commands/compile.js +21 -21
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/config/get.js +9 -8
- package/dist/commands/config/get.js.map +1 -1
- package/dist/commands/config/index.js +7 -6
- package/dist/commands/config/index.js.map +1 -1
- package/dist/commands/config/path.js +8 -7
- package/dist/commands/config/path.js.map +1 -1
- package/dist/commands/config/set-project.js +9 -8
- package/dist/commands/config/set-project.js.map +1 -1
- package/dist/commands/config/set.js +9 -8
- package/dist/commands/config/set.js.map +1 -1
- package/dist/commands/config/show.js +6 -5
- package/dist/commands/config/unset-project.js +9 -8
- package/dist/commands/config/unset-project.js.map +1 -1
- package/dist/commands/config/unset.js +9 -8
- package/dist/commands/config/unset.js.map +1 -1
- package/dist/commands/diff.js +12 -12
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/doctor.js +10 -10
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +52 -48
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +180 -97
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/import/skill.js +339 -0
- package/dist/commands/import/skill.js.map +1 -0
- package/dist/commands/info.js +9 -9
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/init.js +205 -77
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list.js +9 -9
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/new/agent.js +19 -21
- package/dist/commands/new/agent.js.map +1 -1
- package/dist/commands/new/skill.js +11 -12
- package/dist/commands/new/skill.js.map +1 -1
- package/dist/commands/outdated.js +12 -12
- package/dist/commands/outdated.js.map +1 -1
- package/dist/commands/search.js +205 -17
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/test-imports.js +18 -18
- package/dist/commands/test-imports.js.map +1 -1
- package/dist/commands/uninstall.js +70 -83
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +22 -22
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/validate.js +9 -9
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/version/bump.js +8 -8
- package/dist/commands/version/bump.js.map +1 -1
- package/dist/commands/version/index.js +8 -8
- package/dist/commands/version/index.js.map +1 -1
- package/dist/commands/version/set.js +7 -7
- package/dist/commands/version/set.js.map +1 -1
- package/dist/commands/version/show.js +8 -8
- package/dist/commands/version/show.js.map +1 -1
- package/dist/components/common/confirm.js +1 -1
- package/dist/components/common/message.js +1 -1
- package/dist/components/common/message.js.map +1 -1
- package/dist/components/common/spinner.js +1 -1
- package/dist/components/common/spinner.js.map +1 -1
- package/dist/components/skill-search/skill-search.js +10 -0
- package/dist/components/wizard/category-grid.js +9 -0
- package/dist/components/wizard/category-grid.test.js +861 -0
- package/dist/components/wizard/category-grid.test.js.map +1 -0
- package/dist/components/wizard/section-progress.js +9 -0
- package/dist/components/wizard/section-progress.test.js +281 -0
- package/dist/components/wizard/section-progress.test.js.map +1 -0
- package/dist/components/wizard/step-approach.js +4 -3
- package/dist/components/wizard/step-build.js +16 -0
- package/dist/components/wizard/step-build.js.map +1 -0
- package/dist/components/wizard/step-build.test.js +741 -0
- package/dist/components/wizard/step-build.test.js.map +1 -0
- package/dist/components/wizard/step-confirm.js +2 -4
- package/dist/components/wizard/step-refine.js +10 -0
- package/dist/components/wizard/step-refine.js.map +1 -0
- package/dist/components/wizard/step-refine.test.js +236 -0
- package/dist/components/wizard/step-refine.test.js.map +1 -0
- package/dist/components/wizard/step-stack-options.js +11 -0
- package/dist/components/wizard/step-stack-options.js.map +1 -0
- package/dist/components/wizard/step-stack.js +3 -3
- package/dist/components/wizard/wizard-footer.js +9 -0
- package/dist/components/wizard/wizard-footer.js.map +1 -0
- package/dist/components/wizard/wizard-tabs.js +11 -0
- package/dist/components/wizard/wizard-tabs.js.map +1 -0
- package/dist/components/wizard/wizard.js +14 -11
- package/dist/hooks/init.js +5 -4
- package/dist/hooks/init.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/stores/wizard-store.js +2 -2
- package/dist/stores/wizard-store.test.js +249 -15835
- package/dist/stores/wizard-store.test.js.map +1 -1
- package/package.json +3 -2
- package/dist/chunk-367K3JB3.js.map +0 -1
- package/dist/chunk-6ESUJMM7.js.map +0 -1
- package/dist/chunk-6OY6ZYQF.js +0 -93
- package/dist/chunk-6OY6ZYQF.js.map +0 -1
- package/dist/chunk-6WEQADPL.js.map +0 -1
- package/dist/chunk-AU7XVCLO.js.map +0 -1
- package/dist/chunk-AZP2AA5M.js.map +0 -1
- package/dist/chunk-D4IQAT27.js.map +0 -1
- package/dist/chunk-DHFFRMF6.js.map +0 -1
- package/dist/chunk-FKU7VSUD.js.map +0 -1
- package/dist/chunk-J2Y4A3LP.js.map +0 -1
- package/dist/chunk-JMQGWQZU.js.map +0 -1
- package/dist/chunk-JY4RO76L.js +0 -73
- package/dist/chunk-JY4RO76L.js.map +0 -1
- package/dist/chunk-M7YCPFIX.js.map +0 -1
- package/dist/chunk-MJSFR562.js.map +0 -1
- package/dist/chunk-MMDXNZPF.js.map +0 -1
- package/dist/chunk-MYAVQ23U.js.map +0 -1
- package/dist/chunk-OSQDDJXX.js.map +0 -1
- package/dist/chunk-QESUUPOE.js.map +0 -1
- package/dist/chunk-SJYG4EJZ.js.map +0 -1
- package/dist/chunk-SYQ7R2JO.js.map +0 -1
- package/dist/chunk-TD643KB3.js +0 -245
- package/dist/chunk-TD643KB3.js.map +0 -1
- package/dist/chunk-TFV6Z7F7.js.map +0 -1
- package/dist/chunk-TGOHJCQ4.js +0 -83
- package/dist/chunk-TGOHJCQ4.js.map +0 -1
- package/dist/chunk-TOPAIL5W.js.map +0 -1
- package/dist/chunk-U4VYHKPM.js.map +0 -1
- package/dist/chunk-UFWNMW3G.js.map +0 -1
- package/dist/chunk-UNHCZRO4.js.map +0 -1
- package/dist/chunk-URDV4OCP.js.map +0 -1
- package/dist/chunk-YI6JVSFO.js +0 -43
- package/dist/chunk-YI6JVSFO.js.map +0 -1
- package/dist/chunk-YNSNRR5D.js +0 -184
- package/dist/chunk-YNSNRR5D.js.map +0 -1
- package/dist/chunk-Z6DLWTBY.js +0 -46
- package/dist/chunk-Z6DLWTBY.js.map +0 -1
- package/dist/chunk-ZDQIUHAM.js.map +0 -1
- package/dist/chunk-ZSKHDU5P.js.map +0 -1
- package/dist/components/wizard/selection-header.js +0 -11
- package/dist/components/wizard/step-category.js +0 -12
- package/dist/components/wizard/step-subcategory.js +0 -13
- /package/dist/components/{wizard/selection-header.js.map → skill-search/skill-search.js.map} +0 -0
- /package/dist/components/wizard/{step-category.js.map → category-grid.js.map} +0 -0
- /package/dist/components/wizard/{step-subcategory.js.map → section-progress.js.map} +0 -0
package/dist/commands/eject.js
CHANGED
|
@@ -1,65 +1,53 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
copySkillsToLocalFlattened
|
|
4
|
+
} from "../chunk-K7EVM5LY.js";
|
|
5
|
+
import "../chunk-KAAEN2PO.js";
|
|
6
6
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
loadSkillsMatrixFromSource
|
|
8
|
+
} from "../chunk-CPZOTVCI.js";
|
|
9
|
+
import "../chunk-B7CCVP6Q.js";
|
|
10
|
+
import "../chunk-IMDW5ZUP.js";
|
|
10
11
|
import {
|
|
11
12
|
BaseCommand,
|
|
12
13
|
EXIT_CODES
|
|
13
|
-
} from "../chunk-
|
|
14
|
-
import
|
|
14
|
+
} from "../chunk-EHS3TWWP.js";
|
|
15
|
+
import {
|
|
16
|
+
loadProjectConfig,
|
|
17
|
+
resolveSource
|
|
18
|
+
} from "../chunk-V46GGCCI.js";
|
|
19
|
+
import "../chunk-3U3R4NCG.js";
|
|
15
20
|
import {
|
|
16
21
|
copy,
|
|
17
22
|
directoryExists,
|
|
18
23
|
ensureDir,
|
|
19
24
|
fileExists,
|
|
25
|
+
readFile,
|
|
20
26
|
writeFile
|
|
21
|
-
} from "../chunk-
|
|
27
|
+
} from "../chunk-TKFPKEV3.js";
|
|
28
|
+
import {
|
|
29
|
+
CLAUDE_SRC_DIR,
|
|
30
|
+
DIRS,
|
|
31
|
+
LOCAL_SKILLS_PATH,
|
|
32
|
+
PROJECT_ROOT
|
|
33
|
+
} from "../chunk-76DWXGQE.js";
|
|
22
34
|
import {
|
|
23
35
|
init_esm_shims
|
|
24
36
|
} from "../chunk-DHET7RCE.js";
|
|
25
37
|
|
|
26
|
-
// src/cli
|
|
38
|
+
// src/cli/commands/eject.ts
|
|
27
39
|
init_esm_shims();
|
|
28
40
|
import { Args, Flags } from "@oclif/core";
|
|
29
41
|
import path from "path";
|
|
30
42
|
import os from "os";
|
|
31
|
-
|
|
32
|
-
var
|
|
33
|
-
# Agent-skill mappings for this project
|
|
34
|
-
|
|
35
|
-
name: my-project
|
|
36
|
-
description: Project description
|
|
37
|
-
|
|
38
|
-
# Agents to compile
|
|
39
|
-
agents:
|
|
40
|
-
- web-developer
|
|
41
|
-
- api-developer
|
|
42
|
-
- web-tester
|
|
43
|
-
- web-pm
|
|
44
|
-
|
|
45
|
-
# Agent-specific skill assignments (optional)
|
|
46
|
-
# If not specified, all available skills are given to all agents
|
|
47
|
-
agent_skills:
|
|
48
|
-
web-developer:
|
|
49
|
-
- react
|
|
50
|
-
- zustand
|
|
51
|
-
- scss-modules
|
|
52
|
-
api-developer:
|
|
53
|
-
- hono
|
|
54
|
-
- drizzle
|
|
55
|
-
- better-auth
|
|
56
|
-
`;
|
|
43
|
+
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
44
|
+
var EJECT_TYPES = ["agent-partials", "skills", "all"];
|
|
57
45
|
var Eject = class _Eject extends BaseCommand {
|
|
58
|
-
static summary = "Eject
|
|
59
|
-
static description = "Copy
|
|
46
|
+
static summary = "Eject skills or agent partials for local customization";
|
|
47
|
+
static description = "Copy agent partials or skills to your project for customization. Agent partials are always copied from the CLI. Skills are copied from the configured source (public marketplace by default).";
|
|
60
48
|
static args = {
|
|
61
49
|
type: Args.string({
|
|
62
|
-
description: "What to eject:
|
|
50
|
+
description: "What to eject: agent-partials, skills, all",
|
|
63
51
|
required: false,
|
|
64
52
|
options: EJECT_TYPES
|
|
65
53
|
})
|
|
@@ -74,6 +62,10 @@ var Eject = class _Eject extends BaseCommand {
|
|
|
74
62
|
output: Flags.string({
|
|
75
63
|
char: "o",
|
|
76
64
|
description: "Output directory (default: .claude/ in current directory)"
|
|
65
|
+
}),
|
|
66
|
+
refresh: Flags.boolean({
|
|
67
|
+
description: "Force refresh from remote source",
|
|
68
|
+
default: false
|
|
77
69
|
})
|
|
78
70
|
};
|
|
79
71
|
async run() {
|
|
@@ -81,7 +73,7 @@ var Eject = class _Eject extends BaseCommand {
|
|
|
81
73
|
const projectDir = process.cwd();
|
|
82
74
|
if (!args.type) {
|
|
83
75
|
this.error(
|
|
84
|
-
"Please specify what to eject:
|
|
76
|
+
"Please specify what to eject: agent-partials, skills, or all",
|
|
85
77
|
{ exit: EXIT_CODES.INVALID_ARGS }
|
|
86
78
|
);
|
|
87
79
|
}
|
|
@@ -100,7 +92,7 @@ var Eject = class _Eject extends BaseCommand {
|
|
|
100
92
|
});
|
|
101
93
|
}
|
|
102
94
|
} else {
|
|
103
|
-
outputBase = path.join(projectDir,
|
|
95
|
+
outputBase = path.join(projectDir, CLAUDE_SRC_DIR);
|
|
104
96
|
}
|
|
105
97
|
this.log("");
|
|
106
98
|
this.log("Claude Collective Eject");
|
|
@@ -110,96 +102,187 @@ var Eject = class _Eject extends BaseCommand {
|
|
|
110
102
|
}
|
|
111
103
|
const ejectType = args.type;
|
|
112
104
|
const directOutput = !!flags.output;
|
|
105
|
+
let sourceResult;
|
|
106
|
+
if (ejectType === "skills" || ejectType === "all") {
|
|
107
|
+
sourceResult = await loadSkillsMatrixFromSource({
|
|
108
|
+
sourceFlag: flags.source,
|
|
109
|
+
projectDir,
|
|
110
|
+
forceRefresh: flags.refresh
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
113
|
switch (ejectType) {
|
|
114
|
-
case "
|
|
115
|
-
await this.
|
|
116
|
-
break;
|
|
117
|
-
case "config":
|
|
118
|
-
await this.ejectConfig(outputBase, flags.force, directOutput);
|
|
114
|
+
case "agent-partials":
|
|
115
|
+
await this.ejectAgentPartials(outputBase, flags.force, directOutput);
|
|
119
116
|
break;
|
|
120
117
|
case "skills":
|
|
121
|
-
await this.ejectSkills(
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
118
|
+
await this.ejectSkills(
|
|
119
|
+
projectDir,
|
|
120
|
+
flags.force,
|
|
121
|
+
directOutput,
|
|
122
|
+
sourceResult,
|
|
123
|
+
directOutput ? outputBase : void 0
|
|
124
|
+
);
|
|
125
125
|
break;
|
|
126
126
|
case "all":
|
|
127
|
-
await this.
|
|
128
|
-
await this.
|
|
129
|
-
|
|
130
|
-
|
|
127
|
+
await this.ejectAgentPartials(outputBase, flags.force, directOutput);
|
|
128
|
+
await this.ejectSkills(
|
|
129
|
+
projectDir,
|
|
130
|
+
flags.force,
|
|
131
|
+
directOutput,
|
|
132
|
+
sourceResult,
|
|
133
|
+
directOutput ? outputBase : void 0
|
|
134
|
+
);
|
|
131
135
|
break;
|
|
132
136
|
}
|
|
137
|
+
if (flags.source) {
|
|
138
|
+
await this.saveSourceToProjectConfig(projectDir, flags.source);
|
|
139
|
+
}
|
|
140
|
+
await this.ensureMinimalConfig(projectDir, flags.source, sourceResult);
|
|
133
141
|
this.log("");
|
|
134
142
|
this.logSuccess("Eject complete!");
|
|
135
143
|
this.log("");
|
|
136
144
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
+
/**
|
|
146
|
+
* Save source to project-level .claude-src/config.yaml.
|
|
147
|
+
* Creates the config file if it doesn't exist, or merges with existing config.
|
|
148
|
+
*/
|
|
149
|
+
async saveSourceToProjectConfig(projectDir, source) {
|
|
150
|
+
const configPath = path.join(projectDir, CLAUDE_SRC_DIR, "config.yaml");
|
|
151
|
+
let config = {};
|
|
152
|
+
if (await fileExists(configPath)) {
|
|
153
|
+
const content = await readFile(configPath);
|
|
154
|
+
config = parseYaml(content) || {};
|
|
145
155
|
}
|
|
146
|
-
|
|
147
|
-
await
|
|
148
|
-
|
|
149
|
-
this.log(
|
|
156
|
+
config.source = source;
|
|
157
|
+
await ensureDir(path.join(projectDir, CLAUDE_SRC_DIR));
|
|
158
|
+
await writeFile(configPath, stringifyYaml(config, { indent: 2 }));
|
|
159
|
+
this.log(`Source saved to .claude-src/config.yaml`);
|
|
150
160
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
161
|
+
/**
|
|
162
|
+
* Ensure a minimal config.yaml exists so that `cc compile` can work after eject.
|
|
163
|
+
* Only creates if config doesn't already exist.
|
|
164
|
+
* Includes all resolved config values: source, marketplace, author, agents_source.
|
|
165
|
+
*/
|
|
166
|
+
async ensureMinimalConfig(projectDir, sourceFlag, sourceResult) {
|
|
167
|
+
const configPath = path.join(projectDir, CLAUDE_SRC_DIR, "config.yaml");
|
|
168
|
+
if (await fileExists(configPath)) {
|
|
157
169
|
return;
|
|
158
170
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
171
|
+
const projectName = path.basename(projectDir);
|
|
172
|
+
const config = {
|
|
173
|
+
name: projectName,
|
|
174
|
+
installMode: "local"
|
|
175
|
+
};
|
|
176
|
+
const resolvedConfig = sourceResult?.sourceConfig ?? await resolveSource(sourceFlag, projectDir);
|
|
177
|
+
if (sourceFlag) {
|
|
178
|
+
config.source = sourceFlag;
|
|
179
|
+
} else if (resolvedConfig.source) {
|
|
180
|
+
config.source = resolvedConfig.source;
|
|
181
|
+
}
|
|
182
|
+
if (resolvedConfig.marketplace) {
|
|
183
|
+
config.marketplace = resolvedConfig.marketplace;
|
|
184
|
+
}
|
|
185
|
+
const existingProjectConfig = await loadProjectConfig(projectDir);
|
|
186
|
+
if (existingProjectConfig?.author) {
|
|
187
|
+
config.author = existingProjectConfig.author;
|
|
188
|
+
}
|
|
189
|
+
if (existingProjectConfig?.agents_source) {
|
|
190
|
+
config.agents_source = existingProjectConfig.agents_source;
|
|
191
|
+
}
|
|
192
|
+
await ensureDir(path.join(projectDir, CLAUDE_SRC_DIR));
|
|
193
|
+
let configContent = stringifyYaml(config, { indent: 2 });
|
|
194
|
+
const exampleStackComment = `
|
|
195
|
+
# Example stack configuration (uncomment and customize):
|
|
196
|
+
#
|
|
197
|
+
# skills:
|
|
198
|
+
# - web-framework-react
|
|
199
|
+
# - web-styling-scss-modules
|
|
200
|
+
# - api-framework-hono
|
|
201
|
+
# - api-database-drizzle
|
|
202
|
+
#
|
|
203
|
+
# agents:
|
|
204
|
+
# - web-developer
|
|
205
|
+
# - api-developer
|
|
206
|
+
# - web-reviewer
|
|
207
|
+
#
|
|
208
|
+
# stack:
|
|
209
|
+
# web-developer:
|
|
210
|
+
# framework: web-framework-react
|
|
211
|
+
# styling: web-styling-scss-modules
|
|
212
|
+
# api-developer:
|
|
213
|
+
# api: api-framework-hono
|
|
214
|
+
# database: api-database-drizzle
|
|
215
|
+
`;
|
|
216
|
+
configContent += exampleStackComment;
|
|
217
|
+
await writeFile(configPath, configContent);
|
|
218
|
+
this.logSuccess(`Created ${CLAUDE_SRC_DIR}/config.yaml`);
|
|
163
219
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
220
|
+
/**
|
|
221
|
+
* Eject agent partials (templates + agent partial files).
|
|
222
|
+
*
|
|
223
|
+
* Combines the old templates and agents eject into a single operation:
|
|
224
|
+
* - Copies `PROJECT_ROOT/src/agents/_templates/` to `<dest>/_templates/`
|
|
225
|
+
* - Copies agent partials from `PROJECT_ROOT/src/agents/` (excluding `_templates`) to `<dest>/`
|
|
226
|
+
*
|
|
227
|
+
* Always copies from CLI's PROJECT_ROOT - the `--source` flag has no effect.
|
|
228
|
+
*/
|
|
229
|
+
async ejectAgentPartials(outputBase, force, directOutput = false) {
|
|
230
|
+
const sourceDir = path.join(PROJECT_ROOT, DIRS.agents);
|
|
167
231
|
if (!await directoryExists(sourceDir)) {
|
|
168
|
-
this.warn("No
|
|
169
|
-
this.log("Install skills with 'cc init' first, then try again.");
|
|
232
|
+
this.warn("No agent partials found in CLI.");
|
|
170
233
|
return;
|
|
171
234
|
}
|
|
172
|
-
const destDir = directOutput ? outputBase : path.join(outputBase, "
|
|
235
|
+
const destDir = directOutput ? outputBase : path.join(outputBase, "agents");
|
|
173
236
|
if (await directoryExists(destDir) && !force) {
|
|
174
237
|
this.warn(
|
|
175
|
-
`
|
|
238
|
+
`Agent partials already exist at ${destDir}. Use --force to overwrite.`
|
|
176
239
|
);
|
|
177
240
|
return;
|
|
178
241
|
}
|
|
179
242
|
await ensureDir(destDir);
|
|
180
243
|
await copy(sourceDir, destDir);
|
|
181
|
-
this.logSuccess(`
|
|
182
|
-
this.log(
|
|
244
|
+
this.logSuccess(`Agent partials ejected to ${destDir}`);
|
|
245
|
+
this.log(
|
|
246
|
+
"You can now customize templates, agent intro, workflow, and examples locally."
|
|
247
|
+
);
|
|
183
248
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
249
|
+
/**
|
|
250
|
+
* Eject skills from the configured source to local .claude/skills/ directory.
|
|
251
|
+
*
|
|
252
|
+
* Uses the source resolution system:
|
|
253
|
+
* - Default: Public marketplace
|
|
254
|
+
* - `--source /path`: Custom local source
|
|
255
|
+
* - `--source url`: Custom remote source
|
|
256
|
+
*
|
|
257
|
+
* Skills are copied in a flattened structure using their normalized skill IDs.
|
|
258
|
+
*/
|
|
259
|
+
async ejectSkills(projectDir, force, directOutput = false, sourceResult, customOutputBase) {
|
|
260
|
+
const destDir = directOutput && customOutputBase ? customOutputBase : path.join(projectDir, LOCAL_SKILLS_PATH);
|
|
191
261
|
if (await directoryExists(destDir) && !force) {
|
|
192
262
|
this.warn(
|
|
193
|
-
`
|
|
263
|
+
`Skills already exist at ${destDir}. Use --force to overwrite.`
|
|
194
264
|
);
|
|
195
265
|
return;
|
|
196
266
|
}
|
|
267
|
+
const skillIds = Object.keys(sourceResult.matrix.skills).filter(
|
|
268
|
+
(skillId) => !sourceResult.matrix.skills[skillId].local
|
|
269
|
+
);
|
|
270
|
+
if (skillIds.length === 0) {
|
|
271
|
+
this.warn("No skills found in source to eject.");
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
197
274
|
await ensureDir(destDir);
|
|
198
|
-
await
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
275
|
+
const copiedSkills = await copySkillsToLocalFlattened(
|
|
276
|
+
skillIds,
|
|
277
|
+
destDir,
|
|
278
|
+
sourceResult.matrix,
|
|
279
|
+
sourceResult
|
|
280
|
+
);
|
|
281
|
+
const sourceLabel = sourceResult.isLocal ? sourceResult.sourcePath : sourceResult.marketplace || sourceResult.sourceConfig.source;
|
|
282
|
+
this.logSuccess(
|
|
283
|
+
`${copiedSkills.length} skills ejected to ${destDir} from ${sourceLabel}`
|
|
202
284
|
);
|
|
285
|
+
this.log("You can now customize skill content locally.");
|
|
203
286
|
}
|
|
204
287
|
};
|
|
205
288
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli-v2/commands/eject.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport path from \"path\";\nimport os from \"os\";\nimport { BaseCommand } from \"../base-command.js\";\nimport {\n copy,\n ensureDir,\n directoryExists,\n fileExists,\n writeFile,\n} from \"../utils/fs.js\";\nimport { DIRS, PROJECT_ROOT } from \"../consts.js\";\nimport {\n getCollectivePluginDir,\n getPluginSkillsDir,\n} from \"../lib/plugin-finder.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\n\nconst EJECT_TYPES = [\"templates\", \"config\", \"skills\", \"agents\", \"all\"] as const;\ntype EjectType = (typeof EJECT_TYPES)[number];\n\nconst DEFAULT_CONFIG_CONTENT = `# Claude Collective Configuration\n# Agent-skill mappings for this project\n\nname: my-project\ndescription: Project description\n\n# Agents to compile\nagents:\n - web-developer\n - api-developer\n - web-tester\n - web-pm\n\n# Agent-specific skill assignments (optional)\n# If not specified, all available skills are given to all agents\nagent_skills:\n web-developer:\n - react\n - zustand\n - scss-modules\n api-developer:\n - hono\n - drizzle\n - better-auth\n`;\n\nexport default class Eject extends BaseCommand {\n static summary = \"Eject bundled content for local customization\";\n static description =\n \"Copy templates, config, skills, or agent partials to your project for customization\";\n\n static args = {\n type: Args.string({\n description: \"What to eject: templates, config, skills, agents, all\",\n required: false,\n options: EJECT_TYPES as unknown as string[],\n }),\n };\n\n static flags = {\n ...BaseCommand.baseFlags,\n force: Flags.boolean({\n char: \"f\",\n description: \"Overwrite existing files\",\n default: false,\n }),\n output: Flags.string({\n char: \"o\",\n description: \"Output directory (default: .claude/ in current directory)\",\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(Eject);\n const projectDir = process.cwd();\n\n if (!args.type) {\n this.error(\n \"Please specify what to eject: templates, config, skills, agents, or all\",\n { exit: EXIT_CODES.INVALID_ARGS },\n );\n }\n\n if (!EJECT_TYPES.includes(args.type as EjectType)) {\n this.error(`Unknown eject type: ${args.type}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n // Resolve output base directory\n let outputBase: string;\n if (flags.output) {\n // Expand ~ to home directory if present\n const expandedPath = flags.output.startsWith(\"~\")\n ? path.join(os.homedir(), flags.output.slice(1))\n : flags.output;\n outputBase = path.resolve(projectDir, expandedPath);\n\n // Validate output path is not an existing file\n if (await fileExists(outputBase)) {\n this.error(`Output path exists as a file: ${outputBase}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n } else {\n outputBase = path.join(projectDir, \".claude\");\n }\n\n this.log(\"\");\n this.log(\"Claude Collective Eject\");\n this.log(\"\");\n\n // Show output directory when using custom path\n if (flags.output) {\n this.log(`Output directory: ${outputBase}`);\n }\n\n const ejectType = args.type as EjectType;\n const directOutput = !!flags.output;\n\n switch (ejectType) {\n case \"templates\":\n await this.ejectTemplates(outputBase, flags.force, directOutput);\n break;\n case \"config\":\n await this.ejectConfig(outputBase, flags.force, directOutput);\n break;\n case \"skills\":\n await this.ejectSkills(outputBase, flags.force, directOutput);\n break;\n case \"agents\":\n await this.ejectAgents(outputBase, flags.force, directOutput);\n break;\n case \"all\":\n await this.ejectTemplates(outputBase, flags.force, directOutput);\n await this.ejectConfig(outputBase, flags.force, directOutput);\n await this.ejectSkills(outputBase, flags.force, directOutput);\n await this.ejectAgents(outputBase, flags.force, directOutput);\n break;\n }\n\n this.log(\"\");\n this.logSuccess(\"Eject complete!\");\n this.log(\"\");\n }\n\n private async ejectTemplates(\n outputBase: string,\n force: boolean,\n directOutput: boolean = false,\n ): Promise<void> {\n const sourceDir = path.join(PROJECT_ROOT, DIRS.templates);\n // When directOutput is true (--output used), write directly to outputBase\n // When false (default), add \"templates\" subdirectory for backward compatibility\n const destDir = directOutput\n ? outputBase\n : path.join(outputBase, \"templates\");\n\n if ((await directoryExists(destDir)) && !force) {\n this.warn(\n `Templates already exist at ${destDir}. Use --force to overwrite.`,\n );\n return;\n }\n\n await ensureDir(destDir);\n await copy(sourceDir, destDir);\n\n this.logSuccess(`Templates ejected to ${destDir}`);\n this.log(\"You can now customize agent.liquid and partials locally.\");\n }\n\n private async ejectConfig(\n outputBase: string,\n force: boolean,\n directOutput: boolean = false,\n ): Promise<void> {\n // Config always outputs to config.yaml in the specified location\n const destPath = path.join(outputBase, \"config.yaml\");\n\n if ((await fileExists(destPath)) && !force) {\n this.warn(\n `Config already exists at ${destPath}. Use --force to overwrite.`,\n );\n return;\n }\n\n await ensureDir(path.dirname(destPath));\n await writeFile(destPath, DEFAULT_CONFIG_CONTENT);\n\n this.logSuccess(`Config template ejected to ${destPath}`);\n this.log(\"Customize agent-skill mappings for your project.\");\n }\n\n private async ejectSkills(\n outputBase: string,\n force: boolean,\n directOutput: boolean = false,\n ): Promise<void> {\n // Find skills from installed plugin\n const pluginDir = getCollectivePluginDir();\n const sourceDir = getPluginSkillsDir(pluginDir);\n\n if (!(await directoryExists(sourceDir))) {\n this.warn(\"No skills found in installed plugin.\");\n this.log(\"Install skills with 'cc init' first, then try again.\");\n return;\n }\n\n // When directOutput is true (--output used), write directly to outputBase\n // When false (default), add \"skills\" subdirectory\n const destDir = directOutput ? outputBase : path.join(outputBase, \"skills\");\n\n if ((await directoryExists(destDir)) && !force) {\n this.warn(\n `Skills already exist at ${destDir}. Use --force to overwrite.`,\n );\n return;\n }\n\n await ensureDir(destDir);\n await copy(sourceDir, destDir);\n\n this.logSuccess(`Skills ejected to ${destDir}`);\n this.log(\"You can now customize skill content locally.\");\n }\n\n private async ejectAgents(\n outputBase: string,\n force: boolean,\n directOutput: boolean = false,\n ): Promise<void> {\n // Source is the agents directory from PROJECT_ROOT (excluding _templates)\n const sourceDir = path.join(PROJECT_ROOT, DIRS.agents);\n\n if (!(await directoryExists(sourceDir))) {\n this.warn(\"No agent partials found.\");\n return;\n }\n\n // When directOutput is true (--output used), write directly to outputBase\n // When false (default), add \"agents/_partials\" subdirectory\n const destDir = directOutput\n ? outputBase\n : path.join(outputBase, \"agents\", \"_partials\");\n\n if ((await directoryExists(destDir)) && !force) {\n this.warn(\n `Agent partials already exist at ${destDir}. Use --force to overwrite.`,\n );\n return;\n }\n\n await ensureDir(destDir);\n await copy(sourceDir, destDir);\n\n this.logSuccess(`Agent partials ejected to ${destDir}`);\n this.log(\n \"You can now customize agent intro, workflow, and examples locally.\",\n );\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/commands/eject.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport path from \"path\";\nimport os from \"os\";\nimport { parse as parseYaml, stringify as stringifyYaml } from \"yaml\";\nimport { BaseCommand } from \"../base-command.js\";\nimport {\n copy,\n ensureDir,\n directoryExists,\n fileExists,\n readFile,\n writeFile,\n} from \"../utils/fs.js\";\nimport {\n CLAUDE_SRC_DIR,\n DIRS,\n LOCAL_SKILLS_PATH,\n PROJECT_ROOT,\n} from \"../consts.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport {\n loadSkillsMatrixFromSource,\n type SourceLoadResult,\n} from \"../lib/source-loader.js\";\nimport { copySkillsToLocalFlattened } from \"../lib/skill-copier.js\";\nimport { loadProjectConfig, resolveSource } from \"../lib/config.js\";\n\nconst EJECT_TYPES = [\"agent-partials\", \"skills\", \"all\"] as const;\ntype EjectType = (typeof EJECT_TYPES)[number];\n\nexport default class Eject extends BaseCommand {\n static summary = \"Eject skills or agent partials for local customization\";\n static description =\n \"Copy agent partials or skills to your project for customization. \" +\n \"Agent partials are always copied from the CLI. \" +\n \"Skills are copied from the configured source (public marketplace by default).\";\n\n static args = {\n type: Args.string({\n description: \"What to eject: agent-partials, skills, all\",\n required: false,\n options: EJECT_TYPES as unknown as string[],\n }),\n };\n\n static flags = {\n ...BaseCommand.baseFlags,\n force: Flags.boolean({\n char: \"f\",\n description: \"Overwrite existing files\",\n default: false,\n }),\n output: Flags.string({\n char: \"o\",\n description: \"Output directory (default: .claude/ in current directory)\",\n }),\n refresh: Flags.boolean({\n description: \"Force refresh from remote source\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(Eject);\n const projectDir = process.cwd();\n\n if (!args.type) {\n this.error(\n \"Please specify what to eject: agent-partials, skills, or all\",\n { exit: EXIT_CODES.INVALID_ARGS },\n );\n }\n\n if (!EJECT_TYPES.includes(args.type as EjectType)) {\n this.error(`Unknown eject type: ${args.type}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n // Resolve output base directory\n let outputBase: string;\n if (flags.output) {\n // Expand ~ to home directory if present\n const expandedPath = flags.output.startsWith(\"~\")\n ? path.join(os.homedir(), flags.output.slice(1))\n : flags.output;\n outputBase = path.resolve(projectDir, expandedPath);\n\n // Validate output path is not an existing file\n if (await fileExists(outputBase)) {\n this.error(`Output path exists as a file: ${outputBase}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n } else {\n outputBase = path.join(projectDir, CLAUDE_SRC_DIR);\n }\n\n this.log(\"\");\n this.log(\"Claude Collective Eject\");\n this.log(\"\");\n\n // Show output directory when using custom path\n if (flags.output) {\n this.log(`Output directory: ${outputBase}`);\n }\n\n const ejectType = args.type as EjectType;\n const directOutput = !!flags.output;\n\n // Load source when ejecting skills or all\n let sourceResult: SourceLoadResult | undefined;\n if (ejectType === \"skills\" || ejectType === \"all\") {\n sourceResult = await loadSkillsMatrixFromSource({\n sourceFlag: flags.source,\n projectDir,\n forceRefresh: flags.refresh,\n });\n }\n\n switch (ejectType) {\n case \"agent-partials\":\n await this.ejectAgentPartials(outputBase, flags.force, directOutput);\n break;\n case \"skills\":\n await this.ejectSkills(\n projectDir,\n flags.force,\n directOutput,\n sourceResult!,\n directOutput ? outputBase : undefined,\n );\n break;\n case \"all\":\n await this.ejectAgentPartials(outputBase, flags.force, directOutput);\n await this.ejectSkills(\n projectDir,\n flags.force,\n directOutput,\n sourceResult!,\n directOutput ? outputBase : undefined,\n );\n break;\n }\n\n // Save source to project config if --source was provided\n if (flags.source) {\n await this.saveSourceToProjectConfig(projectDir, flags.source);\n }\n\n // Create minimal config.yaml if it doesn't exist\n await this.ensureMinimalConfig(projectDir, flags.source, sourceResult);\n\n this.log(\"\");\n this.logSuccess(\"Eject complete!\");\n this.log(\"\");\n }\n\n /**\n * Save source to project-level .claude-src/config.yaml.\n * Creates the config file if it doesn't exist, or merges with existing config.\n */\n private async saveSourceToProjectConfig(\n projectDir: string,\n source: string,\n ): Promise<void> {\n const configPath = path.join(projectDir, CLAUDE_SRC_DIR, \"config.yaml\");\n\n let config: Record<string, unknown> = {};\n if (await fileExists(configPath)) {\n const content = await readFile(configPath);\n config = (parseYaml(content) as Record<string, unknown>) || {};\n }\n\n config.source = source;\n\n await ensureDir(path.join(projectDir, CLAUDE_SRC_DIR));\n await writeFile(configPath, stringifyYaml(config, { indent: 2 }));\n\n this.log(`Source saved to .claude-src/config.yaml`);\n }\n\n /**\n * Ensure a minimal config.yaml exists so that `cc compile` can work after eject.\n * Only creates if config doesn't already exist.\n * Includes all resolved config values: source, marketplace, author, agents_source.\n */\n private async ensureMinimalConfig(\n projectDir: string,\n sourceFlag?: string,\n sourceResult?: SourceLoadResult,\n ): Promise<void> {\n const configPath = path.join(projectDir, CLAUDE_SRC_DIR, \"config.yaml\");\n\n // Don't overwrite existing config\n if (await fileExists(configPath)) {\n return;\n }\n\n const projectName = path.basename(projectDir);\n\n // Build config with all available values\n const config: Record<string, unknown> = {\n name: projectName,\n installMode: \"local\",\n };\n\n // Get resolved source config\n const resolvedConfig =\n sourceResult?.sourceConfig ??\n (await resolveSource(sourceFlag, projectDir));\n\n // Add source (flag overrides resolved source, but always include it)\n if (sourceFlag) {\n config.source = sourceFlag;\n } else if (resolvedConfig.source) {\n config.source = resolvedConfig.source;\n }\n\n // Add marketplace if available\n if (resolvedConfig.marketplace) {\n config.marketplace = resolvedConfig.marketplace;\n }\n\n // Load project config to get author and agents_source\n const existingProjectConfig = await loadProjectConfig(projectDir);\n if (existingProjectConfig?.author) {\n config.author = existingProjectConfig.author;\n }\n if (existingProjectConfig?.agents_source) {\n config.agents_source = existingProjectConfig.agents_source;\n }\n\n await ensureDir(path.join(projectDir, CLAUDE_SRC_DIR));\n\n // Build config YAML with commented example stack blueprint\n let configContent = stringifyYaml(config, { indent: 2 });\n\n // Append commented example stack configuration as a blueprint for users\n const exampleStackComment = `\n# Example stack configuration (uncomment and customize):\n#\n# skills:\n# - web-framework-react\n# - web-styling-scss-modules\n# - api-framework-hono\n# - api-database-drizzle\n#\n# agents:\n# - web-developer\n# - api-developer\n# - web-reviewer\n#\n# stack:\n# web-developer:\n# framework: web-framework-react\n# styling: web-styling-scss-modules\n# api-developer:\n# api: api-framework-hono\n# database: api-database-drizzle\n`;\n\n configContent += exampleStackComment;\n await writeFile(configPath, configContent);\n\n this.logSuccess(`Created ${CLAUDE_SRC_DIR}/config.yaml`);\n }\n\n /**\n * Eject agent partials (templates + agent partial files).\n *\n * Combines the old templates and agents eject into a single operation:\n * - Copies `PROJECT_ROOT/src/agents/_templates/` to `<dest>/_templates/`\n * - Copies agent partials from `PROJECT_ROOT/src/agents/` (excluding `_templates`) to `<dest>/`\n *\n * Always copies from CLI's PROJECT_ROOT - the `--source` flag has no effect.\n */\n private async ejectAgentPartials(\n outputBase: string,\n force: boolean,\n directOutput: boolean = false,\n ): Promise<void> {\n const sourceDir = path.join(PROJECT_ROOT, DIRS.agents);\n\n if (!(await directoryExists(sourceDir))) {\n this.warn(\"No agent partials found in CLI.\");\n return;\n }\n\n // Destination directory structure:\n // When directOutput is true: write directly to outputBase\n // When false (default): add \"agents\" subdirectory (to .claude-src/agents/)\n const destDir = directOutput ? outputBase : path.join(outputBase, \"agents\");\n\n if ((await directoryExists(destDir)) && !force) {\n this.warn(\n `Agent partials already exist at ${destDir}. Use --force to overwrite.`,\n );\n return;\n }\n\n await ensureDir(destDir);\n\n // Copy entire agents directory (includes _templates and all agent partials)\n await copy(sourceDir, destDir);\n\n this.logSuccess(`Agent partials ejected to ${destDir}`);\n this.log(\n \"You can now customize templates, agent intro, workflow, and examples locally.\",\n );\n }\n\n /**\n * Eject skills from the configured source to local .claude/skills/ directory.\n *\n * Uses the source resolution system:\n * - Default: Public marketplace\n * - `--source /path`: Custom local source\n * - `--source url`: Custom remote source\n *\n * Skills are copied in a flattened structure using their normalized skill IDs.\n */\n private async ejectSkills(\n projectDir: string,\n force: boolean,\n directOutput: boolean = false,\n sourceResult: SourceLoadResult,\n customOutputBase?: string,\n ): Promise<void> {\n // Destination directory structure:\n // When directOutput is true (custom --output): write directly to customOutputBase\n // When false (default): use .claude/skills/ (skills are runtime files, not source files)\n const destDir =\n directOutput && customOutputBase\n ? customOutputBase\n : path.join(projectDir, LOCAL_SKILLS_PATH);\n\n if ((await directoryExists(destDir)) && !force) {\n this.warn(\n `Skills already exist at ${destDir}. Use --force to overwrite.`,\n );\n return;\n }\n\n // Get all non-local skill IDs from the source matrix\n const skillIds = Object.keys(sourceResult.matrix.skills).filter(\n (skillId) => !sourceResult.matrix.skills[skillId].local,\n );\n\n if (skillIds.length === 0) {\n this.warn(\"No skills found in source to eject.\");\n return;\n }\n\n await ensureDir(destDir);\n\n // Copy skills using flattened structure\n const copiedSkills = await copySkillsToLocalFlattened(\n skillIds,\n destDir,\n sourceResult.matrix,\n sourceResult,\n );\n\n const sourceLabel = sourceResult.isLocal\n ? sourceResult.sourcePath\n : sourceResult.marketplace || sourceResult.sourceConfig.source;\n\n this.logSuccess(\n `${copiedSkills.length} skills ejected to ${destDir} from ${sourceLabel}`,\n );\n this.log(\"You can now customize skill content locally.\");\n }\n}\n"],"mappings":"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","names":[]}
|