agents-inc 0.154.0 → 0.155.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 +41 -0
- package/dist/chunk-2H7UWE2G.js +246 -0
- package/dist/chunk-2H7UWE2G.js.map +1 -0
- package/dist/{chunk-LA3JPESW.js → chunk-4A4L3YIW.js} +5 -5
- package/dist/chunk-4G2YHZIM.js +132 -0
- package/dist/chunk-4G2YHZIM.js.map +1 -0
- package/dist/{chunk-BZ4CZBOM.js → chunk-5F2YR5XV.js} +3 -3
- package/dist/{chunk-CHNA5RVS.js → chunk-5OKLCVM4.js} +3 -3
- package/dist/{chunk-ZU6DAR4S.js → chunk-5QZAK6J7.js} +7 -7
- package/dist/{chunk-ZU6DAR4S.js.map → chunk-5QZAK6J7.js.map} +1 -1
- package/dist/{chunk-NFH6SA62.js → chunk-6RLV45HN.js} +10 -10
- package/dist/{chunk-NFH6SA62.js.map → chunk-6RLV45HN.js.map} +1 -1
- package/dist/{chunk-GUDGCFSF.js → chunk-CLFHC2DK.js} +15 -106
- package/dist/chunk-CLFHC2DK.js.map +1 -0
- package/dist/chunk-D2CAV7MG.js +61 -0
- package/dist/chunk-D2CAV7MG.js.map +1 -0
- package/dist/{chunk-UW44KSYL.js → chunk-F2AMBBIA.js} +6 -6
- package/dist/{chunk-UW44KSYL.js.map → chunk-F2AMBBIA.js.map} +1 -1
- package/dist/{chunk-QQTYMW7N.js → chunk-F5T6TV4Z.js} +206 -73
- package/dist/chunk-F5T6TV4Z.js.map +1 -0
- package/dist/{chunk-K3O3YQYG.js → chunk-G47TDUK3.js} +2 -2
- package/dist/{chunk-AURY6RT6.js → chunk-GS2NZ3GD.js} +8 -8
- package/dist/chunk-GS2NZ3GD.js.map +1 -0
- package/dist/{chunk-5MFJ24VM.js → chunk-H6UTKTLK.js} +104 -250
- package/dist/chunk-H6UTKTLK.js.map +1 -0
- package/dist/{chunk-MJFIO5SX.js → chunk-HG4JPXJT.js} +11 -11
- package/dist/chunk-HG4JPXJT.js.map +1 -0
- package/dist/{chunk-IXEDSKMH.js → chunk-HTYH7CKN.js} +3 -3
- package/dist/{chunk-JC7DBPRD.js → chunk-HXKOIWLU.js} +2 -2
- package/dist/chunk-HXKOIWLU.js.map +1 -0
- package/dist/{chunk-NSJ2S7R5.js → chunk-ILUVL7WM.js} +2 -2
- package/dist/{chunk-R54KIGN2.js → chunk-IO5YBKHV.js} +13 -2
- package/dist/chunk-IO5YBKHV.js.map +1 -0
- package/dist/chunk-IXRZAHZF.js +53 -0
- package/dist/chunk-IXRZAHZF.js.map +1 -0
- package/dist/chunk-JCPANDNR.js +35 -0
- package/dist/chunk-JCPANDNR.js.map +1 -0
- package/dist/{chunk-NKCY2ULI.js → chunk-LJCNUP6M.js} +2 -2
- package/dist/{chunk-PRJD5MMQ.js → chunk-MHRC3KRX.js} +5 -5
- package/dist/chunk-MHRC3KRX.js.map +1 -0
- package/dist/chunk-MO5FGLVS.js +142 -0
- package/dist/chunk-MO5FGLVS.js.map +1 -0
- package/dist/{chunk-Q5FLW4JG.js → chunk-OKH64JZE.js} +2 -2
- package/dist/{chunk-WRRP47PY.js → chunk-PCC4LBKB.js} +2 -2
- package/dist/chunk-PMUABBPG.js +258 -0
- package/dist/chunk-PMUABBPG.js.map +1 -0
- package/dist/{chunk-2IMYK4WN.js → chunk-PNMM5HNX.js} +5 -5
- package/dist/{chunk-AKQ5QISO.js → chunk-QWVXOCXO.js} +6 -6
- package/dist/{chunk-IPJOMAWC.js → chunk-RWOYPOMR.js} +12 -2
- package/dist/{chunk-IPJOMAWC.js.map → chunk-RWOYPOMR.js.map} +1 -1
- package/dist/{chunk-ONWEOS77.js → chunk-SY4X2LND.js} +4 -4
- package/dist/{chunk-XGMOXMS4.js → chunk-TBOVYLQJ.js} +2 -2
- package/dist/{chunk-R7JV22QK.js → chunk-TNGMF4UX.js} +20 -20
- package/dist/{chunk-R7JV22QK.js.map → chunk-TNGMF4UX.js.map} +1 -1
- package/dist/{chunk-7VZV4O6B.js → chunk-UMH2YZKG.js} +14 -5
- package/dist/chunk-UMH2YZKG.js.map +1 -0
- package/dist/{chunk-6CNRMCFM.js → chunk-VPASBA7P.js} +2 -2
- package/dist/{chunk-CBF4ZYV3.js → chunk-WCAUUBHO.js} +1376 -741
- package/dist/chunk-WCAUUBHO.js.map +1 -0
- package/dist/{chunk-V3ENMW7G.js → chunk-WFRTHH3A.js} +3 -3
- package/dist/{chunk-DRKSYJZ2.js → chunk-WTJ3AY33.js} +1 -1
- package/dist/{chunk-DRKSYJZ2.js.map → chunk-WTJ3AY33.js.map} +1 -1
- package/dist/{chunk-XMEIVWAS.js → chunk-WUQ3MTPF.js} +11 -5
- package/dist/{chunk-XMEIVWAS.js.map → chunk-WUQ3MTPF.js.map} +1 -1
- package/dist/{chunk-4VCWL2IG.js → chunk-XAXJWXI4.js} +92 -59
- package/dist/chunk-XAXJWXI4.js.map +1 -0
- package/dist/{chunk-B66SC72V.js → chunk-Y5Y7XHVU.js} +4 -4
- package/dist/{chunk-FMYHWKGG.js → chunk-YO2LTXB4.js} +66 -16
- package/dist/chunk-YO2LTXB4.js.map +1 -0
- package/dist/{chunk-TUQF577Z.js → chunk-ZUAZHDKP.js} +40 -41
- package/dist/chunk-ZUAZHDKP.js.map +1 -0
- package/dist/commands/build/marketplace.js +98 -121
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +8 -8
- package/dist/commands/compile.js +19 -24
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/doctor.js +220 -79
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +549 -75
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +26 -21
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/init.js +41 -39
- package/dist/commands/list.js +11 -11
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/new/marketplace.js +243 -0
- package/dist/commands/new/marketplace.js.map +1 -0
- package/dist/commands/search.js +16 -14
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/share.js +67 -0
- package/dist/commands/share.js.map +1 -0
- package/dist/commands/uninstall.js +61 -74
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +9 -9
- package/dist/commands/update.js.map +1 -1
- package/dist/components/common/prompt-confirm.js +1 -1
- package/dist/components/common/removal-plan-confirm.js +10 -0
- package/dist/components/common/select-list.js +2 -2
- package/dist/components/wizard/category-grid.js +5 -5
- package/dist/components/wizard/checkbox-grid.js +5 -5
- package/dist/components/wizard/domain-selection.js +11 -11
- package/dist/components/wizard/run-wizard-session.js +29 -28
- package/dist/components/wizard/scroll-affordance.js +2 -2
- package/dist/components/wizard/skill-agent-summary.js +6 -6
- package/dist/components/wizard/source-grid.js +6 -6
- package/dist/components/wizard/stack-selection.js +8 -8
- package/dist/components/wizard/step-agents.js +10 -11
- package/dist/components/wizard/step-build.js +9 -9
- package/dist/components/wizard/step-confirm.js +10 -10
- package/dist/components/wizard/step-sources.js +10 -10
- package/dist/components/wizard/step-stack.js +9 -9
- package/dist/components/wizard/summary-panel.js +9 -9
- package/dist/components/wizard/toast.js +2 -2
- package/dist/components/wizard/wizard-layout.js +14 -14
- package/dist/components/wizard/wizard-tabs.js +2 -2
- package/dist/components/wizard/wizard.js +27 -27
- package/dist/copy-local-skills-NSUTBVLJ.js +14 -0
- package/dist/hooks/init.js +42 -62
- package/dist/hooks/init.js.map +1 -1
- package/dist/load-agent-defs-X4E57I2U.js +15 -0
- package/dist/{loader-JIZDTR4G.js → loader-G6BFG2VA.js} +3 -3
- package/dist/recompile-project-agents-JE4MM72I.js +20 -0
- package/dist/{source-loader-OE6EJFPU.js → source-loader-3DL3NYUX.js} +7 -5
- package/dist/source-loader-3DL3NYUX.js.map +1 -0
- package/dist/src/agents/developer/ai-developer/critical-reminders.md +1 -1
- package/dist/src/agents/developer/ai-developer/critical-requirements.md +1 -1
- package/dist/src/agents/developer/ai-developer/identity.md +1 -1
- package/dist/src/agents/developer/ai-developer/playbook.md +1 -1
- package/dist/src/agents/developer/api-developer/identity.md +1 -1
- package/dist/src/agents/developer/cli-developer/identity.md +1 -1
- package/dist/src/agents/developer/web-developer/identity.md +1 -1
- package/dist/src/agents/meta/codex-keeper/identity.md +1 -1
- package/dist/src/agents/meta/convention-keeper/identity.md +1 -1
- package/dist/src/agents/meta/skill-summoner/identity.md +1 -1
- package/dist/src/agents/researcher/ai-researcher/identity.md +1 -1
- package/dist/src/agents/researcher/api-researcher/identity.md +1 -1
- package/dist/src/agents/researcher/cli-researcher/identity.md +1 -1
- package/dist/src/agents/researcher/web-researcher/identity.md +1 -1
- package/dist/src/agents/reviewer/reviewer/playbook.md +1 -1
- package/dist/src/agents/tester/ai-tester/identity.md +1 -1
- package/dist/src/agents/tester/api-tester/critical-reminders.md +1 -1
- package/dist/src/agents/tester/api-tester/critical-requirements.md +1 -1
- package/dist/src/agents/tester/api-tester/identity.md +2 -2
- package/dist/src/agents/tester/cli-tester/identity.md +1 -1
- package/dist/src/agents/tester/web-tester/identity.md +3 -3
- package/dist/stores/wizard-store.js +7 -5
- package/package.json +10 -7
- package/src/agents/developer/ai-developer/critical-reminders.md +1 -1
- package/src/agents/developer/ai-developer/critical-requirements.md +1 -1
- package/src/agents/developer/ai-developer/identity.md +1 -1
- package/src/agents/developer/ai-developer/playbook.md +1 -1
- package/src/agents/developer/api-developer/identity.md +1 -1
- package/src/agents/developer/cli-developer/identity.md +1 -1
- package/src/agents/developer/web-developer/identity.md +1 -1
- package/src/agents/meta/codex-keeper/identity.md +1 -1
- package/src/agents/meta/convention-keeper/identity.md +1 -1
- package/src/agents/meta/skill-summoner/identity.md +1 -1
- package/src/agents/researcher/ai-researcher/identity.md +1 -1
- package/src/agents/researcher/api-researcher/identity.md +1 -1
- package/src/agents/researcher/cli-researcher/identity.md +1 -1
- package/src/agents/researcher/web-researcher/identity.md +1 -1
- package/src/agents/reviewer/reviewer/playbook.md +1 -1
- package/src/agents/tester/ai-tester/identity.md +1 -1
- package/src/agents/tester/api-tester/critical-reminders.md +1 -1
- package/src/agents/tester/api-tester/critical-requirements.md +1 -1
- package/src/agents/tester/api-tester/identity.md +2 -2
- package/src/agents/tester/cli-tester/identity.md +1 -1
- package/src/agents/tester/web-tester/identity.md +3 -3
- package/src/schemas/custom-metadata.schema.json +3 -0
- package/src/schemas/metadata.schema.json +3 -0
- package/src/schemas/project-config.schema.json +4 -8
- package/src/schemas/project-source-config.schema.json +2 -2
- package/dist/chunk-4VCWL2IG.js.map +0 -1
- package/dist/chunk-5MFJ24VM.js.map +0 -1
- package/dist/chunk-7VZV4O6B.js.map +0 -1
- package/dist/chunk-AURY6RT6.js.map +0 -1
- package/dist/chunk-CBF4ZYV3.js.map +0 -1
- package/dist/chunk-FMYHWKGG.js.map +0 -1
- package/dist/chunk-GUDGCFSF.js.map +0 -1
- package/dist/chunk-JC7DBPRD.js.map +0 -1
- package/dist/chunk-MJFIO5SX.js.map +0 -1
- package/dist/chunk-OJJLYHM3.js +0 -34
- package/dist/chunk-OJJLYHM3.js.map +0 -1
- package/dist/chunk-PRJD5MMQ.js.map +0 -1
- package/dist/chunk-QQTYMW7N.js.map +0 -1
- package/dist/chunk-QUDQTO3O.js +0 -41
- package/dist/chunk-QUDQTO3O.js.map +0 -1
- package/dist/chunk-R54KIGN2.js.map +0 -1
- package/dist/chunk-TUQF577Z.js.map +0 -1
- package/dist/copy-local-skills-WVHJFRPK.js +0 -14
- package/dist/load-agent-defs-5OT54J5M.js +0 -15
- package/dist/recompile-project-agents-VREEPBDV.js +0 -20
- /package/dist/{chunk-LA3JPESW.js.map → chunk-4A4L3YIW.js.map} +0 -0
- /package/dist/{chunk-BZ4CZBOM.js.map → chunk-5F2YR5XV.js.map} +0 -0
- /package/dist/{chunk-CHNA5RVS.js.map → chunk-5OKLCVM4.js.map} +0 -0
- /package/dist/{chunk-K3O3YQYG.js.map → chunk-G47TDUK3.js.map} +0 -0
- /package/dist/{chunk-IXEDSKMH.js.map → chunk-HTYH7CKN.js.map} +0 -0
- /package/dist/{chunk-NSJ2S7R5.js.map → chunk-ILUVL7WM.js.map} +0 -0
- /package/dist/{chunk-NKCY2ULI.js.map → chunk-LJCNUP6M.js.map} +0 -0
- /package/dist/{chunk-Q5FLW4JG.js.map → chunk-OKH64JZE.js.map} +0 -0
- /package/dist/{chunk-WRRP47PY.js.map → chunk-PCC4LBKB.js.map} +0 -0
- /package/dist/{chunk-2IMYK4WN.js.map → chunk-PNMM5HNX.js.map} +0 -0
- /package/dist/{chunk-AKQ5QISO.js.map → chunk-QWVXOCXO.js.map} +0 -0
- /package/dist/{chunk-ONWEOS77.js.map → chunk-SY4X2LND.js.map} +0 -0
- /package/dist/{chunk-XGMOXMS4.js.map → chunk-TBOVYLQJ.js.map} +0 -0
- /package/dist/{chunk-6CNRMCFM.js.map → chunk-VPASBA7P.js.map} +0 -0
- /package/dist/{chunk-V3ENMW7G.js.map → chunk-WFRTHH3A.js.map} +0 -0
- /package/dist/{chunk-B66SC72V.js.map → chunk-Y5Y7XHVU.js.map} +0 -0
- /package/dist/{copy-local-skills-WVHJFRPK.js.map → components/common/removal-plan-confirm.js.map} +0 -0
- /package/dist/{load-agent-defs-5OT54J5M.js.map → copy-local-skills-NSUTBVLJ.js.map} +0 -0
- /package/dist/{loader-JIZDTR4G.js.map → load-agent-defs-X4E57I2U.js.map} +0 -0
- /package/dist/{recompile-project-agents-VREEPBDV.js.map → loader-G6BFG2VA.js.map} +0 -0
- /package/dist/{source-loader-OE6EJFPU.js.map → recompile-project-agents-JE4MM72I.js.map} +0 -0
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
AGENT_NAMES,
|
|
4
|
-
DOMAINS,
|
|
5
3
|
EFFORT_NAMES,
|
|
6
4
|
GlobalPairWriteViolation,
|
|
7
5
|
MODEL_NAMES,
|
|
8
|
-
SKILL_IDS,
|
|
9
6
|
agentFrontmatterValidationSchema,
|
|
10
7
|
assertGateToken,
|
|
11
8
|
copy,
|
|
@@ -17,7 +14,11 @@ import {
|
|
|
17
14
|
formatZodIssues,
|
|
18
15
|
getErrorMessage,
|
|
19
16
|
glob,
|
|
17
|
+
isAgentName,
|
|
20
18
|
isPathWithin,
|
|
19
|
+
isRecord,
|
|
20
|
+
isSkillAssignment,
|
|
21
|
+
isSkillId,
|
|
21
22
|
listDirectories,
|
|
22
23
|
loadAllAgents,
|
|
23
24
|
loadPluginSkills,
|
|
@@ -48,15 +49,17 @@ import {
|
|
|
48
49
|
warnUnknownFields,
|
|
49
50
|
withGateToken,
|
|
50
51
|
writeFile
|
|
51
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-XAXJWXI4.js";
|
|
52
53
|
import {
|
|
53
54
|
BUILT_IN_MATRIX,
|
|
54
55
|
allSkills,
|
|
56
|
+
byCategoryDeclarationOrder,
|
|
57
|
+
getCategoryDomain,
|
|
55
58
|
getSkillById,
|
|
56
59
|
hasSkill,
|
|
57
60
|
initializeMatrix,
|
|
58
61
|
matrix
|
|
59
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-RWOYPOMR.js";
|
|
60
63
|
import {
|
|
61
64
|
typedEntries,
|
|
62
65
|
typedFromEntries,
|
|
@@ -94,6 +97,7 @@ import {
|
|
|
94
97
|
PLUGIN_MANIFEST_DIR,
|
|
95
98
|
PLUGIN_MANIFEST_FILE,
|
|
96
99
|
PROJECT_ROOT,
|
|
100
|
+
PUBLIC_CATALOGUE_PACKAGE,
|
|
97
101
|
SCHEMA_PATHS,
|
|
98
102
|
SKILLS_DIR_PATH,
|
|
99
103
|
SKILL_CATEGORIES_PATH,
|
|
@@ -103,8 +107,9 @@ import {
|
|
|
103
107
|
STANDARD_DIRS,
|
|
104
108
|
STANDARD_FILES,
|
|
105
109
|
YAML_FORMATTING,
|
|
110
|
+
editorConfigUrl,
|
|
106
111
|
marketplaceManifestPath
|
|
107
|
-
} from "./chunk-
|
|
112
|
+
} from "./chunk-IO5YBKHV.js";
|
|
108
113
|
import {
|
|
109
114
|
defaultCategories,
|
|
110
115
|
defaultRules,
|
|
@@ -113,8 +118,8 @@ import {
|
|
|
113
118
|
|
|
114
119
|
// src/cli/lib/loading/source-loader.ts
|
|
115
120
|
import os15 from "os";
|
|
116
|
-
import { unique as
|
|
117
|
-
import
|
|
121
|
+
import { unique as unique7 } from "remeda";
|
|
122
|
+
import path28 from "path";
|
|
118
123
|
|
|
119
124
|
// src/cli/lib/installation/is-home-directory.ts
|
|
120
125
|
import fs from "fs";
|
|
@@ -137,17 +142,15 @@ var METADATA_KEYS = {
|
|
|
137
142
|
USAGE_GUIDANCE: "usageGuidance"
|
|
138
143
|
};
|
|
139
144
|
var LOCAL_DEFAULTS = {
|
|
140
|
-
|
|
141
|
-
// placeholder written into starter files for the user to replace
|
|
142
|
-
CATEGORY: "dummy-category",
|
|
143
|
-
AUTHOR: "@dummy-author",
|
|
144
|
-
DOMAIN: "dummy"
|
|
145
|
+
AUTHOR: "@dummy-author"
|
|
145
146
|
};
|
|
146
147
|
var SKILL_CONTENT_FILES = [STANDARD_FILES.SKILL_MD, STANDARD_FILES.REFERENCE_MD];
|
|
147
148
|
var SKILL_CONTENT_DIRS = [STANDARD_DIRS.EXAMPLES, STANDARD_DIRS.SCRIPTS];
|
|
148
149
|
|
|
149
150
|
// src/cli/lib/configuration/config.ts
|
|
150
151
|
import os3 from "os";
|
|
152
|
+
import path3 from "path";
|
|
153
|
+
import { z } from "zod";
|
|
151
154
|
|
|
152
155
|
// src/cli/lib/configuration/config-loader.ts
|
|
153
156
|
import path from "path";
|
|
@@ -157,12 +160,41 @@ var CONFIG_EXPORTS_PATH = path.resolve(
|
|
|
157
160
|
path.dirname(fileURLToPath(import.meta.url)),
|
|
158
161
|
"../../config-exports.ts"
|
|
159
162
|
);
|
|
163
|
+
var ConfigSchemaError = class extends Error {
|
|
164
|
+
constructor(configPath, issues) {
|
|
165
|
+
super(`Config validation failed at '${configPath}': ${issues}`);
|
|
166
|
+
this.configPath = configPath;
|
|
167
|
+
this.issues = issues;
|
|
168
|
+
this.name = "ConfigSchemaError";
|
|
169
|
+
}
|
|
170
|
+
configPath;
|
|
171
|
+
issues;
|
|
172
|
+
};
|
|
173
|
+
var ConfigDefaultExportError = class extends Error {
|
|
174
|
+
constructor(configPath) {
|
|
175
|
+
super(`Config at '${configPath}' has no default export`);
|
|
176
|
+
this.configPath = configPath;
|
|
177
|
+
this.name = "ConfigDefaultExportError";
|
|
178
|
+
}
|
|
179
|
+
configPath;
|
|
180
|
+
};
|
|
181
|
+
var ES_MODULE_MARKER = "__esModule";
|
|
182
|
+
function unwrapDefaultExport(namespace) {
|
|
183
|
+
if (isRecord(namespace) && namespace.default !== void 0) return namespace.default;
|
|
184
|
+
return namespace;
|
|
185
|
+
}
|
|
186
|
+
function declaresNoDefaultExport(namespace) {
|
|
187
|
+
return isRecord(namespace) && ES_MODULE_MARKER in namespace && !("default" in namespace);
|
|
188
|
+
}
|
|
189
|
+
function exportsNothing(value) {
|
|
190
|
+
return value == null || typeof value === "object" && Object.keys(value).length === 0;
|
|
191
|
+
}
|
|
160
192
|
async function loadConfig(configPath, schema) {
|
|
161
193
|
if (!await fileExists(configPath)) {
|
|
162
194
|
verbose(`Config not found at ${configPath}`);
|
|
163
195
|
return null;
|
|
164
196
|
}
|
|
165
|
-
let
|
|
197
|
+
let namespace;
|
|
166
198
|
try {
|
|
167
199
|
const jiti = createJiti(import.meta.url, {
|
|
168
200
|
moduleCache: false,
|
|
@@ -177,22 +209,24 @@ async function loadConfig(configPath, schema) {
|
|
|
177
209
|
"@agents-inc/cli/config": CONFIG_EXPORTS_PATH
|
|
178
210
|
}
|
|
179
211
|
});
|
|
180
|
-
|
|
212
|
+
namespace = await jiti.import(configPath);
|
|
181
213
|
} catch (error) {
|
|
182
214
|
throw new Error(`Failed to load config from '${configPath}': ${getErrorMessage(error)}`, {
|
|
183
215
|
cause: error
|
|
184
216
|
});
|
|
185
217
|
}
|
|
186
|
-
|
|
187
|
-
|
|
218
|
+
const raw = unwrapDefaultExport(namespace);
|
|
219
|
+
if (exportsNothing(raw)) {
|
|
220
|
+
verbose(`Config at ${configPath} exports nothing`);
|
|
188
221
|
return null;
|
|
189
222
|
}
|
|
223
|
+
if (declaresNoDefaultExport(namespace)) {
|
|
224
|
+
throw new ConfigDefaultExportError(configPath);
|
|
225
|
+
}
|
|
190
226
|
if (schema) {
|
|
191
227
|
const result = schema.safeParse(raw);
|
|
192
228
|
if (!result.success) {
|
|
193
|
-
throw new
|
|
194
|
-
`Config validation failed at '${configPath}': ${formatZodIssues(result.error.issues)}`
|
|
195
|
-
);
|
|
229
|
+
throw new ConfigSchemaError(configPath, formatZodIssues(result.error.issues));
|
|
196
230
|
}
|
|
197
231
|
return result.data;
|
|
198
232
|
}
|
|
@@ -219,7 +253,7 @@ function resolveInstallPaths(projectDir, scope = "project") {
|
|
|
219
253
|
|
|
220
254
|
// src/cli/lib/configuration/config.ts
|
|
221
255
|
var DEFAULT_SOURCE = `${GITHUB_SOURCE.GITHUB_PREFIX}agents-inc/skills`;
|
|
222
|
-
var SOURCE_ENV_VAR = "
|
|
256
|
+
var SOURCE_ENV_VAR = "CC_MARKETPLACE";
|
|
223
257
|
async function loadSourceConfig(dir, scope) {
|
|
224
258
|
const scopeLabel = scope === "project" ? "Project" : "Global";
|
|
225
259
|
const configPath = getProjectConfigPath(dir);
|
|
@@ -231,7 +265,9 @@ async function loadSourceConfig(dir, scope) {
|
|
|
231
265
|
try {
|
|
232
266
|
data = await loadConfig(configPath, projectSourceConfigSchema);
|
|
233
267
|
} catch (error) {
|
|
234
|
-
|
|
268
|
+
if (error instanceof ConfigSchemaError || error instanceof ConfigDefaultExportError)
|
|
269
|
+
throw error;
|
|
270
|
+
verbose(`Failed to load ${scope} config at ${configPath}: ${getErrorMessage(error)}`);
|
|
235
271
|
return null;
|
|
236
272
|
}
|
|
237
273
|
if (!data) return null;
|
|
@@ -258,33 +294,33 @@ async function loadOwnProjectSourceConfig(projectDir) {
|
|
|
258
294
|
async function resolveSource(request) {
|
|
259
295
|
const { caller, flag, projectDir } = request;
|
|
260
296
|
const effective = await loadEffectiveSourceConfig(projectDir);
|
|
261
|
-
const
|
|
262
|
-
const marketplaceLabel =
|
|
297
|
+
const marketplaceName = effective?.config.marketplaceName;
|
|
298
|
+
const marketplaceLabel = marketplaceName !== void 0 && { marketplace: marketplaceName };
|
|
263
299
|
if (flag !== void 0) {
|
|
264
300
|
assertNamedSourceUsable(flag);
|
|
265
|
-
verbose(`
|
|
301
|
+
verbose(`Marketplace named by this run: ${flag}`);
|
|
266
302
|
return { source: flag, sourceOrigin: "flag", ...marketplaceLabel };
|
|
267
303
|
}
|
|
268
304
|
const envSource = caller === "init" ? readEnvSource() : void 0;
|
|
269
305
|
if (envSource !== void 0) {
|
|
270
306
|
return { source: envSource, sourceOrigin: "env", ...marketplaceLabel };
|
|
271
307
|
}
|
|
272
|
-
if (effective?.config.
|
|
273
|
-
verbose(`
|
|
308
|
+
if (effective?.config.marketplace) {
|
|
309
|
+
verbose(`Marketplace from ${effective.origin} config: ${effective.config.marketplace}`);
|
|
274
310
|
return {
|
|
275
|
-
source: effective.config.
|
|
311
|
+
source: effective.config.marketplace,
|
|
276
312
|
sourceOrigin: effective.origin,
|
|
277
313
|
...marketplaceLabel
|
|
278
314
|
};
|
|
279
315
|
}
|
|
280
|
-
verbose(`Using default
|
|
316
|
+
verbose(`Using default marketplace: ${DEFAULT_SOURCE}`);
|
|
281
317
|
return { source: DEFAULT_SOURCE, sourceOrigin: "default", ...marketplaceLabel };
|
|
282
318
|
}
|
|
283
|
-
var NAMED_SOURCE_LABEL = "The
|
|
319
|
+
var NAMED_SOURCE_LABEL = "The marketplace";
|
|
284
320
|
function assertNamedSourceUsable(flag) {
|
|
285
321
|
if (flag.trim() === "") {
|
|
286
322
|
throw new Error(
|
|
287
|
-
`${NAMED_SOURCE_LABEL} cannot be empty. Provide a valid
|
|
323
|
+
`${NAMED_SOURCE_LABEL} cannot be empty. Provide a valid marketplace: a local directory path or a git repository URL (e.g., './my-skills' or 'https://github.com/user/repo')`
|
|
288
324
|
);
|
|
289
325
|
}
|
|
290
326
|
validateSourceFormat(flag.trim(), NAMED_SOURCE_LABEL);
|
|
@@ -294,19 +330,19 @@ function readEnvSource() {
|
|
|
294
330
|
if (!envValue) return void 0;
|
|
295
331
|
const trimmed = envValue.trim();
|
|
296
332
|
if (trimmed === "") {
|
|
297
|
-
warn(`${SOURCE_ENV_VAR} is set but empty \u2014 ignoring and falling back to next
|
|
333
|
+
warn(`${SOURCE_ENV_VAR} is set but empty \u2014 ignoring and falling back to the next rung.`);
|
|
298
334
|
return void 0;
|
|
299
335
|
}
|
|
300
336
|
try {
|
|
301
337
|
validateSourceFormat(trimmed, SOURCE_ENV_VAR);
|
|
302
338
|
} catch (error) {
|
|
303
339
|
warn(
|
|
304
|
-
`${SOURCE_ENV_VAR} has an invalid value \u2014 ignoring and falling back to next
|
|
340
|
+
`${SOURCE_ENV_VAR} has an invalid value \u2014 ignoring and falling back to the next rung.
|
|
305
341
|
${getErrorMessage(error)}`
|
|
306
342
|
);
|
|
307
343
|
return void 0;
|
|
308
344
|
}
|
|
309
|
-
verbose(`
|
|
345
|
+
verbose(`Marketplace from ${SOURCE_ENV_VAR} env var: ${trimmed}`);
|
|
310
346
|
return trimmed;
|
|
311
347
|
}
|
|
312
348
|
async function resolvePrimarySourceEntry(projectDir) {
|
|
@@ -340,7 +376,7 @@ function validateSourceFormat(source, flagName) {
|
|
|
340
376
|
throw new Error(
|
|
341
377
|
`${flagName} contains invalid characters.
|
|
342
378
|
|
|
343
|
-
|
|
379
|
+
Marketplace values must not contain null bytes.
|
|
344
380
|
Examples:
|
|
345
381
|
${flagName} ./my-skills
|
|
346
382
|
${flagName} github:user/repo`
|
|
@@ -350,7 +386,7 @@ Examples:
|
|
|
350
386
|
throw new Error(
|
|
351
387
|
`${flagName} value is too long (${source.length} characters, max ${MAX_SOURCE_LENGTH}).
|
|
352
388
|
|
|
353
|
-
Provide a shorter
|
|
389
|
+
Provide a shorter marketplace path or URL.
|
|
354
390
|
Examples:
|
|
355
391
|
${flagName} ./my-skills
|
|
356
392
|
${flagName} github:user/repo`
|
|
@@ -379,7 +415,7 @@ Examples:
|
|
|
379
415
|
throw new Error(
|
|
380
416
|
`${flagName} contains path traversal in URL: "${source}"
|
|
381
417
|
|
|
382
|
-
Remote
|
|
418
|
+
Remote marketplace URLs must not contain '..' sequences.
|
|
383
419
|
Examples:
|
|
384
420
|
${flagName} github:user/repo
|
|
385
421
|
${flagName} https://github.com/user/repo`
|
|
@@ -411,7 +447,7 @@ Examples:
|
|
|
411
447
|
throw new Error(
|
|
412
448
|
`${flagName} points to a private or reserved IP address: "${source}"
|
|
413
449
|
|
|
414
|
-
|
|
450
|
+
Marketplace URLs must not target private network addresses.
|
|
415
451
|
Use a public hostname instead.
|
|
416
452
|
Examples:
|
|
417
453
|
${flagName} https://github.com/user/repo
|
|
@@ -424,7 +460,7 @@ function validateGitShorthand(source, repoPath, flagName) {
|
|
|
424
460
|
throw new Error(
|
|
425
461
|
`${flagName} has an invalid repository reference: "${source}"
|
|
426
462
|
|
|
427
|
-
Git shorthand
|
|
463
|
+
Git shorthand marketplaces require an owner/repo format.
|
|
428
464
|
Examples:
|
|
429
465
|
${flagName} github:user/repo
|
|
430
466
|
${flagName} gh:organization/skills`
|
|
@@ -437,7 +473,7 @@ function validateLocalPath(source, flagName) {
|
|
|
437
473
|
throw new Error(
|
|
438
474
|
`${flagName} contains invalid characters: "${source}"
|
|
439
475
|
|
|
440
|
-
|
|
476
|
+
Marketplace paths must not contain control characters.
|
|
441
477
|
Examples:
|
|
442
478
|
${flagName} ./my-skills
|
|
443
479
|
${flagName} /home/user/skills`
|
|
@@ -459,6 +495,24 @@ Examples:
|
|
|
459
495
|
function isDefaultSource(source) {
|
|
460
496
|
return source === DEFAULT_SOURCE;
|
|
461
497
|
}
|
|
498
|
+
var packageIdentitySchema = z.object({ name: z.string() });
|
|
499
|
+
async function isPublicCatalogueCheckout(basePath) {
|
|
500
|
+
const raw = await readFileOptional(path3.join(basePath, STANDARD_FILES.PACKAGE_JSON));
|
|
501
|
+
return declaredPackageName(raw) === PUBLIC_CATALOGUE_PACKAGE;
|
|
502
|
+
}
|
|
503
|
+
function declaredPackageName(raw) {
|
|
504
|
+
let json;
|
|
505
|
+
try {
|
|
506
|
+
json = JSON.parse(raw);
|
|
507
|
+
} catch {
|
|
508
|
+
return null;
|
|
509
|
+
}
|
|
510
|
+
const parsed = packageIdentitySchema.safeParse(json);
|
|
511
|
+
return parsed.success ? parsed.data.name : null;
|
|
512
|
+
}
|
|
513
|
+
async function offersBuiltInStacks(basePath, source) {
|
|
514
|
+
return isDefaultSource(source) || await isPublicCatalogueCheckout(basePath);
|
|
515
|
+
}
|
|
462
516
|
function isLocalSource(source) {
|
|
463
517
|
if (source.startsWith("/") || source.startsWith(".")) {
|
|
464
518
|
return true;
|
|
@@ -467,7 +521,7 @@ function isLocalSource(source) {
|
|
|
467
521
|
if (!hasRemoteProtocol) {
|
|
468
522
|
if (source.includes("..") || source.includes("~")) {
|
|
469
523
|
throw new Error(
|
|
470
|
-
`Invalid
|
|
524
|
+
`Invalid marketplace path: ${source}. Path traversal patterns like '..' and '~' are not allowed for security reasons. Use absolute paths or remote URLs instead (e.g., '/home/user/skills' or 'https://github.com/user/repo').`
|
|
471
525
|
);
|
|
472
526
|
}
|
|
473
527
|
}
|
|
@@ -478,7 +532,7 @@ function isLocalSource(source) {
|
|
|
478
532
|
import { groupBy as groupBy2, indexBy, partition } from "remeda";
|
|
479
533
|
|
|
480
534
|
// ../matrix/src/vendor/generated/source-types.ts
|
|
481
|
-
var
|
|
535
|
+
var SKILL_IDS = [
|
|
482
536
|
"ai-infrastructure-huggingface-inference",
|
|
483
537
|
"ai-infrastructure-litellm",
|
|
484
538
|
"ai-infrastructure-modal",
|
|
@@ -822,7 +876,7 @@ var CATEGORIES = [
|
|
|
822
876
|
"web-ui-kit",
|
|
823
877
|
"web-utilities"
|
|
824
878
|
];
|
|
825
|
-
var
|
|
879
|
+
var DOMAINS = [
|
|
826
880
|
"ai",
|
|
827
881
|
"api",
|
|
828
882
|
"cli",
|
|
@@ -833,7 +887,7 @@ var DOMAINS2 = [
|
|
|
833
887
|
"shared",
|
|
834
888
|
"web"
|
|
835
889
|
];
|
|
836
|
-
var
|
|
890
|
+
var AGENT_NAMES = [
|
|
837
891
|
"agent-summoner",
|
|
838
892
|
"ai-developer",
|
|
839
893
|
"ai-researcher",
|
|
@@ -10517,89 +10571,68 @@ var BUILT_IN_MATRIX2 = {
|
|
|
10517
10571
|
generatedAt: "build"
|
|
10518
10572
|
};
|
|
10519
10573
|
|
|
10520
|
-
// ../matrix/src/
|
|
10521
|
-
import { z } from "zod";
|
|
10522
|
-
|
|
10523
|
-
|
|
10524
|
-
var
|
|
10525
|
-
|
|
10526
|
-
|
|
10527
|
-
|
|
10528
|
-
|
|
10529
|
-
|
|
10530
|
-
var AgentNameSchema = z.enum(AGENT_NAMES2);
|
|
10531
|
-
var ModelNameSchema = z.enum(MODEL_NAMES2);
|
|
10532
|
-
var CategoryDefinitionSchema = z.object({
|
|
10533
|
-
id: CategorySchema,
|
|
10534
|
-
displayName: z.string(),
|
|
10535
|
-
description: z.string(),
|
|
10574
|
+
// ../matrix/src/built-in-matrix.ts
|
|
10575
|
+
import { z as z2 } from "zod";
|
|
10576
|
+
var domainIdSchema = z2.enum(DOMAINS);
|
|
10577
|
+
var skillIdSchema = z2.enum(SKILL_IDS);
|
|
10578
|
+
var categorySchema = z2.enum(CATEGORIES);
|
|
10579
|
+
var agentNameSchema = z2.enum(AGENT_NAMES);
|
|
10580
|
+
var categoryDefinitionSchema = z2.object({
|
|
10581
|
+
id: categorySchema,
|
|
10582
|
+
displayName: z2.string(),
|
|
10583
|
+
description: z2.string(),
|
|
10536
10584
|
// Optional in the CLI's type. Present on all 89 built-in categories today; a category without
|
|
10537
10585
|
// one cannot be placed in the UI, so the read model drops it rather than failing the whole boot.
|
|
10538
|
-
domain:
|
|
10539
|
-
exclusive:
|
|
10540
|
-
required:
|
|
10541
|
-
order:
|
|
10586
|
+
domain: domainIdSchema.exactOptional(),
|
|
10587
|
+
exclusive: z2.boolean(),
|
|
10588
|
+
required: z2.boolean(),
|
|
10589
|
+
order: z2.number()
|
|
10542
10590
|
});
|
|
10543
|
-
var
|
|
10544
|
-
skillId:
|
|
10545
|
-
reason:
|
|
10591
|
+
var skillRelationSchema = z2.object({
|
|
10592
|
+
skillId: skillIdSchema,
|
|
10593
|
+
reason: z2.string()
|
|
10546
10594
|
});
|
|
10547
|
-
var
|
|
10548
|
-
skillIds:
|
|
10549
|
-
needsAny:
|
|
10550
|
-
reason:
|
|
10595
|
+
var skillRequirementSchema = z2.object({
|
|
10596
|
+
skillIds: z2.array(skillIdSchema),
|
|
10597
|
+
needsAny: z2.boolean(),
|
|
10598
|
+
reason: z2.string()
|
|
10551
10599
|
});
|
|
10552
|
-
var
|
|
10553
|
-
id:
|
|
10554
|
-
slug:
|
|
10555
|
-
displayName:
|
|
10556
|
-
description:
|
|
10557
|
-
category:
|
|
10558
|
-
conflictsWith:
|
|
10559
|
-
discourages:
|
|
10560
|
-
requires:
|
|
10600
|
+
var resolvedSkillSchema = z2.object({
|
|
10601
|
+
id: skillIdSchema,
|
|
10602
|
+
slug: z2.string(),
|
|
10603
|
+
displayName: z2.string(),
|
|
10604
|
+
description: z2.string(),
|
|
10605
|
+
category: categorySchema,
|
|
10606
|
+
conflictsWith: z2.array(skillRelationSchema),
|
|
10607
|
+
discourages: z2.array(skillRelationSchema),
|
|
10608
|
+
requires: z2.array(skillRequirementSchema)
|
|
10561
10609
|
});
|
|
10562
|
-
var
|
|
10563
|
-
id:
|
|
10564
|
-
name:
|
|
10565
|
-
description:
|
|
10610
|
+
var resolvedStackSchema = z2.object({
|
|
10611
|
+
id: z2.string(),
|
|
10612
|
+
name: z2.string(),
|
|
10613
|
+
description: z2.string(),
|
|
10566
10614
|
// agent id → category id → skill ids. Partial because a stack names the few
|
|
10567
10615
|
// agents it staffs, not the whole roster; the category keys are the one level
|
|
10568
10616
|
// nothing here reads, so they stay unvalidated strings.
|
|
10569
|
-
skills:
|
|
10570
|
-
|
|
10571
|
-
|
|
10617
|
+
skills: z2.partialRecord(
|
|
10618
|
+
agentNameSchema,
|
|
10619
|
+
z2.record(z2.string(), z2.array(skillIdSchema))
|
|
10572
10620
|
),
|
|
10573
|
-
allSkillIds:
|
|
10574
|
-
philosophy:
|
|
10621
|
+
allSkillIds: z2.array(skillIdSchema),
|
|
10622
|
+
philosophy: z2.string(),
|
|
10575
10623
|
// Never populated by the CLI today; the stack rail groups by it when it appears.
|
|
10576
|
-
group:
|
|
10624
|
+
group: z2.string().exactOptional()
|
|
10577
10625
|
});
|
|
10578
|
-
var
|
|
10626
|
+
var builtInMatrixSchema = z2.object({
|
|
10579
10627
|
// Stamped into every seed payload so a consumer can explain skipped ids.
|
|
10580
|
-
version:
|
|
10581
|
-
categories:
|
|
10582
|
-
skills:
|
|
10583
|
-
suggestedStacks:
|
|
10584
|
-
});
|
|
10585
|
-
var AgentDefinitionSchema = z.object({
|
|
10586
|
-
id: AgentNameSchema,
|
|
10587
|
-
title: z.string(),
|
|
10588
|
-
description: z.string(),
|
|
10589
|
-
model: ModelNameSchema.optional(),
|
|
10590
|
-
tools: z.array(z.string()),
|
|
10591
|
-
// Not narrowed here: which roles are sayable is authored in the read model's
|
|
10592
|
-
// preload table, which reads this file — so the check lives where the list
|
|
10593
|
-
// does, in `flavorOf`, rather than being imported back into the boundary.
|
|
10594
|
-
flavor: z.string()
|
|
10628
|
+
version: z2.string(),
|
|
10629
|
+
categories: z2.record(z2.string(), categoryDefinitionSchema),
|
|
10630
|
+
skills: z2.record(z2.string(), resolvedSkillSchema),
|
|
10631
|
+
suggestedStacks: z2.array(resolvedStackSchema)
|
|
10595
10632
|
});
|
|
10596
|
-
var AgentDefinitionsSchema = z.record(
|
|
10597
|
-
z.string(),
|
|
10598
|
-
AgentDefinitionSchema
|
|
10599
|
-
);
|
|
10600
10633
|
|
|
10601
10634
|
// ../matrix/src/read-model/source.ts
|
|
10602
|
-
var MATRIX =
|
|
10635
|
+
var MATRIX = builtInMatrixSchema.parse(BUILT_IN_MATRIX2);
|
|
10603
10636
|
var MATRIX_VERSION = MATRIX.version;
|
|
10604
10637
|
|
|
10605
10638
|
// ../matrix/src/read-model/domains.ts
|
|
@@ -10636,7 +10669,7 @@ var DOMAIN_DESCRIPTIONS = {
|
|
|
10636
10669
|
meta: "Design patterns, code review, and research methodology",
|
|
10637
10670
|
shared: "Shared utilities and methodology"
|
|
10638
10671
|
};
|
|
10639
|
-
var DOMAIN_IDS = new Set(
|
|
10672
|
+
var DOMAIN_IDS = new Set(DOMAINS);
|
|
10640
10673
|
var isDomain = (domainId) => DOMAIN_IDS.has(domainId);
|
|
10641
10674
|
var agentDomainOf = (agentId) => {
|
|
10642
10675
|
const prefix = agentId.split("-")[0];
|
|
@@ -10664,7 +10697,7 @@ var toCatalogSkill = (skill, domainId) => ({
|
|
|
10664
10697
|
}))
|
|
10665
10698
|
});
|
|
10666
10699
|
var placeableCategories = (categories) => Object.values(categories).filter(
|
|
10667
|
-
(category) => category.domain !== void 0
|
|
10700
|
+
(category) => category.domain !== void 0 && isDomain(category.domain)
|
|
10668
10701
|
);
|
|
10669
10702
|
var byDomainThenAuthoredOrder = (a, b) => compareDomains(a.domain, b.domain) || a.order - b.order;
|
|
10670
10703
|
var toCatalogCategory = (category, skills) => ({
|
|
@@ -10686,27 +10719,29 @@ var toCatalogDomain = (id, categories) => ({
|
|
|
10686
10719
|
0
|
|
10687
10720
|
)
|
|
10688
10721
|
});
|
|
10689
|
-
var buildCatalog = () => {
|
|
10722
|
+
var buildCatalog = (matrix2) => {
|
|
10690
10723
|
const skillsByCategory = groupBy(
|
|
10691
|
-
Object.values(
|
|
10724
|
+
Object.values(matrix2.skills),
|
|
10692
10725
|
(skill) => skill.category
|
|
10693
10726
|
);
|
|
10694
|
-
const categories = placeableCategories(
|
|
10727
|
+
const categories = placeableCategories(matrix2.categories).sort(byDomainThenAuthoredOrder).map(
|
|
10695
10728
|
(category) => toCatalogCategory(category, skillsByCategory.get(category.id) ?? [])
|
|
10696
10729
|
);
|
|
10697
10730
|
const domains = [...groupBy(categories, (category) => category.domainId)].sort(([a], [b]) => compareDomains(a, b)).map(([id, domainCategories]) => toCatalogDomain(id, domainCategories));
|
|
10698
10731
|
const allSkills2 = categories.flatMap((category) => category.skills);
|
|
10699
10732
|
return {
|
|
10700
10733
|
domains,
|
|
10701
|
-
skillsById:
|
|
10702
|
-
categoriesById:
|
|
10734
|
+
skillsById: byId(allSkills2),
|
|
10735
|
+
categoriesById: byId(categories),
|
|
10703
10736
|
skillCount: allSkills2.length
|
|
10704
10737
|
};
|
|
10705
10738
|
};
|
|
10706
|
-
var
|
|
10707
|
-
var
|
|
10708
|
-
var
|
|
10709
|
-
var skillById = (
|
|
10739
|
+
var byId = (items) => Object.fromEntries(items.map((item) => [item.id, item]));
|
|
10740
|
+
var CATALOG = buildCatalog(MATRIX);
|
|
10741
|
+
var createSkillLookup = (catalog) => (skillId) => catalog.skillsById[skillId];
|
|
10742
|
+
var skillById = createSkillLookup(CATALOG);
|
|
10743
|
+
var SHIPPED_IDS = new Set(SKILL_IDS);
|
|
10744
|
+
var isShippedSkillId = (skillId) => SHIPPED_IDS.has(skillId);
|
|
10710
10745
|
|
|
10711
10746
|
// ../matrix/src/generated/agents.ts
|
|
10712
10747
|
var AGENT_DEFINITIONS = {
|
|
@@ -10874,6 +10909,31 @@ var AGENT_DEFINITIONS = {
|
|
|
10874
10909
|
}
|
|
10875
10910
|
};
|
|
10876
10911
|
|
|
10912
|
+
// ../matrix/src/built-in-agents.ts
|
|
10913
|
+
import { z as z3 } from "zod";
|
|
10914
|
+
|
|
10915
|
+
// ../matrix/src/vendor/matrix.ts
|
|
10916
|
+
var MODEL_NAMES2 = ["sonnet", "opus", "haiku", "fable", "inherit"];
|
|
10917
|
+
|
|
10918
|
+
// ../matrix/src/built-in-agents.ts
|
|
10919
|
+
var agentNameSchema2 = z3.enum(AGENT_NAMES);
|
|
10920
|
+
var modelNameSchema = z3.enum(MODEL_NAMES2);
|
|
10921
|
+
var agentDefinitionSchema = z3.object({
|
|
10922
|
+
id: agentNameSchema2,
|
|
10923
|
+
title: z3.string(),
|
|
10924
|
+
description: z3.string(),
|
|
10925
|
+
model: modelNameSchema.exactOptional(),
|
|
10926
|
+
tools: z3.array(z3.string()),
|
|
10927
|
+
// Not narrowed here: which roles are sayable is authored in the read model's
|
|
10928
|
+
// preload table — so the check lives where the list does, in `flavorOf`,
|
|
10929
|
+
// rather than the list being imported back into the boundary.
|
|
10930
|
+
flavor: z3.string()
|
|
10931
|
+
});
|
|
10932
|
+
var agentDefinitionsSchema = z3.record(
|
|
10933
|
+
z3.string(),
|
|
10934
|
+
agentDefinitionSchema
|
|
10935
|
+
);
|
|
10936
|
+
|
|
10877
10937
|
// ../matrix/src/read-model/preload-defaults.ts
|
|
10878
10938
|
var ROLE_FLAVORS = [
|
|
10879
10939
|
"developer",
|
|
@@ -11036,7 +11096,7 @@ var PRELOAD_DEFAULTS = {
|
|
|
11036
11096
|
// Shared — carried across every implementation domain
|
|
11037
11097
|
"shared-security-auth-security": ["developer", "researcher"]
|
|
11038
11098
|
};
|
|
11039
|
-
var KNOWN_SKILL_IDS = new Set(
|
|
11099
|
+
var KNOWN_SKILL_IDS = new Set(SKILL_IDS);
|
|
11040
11100
|
var KNOWN_AGENT_IDS = new Set(Object.keys(AGENT_DEFINITIONS));
|
|
11041
11101
|
var LISTABLE_FLAVORS = new Set(ROLE_FLAVORS);
|
|
11042
11102
|
var assertKnownSkill = (skillId) => {
|
|
@@ -11100,7 +11160,7 @@ var toSubAgentGroup = (domainId, agents) => ({
|
|
|
11100
11160
|
});
|
|
11101
11161
|
var buildSubAgentGroups = () => {
|
|
11102
11162
|
const agents = Object.values(
|
|
11103
|
-
|
|
11163
|
+
agentDefinitionsSchema.parse(AGENT_DEFINITIONS)
|
|
11104
11164
|
).map(toSubAgent);
|
|
11105
11165
|
return [...groupBy(agents, (agent) => agent.domainId)].sort(([a], [b]) => compareDomains(a, b)).map(([domainId, domainAgents]) => toSubAgentGroup(domainId, domainAgents));
|
|
11106
11166
|
};
|
|
@@ -11108,7 +11168,9 @@ var SUB_AGENT_GROUPS = buildSubAgentGroups();
|
|
|
11108
11168
|
var SUB_AGENTS_BY_ID = indexById(
|
|
11109
11169
|
SUB_AGENT_GROUPS.flatMap((group) => group.agents)
|
|
11110
11170
|
);
|
|
11111
|
-
var ROSTER_IDS = new Set(
|
|
11171
|
+
var ROSTER_IDS = new Set(AGENT_NAMES);
|
|
11172
|
+
var isAgentName2 = (agentId) => ROSTER_IDS.has(agentId);
|
|
11173
|
+
var subAgentById = (agentId) => isAgentName2(agentId) ? SUB_AGENTS_BY_ID[agentId] : void 0;
|
|
11112
11174
|
|
|
11113
11175
|
// ../matrix/src/read-model/assignment-defaults.ts
|
|
11114
11176
|
var ROSTER = SUB_AGENT_GROUPS.flatMap(
|
|
@@ -11129,40 +11191,82 @@ var isRoleCraftFor = (skill, agent) => {
|
|
|
11129
11191
|
const craft = CRAFT_CATEGORIES_BY_FLAVOR[agent.flavor];
|
|
11130
11192
|
return craft !== void 0 && craft.includes(skill.categoryId);
|
|
11131
11193
|
};
|
|
11132
|
-
var metaSkillReach = (
|
|
11133
|
-
const
|
|
11194
|
+
var metaSkillReach = (skill, rowFlavors) => {
|
|
11195
|
+
const listedFlavors = new Set(rowFlavors);
|
|
11134
11196
|
return ROSTER.filter(
|
|
11135
|
-
(agent) =>
|
|
11197
|
+
(agent) => listedFlavors.has(agent.flavor) || isRoleCraftFor(skill, agent)
|
|
11136
11198
|
);
|
|
11137
11199
|
};
|
|
11138
|
-
var targetsOf = (
|
|
11139
|
-
if (skill.domainId === "meta") return metaSkillReach(
|
|
11200
|
+
var targetsOf = (skill, rowFlavors) => {
|
|
11201
|
+
if (skill.domainId === "meta") return metaSkillReach(skill, rowFlavors);
|
|
11140
11202
|
if (skill.domainId === "shared") return NON_META_ROSTER;
|
|
11141
11203
|
return implementationDomainReach(skill.domainId);
|
|
11142
11204
|
};
|
|
11205
|
+
var taxonomyOf = (skill) => typeof skill === "string" ? skillById(skill) : skill;
|
|
11206
|
+
var shippedIdOf = (catalogued) => catalogued !== void 0 && isShippedSkillId(catalogued.id) ? catalogued.id : void 0;
|
|
11207
|
+
var rowFlavorsOf = (defaults, shippedId) => shippedId === void 0 ? [] : defaults[shippedId] ?? [];
|
|
11143
11208
|
var createAssignmentResolver = (defaults) => {
|
|
11144
11209
|
const resolveLoad = createLoadStateResolver(defaults);
|
|
11145
|
-
return (
|
|
11146
|
-
const
|
|
11147
|
-
if (!
|
|
11148
|
-
|
|
11149
|
-
|
|
11150
|
-
|
|
11151
|
-
|
|
11210
|
+
return (skill) => {
|
|
11211
|
+
const taxonomy = taxonomyOf(skill);
|
|
11212
|
+
if (!taxonomy) return [];
|
|
11213
|
+
const shippedId = shippedIdOf(skillById(taxonomy.id));
|
|
11214
|
+
const loadOn = (agentId) => shippedId === void 0 ? "lazy" : resolveLoad({ skillId: shippedId, agentId });
|
|
11215
|
+
return targetsOf(taxonomy, rowFlavorsOf(defaults, shippedId)).map(
|
|
11216
|
+
(agent) => ({ agentId: agent.id, load: loadOn(agent.id) })
|
|
11217
|
+
);
|
|
11152
11218
|
};
|
|
11153
11219
|
};
|
|
11154
11220
|
var resolveAssignment = createAssignmentResolver(PRELOAD_DEFAULTS);
|
|
11155
11221
|
|
|
11156
11222
|
// ../matrix/src/read-model/stacks.ts
|
|
11157
|
-
var
|
|
11158
|
-
var STACKS = parsedStacks.map((stack) => ({
|
|
11223
|
+
var toCatalogStack = (stack) => ({
|
|
11159
11224
|
id: stack.id,
|
|
11160
11225
|
name: stack.name,
|
|
11161
11226
|
description: stack.description,
|
|
11162
11227
|
philosophy: stack.philosophy,
|
|
11163
11228
|
...stack.group !== void 0 && { group: stack.group },
|
|
11164
11229
|
skillCount: stack.allSkillIds.length
|
|
11165
|
-
})
|
|
11230
|
+
});
|
|
11231
|
+
var buildStacks = (matrix2) => matrix2.suggestedStacks.map(toCatalogStack);
|
|
11232
|
+
var STACKS = buildStacks(MATRIX);
|
|
11233
|
+
var rosteredAgents = (stack) => Object.keys(stack.skills).map((agentId) => subAgentById(agentId)).filter((agent) => agent !== void 0).map((agent) => agent.id);
|
|
11234
|
+
var toAgentsBySkill = (stack) => {
|
|
11235
|
+
const agentsBySkill = {};
|
|
11236
|
+
for (const agentId of rosteredAgents(stack)) {
|
|
11237
|
+
for (const skillId of Object.values(stack.skills[agentId] ?? {}).flat()) {
|
|
11238
|
+
const agents = agentsBySkill[skillId] ??= [];
|
|
11239
|
+
if (!agents.includes(agentId)) agents.push(agentId);
|
|
11240
|
+
}
|
|
11241
|
+
}
|
|
11242
|
+
return agentsBySkill;
|
|
11243
|
+
};
|
|
11244
|
+
var toLoadByAgent = (skillId) => new Map(
|
|
11245
|
+
resolveAssignment(skillId).map(({ agentId, load }) => [agentId, load])
|
|
11246
|
+
);
|
|
11247
|
+
var toAssignmentsBySkill = (stack) => Object.fromEntries(
|
|
11248
|
+
Object.entries(toAgentsBySkill(stack)).map(([skillId, agentIds]) => {
|
|
11249
|
+
const loadByAgent = toLoadByAgent(skillId);
|
|
11250
|
+
return [
|
|
11251
|
+
skillId,
|
|
11252
|
+
agentIds.map((agentId) => ({
|
|
11253
|
+
agentId,
|
|
11254
|
+
load: loadByAgent.get(agentId) ?? "lazy"
|
|
11255
|
+
}))
|
|
11256
|
+
];
|
|
11257
|
+
})
|
|
11258
|
+
);
|
|
11259
|
+
var createStackExpander = (matrix2) => (stackId) => {
|
|
11260
|
+
const stack = matrix2.suggestedStacks.find(
|
|
11261
|
+
(candidate) => candidate.id === stackId
|
|
11262
|
+
);
|
|
11263
|
+
if (!stack) return void 0;
|
|
11264
|
+
return {
|
|
11265
|
+
skillIds: stack.allSkillIds,
|
|
11266
|
+
assignmentsBySkill: toAssignmentsBySkill(stack)
|
|
11267
|
+
};
|
|
11268
|
+
};
|
|
11269
|
+
var expandStack = createStackExpander(MATRIX);
|
|
11166
11270
|
|
|
11167
11271
|
// ../matrix/src/read-model/selection-defaults.ts
|
|
11168
11272
|
var DEFAULT_SELECTION_OPTIONS = {
|
|
@@ -11301,8 +11405,8 @@ var createSelectionSemantics = (catalog) => {
|
|
|
11301
11405
|
};
|
|
11302
11406
|
};
|
|
11303
11407
|
};
|
|
11304
|
-
var
|
|
11305
|
-
skills: Object.values(
|
|
11408
|
+
var catalogFactsOf = (matrix2) => ({
|
|
11409
|
+
skills: Object.values(matrix2.skills).map((skill) => ({
|
|
11306
11410
|
id: skill.id,
|
|
11307
11411
|
categoryId: skill.category,
|
|
11308
11412
|
conflictsWith: skill.conflictsWith.map((relation) => relation.skillId),
|
|
@@ -11316,10 +11420,10 @@ var shippedFacts = () => ({
|
|
|
11316
11420
|
}))
|
|
11317
11421
|
})),
|
|
11318
11422
|
exclusiveCategoryIds: new Set(
|
|
11319
|
-
Object.values(
|
|
11423
|
+
Object.values(matrix2.categories).filter((category) => category.exclusive).map((category) => category.id)
|
|
11320
11424
|
)
|
|
11321
11425
|
});
|
|
11322
|
-
var judgeSelection = createSelectionSemantics(
|
|
11426
|
+
var judgeSelection = createSelectionSemantics(catalogFactsOf(MATRIX));
|
|
11323
11427
|
|
|
11324
11428
|
// ../matrix/src/contract/selection-scenarios.ts
|
|
11325
11429
|
var DISCOURAGED_PAIRS = Object.values(CATALOG.skillsById).flatMap(
|
|
@@ -11327,82 +11431,185 @@ var DISCOURAGED_PAIRS = Object.values(CATALOG.skillsById).flatMap(
|
|
|
11327
11431
|
);
|
|
11328
11432
|
|
|
11329
11433
|
// ../matrix/src/seed.ts
|
|
11330
|
-
import { z as
|
|
11331
|
-
var SEED_VERSION =
|
|
11332
|
-
var seedModelSchema =
|
|
11333
|
-
var seedEffortSchema =
|
|
11434
|
+
import { z as z4 } from "zod";
|
|
11435
|
+
var SEED_VERSION = 5;
|
|
11436
|
+
var seedModelSchema = z4.enum(["opus", "fable", "sonnet", "haiku"]);
|
|
11437
|
+
var seedEffortSchema = z4.enum([
|
|
11334
11438
|
"low",
|
|
11335
11439
|
"medium",
|
|
11336
11440
|
"high",
|
|
11337
11441
|
"xhigh",
|
|
11338
11442
|
"max"
|
|
11339
11443
|
]);
|
|
11340
|
-
var seedLoadStateSchema =
|
|
11341
|
-
var seedSkillSchema =
|
|
11342
|
-
install:
|
|
11343
|
-
scope:
|
|
11444
|
+
var seedLoadStateSchema = z4.enum(["lazy", "preloaded"]);
|
|
11445
|
+
var seedSkillSchema = z4.object({
|
|
11446
|
+
install: z4.enum(["plugin", "eject"]),
|
|
11447
|
+
scope: z4.enum(["project", "global"]),
|
|
11344
11448
|
// Sub-agent id → load state; presence is assignment. Per (agent, skill),
|
|
11345
11449
|
// matching the granularity of the CLI's stack config.
|
|
11346
|
-
assignments:
|
|
11450
|
+
assignments: z4.record(z4.string(), seedLoadStateSchema)
|
|
11347
11451
|
});
|
|
11348
|
-
var seedAgentSchema =
|
|
11349
|
-
on:
|
|
11350
|
-
model: seedModelSchema.
|
|
11351
|
-
effort: seedEffortSchema.
|
|
11452
|
+
var seedAgentSchema = z4.object({
|
|
11453
|
+
on: z4.boolean().exactOptional(),
|
|
11454
|
+
model: seedModelSchema.exactOptional(),
|
|
11455
|
+
effort: seedEffortSchema.exactOptional(),
|
|
11352
11456
|
// Where this agent's front-matter is written: the project, or the user's own
|
|
11353
11457
|
// ~/.claude. Absent means the shared selection default — `global`, spelled
|
|
11354
11458
|
// once in `DEFAULT_SELECTION_OPTIONS` — so the resting choice never travels,
|
|
11355
11459
|
// exactly as a resting model does not.
|
|
11356
|
-
scope:
|
|
11460
|
+
scope: z4.enum(["project", "global"]).exactOptional()
|
|
11357
11461
|
});
|
|
11358
|
-
var
|
|
11359
|
-
|
|
11462
|
+
var MAX_EXTERNAL_SKILL_BYTES = 262144;
|
|
11463
|
+
var SKILL_MANIFEST = "SKILL.md";
|
|
11464
|
+
var treeBytes = (files) => {
|
|
11465
|
+
const encoder = new TextEncoder();
|
|
11466
|
+
return Object.values(files).reduce(
|
|
11467
|
+
(total, text) => total + encoder.encode(text).length,
|
|
11468
|
+
0
|
|
11469
|
+
);
|
|
11470
|
+
};
|
|
11471
|
+
var seedSkillTreeSchema = z4.record(z4.string().min(1), z4.string()).refine((files) => SKILL_MANIFEST in files, {
|
|
11472
|
+
message: `a skill directory must hold ${SKILL_MANIFEST}`
|
|
11473
|
+
}).refine((files) => treeBytes(files) <= MAX_EXTERNAL_SKILL_BYTES, {
|
|
11474
|
+
message: `a skill directory may not exceed ${String(MAX_EXTERNAL_SKILL_BYTES)} bytes`
|
|
11475
|
+
});
|
|
11476
|
+
var seedExternalSkillSchema = z4.object({
|
|
11477
|
+
displayName: z4.string().min(1),
|
|
11478
|
+
description: z4.string(),
|
|
11479
|
+
// A category of the catalogue this payload names — the placement the user
|
|
11480
|
+
// confirmed. Without it the skill has nowhere to render and no sub-agent
|
|
11481
|
+
// reach, which is the whole difference between a catalogue entry and an
|
|
11482
|
+
// orphan section.
|
|
11483
|
+
categoryId: z4.string().min(1),
|
|
11484
|
+
// GitHub's own `owner/name`.
|
|
11485
|
+
repo: z4.string().min(1),
|
|
11486
|
+
// The skill's DIRECTORY within it — `skills/docx`, never the SKILL.md.
|
|
11487
|
+
path: z4.string().min(1),
|
|
11488
|
+
files: seedSkillTreeSchema
|
|
11489
|
+
});
|
|
11490
|
+
var seedPayloadSchema = z4.object({
|
|
11491
|
+
v: z4.literal(SEED_VERSION),
|
|
11360
11492
|
// Diagnostics only. A mismatch with the consumer's matrix must not fail the
|
|
11361
11493
|
// decode — it explains why some ids were skipped.
|
|
11362
|
-
matrixVersion:
|
|
11363
|
-
stackId:
|
|
11494
|
+
matrixVersion: z4.string(),
|
|
11495
|
+
stackId: z4.string().nullable(),
|
|
11496
|
+
// Where the skills below are fetched from, in the form `--marketplace` takes
|
|
11497
|
+
// one: `github:acme/skills`, a URL, a local path. The ref alone — the name
|
|
11498
|
+
// its manifest gives it is read from the fetched marketplace.json, so
|
|
11499
|
+
// carrying that too would let a payload disagree with the repository it
|
|
11500
|
+
// names. Absent is the default public catalogue, which is why a payload that
|
|
11501
|
+
// installs from it looks exactly as it did before this field existed.
|
|
11502
|
+
marketplace: z4.string().exactOptional(),
|
|
11364
11503
|
// Sparse — presence is selection, exactly like the web store. `remembered`
|
|
11365
11504
|
// is deliberately absent: deselected setup never leaves the browser.
|
|
11366
|
-
skills:
|
|
11505
|
+
skills: z4.record(z4.string(), seedSkillSchema),
|
|
11506
|
+
// Skill id → its whole directory, for the ids above that no catalogue can
|
|
11507
|
+
// resolve. Keyed by the same id `skills` uses, so a selection reads one map
|
|
11508
|
+
// whichever kind of skill it names. Absent is the ordinary case — a payload
|
|
11509
|
+
// built from the catalogue alone — which is why one looks exactly as it did
|
|
11510
|
+
// before content travelled. Content is the expensive part of a payload, so an
|
|
11511
|
+
// added skill nobody selected has no entry here either.
|
|
11512
|
+
external: z4.record(z4.string(), seedExternalSkillSchema).exactOptional(),
|
|
11367
11513
|
// Sparse for the same reason: an agent resting on its own catalogue model
|
|
11368
11514
|
// with no pin has nothing to say, so it has no entry. Presence is a
|
|
11369
11515
|
// statement, not an install: what installs is decided by assignments and
|
|
11370
11516
|
// `on: true` alone, so a derived-off agent can still travel its overrides.
|
|
11371
11517
|
// Only an agent pinned *off* is omitted outright — with the assignment rows
|
|
11372
11518
|
// naming it, since the sharer's own counts exclude them.
|
|
11373
|
-
agents:
|
|
11519
|
+
agents: z4.record(z4.string(), seedAgentSchema)
|
|
11520
|
+
});
|
|
11521
|
+
|
|
11522
|
+
// ../matrix/src/matrix-schema.ts
|
|
11523
|
+
import { z as z5 } from "zod";
|
|
11524
|
+
var idSchema = z5.string().min(1);
|
|
11525
|
+
var matrixCategorySchema = z5.object({
|
|
11526
|
+
id: idSchema,
|
|
11527
|
+
displayName: z5.string(),
|
|
11528
|
+
description: z5.string(),
|
|
11529
|
+
// Optional in the CLI's type. A category without one cannot be placed in the
|
|
11530
|
+
// UI, so a consumer drops it rather than failing the whole catalogue.
|
|
11531
|
+
domain: z5.string().exactOptional(),
|
|
11532
|
+
exclusive: z5.boolean(),
|
|
11533
|
+
required: z5.boolean(),
|
|
11534
|
+
order: z5.number()
|
|
11535
|
+
});
|
|
11536
|
+
var skillRelationSchema2 = z5.object({
|
|
11537
|
+
skillId: idSchema,
|
|
11538
|
+
reason: z5.string()
|
|
11539
|
+
});
|
|
11540
|
+
var skillRequirementSchema2 = z5.object({
|
|
11541
|
+
skillIds: z5.array(idSchema),
|
|
11542
|
+
needsAny: z5.boolean(),
|
|
11543
|
+
reason: z5.string()
|
|
11544
|
+
});
|
|
11545
|
+
var matrixSkillSchema = z5.object({
|
|
11546
|
+
id: idSchema,
|
|
11547
|
+
slug: z5.string(),
|
|
11548
|
+
displayName: z5.string(),
|
|
11549
|
+
description: z5.string(),
|
|
11550
|
+
category: idSchema,
|
|
11551
|
+
conflictsWith: z5.array(skillRelationSchema2),
|
|
11552
|
+
discourages: z5.array(skillRelationSchema2),
|
|
11553
|
+
requires: z5.array(skillRequirementSchema2)
|
|
11554
|
+
});
|
|
11555
|
+
var matrixStackSchema = z5.object({
|
|
11556
|
+
id: idSchema,
|
|
11557
|
+
name: z5.string(),
|
|
11558
|
+
description: z5.string(),
|
|
11559
|
+
// agent id → category id → skill ids. A stack names the few agents it staffs
|
|
11560
|
+
// rather than the whole roster, and the agent roster is as marketplace-owned
|
|
11561
|
+
// as the skills are, so neither level is narrowed.
|
|
11562
|
+
skills: z5.record(z5.string(), z5.record(z5.string(), z5.array(idSchema))),
|
|
11563
|
+
allSkillIds: z5.array(idSchema),
|
|
11564
|
+
philosophy: z5.string(),
|
|
11565
|
+
// Never populated by the CLI today; a stack rail groups by it when it appears.
|
|
11566
|
+
group: z5.string().exactOptional()
|
|
11567
|
+
});
|
|
11568
|
+
var matrixSchema = z5.object({
|
|
11569
|
+
version: z5.string(),
|
|
11570
|
+
categories: z5.record(z5.string(), matrixCategorySchema),
|
|
11571
|
+
skills: z5.record(z5.string(), matrixSkillSchema),
|
|
11572
|
+
suggestedStacks: z5.array(matrixStackSchema)
|
|
11374
11573
|
});
|
|
11375
11574
|
|
|
11376
11575
|
// ../matrix/src/skill-index.ts
|
|
11377
|
-
import { z as
|
|
11378
|
-
var skillIndexEntrySchema =
|
|
11576
|
+
import { z as z6 } from "zod";
|
|
11577
|
+
var skillIndexEntrySchema = z6.object({
|
|
11379
11578
|
// The skill's own name — its frontmatter `name` where there is one, its
|
|
11380
11579
|
// directory name where there is not. Never empty: a skill with neither is
|
|
11381
11580
|
// not addressable and does not make it into the index.
|
|
11382
|
-
name:
|
|
11581
|
+
name: z6.string().min(1),
|
|
11383
11582
|
// Frontmatter `description`, or the SKILL.md's first heading. Empty when the
|
|
11384
11583
|
// file offers neither, which is a thin result rather than an invalid one.
|
|
11385
|
-
description:
|
|
11584
|
+
description: z6.string(),
|
|
11386
11585
|
// GitHub's own `owner/name`, so a result can be attributed and fetched
|
|
11387
11586
|
// without a second lookup.
|
|
11388
|
-
repo:
|
|
11587
|
+
repo: z6.string().min(1),
|
|
11389
11588
|
// The skill DIRECTORY within that repo — `skills/docx`, not
|
|
11390
11589
|
// `skills/docx/SKILL.md`. A skill is a directory in every consumer of this
|
|
11391
11590
|
// index, and the file is only how the directory proves itself.
|
|
11392
|
-
path:
|
|
11591
|
+
path: z6.string().min(1),
|
|
11393
11592
|
// The repository's star count when the index was built. A property of the
|
|
11394
11593
|
// repo rather than the skill, repeated per entry because the dialog ranks
|
|
11395
11594
|
// and badges individual results.
|
|
11396
|
-
stars:
|
|
11595
|
+
stars: z6.number().int().nonnegative(),
|
|
11596
|
+
// How much the skill's whole DIRECTORY weighs — the sum over its blobs of the
|
|
11597
|
+
// sizes GitHub reported for them in the tree listing the crawl already made,
|
|
11598
|
+
// never a download. Repeated per entry because the cap it is read against is
|
|
11599
|
+
// per skill: `MAX_EXTERNAL_SKILL_BYTES` decides whether one directory can
|
|
11600
|
+
// ride a shared link, and without this number that decision cannot be made
|
|
11601
|
+
// until the consumer has listed the repository itself. Zero is a real answer,
|
|
11602
|
+
// for a directory GitHub reported no sizes for at all.
|
|
11603
|
+
bytes: z6.number().int().nonnegative()
|
|
11397
11604
|
});
|
|
11398
|
-
var skillIndexSchema =
|
|
11605
|
+
var skillIndexSchema = z6.object({
|
|
11399
11606
|
// When this index was assembled, as an ISO 8601 instant. The worker's own
|
|
11400
11607
|
// freshness check reads it, and it is served so a caller can say how old the
|
|
11401
11608
|
// list is rather than having to guess.
|
|
11402
|
-
builtAt:
|
|
11403
|
-
skills:
|
|
11609
|
+
builtAt: z6.iso.datetime(),
|
|
11610
|
+
skills: z6.array(skillIndexEntrySchema)
|
|
11404
11611
|
});
|
|
11405
|
-
var skillIndexFreshnessSchema =
|
|
11612
|
+
var skillIndexFreshnessSchema = z6.enum(["fresh", "stale"]);
|
|
11406
11613
|
|
|
11407
11614
|
// src/cli/lib/configuration/scope-predicates.ts
|
|
11408
11615
|
function isActiveAt(entry, scope) {
|
|
@@ -11431,25 +11638,8 @@ function effectivelyExcludedSkillIds(skills) {
|
|
|
11431
11638
|
return new Set(skills.filter((s) => s.excluded && !activeIds.has(s.id)).map((s) => s.id));
|
|
11432
11639
|
}
|
|
11433
11640
|
|
|
11434
|
-
// src/cli/utils/type-guards.ts
|
|
11435
|
-
function isRecord(value) {
|
|
11436
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11437
|
-
}
|
|
11438
|
-
function isDomain2(value) {
|
|
11439
|
-
return DOMAINS.includes(value);
|
|
11440
|
-
}
|
|
11441
|
-
function isAgentName(value) {
|
|
11442
|
-
return AGENT_NAMES.includes(value);
|
|
11443
|
-
}
|
|
11444
|
-
function isSkillId2(value) {
|
|
11445
|
-
return SKILL_IDS.includes(value);
|
|
11446
|
-
}
|
|
11447
|
-
function isSkillAssignment(value) {
|
|
11448
|
-
if (typeof value !== "object" || value === null) return false;
|
|
11449
|
-
return typeof value.id === "string";
|
|
11450
|
-
}
|
|
11451
|
-
|
|
11452
11641
|
// src/cli/lib/configuration/config-generator.ts
|
|
11642
|
+
var MATRIX_SAMPLE_SIZE = 5;
|
|
11453
11643
|
function extractCategoryFromPath(categoryPath) {
|
|
11454
11644
|
if (categoryPath === LOCAL_PSEUDO_CATEGORY) return void 0;
|
|
11455
11645
|
return categoryPath;
|
|
@@ -11463,15 +11653,22 @@ function priorLoadState(existingStack, agent, category, skillId) {
|
|
|
11463
11653
|
return prior.preloaded === true ? "preloaded" : "lazy";
|
|
11464
11654
|
}
|
|
11465
11655
|
function mappedLoadState(skillId, agent) {
|
|
11466
|
-
if (!
|
|
11656
|
+
if (!isSkillId(skillId) || !isAgentName(agent)) return "lazy";
|
|
11467
11657
|
return resolveLoadState({ skillId, agentId: agent });
|
|
11468
11658
|
}
|
|
11469
|
-
function
|
|
11470
|
-
|
|
11659
|
+
function taxonomyOrIdOf(skillId, category) {
|
|
11660
|
+
const domainId = getCategoryDomain(category);
|
|
11661
|
+
if (domainId === void 0) return skillId;
|
|
11662
|
+
return { id: skillId, domainId, categoryId: category };
|
|
11663
|
+
}
|
|
11664
|
+
function isRelevantPair(skillId, category, agent) {
|
|
11665
|
+
return resolveAssignment(taxonomyOrIdOf(skillId, category)).some(
|
|
11666
|
+
(target) => target.agentId === agent
|
|
11667
|
+
);
|
|
11471
11668
|
}
|
|
11472
11669
|
function isPreservedOrRelevant(agent, category, skillId, inputs) {
|
|
11473
11670
|
const hasPriorEntry = priorLoadState(inputs.existingStack, agent, category, skillId) !== void 0;
|
|
11474
|
-
return hasPriorEntry || isRelevantPair(skillId, agent);
|
|
11671
|
+
return hasPriorEntry || isRelevantPair(skillId, category, agent);
|
|
11475
11672
|
}
|
|
11476
11673
|
function getScopeOrThrow(map, key, kind) {
|
|
11477
11674
|
const scope = map.get(key);
|
|
@@ -11511,12 +11708,8 @@ function toStackAssignment(id, agent, category, inputs) {
|
|
|
11511
11708
|
return load === "preloaded" ? { id, preloaded: true } : { id };
|
|
11512
11709
|
}
|
|
11513
11710
|
function inCanonicalCategoryOrder(activeSkillsByCategory) {
|
|
11514
|
-
const
|
|
11515
|
-
|
|
11516
|
-
);
|
|
11517
|
-
const afterEveryDeclared = declarationRank.size;
|
|
11518
|
-
const rankOf = (category) => declarationRank.get(category) ?? afterEveryDeclared;
|
|
11519
|
-
return [...activeSkillsByCategory].sort(([a], [b]) => rankOf(a) - rankOf(b));
|
|
11711
|
+
const byDeclaration = byCategoryDeclarationOrder();
|
|
11712
|
+
return [...activeSkillsByCategory].sort(([a], [b]) => byDeclaration(a, b));
|
|
11520
11713
|
}
|
|
11521
11714
|
function buildAgentStack(agent, inputs) {
|
|
11522
11715
|
const agentStack = {};
|
|
@@ -11541,28 +11734,31 @@ function buildStackForSelection(inputs) {
|
|
|
11541
11734
|
return result;
|
|
11542
11735
|
}
|
|
11543
11736
|
function resolveValidSkills(selectedSkillIds, skillConfigs) {
|
|
11544
|
-
const looked = selectedSkillIds.map((skillId) => {
|
|
11545
|
-
const skill = matrix.skills[skillId];
|
|
11546
|
-
if (!skill) warn(`Skill '${skillId}' NOT FOUND in matrix`, { suppressInTest: true });
|
|
11547
|
-
return { skillId, skill };
|
|
11548
|
-
});
|
|
11737
|
+
const looked = selectedSkillIds.map((skillId) => ({ skillId, skill: matrix.skills[skillId] }));
|
|
11549
11738
|
const found = looked.filter(
|
|
11550
11739
|
(entry) => entry.skill != null
|
|
11551
11740
|
);
|
|
11552
|
-
const
|
|
11553
|
-
|
|
11554
|
-
const matrixSample = typedKeys(matrix.skills).slice(0, 5).join(", ");
|
|
11555
|
-
warn(
|
|
11556
|
-
`${skippedCount}/${selectedSkillIds.length} skills not found in matrix. Matrix keys sample: [${matrixSample}]`,
|
|
11557
|
-
{ suppressInTest: true }
|
|
11558
|
-
);
|
|
11559
|
-
}
|
|
11741
|
+
const absentSkillIds = looked.filter((entry) => entry.skill == null).map((entry) => entry.skillId);
|
|
11742
|
+
reportAbsentSkills(absentSkillIds);
|
|
11560
11743
|
const excludedSkillIds = effectivelyExcludedSkillIds(skillConfigs);
|
|
11561
11744
|
const validSkills = found.map(({ skillId, skill }) => ({
|
|
11562
11745
|
skillId,
|
|
11563
11746
|
category: extractCategoryFromPath(skill.category)
|
|
11564
11747
|
})).filter((entry) => entry.category != null).filter((entry) => !excludedSkillIds.has(entry.skillId));
|
|
11565
|
-
return { validSkills, foundCount: found.length, skippedCount };
|
|
11748
|
+
return { validSkills, foundCount: found.length, skippedCount: absentSkillIds.length };
|
|
11749
|
+
}
|
|
11750
|
+
function reportAbsentSkills(absentSkillIds) {
|
|
11751
|
+
if (absentSkillIds.length === 0) return;
|
|
11752
|
+
for (const skillId of absentSkillIds) {
|
|
11753
|
+
warn(absentSkillWarning(skillId), { suppressInTest: true });
|
|
11754
|
+
}
|
|
11755
|
+
const matrixSample = typedKeys(matrix.skills).slice(0, MATRIX_SAMPLE_SIZE).join(", ");
|
|
11756
|
+
verbose(
|
|
11757
|
+
`${absentSkillIds.length} skills absent from the matrix. Matrix keys sample: [${matrixSample}]`
|
|
11758
|
+
);
|
|
11759
|
+
}
|
|
11760
|
+
function absentSkillWarning(skillId) {
|
|
11761
|
+
return `Skill '${skillId}' is not in this marketplace \u2014 it stays in the configuration and no sub-agent is given it. Run '${CLI_INVOKE_COMMAND} update' to refresh the marketplace, or remove it with '${CLI_INVOKE_COMMAND} edit'.`;
|
|
11566
11762
|
}
|
|
11567
11763
|
function buildSkillScopeMap(skillConfigs) {
|
|
11568
11764
|
const [excludedConfigs, activeConfigs] = partition(skillConfigs, (s) => Boolean(s.excluded));
|
|
@@ -11632,7 +11828,7 @@ function generateProjectConfigFromSkills(name, selectedSkillIds, options) {
|
|
|
11632
11828
|
scopeEligibilityGained: options.scopeEligibilityGained
|
|
11633
11829
|
}
|
|
11634
11830
|
});
|
|
11635
|
-
const skills = options?.skillConfigs ?? selectedSkillIds.map((id) => ({ id, scope: "project",
|
|
11831
|
+
const skills = options?.skillConfigs ?? selectedSkillIds.map((id) => ({ id, scope: "project", origin: EJECT_SOURCE }));
|
|
11636
11832
|
const activeAgentConfigs = resolveActiveAgentConfigs(agentList, options?.agentConfigs);
|
|
11637
11833
|
const excludedAgentConfigs = agentConfigs.filter((ac) => ac.excluded);
|
|
11638
11834
|
const finalAgentConfigs = [...activeAgentConfigs, ...excludedAgentConfigs];
|
|
@@ -11707,7 +11903,7 @@ function splitConfigByScope(config) {
|
|
|
11707
11903
|
name: GLOBAL_CONFIG_NAME,
|
|
11708
11904
|
agents: globalAgents,
|
|
11709
11905
|
skills: globalSkills,
|
|
11710
|
-
|
|
11906
|
+
stack: globalStack,
|
|
11711
11907
|
...config.selectedDomains !== void 0 && { selectedDomains: config.selectedDomains }
|
|
11712
11908
|
};
|
|
11713
11909
|
const projectConfig = {
|
|
@@ -11715,7 +11911,7 @@ function splitConfigByScope(config) {
|
|
|
11715
11911
|
name: config.name,
|
|
11716
11912
|
agents: projectAgents,
|
|
11717
11913
|
skills: projectSkills,
|
|
11718
|
-
|
|
11914
|
+
stack: projectStack
|
|
11719
11915
|
};
|
|
11720
11916
|
return { global: globalConfig, project: projectConfig };
|
|
11721
11917
|
}
|
|
@@ -11725,10 +11921,10 @@ import { indexBy as indexBy2, uniqueBy as uniqueBy2 } from "remeda";
|
|
|
11725
11921
|
|
|
11726
11922
|
// src/cli/lib/configuration/project-config.ts
|
|
11727
11923
|
import os4 from "os";
|
|
11728
|
-
import
|
|
11924
|
+
import path5 from "path";
|
|
11729
11925
|
|
|
11730
11926
|
// src/cli/lib/stacks/stacks-loader.ts
|
|
11731
|
-
import
|
|
11927
|
+
import path4 from "path";
|
|
11732
11928
|
import { flatMap, groupBy as groupBy3, mapValues, partition as partition2, pipe, unique, uniqueBy } from "remeda";
|
|
11733
11929
|
var stacksCache = /* @__PURE__ */ new Map();
|
|
11734
11930
|
function normalizeAgentConfig(agentConfig) {
|
|
@@ -11788,7 +11984,7 @@ async function loadStacks(configDir, stacksFile) {
|
|
|
11788
11984
|
const cacheKey = `${configDir}:${resolvedStacksFile}`;
|
|
11789
11985
|
const cached = stacksCache.get(cacheKey);
|
|
11790
11986
|
if (cached) return cached;
|
|
11791
|
-
const stacksPath =
|
|
11987
|
+
const stacksPath = path4.join(configDir, resolvedStacksFile);
|
|
11792
11988
|
try {
|
|
11793
11989
|
const raw = await loadConfig(stacksPath, stacksConfigSchema);
|
|
11794
11990
|
if (raw == null) {
|
|
@@ -11819,8 +12015,10 @@ async function loadStackById(stackId, configDir, source) {
|
|
|
11819
12015
|
verbose(`Found stack: ${stack.name} (${stackId})`);
|
|
11820
12016
|
return stack;
|
|
11821
12017
|
}
|
|
11822
|
-
if (!
|
|
11823
|
-
verbose(
|
|
12018
|
+
if (!await offersBuiltInStacks(configDir, source)) {
|
|
12019
|
+
verbose(
|
|
12020
|
+
`Marketplace '${source}' does not ship stack '${stackId}', and gets no built-in stand-in`
|
|
12021
|
+
);
|
|
11824
12022
|
return null;
|
|
11825
12023
|
}
|
|
11826
12024
|
const defaultStack = defaultStacks.find((s) => s.id === stackId) ?? null;
|
|
@@ -11907,7 +12105,7 @@ async function loadProjectConfigFromDir(projectDir) {
|
|
|
11907
12105
|
}
|
|
11908
12106
|
const config = {
|
|
11909
12107
|
...parsed,
|
|
11910
|
-
name: parsed.name ??
|
|
12108
|
+
name: parsed.name ?? path5.basename(projectDir),
|
|
11911
12109
|
skills: parsed.skills ?? [],
|
|
11912
12110
|
agents: parsed.agents ?? [],
|
|
11913
12111
|
...normalizedStack && { stack: normalizedStack }
|
|
@@ -11976,8 +12174,8 @@ function mergeConfigs(newConfig, existingConfig, options) {
|
|
|
11976
12174
|
if (existingConfig.description) {
|
|
11977
12175
|
merged.description = existingConfig.description;
|
|
11978
12176
|
}
|
|
11979
|
-
if (existingConfig.
|
|
11980
|
-
merged.
|
|
12177
|
+
if (existingConfig.marketplace && !newConfig.marketplace) {
|
|
12178
|
+
merged.marketplace = existingConfig.marketplace;
|
|
11981
12179
|
}
|
|
11982
12180
|
if (existingConfig.agents.length > 0) {
|
|
11983
12181
|
const newAgentsByKey = indexBy2(merged.agents, agentKey);
|
|
@@ -12026,8 +12224,8 @@ function mergeConfigs(newConfig, existingConfig, options) {
|
|
|
12026
12224
|
if (existingConfig.agentsSource) {
|
|
12027
12225
|
merged.agentsSource = existingConfig.agentsSource;
|
|
12028
12226
|
}
|
|
12029
|
-
if (existingConfig.
|
|
12030
|
-
merged.
|
|
12227
|
+
if (existingConfig.marketplaceName) {
|
|
12228
|
+
merged.marketplaceName = existingConfig.marketplaceName;
|
|
12031
12229
|
}
|
|
12032
12230
|
if (existingConfig.projects && !newConfig.projects) {
|
|
12033
12231
|
merged.projects = existingConfig.projects;
|
|
@@ -12069,12 +12267,26 @@ async function mergeWithExistingConfig(newConfig, context) {
|
|
|
12069
12267
|
}
|
|
12070
12268
|
|
|
12071
12269
|
// src/cli/lib/configuration/config-types-writer.ts
|
|
12072
|
-
import
|
|
12270
|
+
import path6 from "path";
|
|
12073
12271
|
import { groupBy as groupBy4, unique as unique2 } from "remeda";
|
|
12272
|
+
|
|
12273
|
+
// src/cli/utils/string.ts
|
|
12274
|
+
function truncateText(text, maxLength) {
|
|
12275
|
+
if (text.length <= maxLength) return text;
|
|
12276
|
+
return text.slice(0, maxLength - 1) + "\u2026";
|
|
12277
|
+
}
|
|
12278
|
+
function toTitleCase(kebabCase) {
|
|
12279
|
+
return kebabCase.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
12280
|
+
}
|
|
12281
|
+
function bytewise(a, b) {
|
|
12282
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
12283
|
+
}
|
|
12284
|
+
|
|
12285
|
+
// src/cli/lib/configuration/config-types-writer.ts
|
|
12074
12286
|
var MULTI_LINE_THRESHOLD = 6;
|
|
12075
12287
|
var EMPTY_UNION_TYPE = "never";
|
|
12076
12288
|
async function getGlobalConfigTypesPath() {
|
|
12077
|
-
const globalConfigTypesPath =
|
|
12289
|
+
const globalConfigTypesPath = path6.join(
|
|
12078
12290
|
GLOBAL_INSTALL_ROOT,
|
|
12079
12291
|
CLAUDE_SRC_DIR,
|
|
12080
12292
|
STANDARD_FILES.CONFIG_TYPES_TS
|
|
@@ -12085,10 +12297,10 @@ async function getGlobalConfigTypesPath() {
|
|
|
12085
12297
|
return null;
|
|
12086
12298
|
}
|
|
12087
12299
|
function computeGlobalTypesImportPath(projectDir) {
|
|
12088
|
-
const projectClaudeSrc =
|
|
12089
|
-
const globalClaudeSrc =
|
|
12090
|
-
const relativePath =
|
|
12091
|
-
return relativePath.split(
|
|
12300
|
+
const projectClaudeSrc = path6.join(projectDir, CLAUDE_SRC_DIR);
|
|
12301
|
+
const globalClaudeSrc = path6.join(GLOBAL_INSTALL_ROOT, CLAUDE_SRC_DIR);
|
|
12302
|
+
const relativePath = path6.relative(projectClaudeSrc, globalClaudeSrc);
|
|
12303
|
+
return relativePath.split(path6.sep).join("/");
|
|
12092
12304
|
}
|
|
12093
12305
|
var STACK_AGENT_CONFIG_INLINE_THRESHOLD = 3;
|
|
12094
12306
|
function formatLiteralUnion(members) {
|
|
@@ -12099,7 +12311,7 @@ var PROJECT_CONFIG_TYPES_BEFORE = `export type InstallMode = "eject" | "plugin"
|
|
|
12099
12311
|
export type SkillConfig = {
|
|
12100
12312
|
id: SkillId;
|
|
12101
12313
|
scope: "project" | "global";
|
|
12102
|
-
|
|
12314
|
+
origin: string;
|
|
12103
12315
|
excluded?: boolean;
|
|
12104
12316
|
};
|
|
12105
12317
|
|
|
@@ -12123,7 +12335,7 @@ var PROJECT_CONFIG_INTERFACE_AFTER = `export interface ProjectConfig {
|
|
|
12123
12335
|
/** Per-agent configuration with scope */
|
|
12124
12336
|
agents: AgentScopeConfig[];
|
|
12125
12337
|
|
|
12126
|
-
/** Per-skill configuration with scope and
|
|
12338
|
+
/** Per-skill configuration with scope and provenance */
|
|
12127
12339
|
skills: SkillConfig[];
|
|
12128
12340
|
|
|
12129
12341
|
/** Author handle (e.g., "@vince") */
|
|
@@ -12132,12 +12344,12 @@ var PROJECT_CONFIG_INTERFACE_AFTER = `export interface ProjectConfig {
|
|
|
12132
12344
|
/** Stack configuration: agent -> category -> skill assignment */
|
|
12133
12345
|
stack?: Partial<Record<ProjectAgentName, StackAgentConfig>>;
|
|
12134
12346
|
|
|
12135
|
-
/**
|
|
12136
|
-
source?: string;
|
|
12137
|
-
|
|
12138
|
-
/** Marketplace identifier for plugin installation */
|
|
12347
|
+
/** The marketplace this install reads skills from, as a path or URL */
|
|
12139
12348
|
marketplace?: string;
|
|
12140
12349
|
|
|
12350
|
+
/** The name that marketplace's manifest gives it, which plugins are registered under */
|
|
12351
|
+
marketplaceName?: string;
|
|
12352
|
+
|
|
12141
12353
|
/** Agents source path or URL (when agents come from a different source than skills) */
|
|
12142
12354
|
agentsSource?: string;
|
|
12143
12355
|
|
|
@@ -12184,7 +12396,7 @@ function generateStackAgentConfig(skillsByCategory, matrix2) {
|
|
|
12184
12396
|
if (skillsByCategory.size === 0) {
|
|
12185
12397
|
return STACK_AGENT_CONFIG_LOOSE_LINE;
|
|
12186
12398
|
}
|
|
12187
|
-
const properties = [...skillsByCategory.entries()].sort(([a], [b]) => a
|
|
12399
|
+
const properties = [...skillsByCategory.entries()].sort(([a], [b]) => bytewise(a, b)).map(([category, skills]) => {
|
|
12188
12400
|
const arraySuffix = matrix2.categories[category]?.exclusive === true ? "" : "[]";
|
|
12189
12401
|
return ` "${category}"?: SkillAssignment<${formatSkillUnion(skills)}>${arraySuffix};`;
|
|
12190
12402
|
});
|
|
@@ -12202,22 +12414,27 @@ function buildSkillsByCategory(skillIds, categories, matrix2) {
|
|
|
12202
12414
|
])
|
|
12203
12415
|
);
|
|
12204
12416
|
}
|
|
12205
|
-
function
|
|
12206
|
-
|
|
12207
|
-
|
|
12208
|
-
|
|
12209
|
-
|
|
12210
|
-
|
|
12211
|
-
|
|
12417
|
+
function isUndeclaredCategory(category, matrix2) {
|
|
12418
|
+
return matrix2.categories[category] === void 0;
|
|
12419
|
+
}
|
|
12420
|
+
function isCustomSkill(skillId, matrix2) {
|
|
12421
|
+
const declared = matrix2.skills[skillId];
|
|
12422
|
+
return declared === void 0 || declared.custom === true;
|
|
12423
|
+
}
|
|
12424
|
+
function isCustomAgent(agentName, declared, flaggedCustom) {
|
|
12425
|
+
return !declared.has(agentName) || flaggedCustom.has(agentName);
|
|
12426
|
+
}
|
|
12427
|
+
function isCustomDomain(domain, declared) {
|
|
12428
|
+
return !declared.has(domain);
|
|
12212
12429
|
}
|
|
12213
12430
|
async function regenerateConfigTypes(projectDir, backgroundData, extras) {
|
|
12214
12431
|
if (isHomeDirectory(projectDir)) {
|
|
12215
12432
|
throw new GlobalPairWriteViolation(
|
|
12216
|
-
|
|
12433
|
+
path6.join(projectDir, CLAUDE_SRC_DIR, STANDARD_FILES.CONFIG_TYPES_TS)
|
|
12217
12434
|
);
|
|
12218
12435
|
}
|
|
12219
12436
|
const data = await backgroundData;
|
|
12220
|
-
const claudeSrcDir =
|
|
12437
|
+
const claudeSrcDir = path6.join(projectDir, CLAUDE_SRC_DIR);
|
|
12221
12438
|
const isProjectScope = !isHomeDirectory(projectDir);
|
|
12222
12439
|
const globalConfigTypes = isProjectScope ? await getGlobalConfigTypesPath() : null;
|
|
12223
12440
|
const loadedConfig = await loadProjectConfigFromDir(projectDir);
|
|
@@ -12245,7 +12462,7 @@ async function regenerateConfigTypes(projectDir, backgroundData, extras) {
|
|
|
12245
12462
|
loadedConfig?.config
|
|
12246
12463
|
);
|
|
12247
12464
|
}
|
|
12248
|
-
const configTypesPath =
|
|
12465
|
+
const configTypesPath = path6.join(claudeSrcDir, STANDARD_FILES.CONFIG_TYPES_TS);
|
|
12249
12466
|
await writeFile(configTypesPath, source);
|
|
12250
12467
|
verbose(`Regenerated ${STANDARD_FILES.CONFIG_TYPES_TS}`);
|
|
12251
12468
|
}
|
|
@@ -12277,20 +12494,22 @@ function generateConfigTypesSource(matrix2, agentNames, customAgentNames = [], e
|
|
|
12277
12494
|
domains = unique2([...extractDomains(matrix2), ...extraDomainsArr]).sort();
|
|
12278
12495
|
categories = unique2([...typedKeys(matrix2.categories), ...extraCategoriesArr]).sort();
|
|
12279
12496
|
}
|
|
12280
|
-
const
|
|
12281
|
-
|
|
12282
|
-
|
|
12283
|
-
|
|
12284
|
-
const
|
|
12285
|
-
|
|
12286
|
-
|
|
12287
|
-
|
|
12288
|
-
|
|
12289
|
-
|
|
12290
|
-
|
|
12291
|
-
|
|
12292
|
-
const
|
|
12293
|
-
|
|
12497
|
+
const declaredAgents = new Set(agentNames);
|
|
12498
|
+
const flaggedCustomAgents = new Set(customAgentNames);
|
|
12499
|
+
const declaredDomains = new Set(extractDomains(matrix2));
|
|
12500
|
+
const skillIdLine = formatMaybeSectionedUnion(skillIds, (id) => isCustomSkill(id, matrix2));
|
|
12501
|
+
const agentNameLine = formatMaybeSectionedUnion(
|
|
12502
|
+
sortedAgents,
|
|
12503
|
+
(name) => isCustomAgent(name, declaredAgents, flaggedCustomAgents)
|
|
12504
|
+
);
|
|
12505
|
+
const domainLine = formatMaybeSectionedUnion(
|
|
12506
|
+
domains,
|
|
12507
|
+
(domain) => isCustomDomain(domain, declaredDomains)
|
|
12508
|
+
);
|
|
12509
|
+
const categoryLine = formatMaybeSectionedUnion(
|
|
12510
|
+
categories,
|
|
12511
|
+
(category) => isUndeclaredCategory(category, matrix2)
|
|
12512
|
+
);
|
|
12294
12513
|
const selectedAgents = config?.agents ? activeAgentNames(config.agents) : [];
|
|
12295
12514
|
const selectedAgentNameLine = selectedAgents.length > 0 ? formatUnion(selectedAgents) : "AgentName";
|
|
12296
12515
|
const projectScopedAgents = config?.agents ? activeProjectAgentNames(config.agents) : [];
|
|
@@ -12400,12 +12619,12 @@ function formatExtendedUnion(globalTypeName, projectMembers) {
|
|
|
12400
12619
|
}
|
|
12401
12620
|
|
|
12402
12621
|
// src/cli/lib/skills/skill-metadata.ts
|
|
12403
|
-
import
|
|
12622
|
+
import path8 from "path";
|
|
12404
12623
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
12405
12624
|
|
|
12406
12625
|
// src/cli/lib/versioning.ts
|
|
12407
12626
|
import { createHash } from "crypto";
|
|
12408
|
-
import
|
|
12627
|
+
import path7 from "path";
|
|
12409
12628
|
var ISO_DATE_LENGTH = 10;
|
|
12410
12629
|
function getCurrentDate() {
|
|
12411
12630
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, ISO_DATE_LENGTH);
|
|
@@ -12422,18 +12641,18 @@ async function computeFileHash(filePath) {
|
|
|
12422
12641
|
async function computeSkillFolderHash(skillPath) {
|
|
12423
12642
|
const contents = [];
|
|
12424
12643
|
for (const fileName of SKILL_CONTENT_FILES) {
|
|
12425
|
-
const filePath =
|
|
12644
|
+
const filePath = path7.join(skillPath, fileName);
|
|
12426
12645
|
if (await fileExists(filePath)) {
|
|
12427
12646
|
const content = await readFile(filePath);
|
|
12428
12647
|
contents.push(`${fileName}:${content}`);
|
|
12429
12648
|
}
|
|
12430
12649
|
}
|
|
12431
12650
|
for (const dirName of SKILL_CONTENT_DIRS) {
|
|
12432
|
-
const dirPath =
|
|
12651
|
+
const dirPath = path7.join(skillPath, dirName);
|
|
12433
12652
|
if (await fileExists(dirPath)) {
|
|
12434
12653
|
const files = await glob("**/*", dirPath);
|
|
12435
12654
|
for (const file of files.sort()) {
|
|
12436
|
-
const filePath =
|
|
12655
|
+
const filePath = path7.join(dirPath, file);
|
|
12437
12656
|
const content = await readFile(filePath);
|
|
12438
12657
|
contents.push(`${dirName}/${file}:${content}`);
|
|
12439
12658
|
}
|
|
@@ -12516,7 +12735,7 @@ async function readForkedFromMetadata(skillDir) {
|
|
|
12516
12735
|
return metadata?.forkedFrom ?? null;
|
|
12517
12736
|
}
|
|
12518
12737
|
async function readLocalSkillMetadata(skillDir) {
|
|
12519
|
-
const metadataPath =
|
|
12738
|
+
const metadataPath = path8.join(skillDir, STANDARD_FILES.METADATA_YAML);
|
|
12520
12739
|
if (!await fileExists(metadataPath)) {
|
|
12521
12740
|
return null;
|
|
12522
12741
|
}
|
|
@@ -12528,8 +12747,8 @@ async function readLocalSkillMetadata(skillDir) {
|
|
|
12528
12747
|
}
|
|
12529
12748
|
return result.data;
|
|
12530
12749
|
}
|
|
12531
|
-
async function injectForkedFromMetadata(destPath, skillId, contentHash,
|
|
12532
|
-
const metadataPath =
|
|
12750
|
+
async function injectForkedFromMetadata(destPath, skillId, contentHash, origin = {}) {
|
|
12751
|
+
const metadataPath = path8.join(destPath, STANDARD_FILES.METADATA_YAML);
|
|
12533
12752
|
const rawContent = await readFile(metadataPath);
|
|
12534
12753
|
const { yamlContent } = stripYamlSchemaComment(rawContent);
|
|
12535
12754
|
const parseResult = localSkillMetadataSchema.safeParse(parseYaml(yamlContent));
|
|
@@ -12542,7 +12761,8 @@ async function injectForkedFromMetadata(destPath, skillId, contentHash, source)
|
|
|
12542
12761
|
skillId,
|
|
12543
12762
|
contentHash,
|
|
12544
12763
|
date: getCurrentDate(),
|
|
12545
|
-
...source
|
|
12764
|
+
...origin.source !== void 0 && { source: origin.source },
|
|
12765
|
+
...origin.path !== void 0 && { path: origin.path }
|
|
12546
12766
|
}
|
|
12547
12767
|
};
|
|
12548
12768
|
await writeMetadataYaml(metadataPath, metadata, `${yamlSchemaComment(SCHEMA_PATHS.metadata)}
|
|
@@ -12554,7 +12774,7 @@ async function writeMetadataYaml(filePath, metadata, schemaComment = "") {
|
|
|
12554
12774
|
}
|
|
12555
12775
|
|
|
12556
12776
|
// src/cli/lib/skills/skill-copier.ts
|
|
12557
|
-
import
|
|
12777
|
+
import path9 from "path";
|
|
12558
12778
|
var NULL_BYTE_PATTERN2 = /\0/;
|
|
12559
12779
|
function validateSkillPath(resolvedPath, expectedParent, skillPath) {
|
|
12560
12780
|
if (NULL_BYTE_PATTERN2.test(skillPath)) {
|
|
@@ -12562,28 +12782,30 @@ function validateSkillPath(resolvedPath, expectedParent, skillPath) {
|
|
|
12562
12782
|
}
|
|
12563
12783
|
if (!isPathWithin(resolvedPath, expectedParent)) {
|
|
12564
12784
|
throw new Error(
|
|
12565
|
-
`Invalid skill path: '${skillPath}' escapes expected directory '${
|
|
12785
|
+
`Invalid skill path: '${skillPath}' escapes expected directory '${path9.resolve(expectedParent)}'`
|
|
12566
12786
|
);
|
|
12567
12787
|
}
|
|
12568
12788
|
}
|
|
12569
12789
|
function resolveSkillPath(basePath, skillPath) {
|
|
12570
|
-
const resolved =
|
|
12790
|
+
const resolved = path9.join(basePath, skillPath);
|
|
12571
12791
|
validateSkillPath(resolved, basePath, skillPath);
|
|
12572
12792
|
return resolved;
|
|
12573
12793
|
}
|
|
12574
12794
|
function getSkillSourcePath(skill, rootDir) {
|
|
12575
|
-
const srcDir =
|
|
12795
|
+
const srcDir = path9.join(rootDir, SOURCE_SRC_DIR);
|
|
12576
12796
|
return resolveSkillPath(srcDir, skill.path);
|
|
12577
12797
|
}
|
|
12578
12798
|
async function generateSkillHash(skillSourcePath) {
|
|
12579
|
-
const skillMdPath =
|
|
12799
|
+
const skillMdPath = path9.join(skillSourcePath, STANDARD_FILES.SKILL_MD);
|
|
12580
12800
|
return computeFileHash(skillMdPath);
|
|
12581
12801
|
}
|
|
12582
12802
|
async function copySkillTo(skill, sourcePath, destPath, source) {
|
|
12583
12803
|
const contentHash = await generateSkillHash(sourcePath);
|
|
12584
|
-
await ensureDir(
|
|
12804
|
+
await ensureDir(path9.dirname(destPath));
|
|
12585
12805
|
await copy(sourcePath, destPath);
|
|
12586
|
-
await injectForkedFromMetadata(destPath, skill.id, contentHash,
|
|
12806
|
+
await injectForkedFromMetadata(destPath, skill.id, contentHash, {
|
|
12807
|
+
...source !== void 0 && { source }
|
|
12808
|
+
});
|
|
12587
12809
|
return { skillId: skill.id, contentHash, sourcePath, destPath };
|
|
12588
12810
|
}
|
|
12589
12811
|
async function resolveLocalCopiedSkill(skill, localPath) {
|
|
@@ -12596,6 +12818,32 @@ async function resolveLocalCopiedSkill(skill, localPath) {
|
|
|
12596
12818
|
local: true
|
|
12597
12819
|
};
|
|
12598
12820
|
}
|
|
12821
|
+
async function copyEachSkill(selectedSkillIds, copyOne) {
|
|
12822
|
+
const outcomes = await Promise.all(
|
|
12823
|
+
selectedSkillIds.map(async (skillId) => attemptCopy(skillId, copyOne))
|
|
12824
|
+
);
|
|
12825
|
+
const failures = outcomes.filter(isCopyFailure);
|
|
12826
|
+
if (failures.length > 0) throw new Error(copyFailureMessage(failures, selectedSkillIds.length));
|
|
12827
|
+
return outcomes.filter(isCopySuccess).map((outcome) => outcome.copied);
|
|
12828
|
+
}
|
|
12829
|
+
async function attemptCopy(skillId, copyOne) {
|
|
12830
|
+
try {
|
|
12831
|
+
return { skillId, copied: await copyOne(skillId) };
|
|
12832
|
+
} catch (error) {
|
|
12833
|
+
return { skillId, problem: getErrorMessage(error) };
|
|
12834
|
+
}
|
|
12835
|
+
}
|
|
12836
|
+
function isCopyFailure(outcome) {
|
|
12837
|
+
return "problem" in outcome;
|
|
12838
|
+
}
|
|
12839
|
+
function isCopySuccess(outcome) {
|
|
12840
|
+
return "copied" in outcome;
|
|
12841
|
+
}
|
|
12842
|
+
function copyFailureMessage(failures, attempted) {
|
|
12843
|
+
const lines = failures.map((failure) => ` ${failure.skillId}: ${failure.problem}`);
|
|
12844
|
+
return `Could not copy ${failures.length} of ${attempted} skills:
|
|
12845
|
+
${lines.join("\n")}`;
|
|
12846
|
+
}
|
|
12599
12847
|
function getFlattenedSkillDestPath(skill, localSkillsDir) {
|
|
12600
12848
|
return resolveSkillPath(localSkillsDir, skill.id);
|
|
12601
12849
|
}
|
|
@@ -12608,34 +12856,30 @@ async function copySkillToLocalFlattened(skill, localSkillsDir, sourceResult) {
|
|
|
12608
12856
|
);
|
|
12609
12857
|
}
|
|
12610
12858
|
async function copySkillsToLocalFlattened(selectedSkillIds, localSkillsDir, sourceResult, sourceSelections) {
|
|
12611
|
-
|
|
12612
|
-
|
|
12613
|
-
|
|
12614
|
-
|
|
12615
|
-
|
|
12616
|
-
if (skill.local && skill.localPath && !userSelectedRemote) {
|
|
12617
|
-
const destPath = getFlattenedSkillDestPath(skill, localSkillsDir);
|
|
12618
|
-
const alreadyInPlace = path8.resolve(skill.localPath) === path8.resolve(destPath);
|
|
12619
|
-
if (alreadyInPlace) {
|
|
12620
|
-
return resolveLocalCopiedSkill(skill, skill.localPath);
|
|
12621
|
-
}
|
|
12622
|
-
const contentHash = await generateSkillHash(skill.localPath);
|
|
12623
|
-
await ensureDir(path8.dirname(destPath));
|
|
12624
|
-
await copy(skill.localPath, destPath);
|
|
12625
|
-
return { skillId: skill.id, sourcePath: skill.localPath, destPath, contentHash };
|
|
12626
|
-
}
|
|
12859
|
+
return copyEachSkill(selectedSkillIds, async (skillId) => {
|
|
12860
|
+
const skill = getSkillById(skillId);
|
|
12861
|
+
const selectedSource = sourceSelections?.[skillId];
|
|
12862
|
+
const userSelectedRemote = selectedSource && selectedSource !== EJECT_SOURCE;
|
|
12863
|
+
if (!skill.local || !skill.localPath || userSelectedRemote) {
|
|
12627
12864
|
return copySkillToLocalFlattened(skill, localSkillsDir, sourceResult);
|
|
12628
|
-
}
|
|
12629
|
-
|
|
12630
|
-
|
|
12865
|
+
}
|
|
12866
|
+
const destPath = getFlattenedSkillDestPath(skill, localSkillsDir);
|
|
12867
|
+
if (path9.resolve(skill.localPath) === path9.resolve(destPath)) {
|
|
12868
|
+
return resolveLocalCopiedSkill(skill, skill.localPath);
|
|
12869
|
+
}
|
|
12870
|
+
const contentHash = await generateSkillHash(skill.localPath);
|
|
12871
|
+
await ensureDir(path9.dirname(destPath));
|
|
12872
|
+
await copy(skill.localPath, destPath);
|
|
12873
|
+
return { skillId: skill.id, sourcePath: skill.localPath, destPath, contentHash };
|
|
12874
|
+
});
|
|
12631
12875
|
}
|
|
12632
12876
|
|
|
12633
12877
|
// src/cli/lib/skills/skill-plugin-compiler.ts
|
|
12634
|
-
import
|
|
12878
|
+
import path23 from "path";
|
|
12635
12879
|
import { parse as parseYaml2 } from "yaml";
|
|
12636
12880
|
|
|
12637
12881
|
// src/cli/lib/plugins/plugin-manifest.ts
|
|
12638
|
-
import
|
|
12882
|
+
import path10 from "path";
|
|
12639
12883
|
var PLUGIN_DIR_NAME = PLUGIN_MANIFEST_DIR;
|
|
12640
12884
|
var PLUGIN_MANIFEST_FILE2 = STANDARD_FILES.PLUGIN_JSON;
|
|
12641
12885
|
var AGENT_PLUGIN_PREFIX = "agent-";
|
|
@@ -12666,8 +12910,8 @@ function generateAgentPluginManifest(options) {
|
|
|
12666
12910
|
};
|
|
12667
12911
|
}
|
|
12668
12912
|
async function writePluginManifest(outputDir, manifest) {
|
|
12669
|
-
const pluginDir =
|
|
12670
|
-
const manifestPath =
|
|
12913
|
+
const pluginDir = path10.join(outputDir, PLUGIN_DIR_NAME);
|
|
12914
|
+
const manifestPath = path10.join(pluginDir, PLUGIN_MANIFEST_FILE2);
|
|
12671
12915
|
await ensureDir(pluginDir);
|
|
12672
12916
|
const content = JSON.stringify(manifest, null, 2);
|
|
12673
12917
|
await writeFile(manifestPath, content);
|
|
@@ -12676,20 +12920,20 @@ async function writePluginManifest(outputDir, manifest) {
|
|
|
12676
12920
|
|
|
12677
12921
|
// src/cli/lib/plugins/plugin-finder.ts
|
|
12678
12922
|
import os5 from "os";
|
|
12679
|
-
import
|
|
12923
|
+
import path11 from "path";
|
|
12680
12924
|
import { zip } from "remeda";
|
|
12681
12925
|
function getUserPluginsDir() {
|
|
12682
|
-
return
|
|
12926
|
+
return path11.join(os5.homedir(), CLAUDE_DIR, PLUGINS_SUBDIR);
|
|
12683
12927
|
}
|
|
12684
12928
|
function getProjectPluginsDir(projectDir) {
|
|
12685
12929
|
const dir = projectDir ?? process.cwd();
|
|
12686
|
-
return
|
|
12930
|
+
return path11.join(dir, CLAUDE_DIR, PLUGINS_SUBDIR);
|
|
12687
12931
|
}
|
|
12688
12932
|
function getPluginAgentsDir(pluginDir) {
|
|
12689
|
-
return
|
|
12933
|
+
return path11.join(pluginDir, "agents");
|
|
12690
12934
|
}
|
|
12691
12935
|
function getPluginManifestPath(pluginDir) {
|
|
12692
|
-
return
|
|
12936
|
+
return path11.join(pluginDir, PLUGIN_MANIFEST_DIR, PLUGIN_MANIFEST_FILE);
|
|
12693
12937
|
}
|
|
12694
12938
|
async function readPluginManifest(pluginDir) {
|
|
12695
12939
|
const manifestPath = getPluginManifestPath(pluginDir);
|
|
@@ -12728,7 +12972,7 @@ import { readdir } from "fs/promises";
|
|
|
12728
12972
|
|
|
12729
12973
|
// src/cli/lib/installation/installation.ts
|
|
12730
12974
|
import os6 from "os";
|
|
12731
|
-
import
|
|
12975
|
+
import path12 from "path";
|
|
12732
12976
|
var INSTALL_MODE_LABELS = {
|
|
12733
12977
|
plugin: "Plugin",
|
|
12734
12978
|
mixed: "Mixed",
|
|
@@ -12743,8 +12987,8 @@ function declaresNoContent(config) {
|
|
|
12743
12987
|
}
|
|
12744
12988
|
function deriveInstallMode(skills) {
|
|
12745
12989
|
if (skills.length === 0) return "eject";
|
|
12746
|
-
const hasEject = skills.some((s) => s.
|
|
12747
|
-
const hasPlugin = skills.some((s) => s.
|
|
12990
|
+
const hasEject = skills.some((s) => s.origin === EJECT_SOURCE);
|
|
12991
|
+
const hasPlugin = skills.some((s) => s.origin !== EJECT_SOURCE);
|
|
12748
12992
|
if (hasEject && hasPlugin) return "mixed";
|
|
12749
12993
|
return hasEject ? "eject" : "plugin";
|
|
12750
12994
|
}
|
|
@@ -12764,10 +13008,10 @@ async function detectInstallationInDir(dir) {
|
|
|
12764
13008
|
return {
|
|
12765
13009
|
mode,
|
|
12766
13010
|
configPath,
|
|
12767
|
-
agentsDir:
|
|
13011
|
+
agentsDir: path12.join(dir, CLAUDE_DIR, STANDARD_DIRS.AGENTS),
|
|
12768
13012
|
// Mixed mode has local skills in .claude/skills/ and plugins in cache;
|
|
12769
13013
|
// use .claude/skills/ as the primary skillsDir (same as eject mode)
|
|
12770
|
-
skillsDir:
|
|
13014
|
+
skillsDir: path12.join(dir, CLAUDE_DIR, mode === "plugin" ? PLUGINS_SUBDIR : "skills"),
|
|
12771
13015
|
projectDir: dir
|
|
12772
13016
|
};
|
|
12773
13017
|
}
|
|
@@ -12785,26 +13029,49 @@ async function detectInstallation(projectDir = process.cwd()) {
|
|
|
12785
13029
|
|
|
12786
13030
|
// src/cli/lib/installation/local-installer.ts
|
|
12787
13031
|
import os13 from "os";
|
|
12788
|
-
import
|
|
12789
|
-
import { unique as
|
|
13032
|
+
import path20 from "path";
|
|
13033
|
+
import { unique as unique5 } from "remeda";
|
|
12790
13034
|
|
|
12791
13035
|
// src/cli/lib/loading/source-fetcher.ts
|
|
12792
13036
|
import { createHash as createHash2 } from "crypto";
|
|
12793
13037
|
import { downloadTemplate } from "giget";
|
|
12794
13038
|
import os7 from "os";
|
|
12795
|
-
import
|
|
13039
|
+
import path13 from "path";
|
|
13040
|
+
|
|
13041
|
+
// src/cli/lib/validate-kebab-name.ts
|
|
13042
|
+
import { unique as unique3 } from "remeda";
|
|
13043
|
+
var KEBAB_CASE_CHARACTER = /[a-z0-9-]/;
|
|
13044
|
+
function charactersOutsideKebabCase(name) {
|
|
13045
|
+
return unique3([...name].filter((character) => !KEBAB_CASE_CHARACTER.test(character)));
|
|
13046
|
+
}
|
|
13047
|
+
function validateKebabCaseName(name, noun) {
|
|
13048
|
+
if (!name || name.trim() === "") {
|
|
13049
|
+
return `${noun} name is required`;
|
|
13050
|
+
}
|
|
13051
|
+
if (!KEBAB_CASE_PATTERN.test(name)) {
|
|
13052
|
+
return `${noun} name must be kebab-case (lowercase letters, numbers, and hyphens, starting with a letter)`;
|
|
13053
|
+
}
|
|
13054
|
+
return null;
|
|
13055
|
+
}
|
|
12796
13056
|
|
|
12797
13057
|
// src/cli/utils/messages.ts
|
|
12798
13058
|
var ERROR_MESSAGES = {
|
|
12799
13059
|
UNKNOWN_ERROR: "Unknown error occurred",
|
|
12800
13060
|
UNKNOWN_ERROR_SHORT: "Unknown error",
|
|
12801
13061
|
NO_INSTALLATION: `No installation found. Run '${CLI_INVOKE_COMMAND} init' first to set up ${DEFAULT_BRANDING.NAME}`,
|
|
12802
|
-
|
|
12803
|
-
VALIDATION_FAILED: "Validation failed",
|
|
12804
|
-
FAILED_RESOLVE_SOURCE: "Failed to resolve source",
|
|
13062
|
+
FAILED_RESOLVE_SOURCE: "Failed to resolve marketplace",
|
|
12805
13063
|
FAILED_LOAD_AGENT_PARTIALS: "Failed to load agent partials",
|
|
12806
13064
|
FAILED_COMPILE_AGENTS: "Failed to compile agents",
|
|
12807
|
-
CLAUDE_CLI_NOT_FOUND: `Claude CLI not found \u2014 '${CLI_INVOKE_COMMAND} update' refreshes marketplaces through it. Install Claude Code first: https://claude.ai/code
|
|
13065
|
+
CLAUDE_CLI_NOT_FOUND: `Claude CLI not found \u2014 '${CLI_INVOKE_COMMAND} update' refreshes marketplaces through it. Install Claude Code first: https://claude.ai/code`,
|
|
13066
|
+
/**
|
|
13067
|
+
* What `compile` refuses with when every pass discovered zero skills. It is reached only
|
|
13068
|
+
* after an installation was detected, so the state it describes is a configuration with
|
|
13069
|
+
* nothing installed under it — the same state `doctor` reports as `config-empty` and
|
|
13070
|
+
* names `init` for, because `init` on a config that declares nothing opens the wizard
|
|
13071
|
+
* rather than the dashboard. `edit` is the wrong half of the pair here: it modifies the
|
|
13072
|
+
* currently installed skills, and there are none to modify.
|
|
13073
|
+
*/
|
|
13074
|
+
NO_SKILLS_TO_COMPILE: `No skills found. Run '${CLI_INVOKE_COMMAND} init' to choose skills, or add your own under ${LOCAL_SKILLS_PATH}/.`
|
|
12808
13075
|
};
|
|
12809
13076
|
var SUCCESS_MESSAGES = {
|
|
12810
13077
|
UNINSTALL_COMPLETE: "Uninstall complete!",
|
|
@@ -12814,23 +13081,29 @@ var SUCCESS_MESSAGES = {
|
|
|
12814
13081
|
var STATUS_MESSAGES = {
|
|
12815
13082
|
INSTALLING_PLUGINS: "Installing skill plugins...",
|
|
12816
13083
|
LOADING_SKILLS: "Loading skills...",
|
|
12817
|
-
LOADING_MARKETPLACE_SOURCE: "Loading marketplace
|
|
13084
|
+
LOADING_MARKETPLACE_SOURCE: "Loading marketplace...",
|
|
12818
13085
|
RECOMPILING_AGENTS: "Recompiling agents...",
|
|
12819
13086
|
COMPILING_AGENTS: "Compiling agents...",
|
|
12820
13087
|
DISCOVERING_SKILLS: "Discovering skills...",
|
|
12821
|
-
RESOLVING_SOURCE: "Resolving
|
|
12822
|
-
RESOLVING_MARKETPLACE_SOURCE: "Resolving marketplace
|
|
13088
|
+
RESOLVING_SOURCE: "Resolving marketplace...",
|
|
13089
|
+
RESOLVING_MARKETPLACE_SOURCE: "Resolving marketplace...",
|
|
12823
13090
|
LOADING_AGENT_PARTIALS: "Loading agent partials...",
|
|
12824
13091
|
FETCHING_REPOSITORY: "Fetching repository...",
|
|
12825
13092
|
COPYING_SKILLS: "Copying skills...",
|
|
12826
|
-
UPDATING_PLUGIN_SKILLS: "Updating plugin skills...",
|
|
12827
13093
|
/**
|
|
12828
|
-
* Printed when revalidation found the remote
|
|
13094
|
+
* Printed when revalidation found the remote marketplace had moved on. It is the
|
|
12829
13095
|
* only warning a user gets that this load costs a download rather than a
|
|
12830
13096
|
* cache read, so it goes out before the download starts, not after.
|
|
12831
13097
|
*/
|
|
12832
13098
|
MARKETPLACE_HAS_NEWER_CONTENT: "Marketplace has newer content \u2014 fetching the update..."
|
|
12833
13099
|
};
|
|
13100
|
+
var AGENT_PARTIAL_FILES = [
|
|
13101
|
+
STANDARD_FILES.IDENTITY_MD,
|
|
13102
|
+
STANDARD_FILES.PLAYBOOK_MD,
|
|
13103
|
+
STANDARD_FILES.CRITICAL_REQUIREMENTS_MD,
|
|
13104
|
+
STANDARD_FILES.CRITICAL_REMINDERS_MD,
|
|
13105
|
+
STANDARD_FILES.OUTPUT_MD
|
|
13106
|
+
];
|
|
12834
13107
|
var INFO_MESSAGES = {
|
|
12835
13108
|
NO_CHANGES_MADE: "No changes made.",
|
|
12836
13109
|
RUN_COMPILE: `Run '${CLI_INVOKE_COMMAND} compile' to include imported skills in your agents.`,
|
|
@@ -12845,7 +13118,9 @@ var INFO_MESSAGES = {
|
|
|
12845
13118
|
* their work — this line says so once, as information rather than a warning.
|
|
12846
13119
|
*/
|
|
12847
13120
|
EJECTED_SKILLS_USER_OWNED: `Ejected skills are yours to own \u2014 '${CLI_INVOKE_COMMAND} update' does not change them.`,
|
|
12848
|
-
NO_PLUGIN_MARKETPLACES: "No plugin marketplaces are configured \u2014 nothing to refresh."
|
|
13121
|
+
NO_PLUGIN_MARKETPLACES: "No plugin marketplaces are configured \u2014 nothing to refresh.",
|
|
13122
|
+
/** Printed under the destination `eject agent-partials` just named, so it names files only. */
|
|
13123
|
+
AGENT_PARTIALS_CUSTOMIZABLE: `Each sub-agent directory there holds ${AGENT_PARTIAL_FILES.join(", ")} \u2014 edit those to customize that sub-agent.`
|
|
12849
13124
|
};
|
|
12850
13125
|
function pluginsInstalled(count) {
|
|
12851
13126
|
return `Installed ${count} skill plugins`;
|
|
@@ -12885,6 +13160,31 @@ function marketplacesRefreshFailed(marketplaces) {
|
|
|
12885
13160
|
const subject = marketplaces.length === 1 ? "marketplace" : "marketplaces";
|
|
12886
13161
|
return `${marketplaces.length} ${subject} could not be updated: ${marketplaces.join(", ")}`;
|
|
12887
13162
|
}
|
|
13163
|
+
function marketplaceOwnerHasNoName(packageJsonPath) {
|
|
13164
|
+
return [
|
|
13165
|
+
`A marketplace's owner must have a name, and no name could be read from 'author' in ${packageJsonPath}.`,
|
|
13166
|
+
`Nothing was written: a ${MARKETPLACE_JSON} whose 'owner.name' is empty is refused by this CLI's own reader, so the build would have reported success for a marketplace nobody can install from.`,
|
|
13167
|
+
`Set 'author' in that file \u2014 either "Jane Doe <jane@example.com>" or { "name": "Jane Doe" } \u2014 and build again.`
|
|
13168
|
+
].join("\n\n");
|
|
13169
|
+
}
|
|
13170
|
+
function marketplaceHasNoVersion(packageJsonPath) {
|
|
13171
|
+
return [
|
|
13172
|
+
`A marketplace must have a version, and 'version' in ${packageJsonPath} is empty.`,
|
|
13173
|
+
`Nothing was written: a ${MARKETPLACE_JSON} whose 'version' is empty is refused by this CLI's own reader, so the build would have reported success for a marketplace nobody can install from.`,
|
|
13174
|
+
`Set 'version' in that file \u2014 "0.1.0" if this is its first release \u2014 and build again.`
|
|
13175
|
+
].join("\n\n");
|
|
13176
|
+
}
|
|
13177
|
+
function marketplaceNameNotPublishable(name, packageJsonPath) {
|
|
13178
|
+
const offenders = charactersOutsideKebabCase(name);
|
|
13179
|
+
return [
|
|
13180
|
+
`Marketplace name '${name}', read from 'name' in ${packageJsonPath}, is not a name a marketplace may publish under.`,
|
|
13181
|
+
...offenders.length > 0 ? [
|
|
13182
|
+
`It carries ${offenders.map((character) => `'${character}'`).join(" and ")}, which a marketplace name may not.`
|
|
13183
|
+
] : [],
|
|
13184
|
+
`A marketplace name is kebab-case: lowercase letters, numbers and hyphens, starting with a letter.`,
|
|
13185
|
+
`Publish under a name of your own instead: '${CLI_INVOKE_COMMAND} build marketplace --name <your-marketplace>'.`
|
|
13186
|
+
].join("\n\n");
|
|
13187
|
+
}
|
|
12888
13188
|
function configTypesRefreshFailed(reason) {
|
|
12889
13189
|
return `Could not refresh ${STANDARD_FILES.CONFIG_TYPES_TS} \u2014 type unions may be stale: ${reason}`;
|
|
12890
13190
|
}
|
|
@@ -12918,17 +13218,94 @@ function skillMetadataUnusableError(entries) {
|
|
|
12918
13218
|
function savedSkillMetadataUnusableError(entries) {
|
|
12919
13219
|
return [
|
|
12920
13220
|
metadataUnusableOpening(entries),
|
|
12921
|
-
`A config entry naming a skill this file cannot describe is dropped as one this
|
|
13221
|
+
`A config entry naming a skill this file cannot describe is dropped as one this marketplace does not carry \u2014 and a file that can be repaired must not cost an install its record.`,
|
|
12922
13222
|
METADATA_UNUSABLE_WAY_OUT
|
|
12923
13223
|
].join("\n");
|
|
12924
13224
|
}
|
|
12925
13225
|
var SHARED_CONFIG_GREENFIELD_HINT = "installing a shared configuration is a fresh setup, not a merge";
|
|
13226
|
+
function sharedConfigDestinations(id) {
|
|
13227
|
+
return [
|
|
13228
|
+
` Install it: ${CLI_INVOKE_COMMAND} init --from ${id}`,
|
|
13229
|
+
` Open it: ${editorConfigUrl(id)}`
|
|
13230
|
+
];
|
|
13231
|
+
}
|
|
12926
13232
|
function sharedConfigExistingInstall(configPath) {
|
|
12927
13233
|
return `An installation already exists at ${configPath}. Run '${CLI_INVOKE_COMMAND} uninstall' first \u2014 ${SHARED_CONFIG_GREENFIELD_HINT}.`;
|
|
12928
13234
|
}
|
|
12929
13235
|
function sharedConfigGlobalInstall(configPath) {
|
|
12930
13236
|
return `This configuration installs global-scoped content, and a global installation already exists at ${configPath}. Run '${CLI_INVOKE_COMMAND} uninstall' from your home directory first \u2014 ${SHARED_CONFIG_GREENFIELD_HINT}.`;
|
|
12931
13237
|
}
|
|
13238
|
+
function sharedConfigProjectScopeAtHome(skillIds, agentNames) {
|
|
13239
|
+
return [
|
|
13240
|
+
"This configuration cannot be installed here: the home directory is the global scope, and a global installation holds only global-scoped content \u2014 so these project-scoped entries have nowhere to be written:",
|
|
13241
|
+
...skillIds.map((id) => ` skill ${id} (scope: project)`),
|
|
13242
|
+
...agentNames.map((name) => ` sub-agent ${name} (scope: project)`),
|
|
13243
|
+
"Run this from inside a project directory, or re-share it with each entry above at global scope."
|
|
13244
|
+
].join("\n");
|
|
13245
|
+
}
|
|
13246
|
+
function skippedUnknownSkills(skillIds) {
|
|
13247
|
+
return `Skipped ${skillIds.length} skill(s) this catalog does not know: ${skillIds.join(", ")}`;
|
|
13248
|
+
}
|
|
13249
|
+
function skippedUnknownAgents(agentNames) {
|
|
13250
|
+
return `Skipped ${agentNames.length} unknown sub-agent(s): ${agentNames.join(", ")}`;
|
|
13251
|
+
}
|
|
13252
|
+
function carriedSkillsWritten(skillIds) {
|
|
13253
|
+
return `Wrote ${skillIds.length} skill(s) this configuration carries: ${skillIds.join(", ")}`;
|
|
13254
|
+
}
|
|
13255
|
+
var SHARED_CONFIG_APPLY = {
|
|
13256
|
+
PREVIEW_HEADING: "Applying this configuration will remove:",
|
|
13257
|
+
SKILLS_HEADING: "Skills:",
|
|
13258
|
+
AGENTS_HEADING: "Sub-agents:",
|
|
13259
|
+
/**
|
|
13260
|
+
* The two headings a PROJECT run prints instead, for entries that live at global scope. They
|
|
13261
|
+
* exist only there: at the home directory every entry is global, so a heading saying so would
|
|
13262
|
+
* label the whole list with the one fact the location already states.
|
|
13263
|
+
*/
|
|
13264
|
+
GLOBAL_SKILLS_HEADING: "Skills installed globally:",
|
|
13265
|
+
GLOBAL_AGENTS_HEADING: "Sub-agents installed globally:",
|
|
13266
|
+
/** Printed in place of the sections when the payload takes nothing away. */
|
|
13267
|
+
NOTHING_REMOVED: "Nothing is removed \u2014 this configuration only adds and re-tunes.",
|
|
13268
|
+
CONFIRM: "Apply this configuration?"
|
|
13269
|
+
};
|
|
13270
|
+
function sharedConfigNeedsTerminal(id) {
|
|
13271
|
+
return [
|
|
13272
|
+
`Applying configuration '${id}' removes whatever it leaves out, so it has to be confirmed \u2014 and there is no terminal here to confirm it at.`,
|
|
13273
|
+
`Run '${CLI_INVOKE_COMMAND} edit --from ${id}' from a terminal, or '${CLI_INVOKE_COMMAND} init --from ${id}' in a clean directory, which installs without removing anything.`
|
|
13274
|
+
].join("\n");
|
|
13275
|
+
}
|
|
13276
|
+
var SHARED_CONFIG_ONE_DIRECTION = "--ui and --from are the two directions of the same round trip: --ui hands this installation to the editor, and --from applies one back. Run one, then the other.";
|
|
13277
|
+
function globallyInstalledRemoved(otherProjects) {
|
|
13278
|
+
return [
|
|
13279
|
+
"These are installed globally, and a global install is shared by every project on this machine.",
|
|
13280
|
+
...globalRemovalReach(otherProjects),
|
|
13281
|
+
`To keep them, answer no and re-share the configuration with them included.`
|
|
13282
|
+
].join("\n");
|
|
13283
|
+
}
|
|
13284
|
+
function globalRemovalReach(otherProjects) {
|
|
13285
|
+
if (otherProjects.length === 0) {
|
|
13286
|
+
return [
|
|
13287
|
+
"No other project is registered here, so nothing else changes today \u2014 a project set up later inherits whatever the global install holds then."
|
|
13288
|
+
];
|
|
13289
|
+
}
|
|
13290
|
+
return [
|
|
13291
|
+
`Also affects ${otherProjects.length} other registered project(s):`,
|
|
13292
|
+
...otherProjects.map((projectDir) => ` ${projectDir}`)
|
|
13293
|
+
];
|
|
13294
|
+
}
|
|
13295
|
+
function authoredHereKept(skillIds) {
|
|
13296
|
+
return [
|
|
13297
|
+
"Kept \u2014 written here rather than installed, so a shared configuration never carried them:",
|
|
13298
|
+
...skillIds.map((id) => ` skill ${id}`),
|
|
13299
|
+
`Remove them with '${CLI_INVOKE_COMMAND} edit'.`
|
|
13300
|
+
].join("\n");
|
|
13301
|
+
}
|
|
13302
|
+
function unplaceableKept(skillIds) {
|
|
13303
|
+
return [
|
|
13304
|
+
"Kept \u2014 named by this configuration, and this catalogue cannot place them:",
|
|
13305
|
+
...skillIds.map((id) => ` skill ${id}`),
|
|
13306
|
+
`Run '${CLI_INVOKE_COMMAND} update' to refresh this installation's marketplace, then apply the configuration again.`
|
|
13307
|
+
].join("\n");
|
|
13308
|
+
}
|
|
12932
13309
|
function configUnreadableError(configLoadFailure2) {
|
|
12933
13310
|
return [
|
|
12934
13311
|
configLoadFailure2,
|
|
@@ -12940,8 +13317,10 @@ function configUnreadableError(configLoadFailure2) {
|
|
|
12940
13317
|
function registeredProjectsUpdateFailed(reason) {
|
|
12941
13318
|
return `Could not update registered projects \u2014 their configs may still reference the uninstalled global content: ${reason}`;
|
|
12942
13319
|
}
|
|
12943
|
-
function
|
|
12944
|
-
|
|
13320
|
+
function unmarkedAgentsKept(agentsDir, count) {
|
|
13321
|
+
const subject = count === 1 ? "agent" : "agents";
|
|
13322
|
+
const object = count === 1 ? "it" : "them";
|
|
13323
|
+
return `Kept ${count} ${subject} in ${agentsDir}/ \u2014 no ${DEFAULT_PLUGIN_NAME} marker, so this CLI did not compile ${object}.`;
|
|
12945
13324
|
}
|
|
12946
13325
|
var UNINSTALL_PLAN = {
|
|
12947
13326
|
PREVIEW_HEADING: "The following will be removed:",
|
|
@@ -12950,7 +13329,7 @@ var UNINSTALL_PLAN = {
|
|
|
12950
13329
|
CONFIG_HEADING: "Config:"
|
|
12951
13330
|
};
|
|
12952
13331
|
function localSkillsRemoval(skillsDir) {
|
|
12953
|
-
return `${skillsDir}/ (matching
|
|
13332
|
+
return `${skillsDir}/ (matching the marketplace)`;
|
|
12954
13333
|
}
|
|
12955
13334
|
function compiledAgentsRemoval(agentsDir) {
|
|
12956
13335
|
return `${agentsDir}/ (CLI-compiled)`;
|
|
@@ -12968,7 +13347,7 @@ function sanitizeSourceForCache(source) {
|
|
|
12968
13347
|
}
|
|
12969
13348
|
function getCacheDir(source) {
|
|
12970
13349
|
const sanitized = sanitizeSourceForCache(source) || "unknown";
|
|
12971
|
-
return
|
|
13350
|
+
return path13.join(CACHE_DIR, "sources", sanitized);
|
|
12972
13351
|
}
|
|
12973
13352
|
async function fetchFromSource(source, options = {}) {
|
|
12974
13353
|
const { subdir } = options;
|
|
@@ -12978,19 +13357,19 @@ async function fetchFromSource(source, options = {}) {
|
|
|
12978
13357
|
return fetchFromRemoteSource(source, subdir);
|
|
12979
13358
|
}
|
|
12980
13359
|
async function fetchFromLocalSource(source, subdir) {
|
|
12981
|
-
const fullPath = subdir ?
|
|
12982
|
-
const absolutePath =
|
|
13360
|
+
const fullPath = subdir ? path13.join(source, subdir) : source;
|
|
13361
|
+
const absolutePath = path13.isAbsolute(fullPath) ? fullPath : path13.resolve(process.cwd(), fullPath);
|
|
12983
13362
|
if (!await directoryExists(absolutePath)) {
|
|
12984
13363
|
throw new Error(
|
|
12985
|
-
`Local
|
|
13364
|
+
`Local marketplace not found: '${absolutePath}'
|
|
12986
13365
|
|
|
12987
|
-
Nothing is at that path, and a local
|
|
13366
|
+
Nothing is at that path, and a local marketplace must be a directory holding skills.
|
|
12988
13367
|
|
|
12989
13368
|
Check it for a typo, or name a marketplace that exists:
|
|
12990
|
-
--
|
|
13369
|
+
--marketplace ${DEFAULT_SOURCE}`
|
|
12991
13370
|
);
|
|
12992
13371
|
}
|
|
12993
|
-
verbose(`Using local
|
|
13372
|
+
verbose(`Using local marketplace: ${absolutePath}`);
|
|
12994
13373
|
return {
|
|
12995
13374
|
path: absolutePath,
|
|
12996
13375
|
fromCache: false,
|
|
@@ -13009,8 +13388,8 @@ function getGigetCacheDir(source) {
|
|
|
13009
13388
|
return void 0;
|
|
13010
13389
|
}
|
|
13011
13390
|
const templateName = uriMatch.groups.repo.replace("/", "-").replace(/[^\da-z-]/gi, "-");
|
|
13012
|
-
const gigetCacheRoot = process.env.XDG_CACHE_HOME ?
|
|
13013
|
-
return
|
|
13391
|
+
const gigetCacheRoot = process.env.XDG_CACHE_HOME ? path13.resolve(process.env.XDG_CACHE_HOME, "giget") : path13.resolve(os7.homedir(), ".cache", "giget");
|
|
13392
|
+
return path13.join(gigetCacheRoot, providerName, templateName);
|
|
13014
13393
|
}
|
|
13015
13394
|
async function clearGigetCache(source) {
|
|
13016
13395
|
const gigetDir = getGigetCacheDir(source);
|
|
@@ -13029,14 +13408,14 @@ async function fetchFromRemoteSource(source, subdir) {
|
|
|
13029
13408
|
const verdict = await revalidateCachedCopy(cacheDir, source);
|
|
13030
13409
|
const cached = { path: cacheDir, fromCache: true, source: fullSource };
|
|
13031
13410
|
if (verdict === "current" || verdict === "unreachable") {
|
|
13032
|
-
verbose(`Using cached
|
|
13411
|
+
verbose(`Using cached marketplace: ${cacheDir}`);
|
|
13033
13412
|
return cached;
|
|
13034
13413
|
}
|
|
13035
13414
|
announceRefetch(verdict);
|
|
13036
13415
|
await clearGigetCache(source);
|
|
13037
13416
|
await remove(cacheDir);
|
|
13038
13417
|
}
|
|
13039
|
-
await ensureDir(
|
|
13418
|
+
await ensureDir(path13.dirname(cacheDir));
|
|
13040
13419
|
try {
|
|
13041
13420
|
const result = await downloadTemplate(fullSource, {
|
|
13042
13421
|
dir: cacheDir,
|
|
@@ -13111,7 +13490,7 @@ async function readFetchRecord(cacheDir) {
|
|
|
13111
13490
|
if (!raw) return void 0;
|
|
13112
13491
|
const parsed = sourceRevalidationSchema.safeParse(parseJsonOrUndefined(raw));
|
|
13113
13492
|
if (!parsed.success) {
|
|
13114
|
-
verbose(`Unusable fetch record at ${fetchRecordPath(cacheDir)} \u2014 re-fetching the
|
|
13493
|
+
verbose(`Unusable fetch record at ${fetchRecordPath(cacheDir)} \u2014 re-fetching the marketplace`);
|
|
13115
13494
|
return void 0;
|
|
13116
13495
|
}
|
|
13117
13496
|
return parsed.data;
|
|
@@ -13179,23 +13558,25 @@ If you're behind a corporate proxy, you may need to set:
|
|
|
13179
13558
|
}
|
|
13180
13559
|
return new Error(`Failed to fetch ${source}: ${message}`);
|
|
13181
13560
|
}
|
|
13561
|
+
var MarketplaceManifestAbsentError = class extends Error {
|
|
13562
|
+
};
|
|
13182
13563
|
async function fetchMarketplace(source) {
|
|
13183
13564
|
const result = await fetchFromSource(source, {
|
|
13184
13565
|
subdir: ""
|
|
13185
13566
|
// Root of repo
|
|
13186
13567
|
});
|
|
13187
13568
|
const marketplacePath = marketplaceManifestPath(result.path);
|
|
13188
|
-
if (!await
|
|
13189
|
-
throw new
|
|
13190
|
-
`Marketplace not found
|
|
13569
|
+
if (!await fileExists(marketplacePath)) {
|
|
13570
|
+
throw new MarketplaceManifestAbsentError(
|
|
13571
|
+
`Marketplace not found at: ${source}
|
|
13191
13572
|
|
|
13192
13573
|
The .claude-plugin/marketplace.json file is missing from this repository.
|
|
13193
13574
|
|
|
13194
13575
|
Possible causes:
|
|
13195
|
-
- The
|
|
13576
|
+
- The marketplace URL may be incorrect
|
|
13196
13577
|
- The repository may not have a marketplace configured
|
|
13197
13578
|
|
|
13198
|
-
To create a marketplace, add a .claude-plugin/marketplace.json file to your
|
|
13579
|
+
To create a marketplace, add a .claude-plugin/marketplace.json file to your marketplace repository.`
|
|
13199
13580
|
);
|
|
13200
13581
|
}
|
|
13201
13582
|
const content = await readFileSafe(marketplacePath, MAX_MARKETPLACE_FILE_SIZE);
|
|
@@ -13255,22 +13636,26 @@ Too many plugins: ${marketplace.plugins.length} (limit: ${MAX_MARKETPLACE_PLUGIN
|
|
|
13255
13636
|
|
|
13256
13637
|
// src/cli/lib/loading/multi-source-loader.ts
|
|
13257
13638
|
import os8 from "os";
|
|
13639
|
+
function isLocalOnlySkill(skill) {
|
|
13640
|
+
return skill?.availableSources !== void 0 && !skill.availableSources.some((source) => source.type !== "local");
|
|
13641
|
+
}
|
|
13258
13642
|
function addAvailableSource(skill, source) {
|
|
13259
13643
|
skill.availableSources = skill.availableSources ?? [];
|
|
13260
13644
|
skill.availableSources.push(source);
|
|
13261
13645
|
}
|
|
13262
|
-
async function loadSkillsFromAllSources(primaryMatrix, sourceConfig, projectDir, marketplace) {
|
|
13646
|
+
async function loadSkillsFromAllSources(primaryMatrix, sourceConfig, projectDir, marketplace, unbackedSkillIds = /* @__PURE__ */ new Set()) {
|
|
13263
13647
|
const resolvedMarketplace = marketplace ?? sourceConfig.marketplace;
|
|
13264
13648
|
const primarySourceName = resolvedMarketplace ?? DEFAULT_PUBLIC_SOURCE_NAME;
|
|
13265
13649
|
const primarySourceType = isDefaultSource(sourceConfig.source) ? "public" : "private";
|
|
13266
|
-
tagPrimarySourceSkills(primaryMatrix, primarySourceName, primarySourceType);
|
|
13650
|
+
tagPrimarySourceSkills(primaryMatrix, primarySourceName, primarySourceType, unbackedSkillIds);
|
|
13267
13651
|
tagLocalSkills(primaryMatrix);
|
|
13268
13652
|
await tagPluginSkills(primaryMatrix, projectDir, primarySourceName, primarySourceType);
|
|
13269
13653
|
setActiveSources(primaryMatrix);
|
|
13270
13654
|
}
|
|
13271
|
-
function tagPrimarySourceSkills(matrix2, sourceName, sourceType) {
|
|
13272
|
-
for (const [, skill] of typedEntries(matrix2.skills)) {
|
|
13655
|
+
function tagPrimarySourceSkills(matrix2, sourceName, sourceType, unbackedSkillIds) {
|
|
13656
|
+
for (const [id, skill] of typedEntries(matrix2.skills)) {
|
|
13273
13657
|
if (!skill) continue;
|
|
13658
|
+
if (unbackedSkillIds.has(id)) continue;
|
|
13274
13659
|
const source = {
|
|
13275
13660
|
name: sourceName,
|
|
13276
13661
|
type: sourceType,
|
|
@@ -13409,9 +13794,60 @@ async function resolveAgents(agents, skills, compileConfig, _projectRoot) {
|
|
|
13409
13794
|
|
|
13410
13795
|
// src/cli/lib/compiler.ts
|
|
13411
13796
|
import { Liquid } from "liquidjs";
|
|
13412
|
-
import
|
|
13797
|
+
import path15 from "path";
|
|
13413
13798
|
import { pipe as pipe2, flatMap as flatMap2, filter, uniqueBy as uniqueBy3 } from "remeda";
|
|
13414
13799
|
|
|
13800
|
+
// src/cli/lib/agents/agent-provenance.ts
|
|
13801
|
+
import path14 from "path";
|
|
13802
|
+
import { z as z7 } from "zod";
|
|
13803
|
+
var MARKER_OPEN = `<!-- Generated by ${DEFAULT_PLUGIN_NAME} v`;
|
|
13804
|
+
var MARKER_NOTICE = " \u2014 do not edit; compile rewrites this file";
|
|
13805
|
+
var MARKER_CLOSE = " -->";
|
|
13806
|
+
var FRONTMATTER_FENCE = "---";
|
|
13807
|
+
var PACKAGE_JSON_FILE = "package.json";
|
|
13808
|
+
var ownPackageJsonSchema = z7.object({ version: z7.string().min(1) });
|
|
13809
|
+
function provenanceMarker(version) {
|
|
13810
|
+
return `${MARKER_OPEN}${version}${MARKER_NOTICE}${MARKER_CLOSE}`;
|
|
13811
|
+
}
|
|
13812
|
+
function isProvenanceMarker(line) {
|
|
13813
|
+
return line.startsWith(MARKER_OPEN) && line.endsWith(MARKER_CLOSE);
|
|
13814
|
+
}
|
|
13815
|
+
function bodyStartIndex(lines) {
|
|
13816
|
+
if (lines[0] !== FRONTMATTER_FENCE) return 0;
|
|
13817
|
+
const closingFence = lines.indexOf(FRONTMATTER_FENCE, 1);
|
|
13818
|
+
if (closingFence === -1) return 0;
|
|
13819
|
+
return closingFence + 1;
|
|
13820
|
+
}
|
|
13821
|
+
function hasProvenanceMarker(content) {
|
|
13822
|
+
const lines = content.split("\n");
|
|
13823
|
+
const firstBodyLine = lines[bodyStartIndex(lines)];
|
|
13824
|
+
return firstBodyLine !== void 0 && isProvenanceMarker(firstBodyLine);
|
|
13825
|
+
}
|
|
13826
|
+
function stampProvenanceMarker(content, version) {
|
|
13827
|
+
const lines = content.split("\n");
|
|
13828
|
+
const bodyStart = bodyStartIndex(lines);
|
|
13829
|
+
const replacedLines = hasProvenanceMarker(content) ? 1 : 0;
|
|
13830
|
+
return [
|
|
13831
|
+
...lines.slice(0, bodyStart),
|
|
13832
|
+
provenanceMarker(version),
|
|
13833
|
+
...lines.slice(bodyStart + replacedLines)
|
|
13834
|
+
].join("\n");
|
|
13835
|
+
}
|
|
13836
|
+
var ownVersion;
|
|
13837
|
+
function cliVersion() {
|
|
13838
|
+
ownVersion ??= readOwnVersion();
|
|
13839
|
+
return ownVersion;
|
|
13840
|
+
}
|
|
13841
|
+
async function readOwnVersion() {
|
|
13842
|
+
const manifestPath = path14.join(PROJECT_ROOT, PACKAGE_JSON_FILE);
|
|
13843
|
+
const raw = JSON.parse(await readFile(manifestPath));
|
|
13844
|
+
const parsed = ownPackageJsonSchema.safeParse(raw);
|
|
13845
|
+
if (!parsed.success) {
|
|
13846
|
+
throw new Error(`Could not read this CLI's own version from ${manifestPath}`);
|
|
13847
|
+
}
|
|
13848
|
+
return parsed.data.version;
|
|
13849
|
+
}
|
|
13850
|
+
|
|
13415
13851
|
// src/cli/lib/validation-result.ts
|
|
13416
13852
|
function validResult() {
|
|
13417
13853
|
return { valid: true, errors: [], warnings: [] };
|
|
@@ -13490,24 +13926,24 @@ function sanitizeCompiledAgentData(data) {
|
|
|
13490
13926
|
async function readAgentFiles(name, agent, projectRoot) {
|
|
13491
13927
|
const agentSourceRoot = agent.sourceRoot || projectRoot;
|
|
13492
13928
|
const agentBaseDir = agent.agentBaseDir || DIRS.agents;
|
|
13493
|
-
const agentDir =
|
|
13494
|
-
const identity = await readFile(
|
|
13495
|
-
const playbook = await readFile(
|
|
13929
|
+
const agentDir = path15.join(agentSourceRoot, agentBaseDir, agent.path || name);
|
|
13930
|
+
const identity = await readFile(path15.join(agentDir, STANDARD_FILES.IDENTITY_MD));
|
|
13931
|
+
const playbook = await readFile(path15.join(agentDir, STANDARD_FILES.PLAYBOOK_MD));
|
|
13496
13932
|
const criticalRequirementsTop = await readFileOptional(
|
|
13497
|
-
|
|
13933
|
+
path15.join(agentDir, STANDARD_FILES.CRITICAL_REQUIREMENTS_MD),
|
|
13498
13934
|
""
|
|
13499
13935
|
);
|
|
13500
13936
|
const criticalReminders = await readFileOptional(
|
|
13501
|
-
|
|
13937
|
+
path15.join(agentDir, STANDARD_FILES.CRITICAL_REMINDERS_MD),
|
|
13502
13938
|
""
|
|
13503
13939
|
);
|
|
13504
13940
|
const agentPath = agent.path || name;
|
|
13505
13941
|
const parts = agentPath.split("/");
|
|
13506
13942
|
const category = parts[0] || name;
|
|
13507
|
-
const categoryDir =
|
|
13508
|
-
let output = await readFileOptional(
|
|
13943
|
+
const categoryDir = path15.join(agentSourceRoot, agentBaseDir, category);
|
|
13944
|
+
let output = await readFileOptional(path15.join(agentDir, STANDARD_FILES.OUTPUT_MD), "");
|
|
13509
13945
|
if (!output) {
|
|
13510
|
-
output = await readFileOptional(
|
|
13946
|
+
output = await readFileOptional(path15.join(categoryDir, STANDARD_FILES.OUTPUT_MD), "");
|
|
13511
13947
|
}
|
|
13512
13948
|
return { identity, playbook, output, criticalRequirementsTop, criticalReminders };
|
|
13513
13949
|
}
|
|
@@ -13528,26 +13964,30 @@ function buildAgentTemplateContext(name, agent, files, mapSkill = (skill) => ski
|
|
|
13528
13964
|
preloadedSkillIds
|
|
13529
13965
|
};
|
|
13530
13966
|
}
|
|
13967
|
+
async function renderCompiledAgent(engine, data) {
|
|
13968
|
+
const rendered = await engine.renderFile("agent", sanitizeCompiledAgentData(data));
|
|
13969
|
+
return stampProvenanceMarker(rendered, await cliVersion());
|
|
13970
|
+
}
|
|
13531
13971
|
async function createLiquidEngine(projectDir) {
|
|
13532
13972
|
const roots = [];
|
|
13533
13973
|
if (projectDir) {
|
|
13534
|
-
const srcTemplatesDir =
|
|
13974
|
+
const srcTemplatesDir = path15.join(
|
|
13535
13975
|
projectDir,
|
|
13536
13976
|
CLAUDE_SRC_DIR,
|
|
13537
13977
|
STANDARD_DIRS.AGENTS,
|
|
13538
|
-
|
|
13978
|
+
path15.basename(DIRS.templates)
|
|
13539
13979
|
);
|
|
13540
13980
|
if (await directoryExists(srcTemplatesDir)) {
|
|
13541
13981
|
roots.push(srcTemplatesDir);
|
|
13542
13982
|
verbose(`Using local templates from: ${srcTemplatesDir}`);
|
|
13543
13983
|
}
|
|
13544
|
-
const legacyTemplatesDir =
|
|
13984
|
+
const legacyTemplatesDir = path15.join(projectDir, CLAUDE_DIR, STANDARD_DIRS.TEMPLATES);
|
|
13545
13985
|
if (await directoryExists(legacyTemplatesDir)) {
|
|
13546
13986
|
roots.push(legacyTemplatesDir);
|
|
13547
13987
|
verbose(`Using legacy templates from: ${legacyTemplatesDir}`);
|
|
13548
13988
|
}
|
|
13549
13989
|
}
|
|
13550
|
-
roots.push(
|
|
13990
|
+
roots.push(path15.join(PROJECT_ROOT, DIRS.templates));
|
|
13551
13991
|
return new Liquid({
|
|
13552
13992
|
root: roots,
|
|
13553
13993
|
extname: ".liquid",
|
|
@@ -13566,12 +14006,12 @@ async function compileAgentForPlugin(name, agent, fallbackRoot, engine) {
|
|
|
13566
14006
|
...skill,
|
|
13567
14007
|
...pluginRefFor(skill)
|
|
13568
14008
|
}));
|
|
13569
|
-
return engine
|
|
14009
|
+
return renderCompiledAgent(engine, data);
|
|
13570
14010
|
}
|
|
13571
14011
|
|
|
13572
14012
|
// src/cli/lib/agents/write-compiled-agents.ts
|
|
13573
14013
|
import os9 from "os";
|
|
13574
|
-
import
|
|
14014
|
+
import path16 from "path";
|
|
13575
14015
|
async function holdsExactly(filePath, content) {
|
|
13576
14016
|
return await fileExists(filePath) && await readFile(filePath) === content;
|
|
13577
14017
|
}
|
|
@@ -13584,7 +14024,7 @@ async function writeCompiledAgentsByScope(params) {
|
|
|
13584
14024
|
const output = await compileAgentForPlugin(name, agent, params.sourcePath, params.engine);
|
|
13585
14025
|
const scope = params.agentScopeMap?.get(name) ?? UNROUTED_AGENT_SCOPE;
|
|
13586
14026
|
const targetDir = scope === "global" ? globalAgentsDir : params.projectAgentsDir;
|
|
13587
|
-
const targetPath =
|
|
14027
|
+
const targetPath = path16.join(targetDir, `${name}.md`);
|
|
13588
14028
|
const rewritten = !await holdsExactly(targetPath, output);
|
|
13589
14029
|
if (rewritten) await writeFile(targetPath, output);
|
|
13590
14030
|
outcomes.push({ name, ok: true, scope, targetDir, rewritten });
|
|
@@ -13597,11 +14037,11 @@ async function writeCompiledAgentsByScope(params) {
|
|
|
13597
14037
|
|
|
13598
14038
|
// src/cli/lib/config-gate/index.ts
|
|
13599
14039
|
import os12 from "os";
|
|
13600
|
-
import
|
|
14040
|
+
import path19 from "path";
|
|
13601
14041
|
|
|
13602
14042
|
// src/cli/lib/configuration/config-writer.ts
|
|
13603
14043
|
import os10 from "os";
|
|
13604
|
-
import
|
|
14044
|
+
import path17 from "path";
|
|
13605
14045
|
var EXTRACTED_FIELDS = /* @__PURE__ */ new Set(["skills", "agents", "stack", "selectedDomains"]);
|
|
13606
14046
|
var CANONICAL_FIELD_ORDER = [
|
|
13607
14047
|
"name",
|
|
@@ -13611,8 +14051,8 @@ var CANONICAL_FIELD_ORDER = [
|
|
|
13611
14051
|
"author",
|
|
13612
14052
|
"selectedDomains",
|
|
13613
14053
|
"stack",
|
|
13614
|
-
"source",
|
|
13615
14054
|
"marketplace",
|
|
14055
|
+
"marketplaceName",
|
|
13616
14056
|
"agentsSource",
|
|
13617
14057
|
"projects"
|
|
13618
14058
|
];
|
|
@@ -13624,6 +14064,20 @@ function canonicalizeFieldOrder(cleaned) {
|
|
|
13624
14064
|
const passthrough = Object.entries(cleaned).filter(([key]) => !CANONICAL_FIELDS.has(key));
|
|
13625
14065
|
return Object.fromEntries([...inSchemaOrder, ...passthrough]);
|
|
13626
14066
|
}
|
|
14067
|
+
function withKeysOrderedBy(record, compareKeys) {
|
|
14068
|
+
return Object.fromEntries(Object.entries(record).sort(([a], [b]) => compareKeys(a, b)));
|
|
14069
|
+
}
|
|
14070
|
+
function compareNamesInCodeUnitOrder(a, b) {
|
|
14071
|
+
if (a === b) return 0;
|
|
14072
|
+
return a < b ? -1 : 1;
|
|
14073
|
+
}
|
|
14074
|
+
function canonicalizeStackOrder(stack) {
|
|
14075
|
+
const byDeclaration = byCategoryDeclarationOrder();
|
|
14076
|
+
const withCategoriesInOrder = Object.entries(stack).map(
|
|
14077
|
+
([agent, categories]) => [agent, withKeysOrderedBy(categories, byDeclaration)]
|
|
14078
|
+
);
|
|
14079
|
+
return withKeysOrderedBy(Object.fromEntries(withCategoriesInOrder), compareNamesInCodeUnitOrder);
|
|
14080
|
+
}
|
|
13627
14081
|
function renderEntryLine(entry) {
|
|
13628
14082
|
return ` ${JSON.stringify(entry)},`;
|
|
13629
14083
|
}
|
|
@@ -13644,9 +14098,10 @@ function cleanForEmission(config, options) {
|
|
|
13644
14098
|
delete cleaned.projects;
|
|
13645
14099
|
}
|
|
13646
14100
|
if (cleaned.stack) {
|
|
13647
|
-
|
|
14101
|
+
const compacted = compactStackAssignments(
|
|
13648
14102
|
cleaned.stack
|
|
13649
14103
|
);
|
|
14104
|
+
cleaned.stack = canonicalizeStackOrder(compacted);
|
|
13650
14105
|
}
|
|
13651
14106
|
return canonicalizeFieldOrder(cleaned);
|
|
13652
14107
|
}
|
|
@@ -13923,7 +14378,7 @@ function compactStackAssignments(stack) {
|
|
|
13923
14378
|
);
|
|
13924
14379
|
}
|
|
13925
14380
|
function getGlobalConfigImportPath() {
|
|
13926
|
-
return
|
|
14381
|
+
return path17.join(os10.homedir(), CLAUDE_SRC_DIR);
|
|
13927
14382
|
}
|
|
13928
14383
|
function generateBlankGlobalConfigSource() {
|
|
13929
14384
|
return `import type { ProjectConfig } from "./config-types";
|
|
@@ -13992,7 +14447,7 @@ function diffSkills(prev, next) {
|
|
|
13992
14447
|
for (const [id, afterEntry] of after) {
|
|
13993
14448
|
const beforeEntry = before.get(id);
|
|
13994
14449
|
if (!beforeEntry || isDeepEqual(beforeEntry, afterEntry)) continue;
|
|
13995
|
-
if (beforeEntry.
|
|
14450
|
+
if (beforeEntry.origin !== afterEntry.origin) sourceChanged.push(id);
|
|
13996
14451
|
else otherChanged.push(id);
|
|
13997
14452
|
}
|
|
13998
14453
|
return { added, removed, sourceChanged, otherChanged };
|
|
@@ -14066,16 +14521,16 @@ var NO_AGENTS = Promise.resolve({});
|
|
|
14066
14521
|
|
|
14067
14522
|
// src/cli/lib/config-gate/pair-writer.ts
|
|
14068
14523
|
import os11 from "os";
|
|
14069
|
-
import
|
|
14524
|
+
import path18 from "path";
|
|
14070
14525
|
function globalPairPaths() {
|
|
14071
|
-
const dir =
|
|
14526
|
+
const dir = path18.join(os11.homedir(), CLAUDE_SRC_DIR);
|
|
14072
14527
|
return {
|
|
14073
|
-
configPath:
|
|
14074
|
-
typesPath:
|
|
14528
|
+
configPath: path18.join(dir, STANDARD_FILES.CONFIG_TS),
|
|
14529
|
+
typesPath: path18.join(dir, STANDARD_FILES.CONFIG_TYPES_TS)
|
|
14075
14530
|
};
|
|
14076
14531
|
}
|
|
14077
14532
|
function typesPathFor(configPath) {
|
|
14078
|
-
return
|
|
14533
|
+
return path18.join(path18.dirname(configPath), STANDARD_FILES.CONFIG_TYPES_TS);
|
|
14079
14534
|
}
|
|
14080
14535
|
async function writeIfChanged(filePath, source) {
|
|
14081
14536
|
assertGateToken(filePath);
|
|
@@ -14124,16 +14579,16 @@ async function ensureBlankPair() {
|
|
|
14124
14579
|
verbose("Global config already exists, skipping blank creation");
|
|
14125
14580
|
return false;
|
|
14126
14581
|
}
|
|
14127
|
-
await ensureDir(
|
|
14582
|
+
await ensureDir(path18.dirname(configPath));
|
|
14128
14583
|
await writeIfChanged(configPath, generateBlankGlobalConfigSource());
|
|
14129
14584
|
await writeIfChanged(typesPath, generateBlankGlobalConfigTypesSource());
|
|
14130
|
-
verbose(`Created blank global config at ${
|
|
14585
|
+
verbose(`Created blank global config at ${path18.dirname(configPath)}`);
|
|
14131
14586
|
return true;
|
|
14132
14587
|
}
|
|
14133
14588
|
|
|
14134
14589
|
// src/cli/lib/config-gate/propagate.ts
|
|
14135
14590
|
import fs2 from "fs";
|
|
14136
|
-
import { isDeepEqual as isDeepEqual2, unique as
|
|
14591
|
+
import { isDeepEqual as isDeepEqual2, unique as unique4 } from "remeda";
|
|
14137
14592
|
async function writeConfigFile(config, configPath, options) {
|
|
14138
14593
|
const source = generateConfigSource(config, options);
|
|
14139
14594
|
await writeFile(configPath, source);
|
|
@@ -14197,9 +14652,9 @@ function mergeGlobalConfigs(existing, incoming) {
|
|
|
14197
14652
|
const mergedSelectedDomains = [
|
|
14198
14653
|
.../* @__PURE__ */ new Set([...existing.selectedDomains ?? [], ...incoming.selectedDomains ?? []])
|
|
14199
14654
|
];
|
|
14655
|
+
const mergedMarketplaceName = existing.marketplaceName ?? incoming.marketplaceName;
|
|
14200
14656
|
const mergedMarketplace = existing.marketplace ?? incoming.marketplace;
|
|
14201
|
-
const
|
|
14202
|
-
const changed = newSkills.length > 0 || newAgents.length > 0 || stackChanged || !isDeepEqual2(existing.selectedDomains ?? [], mergedSelectedDomains) || mergedMarketplace !== existing.marketplace || mergedSource !== existing.source;
|
|
14657
|
+
const changed = newSkills.length > 0 || newAgents.length > 0 || stackChanged || !isDeepEqual2(existing.selectedDomains ?? [], mergedSelectedDomains) || mergedMarketplaceName !== existing.marketplaceName || mergedMarketplace !== existing.marketplace;
|
|
14203
14658
|
return {
|
|
14204
14659
|
config: {
|
|
14205
14660
|
...existing,
|
|
@@ -14207,8 +14662,8 @@ function mergeGlobalConfigs(existing, incoming) {
|
|
|
14207
14662
|
agents: mergedAgents,
|
|
14208
14663
|
stack: mergedStack,
|
|
14209
14664
|
selectedDomains: mergedSelectedDomains,
|
|
14210
|
-
...
|
|
14211
|
-
...
|
|
14665
|
+
...mergedMarketplaceName !== void 0 && { marketplaceName: mergedMarketplaceName },
|
|
14666
|
+
...mergedMarketplace !== void 0 && { marketplace: mergedMarketplace }
|
|
14212
14667
|
},
|
|
14213
14668
|
changed
|
|
14214
14669
|
};
|
|
@@ -14362,7 +14817,7 @@ function inlinedProjectView(reconciledSplit, effectiveGlobal) {
|
|
|
14362
14817
|
...reconciledSplit,
|
|
14363
14818
|
skills: [...effectiveGlobal.skills, ...reconciledSplit.skills],
|
|
14364
14819
|
agents: [...effectiveGlobal.agents, ...reconciledSplit.agents],
|
|
14365
|
-
selectedDomains:
|
|
14820
|
+
selectedDomains: unique4([
|
|
14366
14821
|
...effectiveGlobal.selectedDomains ?? [],
|
|
14367
14822
|
...reconciledSplit.selectedDomains ?? []
|
|
14368
14823
|
]),
|
|
@@ -14426,12 +14881,8 @@ async function pruneGlobalEntriesFromRegisteredProjects(globalConfig, matrix2, a
|
|
|
14426
14881
|
};
|
|
14427
14882
|
return propagateGlobalChangesToProjects(emptiedGlobal, matrix2, agents);
|
|
14428
14883
|
}
|
|
14429
|
-
async function resolveEffectiveGlobalConfig(globalSplit, existingGlobalConfig, projectDir) {
|
|
14430
|
-
const
|
|
14431
|
-
const merged = !hasGlobalItems ? {
|
|
14432
|
-
config: existingGlobalConfig ?? { name: GLOBAL_CONFIG_NAME, skills: [], agents: [] },
|
|
14433
|
-
changed: false
|
|
14434
|
-
} : existingGlobalConfig ? mergeGlobalConfigs(existingGlobalConfig, globalSplit) : { config: globalSplit, changed: true };
|
|
14884
|
+
async function resolveEffectiveGlobalConfig(globalSplit, existingGlobalConfig, projectDir, authority) {
|
|
14885
|
+
const merged = authority === "all" ? matchGlobalToSession(globalSplit, existingGlobalConfig) : addSessionToGlobal(globalSplit, existingGlobalConfig);
|
|
14435
14886
|
const registration = await registerProjectPath(merged.config, projectDir);
|
|
14436
14887
|
return {
|
|
14437
14888
|
config: registration.config,
|
|
@@ -14439,6 +14890,22 @@ async function resolveEffectiveGlobalConfig(globalSplit, existingGlobalConfig, p
|
|
|
14439
14890
|
changed: merged.changed || registration.changed
|
|
14440
14891
|
};
|
|
14441
14892
|
}
|
|
14893
|
+
function addSessionToGlobal(globalSplit, existingGlobalConfig) {
|
|
14894
|
+
const hasGlobalItems = globalSplit.skills.length > 0 || globalSplit.agents.length > 0;
|
|
14895
|
+
if (!hasGlobalItems) {
|
|
14896
|
+
return {
|
|
14897
|
+
config: existingGlobalConfig ?? { name: GLOBAL_CONFIG_NAME, skills: [], agents: [] },
|
|
14898
|
+
changed: false
|
|
14899
|
+
};
|
|
14900
|
+
}
|
|
14901
|
+
if (!existingGlobalConfig) return { config: globalSplit, changed: true };
|
|
14902
|
+
return mergeGlobalConfigs(existingGlobalConfig, globalSplit);
|
|
14903
|
+
}
|
|
14904
|
+
function matchGlobalToSession(globalSplit, existingGlobalConfig) {
|
|
14905
|
+
if (!existingGlobalConfig) return { config: globalSplit, changed: true };
|
|
14906
|
+
const config = mergeConfigs(globalSplit, existingGlobalConfig, { authoritativeScope: "all" });
|
|
14907
|
+
return { config, changed: !isDeepEqual2(config, existingGlobalConfig) };
|
|
14908
|
+
}
|
|
14442
14909
|
function buildConfigTypesBackgroundData(matrix2, agents) {
|
|
14443
14910
|
const agentNames = typedKeys(agents);
|
|
14444
14911
|
const customAgentNames = agentNames.filter((name) => agents[name]?.custom === true);
|
|
@@ -14450,13 +14917,13 @@ function stackCategories(stack) {
|
|
|
14450
14917
|
function buildProjectTypesExtras(finalConfig, matrix2) {
|
|
14451
14918
|
const activeSkills = finalConfig.skills.filter((s) => !s.excluded);
|
|
14452
14919
|
const activeAgents = finalConfig.agents.filter((a) => !a.excluded);
|
|
14453
|
-
const extraSkillIds =
|
|
14454
|
-
const extraAgentNames =
|
|
14455
|
-
const extraCategories =
|
|
14920
|
+
const extraSkillIds = unique4(activeSkills.map((s) => s.id));
|
|
14921
|
+
const extraAgentNames = unique4(activeAgents.map((a) => a.name));
|
|
14922
|
+
const extraCategories = unique4([
|
|
14456
14923
|
...deriveCategories(extraSkillIds, matrix2),
|
|
14457
14924
|
...stackCategories(finalConfig.stack)
|
|
14458
14925
|
]);
|
|
14459
|
-
const extraDomains =
|
|
14926
|
+
const extraDomains = unique4([
|
|
14460
14927
|
...deriveDomains(extraCategories, matrix2),
|
|
14461
14928
|
...finalConfig.selectedDomains ?? []
|
|
14462
14929
|
]);
|
|
@@ -14472,7 +14939,7 @@ var NOTHING_RECOMPILED = {
|
|
|
14472
14939
|
};
|
|
14473
14940
|
async function recompilePropagated(projectDirs) {
|
|
14474
14941
|
if (projectDirs.length === 0) return NOTHING_RECOMPILED;
|
|
14475
|
-
const { recompilePropagatedProjectAgents } = await import("./recompile-project-agents-
|
|
14942
|
+
const { recompilePropagatedProjectAgents } = await import("./recompile-project-agents-JE4MM72I.js");
|
|
14476
14943
|
return recompilePropagatedProjectAgents(projectDirs);
|
|
14477
14944
|
}
|
|
14478
14945
|
|
|
@@ -14502,7 +14969,7 @@ async function applyConsequences(globalConfig, changes, deps, currentProjectDir)
|
|
|
14502
14969
|
function lazyGateDeps(projectDir) {
|
|
14503
14970
|
return {
|
|
14504
14971
|
loadMatrix: async () => {
|
|
14505
|
-
const { loadSkillsMatrixFromSource: loadSkillsMatrixFromSource2 } = await import("./source-loader-
|
|
14972
|
+
const { loadSkillsMatrixFromSource: loadSkillsMatrixFromSource2 } = await import("./source-loader-3DL3NYUX.js");
|
|
14506
14973
|
const { matrix: matrix2 } = await loadSkillsMatrixFromSource2({
|
|
14507
14974
|
projectDir,
|
|
14508
14975
|
skipExtraSources: true,
|
|
@@ -14511,8 +14978,8 @@ function lazyGateDeps(projectDir) {
|
|
|
14511
14978
|
return matrix2;
|
|
14512
14979
|
},
|
|
14513
14980
|
loadAgents: async () => {
|
|
14514
|
-
const { loadAgentDefs } = await import("./load-agent-defs-
|
|
14515
|
-
return (await loadAgentDefs(
|
|
14981
|
+
const { loadAgentDefs } = await import("./load-agent-defs-X4E57I2U.js");
|
|
14982
|
+
return (await loadAgentDefs()).agents;
|
|
14516
14983
|
}
|
|
14517
14984
|
};
|
|
14518
14985
|
}
|
|
@@ -14539,13 +15006,14 @@ async function writeFromProjectContext(args, homeDir, deps) {
|
|
|
14539
15006
|
const effective = await resolveEffectiveGlobalConfig(
|
|
14540
15007
|
globalConfig,
|
|
14541
15008
|
existingGlobal?.config,
|
|
14542
|
-
projectDir
|
|
15009
|
+
projectDir,
|
|
15010
|
+
args.authoritativeScope
|
|
14543
15011
|
);
|
|
14544
15012
|
const effectiveGlobalConfig = effective.config;
|
|
14545
15013
|
const changes = classifyGlobalChange(existingGlobal?.config, effectiveGlobalConfig);
|
|
14546
15014
|
let globalWritten = false;
|
|
14547
15015
|
if (effective.changed) {
|
|
14548
|
-
await ensureDir(
|
|
15016
|
+
await ensureDir(path19.dirname(globalConfigPath));
|
|
14549
15017
|
globalWritten = await writeGlobalPair(effectiveGlobalConfig, globalConfigPath, matrix2, agents);
|
|
14550
15018
|
verbose(`Updated global config at ${globalConfigPath}`);
|
|
14551
15019
|
} else {
|
|
@@ -14564,7 +15032,7 @@ async function writeFromProjectContext(args, homeDir, deps) {
|
|
|
14564
15032
|
);
|
|
14565
15033
|
const hasProjectItems = reconciledProjectConfig.skills.length > 0 || reconciledProjectConfig.agents.length > 0;
|
|
14566
15034
|
if (args.projectInstallationExists || hasProjectItems) {
|
|
14567
|
-
await ensureDir(
|
|
15035
|
+
await ensureDir(path19.dirname(projectConfigPath));
|
|
14568
15036
|
await writeProjectConfigPair(
|
|
14569
15037
|
projectDir,
|
|
14570
15038
|
reconciledProjectConfig,
|
|
@@ -14620,9 +15088,9 @@ async function reconcileTypesFromDisk(projectDir, config, deps, options) {
|
|
|
14620
15088
|
}
|
|
14621
15089
|
function withMigratedSource(skill, migratedSources) {
|
|
14622
15090
|
if (!isActiveAt(skill, "global")) return skill;
|
|
14623
|
-
const
|
|
14624
|
-
if (
|
|
14625
|
-
return { ...skill,
|
|
15091
|
+
const origin = migratedSources.get(skill.id);
|
|
15092
|
+
if (origin === void 0 || origin === skill.origin) return skill;
|
|
15093
|
+
return { ...skill, origin };
|
|
14626
15094
|
}
|
|
14627
15095
|
function applyMigratedGlobalSources(globalSkills, migratedSources) {
|
|
14628
15096
|
const skills = globalSkills.map((skill) => withMigratedSource(skill, migratedSources));
|
|
@@ -14654,7 +15122,7 @@ function applyMutation(mutation, current) {
|
|
|
14654
15122
|
return filtered.length === projects.length ? null : { ...current, projects: filtered };
|
|
14655
15123
|
}
|
|
14656
15124
|
case "set-source":
|
|
14657
|
-
return { ...current,
|
|
15125
|
+
return { ...current, marketplace: mutation.source };
|
|
14658
15126
|
default: {
|
|
14659
15127
|
const _exhaustive = mutation;
|
|
14660
15128
|
return _exhaustive;
|
|
@@ -14711,7 +15179,7 @@ async function writeProjectPartial(projectDir, partial, options = {}) {
|
|
|
14711
15179
|
throw new GlobalPairWriteViolation(getProjectConfigPath(projectDir));
|
|
14712
15180
|
}
|
|
14713
15181
|
const configPath = getProjectConfigPath(projectDir);
|
|
14714
|
-
await ensureDir(
|
|
15182
|
+
await ensureDir(path19.join(projectDir, CLAUDE_SRC_DIR));
|
|
14715
15183
|
await writeFile(
|
|
14716
15184
|
configPath,
|
|
14717
15185
|
generateConfigSource(fillRequiredFields(withNormalizedStack(partial), options.fallbackName))
|
|
@@ -14722,7 +15190,7 @@ async function writeProjectPartial(projectDir, partial, options = {}) {
|
|
|
14722
15190
|
function computeNewlyAddedSkillIds(currentSkills, priorSkills) {
|
|
14723
15191
|
const priorActiveIds = new Set((priorSkills ?? []).filter((s) => !s.excluded).map((s) => s.id));
|
|
14724
15192
|
const currentActiveIds = currentSkills.filter((s) => !s.excluded).map((s) => s.id);
|
|
14725
|
-
return
|
|
15193
|
+
return unique5(currentActiveIds.filter((id) => !priorActiveIds.has(id)));
|
|
14726
15194
|
}
|
|
14727
15195
|
function computeScopeEligibilityGained(currentSkills, currentAgents, priorSkills, priorAgents) {
|
|
14728
15196
|
const priorSkillScope = activeSkillScopeMap(priorSkills);
|
|
@@ -14747,7 +15215,7 @@ function resolveStackProperty(generated, assigned) {
|
|
|
14747
15215
|
return generated && assigned ? assigned : generated;
|
|
14748
15216
|
}
|
|
14749
15217
|
function configNameFor(projectDir) {
|
|
14750
|
-
return isHomeDirectory(projectDir) ? DEFAULT_PLUGIN_NAME :
|
|
15218
|
+
return isHomeDirectory(projectDir) ? DEFAULT_PLUGIN_NAME : path20.basename(projectDir);
|
|
14751
15219
|
}
|
|
14752
15220
|
async function loadCuratedStack(projectDir, projectStack) {
|
|
14753
15221
|
const globalStack = isHomeDirectory(projectDir) ? void 0 : await loadGlobalStack();
|
|
@@ -14757,7 +15225,7 @@ async function loadGlobalStack() {
|
|
|
14757
15225
|
return (await loadProjectConfigFromDir(os13.homedir()))?.config.stack;
|
|
14758
15226
|
}
|
|
14759
15227
|
async function buildEjectConfig(wizardResult, sourceResult, projectDir) {
|
|
14760
|
-
const skillIds =
|
|
15228
|
+
const skillIds = unique5(wizardResult.skills.map((s) => s.id));
|
|
14761
15229
|
verbose(
|
|
14762
15230
|
`buildEjectConfig: selectedStackId='${wizardResult.selectedStackId}', skills=[${skillIds.join(", ")}], selectedAgents=[${wizardResult.selectedAgents.join(", ")}]`
|
|
14763
15231
|
);
|
|
@@ -14816,12 +15284,12 @@ function setConfigMetadata(config, wizardResult, sourceResult, sourceFlag) {
|
|
|
14816
15284
|
result.selectedDomains = wizardResult.selectedDomains;
|
|
14817
15285
|
}
|
|
14818
15286
|
if (sourceFlag) {
|
|
14819
|
-
result.
|
|
15287
|
+
result.marketplace = sourceFlag;
|
|
14820
15288
|
} else if (sourceResult.sourceConfig.source) {
|
|
14821
|
-
result.
|
|
15289
|
+
result.marketplace = sourceResult.sourceConfig.source;
|
|
14822
15290
|
}
|
|
14823
15291
|
if (sourceResult.marketplace) {
|
|
14824
|
-
result.
|
|
15292
|
+
result.marketplaceName = sourceResult.marketplace;
|
|
14825
15293
|
}
|
|
14826
15294
|
return result;
|
|
14827
15295
|
}
|
|
@@ -14846,7 +15314,7 @@ function buildCompileAgents(config, agents) {
|
|
|
14846
15314
|
const globalSkillIds = new Set(
|
|
14847
15315
|
config.skills.filter((s) => isActiveAt(s, "global")).map((s) => s.id)
|
|
14848
15316
|
);
|
|
14849
|
-
const sourceById = new Map(config.skills.map((s) => [s.id, s.
|
|
15317
|
+
const sourceById = new Map(config.skills.map((s) => [s.id, s.origin]));
|
|
14850
15318
|
const buildAgentCompileEntry = (agentConfig) => {
|
|
14851
15319
|
const tuning = {
|
|
14852
15320
|
...agentConfig.model !== void 0 && { model: agentConfig.model },
|
|
@@ -14872,7 +15340,7 @@ function buildAgentScopeMap(config) {
|
|
|
14872
15340
|
|
|
14873
15341
|
// src/cli/utils/exec.ts
|
|
14874
15342
|
import { spawn } from "child_process";
|
|
14875
|
-
import { z as
|
|
15343
|
+
import { z as z8 } from "zod";
|
|
14876
15344
|
import os14 from "os";
|
|
14877
15345
|
var MAX_PLUGIN_PATH_LENGTH = 1024;
|
|
14878
15346
|
var MAX_PLUGIN_NAME_LENGTH = 256;
|
|
@@ -14901,20 +15369,20 @@ Plugin paths may only contain alphanumeric characters, dashes, underscores, dots
|
|
|
14901
15369
|
}
|
|
14902
15370
|
function validateMarketplaceSource(source) {
|
|
14903
15371
|
if (!source || source.trim().length === 0) {
|
|
14904
|
-
throw new Error("Marketplace
|
|
15372
|
+
throw new Error("Marketplace must not be empty.");
|
|
14905
15373
|
}
|
|
14906
15374
|
if (source.length > MAX_MARKETPLACE_SOURCE_LENGTH) {
|
|
14907
15375
|
throw new Error(
|
|
14908
|
-
`Marketplace
|
|
15376
|
+
`Marketplace is too long (${source.length} characters, max ${MAX_MARKETPLACE_SOURCE_LENGTH}).`
|
|
14909
15377
|
);
|
|
14910
15378
|
}
|
|
14911
15379
|
if (CONTROL_CHAR_PATTERN.test(source)) {
|
|
14912
|
-
throw new Error("Marketplace
|
|
15380
|
+
throw new Error("Marketplace contains invalid control characters.");
|
|
14913
15381
|
}
|
|
14914
15382
|
if (!SAFE_PLUGIN_PATH_PATTERN.test(source)) {
|
|
14915
15383
|
throw new Error(
|
|
14916
|
-
`Marketplace
|
|
14917
|
-
|
|
15384
|
+
`Marketplace contains invalid characters: "${source}"
|
|
15385
|
+
Marketplaces may only contain alphanumeric characters, dashes, underscores, dots, slashes, @, and colons.`
|
|
14918
15386
|
);
|
|
14919
15387
|
}
|
|
14920
15388
|
}
|
|
@@ -14967,11 +15435,15 @@ async function execCommand(command, args, options) {
|
|
|
14967
15435
|
function resolvePluginCwd(scope, projectDir) {
|
|
14968
15436
|
return scope === "user" ? os14.homedir() : projectDir;
|
|
14969
15437
|
}
|
|
14970
|
-
|
|
15438
|
+
function configDirEnv(options) {
|
|
15439
|
+
if (options?.configDir === void 0) return {};
|
|
15440
|
+
return { env: { CLAUDE_CONFIG_DIR: options.configDir } };
|
|
15441
|
+
}
|
|
15442
|
+
async function claudePluginInstall(pluginPath, scope, projectDir, options) {
|
|
14971
15443
|
validatePluginPath(pluginPath);
|
|
14972
15444
|
const cwd = resolvePluginCwd(scope, projectDir);
|
|
14973
15445
|
const args = ["plugin", "install", pluginPath, "--scope", scope];
|
|
14974
|
-
const result = await execCommand("claude", args, { cwd });
|
|
15446
|
+
const result = await execCommand("claude", args, { cwd, ...configDirEnv(options) });
|
|
14975
15447
|
if (result.exitCode !== 0) {
|
|
14976
15448
|
const errorMessage = result.stderr || result.stdout || "Unknown error";
|
|
14977
15449
|
throw new Error(`Plugin installation failed: ${errorMessage.trim()}`);
|
|
@@ -14985,17 +15457,21 @@ async function isClaudeCLIAvailable() {
|
|
|
14985
15457
|
return false;
|
|
14986
15458
|
}
|
|
14987
15459
|
}
|
|
14988
|
-
var marketplaceInfoListSchema =
|
|
14989
|
-
|
|
14990
|
-
name:
|
|
14991
|
-
source:
|
|
14992
|
-
repo:
|
|
14993
|
-
path:
|
|
15460
|
+
var marketplaceInfoListSchema = z8.array(
|
|
15461
|
+
z8.object({
|
|
15462
|
+
name: z8.string(),
|
|
15463
|
+
source: z8.string(),
|
|
15464
|
+
repo: z8.string().exactOptional(),
|
|
15465
|
+
path: z8.string().exactOptional()
|
|
14994
15466
|
})
|
|
14995
15467
|
);
|
|
14996
|
-
async function claudePluginMarketplaceList() {
|
|
15468
|
+
async function claudePluginMarketplaceList(options) {
|
|
14997
15469
|
try {
|
|
14998
|
-
const result = await execCommand(
|
|
15470
|
+
const result = await execCommand(
|
|
15471
|
+
"claude",
|
|
15472
|
+
["plugin", "marketplace", "list", "--json"],
|
|
15473
|
+
configDirEnv(options)
|
|
15474
|
+
);
|
|
14999
15475
|
if (result.exitCode !== 0) {
|
|
15000
15476
|
return [];
|
|
15001
15477
|
}
|
|
@@ -15016,16 +15492,16 @@ async function claudePluginMarketplaceList() {
|
|
|
15016
15492
|
return [];
|
|
15017
15493
|
}
|
|
15018
15494
|
}
|
|
15019
|
-
async function claudePluginMarketplaceExists(name) {
|
|
15020
|
-
const marketplaces = await claudePluginMarketplaceList();
|
|
15495
|
+
async function claudePluginMarketplaceExists(name, options) {
|
|
15496
|
+
const marketplaces = await claudePluginMarketplaceList(options);
|
|
15021
15497
|
return marketplaces.some((m) => m.name === name);
|
|
15022
15498
|
}
|
|
15023
|
-
async function claudePluginMarketplaceAdd(source) {
|
|
15499
|
+
async function claudePluginMarketplaceAdd(source, options) {
|
|
15024
15500
|
validateMarketplaceSource(source);
|
|
15025
15501
|
const args = ["plugin", "marketplace", "add", source];
|
|
15026
15502
|
let result;
|
|
15027
15503
|
try {
|
|
15028
|
-
result = await execCommand("claude", args,
|
|
15504
|
+
result = await execCommand("claude", args, configDirEnv(options));
|
|
15029
15505
|
} catch (err) {
|
|
15030
15506
|
throw new Error(`Failed to add marketplace: ${getErrorMessage(err)}`, { cause: err });
|
|
15031
15507
|
}
|
|
@@ -15037,12 +15513,12 @@ async function claudePluginMarketplaceAdd(source) {
|
|
|
15037
15513
|
throw new Error(`Failed to add marketplace: ${errorMessage.trim()}`);
|
|
15038
15514
|
}
|
|
15039
15515
|
}
|
|
15040
|
-
async function claudePluginMarketplaceUpdate(name) {
|
|
15516
|
+
async function claudePluginMarketplaceUpdate(name, options) {
|
|
15041
15517
|
validatePluginName(name);
|
|
15042
15518
|
const args = ["plugin", "marketplace", "update", name];
|
|
15043
15519
|
let result;
|
|
15044
15520
|
try {
|
|
15045
|
-
result = await execCommand("claude", args,
|
|
15521
|
+
result = await execCommand("claude", args, configDirEnv(options));
|
|
15046
15522
|
} catch (err) {
|
|
15047
15523
|
throw new Error(`Failed to update marketplace: ${getErrorMessage(err)}`, { cause: err });
|
|
15048
15524
|
}
|
|
@@ -15051,11 +15527,11 @@ async function claudePluginMarketplaceUpdate(name) {
|
|
|
15051
15527
|
throw new Error(`Failed to update marketplace: ${errorMessage.trim()}`);
|
|
15052
15528
|
}
|
|
15053
15529
|
}
|
|
15054
|
-
async function claudePluginUninstall(pluginName, scope, projectDir) {
|
|
15530
|
+
async function claudePluginUninstall(pluginName, scope, projectDir, options) {
|
|
15055
15531
|
validatePluginName(pluginName);
|
|
15056
15532
|
const cwd = resolvePluginCwd(scope, projectDir);
|
|
15057
15533
|
const args = ["plugin", "uninstall", pluginName, "--scope", scope];
|
|
15058
|
-
const result = await execCommand("claude", args, { cwd });
|
|
15534
|
+
const result = await execCommand("claude", args, { cwd, ...configDirEnv(options) });
|
|
15059
15535
|
if (result.exitCode !== 0) {
|
|
15060
15536
|
const errorMessage = result.stderr || result.stdout || "Unknown error";
|
|
15061
15537
|
if (errorMessage.includes("not installed") || errorMessage.includes("not found")) {
|
|
@@ -15064,19 +15540,22 @@ async function claudePluginUninstall(pluginName, scope, projectDir) {
|
|
|
15064
15540
|
throw new Error(`Plugin uninstall failed: ${errorMessage.trim()}`);
|
|
15065
15541
|
}
|
|
15066
15542
|
}
|
|
15067
|
-
async function claudePluginUninstallBestEffort(pluginRef, primaryScope, projectDir) {
|
|
15543
|
+
async function claudePluginUninstallBestEffort(pluginRef, primaryScope, projectDir, options) {
|
|
15068
15544
|
const fallbackScope = primaryScope === "project" ? "user" : "project";
|
|
15069
15545
|
try {
|
|
15070
|
-
await claudePluginUninstall(pluginRef, primaryScope, projectDir);
|
|
15546
|
+
await claudePluginUninstall(pluginRef, primaryScope, projectDir, options);
|
|
15071
15547
|
} catch {
|
|
15072
15548
|
}
|
|
15073
15549
|
try {
|
|
15074
|
-
await claudePluginUninstall(pluginRef, fallbackScope, projectDir);
|
|
15550
|
+
await claudePluginUninstall(pluginRef, fallbackScope, projectDir, options);
|
|
15075
15551
|
} catch {
|
|
15076
15552
|
}
|
|
15077
15553
|
}
|
|
15078
15554
|
|
|
15079
15555
|
// src/cli/lib/installation/mode-migrator.ts
|
|
15556
|
+
function ejectCopyFailureError(failedCount) {
|
|
15557
|
+
return `Failed to copy ${failedCount} skill(s) for eject. Eject intent could not be honored. Check that the destination skills directory is writable, then run '${CLI_INVOKE_COMMAND} edit' again \u2014 or switch the affected skills back to plugin mode.`;
|
|
15558
|
+
}
|
|
15080
15559
|
function detectMigrations(oldSkills, newSkills) {
|
|
15081
15560
|
const toEject = [];
|
|
15082
15561
|
const toPlugin = [];
|
|
@@ -15087,13 +15566,13 @@ function detectMigrations(oldSkills, newSkills) {
|
|
|
15087
15566
|
if (!oldSkill) continue;
|
|
15088
15567
|
const migration = {
|
|
15089
15568
|
id: newSkill.id,
|
|
15090
|
-
oldSource: oldSkill.
|
|
15091
|
-
newSource: newSkill.
|
|
15569
|
+
oldSource: oldSkill.origin,
|
|
15570
|
+
newSource: newSkill.origin,
|
|
15092
15571
|
oldScope: oldSkill.scope,
|
|
15093
15572
|
newScope: newSkill.scope
|
|
15094
15573
|
};
|
|
15095
|
-
const wasEject = oldSkill.
|
|
15096
|
-
const isEject = newSkill.
|
|
15574
|
+
const wasEject = oldSkill.origin === EJECT_SOURCE;
|
|
15575
|
+
const isEject = newSkill.origin === EJECT_SOURCE;
|
|
15097
15576
|
if (wasEject && !isEject) {
|
|
15098
15577
|
toPlugin.push(migration);
|
|
15099
15578
|
} else if (!wasEject && isEject) {
|
|
@@ -15106,48 +15585,17 @@ function detectMigrations(oldSkills, newSkills) {
|
|
|
15106
15585
|
return { toEject, toPlugin, scopeChanges };
|
|
15107
15586
|
}
|
|
15108
15587
|
async function executeMigration(plan, projectDir, sourceResult) {
|
|
15109
|
-
const warnings = [];
|
|
15110
|
-
const ejectedSkills = [];
|
|
15111
15588
|
const pluginInstalls = { installed: [], failed: [] };
|
|
15112
|
-
|
|
15113
|
-
|
|
15114
|
-
|
|
15115
|
-
|
|
15116
|
-
|
|
15117
|
-
|
|
15118
|
-
);
|
|
15119
|
-
if (migrations.length === 0) continue;
|
|
15120
|
-
const copied = await copySkillsToLocalFlattened(
|
|
15121
|
-
migrations.map((m) => m.id),
|
|
15122
|
-
resolveInstallPaths(projectDir, scope).skillsDir,
|
|
15123
|
-
sourceResult
|
|
15124
|
-
);
|
|
15125
|
-
ejectedSkills.push(...copied.map((skill) => skill.skillId));
|
|
15126
|
-
}
|
|
15127
|
-
if (!sourceResult.marketplace) {
|
|
15128
|
-
warnings.push(
|
|
15129
|
-
...plan.toEject.filter((m) => !(m.oldScope === "global" && m.newScope === "project")).map((m) => `Could not uninstall plugin for ${m.id}: no marketplace configured`)
|
|
15130
|
-
);
|
|
15131
|
-
} else {
|
|
15132
|
-
for (const migration of plan.toEject) {
|
|
15133
|
-
if (migration.oldScope === "global" && migration.newScope === "project") {
|
|
15134
|
-
verbose(`Keeping global plugin for ${migration.id} (migrated to project-eject)`);
|
|
15135
|
-
continue;
|
|
15136
|
-
}
|
|
15137
|
-
const pluginScope = toClaudePluginScope(migration.oldScope);
|
|
15138
|
-
const pluginRef = buildMarketplacePluginRef(migration.id, sourceResult.marketplace);
|
|
15139
|
-
await claudePluginUninstall(pluginRef, pluginScope, projectDir);
|
|
15140
|
-
verbose(`Uninstalled plugin for ${migration.id}`);
|
|
15141
|
-
}
|
|
15142
|
-
}
|
|
15143
|
-
} catch (error) {
|
|
15144
|
-
warnings.push(`Could not copy skills for eject: ${getErrorMessage(error)}`);
|
|
15145
|
-
}
|
|
15146
|
-
}
|
|
15589
|
+
const ejectCopies = await copyMigratedSkillsToLocal(plan.toEject, projectDir, sourceResult);
|
|
15590
|
+
const warnings = await uninstallMigratedPlugins(
|
|
15591
|
+
migrationsWhoseCopyLanded(plan.toEject, ejectCopies),
|
|
15592
|
+
projectDir,
|
|
15593
|
+
sourceResult
|
|
15594
|
+
);
|
|
15147
15595
|
if (plan.toPlugin.length > 0) {
|
|
15148
15596
|
if (!sourceResult.marketplace) {
|
|
15149
15597
|
throw new Error(
|
|
15150
|
-
`Cannot install skills as plugins: marketplace could not be resolved from
|
|
15598
|
+
`Cannot install skills as plugins: marketplace could not be resolved from '${sourceResult.sourceConfig.source}'. Plugin install mode requires a marketplace \u2014 fix the marketplace or switch the affected skills to eject mode.`
|
|
15151
15599
|
);
|
|
15152
15600
|
}
|
|
15153
15601
|
for (const migration of plan.toPlugin) {
|
|
@@ -15164,7 +15612,50 @@ async function executeMigration(plan, projectDir, sourceResult) {
|
|
|
15164
15612
|
await deleteEjectedWorkingCopy(migration, projectDir);
|
|
15165
15613
|
}
|
|
15166
15614
|
}
|
|
15167
|
-
return {
|
|
15615
|
+
return { ejectCopies, pluginInstalls, warnings };
|
|
15616
|
+
}
|
|
15617
|
+
async function copyMigratedSkillsToLocal(migrations, projectDir, sourceResult) {
|
|
15618
|
+
const copies = { copied: [], failed: [] };
|
|
15619
|
+
for (const migration of migrations) {
|
|
15620
|
+
const { skillsDir } = resolveInstallPaths(projectDir, migration.newScope);
|
|
15621
|
+
try {
|
|
15622
|
+
const copied = await copySkillsToLocalFlattened([migration.id], skillsDir, sourceResult);
|
|
15623
|
+
copies.copied.push(...copied.map((skill) => skill.skillId));
|
|
15624
|
+
} catch (error) {
|
|
15625
|
+
copies.failed.push({ id: migration.id, error: getErrorMessage(error) });
|
|
15626
|
+
}
|
|
15627
|
+
}
|
|
15628
|
+
return copies;
|
|
15629
|
+
}
|
|
15630
|
+
function migrationsWhoseCopyLanded(migrations, copies) {
|
|
15631
|
+
const landed = new Set(copies.copied);
|
|
15632
|
+
return migrations.filter((migration) => landed.has(migration.id));
|
|
15633
|
+
}
|
|
15634
|
+
function keepsGlobalPluginRegistration(migration) {
|
|
15635
|
+
return migration.oldScope === "global" && migration.newScope === "project";
|
|
15636
|
+
}
|
|
15637
|
+
async function uninstallMigratedPlugins(migrations, projectDir, sourceResult) {
|
|
15638
|
+
const warnings = [];
|
|
15639
|
+
for (const migration of migrations) {
|
|
15640
|
+
if (keepsGlobalPluginRegistration(migration)) {
|
|
15641
|
+
verbose(`Keeping global plugin for ${migration.id} (migrated to project-eject)`);
|
|
15642
|
+
continue;
|
|
15643
|
+
}
|
|
15644
|
+
if (!sourceResult.marketplace) {
|
|
15645
|
+
warnings.push(`Could not uninstall plugin for ${migration.id}: no marketplace configured`);
|
|
15646
|
+
continue;
|
|
15647
|
+
}
|
|
15648
|
+
const pluginScope = toClaudePluginScope(migration.oldScope);
|
|
15649
|
+
const pluginRef = buildMarketplacePluginRef(migration.id, sourceResult.marketplace);
|
|
15650
|
+
try {
|
|
15651
|
+
await claudePluginUninstall(pluginRef, pluginScope, projectDir);
|
|
15652
|
+
} catch (error) {
|
|
15653
|
+
warnings.push(`Could not uninstall plugin for ${migration.id}: ${getErrorMessage(error)}`);
|
|
15654
|
+
continue;
|
|
15655
|
+
}
|
|
15656
|
+
verbose(`Uninstalled plugin for ${migration.id}`);
|
|
15657
|
+
}
|
|
15658
|
+
return warnings;
|
|
15168
15659
|
}
|
|
15169
15660
|
async function deleteEjectedWorkingCopy(migration, projectDir) {
|
|
15170
15661
|
if (migration.oldScope === "global" && migration.newScope === "project") {
|
|
@@ -15175,28 +15666,34 @@ async function deleteEjectedWorkingCopy(migration, projectDir) {
|
|
|
15175
15666
|
}
|
|
15176
15667
|
|
|
15177
15668
|
// src/cli/lib/plugins/plugin-settings.ts
|
|
15178
|
-
import
|
|
15179
|
-
import { z as
|
|
15180
|
-
var pluginSettingsSchema =
|
|
15181
|
-
|
|
15669
|
+
import path21 from "path";
|
|
15670
|
+
import { z as z9 } from "zod";
|
|
15671
|
+
var pluginSettingsSchema = z9.object({
|
|
15672
|
+
// The one genuine optional here: a settings.json with no plugin enabled omits the
|
|
15673
|
+
// key entirely, and `getEnabledPluginKeys` says so in its own diagnostic rather than
|
|
15674
|
+
// defaulting it away. `lastUpdated` and `gitCommitSha` used to sit beside the fields
|
|
15675
|
+
// below on the same footing and were decoration — declared, never read, and stripped
|
|
15676
|
+
// by `z.object` either way.
|
|
15677
|
+
enabledPlugins: z9.record(z9.string(), z9.unknown()).exactOptional()
|
|
15182
15678
|
}).passthrough();
|
|
15183
|
-
var
|
|
15184
|
-
|
|
15185
|
-
|
|
15186
|
-
|
|
15187
|
-
|
|
15188
|
-
|
|
15189
|
-
|
|
15190
|
-
|
|
15191
|
-
})
|
|
15192
|
-
|
|
15193
|
-
|
|
15194
|
-
|
|
15679
|
+
var installationFields = {
|
|
15680
|
+
installPath: z9.string(),
|
|
15681
|
+
version: z9.string(),
|
|
15682
|
+
installedAt: z9.string()
|
|
15683
|
+
};
|
|
15684
|
+
var pluginInstallationSchema = z9.discriminatedUnion("scope", [
|
|
15685
|
+
z9.object({ scope: z9.literal("project"), projectPath: z9.string(), ...installationFields }),
|
|
15686
|
+
z9.object({ scope: z9.literal("user"), ...installationFields }),
|
|
15687
|
+
z9.object({ scope: z9.literal("local"), ...installationFields })
|
|
15688
|
+
]);
|
|
15689
|
+
var installedPluginsSchema = z9.object({
|
|
15690
|
+
version: z9.number(),
|
|
15691
|
+
plugins: z9.record(z9.string(), z9.array(pluginInstallationSchema))
|
|
15195
15692
|
}).passthrough();
|
|
15196
15693
|
var SETTINGS_FILE = STANDARD_FILES.SETTINGS_JSON;
|
|
15197
15694
|
var INSTALLED_PLUGINS_FILE = "installed_plugins.json";
|
|
15198
15695
|
function getInstalledPluginsRegistryPath(pluginsDir) {
|
|
15199
|
-
return
|
|
15696
|
+
return path21.join(pluginsDir, INSTALLED_PLUGINS_FILE);
|
|
15200
15697
|
}
|
|
15201
15698
|
async function listRegisteredPluginInstalls(pluginsDir) {
|
|
15202
15699
|
const registryPath = getInstalledPluginsRegistryPath(pluginsDir);
|
|
@@ -15214,7 +15711,7 @@ async function listRegisteredPluginInstalls(pluginsDir) {
|
|
|
15214
15711
|
});
|
|
15215
15712
|
}
|
|
15216
15713
|
async function getEnabledPluginKeys(projectDir) {
|
|
15217
|
-
const settingsPath =
|
|
15714
|
+
const settingsPath = path21.join(projectDir, CLAUDE_DIR, SETTINGS_FILE);
|
|
15218
15715
|
if (!await fileExists(settingsPath)) {
|
|
15219
15716
|
verbose(`No settings.json found at '${settingsPath}'`);
|
|
15220
15717
|
return [];
|
|
@@ -15357,8 +15854,7 @@ async function getInstallationInfo() {
|
|
|
15357
15854
|
skillCount,
|
|
15358
15855
|
agentCount: sumCounts(agentDirCounts),
|
|
15359
15856
|
configPath: installation.configPath,
|
|
15360
|
-
agentDirs: agentDirCounts.filter(hasEntries).map((scopeCount) => scopeCount.dir)
|
|
15361
|
-
skillsDir: installation.skillsDir
|
|
15857
|
+
agentDirs: agentDirCounts.filter(hasEntries).map((scopeCount) => scopeCount.dir)
|
|
15362
15858
|
};
|
|
15363
15859
|
}
|
|
15364
15860
|
function installedScopes(installation) {
|
|
@@ -15427,7 +15923,7 @@ function formatInstallationDisplay(info) {
|
|
|
15427
15923
|
}
|
|
15428
15924
|
|
|
15429
15925
|
// src/cli/lib/plugins/plugin-validator.ts
|
|
15430
|
-
import
|
|
15926
|
+
import path22 from "path";
|
|
15431
15927
|
import fg from "fast-glob";
|
|
15432
15928
|
var PLUGIN_DIR = PLUGIN_MANIFEST_DIR;
|
|
15433
15929
|
var PLUGIN_MANIFEST = STANDARD_FILES.PLUGIN_JSON;
|
|
@@ -15444,15 +15940,15 @@ async function validatePluginStructure(pluginPath) {
|
|
|
15444
15940
|
if (!await directoryExists(pluginPath)) {
|
|
15445
15941
|
return invalidResult(`Plugin directory does not exist: ${pluginPath}`);
|
|
15446
15942
|
}
|
|
15447
|
-
const pluginDir =
|
|
15943
|
+
const pluginDir = path22.join(pluginPath, PLUGIN_DIR);
|
|
15448
15944
|
if (!await directoryExists(pluginDir)) {
|
|
15449
15945
|
errors.push(`Missing ${PLUGIN_DIR}/ directory`);
|
|
15450
15946
|
}
|
|
15451
|
-
const manifestPath =
|
|
15947
|
+
const manifestPath = path22.join(pluginDir, PLUGIN_MANIFEST);
|
|
15452
15948
|
if (!await fileExists(manifestPath)) {
|
|
15453
15949
|
errors.push(`Missing ${PLUGIN_DIR}/${PLUGIN_MANIFEST}`);
|
|
15454
15950
|
}
|
|
15455
|
-
const readmePath =
|
|
15951
|
+
const readmePath = path22.join(pluginPath, STANDARD_FILES.README_MD);
|
|
15456
15952
|
if (!await fileExists(readmePath)) {
|
|
15457
15953
|
warnings.push("Missing README.md (recommended for documentation)");
|
|
15458
15954
|
}
|
|
@@ -15496,15 +15992,15 @@ async function validatePluginManifest(manifestPath) {
|
|
|
15496
15992
|
if (!manifest.description) {
|
|
15497
15993
|
warnings.push("Missing description field (recommended for discoverability)");
|
|
15498
15994
|
}
|
|
15499
|
-
const pluginDir =
|
|
15995
|
+
const pluginDir = path22.dirname(path22.dirname(manifestPath));
|
|
15500
15996
|
if (manifest.skills && typeof manifest.skills === "string") {
|
|
15501
|
-
const skillsPath =
|
|
15997
|
+
const skillsPath = path22.join(pluginDir, manifest.skills);
|
|
15502
15998
|
if (!await directoryExists(skillsPath)) {
|
|
15503
15999
|
errors.push(`Skills path does not exist: ${manifest.skills}`);
|
|
15504
16000
|
}
|
|
15505
16001
|
}
|
|
15506
16002
|
if (manifest.agents && typeof manifest.agents === "string") {
|
|
15507
|
-
const agentsPath =
|
|
16003
|
+
const agentsPath = path22.join(pluginDir, manifest.agents);
|
|
15508
16004
|
if (!await directoryExists(agentsPath)) {
|
|
15509
16005
|
errors.push(`Agents path does not exist: ${manifest.agents}`);
|
|
15510
16006
|
}
|
|
@@ -15571,7 +16067,7 @@ function prefixResult(result, prefix) {
|
|
|
15571
16067
|
};
|
|
15572
16068
|
}
|
|
15573
16069
|
async function validatePluginSkillFiles(pluginPath, skillsRelPath) {
|
|
15574
|
-
const skillsDir =
|
|
16070
|
+
const skillsDir = path22.join(pluginPath, skillsRelPath);
|
|
15575
16071
|
if (!await directoryExists(skillsDir)) return validResult();
|
|
15576
16072
|
const files = await fg(`**/${STANDARD_FILES.SKILL_MD}`, { cwd: skillsDir, absolute: true });
|
|
15577
16073
|
if (files.length === 0) {
|
|
@@ -15583,13 +16079,13 @@ async function validatePluginSkillFiles(pluginPath, skillsRelPath) {
|
|
|
15583
16079
|
}
|
|
15584
16080
|
const results = await Promise.all(
|
|
15585
16081
|
files.map(
|
|
15586
|
-
async (f) => prefixResult(await validateSkillFrontmatter(f),
|
|
16082
|
+
async (f) => prefixResult(await validateSkillFrontmatter(f), path22.relative(pluginPath, f))
|
|
15587
16083
|
)
|
|
15588
16084
|
);
|
|
15589
16085
|
return mergeValidationResults(results);
|
|
15590
16086
|
}
|
|
15591
16087
|
async function validatePluginAgentFiles(pluginPath, agentsRelPath) {
|
|
15592
|
-
const agentsDir =
|
|
16088
|
+
const agentsDir = path22.join(pluginPath, agentsRelPath);
|
|
15593
16089
|
if (!await directoryExists(agentsDir)) return validResult();
|
|
15594
16090
|
const files = await fg("*.md", { cwd: agentsDir, absolute: true });
|
|
15595
16091
|
if (files.length === 0) {
|
|
@@ -15601,7 +16097,7 @@ async function validatePluginAgentFiles(pluginPath, agentsRelPath) {
|
|
|
15601
16097
|
}
|
|
15602
16098
|
const results = await Promise.all(
|
|
15603
16099
|
files.map(
|
|
15604
|
-
async (f) => prefixResult(await validateAgentFrontmatter(f),
|
|
16100
|
+
async (f) => prefixResult(await validateAgentFrontmatter(f), path22.relative(pluginPath, f))
|
|
15605
16101
|
)
|
|
15606
16102
|
);
|
|
15607
16103
|
return mergeValidationResults(results);
|
|
@@ -15643,7 +16139,7 @@ async function validateAllPlugins(pluginsDir) {
|
|
|
15643
16139
|
const dirChecks = await Promise.all(
|
|
15644
16140
|
allDirs.map(async (dirName) => ({
|
|
15645
16141
|
dirName,
|
|
15646
|
-
isPlugin: await directoryExists(
|
|
16142
|
+
isPlugin: await directoryExists(path22.join(pluginsDir, dirName, PLUGIN_DIR))
|
|
15647
16143
|
}))
|
|
15648
16144
|
);
|
|
15649
16145
|
const pluginDirs = dirChecks.filter((c) => c.isPlugin).map((c) => c.dirName);
|
|
@@ -15662,7 +16158,7 @@ async function validateAllPlugins(pluginsDir) {
|
|
|
15662
16158
|
};
|
|
15663
16159
|
}
|
|
15664
16160
|
for (const pluginName of pluginDirs) {
|
|
15665
|
-
const pluginPath =
|
|
16161
|
+
const pluginPath = path22.join(pluginsDir, pluginName);
|
|
15666
16162
|
const result = await validatePlugin(pluginPath);
|
|
15667
16163
|
results.push({ name: pluginName, result });
|
|
15668
16164
|
}
|
|
@@ -15685,7 +16181,7 @@ function sanitizeSkillName(name) {
|
|
|
15685
16181
|
return name.replace(/\+/g, "-");
|
|
15686
16182
|
}
|
|
15687
16183
|
async function readSkillMetadata2(skillPath) {
|
|
15688
|
-
const metadataPath =
|
|
16184
|
+
const metadataPath = path23.join(skillPath, STANDARD_FILES.METADATA_YAML);
|
|
15689
16185
|
if (!await fileExists(metadataPath)) {
|
|
15690
16186
|
return null;
|
|
15691
16187
|
}
|
|
@@ -15729,8 +16225,8 @@ This skill is automatically available when installed.
|
|
|
15729
16225
|
}
|
|
15730
16226
|
async function compileSkillPlugin(options) {
|
|
15731
16227
|
const { skillPath, outputDir, skillName: overrideName } = options;
|
|
15732
|
-
const dirBasename =
|
|
15733
|
-
const skillMdPath =
|
|
16228
|
+
const dirBasename = path23.basename(skillPath);
|
|
16229
|
+
const skillMdPath = path23.join(skillPath, STANDARD_FILES.SKILL_MD);
|
|
15734
16230
|
if (!await fileExists(skillMdPath)) {
|
|
15735
16231
|
throw new Error(
|
|
15736
16232
|
`Skill '${dirBasename}' is missing required ${STANDARD_FILES.SKILL_MD} file. Expected at: ${skillMdPath}`
|
|
@@ -15746,8 +16242,8 @@ async function compileSkillPlugin(options) {
|
|
|
15746
16242
|
const skillName = overrideName ?? sanitizeSkillName(frontmatter.name);
|
|
15747
16243
|
verbose(`Compiling skill plugin: ${skillName} from ${skillPath}`);
|
|
15748
16244
|
const metadata = await readSkillMetadata2(skillPath);
|
|
15749
|
-
const pluginDir =
|
|
15750
|
-
const skillsDir =
|
|
16245
|
+
const pluginDir = path23.join(outputDir, skillName);
|
|
16246
|
+
const skillsDir = path23.join(pluginDir, "skills", skillName);
|
|
15751
16247
|
await ensureDir(pluginDir);
|
|
15752
16248
|
await ensureDir(skillsDir);
|
|
15753
16249
|
const newHash = await computeSkillFolderHash(skillPath);
|
|
@@ -15766,26 +16262,26 @@ async function compileSkillPlugin(options) {
|
|
|
15766
16262
|
await writePluginManifest(pluginDir, manifest);
|
|
15767
16263
|
await writeContentHash(pluginDir, contentHash, getPluginManifestPath);
|
|
15768
16264
|
verbose(` Wrote plugin.json for ${skillName} (v${version})`);
|
|
15769
|
-
await writeFile(
|
|
16265
|
+
await writeFile(path23.join(skillsDir, STANDARD_FILES.SKILL_MD), skillMdContent);
|
|
15770
16266
|
verbose(` Copied ${STANDARD_FILES.SKILL_MD}`);
|
|
15771
16267
|
for (const fileName of SKILL_CONTENT_FILES) {
|
|
15772
16268
|
if (fileName === STANDARD_FILES.SKILL_MD) continue;
|
|
15773
|
-
const sourcePath =
|
|
16269
|
+
const sourcePath = path23.join(skillPath, fileName);
|
|
15774
16270
|
if (await fileExists(sourcePath)) {
|
|
15775
16271
|
const content = await readFile(sourcePath);
|
|
15776
|
-
await writeFile(
|
|
16272
|
+
await writeFile(path23.join(skillsDir, fileName), content);
|
|
15777
16273
|
verbose(` Copied ${fileName}`);
|
|
15778
16274
|
}
|
|
15779
16275
|
}
|
|
15780
16276
|
for (const dirName of SKILL_CONTENT_DIRS) {
|
|
15781
|
-
const sourceDir =
|
|
16277
|
+
const sourceDir = path23.join(skillPath, dirName);
|
|
15782
16278
|
if (await fileExists(sourceDir)) {
|
|
15783
|
-
await copy(sourceDir,
|
|
16279
|
+
await copy(sourceDir, path23.join(skillsDir, dirName));
|
|
15784
16280
|
verbose(` Copied ${dirName}/`);
|
|
15785
16281
|
}
|
|
15786
16282
|
}
|
|
15787
16283
|
const readme = generateReadme(skillName, frontmatter);
|
|
15788
|
-
await writeFile(
|
|
16284
|
+
await writeFile(path23.join(pluginDir, STANDARD_FILES.README_MD), readme);
|
|
15789
16285
|
verbose(" Generated README.md");
|
|
15790
16286
|
return {
|
|
15791
16287
|
pluginPath: pluginDir,
|
|
@@ -15798,7 +16294,7 @@ async function compileAllSkillPlugins(skillsDir, outputDir) {
|
|
|
15798
16294
|
const failed = [];
|
|
15799
16295
|
const skillMdFiles = await glob(`**/${STANDARD_FILES.SKILL_MD}`, skillsDir);
|
|
15800
16296
|
for (const skillMdFile of skillMdFiles) {
|
|
15801
|
-
const skillPath =
|
|
16297
|
+
const skillPath = path23.join(skillsDir, path23.dirname(skillMdFile));
|
|
15802
16298
|
try {
|
|
15803
16299
|
const result = await compileSkillPlugin({
|
|
15804
16300
|
skillPath,
|
|
@@ -15808,7 +16304,7 @@ async function compileAllSkillPlugins(skillsDir, outputDir) {
|
|
|
15808
16304
|
log(` [OK] ${result.skillName}`);
|
|
15809
16305
|
} catch (error) {
|
|
15810
16306
|
const errorMessage = getErrorMessage(error);
|
|
15811
|
-
const dirBasename =
|
|
16307
|
+
const dirBasename = path23.basename(skillPath);
|
|
15812
16308
|
failed.push(dirBasename);
|
|
15813
16309
|
warn(`Failed to compile skill from '${dirBasename}': ${errorMessage}`);
|
|
15814
16310
|
}
|
|
@@ -15824,9 +16320,9 @@ Compiled ${results.length} skill plugins:`);
|
|
|
15824
16320
|
}
|
|
15825
16321
|
|
|
15826
16322
|
// src/cli/lib/skills/local-skill-loader.ts
|
|
15827
|
-
import
|
|
16323
|
+
import path24 from "path";
|
|
15828
16324
|
async function discoverLocalSkills(projectDir) {
|
|
15829
|
-
const localSkillsPath =
|
|
16325
|
+
const localSkillsPath = path24.join(projectDir, LOCAL_SKILLS_PATH);
|
|
15830
16326
|
if (!await directoryExists(localSkillsPath)) {
|
|
15831
16327
|
verbose(`Local skills directory not found: ${localSkillsPath}`);
|
|
15832
16328
|
return null;
|
|
@@ -15843,9 +16339,9 @@ async function discoverLocalSkills(projectDir) {
|
|
|
15843
16339
|
};
|
|
15844
16340
|
}
|
|
15845
16341
|
async function extractLocalSkill(localSkillsPath, skillDirName) {
|
|
15846
|
-
const skillDir =
|
|
15847
|
-
const metadataPath =
|
|
15848
|
-
const skillMdPath =
|
|
16342
|
+
const skillDir = path24.join(localSkillsPath, skillDirName);
|
|
16343
|
+
const metadataPath = path24.join(skillDir, STANDARD_FILES.METADATA_YAML);
|
|
16344
|
+
const skillMdPath = path24.join(skillDir, STANDARD_FILES.SKILL_MD);
|
|
15849
16345
|
if (!await fileExists(metadataPath)) {
|
|
15850
16346
|
verbose(`Skipping local skill '${skillDirName}': No metadata.yaml found`);
|
|
15851
16347
|
return null;
|
|
@@ -15862,6 +16358,12 @@ async function extractLocalSkill(localSkillsPath, skillDirName) {
|
|
|
15862
16358
|
return null;
|
|
15863
16359
|
}
|
|
15864
16360
|
const metadata = read.metadata;
|
|
16361
|
+
if (metadata.category === LOCAL_PSEUDO_CATEGORY) {
|
|
16362
|
+
warn(
|
|
16363
|
+
`Skipping local skill '${skillDirName}': ${METADATA_KEYS.CATEGORY} '${LOCAL_PSEUDO_CATEGORY}' is a placeholder, not a real category, so no sub-agent can be given this skill. Set ${METADATA_KEYS.CATEGORY} in ${metadataPath} to a real one.`
|
|
16364
|
+
);
|
|
16365
|
+
return null;
|
|
16366
|
+
}
|
|
15865
16367
|
const skillMdContent = await readFile(skillMdPath);
|
|
15866
16368
|
const frontmatter = parseFrontmatter(skillMdContent, skillMdPath);
|
|
15867
16369
|
if (!frontmatter) {
|
|
@@ -15869,7 +16371,7 @@ async function extractLocalSkill(localSkillsPath, skillDirName) {
|
|
|
15869
16371
|
return null;
|
|
15870
16372
|
}
|
|
15871
16373
|
const relativePath = `${LOCAL_SKILLS_PATH}/${skillDirName}/`;
|
|
15872
|
-
const absolutePath =
|
|
16374
|
+
const absolutePath = path24.join(localSkillsPath, skillDirName) + path24.sep;
|
|
15873
16375
|
const skillId = frontmatter.name;
|
|
15874
16376
|
const extracted = {
|
|
15875
16377
|
id: skillId,
|
|
@@ -15891,7 +16393,7 @@ async function extractLocalSkill(localSkillsPath, skillDirName) {
|
|
|
15891
16393
|
}
|
|
15892
16394
|
|
|
15893
16395
|
// src/cli/lib/skills/unresolved-skill-entries.ts
|
|
15894
|
-
import
|
|
16396
|
+
import path25 from "path";
|
|
15895
16397
|
async function findUnusableSavedSkillMetadata(unresolvedIds, savedSkills, projectDir) {
|
|
15896
16398
|
const classified = await classifyUnresolvedSkills(unresolvedIds, savedSkills, projectDir);
|
|
15897
16399
|
return classified.flatMap(({ fate }) => fate.kind === "unusable-metadata" ? [fate.detail] : []);
|
|
@@ -15914,10 +16416,10 @@ async function classifyUnresolvedSkills(unresolvedIds, savedSkills, projectDir)
|
|
|
15914
16416
|
);
|
|
15915
16417
|
}
|
|
15916
16418
|
async function classifySavedSkill(id, saved, projectDir) {
|
|
15917
|
-
if (saved?.
|
|
15918
|
-
const skillDir =
|
|
16419
|
+
if (saved?.origin !== EJECT_SOURCE) return { kind: "dropped-by-source" };
|
|
16420
|
+
const skillDir = path25.join(resolveInstallPaths(projectDir, saved.scope).skillsDir, id);
|
|
15919
16421
|
if (!await directoryExists(skillDir)) return { kind: "files-gone", skillDir };
|
|
15920
|
-
const metadataPath =
|
|
16422
|
+
const metadataPath = path25.join(skillDir, STANDARD_FILES.METADATA_YAML);
|
|
15921
16423
|
if (!await fileExists(metadataPath)) return { kind: "not-installed-there", skillDir };
|
|
15922
16424
|
const read = await readSkillMetadata(metadataPath);
|
|
15923
16425
|
if (!read.usable) {
|
|
@@ -15930,7 +16432,7 @@ async function classifySavedSkill(id, saved, projectDir) {
|
|
|
15930
16432
|
return { kind: "unplaceable-category", skillDir, category: read.metadata.category };
|
|
15931
16433
|
}
|
|
15932
16434
|
async function skillMdNames(skillDir, id) {
|
|
15933
|
-
const skillMdPath =
|
|
16435
|
+
const skillMdPath = path25.join(skillDir, STANDARD_FILES.SKILL_MD);
|
|
15934
16436
|
if (!await fileExists(skillMdPath)) return false;
|
|
15935
16437
|
const frontmatter = parseFrontmatter(await readFile(skillMdPath), skillMdPath);
|
|
15936
16438
|
return frontmatter?.name === id;
|
|
@@ -15955,7 +16457,7 @@ function removalReason(id, fate, sourceLabel) {
|
|
|
15955
16457
|
}
|
|
15956
16458
|
|
|
15957
16459
|
// src/cli/lib/skills/local-skill-mover.ts
|
|
15958
|
-
import
|
|
16460
|
+
import path26 from "path";
|
|
15959
16461
|
function validateSkillId(skillId) {
|
|
15960
16462
|
return !(skillId.length === 0 || skillId.includes("\0") || skillId.includes("..") || skillId.includes("/") || skillId.includes("\\"));
|
|
15961
16463
|
}
|
|
@@ -15964,8 +16466,8 @@ async function deleteLocalSkill(projectDir, skillId) {
|
|
|
15964
16466
|
warn(`Invalid skill ID for deletion: '${skillId}'`);
|
|
15965
16467
|
return;
|
|
15966
16468
|
}
|
|
15967
|
-
const skillPath =
|
|
15968
|
-
const skillsDir =
|
|
16469
|
+
const skillPath = path26.resolve(path26.join(projectDir, LOCAL_SKILLS_PATH, skillId));
|
|
16470
|
+
const skillsDir = path26.resolve(path26.join(projectDir, LOCAL_SKILLS_PATH));
|
|
15969
16471
|
if (!isPathWithin(skillPath, skillsDir)) {
|
|
15970
16472
|
warn(`Skill ID '${skillId}' resolves outside the skills directory.`);
|
|
15971
16473
|
return;
|
|
@@ -15985,10 +16487,10 @@ async function migrateLocalSkillScope(skillId, fromScope, projectDir) {
|
|
|
15985
16487
|
const toScope = fromScope === "global" ? "project" : "global";
|
|
15986
16488
|
const fromBaseDir = installBaseDir(projectDir, fromScope);
|
|
15987
16489
|
const toBaseDir = installBaseDir(projectDir, toScope);
|
|
15988
|
-
const fromPath =
|
|
15989
|
-
const toPath =
|
|
15990
|
-
const fromSkillsDir =
|
|
15991
|
-
const toSkillsDir =
|
|
16490
|
+
const fromPath = path26.resolve(path26.join(fromBaseDir, LOCAL_SKILLS_PATH, skillId));
|
|
16491
|
+
const toPath = path26.resolve(path26.join(toBaseDir, LOCAL_SKILLS_PATH, skillId));
|
|
16492
|
+
const fromSkillsDir = path26.resolve(path26.join(fromBaseDir, LOCAL_SKILLS_PATH));
|
|
16493
|
+
const toSkillsDir = path26.resolve(path26.join(toBaseDir, LOCAL_SKILLS_PATH));
|
|
15992
16494
|
if (!isPathWithin(fromPath, fromSkillsDir)) {
|
|
15993
16495
|
warn(`Skill ID '${skillId}' resolves outside the source skills directory.`);
|
|
15994
16496
|
return;
|
|
@@ -16015,21 +16517,94 @@ async function migrateLocalSkillScope(skillId, fromScope, projectDir) {
|
|
|
16015
16517
|
|
|
16016
16518
|
// src/cli/lib/matrix/matrix-loader.ts
|
|
16017
16519
|
import { parse as parseYaml3 } from "yaml";
|
|
16018
|
-
import
|
|
16019
|
-
|
|
16020
|
-
|
|
16021
|
-
|
|
16022
|
-
|
|
16023
|
-
|
|
16024
|
-
|
|
16025
|
-
|
|
16026
|
-
return text.slice(0, maxLength - 1) + "\u2026";
|
|
16520
|
+
import path27 from "path";
|
|
16521
|
+
async function loadSkillCategories(configPath) {
|
|
16522
|
+
const data = await loadConfig(configPath, skillCategoriesFileSchema);
|
|
16523
|
+
if (!data) {
|
|
16524
|
+
throw new Error(`Invalid skill categories at '${configPath}': failed to load or validate`);
|
|
16525
|
+
}
|
|
16526
|
+
verbose(`Loaded skill categories: ${configPath}`);
|
|
16527
|
+
return data.categories;
|
|
16027
16528
|
}
|
|
16028
|
-
function
|
|
16029
|
-
|
|
16529
|
+
async function loadSkillRules(configPath) {
|
|
16530
|
+
const data = await loadConfig(configPath, skillRulesFileSchema);
|
|
16531
|
+
if (!data) {
|
|
16532
|
+
throw new Error(`Invalid skill rules at '${configPath}': failed to load or validate`);
|
|
16533
|
+
}
|
|
16534
|
+
const config = {
|
|
16535
|
+
version: data.version,
|
|
16536
|
+
relationships: data.relationships ?? {
|
|
16537
|
+
conflicts: [],
|
|
16538
|
+
discourages: [],
|
|
16539
|
+
requires: [],
|
|
16540
|
+
alternatives: []
|
|
16541
|
+
}
|
|
16542
|
+
};
|
|
16543
|
+
verbose(`Loaded skill rules: ${configPath}`);
|
|
16544
|
+
return config;
|
|
16545
|
+
}
|
|
16546
|
+
async function extractAllSkills(skillsDir) {
|
|
16547
|
+
const skills = [];
|
|
16548
|
+
const metadataFiles = await glob(`**/${STANDARD_FILES.METADATA_YAML}`, skillsDir);
|
|
16549
|
+
for (const metadataFile of metadataFiles) {
|
|
16550
|
+
const skillDir = path27.dirname(metadataFile);
|
|
16551
|
+
const skillMdPath = path27.join(skillsDir, skillDir, STANDARD_FILES.SKILL_MD);
|
|
16552
|
+
const metadataPath = path27.join(skillsDir, metadataFile);
|
|
16553
|
+
if (!await fileExists(skillMdPath)) {
|
|
16554
|
+
verbose(`Skipping ${metadataFile}: No ${STANDARD_FILES.SKILL_MD} found`);
|
|
16555
|
+
continue;
|
|
16556
|
+
}
|
|
16557
|
+
const metadataContent = await readFile(metadataPath);
|
|
16558
|
+
let rawMetadata;
|
|
16559
|
+
try {
|
|
16560
|
+
rawMetadata = parseYaml3(metadataContent);
|
|
16561
|
+
} catch (error) {
|
|
16562
|
+
warn(
|
|
16563
|
+
`Skipping '${metadataFile}': unparseable ${STANDARD_FILES.METADATA_YAML} at ${metadataPath} \u2014 ${getErrorMessage(error)}`
|
|
16564
|
+
);
|
|
16565
|
+
continue;
|
|
16566
|
+
}
|
|
16567
|
+
const metadataResult = matrixRawMetadataSchema.safeParse(rawMetadata);
|
|
16568
|
+
if (!metadataResult.success) {
|
|
16569
|
+
warn(
|
|
16570
|
+
`Skipping '${metadataFile}': invalid metadata.yaml \u2014 ${formatZodIssues(metadataResult.error.issues)}`
|
|
16571
|
+
);
|
|
16572
|
+
continue;
|
|
16573
|
+
}
|
|
16574
|
+
const metadata = metadataResult.data;
|
|
16575
|
+
const skillMdContent = await readFile(skillMdPath);
|
|
16576
|
+
const frontmatter = parseFrontmatter(skillMdContent, skillMdPath);
|
|
16577
|
+
if (!frontmatter) {
|
|
16578
|
+
verbose(`Skipping ${metadataFile}: Invalid SKILL.md frontmatter`);
|
|
16579
|
+
continue;
|
|
16580
|
+
}
|
|
16581
|
+
if (!metadata.displayName) {
|
|
16582
|
+
throw new Error(
|
|
16583
|
+
`Skill at ${metadataFile} is missing required '${METADATA_KEYS.DISPLAY_NAME}' field in metadata.yaml`
|
|
16584
|
+
);
|
|
16585
|
+
}
|
|
16586
|
+
const skillId = frontmatter.name;
|
|
16587
|
+
const extracted = {
|
|
16588
|
+
id: skillId,
|
|
16589
|
+
directoryPath: skillDir,
|
|
16590
|
+
description: metadata.cliDescription || frontmatter.description,
|
|
16591
|
+
...metadata.usageGuidance !== void 0 && { usageGuidance: metadata.usageGuidance },
|
|
16592
|
+
category: metadata.category,
|
|
16593
|
+
author: metadata.author,
|
|
16594
|
+
path: `skills/${skillDir}/`,
|
|
16595
|
+
domain: metadata.domain,
|
|
16596
|
+
displayName: metadata.displayName,
|
|
16597
|
+
slug: metadata.slug,
|
|
16598
|
+
...metadata.custom === true ? { custom: true } : {}
|
|
16599
|
+
};
|
|
16600
|
+
skills.push(extracted);
|
|
16601
|
+
verbose(`Extracted skill: ${skillId}`);
|
|
16602
|
+
}
|
|
16603
|
+
return skills;
|
|
16030
16604
|
}
|
|
16031
16605
|
|
|
16032
16606
|
// src/cli/lib/matrix/skill-resolution.ts
|
|
16607
|
+
import { unique as unique6, uniqueBy as uniqueBy4 } from "remeda";
|
|
16033
16608
|
var AUTO_SYNTH_ORDER = 999;
|
|
16034
16609
|
function synthesizeCategory(category, domain) {
|
|
16035
16610
|
verbose(
|
|
@@ -16046,21 +16621,36 @@ function synthesizeCategory(category, domain) {
|
|
|
16046
16621
|
order: AUTO_SYNTH_ORDER
|
|
16047
16622
|
};
|
|
16048
16623
|
}
|
|
16624
|
+
function claimSlug(slugMap, slug, id) {
|
|
16625
|
+
const incumbent = slugMap.slugToId[slug];
|
|
16626
|
+
if (incumbent === id) return;
|
|
16627
|
+
if (incumbent !== void 0) {
|
|
16628
|
+
warn(`Duplicate slug '${slug}': already mapped to '${incumbent}', ignoring '${id}'`);
|
|
16629
|
+
return;
|
|
16630
|
+
}
|
|
16631
|
+
slugMap.slugToId[slug] = id;
|
|
16632
|
+
slugMap.idToSlug[id] = slug;
|
|
16633
|
+
}
|
|
16049
16634
|
function buildSlugMap(skills) {
|
|
16050
|
-
const
|
|
16051
|
-
const
|
|
16635
|
+
const slugMap = { slugToId: {}, idToSlug: {} };
|
|
16636
|
+
for (const skill of skills) {
|
|
16637
|
+
claimSlug(slugMap, skill.slug, skill.id);
|
|
16638
|
+
}
|
|
16639
|
+
return slugMap;
|
|
16640
|
+
}
|
|
16641
|
+
function buildResolvedSkillMap(skills, categories, relationships, slugMap) {
|
|
16642
|
+
const resolvedSkills = {};
|
|
16052
16643
|
for (const skill of skills) {
|
|
16053
|
-
const
|
|
16054
|
-
if (
|
|
16644
|
+
const existing = resolvedSkills[skill.id];
|
|
16645
|
+
if (existing) {
|
|
16055
16646
|
warn(
|
|
16056
|
-
`Duplicate
|
|
16647
|
+
`Duplicate skill id '${skill.id}': already resolved from '${existing.path}', ignoring '${skill.path}'`
|
|
16057
16648
|
);
|
|
16058
16649
|
continue;
|
|
16059
16650
|
}
|
|
16060
|
-
|
|
16061
|
-
idToSlug[skill.id] = skill.slug;
|
|
16651
|
+
resolvedSkills[skill.id] = buildResolvedSkill(skill, categories, relationships, slugMap);
|
|
16062
16652
|
}
|
|
16063
|
-
return
|
|
16653
|
+
return resolvedSkills;
|
|
16064
16654
|
}
|
|
16065
16655
|
function resolveToCanonicalId(slug, slugToId, context) {
|
|
16066
16656
|
const slugResult = slugToId[slug];
|
|
@@ -16071,13 +16661,48 @@ function resolveToCanonicalId(slug, slugToId, context) {
|
|
|
16071
16661
|
warn(`Unresolved slug '${slug}'${location} \u2014 skipping`);
|
|
16072
16662
|
return null;
|
|
16073
16663
|
}
|
|
16664
|
+
function slugsNamedByRules(relationships) {
|
|
16665
|
+
return [
|
|
16666
|
+
...relationships.conflicts.flatMap((rule) => rule.skills),
|
|
16667
|
+
...relationships.discourages.flatMap((rule) => rule.skills),
|
|
16668
|
+
...relationships.requires.flatMap((rule) => [rule.skill, ...rule.needs]),
|
|
16669
|
+
...relationships.alternatives.flatMap((rule) => rule.skills)
|
|
16670
|
+
];
|
|
16671
|
+
}
|
|
16672
|
+
function collectUnresolvedSlugs(relationships, slugToId) {
|
|
16673
|
+
return unique6(slugsNamedByRules(relationships).filter((slug) => slugToId[slug] === void 0));
|
|
16674
|
+
}
|
|
16675
|
+
function mergeRelationships(source, defaults) {
|
|
16676
|
+
return {
|
|
16677
|
+
conflicts: [...source.conflicts, ...defaults.conflicts],
|
|
16678
|
+
discourages: [...source.discourages, ...defaults.discourages],
|
|
16679
|
+
requires: [...source.requires, ...defaults.requires],
|
|
16680
|
+
alternatives: [...source.alternatives, ...defaults.alternatives]
|
|
16681
|
+
};
|
|
16682
|
+
}
|
|
16683
|
+
var MIN_RELATABLE_GROUP_MEMBERS = 2;
|
|
16684
|
+
function narrowGroupsToSlugs(rules, shipped) {
|
|
16685
|
+
return rules.map((rule) => ({ ...rule, skills: rule.skills.filter((slug) => shipped.has(slug)) })).filter((rule) => rule.skills.length >= MIN_RELATABLE_GROUP_MEMBERS);
|
|
16686
|
+
}
|
|
16687
|
+
function narrowRequirementsToSlugs(rules, shipped) {
|
|
16688
|
+
return rules.filter((rule) => shipped.has(rule.skill)).map((rule) => ({ ...rule, needs: rule.needs.filter((slug) => shipped.has(slug)) })).filter((rule) => rule.needs.length > 0);
|
|
16689
|
+
}
|
|
16690
|
+
function narrowToShippedSlugs(rules, shipped) {
|
|
16691
|
+
return {
|
|
16692
|
+
conflicts: narrowGroupsToSlugs(rules.conflicts, shipped),
|
|
16693
|
+
discourages: narrowGroupsToSlugs(rules.discourages, shipped),
|
|
16694
|
+
requires: narrowRequirementsToSlugs(rules.requires, shipped),
|
|
16695
|
+
alternatives: narrowGroupsToSlugs(rules.alternatives, shipped)
|
|
16696
|
+
};
|
|
16697
|
+
}
|
|
16698
|
+
function relationshipsForSource(skills, sourceRules) {
|
|
16699
|
+
const shipped = new Set(skills.map((skill) => skill.slug));
|
|
16700
|
+
const builtIn = narrowToShippedSlugs(defaultRules.relationships, shipped);
|
|
16701
|
+
return sourceRules ? mergeRelationships(sourceRules.relationships, builtIn) : builtIn;
|
|
16702
|
+
}
|
|
16074
16703
|
function mergeMatrixWithSkills(categories, relationships, skills) {
|
|
16075
16704
|
const slugMap = buildSlugMap(skills);
|
|
16076
|
-
const resolvedSkills =
|
|
16077
|
-
for (const skill of skills) {
|
|
16078
|
-
const resolved = buildResolvedSkill(skill, categories, relationships, slugMap);
|
|
16079
|
-
resolvedSkills[skill.id] = resolved;
|
|
16080
|
-
}
|
|
16705
|
+
const resolvedSkills = buildResolvedSkillMap(skills, categories, relationships, slugMap);
|
|
16081
16706
|
const synthesizedCategories = { ...categories };
|
|
16082
16707
|
for (const skill of skills) {
|
|
16083
16708
|
if (skill.category === LOCAL_PSEUDO_CATEGORY) continue;
|
|
@@ -16087,12 +16712,14 @@ function mergeMatrixWithSkills(categories, relationships, skills) {
|
|
|
16087
16712
|
verbose(`Auto-synthesized category '${skill.category}' for skill '${skill.id}'`);
|
|
16088
16713
|
}
|
|
16089
16714
|
}
|
|
16715
|
+
const unresolvedSlugs = collectUnresolvedSlugs(relationships, slugMap.slugToId);
|
|
16090
16716
|
const merged = {
|
|
16091
16717
|
version: DEFAULT_VERSION,
|
|
16092
16718
|
categories: synthesizedCategories,
|
|
16093
16719
|
skills: resolvedSkills,
|
|
16094
16720
|
suggestedStacks: [],
|
|
16095
16721
|
slugMap,
|
|
16722
|
+
...unresolvedSlugs.length > 0 && { unresolvedSlugs },
|
|
16096
16723
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
16097
16724
|
};
|
|
16098
16725
|
return merged;
|
|
@@ -16100,6 +16727,11 @@ function mergeMatrixWithSkills(categories, relationships, skills) {
|
|
|
16100
16727
|
function resolveSlugsOrSkip(slugs, resolve, context) {
|
|
16101
16728
|
return slugs.map((slug) => resolve(slug, context)).filter((id) => id !== null);
|
|
16102
16729
|
}
|
|
16730
|
+
function resolveEveryNeed(needs, resolve) {
|
|
16731
|
+
if (needs.length === 0) return null;
|
|
16732
|
+
const resolved = resolveSlugsOrSkip(needs, resolve, "requires.needs");
|
|
16733
|
+
return resolved.length === needs.length ? resolved : null;
|
|
16734
|
+
}
|
|
16103
16735
|
function collectSymmetricGroupMembers(rules, skillId, resolve, context) {
|
|
16104
16736
|
const members = rules.flatMap((rule) => {
|
|
16105
16737
|
const resolved = resolveSlugsOrSkip(rule.skills, resolve, context);
|
|
@@ -16131,8 +16763,8 @@ function resolveRelationships(skillId, relationships, resolve) {
|
|
|
16131
16763
|
for (const rule of relationships.requires) {
|
|
16132
16764
|
const ruleSkillId = resolve(rule.skill, "requires.skill");
|
|
16133
16765
|
if (ruleSkillId !== skillId) continue;
|
|
16134
|
-
const resolvedNeeds =
|
|
16135
|
-
if (resolvedNeeds
|
|
16766
|
+
const resolvedNeeds = resolveEveryNeed(rule.needs, resolve);
|
|
16767
|
+
if (!resolvedNeeds) continue;
|
|
16136
16768
|
requires.push({
|
|
16137
16769
|
skillIds: resolvedNeeds,
|
|
16138
16770
|
needsAny: rule.needsAny ?? false,
|
|
@@ -16164,84 +16796,6 @@ function buildResolvedSkill(skill, _categories, relationships, slugMap) {
|
|
|
16164
16796
|
};
|
|
16165
16797
|
}
|
|
16166
16798
|
|
|
16167
|
-
// src/cli/lib/matrix/matrix-loader.ts
|
|
16168
|
-
async function loadSkillCategories(configPath) {
|
|
16169
|
-
const data = await loadConfig(configPath, skillCategoriesFileSchema);
|
|
16170
|
-
if (!data) {
|
|
16171
|
-
throw new Error(`Invalid skill categories at '${configPath}': failed to load or validate`);
|
|
16172
|
-
}
|
|
16173
|
-
verbose(`Loaded skill categories: ${configPath}`);
|
|
16174
|
-
return data.categories;
|
|
16175
|
-
}
|
|
16176
|
-
async function loadSkillRules(configPath) {
|
|
16177
|
-
const data = await loadConfig(configPath, skillRulesFileSchema);
|
|
16178
|
-
if (!data) {
|
|
16179
|
-
throw new Error(`Invalid skill rules at '${configPath}': failed to load or validate`);
|
|
16180
|
-
}
|
|
16181
|
-
const config = {
|
|
16182
|
-
version: data.version,
|
|
16183
|
-
relationships: data.relationships ?? {
|
|
16184
|
-
conflicts: [],
|
|
16185
|
-
discourages: [],
|
|
16186
|
-
requires: [],
|
|
16187
|
-
alternatives: []
|
|
16188
|
-
}
|
|
16189
|
-
};
|
|
16190
|
-
verbose(`Loaded skill rules: ${configPath}`);
|
|
16191
|
-
return config;
|
|
16192
|
-
}
|
|
16193
|
-
async function extractAllSkills(skillsDir) {
|
|
16194
|
-
const skills = [];
|
|
16195
|
-
const metadataFiles = await glob(`**/${STANDARD_FILES.METADATA_YAML}`, skillsDir);
|
|
16196
|
-
for (const metadataFile of metadataFiles) {
|
|
16197
|
-
const skillDir = path25.dirname(metadataFile);
|
|
16198
|
-
const skillMdPath = path25.join(skillsDir, skillDir, STANDARD_FILES.SKILL_MD);
|
|
16199
|
-
const metadataPath = path25.join(skillsDir, metadataFile);
|
|
16200
|
-
if (!await fileExists(skillMdPath)) {
|
|
16201
|
-
verbose(`Skipping ${metadataFile}: No ${STANDARD_FILES.SKILL_MD} found`);
|
|
16202
|
-
continue;
|
|
16203
|
-
}
|
|
16204
|
-
const metadataContent = await readFile(metadataPath);
|
|
16205
|
-
const rawMetadata = parseYaml3(metadataContent);
|
|
16206
|
-
const metadataResult = matrixRawMetadataSchema.safeParse(rawMetadata);
|
|
16207
|
-
if (!metadataResult.success) {
|
|
16208
|
-
warn(
|
|
16209
|
-
`Skipping '${metadataFile}': invalid metadata.yaml \u2014 ${formatZodIssues(metadataResult.error.issues)}`
|
|
16210
|
-
);
|
|
16211
|
-
continue;
|
|
16212
|
-
}
|
|
16213
|
-
const metadata = metadataResult.data;
|
|
16214
|
-
const skillMdContent = await readFile(skillMdPath);
|
|
16215
|
-
const frontmatter = parseFrontmatter(skillMdContent, skillMdPath);
|
|
16216
|
-
if (!frontmatter) {
|
|
16217
|
-
verbose(`Skipping ${metadataFile}: Invalid SKILL.md frontmatter`);
|
|
16218
|
-
continue;
|
|
16219
|
-
}
|
|
16220
|
-
if (!metadata.displayName) {
|
|
16221
|
-
throw new Error(
|
|
16222
|
-
`Skill at ${metadataFile} is missing required '${METADATA_KEYS.DISPLAY_NAME}' field in metadata.yaml`
|
|
16223
|
-
);
|
|
16224
|
-
}
|
|
16225
|
-
const skillId = frontmatter.name;
|
|
16226
|
-
const extracted = {
|
|
16227
|
-
id: skillId,
|
|
16228
|
-
directoryPath: skillDir,
|
|
16229
|
-
description: metadata.cliDescription || frontmatter.description,
|
|
16230
|
-
...metadata.usageGuidance !== void 0 && { usageGuidance: metadata.usageGuidance },
|
|
16231
|
-
category: metadata.category,
|
|
16232
|
-
author: metadata.author,
|
|
16233
|
-
path: `skills/${skillDir}/`,
|
|
16234
|
-
domain: metadata.domain,
|
|
16235
|
-
displayName: metadata.displayName,
|
|
16236
|
-
slug: metadata.slug,
|
|
16237
|
-
...metadata.custom === true ? { custom: true } : {}
|
|
16238
|
-
};
|
|
16239
|
-
skills.push(extracted);
|
|
16240
|
-
verbose(`Extracted skill: ${skillId}`);
|
|
16241
|
-
}
|
|
16242
|
-
return skills;
|
|
16243
|
-
}
|
|
16244
|
-
|
|
16245
16799
|
// src/cli/lib/matrix/matrix-resolver.ts
|
|
16246
16800
|
import { groupBy as groupBy5 } from "remeda";
|
|
16247
16801
|
function getLabel(skill) {
|
|
@@ -18045,6 +18599,7 @@ function checkMatrixHealth(matrix2) {
|
|
|
18045
18599
|
...checkCategoryDomains(matrix2),
|
|
18046
18600
|
...checkSkillCategories(matrix2),
|
|
18047
18601
|
...checkSkillRelationRefs(matrix2),
|
|
18602
|
+
...checkUnresolvedRuleSlugs(matrix2),
|
|
18048
18603
|
...checkAuditVerdictContradictions(matrix2),
|
|
18049
18604
|
...checkUnauditedSkills(matrix2)
|
|
18050
18605
|
];
|
|
@@ -18093,6 +18648,13 @@ function checkSkillRelationRefs(matrix2) {
|
|
|
18093
18648
|
)
|
|
18094
18649
|
);
|
|
18095
18650
|
}
|
|
18651
|
+
function checkUnresolvedRuleSlugs(matrix2) {
|
|
18652
|
+
return (matrix2.unresolvedSlugs ?? []).map((slug) => ({
|
|
18653
|
+
severity: "error",
|
|
18654
|
+
finding: "rule-unresolved-slug",
|
|
18655
|
+
details: `Unresolved slug '${slug}' in the relationship rules \u2014 no skill carries it, so every rule naming it states nothing`
|
|
18656
|
+
}));
|
|
18657
|
+
}
|
|
18096
18658
|
function isExclusiveCategory3(matrix2, category) {
|
|
18097
18659
|
if (category === LOCAL_PSEUDO_CATEGORY) return false;
|
|
18098
18660
|
const definition = matrix2.categories[category];
|
|
@@ -18125,12 +18687,12 @@ function checkUnauditedSkills(matrix2) {
|
|
|
18125
18687
|
return typedEntries(matrix2.skills).filter(
|
|
18126
18688
|
([skillId, skill]) => (
|
|
18127
18689
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- typedEntries/Object.entries launders the `| undefined` a Partial<Record> admits out of its result type, so this guard reads as dead while still covering an explicitly-undefined slot
|
|
18128
|
-
skill !== void 0 && !skill.local && auditEntryFor(skillId) === void 0
|
|
18690
|
+
skill !== void 0 && !skill.local && isSkillId(skillId) && auditEntryFor(skillId) === void 0
|
|
18129
18691
|
)
|
|
18130
18692
|
).map(([skillId]) => ({
|
|
18131
18693
|
severity: "warning",
|
|
18132
18694
|
finding: "skill-unaudited",
|
|
18133
|
-
details: `Skill '${skillId}' has no audit verdict \u2014
|
|
18695
|
+
details: `Skill '${skillId}' has no audit verdict \u2014 the built-in audit manifest is missing an entry it is meant to carry`
|
|
18134
18696
|
}));
|
|
18135
18697
|
}
|
|
18136
18698
|
|
|
@@ -18148,6 +18710,7 @@ async function loadSkillsMatrixFromSource(options = {}) {
|
|
|
18148
18710
|
verbose(`Loading skills from source: ${source}`);
|
|
18149
18711
|
const result = await resolveBaseResult(source, sourceConfig, devMode, matrixOnly);
|
|
18150
18712
|
const resolvedProjectDir = projectDir || process.cwd();
|
|
18713
|
+
const marketplaceSkillIds = new Set(typedKeys(result.matrix.skills));
|
|
18151
18714
|
const homeDir = os15.homedir();
|
|
18152
18715
|
if (!isHomeDirectory(resolvedProjectDir)) {
|
|
18153
18716
|
result.matrix = await mergeDiscoveredLocalSkills(result.matrix, homeDir, "global");
|
|
@@ -18158,23 +18721,34 @@ async function loadSkillsMatrixFromSource(options = {}) {
|
|
|
18158
18721
|
result.matrix,
|
|
18159
18722
|
sourceConfig,
|
|
18160
18723
|
resolvedProjectDir,
|
|
18161
|
-
result.marketplace
|
|
18724
|
+
result.marketplace,
|
|
18725
|
+
idsOutsideMarketplace(result.matrix, marketplaceSkillIds)
|
|
18162
18726
|
);
|
|
18163
18727
|
}
|
|
18164
18728
|
checkMatrixHealth(result.matrix);
|
|
18165
18729
|
initializeMatrix(result.matrix);
|
|
18166
18730
|
return result;
|
|
18167
18731
|
}
|
|
18732
|
+
function idsOutsideMarketplace(matrix2, marketplaceSkillIds) {
|
|
18733
|
+
return new Set(typedKeys(matrix2.skills).filter((id) => !marketplaceSkillIds.has(id)));
|
|
18734
|
+
}
|
|
18735
|
+
function copyOfBuiltInMatrix() {
|
|
18736
|
+
return {
|
|
18737
|
+
...BUILT_IN_MATRIX,
|
|
18738
|
+
skills: { ...BUILT_IN_MATRIX.skills },
|
|
18739
|
+
categories: { ...BUILT_IN_MATRIX.categories },
|
|
18740
|
+
suggestedStacks: [...BUILT_IN_MATRIX.suggestedStacks],
|
|
18741
|
+
slugMap: {
|
|
18742
|
+
slugToId: { ...BUILT_IN_MATRIX.slugMap.slugToId },
|
|
18743
|
+
idToSlug: { ...BUILT_IN_MATRIX.slugMap.idToSlug }
|
|
18744
|
+
}
|
|
18745
|
+
};
|
|
18746
|
+
}
|
|
18168
18747
|
async function resolveBaseResult(source, sourceConfig, devMode, matrixOnly) {
|
|
18169
18748
|
if (isDefaultSource(source) && !devMode) {
|
|
18170
18749
|
const sourcePath = matrixOnly ? "" : (await fetchFromSource(source)).path;
|
|
18171
18750
|
return {
|
|
18172
|
-
matrix:
|
|
18173
|
-
...BUILT_IN_MATRIX,
|
|
18174
|
-
skills: { ...BUILT_IN_MATRIX.skills },
|
|
18175
|
-
categories: { ...BUILT_IN_MATRIX.categories },
|
|
18176
|
-
suggestedStacks: [...BUILT_IN_MATRIX.suggestedStacks]
|
|
18177
|
-
},
|
|
18751
|
+
matrix: copyOfBuiltInMatrix(),
|
|
18178
18752
|
sourceConfig,
|
|
18179
18753
|
sourcePath,
|
|
18180
18754
|
isLocal: false,
|
|
@@ -18184,44 +18758,40 @@ async function resolveBaseResult(source, sourceConfig, devMode, matrixOnly) {
|
|
|
18184
18758
|
const isLocal = isLocalSource(source) || devMode === true;
|
|
18185
18759
|
return isLocal ? loadFromLocal(source, sourceConfig) : loadFromRemote(source, sourceConfig);
|
|
18186
18760
|
}
|
|
18187
|
-
async function
|
|
18761
|
+
async function readManifestState(source) {
|
|
18188
18762
|
try {
|
|
18189
|
-
const
|
|
18190
|
-
|
|
18191
|
-
|
|
18192
|
-
return {
|
|
18193
|
-
|
|
18194
|
-
verbose(`Source does not have a marketplace.json \u2014 using source name as label`);
|
|
18195
|
-
return sourceConfig.marketplace === void 0 ? {} : { marketplace: sourceConfig.marketplace };
|
|
18763
|
+
const { marketplace } = await fetchMarketplace(source);
|
|
18764
|
+
return { kind: "named", name: marketplace.name };
|
|
18765
|
+
} catch (error) {
|
|
18766
|
+
if (error instanceof MarketplaceManifestAbsentError) return { kind: "absent" };
|
|
18767
|
+
return { kind: "unreadable", reason: getErrorMessage(error) };
|
|
18196
18768
|
}
|
|
18197
18769
|
}
|
|
18198
|
-
function
|
|
18199
|
-
return {
|
|
18200
|
-
conflicts: [...source.conflicts, ...defaults.conflicts],
|
|
18201
|
-
discourages: [...source.discourages, ...defaults.discourages],
|
|
18202
|
-
requires: [...source.requires, ...defaults.requires],
|
|
18203
|
-
alternatives: [...source.alternatives, ...defaults.alternatives]
|
|
18204
|
-
};
|
|
18205
|
-
}
|
|
18206
|
-
var MIN_RELATABLE_GROUP_MEMBERS = 2;
|
|
18207
|
-
function narrowGroupsToSlugs(rules, shipped) {
|
|
18208
|
-
return rules.map((rule) => ({ ...rule, skills: rule.skills.filter((slug) => shipped.has(slug)) })).filter((rule) => rule.skills.length >= MIN_RELATABLE_GROUP_MEMBERS);
|
|
18209
|
-
}
|
|
18210
|
-
function narrowRequirementsToSlugs(rules, shipped) {
|
|
18211
|
-
return rules.filter((rule) => shipped.has(rule.skill)).map((rule) => ({ ...rule, needs: rule.needs.filter((slug) => shipped.has(slug)) })).filter((rule) => rule.needs.length > 0);
|
|
18770
|
+
function configuredLabel(sourceConfig) {
|
|
18771
|
+
return sourceConfig.marketplace === void 0 ? {} : { marketplace: sourceConfig.marketplace };
|
|
18212
18772
|
}
|
|
18213
|
-
function
|
|
18214
|
-
|
|
18215
|
-
|
|
18216
|
-
|
|
18217
|
-
|
|
18218
|
-
|
|
18219
|
-
|
|
18220
|
-
}
|
|
18221
|
-
|
|
18222
|
-
|
|
18223
|
-
|
|
18224
|
-
|
|
18773
|
+
async function resolveMarketplaceLabels(source, sourceConfig) {
|
|
18774
|
+
const state = await readManifestState(source);
|
|
18775
|
+
switch (state.kind) {
|
|
18776
|
+
case "named": {
|
|
18777
|
+
const marketplace = sourceConfig.marketplace ?? state.name;
|
|
18778
|
+
verbose(`Using marketplace name from ${MARKETPLACE_JSON}: ${marketplace}`);
|
|
18779
|
+
return { marketplace };
|
|
18780
|
+
}
|
|
18781
|
+
case "absent":
|
|
18782
|
+
verbose(`Marketplace has no ${MARKETPLACE_JSON} \u2014 using its ref as the label`);
|
|
18783
|
+
return configuredLabel(sourceConfig);
|
|
18784
|
+
case "unreadable":
|
|
18785
|
+
warn(
|
|
18786
|
+
`Marketplace has a ${MARKETPLACE_JSON} this CLI cannot read, so its ref is the label instead:
|
|
18787
|
+
${state.reason}`
|
|
18788
|
+
);
|
|
18789
|
+
return configuredLabel(sourceConfig);
|
|
18790
|
+
default: {
|
|
18791
|
+
const exhaustive = state;
|
|
18792
|
+
return exhaustive;
|
|
18793
|
+
}
|
|
18794
|
+
}
|
|
18225
18795
|
}
|
|
18226
18796
|
async function mergeDiscoveredLocalSkills(matrix2, dir, label) {
|
|
18227
18797
|
const discovered = await discoverLocalSkills(dir);
|
|
@@ -18258,12 +18828,15 @@ async function loadFromRemote(source, sourceConfig) {
|
|
|
18258
18828
|
...labels
|
|
18259
18829
|
};
|
|
18260
18830
|
}
|
|
18831
|
+
async function loadMarketplaceMatrix(marketplaceDir) {
|
|
18832
|
+
return loadAndMergeFromBasePath(marketplaceDir, marketplaceDir);
|
|
18833
|
+
}
|
|
18261
18834
|
async function loadAndMergeFromBasePath(basePath, source) {
|
|
18262
18835
|
const sourceProjectConfig = await loadProjectSourceConfig(basePath);
|
|
18263
18836
|
const skillsDirRelPath = sourceProjectConfig?.skillsDir ?? SKILLS_DIR_PATH;
|
|
18264
18837
|
const stacksRelFile = sourceProjectConfig?.stacksFile;
|
|
18265
|
-
const sourceCategoriesPath =
|
|
18266
|
-
const sourceRulesPath =
|
|
18838
|
+
const sourceCategoriesPath = path28.join(basePath, SKILL_CATEGORIES_PATH);
|
|
18839
|
+
const sourceRulesPath = path28.join(basePath, SKILL_RULES_PATH);
|
|
18267
18840
|
const hasSourceCategories = await fileExists(sourceCategoriesPath);
|
|
18268
18841
|
const hasSourceRules = await fileExists(sourceRulesPath);
|
|
18269
18842
|
const sourceCategories = hasSourceCategories ? await loadSkillCategories(sourceCategoriesPath) : void 0;
|
|
@@ -18282,10 +18855,11 @@ async function loadAndMergeFromBasePath(basePath, source) {
|
|
|
18282
18855
|
} else {
|
|
18283
18856
|
verbose(`Matrix from CLI only (source has no categories/rules files)`);
|
|
18284
18857
|
}
|
|
18285
|
-
const skillsDir =
|
|
18858
|
+
const skillsDir = path28.join(basePath, skillsDirRelPath);
|
|
18286
18859
|
verbose(`Skills from source: ${skillsDir}`);
|
|
18287
18860
|
const skills = await extractAllSkills(skillsDir);
|
|
18288
|
-
|
|
18861
|
+
await refuseCatalogueCollisions(basePath, source, skills);
|
|
18862
|
+
const relationships = relationshipsForSource(skills, sourceRules);
|
|
18289
18863
|
const mergedMatrix = mergeMatrixWithSkills(categories, relationships, skills);
|
|
18290
18864
|
initializeMatrix(mergedMatrix);
|
|
18291
18865
|
const stacks = await resolveOfferedStacks(basePath, stacksRelFile, source);
|
|
@@ -18303,18 +18877,38 @@ async function loadAndMergeFromBasePath(basePath, source) {
|
|
|
18303
18877
|
}
|
|
18304
18878
|
return mergedMatrix;
|
|
18305
18879
|
}
|
|
18880
|
+
var CATALOGUE_SKILL_IDS = new Set(typedKeys(BUILT_IN_MATRIX.skills));
|
|
18881
|
+
var MAX_REPORTED_COLLISIONS = 10;
|
|
18882
|
+
async function refuseCatalogueCollisions(basePath, source, skills) {
|
|
18883
|
+
const collidingIds = skills.map((skill) => skill.id).filter((id) => CATALOGUE_SKILL_IDS.has(id));
|
|
18884
|
+
if (collidingIds.length === 0) return;
|
|
18885
|
+
if (await isPublicCatalogueCheckout(basePath)) return;
|
|
18886
|
+
throw new Error(catalogueCollisionError(collidingIds, source));
|
|
18887
|
+
}
|
|
18888
|
+
function catalogueCollisionError(collidingIds, source) {
|
|
18889
|
+
const listed = collidingIds.slice(0, MAX_REPORTED_COLLISIONS).map((id) => ` ${id}`);
|
|
18890
|
+
const unlisted = collidingIds.length - listed.length;
|
|
18891
|
+
return [
|
|
18892
|
+
`Marketplace '${source}' ships ${collidingIds.length} skill id(s) the public catalogue already owns:`,
|
|
18893
|
+
...listed,
|
|
18894
|
+
...unlisted > 0 ? [` ... and ${unlisted} more`] : [],
|
|
18895
|
+
`A skill id is the directory the skill installs into, so these would shadow the public catalogue's own skills. Every id must carry its marketplace's name as a namespace \u2014 '<marketplace>-<id>'. Rename each skill and the 'name' in its SKILL.md, then re-run 'build marketplace', which refuses the same ids before they are published.`
|
|
18896
|
+
].join("\n");
|
|
18897
|
+
}
|
|
18306
18898
|
async function resolveOfferedStacks(basePath, stacksFile, source) {
|
|
18307
18899
|
const sourceStacks = await loadStacks(basePath, stacksFile);
|
|
18308
18900
|
if (sourceStacks.length > 0) {
|
|
18309
18901
|
verbose(`Offering the ${sourceStacks.length} stacks the source ships`);
|
|
18310
18902
|
return sourceStacks;
|
|
18311
18903
|
}
|
|
18312
|
-
if (
|
|
18313
|
-
verbose(
|
|
18314
|
-
|
|
18904
|
+
if (await offersBuiltInStacks(basePath, source)) {
|
|
18905
|
+
verbose(
|
|
18906
|
+
`The public catalogue ships no stacks \u2014 offering the ${defaultStacks.length} built-in stacks`
|
|
18907
|
+
);
|
|
18908
|
+
return defaultStacks;
|
|
18315
18909
|
}
|
|
18316
|
-
verbose(`
|
|
18317
|
-
return
|
|
18910
|
+
verbose(`Marketplace '${source}' ships no stacks, and gets no built-in stand-in \u2014 offering none`);
|
|
18911
|
+
return [];
|
|
18318
18912
|
}
|
|
18319
18913
|
function convertStackToResolvedStack(stack) {
|
|
18320
18914
|
const agentConfigs = typedKeys(stack.agents).flatMap((agentId) => {
|
|
@@ -18326,7 +18920,7 @@ function convertStackToResolvedStack(stack) {
|
|
|
18326
18920
|
({ agentId, agentConfig }) => [agentId, resolveStackAgentSkills(agentConfig)]
|
|
18327
18921
|
)
|
|
18328
18922
|
);
|
|
18329
|
-
const allSkillIds =
|
|
18923
|
+
const allSkillIds = unique7(
|
|
18330
18924
|
agentConfigs.flatMap(
|
|
18331
18925
|
({ agentConfig }) => resolveAgentConfigToSkills(agentConfig).map((ref) => ref.id)
|
|
18332
18926
|
)
|
|
@@ -18358,12 +18952,23 @@ function extractSourceName(source) {
|
|
|
18358
18952
|
const firstSegment = withoutUrl.split("/")[0];
|
|
18359
18953
|
return firstSegment || source;
|
|
18360
18954
|
}
|
|
18955
|
+
function declaresCategory(matrix2, category) {
|
|
18956
|
+
return category !== LOCAL_PSEUDO_CATEGORY && matrix2.categories[category] !== void 0;
|
|
18957
|
+
}
|
|
18958
|
+
function undeclaredCategoryRefusal(metadata, category) {
|
|
18959
|
+
const metadataPath = path28.join(metadata.path, STANDARD_FILES.METADATA_YAML);
|
|
18960
|
+
return `Skipping local skill '${metadata.id}': ${METADATA_KEYS.CATEGORY} '${category}' is not one this installation declares, so the skill belongs in no grid tab and can be given to no sub-agent. Set ${METADATA_KEYS.CATEGORY} in ${metadataPath} to a category that already exists \u2014 a skill is placed in the taxonomy, it does not extend it.`;
|
|
18961
|
+
}
|
|
18361
18962
|
function mergeLocalSkillsIntoMatrix(matrix2, localResult) {
|
|
18362
18963
|
for (const metadata of localResult.skills) {
|
|
18363
18964
|
const existingSkill = matrix2.skills[metadata.id];
|
|
18364
18965
|
const category = existingSkill?.category ?? metadata.category;
|
|
18365
18966
|
const slug = existingSkill?.slug ?? metadata.slug;
|
|
18366
18967
|
const displayName = existingSkill?.displayName ?? metadata.displayName;
|
|
18968
|
+
if (metadata.custom === true && !declaresCategory(matrix2, category)) {
|
|
18969
|
+
warn(undeclaredCategoryRefusal(metadata, category));
|
|
18970
|
+
continue;
|
|
18971
|
+
}
|
|
18367
18972
|
const resolvedSkill = {
|
|
18368
18973
|
id: metadata.id,
|
|
18369
18974
|
slug,
|
|
@@ -18382,6 +18987,7 @@ function mergeLocalSkillsIntoMatrix(matrix2, localResult) {
|
|
|
18382
18987
|
...metadata.custom !== void 0 && { custom: metadata.custom }
|
|
18383
18988
|
};
|
|
18384
18989
|
matrix2.skills[metadata.id] = resolvedSkill;
|
|
18990
|
+
claimSlug(matrix2.slugMap, slug, metadata.id);
|
|
18385
18991
|
if (category !== LOCAL_PSEUDO_CATEGORY && !matrix2.categories[category]) {
|
|
18386
18992
|
matrix2.categories[category] = {
|
|
18387
18993
|
id: category,
|
|
@@ -18400,6 +19006,7 @@ function mergeLocalSkillsIntoMatrix(matrix2, localResult) {
|
|
|
18400
19006
|
}
|
|
18401
19007
|
|
|
18402
19008
|
export {
|
|
19009
|
+
validateKebabCaseName,
|
|
18403
19010
|
ERROR_MESSAGES,
|
|
18404
19011
|
SUCCESS_MESSAGES,
|
|
18405
19012
|
STATUS_MESSAGES,
|
|
@@ -18414,17 +19021,31 @@ export {
|
|
|
18414
19021
|
marketplacesRefreshed,
|
|
18415
19022
|
marketplaceRefreshFailed,
|
|
18416
19023
|
marketplacesRefreshFailed,
|
|
19024
|
+
marketplaceOwnerHasNoName,
|
|
19025
|
+
marketplaceHasNoVersion,
|
|
19026
|
+
marketplaceNameNotPublishable,
|
|
18417
19027
|
configTypesRefreshFailed,
|
|
18418
19028
|
registeredProjectsUpdated,
|
|
18419
19029
|
registeredProjectUpdateSkipped,
|
|
18420
19030
|
skillMetadataUnusableDetail,
|
|
18421
19031
|
skillMetadataUnusableError,
|
|
18422
19032
|
savedSkillMetadataUnusableError,
|
|
19033
|
+
sharedConfigDestinations,
|
|
18423
19034
|
sharedConfigExistingInstall,
|
|
18424
19035
|
sharedConfigGlobalInstall,
|
|
19036
|
+
sharedConfigProjectScopeAtHome,
|
|
19037
|
+
skippedUnknownSkills,
|
|
19038
|
+
skippedUnknownAgents,
|
|
19039
|
+
carriedSkillsWritten,
|
|
19040
|
+
SHARED_CONFIG_APPLY,
|
|
19041
|
+
sharedConfigNeedsTerminal,
|
|
19042
|
+
SHARED_CONFIG_ONE_DIRECTION,
|
|
19043
|
+
globallyInstalledRemoved,
|
|
19044
|
+
authoredHereKept,
|
|
19045
|
+
unplaceableKept,
|
|
18425
19046
|
configUnreadableError,
|
|
18426
19047
|
registeredProjectsUpdateFailed,
|
|
18427
|
-
|
|
19048
|
+
unmarkedAgentsKept,
|
|
18428
19049
|
UNINSTALL_PLAN,
|
|
18429
19050
|
localSkillsRemoval,
|
|
18430
19051
|
compiledAgentsRemoval,
|
|
@@ -18434,9 +19055,7 @@ export {
|
|
|
18434
19055
|
activeAgentNames,
|
|
18435
19056
|
activeAgentScopeMap,
|
|
18436
19057
|
effectivelyExcludedSkillIds,
|
|
18437
|
-
|
|
18438
|
-
isDomain2 as isDomain,
|
|
18439
|
-
isAgentName,
|
|
19058
|
+
ConfigDefaultExportError,
|
|
18440
19059
|
loadConfig,
|
|
18441
19060
|
installBaseDir,
|
|
18442
19061
|
getProjectConfigPath,
|
|
@@ -18454,10 +19073,22 @@ export {
|
|
|
18454
19073
|
findConfigLoadFailures,
|
|
18455
19074
|
loadProjectConfig,
|
|
18456
19075
|
validateProjectConfig,
|
|
19076
|
+
INSTALL_MODE_LABELS,
|
|
19077
|
+
INSTALL_MODE_DESCRIPTIONS,
|
|
19078
|
+
declaresNoContent,
|
|
19079
|
+
deriveInstallMode,
|
|
19080
|
+
detectProjectInstallation,
|
|
19081
|
+
detectGlobalInstallation,
|
|
19082
|
+
detectInstallation,
|
|
18457
19083
|
computeStringHash,
|
|
19084
|
+
computeFileHash,
|
|
18458
19085
|
determinePluginVersion,
|
|
18459
19086
|
writeContentHash,
|
|
18460
19087
|
readForkedFromMetadata,
|
|
19088
|
+
readLocalSkillMetadata,
|
|
19089
|
+
injectForkedFromMetadata,
|
|
19090
|
+
writeMetadataYaml,
|
|
19091
|
+
validateSkillPath,
|
|
18461
19092
|
copySkillsToLocalFlattened,
|
|
18462
19093
|
generateAgentPluginManifest,
|
|
18463
19094
|
writePluginManifest,
|
|
@@ -18469,39 +19100,56 @@ export {
|
|
|
18469
19100
|
buildMarketplacePluginRef,
|
|
18470
19101
|
parseMarketplacePluginRef,
|
|
18471
19102
|
toClaudePluginScope,
|
|
19103
|
+
MATRIX_VERSION,
|
|
18472
19104
|
DOMAIN_ORDER,
|
|
18473
19105
|
DOMAIN_DESCRIPTIONS,
|
|
18474
19106
|
DEFAULT_SELECTION_OPTIONS,
|
|
19107
|
+
SEED_VERSION,
|
|
19108
|
+
seedModelSchema,
|
|
19109
|
+
seedExternalSkillSchema,
|
|
18475
19110
|
seedPayloadSchema,
|
|
18476
19111
|
isScopePairCompatible,
|
|
18477
|
-
fetchFromSource,
|
|
18478
|
-
fetchMarketplace,
|
|
18479
19112
|
truncateText,
|
|
18480
19113
|
toTitleCase,
|
|
19114
|
+
fetchFromSource,
|
|
19115
|
+
fetchMarketplace,
|
|
19116
|
+
isLocalOnlySkill,
|
|
19117
|
+
claimSlug,
|
|
18481
19118
|
getUnmetRequiredBy,
|
|
18482
19119
|
getCellState,
|
|
18483
19120
|
validateSelection,
|
|
18484
19121
|
getAvailableSkills,
|
|
18485
19122
|
checkMatrixHealth,
|
|
18486
19123
|
loadSkillsMatrixFromSource,
|
|
19124
|
+
loadMarketplaceMatrix,
|
|
18487
19125
|
convertStackToResolvedStack,
|
|
18488
19126
|
extractSourceName,
|
|
18489
19127
|
mergeLocalSkillsIntoMatrix,
|
|
18490
|
-
INSTALL_MODE_LABELS,
|
|
18491
|
-
INSTALL_MODE_DESCRIPTIONS,
|
|
18492
|
-
declaresNoContent,
|
|
18493
|
-
deriveInstallMode,
|
|
18494
|
-
detectProjectInstallation,
|
|
18495
|
-
detectGlobalInstallation,
|
|
18496
|
-
detectInstallation,
|
|
18497
|
-
resolveAgents,
|
|
18498
|
-
createLiquidEngine,
|
|
18499
|
-
writeCompiledAgentsByScope,
|
|
18500
19128
|
getInstalledPluginsRegistryPath,
|
|
18501
19129
|
listRegisteredPluginInstalls,
|
|
18502
19130
|
getVerifiedPluginInstallPaths,
|
|
18503
19131
|
discoverAllPluginSkills,
|
|
18504
19132
|
listPluginNames,
|
|
19133
|
+
getInstallationInfo,
|
|
19134
|
+
formatInstallationDisplay,
|
|
19135
|
+
validateSkillFrontmatter,
|
|
19136
|
+
validateAgentFrontmatter,
|
|
19137
|
+
validatePlugin,
|
|
19138
|
+
validateAllPlugins,
|
|
19139
|
+
compileSkillPlugin,
|
|
19140
|
+
compileAllSkillPlugins,
|
|
19141
|
+
printCompilationSummary,
|
|
19142
|
+
discoverLocalSkills,
|
|
19143
|
+
findUnusableSavedSkillMetadata,
|
|
19144
|
+
unresolvedSkillRemovalReasons,
|
|
19145
|
+
deleteLocalSkill,
|
|
19146
|
+
migrateLocalSkillScope,
|
|
19147
|
+
resolveAgents,
|
|
19148
|
+
hasProvenanceMarker,
|
|
19149
|
+
createLiquidEngine,
|
|
19150
|
+
writeCompiledAgentsByScope,
|
|
19151
|
+
normalizeProjectPath,
|
|
19152
|
+
execCommand,
|
|
18505
19153
|
claudePluginInstall,
|
|
18506
19154
|
isClaudeCLIAvailable,
|
|
18507
19155
|
claudePluginMarketplaceExists,
|
|
@@ -18520,21 +19168,8 @@ export {
|
|
|
18520
19168
|
buildAndMergeConfig,
|
|
18521
19169
|
buildCompileAgents,
|
|
18522
19170
|
buildAgentScopeMap,
|
|
19171
|
+
ejectCopyFailureError,
|
|
18523
19172
|
detectMigrations,
|
|
18524
|
-
executeMigration
|
|
18525
|
-
getInstallationInfo,
|
|
18526
|
-
formatInstallationDisplay,
|
|
18527
|
-
validateSkillFrontmatter,
|
|
18528
|
-
validateAgentFrontmatter,
|
|
18529
|
-
validatePlugin,
|
|
18530
|
-
validateAllPlugins,
|
|
18531
|
-
compileSkillPlugin,
|
|
18532
|
-
compileAllSkillPlugins,
|
|
18533
|
-
printCompilationSummary,
|
|
18534
|
-
discoverLocalSkills,
|
|
18535
|
-
findUnusableSavedSkillMetadata,
|
|
18536
|
-
unresolvedSkillRemovalReasons,
|
|
18537
|
-
deleteLocalSkill,
|
|
18538
|
-
migrateLocalSkillScope
|
|
19173
|
+
executeMigration
|
|
18539
19174
|
};
|
|
18540
|
-
//# sourceMappingURL=chunk-
|
|
19175
|
+
//# sourceMappingURL=chunk-WCAUUBHO.js.map
|