@vibe-agent-toolkit/cli 0.1.41-rc.5 → 0.1.41-rc.7
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/README.md +4 -3
- package/dist/bin/vat +1 -1
- package/dist/bin/vat.js +1 -1
- package/dist/bin/vat.js.map +1 -1
- package/dist/bin.js +2 -4
- package/dist/bin.js.map +1 -1
- package/dist/commands/agent/help.d.ts.map +1 -1
- package/dist/commands/agent/help.js +2 -4
- package/dist/commands/agent/help.js.map +1 -1
- package/dist/commands/audit/hierarchical-output.d.ts +6 -2
- package/dist/commands/audit/hierarchical-output.d.ts.map +1 -1
- package/dist/commands/audit/hierarchical-output.js +93 -50
- package/dist/commands/audit/hierarchical-output.js.map +1 -1
- package/dist/commands/audit-settings.d.ts +35 -0
- package/dist/commands/audit-settings.d.ts.map +1 -1
- package/dist/commands/audit-settings.js +121 -51
- package/dist/commands/audit-settings.js.map +1 -1
- package/dist/commands/audit.d.ts +63 -1
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +329 -187
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/build.d.ts.map +1 -1
- package/dist/commands/build.js +47 -18
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/claude/marketplace/license-utils.d.ts +39 -2
- package/dist/commands/claude/marketplace/license-utils.d.ts.map +1 -1
- package/dist/commands/claude/marketplace/license-utils.js +114 -68
- package/dist/commands/claude/marketplace/license-utils.js.map +1 -1
- package/dist/commands/claude/marketplace/publish.js +5 -4
- package/dist/commands/claude/marketplace/publish.js.map +1 -1
- package/dist/commands/claude/marketplace/validate.d.ts.map +1 -1
- package/dist/commands/claude/marketplace/validate.js +13 -19
- package/dist/commands/claude/marketplace/validate.js.map +1 -1
- package/dist/commands/claude/org/skills.d.ts +21 -0
- package/dist/commands/claude/org/skills.d.ts.map +1 -1
- package/dist/commands/claude/org/skills.js +107 -30
- package/dist/commands/claude/org/skills.js.map +1 -1
- package/dist/commands/claude/plugin/build.d.ts +94 -1
- package/dist/commands/claude/plugin/build.d.ts.map +1 -1
- package/dist/commands/claude/plugin/build.js +307 -106
- package/dist/commands/claude/plugin/build.js.map +1 -1
- package/dist/commands/claude/plugin/install.d.ts.map +1 -1
- package/dist/commands/claude/plugin/install.js +7 -2
- package/dist/commands/claude/plugin/install.js.map +1 -1
- package/dist/commands/claude/plugin/marketplace-json.d.ts +36 -0
- package/dist/commands/claude/plugin/marketplace-json.d.ts.map +1 -0
- package/dist/commands/claude/plugin/marketplace-json.js +34 -0
- package/dist/commands/claude/plugin/marketplace-json.js.map +1 -0
- package/dist/commands/claude/plugin/plugin-json-merge.d.ts +30 -1
- package/dist/commands/claude/plugin/plugin-json-merge.d.ts.map +1 -1
- package/dist/commands/claude/plugin/plugin-json-merge.js +92 -14
- package/dist/commands/claude/plugin/plugin-json-merge.js.map +1 -1
- package/dist/commands/claude/plugin/tree-copy.d.ts +10 -3
- package/dist/commands/claude/plugin/tree-copy.d.ts.map +1 -1
- package/dist/commands/claude/plugin/tree-copy.js +0 -1
- package/dist/commands/claude/plugin/tree-copy.js.map +1 -1
- package/dist/commands/claude/plugin/uninstall.d.ts.map +1 -1
- package/dist/commands/claude/plugin/uninstall.js +10 -2
- package/dist/commands/claude/plugin/uninstall.js.map +1 -1
- package/dist/commands/corpus/runner.d.ts.map +1 -1
- package/dist/commands/corpus/runner.js +15 -26
- package/dist/commands/corpus/runner.js.map +1 -1
- package/dist/commands/doctor.d.ts +57 -8
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +142 -67
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/phase-utils.d.ts +62 -2
- package/dist/commands/phase-utils.d.ts.map +1 -1
- package/dist/commands/phase-utils.js +74 -2
- package/dist/commands/phase-utils.js.map +1 -1
- package/dist/commands/rag/help.d.ts.map +1 -1
- package/dist/commands/rag/help.js +2 -4
- package/dist/commands/rag/help.js.map +1 -1
- package/dist/commands/resources/help.d.ts.map +1 -1
- package/dist/commands/resources/help.js +2 -4
- package/dist/commands/resources/help.js.map +1 -1
- package/dist/commands/resources/index.d.ts.map +1 -1
- package/dist/commands/resources/index.js +13 -6
- package/dist/commands/resources/index.js.map +1 -1
- package/dist/commands/resources/validate.d.ts +19 -0
- package/dist/commands/resources/validate.d.ts.map +1 -1
- package/dist/commands/resources/validate.js +89 -24
- package/dist/commands/resources/validate.js.map +1 -1
- package/dist/commands/skill/review.d.ts.map +1 -1
- package/dist/commands/skill/review.js +33 -20
- package/dist/commands/skill/review.js.map +1 -1
- package/dist/commands/skill/test/configure.d.ts.map +1 -1
- package/dist/commands/skill/test/configure.js +1 -1
- package/dist/commands/skill/test/configure.js.map +1 -1
- package/dist/commands/skill/test/run.d.ts +29 -2
- package/dist/commands/skill/test/run.d.ts.map +1 -1
- package/dist/commands/skill/test/run.js +67 -19
- package/dist/commands/skill/test/run.js.map +1 -1
- package/dist/commands/skills/build.d.ts +51 -0
- package/dist/commands/skills/build.d.ts.map +1 -1
- package/dist/commands/skills/build.js +94 -86
- package/dist/commands/skills/build.js.map +1 -1
- package/dist/commands/skills/install.d.ts.map +1 -1
- package/dist/commands/skills/install.js +79 -25
- package/dist/commands/skills/install.js.map +1 -1
- package/dist/commands/skills/list.d.ts.map +1 -1
- package/dist/commands/skills/list.js +9 -5
- package/dist/commands/skills/list.js.map +1 -1
- package/dist/commands/skills/package.d.ts +2 -0
- package/dist/commands/skills/package.d.ts.map +1 -1
- package/dist/commands/skills/package.js +61 -42
- package/dist/commands/skills/package.js.map +1 -1
- package/dist/commands/skills/skill-discovery.d.ts +7 -0
- package/dist/commands/skills/skill-discovery.d.ts.map +1 -1
- package/dist/commands/skills/skill-discovery.js +14 -4
- package/dist/commands/skills/skill-discovery.js.map +1 -1
- package/dist/commands/skills/validate.d.ts +38 -0
- package/dist/commands/skills/validate.d.ts.map +1 -1
- package/dist/commands/skills/validate.js +125 -70
- package/dist/commands/skills/validate.js.map +1 -1
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +11 -5
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +76 -28
- package/dist/commands/verify.js.map +1 -1
- package/dist/skill-resolution/classify.d.ts +7 -2
- package/dist/skill-resolution/classify.d.ts.map +1 -1
- package/dist/skill-resolution/classify.js +7 -2
- package/dist/skill-resolution/classify.js.map +1 -1
- package/dist/skill-resolution/resolve-skill-reference.d.ts +10 -8
- package/dist/skill-resolution/resolve-skill-reference.d.ts.map +1 -1
- package/dist/skill-resolution/resolve-skill-reference.js +62 -23
- package/dist/skill-resolution/resolve-skill-reference.js.map +1 -1
- package/dist/skill-resolution/types.d.ts +3 -2
- package/dist/skill-resolution/types.d.ts.map +1 -1
- package/dist/utils/config-loader.d.ts.map +1 -1
- package/dist/utils/config-loader.js +0 -2
- package/dist/utils/config-loader.js.map +1 -1
- package/dist/utils/help-loader.d.ts +16 -0
- package/dist/utils/help-loader.d.ts.map +1 -1
- package/dist/utils/help-loader.js +31 -1
- package/dist/utils/help-loader.js.map +1 -1
- package/dist/utils/issue-anchor.d.ts +26 -0
- package/dist/utils/issue-anchor.d.ts.map +1 -0
- package/dist/utils/issue-anchor.js +39 -0
- package/dist/utils/issue-anchor.js.map +1 -0
- package/dist/utils/issue-rendering.d.ts +61 -0
- package/dist/utils/issue-rendering.d.ts.map +1 -0
- package/dist/utils/issue-rendering.js +135 -0
- package/dist/utils/issue-rendering.js.map +1 -0
- package/dist/utils/output.d.ts +26 -4
- package/dist/utils/output.d.ts.map +1 -1
- package/dist/utils/output.js +27 -6
- package/dist/utils/output.js.map +1 -1
- package/dist/utils/project-root-policy.d.ts +2 -2
- package/dist/utils/project-root-policy.js +2 -2
- package/dist/utils/skill-packaging-config.d.ts +15 -6
- package/dist/utils/skill-packaging-config.d.ts.map +1 -1
- package/dist/utils/skill-packaging-config.js +23 -5
- package/dist/utils/skill-packaging-config.js.map +1 -1
- package/dist/utils/validate-help-files.d.ts +3 -2
- package/dist/utils/validate-help-files.d.ts.map +1 -1
- package/dist/utils/validate-help-files.js +48 -5
- package/dist/utils/validate-help-files.js.map +1 -1
- package/dist/utils/verdict-helpers.d.ts +10 -2
- package/dist/utils/verdict-helpers.d.ts.map +1 -1
- package/dist/utils/verdict-helpers.js +13 -3
- package/dist/utils/verdict-helpers.js.map +1 -1
- package/docs/audit.md +40 -14
- package/docs/doctor.md +46 -10
- package/docs/index.md +1 -1
- package/docs/resources.md +24 -8
- package/docs/skill-test.md +47 -3
- package/docs/skills.md +28 -6
- package/package.json +12 -12
|
@@ -8,14 +8,20 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { cpSync, existsSync, readFileSync } from 'node:fs';
|
|
10
10
|
import { mkdir, readdir, rm, writeFile } from 'node:fs/promises';
|
|
11
|
-
import {
|
|
11
|
+
import { basename } from 'node:path';
|
|
12
|
+
import { countBySeverity } from '@vibe-agent-toolkit/agent-schema';
|
|
13
|
+
import { createProjectRegistry, getPluginOutputDir, getPluginSourceDir, listPluginSourceSkillDirs, listUntrackedPluginSkillDirs, packageSkill, packagingConfigToPackageOptions, skillNameToFsPath } from '@vibe-agent-toolkit/agent-skills';
|
|
12
14
|
import { safePath, toForwardSlash } from '@vibe-agent-toolkit/utils';
|
|
13
15
|
import { Command } from 'commander';
|
|
16
|
+
import { readSkillName } from '../../../commands/skills/skill-discovery.js';
|
|
14
17
|
import { handleCommandError } from '../../../utils/command-error.js';
|
|
15
18
|
import { loadConfig } from '../../../utils/config-loader.js';
|
|
19
|
+
import { collectPostBuildIssues, formatIssueLines, formatIssueSetHeading, sumSeverityCounts, } from '../../../utils/issue-rendering.js';
|
|
16
20
|
import { createLogger } from '../../../utils/logger.js';
|
|
17
21
|
import { writeYamlOutput } from '../../../utils/output.js';
|
|
22
|
+
import { mergeSkillPackagingConfig } from '../../../utils/skill-packaging-config.js';
|
|
18
23
|
import { loadClaudeProjectConfig } from '../claude-config.js';
|
|
24
|
+
import { buildMarketplaceJson } from './marketplace-json.js';
|
|
19
25
|
import { resolvePluginChangelogPath } from './plugin-changelog.js';
|
|
20
26
|
import { applyPluginFiles } from './plugin-files.js';
|
|
21
27
|
import { mergePluginJson, resolveVersion } from './plugin-json-merge.js';
|
|
@@ -36,7 +42,10 @@ Description:
|
|
|
36
42
|
plugin's skills: selector.
|
|
37
43
|
|
|
38
44
|
For each marketplace, for each plugin:
|
|
39
|
-
- Tree-copies plugins/<name>/ (commands, hooks, agents,
|
|
45
|
+
- Tree-copies plugins/<name>/ non-skill content (commands, hooks, agents, .mcp.json)
|
|
46
|
+
- Packages each plugin-local skill (plugins/<name>/skills/*) with the same
|
|
47
|
+
packager used for pool skills — links rewritten, files: applied, declared
|
|
48
|
+
test input excluded. Skills are never copied verbatim.
|
|
40
49
|
- Imports pool skills (dist/skills/) via the plugin's skills: selector
|
|
41
50
|
- Applies explicit files: source→dest mappings for compiled artifacts
|
|
42
51
|
- Merges plugin.json with author, description, and VAT-supplied metadata
|
|
@@ -114,15 +123,21 @@ export async function runClaudePluginBuild(configDir, options = {}) {
|
|
|
114
123
|
}
|
|
115
124
|
// Discover available skills from dist/skills/ for pool-to-plugin selectors
|
|
116
125
|
const availableSkills = await discoverBuiltSkills(configDir);
|
|
117
|
-
// Load the project's skills config (defaults + per-skill) so
|
|
118
|
-
//
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
// would be missing from the shipped plugin tree. Undefined when no config.
|
|
126
|
+
// Load the project's skills config (defaults + per-skill) so each plugin-local
|
|
127
|
+
// skill is PACKAGED with its own effective packaging config — the same config
|
|
128
|
+
// `vat skills build` would use for it. Undefined when no config, in which case
|
|
129
|
+
// plugin-local skills package with schema defaults.
|
|
122
130
|
const skillsConfig = projectConfig?.skills;
|
|
123
131
|
logger.info(`Building Claude plugin artifacts`);
|
|
124
132
|
logger.info(` Config: ${safePath.join(configDir, 'vibe-agent-toolkit.config.yaml')}`);
|
|
125
133
|
logger.info(` Skills available: ${availableSkills.length}`);
|
|
134
|
+
// THE registry for this build: one crawl+parse of the project's markdown,
|
|
135
|
+
// shared by every plugin-local skill in every marketplace. `packageSkill`
|
|
136
|
+
// builds this itself when it is not given one, so omitting it does not fail —
|
|
137
|
+
// it just re-reads the whole project once per skill, which is how a 46-skill
|
|
138
|
+
// build came to take longer than a 30-minute CI budget.
|
|
139
|
+
const sharedRegistry = await createProjectRegistry(configDir);
|
|
140
|
+
logger.debug(`Project registry: ${sharedRegistry.getAllResources().length} markdown resources (built once)`);
|
|
126
141
|
const results = [];
|
|
127
142
|
const allPluginNames = [];
|
|
128
143
|
for (const mp of Object.values(marketplaces)) {
|
|
@@ -137,7 +152,16 @@ export async function runClaudePluginBuild(configDir, options = {}) {
|
|
|
137
152
|
}
|
|
138
153
|
const mpConfig = marketplaces[name];
|
|
139
154
|
logger.info(`\n Building marketplace: ${name}`);
|
|
140
|
-
const result = await buildMarketplace(
|
|
155
|
+
const result = await buildMarketplace({
|
|
156
|
+
name,
|
|
157
|
+
config: mpConfig,
|
|
158
|
+
availableSkills,
|
|
159
|
+
configDir,
|
|
160
|
+
skillsConfig,
|
|
161
|
+
rootVersion,
|
|
162
|
+
registry: sharedRegistry,
|
|
163
|
+
logger,
|
|
164
|
+
});
|
|
141
165
|
results.push(result);
|
|
142
166
|
if (result.status === 'error') {
|
|
143
167
|
throw new Error(`Claude plugin build failed for marketplace '${name}': ${result.reason ?? 'unknown error'}`);
|
|
@@ -165,8 +189,12 @@ async function pluginBuildCommand(options) {
|
|
|
165
189
|
const duration = Date.now() - startTime;
|
|
166
190
|
const totalPlugins = results.flatMap((r) => r.plugins).length;
|
|
167
191
|
const totalSkills = results.flatMap((r) => r.plugins).flatMap((p) => p.skillsCopied).length;
|
|
192
|
+
const allPlugins = results.flatMap((r) => r.plugins);
|
|
168
193
|
writeYamlOutput({
|
|
169
194
|
status: 'success',
|
|
195
|
+
// The build gate is two-valued and a warning does not fail it, so the
|
|
196
|
+
// distribution has to travel next to the status rather than inside it.
|
|
197
|
+
issueCounts: sumSeverityCounts(allPlugins.map((p) => p.localSkillIssueCounts)),
|
|
170
198
|
marketplacesBuilt: results.filter((r) => r.status === 'built').length,
|
|
171
199
|
pluginsBuilt: totalPlugins,
|
|
172
200
|
skillsPackaged: totalSkills,
|
|
@@ -184,7 +212,8 @@ async function pluginBuildCommand(options) {
|
|
|
184
212
|
mcpCopied: p.mcpCopied,
|
|
185
213
|
treeFilesCopied: p.treeFilesCopied,
|
|
186
214
|
explicitFilesCopied: p.explicitFilesCopied,
|
|
187
|
-
|
|
215
|
+
localSkillsPackaged: p.localSkillsPackaged,
|
|
216
|
+
issueCounts: p.localSkillIssueCounts,
|
|
188
217
|
})),
|
|
189
218
|
})),
|
|
190
219
|
duration: `${duration}ms`,
|
|
@@ -219,7 +248,8 @@ async function copyDistributionFiles(marketplaceDir, configDir, config, logger)
|
|
|
219
248
|
}
|
|
220
249
|
}
|
|
221
250
|
}
|
|
222
|
-
async function buildMarketplace(
|
|
251
|
+
async function buildMarketplace(input) {
|
|
252
|
+
const { name, config, availableSkills, configDir, skillsConfig, rootVersion, registry, logger } = input;
|
|
223
253
|
const plugins = [];
|
|
224
254
|
// Clean stale marketplace directory before rebuilding — removes orphaned plugins
|
|
225
255
|
const marketplaceBaseDir = safePath.join(configDir, 'dist', '.claude', 'plugins', 'marketplaces', name);
|
|
@@ -238,6 +268,7 @@ async function buildMarketplace(name, config, availableSkills, configDir, skills
|
|
|
238
268
|
skillsConfig,
|
|
239
269
|
owner: config.owner,
|
|
240
270
|
rootVersion,
|
|
271
|
+
registry,
|
|
241
272
|
logger,
|
|
242
273
|
});
|
|
243
274
|
plugins.push(pluginResult);
|
|
@@ -247,27 +278,18 @@ async function buildMarketplace(name, config, availableSkills, configDir, skills
|
|
|
247
278
|
const claudePluginDir = safePath.join(marketplaceDir, CLAUDE_PLUGIN_DIRNAME);
|
|
248
279
|
// eslint-disable-next-line security/detect-non-literal-fs-filename -- resolved paths
|
|
249
280
|
await mkdir(claudePluginDir, { recursive: true });
|
|
250
|
-
|
|
251
|
-
|
|
281
|
+
// Each entry's author is the plugin's own MERGED author (see marketplace-json.ts),
|
|
282
|
+
// so marketplace.json and that plugin's plugin.json cannot disagree.
|
|
283
|
+
const marketplaceJson = buildMarketplaceJson({
|
|
252
284
|
name,
|
|
253
|
-
owner:
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
...(pluginDesc ? { description: pluginDesc } : {}),
|
|
262
|
-
source: `./plugins/${p.pluginName}`,
|
|
263
|
-
...(p.pluginVersion ? { version: p.pluginVersion } : {}),
|
|
264
|
-
author: {
|
|
265
|
-
name: config.owner.name,
|
|
266
|
-
...(config.owner.email ? { email: config.owner.email } : {}),
|
|
267
|
-
},
|
|
268
|
-
};
|
|
269
|
-
}),
|
|
270
|
-
};
|
|
285
|
+
owner: config.owner,
|
|
286
|
+
plugins: plugins.map((p) => ({
|
|
287
|
+
name: p.pluginName,
|
|
288
|
+
description: config.plugins.find((pd) => pd.name === p.pluginName)?.description,
|
|
289
|
+
version: p.pluginVersion,
|
|
290
|
+
author: p.pluginAuthor,
|
|
291
|
+
})),
|
|
292
|
+
});
|
|
271
293
|
// eslint-disable-next-line security/detect-non-literal-fs-filename -- resolved paths
|
|
272
294
|
await writeFile(safePath.join(claudePluginDir, 'marketplace.json'), JSON.stringify(marketplaceJson, null, 2));
|
|
273
295
|
logger.info(` .claude-plugin/marketplace.json`);
|
|
@@ -350,7 +372,7 @@ async function writeMergedPluginJson(pluginDef, authorJson, pluginVersion, plugi
|
|
|
350
372
|
const pluginJsonDir = safePath.join(pluginDir, CLAUDE_PLUGIN_DIRNAME);
|
|
351
373
|
// eslint-disable-next-line security/detect-non-literal-fs-filename -- resolved paths
|
|
352
374
|
await mkdir(pluginJsonDir, { recursive: true });
|
|
353
|
-
const { merged, warnings } = mergePluginJson({
|
|
375
|
+
const { merged, author, warnings } = mergePluginJson({
|
|
354
376
|
vat: {
|
|
355
377
|
name: pluginDef.name,
|
|
356
378
|
version: pluginVersion,
|
|
@@ -364,12 +386,24 @@ async function writeMergedPluginJson(pluginDef, authorJson, pluginVersion, plugi
|
|
|
364
386
|
// eslint-disable-next-line security/detect-non-literal-fs-filename -- resolved paths
|
|
365
387
|
await writeFile(safePath.join(pluginJsonDir, 'plugin.json'), JSON.stringify(merged, null, 2));
|
|
366
388
|
logger.info(` .claude-plugin/plugin.json`);
|
|
389
|
+
return author;
|
|
367
390
|
}
|
|
368
391
|
/**
|
|
369
392
|
* Copy pool skills (from dist/skills/) selected by the plugin's skills: selector
|
|
370
393
|
* into the plugin bundle's skills/ directory.
|
|
394
|
+
*
|
|
395
|
+
* `destOverrides` maps a selected skill's NAME to the `skills/`-relative directory
|
|
396
|
+
* it must land in, and carries the collision referee's decision (see
|
|
397
|
+
* {@link resolveCollidingSkills}): when the pool copy wins over a plugin-local copy,
|
|
398
|
+
* it takes over the plugin-local skill's own authored directory path rather than the
|
|
399
|
+
* default `skills/<fsName>`. That keeps ONE invariant true for every plugin-local
|
|
400
|
+
* skill, refereed or not — it ships at the path it was authored at, which is exactly
|
|
401
|
+
* what `DistributedSkillLocation.skillOutputDir` promises every consumer of the
|
|
402
|
+
* layout module. Without it a NESTED collision (`skills/group/foo` losing to pool
|
|
403
|
+
* `foo`) landed at `skills/foo`, and `vat skill test foo` then hard-failed looking for
|
|
404
|
+
* a dist at `skills/group/foo` that the build never wrote.
|
|
371
405
|
*/
|
|
372
|
-
async function copyPoolSkills(pluginDef, marketplaceAvailable, configDir, pluginDir, logger) {
|
|
406
|
+
async function copyPoolSkills(pluginDef, marketplaceAvailable, configDir, pluginDir, destOverrides, logger) {
|
|
373
407
|
const selected = resolvePluginSkills(pluginDef, marketplaceAvailable);
|
|
374
408
|
const copied = [];
|
|
375
409
|
for (const skillName of selected) {
|
|
@@ -379,7 +413,7 @@ async function copyPoolSkills(pluginDef, marketplaceAvailable, configDir, plugin
|
|
|
379
413
|
throw new Error(`Skill "${skillName}" not built at ${skillDistPath}. ` +
|
|
380
414
|
`Run: vat skills build (or vat build to build everything)`);
|
|
381
415
|
}
|
|
382
|
-
const fsPath = skillNameToFsPath(skillName);
|
|
416
|
+
const fsPath = destOverrides.get(skillName) ?? skillNameToFsPath(skillName);
|
|
383
417
|
const destPath = safePath.join(pluginDir, 'skills', fsPath);
|
|
384
418
|
// eslint-disable-next-line security/detect-non-literal-fs-filename -- resolved paths
|
|
385
419
|
await mkdir(destPath, { recursive: true });
|
|
@@ -390,56 +424,178 @@ async function copyPoolSkills(pluginDef, marketplaceAvailable, configDir, plugin
|
|
|
390
424
|
return copied;
|
|
391
425
|
}
|
|
392
426
|
/**
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
*
|
|
397
|
-
*
|
|
398
|
-
*
|
|
399
|
-
*
|
|
427
|
+
* Discover the plugin's own skills ONCE, resolving each one's declared name.
|
|
428
|
+
*
|
|
429
|
+
* Every later phase — the collision referee, the packager, and the tree-copy's
|
|
430
|
+
* exclusion list — reads this one list, so "which directories under `skills/` are
|
|
431
|
+
* skills" has exactly one answer per build. Two independent listings is the shape
|
|
432
|
+
* that previously let a directory be excluded by one phase and skipped by the
|
|
433
|
+
* other, shipping NOWHERE with no diagnostic.
|
|
434
|
+
*
|
|
435
|
+
* {@link listPluginSourceSkillDirs} supplies the directories: recursive (a nested
|
|
436
|
+
* `skills/<group>/<skill>/SKILL.md` is a skill Claude Code loads, so VAT packages
|
|
437
|
+
* it) and filtered to the same git-visible file set the tree-copy sees (a
|
|
438
|
+
* gitignored/untracked skill dir must not be published by one producer when the
|
|
439
|
+
* other would never have shipped it).
|
|
400
440
|
*/
|
|
401
|
-
async function
|
|
402
|
-
//
|
|
403
|
-
//
|
|
404
|
-
//
|
|
405
|
-
|
|
406
|
-
for (const
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
441
|
+
async function discoverPluginLocalSkills(pluginSourceDir, logger) {
|
|
442
|
+
// Git visibility is the right filter, but a SILENT drop is not: a skill the author
|
|
443
|
+
// just created and has not `git add`ed is simply absent from the built plugin, and
|
|
444
|
+
// a build that says "success" while omitting it reads as one that shipped it.
|
|
445
|
+
// Gitignored dirs are excluded from this list — ignoring one IS the instruction.
|
|
446
|
+
for (const dir of listUntrackedPluginSkillDirs(pluginSourceDir)) {
|
|
447
|
+
logger.info(`warning: skills/${dir}/SKILL.md exists but is not tracked by git, so it was NOT packaged ` +
|
|
448
|
+
`into this plugin (the plugin build ships tracked files only). Run \`git add\` on it, or ` +
|
|
449
|
+
`add it to .gitignore to silence this.`);
|
|
450
|
+
}
|
|
451
|
+
const skills = [];
|
|
452
|
+
for (const skillDirPath of listPluginSourceSkillDirs(pluginSourceDir)) {
|
|
453
|
+
const skillPath = safePath.join(pluginSourceDir, 'skills', skillDirPath, 'SKILL.md');
|
|
454
|
+
// Resolved through the SAME reader `vat skills build` uses — per-skill config is
|
|
455
|
+
// keyed by name, so two answers would mean two effective configs.
|
|
456
|
+
const skillName = await readSkillName(skillPath) ?? lastPathSegment(skillDirPath);
|
|
457
|
+
skills.push({ skillDirPath, skillPath, skillName });
|
|
458
|
+
}
|
|
459
|
+
return skills;
|
|
460
|
+
}
|
|
461
|
+
/** Trailing segment of a skill dir path (`group/nested` → `nested`). */
|
|
462
|
+
function lastPathSegment(dirPath) {
|
|
463
|
+
return basename(dirPath);
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* PACKAGE each plugin-local skill (a skill living in the plugin's own `skills/`
|
|
467
|
+
* source tree) with the SAME packager that produces pool skills.
|
|
468
|
+
*
|
|
469
|
+
* This is the "one production path" rule. A plugin-local skill used to be
|
|
470
|
+
* tree-copied VERBATIM — every byte in its source directory shipped, links were
|
|
471
|
+
* never rewritten, and `files:` had to be re-applied separately because the
|
|
472
|
+
* packager never ran. That produced a materially different artifact from the
|
|
473
|
+
* pool path for the same kind of thing, and the difference was invisible: it
|
|
474
|
+
* shipped eval suites (answer keys included), scratch files, and un-rewritten
|
|
475
|
+
* links. The collision referee already conceded the point by preferring the
|
|
476
|
+
* pool copy whenever both existed.
|
|
477
|
+
*
|
|
478
|
+
* Now both paths run `packageSkill`, so "what ships in a skill" has exactly one
|
|
479
|
+
* answer: link-reachable resources plus declared `files:`, links rewritten,
|
|
480
|
+
* declared test input excluded, post-build checks applied.
|
|
481
|
+
*
|
|
482
|
+
* `input.skills` is the already-refereed set: pool-sourced collisions have been
|
|
483
|
+
* filtered out by {@link resolveCollidingSkills} and are copied in by Phase 3
|
|
484
|
+
* instead. Returns each packaged skill's result for error reporting.
|
|
485
|
+
*
|
|
486
|
+
* The returned list is also the ONLY definition of "which dirs under `skills/` did
|
|
487
|
+
* the packager produce": the tree-copy exclusion list is derived from it (see
|
|
488
|
+
* Phase 2b in {@link buildPlugin}), so a directory absent from it is a directory
|
|
489
|
+
* the tree-copy still ships.
|
|
490
|
+
*/
|
|
491
|
+
export async function packagePluginLocalSkills(input) {
|
|
492
|
+
const packaged = [];
|
|
493
|
+
for (const { skillDirPath, skillPath, skillName } of input.skills) {
|
|
494
|
+
// Per-skill config is keyed by the skill's declared NAME; the directory path and
|
|
495
|
+
// its trailing segment are fallbacks for the common cases where they coincide.
|
|
496
|
+
// The fallback LIST must stay a superset of `vat verify`'s (checkFilesConfigDests
|
|
497
|
+
// cannot read declared names, so it tries path-then-leaf): if verify resolved a
|
|
498
|
+
// key the build did not, verify would check `files:` dests for a skill the build
|
|
499
|
+
// was never told to copy them into, and fail a build that had in fact succeeded.
|
|
500
|
+
const packagingConfig = mergeSkillPackagingConfig(input.skillsConfig?.defaults, input.skillsConfig?.config?.[skillName] ??
|
|
501
|
+
input.skillsConfig?.config?.[skillDirPath] ??
|
|
502
|
+
input.skillsConfig?.config?.[lastPathSegment(skillDirPath)]);
|
|
503
|
+
const skillOutputDir = safePath.join(input.pluginDir, 'skills', skillDirPath);
|
|
504
|
+
const result = await packageSkill(skillPath, {
|
|
505
|
+
...packagingConfigToPackageOptions(packagingConfig, { skillPath, outputPath: skillOutputDir }),
|
|
506
|
+
registry: input.registry,
|
|
422
507
|
});
|
|
423
|
-
|
|
424
|
-
|
|
508
|
+
input.logger.info(` ${skillName} -> skills/${skillDirPath} (${result.files.dependencies.length + 1} files)`);
|
|
509
|
+
packaged.push({ skillDirPath, result });
|
|
510
|
+
}
|
|
511
|
+
return packaged;
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Summarize post-build issues for the plugin-local skills: the lines to print,
|
|
515
|
+
* the dirs that emitted errors, and the per-severity distribution.
|
|
516
|
+
*
|
|
517
|
+
* Mirrors `vat skills build`: a skill whose packaged output fails validation
|
|
518
|
+
* fails the build, so the two lanes hold the same bar, and they now render
|
|
519
|
+
* findings through the same helper — this lane used to label every non-error
|
|
520
|
+
* severity `[WARNING]`, so `info` findings were reported as warnings, and it
|
|
521
|
+
* read only `postBuildIssues`, so a skill failing purely on the built-output
|
|
522
|
+
* validation aborted the plugin build with no issue text at all.
|
|
523
|
+
*
|
|
524
|
+
* Pure so the whole rendered set is assertable.
|
|
525
|
+
*/
|
|
526
|
+
export function summarizePackagedSkillIssues(packaged) {
|
|
527
|
+
const lines = [];
|
|
528
|
+
const withErrors = [];
|
|
529
|
+
const perSkillCounts = [];
|
|
530
|
+
for (const { skillDirPath, result } of packaged) {
|
|
531
|
+
const issues = collectPostBuildIssues(result);
|
|
532
|
+
perSkillCounts.push(countBySeverity(issues));
|
|
533
|
+
if (issues.length > 0) {
|
|
534
|
+
lines.push(` ${skillDirPath}: ${formatIssueSetHeading(issues, 'post-build')}`);
|
|
535
|
+
for (const issue of issues) {
|
|
536
|
+
lines.push(...formatIssueLines(issue, ' '));
|
|
537
|
+
}
|
|
425
538
|
}
|
|
426
|
-
|
|
539
|
+
if (result.hasErrors)
|
|
540
|
+
withErrors.push(skillDirPath);
|
|
427
541
|
}
|
|
428
|
-
return
|
|
542
|
+
return { lines, withErrors, issueCounts: sumSeverityCounts(perSkillCounts) };
|
|
543
|
+
}
|
|
544
|
+
/** Print the summary to stderr and return what the caller gates on. */
|
|
545
|
+
function reportPackagedSkillIssues(packaged, logger) {
|
|
546
|
+
const { lines, withErrors, issueCounts } = summarizePackagedSkillIssues(packaged);
|
|
547
|
+
for (const line of lines) {
|
|
548
|
+
logger.info(line);
|
|
549
|
+
}
|
|
550
|
+
return { withErrors, issueCounts };
|
|
429
551
|
}
|
|
430
552
|
/**
|
|
431
|
-
*
|
|
432
|
-
*
|
|
433
|
-
*
|
|
434
|
-
*
|
|
435
|
-
*
|
|
553
|
+
* Split the plugin's own skills into those that COLLIDE with its resolved pool
|
|
554
|
+
* selector and those that do not. A colliding skill would otherwise be produced
|
|
555
|
+
* twice — once by the local packager, once by the Phase 3 pool copy-in — putting
|
|
556
|
+
* two definitions of the same skill in one plugin.
|
|
557
|
+
*
|
|
558
|
+
* Matched on the DECLARED NAME, and ONLY the declared name. Name is what makes two
|
|
559
|
+
* copies the same skill: a skill named `foo` authored in `skills/bar/` collides
|
|
560
|
+
* with pool `foo` just as surely as one in `skills/foo/`, and a NESTED skill
|
|
561
|
+
* (`skills/group/foo/`) collides too even though its directory path shares no
|
|
562
|
+
* segment with the pool copy's `skills/foo/`. A dirname-only comparison missed all
|
|
563
|
+
* of those, and the nested case shipped the skill twice, at two depths, in one plugin.
|
|
564
|
+
*
|
|
565
|
+
* The directory leaf is deliberately NOT also matched. It adds nothing (when a
|
|
566
|
+
* skill's `SKILL.md` declares no name, {@link discoverPluginLocalSkills} already
|
|
567
|
+
* falls back to that leaf, so the name comparison covers it) and it over-matches:
|
|
568
|
+
* a plugin-local skill named `bar` living in `skills/foo/`, in a plugin that selects
|
|
569
|
+
* an unrelated pool skill `foo`, was refereed away as if it were the pool's `foo` —
|
|
570
|
+
* so `bar` was neither packaged nor tree-copied and shipped NOWHERE, under a warning
|
|
571
|
+
* claiming a skill named `bar` had been "selected from the pool".
|
|
572
|
+
*
|
|
573
|
+
* `conflicts` is the residue that name-matching alone cannot resolve: a
|
|
574
|
+
* non-colliding plugin-local skill whose authored directory is the same directory a
|
|
575
|
+
* selected pool skill copies into. Two DIFFERENT skills, one output dir — the
|
|
576
|
+
* packager and the Phase 3 copy would write over each other. There is no correct
|
|
577
|
+
* winner, so the caller fails the build instead of silently picking one.
|
|
436
578
|
*/
|
|
437
|
-
function
|
|
579
|
+
function resolveCollidingSkills(skills, selectedSkillNames) {
|
|
438
580
|
const selectedFsNames = new Set(selectedSkillNames.map((name) => skillNameToFsPath(name)));
|
|
439
|
-
|
|
581
|
+
const colliding = [];
|
|
582
|
+
const packageable = [];
|
|
583
|
+
const conflicts = [];
|
|
584
|
+
for (const skill of skills) {
|
|
585
|
+
if (selectedFsNames.has(skillNameToFsPath(skill.skillName))) {
|
|
586
|
+
colliding.push(skill);
|
|
587
|
+
continue;
|
|
588
|
+
}
|
|
589
|
+
packageable.push(skill);
|
|
590
|
+
const clash = [...selectedFsNames].find((fsName) => toForwardSlash(skill.skillDirPath) === fsName ||
|
|
591
|
+
toForwardSlash(skill.skillDirPath).startsWith(`${toForwardSlash(fsName)}/`));
|
|
592
|
+
if (clash !== undefined)
|
|
593
|
+
conflicts.push({ skill, poolSkillFsPath: clash });
|
|
594
|
+
}
|
|
595
|
+
return { colliding, packageable, conflicts };
|
|
440
596
|
}
|
|
441
597
|
async function buildPlugin(input) {
|
|
442
|
-
const { marketplaceName, pluginDef, marketplaceAvailable, configDir, skillsConfig, owner, rootVersion, logger } = input;
|
|
598
|
+
const { marketplaceName, pluginDef, marketplaceAvailable, configDir, skillsConfig, owner, rootVersion, registry, logger } = input;
|
|
443
599
|
const pluginDir = getPluginOutputDir(configDir, marketplaceName, pluginDef.name);
|
|
444
600
|
const pluginSourceDir = getPluginSourceDir(configDir, pluginDef);
|
|
445
601
|
logger.info(` Building plugin: ${pluginDef.name}`);
|
|
@@ -463,47 +619,90 @@ async function buildPlugin(input) {
|
|
|
463
619
|
}
|
|
464
620
|
// eslint-disable-next-line security/detect-non-literal-fs-filename -- resolved paths
|
|
465
621
|
await mkdir(pluginDir, { recursive: true });
|
|
466
|
-
// Phase 1.
|
|
467
|
-
//
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
// copies coexist at two depths inside the same skills/<name>/ dir and the
|
|
471
|
-
// raw copy ships un-rewritten (dead) links.
|
|
472
|
-
const selectedSkillNames = resolvePluginSkills(pluginDef, marketplaceAvailable);
|
|
473
|
-
const collidingSkillDirs = pluginSourceExists
|
|
474
|
-
? resolveCollidingSkillDirs(pluginSourceDir, selectedSkillNames)
|
|
622
|
+
// Phase 1.4: discover the plugin's own skills ONCE (recursive; git-visible only),
|
|
623
|
+
// resolving each declared name. Every phase below reads this list.
|
|
624
|
+
const localSkills = pluginSourceExists
|
|
625
|
+
? await discoverPluginLocalSkills(pluginSourceDir, logger)
|
|
475
626
|
: [];
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
627
|
+
// Phase 1.5: collision referee. Resolve the plugin's pool selector BEFORE the
|
|
628
|
+
// tree-copy so a skill present in BOTH the plugin's own skills/ tree AND the
|
|
629
|
+
// resolved pool selector is sourced from exactly one place. Both copies are now
|
|
630
|
+
// packager output, so the referee is no longer about "raw copy ships dead links"
|
|
631
|
+
// — it is about not producing the same skill twice, at two depths, in one dir.
|
|
632
|
+
const selectedSkillNames = resolvePluginSkills(pluginDef, marketplaceAvailable);
|
|
633
|
+
const { colliding: collidingSkills, packageable, conflicts } = resolveCollidingSkills(localSkills, selectedSkillNames);
|
|
634
|
+
if (conflicts.length > 0) {
|
|
635
|
+
const pluginSourceRel = toForwardSlash(safePath.relative(configDir, pluginSourceDir));
|
|
636
|
+
throw new Error(`Plugin '${pluginDef.name}': two DIFFERENT skills claim the same output directory.\n` +
|
|
637
|
+
conflicts
|
|
638
|
+
.map(({ skill, poolSkillFsPath }) => ` - skills/${skill.skillDirPath} holds the plugin-local skill "${skill.skillName}", ` +
|
|
639
|
+
`but the plugin's skills: selector also copies a pool skill into skills/${poolSkillFsPath}.`)
|
|
640
|
+
.join('\n') +
|
|
641
|
+
`\nRename the plugin-local directory under ${pluginSourceRel}/skills/, or drop the pool skill ` +
|
|
642
|
+
`from this plugin's skills: selector. (Only a same-NAME collision has a winner — the pool copy; ` +
|
|
643
|
+
`two different skills sharing one directory does not.)`);
|
|
644
|
+
}
|
|
645
|
+
// The pool copy takes over the plugin-local skill's OWN authored directory (see
|
|
646
|
+
// copyPoolSkills) so "a plugin-local skill ships at its authored path" holds
|
|
647
|
+
// whether it was packaged locally or refereed to the pool.
|
|
648
|
+
const poolDestOverrides = new Map(collidingSkills.map(({ skillName, skillDirPath }) => [skillName, skillDirPath]));
|
|
649
|
+
for (const { skillName, skillDirPath } of collidingSkills) {
|
|
650
|
+
logger.info(`warning: skill "${skillName}" is selected from the pool AND present at ` +
|
|
651
|
+
`${toForwardSlash(safePath.relative(configDir, pluginSourceDir))}/skills/${skillDirPath}/ — ` +
|
|
652
|
+
`using the pool-packaged copy (dist/skills/${skillNameToFsPath(skillName)}) and not packaging ` +
|
|
653
|
+
`the plugin-local copy. It ships at skills/${skillDirPath}, the path it was authored at.`);
|
|
654
|
+
}
|
|
655
|
+
// Phase 2a: PACKAGE each non-colliding plugin-local skill with the same packager
|
|
656
|
+
// that produces pool skills — one production path for skills (see
|
|
657
|
+
// packagePluginLocalSkills). This subsumes the old separate files: application:
|
|
658
|
+
// the packager owns files: semantics, so no lane re-implements them. Runs BEFORE
|
|
659
|
+
// the tree-copy so the tree-copy's exclusion list can be derived from what this
|
|
660
|
+
// actually produced.
|
|
661
|
+
const packagedLocalSkills = await packagePluginLocalSkills({
|
|
662
|
+
skills: packageable,
|
|
663
|
+
pluginDir,
|
|
664
|
+
skillsConfig,
|
|
665
|
+
registry,
|
|
666
|
+
logger,
|
|
667
|
+
});
|
|
668
|
+
const { withErrors: skillsWithErrors, issueCounts: localSkillIssueCounts } = reportPackagedSkillIssues(packagedLocalSkills, logger);
|
|
669
|
+
if (skillsWithErrors.length > 0) {
|
|
670
|
+
throw new Error(`Plugin '${pluginDef.name}': ${skillsWithErrors.length} plugin-local skill(s) emitted ` +
|
|
671
|
+
`post-build validation errors: ${skillsWithErrors.join(', ')}`);
|
|
480
672
|
}
|
|
481
|
-
|
|
673
|
+
const localSkillsPackaged = packagedLocalSkills.length;
|
|
674
|
+
// Phase 2b: tree copy of everything the other phases did NOT produce (commands,
|
|
675
|
+
// hooks, agents, .mcp.json, root files), skipping .claude-plugin/ and respecting
|
|
676
|
+
// .gitignore.
|
|
677
|
+
//
|
|
678
|
+
// The exclusion list is the set of `skills/<dir>` entries some OTHER phase
|
|
679
|
+
// produces: the ones the packager just wrote (Phase 2a) plus the pool-sourced
|
|
680
|
+
// collisions Phase 3 copies in. Both halves come from the SAME Phase 1.4
|
|
681
|
+
// discovery, partitioned — never from a second listing of `skills/` — which is
|
|
682
|
+
// what makes "excluded here" and "produced elsewhere" the same set by
|
|
683
|
+
// construction. Two independent filters over the same directory would let a dir
|
|
684
|
+
// be excluded by one and skipped by the other, and it would then ship NOWHERE,
|
|
685
|
+
// with no diagnostic.
|
|
686
|
+
//
|
|
687
|
+
// What remains for the tree-copy is everything under `skills/` that is NOT a
|
|
688
|
+
// skill: a `shared/` helper dir, `_templates/`, or the bare PARENT segment of a
|
|
689
|
+
// nested skill (`skills/group/` when the skill is `skills/group/nested/`). A
|
|
690
|
+
// directory holding a SKILL.md is never copied verbatim at any depth — that is
|
|
691
|
+
// exactly how eval suites, scratch files, and un-rewritten links used to ship.
|
|
692
|
+
const producedSkillDirs = [
|
|
693
|
+
...packagedLocalSkills.map(({ skillDirPath }) => skillDirPath),
|
|
694
|
+
...collidingSkills.map(({ skillDirPath }) => skillDirPath),
|
|
695
|
+
];
|
|
482
696
|
const treeResult = pluginSourceExists
|
|
483
697
|
? await treeCopyPlugin({
|
|
484
698
|
sourceDir: pluginSourceDir,
|
|
485
699
|
destDir: pluginDir,
|
|
486
|
-
excludeSkillDirs:
|
|
700
|
+
excludeSkillDirs: producedSkillDirs,
|
|
487
701
|
warn: (m) => logger.info(`warning: ${m}`),
|
|
488
702
|
})
|
|
489
703
|
: { commandsCopied: 0, hooksCopied: 0, agentsCopied: 0, mcpCopied: 0, filesCopied: 0 };
|
|
490
|
-
// Phase 2.5: apply each NON-colliding tree-copied plugin-source skill's
|
|
491
|
-
// skill-level files: mapping into the distributed skill dir (the tree-copy
|
|
492
|
-
// is verbatim and never runs the skill-packager). Pool skills — including a
|
|
493
|
-
// colliding skill, now pool-sourced only — already had files: baked in by
|
|
494
|
-
// `vat skills build`, so this only touches genuinely tree-copied skills.
|
|
495
|
-
const skillFilesCopied = pluginSourceExists
|
|
496
|
-
? await applyTreeCopiedSkillFiles({
|
|
497
|
-
pluginSourceDir,
|
|
498
|
-
pluginDir,
|
|
499
|
-
configDir,
|
|
500
|
-
skillsConfig,
|
|
501
|
-
excludeSkillDirs: new Set(collidingSkillDirs),
|
|
502
|
-
logger,
|
|
503
|
-
})
|
|
504
|
-
: 0;
|
|
505
704
|
// Phase 3: pool-skill copy-in (from dist/skills/ via the plugin's skills: selector).
|
|
506
|
-
const skillsCopied = await copyPoolSkills(pluginDef, marketplaceAvailable, configDir, pluginDir, logger);
|
|
705
|
+
const skillsCopied = await copyPoolSkills(pluginDef, marketplaceAvailable, configDir, pluginDir, poolDestOverrides, logger);
|
|
507
706
|
// Phase 4: files[] mapping (may overwrite tree-copied files).
|
|
508
707
|
let explicitFilesCopied = 0;
|
|
509
708
|
if (pluginDef.files && pluginDef.files.length > 0) {
|
|
@@ -520,7 +719,7 @@ async function buildPlugin(input) {
|
|
|
520
719
|
// truth that flows into both the merged plugin.json and marketplace.json.
|
|
521
720
|
const authorJson = readAuthorPluginJson(pluginSourceDir);
|
|
522
721
|
const pluginVersion = resolveVersion(pluginDef, authorJson, rootVersion, { warn: (message) => logger.info(`warning: ${message}`) });
|
|
523
|
-
await writeMergedPluginJson(pluginDef, authorJson, pluginVersion, pluginDir, owner, logger);
|
|
722
|
+
const pluginAuthor = await writeMergedPluginJson(pluginDef, authorJson, pluginVersion, pluginDir, owner, logger);
|
|
524
723
|
// Phase 6: per-plugin CHANGELOG copy. Resolves to <pluginSourceDir>/CHANGELOG.md
|
|
525
724
|
// by default, or `entry.changelog` (relative to plugin source) when configured.
|
|
526
725
|
// No-op when neither resolves — marketplace-level CHANGELOG (handled in
|
|
@@ -534,6 +733,7 @@ async function buildPlugin(input) {
|
|
|
534
733
|
pluginName: pluginDef.name,
|
|
535
734
|
pluginDir,
|
|
536
735
|
pluginVersion,
|
|
736
|
+
pluginAuthor,
|
|
537
737
|
skillsCopied,
|
|
538
738
|
commandsCopied: treeResult.commandsCopied,
|
|
539
739
|
hooksCopied: treeResult.hooksCopied,
|
|
@@ -541,7 +741,8 @@ async function buildPlugin(input) {
|
|
|
541
741
|
mcpCopied: treeResult.mcpCopied,
|
|
542
742
|
treeFilesCopied: treeResult.filesCopied,
|
|
543
743
|
explicitFilesCopied,
|
|
544
|
-
|
|
744
|
+
localSkillsPackaged,
|
|
745
|
+
localSkillIssueCounts,
|
|
545
746
|
};
|
|
546
747
|
}
|
|
547
748
|
//# sourceMappingURL=build.js.map
|