agents-inc 0.153.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 +65 -0
- package/dist/chunk-2H7UWE2G.js +246 -0
- package/dist/chunk-2H7UWE2G.js.map +1 -0
- package/dist/{chunk-ZNDLUWWD.js → chunk-4A4L3YIW.js} +5 -5
- package/dist/chunk-4G2YHZIM.js +132 -0
- package/dist/chunk-4G2YHZIM.js.map +1 -0
- package/dist/{chunk-WDAO3RUY.js → chunk-5F2YR5XV.js} +3 -3
- package/dist/{chunk-JFAUQDZM.js → chunk-5OKLCVM4.js} +3 -3
- package/dist/{chunk-REKOWTIB.js → chunk-5QZAK6J7.js} +44 -10
- package/dist/chunk-5QZAK6J7.js.map +1 -0
- package/dist/{chunk-VECFAKM5.js → chunk-6RLV45HN.js} +10 -10
- package/dist/{chunk-VECFAKM5.js.map → chunk-6RLV45HN.js.map} +1 -1
- package/dist/{chunk-K7PJDWER.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-NXGMM5YN.js → chunk-F2AMBBIA.js} +6 -6
- package/dist/{chunk-NXGMM5YN.js.map → chunk-F2AMBBIA.js.map} +1 -1
- package/dist/{chunk-HEBPKK5L.js → chunk-F5T6TV4Z.js} +213 -92
- package/dist/chunk-F5T6TV4Z.js.map +1 -0
- package/dist/{chunk-K3O3YQYG.js → chunk-G47TDUK3.js} +2 -2
- package/dist/{chunk-U2DNAHFE.js → chunk-GS2NZ3GD.js} +8 -8
- package/dist/chunk-GS2NZ3GD.js.map +1 -0
- package/dist/{chunk-ORJ5Y222.js → chunk-H6UTKTLK.js} +176 -256
- package/dist/chunk-H6UTKTLK.js.map +1 -0
- package/dist/{chunk-M5HSTNYU.js → chunk-HG4JPXJT.js} +11 -29
- package/dist/chunk-HG4JPXJT.js.map +1 -0
- package/dist/{chunk-VGEBYCQZ.js → chunk-HTYH7CKN.js} +4 -15
- package/dist/chunk-HTYH7CKN.js.map +1 -0
- 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-R4SEU3DF.js → chunk-LJCNUP6M.js} +2 -2
- package/dist/{chunk-FRWKCE6R.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-WG6V6VJV.js → chunk-PCC4LBKB.js} +2 -2
- package/dist/chunk-PMUABBPG.js +258 -0
- package/dist/chunk-PMUABBPG.js.map +1 -0
- package/dist/{chunk-EFU6P3B7.js → chunk-PNMM5HNX.js} +5 -5
- package/dist/{chunk-4VYALFQZ.js → chunk-QWVXOCXO.js} +6 -6
- package/dist/{chunk-35VOK7XE.js → chunk-RWOYPOMR.js} +4365 -4355
- package/dist/chunk-RWOYPOMR.js.map +1 -0
- package/dist/{chunk-IO4VEW5U.js → chunk-SY4X2LND.js} +4 -4
- package/dist/{chunk-XGMOXMS4.js → chunk-TBOVYLQJ.js} +2 -2
- package/dist/{chunk-BMGBA6HJ.js → chunk-TNGMF4UX.js} +20 -20
- package/dist/{chunk-BMGBA6HJ.js.map → chunk-TNGMF4UX.js.map} +1 -1
- package/dist/{chunk-TY6CAOL7.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-NXQAY5U7.js → chunk-WCAUUBHO.js} +5860 -5126
- package/dist/chunk-WCAUUBHO.js.map +1 -0
- package/dist/{chunk-V3ENMW7G.js → chunk-WFRTHH3A.js} +3 -3
- package/dist/{chunk-2HC2SNRP.js → chunk-WTJ3AY33.js} +1 -5
- package/dist/chunk-WTJ3AY33.js.map +1 -0
- package/dist/{chunk-F7Z5I6GU.js → chunk-WUQ3MTPF.js} +11 -5
- package/dist/{chunk-F7Z5I6GU.js.map → chunk-WUQ3MTPF.js.map} +1 -1
- package/dist/{chunk-U2YSGBHA.js → chunk-XAXJWXI4.js} +93 -43
- package/dist/chunk-XAXJWXI4.js.map +1 -0
- package/dist/{chunk-ACKC577F.js → chunk-Y5Y7XHVU.js} +4 -4
- package/dist/{chunk-X5XJ6WKO.js → chunk-YO2LTXB4.js} +107 -16
- package/dist/chunk-YO2LTXB4.js.map +1 -0
- package/dist/{chunk-FIHTAFST.js → chunk-ZUAZHDKP.js} +64 -65
- package/dist/chunk-ZUAZHDKP.js.map +1 -0
- package/dist/commands/build/marketplace.js +98 -120
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +8 -8
- package/dist/commands/compile.js +57 -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 +608 -100
- 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 +34 -24
- 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 +234 -196
- 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-4U7UCE2Y.js → loader-G6BFG2VA.js} +3 -3
- package/dist/recompile-project-agents-JE4MM72I.js +20 -0
- package/dist/{source-loader-ZNSYJJCI.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/plugin.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-2HC2SNRP.js.map +0 -1
- package/dist/chunk-35VOK7XE.js.map +0 -1
- package/dist/chunk-FIHTAFST.js.map +0 -1
- package/dist/chunk-FRWKCE6R.js.map +0 -1
- package/dist/chunk-HEBPKK5L.js.map +0 -1
- package/dist/chunk-JC7DBPRD.js.map +0 -1
- package/dist/chunk-K7PJDWER.js.map +0 -1
- package/dist/chunk-KET3EVGX.js +0 -41
- package/dist/chunk-KET3EVGX.js.map +0 -1
- package/dist/chunk-M5HSTNYU.js.map +0 -1
- package/dist/chunk-NXQAY5U7.js.map +0 -1
- package/dist/chunk-OJJLYHM3.js +0 -34
- package/dist/chunk-OJJLYHM3.js.map +0 -1
- package/dist/chunk-ORJ5Y222.js.map +0 -1
- package/dist/chunk-R54KIGN2.js.map +0 -1
- package/dist/chunk-REKOWTIB.js.map +0 -1
- package/dist/chunk-TY6CAOL7.js.map +0 -1
- package/dist/chunk-U2DNAHFE.js.map +0 -1
- package/dist/chunk-U2YSGBHA.js.map +0 -1
- package/dist/chunk-VGEBYCQZ.js.map +0 -1
- package/dist/chunk-X5XJ6WKO.js.map +0 -1
- package/dist/copy-local-skills-KF2RAVD3.js +0 -14
- package/dist/load-agent-defs-DGXGBU3Q.js +0 -15
- package/dist/recompile-project-agents-CJVBAWDJ.js +0 -20
- /package/dist/{chunk-ZNDLUWWD.js.map → chunk-4A4L3YIW.js.map} +0 -0
- /package/dist/{chunk-WDAO3RUY.js.map → chunk-5F2YR5XV.js.map} +0 -0
- /package/dist/{chunk-JFAUQDZM.js.map → chunk-5OKLCVM4.js.map} +0 -0
- /package/dist/{chunk-K3O3YQYG.js.map → chunk-G47TDUK3.js.map} +0 -0
- /package/dist/{chunk-NSJ2S7R5.js.map → chunk-ILUVL7WM.js.map} +0 -0
- /package/dist/{chunk-R4SEU3DF.js.map → chunk-LJCNUP6M.js.map} +0 -0
- /package/dist/{chunk-Q5FLW4JG.js.map → chunk-OKH64JZE.js.map} +0 -0
- /package/dist/{chunk-WG6V6VJV.js.map → chunk-PCC4LBKB.js.map} +0 -0
- /package/dist/{chunk-EFU6P3B7.js.map → chunk-PNMM5HNX.js.map} +0 -0
- /package/dist/{chunk-4VYALFQZ.js.map → chunk-QWVXOCXO.js.map} +0 -0
- /package/dist/{chunk-IO4VEW5U.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-ACKC577F.js.map → chunk-Y5Y7XHVU.js.map} +0 -0
- /package/dist/{copy-local-skills-KF2RAVD3.js.map → components/common/removal-plan-confirm.js.map} +0 -0
- /package/dist/{load-agent-defs-DGXGBU3Q.js.map → copy-local-skills-NSUTBVLJ.js.map} +0 -0
- /package/dist/{loader-4U7UCE2Y.js.map → load-agent-defs-X4E57I2U.js.map} +0 -0
- /package/dist/{recompile-project-agents-CJVBAWDJ.js.map → loader-G6BFG2VA.js.map} +0 -0
- /package/dist/{source-loader-ZNSYJJCI.js.map → recompile-project-agents-JE4MM72I.js.map} +0 -0
|
@@ -1,121 +1,52 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
generateMarketplace,
|
|
4
|
+
getMarketplaceStats,
|
|
5
|
+
validateMarketplaceName,
|
|
6
|
+
validateSkillIdNamespace,
|
|
7
|
+
writeMarketplace
|
|
8
|
+
} from "../../chunk-4G2YHZIM.js";
|
|
2
9
|
import {
|
|
3
10
|
BaseCommand,
|
|
4
11
|
EXIT_CODES
|
|
5
|
-
} from "../../chunk-
|
|
6
|
-
import "../../chunk-
|
|
7
|
-
import "../../chunk-
|
|
12
|
+
} from "../../chunk-YO2LTXB4.js";
|
|
13
|
+
import "../../chunk-UMH2YZKG.js";
|
|
14
|
+
import "../../chunk-G47TDUK3.js";
|
|
8
15
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
16
|
+
loadMarketplaceMatrix,
|
|
17
|
+
marketplaceHasNoVersion,
|
|
18
|
+
marketplaceNameNotPublishable,
|
|
19
|
+
marketplaceOwnerHasNoName,
|
|
20
|
+
validateKebabCaseName
|
|
21
|
+
} from "../../chunk-WCAUUBHO.js";
|
|
11
22
|
import {
|
|
12
|
-
ensureDir,
|
|
13
23
|
getErrorMessage,
|
|
14
|
-
glob,
|
|
15
24
|
readFile,
|
|
16
25
|
setVerbose,
|
|
17
|
-
verbose,
|
|
18
26
|
warn,
|
|
19
27
|
writeFile
|
|
20
|
-
} from "../../chunk-
|
|
21
|
-
import "../../chunk-
|
|
28
|
+
} from "../../chunk-XAXJWXI4.js";
|
|
29
|
+
import "../../chunk-RWOYPOMR.js";
|
|
22
30
|
import "../../chunk-VASLW636.js";
|
|
23
31
|
import {
|
|
24
|
-
|
|
25
|
-
|
|
32
|
+
CATALOG_JSON,
|
|
33
|
+
CLI_INVOKE_COMMAND,
|
|
34
|
+
GENERATED_AT_BUILD,
|
|
26
35
|
MARKETPLACE_JSON,
|
|
27
36
|
PLUGINS_DIST_PATH,
|
|
28
37
|
PLUGIN_MANIFEST_DIR,
|
|
29
|
-
|
|
30
|
-
} from "../../chunk-
|
|
38
|
+
STANDARD_FILES
|
|
39
|
+
} from "../../chunk-IO5YBKHV.js";
|
|
31
40
|
import "../../chunk-VZRO7RYT.js";
|
|
32
41
|
|
|
33
42
|
// src/cli/commands/build/marketplace.ts
|
|
34
43
|
import { Flags } from "@oclif/core";
|
|
35
|
-
import path2 from "path";
|
|
36
|
-
import { sortBy as sortBy2 } from "remeda";
|
|
37
|
-
import { z } from "zod";
|
|
38
|
-
|
|
39
|
-
// src/cli/lib/marketplace-generator.ts
|
|
40
44
|
import path from "path";
|
|
41
|
-
import {
|
|
42
|
-
|
|
43
|
-
var MARKETPLACE_SCHEMA_URL = "https://anthropic.com/claude-code/marketplace.schema.json";
|
|
44
|
-
function convertManifestToMarketplacePlugin(manifest, pluginRoot, pluginDirName) {
|
|
45
|
-
return {
|
|
46
|
-
name: manifest.name,
|
|
47
|
-
source: `./${pluginRoot}/${pluginDirName}`,
|
|
48
|
-
...manifest.description !== void 0 && { description: manifest.description },
|
|
49
|
-
...manifest.version !== void 0 && { version: manifest.version },
|
|
50
|
-
...manifest.author !== void 0 && { author: manifest.author },
|
|
51
|
-
...manifest.keywords !== void 0 && { keywords: manifest.keywords }
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
async function generateMarketplace(pluginsDir, options) {
|
|
55
|
-
verbose(`Scanning plugins directory: ${pluginsDir}`);
|
|
56
|
-
const manifestFiles = await glob(`**/${PLUGIN_MANIFEST_PATH}`, pluginsDir);
|
|
57
|
-
verbose(`Found ${manifestFiles.length} plugin manifests`);
|
|
58
|
-
const plugins = [];
|
|
59
|
-
for (const manifestFile of manifestFiles) {
|
|
60
|
-
const separator = manifestFile.indexOf("/");
|
|
61
|
-
const pluginDirName = separator === -1 ? manifestFile : manifestFile.slice(0, separator);
|
|
62
|
-
const pluginDir = path.join(pluginsDir, pluginDirName);
|
|
63
|
-
const manifest = await readPluginManifest(pluginDir);
|
|
64
|
-
if (!manifest) {
|
|
65
|
-
warn(`Could not read plugin manifest: '${manifestFile}'`);
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
const plugin = convertManifestToMarketplacePlugin(
|
|
69
|
-
manifest,
|
|
70
|
-
options.pluginRoot.replace(/^\.\//, ""),
|
|
71
|
-
pluginDirName
|
|
72
|
-
);
|
|
73
|
-
plugins.push(plugin);
|
|
74
|
-
verbose(` [OK] ${plugin.name}`);
|
|
75
|
-
}
|
|
76
|
-
const sortedPlugins = sortBy(plugins, (p) => p.name);
|
|
77
|
-
return {
|
|
78
|
-
$schema: MARKETPLACE_SCHEMA_URL,
|
|
79
|
-
name: options.name,
|
|
80
|
-
version: options.version ?? DEFAULT_VERSION,
|
|
81
|
-
owner: {
|
|
82
|
-
name: options.ownerName,
|
|
83
|
-
...options.ownerEmail ? { email: options.ownerEmail } : {}
|
|
84
|
-
},
|
|
85
|
-
metadata: {
|
|
86
|
-
pluginRoot: options.pluginRoot
|
|
87
|
-
},
|
|
88
|
-
plugins: sortedPlugins,
|
|
89
|
-
...options.description ? { description: options.description } : {}
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
async function writeMarketplace(outputPath, marketplace) {
|
|
93
|
-
await ensureDir(path.dirname(outputPath));
|
|
94
|
-
const content = `${JSON.stringify(marketplace, null, 2)}
|
|
95
|
-
`;
|
|
96
|
-
await writeFile(outputPath, content);
|
|
97
|
-
}
|
|
98
|
-
function getMarketplaceStats(marketplace) {
|
|
99
|
-
return {
|
|
100
|
-
total: marketplace.plugins.length,
|
|
101
|
-
byCategory: countBy(marketplace.plugins, (p) => p.category ?? "uncategorized")
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// src/cli/lib/validate-kebab-name.ts
|
|
106
|
-
function validateKebabCaseName(name, noun) {
|
|
107
|
-
if (!name || name.trim() === "") {
|
|
108
|
-
return `${noun} name is required`;
|
|
109
|
-
}
|
|
110
|
-
if (!KEBAB_CASE_PATTERN.test(name)) {
|
|
111
|
-
return `${noun} name must be kebab-case (lowercase letters, numbers, and hyphens, starting with a letter)`;
|
|
112
|
-
}
|
|
113
|
-
return null;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// src/cli/commands/build/marketplace.ts
|
|
45
|
+
import { sortBy } from "remeda";
|
|
46
|
+
import { z } from "zod";
|
|
117
47
|
var DEFAULT_OUTPUT_FILE = `${PLUGIN_MANIFEST_DIR}/${MARKETPLACE_JSON}`;
|
|
118
48
|
var AUTHOR_STRING_PATTERN = /^(.*?)\s*<([^>]+)>\s*(?:\(([^)]+)\))?\s*$/;
|
|
49
|
+
var MARKETPLACE_NOUN = "Marketplace";
|
|
119
50
|
var packageAuthorObjectSchema = z.object({
|
|
120
51
|
name: z.string(),
|
|
121
52
|
email: z.string().exactOptional(),
|
|
@@ -172,8 +103,8 @@ var BuildMarketplace = class _BuildMarketplace extends BaseCommand {
|
|
|
172
103
|
const { flags } = await this.parse(_BuildMarketplace);
|
|
173
104
|
setVerbose(flags.verbose);
|
|
174
105
|
const projectRoot = process.cwd();
|
|
175
|
-
const pluginsDir =
|
|
176
|
-
const outputPath =
|
|
106
|
+
const pluginsDir = path.resolve(projectRoot, flags["plugins-dir"]);
|
|
107
|
+
const outputPath = path.resolve(projectRoot, flags.output);
|
|
177
108
|
const identity = await this.loadMarketplaceIdentity(projectRoot, flags.name);
|
|
178
109
|
this.printHeader(pluginsDir, outputPath);
|
|
179
110
|
try {
|
|
@@ -183,6 +114,7 @@ var BuildMarketplace = class _BuildMarketplace extends BaseCommand {
|
|
|
183
114
|
flags["plugins-dir"],
|
|
184
115
|
identity
|
|
185
116
|
);
|
|
117
|
+
await this.writeCatalog(projectRoot, outputPath);
|
|
186
118
|
this.printStats(marketplace);
|
|
187
119
|
this.printSample(marketplace);
|
|
188
120
|
this.log("");
|
|
@@ -196,7 +128,7 @@ var BuildMarketplace = class _BuildMarketplace extends BaseCommand {
|
|
|
196
128
|
}
|
|
197
129
|
}
|
|
198
130
|
async loadMarketplaceIdentity(projectRoot, nameOverride) {
|
|
199
|
-
const packageJsonPath =
|
|
131
|
+
const packageJsonPath = path.join(projectRoot, STANDARD_FILES.PACKAGE_JSON);
|
|
200
132
|
let rawContent;
|
|
201
133
|
try {
|
|
202
134
|
rawContent = await readFile(packageJsonPath);
|
|
@@ -223,16 +155,17 @@ var BuildMarketplace = class _BuildMarketplace extends BaseCommand {
|
|
|
223
155
|
);
|
|
224
156
|
}
|
|
225
157
|
const { name, version, description, author } = parseResult.data;
|
|
158
|
+
if (version.trim() === "") {
|
|
159
|
+
this.error(marketplaceHasNoVersion(packageJsonPath), { exit: EXIT_CODES.ERROR });
|
|
160
|
+
}
|
|
226
161
|
const owner = parseAuthor(author);
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
}
|
|
235
|
-
resolvedName = nameOverride;
|
|
162
|
+
if (owner.name.trim() === "") {
|
|
163
|
+
this.error(marketplaceOwnerHasNoName(packageJsonPath), { exit: EXIT_CODES.ERROR });
|
|
164
|
+
}
|
|
165
|
+
const resolvedName = this.resolvePublishableName(name, nameOverride, packageJsonPath);
|
|
166
|
+
const reservedError = validateMarketplaceName(resolvedName, name);
|
|
167
|
+
if (reservedError) {
|
|
168
|
+
this.error(reservedError, { exit: EXIT_CODES.ERROR });
|
|
236
169
|
}
|
|
237
170
|
return {
|
|
238
171
|
name: resolvedName,
|
|
@@ -242,6 +175,32 @@ var BuildMarketplace = class _BuildMarketplace extends BaseCommand {
|
|
|
242
175
|
...owner.email !== void 0 && { ownerEmail: owner.email }
|
|
243
176
|
};
|
|
244
177
|
}
|
|
178
|
+
/**
|
|
179
|
+
* The name this marketplace publishes under, refused before anything is written when
|
|
180
|
+
* it is not one `claude plugin marketplace add` will accept.
|
|
181
|
+
*
|
|
182
|
+
* Both halves are judged by the same rule and refused with different sentences: a
|
|
183
|
+
* `--name` the author typed is an argument they can retype, while a name derived from
|
|
184
|
+
* package.json is a fact about their package — an npm scoped name is legitimate there
|
|
185
|
+
* and illegitimate here — so its way out is the flag rather than a package rename.
|
|
186
|
+
*/
|
|
187
|
+
resolvePublishableName(packageName, nameOverride, packageJsonPath) {
|
|
188
|
+
if (nameOverride !== void 0) {
|
|
189
|
+
const invalidOverride = validateKebabCaseName(nameOverride, MARKETPLACE_NOUN);
|
|
190
|
+
if (invalidOverride) {
|
|
191
|
+
this.error(`Invalid --name '${nameOverride}': ${invalidOverride}`, {
|
|
192
|
+
exit: EXIT_CODES.INVALID_ARGS
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
return nameOverride;
|
|
196
|
+
}
|
|
197
|
+
if (validateKebabCaseName(packageName, MARKETPLACE_NOUN)) {
|
|
198
|
+
this.error(marketplaceNameNotPublishable(packageName, packageJsonPath), {
|
|
199
|
+
exit: EXIT_CODES.ERROR
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
return packageName;
|
|
203
|
+
}
|
|
245
204
|
printHeader(pluginsDir, outputPath) {
|
|
246
205
|
this.log("");
|
|
247
206
|
this.log("Generating marketplace.json");
|
|
@@ -261,15 +220,41 @@ var BuildMarketplace = class _BuildMarketplace extends BaseCommand {
|
|
|
261
220
|
});
|
|
262
221
|
const stats = getMarketplaceStats(marketplace);
|
|
263
222
|
this.log(`Found ${stats.total} plugins`);
|
|
223
|
+
if (marketplace.plugins.length === 0) {
|
|
224
|
+
this.error(noPluginsToPublish(pluginsDir, pluginsDirFlag), { exit: EXIT_CODES.ERROR });
|
|
225
|
+
}
|
|
226
|
+
const namespaceError = validateSkillIdNamespace(marketplace);
|
|
227
|
+
if (namespaceError) {
|
|
228
|
+
this.error(namespaceError, { exit: EXIT_CODES.ERROR });
|
|
229
|
+
}
|
|
264
230
|
this.log("Writing marketplace.json...");
|
|
265
231
|
await writeMarketplace(outputPath, marketplace);
|
|
266
232
|
this.log(`Wrote ${outputPath}`);
|
|
267
233
|
return marketplace;
|
|
268
234
|
}
|
|
235
|
+
/**
|
|
236
|
+
* Writes the marketplace's catalogue beside its manifest.
|
|
237
|
+
*
|
|
238
|
+
* Unconditional, and there is no flag to make it otherwise: a consumer
|
|
239
|
+
* fetching a marketplace cannot tell an author who omitted a flag from a
|
|
240
|
+
* marketplace that is broken, so an absent catalogue has to mean the second.
|
|
241
|
+
*
|
|
242
|
+
* `generatedAt` is stamped rather than carried: see {@link GENERATED_AT_BUILD}
|
|
243
|
+
* for why a published artefact records a build and not a moment.
|
|
244
|
+
*/
|
|
245
|
+
async writeCatalog(projectRoot, outputPath) {
|
|
246
|
+
const catalogPath = path.join(path.dirname(outputPath), CATALOG_JSON);
|
|
247
|
+
this.log(`Writing ${CATALOG_JSON}...`);
|
|
248
|
+
const matrix = await loadMarketplaceMatrix(projectRoot);
|
|
249
|
+
const catalog = { ...matrix, generatedAt: GENERATED_AT_BUILD };
|
|
250
|
+
await writeFile(catalogPath, `${JSON.stringify(catalog, null, 2)}
|
|
251
|
+
`);
|
|
252
|
+
this.log(`Wrote ${catalogPath}`);
|
|
253
|
+
}
|
|
269
254
|
printStats(marketplace) {
|
|
270
255
|
this.log("");
|
|
271
256
|
this.log("Category breakdown:");
|
|
272
|
-
const sortedCategories =
|
|
257
|
+
const sortedCategories = sortBy(
|
|
273
258
|
Object.entries(getMarketplaceStats(marketplace).byCategory),
|
|
274
259
|
([, count]) => -count
|
|
275
260
|
);
|
|
@@ -294,24 +279,17 @@ var BuildMarketplace = class _BuildMarketplace extends BaseCommand {
|
|
|
294
279
|
}
|
|
295
280
|
}
|
|
296
281
|
};
|
|
282
|
+
function noPluginsToPublish(pluginsDir, pluginsDirFlag) {
|
|
283
|
+
return `No plugins found in ${pluginsDir}. A marketplace with no plugins is refused when it is read back, so none was written. Run '${CLI_INVOKE_COMMAND} build plugins' first, or point --plugins-dir at the directory holding them (it is '${pluginsDirFlag}' for this run).`;
|
|
284
|
+
}
|
|
297
285
|
function parseAuthor(author) {
|
|
298
|
-
if (!author) {
|
|
299
|
-
warn("package.json is missing 'author' field \u2014 marketplace owner.email will be empty");
|
|
300
|
-
return { name: "" };
|
|
301
|
-
}
|
|
286
|
+
if (!author) return { name: "" };
|
|
302
287
|
if (typeof author === "object") {
|
|
303
288
|
return { name: author.name, ...author.email !== void 0 && { email: author.email } };
|
|
304
289
|
}
|
|
305
290
|
const [, matchedName, matchedEmail] = author.match(AUTHOR_STRING_PATTERN) ?? [];
|
|
306
291
|
if (matchedName !== void 0 && matchedEmail !== void 0) {
|
|
307
|
-
|
|
308
|
-
const email = matchedEmail.trim();
|
|
309
|
-
if (name === "") {
|
|
310
|
-
warn(
|
|
311
|
-
`package.json 'author' field "${author}" has no parseable name \u2014 marketplace owner.name will be empty`
|
|
312
|
-
);
|
|
313
|
-
}
|
|
314
|
-
return { name, email };
|
|
292
|
+
return { name: matchedName.trim(), email: matchedEmail.trim() };
|
|
315
293
|
}
|
|
316
294
|
warn(
|
|
317
295
|
`package.json 'author' field "${author}" has no parseable email \u2014 marketplace owner.email will be empty`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/cli/commands/build/marketplace.ts","../../../src/cli/lib/marketplace-generator.ts","../../../src/cli/lib/validate-kebab-name.ts"],"sourcesContent":["import { Flags } from \"@oclif/core\";\nimport path from \"path\";\nimport { sortBy } from \"remeda\";\nimport { z } from \"zod\";\n\nimport { BaseCommand } from \"../../base-command\";\nimport { setVerbose, warn } from \"../../utils/logger\";\nimport { readFile } from \"../../utils/fs\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { EXIT_CODES } from \"../../lib/exit-codes\";\nimport {\n generateMarketplace,\n writeMarketplace,\n getMarketplaceStats,\n} from \"../../lib/marketplace-generator\";\nimport { MARKETPLACE_JSON, PLUGIN_MANIFEST_DIR, PLUGINS_DIST_PATH } from \"../../consts\";\nimport type { Marketplace } from \"../../types/plugins\";\nimport { validateKebabCaseName } from \"../../lib/validate-kebab-name.js\";\n\nconst DEFAULT_OUTPUT_FILE = `${PLUGIN_MANIFEST_DIR}/${MARKETPLACE_JSON}`;\n\nconst AUTHOR_STRING_PATTERN = /^(.*?)\\s*<([^>]+)>\\s*(?:\\(([^)]+)\\))?\\s*$/;\n\nconst packageAuthorObjectSchema = z.object({\n name: z.string(),\n email: z.string().exactOptional(),\n url: z.string().exactOptional(),\n});\n\nconst packageJsonSchema = z\n .object({\n name: z.string(),\n version: z.string(),\n description: z.string(),\n author: z.union([z.string(), packageAuthorObjectSchema]).exactOptional(),\n })\n .passthrough();\n\ntype PackageJson = z.infer<typeof packageJsonSchema>;\ntype MarketplaceIdentity = Pick<PackageJson, \"name\" | \"version\" | \"description\"> & {\n ownerName: string;\n ownerEmail?: string;\n};\n\nexport default class BuildMarketplace extends BaseCommand {\n static summary = \"Generate marketplace.json from built plugins (requires skills repo)\";\n\n static description =\n \"Generate marketplace.json from built plugins. This command scans the plugins directory and generates a marketplace manifest file. Reads marketplace identity (name, version, description, author) from package.json in the current working directory. Use --name to override the marketplace name when package.json uses an npm scoped name (e.g. @scope/pkg), which is not a valid marketplace name.\";\n\n static examples = [\n {\n description: \"Generate marketplace.json from the default plugins directory\",\n command: \"<%= config.bin %> <%= command.id %>\",\n },\n {\n description: \"Generate marketplace.json from a custom plugins directory\",\n command: \"<%= config.bin %> <%= command.id %> --plugins-dir dist/stacks\",\n },\n {\n description: \"Write marketplace.json to a custom output path\",\n command: \"<%= config.bin %> <%= command.id %> --output .claude-plugin/market.json\",\n },\n {\n description:\n \"Override the marketplace name (use when package.json has an npm scoped name like @scope/pkg)\",\n command: \"<%= config.bin %> <%= command.id %> --name my-marketplace\",\n },\n ];\n\n static flags = {\n name: Flags.string({\n description:\n \"Override the marketplace name (defaults to package.json 'name'). Must be kebab-case.\",\n }),\n \"plugins-dir\": Flags.string({\n char: \"p\",\n description: \"Plugins directory\",\n default: PLUGINS_DIST_PATH,\n }),\n output: Flags.string({\n char: \"o\",\n description: \"Output file\",\n default: DEFAULT_OUTPUT_FILE,\n }),\n verbose: Flags.boolean({\n char: \"v\",\n description: \"Enable verbose logging\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(BuildMarketplace);\n setVerbose(flags.verbose);\n\n const projectRoot = process.cwd();\n const pluginsDir = path.resolve(projectRoot, flags[\"plugins-dir\"]);\n const outputPath = path.resolve(projectRoot, flags.output);\n const identity = await this.loadMarketplaceIdentity(projectRoot, flags.name);\n\n this.printHeader(pluginsDir, outputPath);\n\n try {\n const marketplace = await this.generateAndWrite(\n pluginsDir,\n outputPath,\n flags[\"plugins-dir\"],\n identity,\n );\n this.printStats(marketplace);\n this.printSample(marketplace);\n\n this.log(\"\");\n this.logSuccess(\n `Marketplace generated with ${getMarketplaceStats(marketplace).total} plugins!`,\n );\n this.log(\"\");\n } catch (error) {\n this.log(\"Generation failed\");\n this.handleError(error);\n }\n }\n\n private async loadMarketplaceIdentity(\n projectRoot: string,\n nameOverride?: string,\n ): Promise<MarketplaceIdentity> {\n const packageJsonPath = path.join(projectRoot, \"package.json\");\n\n let rawContent: string;\n try {\n rawContent = await readFile(packageJsonPath);\n } catch {\n this.error(\n `Missing package.json at ${projectRoot}. build marketplace reads marketplace identity from package.json.`,\n { exit: EXIT_CODES.ERROR },\n );\n }\n\n let parsedJson: unknown;\n try {\n parsedJson = JSON.parse(rawContent);\n } catch (error) {\n this.error(`Failed to parse package.json at ${packageJsonPath}: ${getErrorMessage(error)}`, {\n exit: EXIT_CODES.ERROR,\n });\n }\n\n const parseResult = packageJsonSchema.safeParse(parsedJson);\n if (!parseResult.success) {\n const missingFields = parseResult.error.issues.map((i) => i.path.join(\".\")).join(\", \");\n this.error(\n `package.json at ${packageJsonPath} is missing required fields: ${missingFields}. build marketplace reads marketplace identity from package.json.`,\n { exit: EXIT_CODES.ERROR },\n );\n }\n\n const { name, version, description, author } = parseResult.data;\n const owner = parseAuthor(author);\n\n let resolvedName = name;\n if (nameOverride !== undefined) {\n const validationError = validateKebabCaseName(nameOverride, \"Marketplace\");\n if (validationError) {\n this.error(`Invalid --name '${nameOverride}': ${validationError}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n resolvedName = nameOverride;\n }\n\n return {\n name: resolvedName,\n version,\n description,\n ownerName: owner.name,\n ...(owner.email !== undefined && { ownerEmail: owner.email }),\n };\n }\n\n private printHeader(pluginsDir: string, outputPath: string): void {\n this.log(\"\");\n this.log(\"Generating marketplace.json\");\n this.log(` Plugins directory: ${pluginsDir}`);\n this.log(` Output file: ${outputPath}`);\n this.log(\"\");\n }\n\n private async generateAndWrite(\n pluginsDir: string,\n outputPath: string,\n pluginsDirFlag: string,\n identity: MarketplaceIdentity,\n ): Promise<Marketplace> {\n this.log(\"Scanning plugins...\");\n\n const marketplace = await generateMarketplace(pluginsDir, {\n name: identity.name,\n version: identity.version,\n description: identity.description,\n ownerName: identity.ownerName,\n ...(identity.ownerEmail !== undefined && { ownerEmail: identity.ownerEmail }),\n pluginRoot: `./${pluginsDirFlag}`,\n });\n\n const stats = getMarketplaceStats(marketplace);\n this.log(`Found ${stats.total} plugins`);\n\n this.log(\"Writing marketplace.json...\");\n await writeMarketplace(outputPath, marketplace);\n this.log(`Wrote ${outputPath}`);\n\n return marketplace;\n }\n\n private printStats(marketplace: Marketplace): void {\n this.log(\"\");\n this.log(\"Category breakdown:\");\n const sortedCategories = sortBy(\n Object.entries(getMarketplaceStats(marketplace).byCategory),\n ([, count]) => -count,\n );\n for (const [category, count] of sortedCategories) {\n this.log(` ${category}: ${count}`);\n }\n }\n\n private printSample(marketplace: Marketplace): void {\n this.log(\"\");\n this.log(\"Sample plugins:\");\n const sampleSize = 5;\n for (const plugin of marketplace.plugins.slice(0, sampleSize)) {\n const version = plugin.version ? `v${plugin.version}` : \"\";\n const category = plugin.category ? `[${plugin.category}]` : \"\";\n this.log(` ${plugin.name} ${version} ${category}`);\n if (plugin.description) {\n this.log(` ${plugin.description}`);\n }\n }\n if (marketplace.plugins.length > sampleSize) {\n this.log(` ... and ${marketplace.plugins.length - sampleSize} more`);\n }\n }\n}\n\ntype ParsedAuthor = {\n name: string;\n email?: string;\n};\n\n/**\n * Parses a package.json `author` field into name + optional email.\n *\n * npm supports both shorthand strings `\"Name <email> (url)\"` and object form\n * `{ name, email, url }`. We emit a warning when a string author has no\n * parseable email so the caller knows the marketplace owner.email will be absent.\n */\nfunction parseAuthor(author: string | { name: string; email?: string } | undefined): ParsedAuthor {\n if (!author) {\n warn(\"package.json is missing 'author' field — marketplace owner.email will be empty\");\n return { name: \"\" };\n }\n\n if (typeof author === \"object\") {\n return { name: author.name, ...(author.email !== undefined && { email: author.email }) };\n }\n\n const [, matchedName, matchedEmail] = author.match(AUTHOR_STRING_PATTERN) ?? [];\n if (matchedName !== undefined && matchedEmail !== undefined) {\n const name = matchedName.trim();\n const email = matchedEmail.trim();\n if (name === \"\") {\n warn(\n `package.json 'author' field \"${author}\" has no parseable name — marketplace owner.name will be empty`,\n );\n }\n return { name, email };\n }\n\n warn(\n `package.json 'author' field \"${author}\" has no parseable email — marketplace owner.email will be empty`,\n );\n return { name: author.trim() };\n}\n","import path from \"path\";\nimport { countBy, sortBy } from \"remeda\";\n\nimport { DEFAULT_VERSION, PLUGIN_MANIFEST_DIR, PLUGIN_MANIFEST_FILE } from \"../consts\";\nimport { writeFile, glob, ensureDir } from \"../utils/fs\";\nimport { verbose, warn } from \"../utils/logger\";\nimport type { Marketplace, MarketplacePlugin, PluginManifest } from \"../types\";\nimport { readPluginManifest } from \"./plugins\";\n\nconst PLUGIN_MANIFEST_PATH = `${PLUGIN_MANIFEST_DIR}/${PLUGIN_MANIFEST_FILE}`;\nconst MARKETPLACE_SCHEMA_URL = \"https://anthropic.com/claude-code/marketplace.schema.json\";\n\ntype MarketplaceOptions = {\n name: string;\n version?: string;\n description?: string;\n ownerName: string;\n ownerEmail?: string;\n pluginRoot: string;\n};\n\nfunction convertManifestToMarketplacePlugin(\n manifest: PluginManifest,\n pluginRoot: string,\n pluginDirName: string,\n): MarketplacePlugin {\n return {\n name: manifest.name,\n source: `./${pluginRoot}/${pluginDirName}`,\n ...(manifest.description !== undefined && { description: manifest.description }),\n ...(manifest.version !== undefined && { version: manifest.version }),\n ...(manifest.author !== undefined && { author: manifest.author }),\n ...(manifest.keywords !== undefined && { keywords: manifest.keywords }),\n };\n}\n\nexport async function generateMarketplace(\n pluginsDir: string,\n options: MarketplaceOptions,\n): Promise<Marketplace> {\n verbose(`Scanning plugins directory: ${pluginsDir}`);\n\n const manifestFiles = await glob(`**/${PLUGIN_MANIFEST_PATH}`, pluginsDir);\n verbose(`Found ${manifestFiles.length} plugin manifests`);\n\n const plugins: MarketplacePlugin[] = [];\n\n for (const manifestFile of manifestFiles) {\n const separator = manifestFile.indexOf(\"/\");\n const pluginDirName = separator === -1 ? manifestFile : manifestFile.slice(0, separator);\n const pluginDir = path.join(pluginsDir, pluginDirName);\n\n const manifest = await readPluginManifest(pluginDir);\n if (!manifest) {\n warn(`Could not read plugin manifest: '${manifestFile}'`);\n continue;\n }\n\n const plugin = convertManifestToMarketplacePlugin(\n manifest,\n options.pluginRoot.replace(/^\\.\\//, \"\"),\n pluginDirName,\n );\n plugins.push(plugin);\n verbose(` [OK] ${plugin.name}`);\n }\n\n const sortedPlugins = sortBy(plugins, (p) => p.name);\n\n // Field order matters: the object is serialized verbatim into marketplace.json,\n // so conditional fields keep the same positions the previous emissions used.\n return {\n $schema: MARKETPLACE_SCHEMA_URL,\n name: options.name,\n version: options.version ?? DEFAULT_VERSION,\n owner: {\n name: options.ownerName,\n ...(options.ownerEmail ? { email: options.ownerEmail } : {}),\n },\n metadata: {\n pluginRoot: options.pluginRoot,\n },\n plugins: sortedPlugins,\n ...(options.description ? { description: options.description } : {}),\n };\n}\n\nexport async function writeMarketplace(\n outputPath: string,\n marketplace: Marketplace,\n): Promise<void> {\n await ensureDir(path.dirname(outputPath));\n const content = `${JSON.stringify(marketplace, null, 2)}\\n`;\n await writeFile(outputPath, content);\n}\n\nexport function getMarketplaceStats(marketplace: Marketplace): {\n total: number;\n byCategory: Record<string, number>;\n} {\n return {\n total: marketplace.plugins.length,\n byCategory: countBy(marketplace.plugins, (p) => p.category ?? \"uncategorized\"),\n };\n}\n","import { KEBAB_CASE_PATTERN } from \"../consts.js\";\n\n/**\n * Validates a user-supplied entity name against the kebab-case convention.\n * Returns an error message naming the entity (e.g. \"Marketplace\", \"Skill\"),\n * or null when the name is valid.\n */\nexport function validateKebabCaseName(name: string, noun: string): string | null {\n if (!name || name.trim() === \"\") {\n return `${noun} name is required`;\n }\n\n if (!KEBAB_CASE_PATTERN.test(name)) {\n return `${noun} name must be kebab-case (lowercase letters, numbers, and hyphens, starting with a letter)`;\n }\n\n return null;\n}\n"],"mappings":"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","names":["path","sortBy","path","sortBy"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/cli/commands/build/marketplace.ts"],"sourcesContent":["import { Flags } from \"@oclif/core\";\nimport path from \"path\";\nimport { sortBy } from \"remeda\";\nimport { z } from \"zod\";\n\nimport { BaseCommand } from \"../../base-command\";\nimport { setVerbose, warn } from \"../../utils/logger\";\nimport {\n marketplaceHasNoVersion,\n marketplaceNameNotPublishable,\n marketplaceOwnerHasNoName,\n} from \"../../utils/messages\";\nimport { readFile, writeFile } from \"../../utils/fs\";\nimport { getErrorMessage } from \"../../utils/errors\";\nimport { EXIT_CODES } from \"../../lib/exit-codes\";\nimport { loadMarketplaceMatrix } from \"../../lib/loading\";\nimport {\n generateMarketplace,\n writeMarketplace,\n getMarketplaceStats,\n validateMarketplaceName,\n validateSkillIdNamespace,\n} from \"../../lib/marketplace-generator\";\nimport {\n CATALOG_JSON,\n CLI_INVOKE_COMMAND,\n GENERATED_AT_BUILD,\n MARKETPLACE_JSON,\n PLUGIN_MANIFEST_DIR,\n PLUGINS_DIST_PATH,\n STANDARD_FILES,\n} from \"../../consts\";\nimport type { Marketplace } from \"../../types/plugins\";\nimport { validateKebabCaseName } from \"../../lib/validate-kebab-name.js\";\n\nconst DEFAULT_OUTPUT_FILE = `${PLUGIN_MANIFEST_DIR}/${MARKETPLACE_JSON}`;\n\nconst AUTHOR_STRING_PATTERN = /^(.*?)\\s*<([^>]+)>\\s*(?:\\(([^)]+)\\))?\\s*$/;\n\n/** The entity {@link validateKebabCaseName} names in this command's refusals. */\nconst MARKETPLACE_NOUN = \"Marketplace\";\n\nconst packageAuthorObjectSchema = z.object({\n name: z.string(),\n email: z.string().exactOptional(),\n url: z.string().exactOptional(),\n});\n\nconst packageJsonSchema = z\n .object({\n name: z.string(),\n version: z.string(),\n description: z.string(),\n author: z.union([z.string(), packageAuthorObjectSchema]).exactOptional(),\n })\n .passthrough();\n\ntype PackageJson = z.infer<typeof packageJsonSchema>;\ntype MarketplaceIdentity = Pick<PackageJson, \"name\" | \"version\" | \"description\"> & {\n ownerName: string;\n ownerEmail?: string;\n};\n\nexport default class BuildMarketplace extends BaseCommand {\n static summary = \"Generate marketplace.json from built plugins (requires skills repo)\";\n\n static description =\n \"Generate marketplace.json from built plugins. This command scans the plugins directory and generates a marketplace manifest file. Reads marketplace identity (name, version, description, author) from package.json in the current working directory. Use --name to override the marketplace name when package.json uses an npm scoped name (e.g. @scope/pkg), which is not a valid marketplace name.\";\n\n static examples = [\n {\n description: \"Generate marketplace.json from the default plugins directory\",\n command: \"<%= config.bin %> <%= command.id %>\",\n },\n {\n description: \"Generate marketplace.json from a custom plugins directory\",\n command: \"<%= config.bin %> <%= command.id %> --plugins-dir dist/stacks\",\n },\n {\n description: \"Write marketplace.json to a custom output path\",\n command: \"<%= config.bin %> <%= command.id %> --output .claude-plugin/market.json\",\n },\n {\n description:\n \"Override the marketplace name (use when package.json has an npm scoped name like @scope/pkg)\",\n command: \"<%= config.bin %> <%= command.id %> --name my-marketplace\",\n },\n ];\n\n static flags = {\n name: Flags.string({\n description:\n \"Override the marketplace name (defaults to package.json 'name'). Must be kebab-case.\",\n }),\n \"plugins-dir\": Flags.string({\n char: \"p\",\n description: \"Plugins directory\",\n default: PLUGINS_DIST_PATH,\n }),\n output: Flags.string({\n char: \"o\",\n description: \"Output file\",\n default: DEFAULT_OUTPUT_FILE,\n }),\n verbose: Flags.boolean({\n char: \"v\",\n description: \"Enable verbose logging\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(BuildMarketplace);\n setVerbose(flags.verbose);\n\n const projectRoot = process.cwd();\n const pluginsDir = path.resolve(projectRoot, flags[\"plugins-dir\"]);\n const outputPath = path.resolve(projectRoot, flags.output);\n const identity = await this.loadMarketplaceIdentity(projectRoot, flags.name);\n\n this.printHeader(pluginsDir, outputPath);\n\n try {\n const marketplace = await this.generateAndWrite(\n pluginsDir,\n outputPath,\n flags[\"plugins-dir\"],\n identity,\n );\n await this.writeCatalog(projectRoot, outputPath);\n this.printStats(marketplace);\n this.printSample(marketplace);\n\n this.log(\"\");\n this.logSuccess(\n `Marketplace generated with ${getMarketplaceStats(marketplace).total} plugins!`,\n );\n this.log(\"\");\n } catch (error) {\n this.log(\"Generation failed\");\n this.handleError(error);\n }\n }\n\n private async loadMarketplaceIdentity(\n projectRoot: string,\n nameOverride?: string,\n ): Promise<MarketplaceIdentity> {\n const packageJsonPath = path.join(projectRoot, STANDARD_FILES.PACKAGE_JSON);\n\n let rawContent: string;\n try {\n rawContent = await readFile(packageJsonPath);\n } catch {\n this.error(\n `Missing package.json at ${projectRoot}. build marketplace reads marketplace identity from package.json.`,\n { exit: EXIT_CODES.ERROR },\n );\n }\n\n let parsedJson: unknown;\n try {\n parsedJson = JSON.parse(rawContent);\n } catch (error) {\n this.error(`Failed to parse package.json at ${packageJsonPath}: ${getErrorMessage(error)}`, {\n exit: EXIT_CODES.ERROR,\n });\n }\n\n const parseResult = packageJsonSchema.safeParse(parsedJson);\n if (!parseResult.success) {\n const missingFields = parseResult.error.issues.map((i) => i.path.join(\".\")).join(\", \");\n this.error(\n `package.json at ${packageJsonPath} is missing required fields: ${missingFields}. build marketplace reads marketplace identity from package.json.`,\n { exit: EXIT_CODES.ERROR },\n );\n }\n\n const { name, version, description, author } = parseResult.data;\n\n if (version.trim() === \"\") {\n this.error(marketplaceHasNoVersion(packageJsonPath), { exit: EXIT_CODES.ERROR });\n }\n\n const owner = parseAuthor(author);\n if (owner.name.trim() === \"\") {\n this.error(marketplaceOwnerHasNoName(packageJsonPath), { exit: EXIT_CODES.ERROR });\n }\n\n const resolvedName = this.resolvePublishableName(name, nameOverride, packageJsonPath);\n\n const reservedError = validateMarketplaceName(resolvedName, name);\n if (reservedError) {\n this.error(reservedError, { exit: EXIT_CODES.ERROR });\n }\n\n return {\n name: resolvedName,\n version,\n description,\n ownerName: owner.name,\n ...(owner.email !== undefined && { ownerEmail: owner.email }),\n };\n }\n\n /**\n * The name this marketplace publishes under, refused before anything is written when\n * it is not one `claude plugin marketplace add` will accept.\n *\n * Both halves are judged by the same rule and refused with different sentences: a\n * `--name` the author typed is an argument they can retype, while a name derived from\n * package.json is a fact about their package — an npm scoped name is legitimate there\n * and illegitimate here — so its way out is the flag rather than a package rename.\n */\n private resolvePublishableName(\n packageName: string,\n nameOverride: string | undefined,\n packageJsonPath: string,\n ): string {\n if (nameOverride !== undefined) {\n const invalidOverride = validateKebabCaseName(nameOverride, MARKETPLACE_NOUN);\n if (invalidOverride) {\n this.error(`Invalid --name '${nameOverride}': ${invalidOverride}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n return nameOverride;\n }\n\n if (validateKebabCaseName(packageName, MARKETPLACE_NOUN)) {\n this.error(marketplaceNameNotPublishable(packageName, packageJsonPath), {\n exit: EXIT_CODES.ERROR,\n });\n }\n return packageName;\n }\n\n private printHeader(pluginsDir: string, outputPath: string): void {\n this.log(\"\");\n this.log(\"Generating marketplace.json\");\n this.log(` Plugins directory: ${pluginsDir}`);\n this.log(` Output file: ${outputPath}`);\n this.log(\"\");\n }\n\n private async generateAndWrite(\n pluginsDir: string,\n outputPath: string,\n pluginsDirFlag: string,\n identity: MarketplaceIdentity,\n ): Promise<Marketplace> {\n this.log(\"Scanning plugins...\");\n\n const marketplace = await generateMarketplace(pluginsDir, {\n name: identity.name,\n version: identity.version,\n description: identity.description,\n ownerName: identity.ownerName,\n ...(identity.ownerEmail !== undefined && { ownerEmail: identity.ownerEmail }),\n pluginRoot: `./${pluginsDirFlag}`,\n });\n\n const stats = getMarketplaceStats(marketplace);\n this.log(`Found ${stats.total} plugins`);\n\n if (marketplace.plugins.length === 0) {\n this.error(noPluginsToPublish(pluginsDir, pluginsDirFlag), { exit: EXIT_CODES.ERROR });\n }\n\n const namespaceError = validateSkillIdNamespace(marketplace);\n if (namespaceError) {\n this.error(namespaceError, { exit: EXIT_CODES.ERROR });\n }\n\n this.log(\"Writing marketplace.json...\");\n await writeMarketplace(outputPath, marketplace);\n this.log(`Wrote ${outputPath}`);\n\n return marketplace;\n }\n\n /**\n * Writes the marketplace's catalogue beside its manifest.\n *\n * Unconditional, and there is no flag to make it otherwise: a consumer\n * fetching a marketplace cannot tell an author who omitted a flag from a\n * marketplace that is broken, so an absent catalogue has to mean the second.\n *\n * `generatedAt` is stamped rather than carried: see {@link GENERATED_AT_BUILD}\n * for why a published artefact records a build and not a moment.\n */\n private async writeCatalog(projectRoot: string, outputPath: string): Promise<void> {\n const catalogPath = path.join(path.dirname(outputPath), CATALOG_JSON);\n\n this.log(`Writing ${CATALOG_JSON}...`);\n const matrix = await loadMarketplaceMatrix(projectRoot);\n const catalog = { ...matrix, generatedAt: GENERATED_AT_BUILD };\n await writeFile(catalogPath, `${JSON.stringify(catalog, null, 2)}\\n`);\n this.log(`Wrote ${catalogPath}`);\n }\n\n private printStats(marketplace: Marketplace): void {\n this.log(\"\");\n this.log(\"Category breakdown:\");\n const sortedCategories = sortBy(\n Object.entries(getMarketplaceStats(marketplace).byCategory),\n ([, count]) => -count,\n );\n for (const [category, count] of sortedCategories) {\n this.log(` ${category}: ${count}`);\n }\n }\n\n private printSample(marketplace: Marketplace): void {\n this.log(\"\");\n this.log(\"Sample plugins:\");\n const sampleSize = 5;\n for (const plugin of marketplace.plugins.slice(0, sampleSize)) {\n const version = plugin.version ? `v${plugin.version}` : \"\";\n const category = plugin.category ? `[${plugin.category}]` : \"\";\n this.log(` ${plugin.name} ${version} ${category}`);\n if (plugin.description) {\n this.log(` ${plugin.description}`);\n }\n }\n if (marketplace.plugins.length > sampleSize) {\n this.log(` ... and ${marketplace.plugins.length - sampleSize} more`);\n }\n }\n}\n\ntype ParsedAuthor = {\n name: string;\n email?: string;\n};\n\n/**\n * Refuses a manifest with no plugins in it, which the reader in this same package will not accept:\n * `marketplaceSchema.plugins` is `z.array(...).min(1)`, so `fetchMarketplace` throws\n * `plugins: Too small` on a file this command wrote and called a success. Every field that schema\n * constrains is a condition this command refuses before writing — `name`, `version` and\n * `owner.name` are the other three, all guarded off package.json. `version` was the one this\n * sentence claimed and did not have: `packageJsonSchema` types it as a bare string and the\n * generator defaults it with `??`, so `\"\"` reached the manifest untouched. This one is only\n * knowable after the scan, which is why it sits here rather than beside them.\n *\n * The two ways in are running before `build plugins` and pointing `--plugins-dir` somewhere else, so\n * the sentence names the directory it scanned and both ways out. Written here rather than in\n * `utils/messages.ts` for the reason the `Missing package.json` refusal above it is: it has one\n * caller and composes nothing another surface has to agree with.\n */\nfunction noPluginsToPublish(pluginsDir: string, pluginsDirFlag: string): string {\n return (\n `No plugins found in ${pluginsDir}. A marketplace with no plugins is refused when it is read ` +\n `back, so none was written. Run '${CLI_INVOKE_COMMAND} build plugins' first, or point ` +\n `--plugins-dir at the directory holding them (it is '${pluginsDirFlag}' for this run).`\n );\n}\n\n/**\n * Parses a package.json `author` field into name + optional email.\n *\n * npm supports both shorthand strings `\"Name <email> (url)\"` and object form\n * `{ name, email, url }`. An absent author and one that yields no name both come back\n * with an empty `name`, and the caller refuses on that — one condition, one sentence,\n * written where the refusal is. A missing EMAIL is warned about and carried on from,\n * because `owner.email` is the half the manifest schema leaves optional.\n */\nfunction parseAuthor(author: string | { name: string; email?: string } | undefined): ParsedAuthor {\n if (!author) return { name: \"\" };\n\n if (typeof author === \"object\") {\n return { name: author.name, ...(author.email !== undefined && { email: author.email }) };\n }\n\n const [, matchedName, matchedEmail] = author.match(AUTHOR_STRING_PATTERN) ?? [];\n if (matchedName !== undefined && matchedEmail !== undefined) {\n return { name: matchedName.trim(), email: matchedEmail.trim() };\n }\n\n warn(\n `package.json 'author' field \"${author}\" has no parseable email — marketplace owner.email will be empty`,\n );\n return { name: author.trim() };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -2,29 +2,29 @@
|
|
|
2
2
|
import {
|
|
3
3
|
compileAllAgentPlugins,
|
|
4
4
|
printAgentCompilationSummary
|
|
5
|
-
} from "../../chunk-
|
|
5
|
+
} from "../../chunk-ZUAZHDKP.js";
|
|
6
6
|
import {
|
|
7
7
|
BaseCommand
|
|
8
|
-
} from "../../chunk-
|
|
9
|
-
import "../../chunk-
|
|
10
|
-
import "../../chunk-
|
|
8
|
+
} from "../../chunk-YO2LTXB4.js";
|
|
9
|
+
import "../../chunk-UMH2YZKG.js";
|
|
10
|
+
import "../../chunk-G47TDUK3.js";
|
|
11
11
|
import {
|
|
12
12
|
compileAllSkillPlugins,
|
|
13
13
|
compileSkillPlugin,
|
|
14
14
|
printCompilationSummary,
|
|
15
15
|
readPluginManifest
|
|
16
|
-
} from "../../chunk-
|
|
16
|
+
} from "../../chunk-WCAUUBHO.js";
|
|
17
17
|
import {
|
|
18
18
|
listDirectories,
|
|
19
19
|
remove,
|
|
20
20
|
setVerbose
|
|
21
|
-
} from "../../chunk-
|
|
22
|
-
import "../../chunk-
|
|
21
|
+
} from "../../chunk-XAXJWXI4.js";
|
|
22
|
+
import "../../chunk-RWOYPOMR.js";
|
|
23
23
|
import "../../chunk-VASLW636.js";
|
|
24
24
|
import {
|
|
25
25
|
DIRS,
|
|
26
26
|
PLUGINS_DIST_PATH
|
|
27
|
-
} from "../../chunk-
|
|
27
|
+
} from "../../chunk-IO5YBKHV.js";
|
|
28
28
|
import "../../chunk-VZRO7RYT.js";
|
|
29
29
|
|
|
30
30
|
// src/cli/commands/build/plugins.ts
|
package/dist/commands/compile.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
detectBothInstallations
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-WUQ3MTPF.js";
|
|
5
5
|
import {
|
|
6
6
|
compileAgents,
|
|
7
7
|
discoverInstalledSkills
|
|
8
|
-
} from "../chunk-
|
|
9
|
-
import "../chunk-NXGMM5YN.js";
|
|
8
|
+
} from "../chunk-5QZAK6J7.js";
|
|
10
9
|
import {
|
|
11
10
|
loadAgentDefs
|
|
12
|
-
} from "../chunk-
|
|
13
|
-
import "../chunk-
|
|
11
|
+
} from "../chunk-MHRC3KRX.js";
|
|
12
|
+
import "../chunk-F2AMBBIA.js";
|
|
13
|
+
import "../chunk-ZUAZHDKP.js";
|
|
14
14
|
import {
|
|
15
15
|
BaseCommand,
|
|
16
16
|
EXIT_CODES
|
|
17
|
-
} from "../chunk-
|
|
18
|
-
import "../chunk-
|
|
19
|
-
import "../chunk-
|
|
17
|
+
} from "../chunk-YO2LTXB4.js";
|
|
18
|
+
import "../chunk-UMH2YZKG.js";
|
|
19
|
+
import "../chunk-G47TDUK3.js";
|
|
20
20
|
import {
|
|
21
21
|
ConfigLoadError,
|
|
22
22
|
ERROR_MESSAGES,
|
|
@@ -26,32 +26,35 @@ import {
|
|
|
26
26
|
effectivelyExcludedSkillIds,
|
|
27
27
|
getStackSkillIds,
|
|
28
28
|
globalScopedAgentsHint,
|
|
29
|
+
isActiveAt,
|
|
29
30
|
loadProjectConfig,
|
|
30
31
|
loadProjectConfigFromDir,
|
|
31
32
|
loadSkillsMatrixFromSource,
|
|
32
33
|
recompileSummary,
|
|
33
34
|
reconcileTypesFromDisk,
|
|
34
35
|
registeredProjectUpdateSkipped,
|
|
36
|
+
resolveAgentConfigToSkills,
|
|
35
37
|
resolveSource,
|
|
38
|
+
scopeBlockedStackAssignment,
|
|
36
39
|
skillMetadataUnusableDetail,
|
|
37
40
|
skillMetadataUnusableError
|
|
38
|
-
} from "../chunk-
|
|
41
|
+
} from "../chunk-WCAUUBHO.js";
|
|
39
42
|
import {
|
|
40
43
|
getErrorMessage,
|
|
41
44
|
setVerbose,
|
|
42
45
|
verbose
|
|
43
|
-
} from "../chunk-
|
|
44
|
-
import "../chunk-
|
|
46
|
+
} from "../chunk-XAXJWXI4.js";
|
|
47
|
+
import "../chunk-RWOYPOMR.js";
|
|
45
48
|
import "../chunk-VASLW636.js";
|
|
46
49
|
import {
|
|
47
|
-
CLI_INVOKE_COMMAND,
|
|
48
50
|
STANDARD_FILES
|
|
49
|
-
} from "../chunk-
|
|
51
|
+
} from "../chunk-IO5YBKHV.js";
|
|
50
52
|
import "../chunk-VZRO7RYT.js";
|
|
51
53
|
|
|
52
54
|
// src/cli/commands/compile.ts
|
|
53
55
|
import { Flags } from "@oclif/core";
|
|
54
56
|
import os from "os";
|
|
57
|
+
import { unique } from "remeda";
|
|
55
58
|
var Compile = class _Compile extends BaseCommand {
|
|
56
59
|
static summary = "Compile agents using local skills and agent definitions";
|
|
57
60
|
static description = "Compile agents with resolved skill references. Compiles to the Claude plugin directory.";
|
|
@@ -72,7 +75,7 @@ var Compile = class _Compile extends BaseCommand {
|
|
|
72
75
|
const cwd = process.cwd();
|
|
73
76
|
const installations = await this.detectInstallations(cwd);
|
|
74
77
|
await this.resolveAndLogSource(cwd);
|
|
75
|
-
const agentDefs = await this.loadAgentDefsOrFail(
|
|
78
|
+
const agentDefs = await this.loadAgentDefsOrFail();
|
|
76
79
|
await this.runCompilePasses(installations, agentDefs, cwd);
|
|
77
80
|
}
|
|
78
81
|
async detectInstallations(cwd) {
|
|
@@ -93,8 +96,8 @@ var Compile = class _Compile extends BaseCommand {
|
|
|
93
96
|
return installations;
|
|
94
97
|
}
|
|
95
98
|
/**
|
|
96
|
-
* Names where the
|
|
97
|
-
* one, then the default. `compile` takes no `--
|
|
99
|
+
* Names where the marketplace came from — the project's own config first, then the global
|
|
100
|
+
* one, then the default. `compile` takes no `--marketplace`: it recompiles an installation
|
|
98
101
|
* that already recorded which marketplace its skill references answer to, and reading
|
|
99
102
|
* a different one would write agents against a catalogue config.ts does not name.
|
|
100
103
|
*/
|
|
@@ -102,19 +105,18 @@ var Compile = class _Compile extends BaseCommand {
|
|
|
102
105
|
this.log(STATUS_MESSAGES.RESOLVING_SOURCE);
|
|
103
106
|
try {
|
|
104
107
|
const sourceConfig = await resolveSource({ caller: "stored", projectDir });
|
|
105
|
-
this.log(`
|
|
108
|
+
this.log(`Marketplace: ${sourceConfig.sourceOrigin}`);
|
|
106
109
|
} catch (error) {
|
|
107
110
|
this.log(ERROR_MESSAGES.FAILED_RESOLVE_SOURCE);
|
|
108
111
|
this.handleError(error);
|
|
109
112
|
}
|
|
110
113
|
}
|
|
111
|
-
async loadAgentDefsOrFail(
|
|
114
|
+
async loadAgentDefsOrFail() {
|
|
112
115
|
this.log(STATUS_MESSAGES.LOADING_AGENT_PARTIALS);
|
|
113
116
|
try {
|
|
114
|
-
const defs = await loadAgentDefs(
|
|
117
|
+
const defs = await loadAgentDefs();
|
|
115
118
|
this.log("Agent partials loaded");
|
|
116
119
|
verbose(` Agents: ${defs.agentSourcePaths.agentsDir}`);
|
|
117
|
-
verbose(` Templates: ${defs.agentSourcePaths.templatesDir}`);
|
|
118
120
|
return defs;
|
|
119
121
|
} catch (error) {
|
|
120
122
|
this.log(ERROR_MESSAGES.FAILED_LOAD_AGENT_PARTIALS);
|
|
@@ -129,10 +131,7 @@ var Compile = class _Compile extends BaseCommand {
|
|
|
129
131
|
if (hadSkills) totalPassesWithSkills++;
|
|
130
132
|
}
|
|
131
133
|
if (totalPassesWithSkills === 0) {
|
|
132
|
-
this.error(
|
|
133
|
-
`No skills found. Add skills with '${CLI_INVOKE_COMMAND} add <skill>' or create in .claude/skills/.`,
|
|
134
|
-
{ exit: EXIT_CODES.ERROR }
|
|
135
|
-
);
|
|
134
|
+
this.error(ERROR_MESSAGES.NO_SKILLS_TO_COMPILE, { exit: EXIT_CODES.ERROR });
|
|
136
135
|
}
|
|
137
136
|
}
|
|
138
137
|
/**
|
|
@@ -182,6 +181,24 @@ var Compile = class _Compile extends BaseCommand {
|
|
|
182
181
|
);
|
|
183
182
|
}
|
|
184
183
|
}
|
|
184
|
+
/**
|
|
185
|
+
* `config.ts` is the hand-editable half of the pair, so it can declare a pair the scope
|
|
186
|
+
* rule forbids: a GLOBAL sub-agent whose stack carries a PROJECT-scoped skill. The
|
|
187
|
+
* compile-time filter in `buildCompileAgents` drops that reference on the way to the
|
|
188
|
+
* resolver and `compile` rewrites nothing in `config.ts`, so the row survives and is
|
|
189
|
+
* dropped again on every future run — while the recompile summary reports a clean pass
|
|
190
|
+
* over an agent that no longer carries what its own config says it does.
|
|
191
|
+
*
|
|
192
|
+
* The sibling of {@link warnUnresolvedStackSkills} one layer over: there the skill is
|
|
193
|
+
* missing from disk, here it is present and unreachable from that sub-agent.
|
|
194
|
+
*/
|
|
195
|
+
async warnScopeDroppedStackPairs(projectDir) {
|
|
196
|
+
const loaded = await loadProjectConfig(projectDir);
|
|
197
|
+
if (!loaded?.config.stack) return;
|
|
198
|
+
for (const [skillId, agentNames] of findScopeDroppedStackPairs(loaded.config)) {
|
|
199
|
+
this.warn(scopeBlockedStackAssignment(agentNames, skillId));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
185
202
|
/**
|
|
186
203
|
* The project pass compiled no agents, but the project config may still declare
|
|
187
204
|
* global-scope agents whose stack lives in the global config. Without a pointer
|
|
@@ -269,6 +286,7 @@ var Compile = class _Compile extends BaseCommand {
|
|
|
269
286
|
return false;
|
|
270
287
|
}
|
|
271
288
|
await this.warnUnresolvedStackSkills(projectDir, allSkills);
|
|
289
|
+
await this.warnScopeDroppedStackPairs(projectDir);
|
|
272
290
|
this.log(STATUS_MESSAGES.RECOMPILING_AGENTS);
|
|
273
291
|
try {
|
|
274
292
|
const recompileResult = await compileAgents({
|
|
@@ -339,6 +357,21 @@ function buildCompilePasses(installations, cwd, agentDefs) {
|
|
|
339
357
|
}
|
|
340
358
|
return [];
|
|
341
359
|
}
|
|
360
|
+
function findScopeDroppedStackPairs(config) {
|
|
361
|
+
const stack = config.stack ?? {};
|
|
362
|
+
const globalAgentNames = config.agents.filter((agent) => isActiveAt(agent, "global")).map((agent) => agent.name);
|
|
363
|
+
const projectScopedIds = unique(
|
|
364
|
+
config.skills.filter((skill) => isActiveAt(skill, "project")).map((skill) => skill.id)
|
|
365
|
+
);
|
|
366
|
+
return projectScopedIds.map((skillId) => [
|
|
367
|
+
skillId,
|
|
368
|
+
globalAgentNames.filter((agentName) => stackAssignsSkill(stack[agentName], skillId))
|
|
369
|
+
]).filter(([, agentNames]) => agentNames.length > 0);
|
|
370
|
+
}
|
|
371
|
+
function stackAssignsSkill(agentStack, skillId) {
|
|
372
|
+
if (!agentStack) return false;
|
|
373
|
+
return resolveAgentConfigToSkills(agentStack).some((ref) => ref.id === skillId);
|
|
374
|
+
}
|
|
342
375
|
function formatDiscoveryMessage(result) {
|
|
343
376
|
const { totalSkillCount, pluginSkillCount } = result;
|
|
344
377
|
const localCount = totalSkillCount - pluginSkillCount;
|