release-skill 0.4.1 → 0.4.2
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codebuddy-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +2 -2
- package/.kimi-plugin/plugin.json +1 -1
- package/CHANGELOG.md +15 -0
- package/INSTALL.md +2 -2
- package/INSTALL.zh-CN.md +2 -2
- package/README.md +16 -9
- package/README.zh-CN.md +12 -8
- package/adapters/claude/.claude-plugin/marketplace.json +1 -1
- package/adapters/claude/.claude-plugin/plugin.json +1 -1
- package/adapters/claude/bin/release-skill.bundle.mjs +81 -18
- package/adapters/claude/schemas/release-plan.schema.json +5 -0
- package/adapters/claude/schemas/release-project.schema.json +5 -0
- package/adapters/codex/.codex-plugin/plugin.json +2 -2
- package/adapters/codex/bin/release-skill.bundle.mjs +81 -18
- package/adapters/codex/schemas/release-plan.schema.json +5 -0
- package/adapters/codex/schemas/release-project.schema.json +5 -0
- package/adapters/kimi/.kimi-plugin/plugin.json +1 -1
- package/adapters/kimi/bin/release-skill.bundle.mjs +81 -18
- package/adapters/kimi/schemas/release-plan.schema.json +5 -0
- package/adapters/kimi/schemas/release-project.schema.json +5 -0
- package/adapters/workbuddy/.codebuddy-plugin/plugin.json +1 -1
- package/adapters/workbuddy/bin/release-skill.bundle.mjs +81 -18
- package/adapters/workbuddy/schemas/release-plan.schema.json +5 -0
- package/adapters/workbuddy/schemas/release-project.schema.json +5 -0
- package/bin/release-skill.bundle.mjs +81 -18
- package/package.json +1 -1
- package/schemas/release-plan.schema.json +5 -0
- package/schemas/release-project.schema.json +5 -0
- package/src/adapters/plugin-marketplace.mjs +21 -5
- package/src/commands/prepare.mjs +19 -13
- package/src/core/plan.mjs +4 -3
- package/src/platforms/codebuddy.mjs +92 -10
- package/src/platforms/registry.mjs +4 -3
package/src/commands/prepare.mjs
CHANGED
|
@@ -1289,19 +1289,17 @@ export function buildExternalActions(unitResults, resolvedVersions, productionAs
|
|
|
1289
1289
|
});
|
|
1290
1290
|
// Consumer marketplace install actions (only when distribution
|
|
1291
1291
|
// declared), driven by the platform registry (T2.2 step 3): one loop
|
|
1292
|
-
// body for every platform
|
|
1293
|
-
//
|
|
1294
|
-
//
|
|
1295
|
-
//
|
|
1296
|
-
//
|
|
1297
|
-
// entrySkill are the meaningful identity fields there).
|
|
1292
|
+
// body for every platform. Marketplace identity follows the distribution
|
|
1293
|
+
// declaration: claude/codex require it via the registry schema fields;
|
|
1294
|
+
// kimi/codebuddy tolerate an optional declaration (codebuddy defaults to
|
|
1295
|
+
// its unified marketplace constant downstream when undeclared).
|
|
1296
|
+
// Undeclared stays absent so legacy frozen plans remain byte-identical.
|
|
1298
1297
|
const frozenUnitDists = frozenDistributions?.get(unit.id) ?? null;
|
|
1299
1298
|
for (const platform of PLATFORMS) {
|
|
1300
1299
|
const dist = frozenUnitDists
|
|
1301
1300
|
? frozenUnitDists.find((d) => d.type === platform.distributionType)
|
|
1302
1301
|
: (unit.distributions ?? []).find((d) => d.type === platform.distributionType);
|
|
1303
1302
|
if (!dist) continue;
|
|
1304
|
-
const requiresMarketplace = platform.schemaRequiredFields.includes('marketplace');
|
|
1305
1303
|
const timeoutMs = Number.isInteger(dist.timeoutMs) ? dist.timeoutMs : 300000;
|
|
1306
1304
|
// External independent marketplace form: the distribution declares
|
|
1307
1305
|
// marketplaceRepo, so the install targets the external marketplace repo
|
|
@@ -1350,7 +1348,8 @@ export function buildExternalActions(unitResults, resolvedVersions, productionAs
|
|
|
1350
1348
|
parameters: {
|
|
1351
1349
|
consumer: platform.id,
|
|
1352
1350
|
plugin: dist.plugin,
|
|
1353
|
-
...(
|
|
1351
|
+
...(dist.marketplace !== undefined ? { marketplace: dist.marketplace } : {}),
|
|
1352
|
+
...(dist.marketplaceSource !== undefined ? { marketplaceSource: dist.marketplaceSource } : {}),
|
|
1354
1353
|
repo: externalMarketplace ? dist.marketplaceRepo : unit.publicRepo,
|
|
1355
1354
|
version,
|
|
1356
1355
|
entrySkill: dist.entrySkill,
|
|
@@ -1377,7 +1376,8 @@ export function buildExternalActions(unitResults, resolvedVersions, productionAs
|
|
|
1377
1376
|
expected: {
|
|
1378
1377
|
installed: true,
|
|
1379
1378
|
plugin: dist.plugin,
|
|
1380
|
-
...(
|
|
1379
|
+
...(dist.marketplace !== undefined ? { marketplace: dist.marketplace } : {}),
|
|
1380
|
+
...(dist.marketplaceSource !== undefined ? { marketplaceSource: dist.marketplaceSource } : {}),
|
|
1381
1381
|
version,
|
|
1382
1382
|
entrySkill: dist.entrySkill,
|
|
1383
1383
|
...(externalMarketplace ? { marketplaceLocation: 'external', repo: dist.marketplaceRepo } : {}),
|
|
@@ -1532,13 +1532,17 @@ export function buildExternalActions(unitResults, resolvedVersions, productionAs
|
|
|
1532
1532
|
// non-production loop above plus the production-only bindings
|
|
1533
1533
|
// (ref/snapshotPath/manifestDigest parameters; consumer/repo/ref/
|
|
1534
1534
|
// entrySkillFound/manifestDigest expected). Marketplace identity follows
|
|
1535
|
-
// the
|
|
1535
|
+
// the distribution declaration, same as the non-production loop.
|
|
1536
1536
|
for (const platform of PLATFORMS) {
|
|
1537
1537
|
const dist = frozenUnitDists
|
|
1538
1538
|
? frozenUnitDists.find((d) => d.type === platform.distributionType)
|
|
1539
1539
|
: (unit.distributions ?? []).find((d) => d.type === platform.distributionType);
|
|
1540
1540
|
if (!dist) continue;
|
|
1541
|
-
|
|
1541
|
+
// Marketplace identity follows the distribution declaration: claude/codex
|
|
1542
|
+
// require it via the registry schema fields; kimi/codebuddy tolerate an
|
|
1543
|
+
// optional declaration (codebuddy defaults to its unified marketplace
|
|
1544
|
+
// constant downstream when undeclared). Undeclared stays absent so
|
|
1545
|
+
// legacy frozen plans remain byte-identical.
|
|
1542
1546
|
const timeoutMs = Number.isInteger(dist.timeoutMs) ? dist.timeoutMs : 300000;
|
|
1543
1547
|
// External independent marketplace form: the install targets the external
|
|
1544
1548
|
// marketplace repo with the add-ref + marketplaceCommitSha frozen online
|
|
@@ -1583,7 +1587,8 @@ export function buildExternalActions(unitResults, resolvedVersions, productionAs
|
|
|
1583
1587
|
parameters: {
|
|
1584
1588
|
consumer: platform.id,
|
|
1585
1589
|
plugin: dist.plugin,
|
|
1586
|
-
...(
|
|
1590
|
+
...(dist.marketplace !== undefined ? { marketplace: dist.marketplace } : {}),
|
|
1591
|
+
...(dist.marketplaceSource !== undefined ? { marketplaceSource: dist.marketplaceSource } : {}),
|
|
1587
1592
|
repo: externalMarketplace ? dist.marketplaceRepo : unit.publicRepo,
|
|
1588
1593
|
ref: externalMarketplace ? freeze.ref : resolvedTag,
|
|
1589
1594
|
version: unitVersion,
|
|
@@ -1622,7 +1627,8 @@ export function buildExternalActions(unitResults, resolvedVersions, productionAs
|
|
|
1622
1627
|
installed: true,
|
|
1623
1628
|
consumer: platform.id,
|
|
1624
1629
|
plugin: dist.plugin,
|
|
1625
|
-
...(
|
|
1630
|
+
...(dist.marketplace !== undefined ? { marketplace: dist.marketplace } : {}),
|
|
1631
|
+
...(dist.marketplaceSource !== undefined ? { marketplaceSource: dist.marketplaceSource } : {}),
|
|
1626
1632
|
repo: externalMarketplace ? dist.marketplaceRepo : unit.publicRepo,
|
|
1627
1633
|
version: unitVersion,
|
|
1628
1634
|
ref: externalMarketplace ? freeze.ref : resolvedTag,
|
package/src/core/plan.mjs
CHANGED
|
@@ -751,9 +751,10 @@ export function validatePlanActionCompleteness(plan, options = {}) {
|
|
|
751
751
|
// consumer id, and — via the schema required fields — whether marketplace
|
|
752
752
|
// identity is a required binding). Platforms without a required
|
|
753
753
|
// marketplace (kimi, MINOR-1: Kimi Code has an interactive marketplace
|
|
754
|
-
// but no non-interactive install API
|
|
755
|
-
//
|
|
756
|
-
//
|
|
754
|
+
// but no non-interactive install API; codebuddy, whose unified marketplace
|
|
755
|
+
// defaults to a constant but may be overridden by the distribution)
|
|
756
|
+
// tolerate a declared marketplace as an optional value but never bind it
|
|
757
|
+
// as a required condition, in parameters or in expected.
|
|
757
758
|
for (const platform of PLATFORMS) {
|
|
758
759
|
const dist = distributions.find((d) => d.type === platform.distributionType);
|
|
759
760
|
if (!dist) continue;
|
|
@@ -88,15 +88,55 @@ export const CODEBUDDY_REQUIREMENT_FILE = 'release-skill-codebuddy-manual-instal
|
|
|
88
88
|
export const CODEBUDDY_ATTESTATION_FILE = 'release-skill-codebuddy-attestation.json';
|
|
89
89
|
|
|
90
90
|
/**
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
* segment in both channels
|
|
91
|
+
* Default unified marketplace the WorkBuddy desktop app and the codebuddy CLI
|
|
92
|
+
* install from (verified fact). A distribution may override this by declaring
|
|
93
|
+
* `marketplace` (see resolveCodeBuddyMarketplace); the install path is
|
|
94
|
+
* validated against the resolved marketplace segment in both channels, and a
|
|
95
|
+
* declared attestation `marketplace` field must equal the resolved name.
|
|
95
96
|
*/
|
|
96
97
|
export const CODEBUDDY_MARKETPLACE_NAME = 'artifact-skill-set';
|
|
97
|
-
/**
|
|
98
|
+
/** Default marketplace source URL (used only when no marketplace override is declared). */
|
|
98
99
|
export const CODEBUDDY_MARKETPLACE_SOURCE = 'https://github.com/ifoohoo/artifact-skill-set';
|
|
99
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Resolve the unified marketplace name for a codebuddy action.
|
|
103
|
+
*
|
|
104
|
+
* Falls back to CODEBUDDY_MARKETPLACE_NAME when the action carries no
|
|
105
|
+
* `marketplace` (legacy frozen plans, byte-identical behavior). A declared
|
|
106
|
+
* marketplace must be a non-empty string; anything else fails closed.
|
|
107
|
+
*
|
|
108
|
+
* @param {object} [action] - expanded codebuddy action (may be undefined).
|
|
109
|
+
* @returns {string} the resolved marketplace name.
|
|
110
|
+
* @throws {Error} when a declared marketplace is not a non-empty string.
|
|
111
|
+
*/
|
|
112
|
+
export function resolveCodeBuddyMarketplace(action) {
|
|
113
|
+
const marketplace = action?.marketplace ?? CODEBUDDY_MARKETPLACE_NAME;
|
|
114
|
+
if (typeof marketplace !== 'string' || marketplace.length === 0) {
|
|
115
|
+
throw new Error(`codebuddy marketplace must be a non-empty string when declared, got ${JSON.stringify(action?.marketplace)}`);
|
|
116
|
+
}
|
|
117
|
+
return marketplace;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Resolve the marketplace source URL for a codebuddy action, when knowable.
|
|
122
|
+
*
|
|
123
|
+
* The default marketplace has a verified source constant; a configured
|
|
124
|
+
* marketplace only has a source when the distribution declared
|
|
125
|
+
* `marketplaceSource`. When neither applies, null is returned and callers
|
|
126
|
+
* must NOT fabricate a URL.
|
|
127
|
+
*
|
|
128
|
+
* @param {object} [action] - expanded codebuddy action (may be undefined).
|
|
129
|
+
* @returns {string|null} the source URL, or null when unknown.
|
|
130
|
+
*/
|
|
131
|
+
export function resolveCodeBuddyMarketplaceSource(action) {
|
|
132
|
+
if (action?.marketplace === undefined || action?.marketplace === null) {
|
|
133
|
+
return CODEBUDDY_MARKETPLACE_SOURCE;
|
|
134
|
+
}
|
|
135
|
+
return typeof action.marketplaceSource === 'string' && action.marketplaceSource.length > 0
|
|
136
|
+
? action.marketplaceSource
|
|
137
|
+
: null;
|
|
138
|
+
}
|
|
139
|
+
|
|
100
140
|
/** Authoritative codebuddy plugin manifest (single candidate, no precedence). */
|
|
101
141
|
export const CODEBUDDY_PLUGIN_MANIFEST_RELATIVE = join('.codebuddy-plugin', 'plugin.json');
|
|
102
142
|
|
|
@@ -185,7 +225,7 @@ export function codebuddyAuthorityDir(context, planDigest, plugin) {
|
|
|
185
225
|
/**
|
|
186
226
|
* 统一人工安装说明:面向 CodeBuddy / WorkBuddy 的人工结果流程。
|
|
187
227
|
*
|
|
188
|
-
* @param {{plugin:string, version:string, ref:string, attestationDir:string, requiresInstalledClosure:boolean}} p
|
|
228
|
+
* @param {{plugin:string, version:string, ref:string, attestationDir:string, requiresInstalledClosure:boolean, marketplace:string, marketplaceSource:string|null}} p
|
|
189
229
|
* @returns {string[]}
|
|
190
230
|
*/
|
|
191
231
|
function buildCodeBuddyManualInstructions({
|
|
@@ -194,11 +234,13 @@ function buildCodeBuddyManualInstructions({
|
|
|
194
234
|
ref,
|
|
195
235
|
attestationDir,
|
|
196
236
|
requiresInstalledClosure,
|
|
237
|
+
marketplace,
|
|
238
|
+
marketplaceSource,
|
|
197
239
|
}) {
|
|
198
240
|
return [
|
|
199
241
|
`CodeBuddy/WorkBuddy 插件安装无法锁定冻结 ref(codebuddy CLI marketplace add/install 没有 ref 选项,跟踪默认分支),因此安装是需要人工结果证明的手动步骤。`,
|
|
200
242
|
`1) publish 完成所有远端写入后进入 PUBLISHED 状态(自动化 Git 分支/标签、npm 和 GitHub Release 写入已完成)。此 codebuddy 检查点标记为需要人工安装。`,
|
|
201
|
-
`2) 从统一市场 "${
|
|
243
|
+
`2) 从统一市场 "${marketplace}"${marketplaceSource ? ` (${marketplaceSource})` : ''} 安装 ${plugin}。确认安装的插件版本等于冻结版本 ${version}。`,
|
|
202
244
|
`3) 将人工结果 JSON 写入: ${attestationDir}/${CODEBUDDY_ATTESTATION_FILE}`,
|
|
203
245
|
` 必填字段: platform="codebuddy", version, planDigest(冻结计划摘要), result("passed" 或 "failed"), actor(确认人), confirmedAt(ISO 8601 时间戳)${requiresInstalledClosure ? ',installChannel("desktop" 或 "cli"),installPath(实际安装后的插件目录)' : ''}`,
|
|
204
246
|
` 可选字段: note(备注)`,
|
|
@@ -312,15 +354,35 @@ export function validateCodeBuddyAttestation(attestation, action, isoNow, boundP
|
|
|
312
354
|
if (normalized.installPath.includes('..')) {
|
|
313
355
|
return { valid: false, error: 'codebuddy attestation installPath must not contain path traversal ("..")', normalized: null };
|
|
314
356
|
}
|
|
315
|
-
// CLI 通道:installPath
|
|
357
|
+
// CLI 通道:installPath 必须以预期后缀结尾(市场名解析自冻结动作,
|
|
358
|
+
// 未声明时回落到默认统一市场常量)
|
|
316
359
|
if (normalized.installChannel === 'cli') {
|
|
317
|
-
|
|
360
|
+
let resolvedMarketplace;
|
|
361
|
+
try {
|
|
362
|
+
resolvedMarketplace = resolveCodeBuddyMarketplace(action);
|
|
363
|
+
} catch (resolveErr) {
|
|
364
|
+
return { valid: false, error: resolveErr.message, normalized: null };
|
|
365
|
+
}
|
|
366
|
+
const expectedSuffix = `.workbuddy/plugins/marketplaces/${resolvedMarketplace}/plugins/${action.plugin}`;
|
|
318
367
|
if (!normalized.installPath.endsWith(expectedSuffix)) {
|
|
319
368
|
return { valid: false, error: `codebuddy CLI attestation installPath must end with "${expectedSuffix}", got "${normalized.installPath}"`, normalized: null };
|
|
320
369
|
}
|
|
321
370
|
}
|
|
322
371
|
}
|
|
323
372
|
|
|
373
|
+
// 可选 marketplace 字段:一旦声明必须等于冻结动作解析出的市场名
|
|
374
|
+
if (normalized.marketplace !== undefined) {
|
|
375
|
+
let resolvedMarketplace;
|
|
376
|
+
try {
|
|
377
|
+
resolvedMarketplace = resolveCodeBuddyMarketplace(action);
|
|
378
|
+
} catch (resolveErr) {
|
|
379
|
+
return { valid: false, error: resolveErr.message, normalized: null };
|
|
380
|
+
}
|
|
381
|
+
if (normalized.marketplace !== resolvedMarketplace) {
|
|
382
|
+
return { valid: false, error: `codebuddy attestation marketplace "${normalized.marketplace}" does not match the resolved marketplace "${resolvedMarketplace}"`, normalized: null };
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
324
386
|
// result 只接受 passed 或 failed
|
|
325
387
|
if (normalized.result !== 'passed' && normalized.result !== 'failed') {
|
|
326
388
|
return { valid: false, error: `codebuddy attestation result "${normalized.result}" must be "passed" or "failed"`, normalized: null };
|
|
@@ -454,6 +516,22 @@ export async function executeCodeBuddyManualRequirement(action, context) {
|
|
|
454
516
|
|
|
455
517
|
const ref = action.ref ?? `v${action.version}`;
|
|
456
518
|
|
|
519
|
+
// Unified marketplace identity: resolved from the frozen action (declared
|
|
520
|
+
// `marketplace`/`marketplaceSource`), falling back to the default constants
|
|
521
|
+
// for legacy plans. A fabricated source URL is never emitted for a
|
|
522
|
+
// configured marketplace without a declared marketplaceSource.
|
|
523
|
+
let marketplace;
|
|
524
|
+
try {
|
|
525
|
+
marketplace = resolveCodeBuddyMarketplace(action);
|
|
526
|
+
} catch (marketplaceErr) {
|
|
527
|
+
return createResult({
|
|
528
|
+
actionType,
|
|
529
|
+
status: ActionStatus.EXECUTE_FAILED,
|
|
530
|
+
error: marketplaceErr.message,
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
const marketplaceSource = resolveCodeBuddyMarketplaceSource(action);
|
|
534
|
+
|
|
457
535
|
// (B) Stable plugin-level authority dir, shared across
|
|
458
536
|
// publish/reconcile/verify run dirs.
|
|
459
537
|
let attestationDir;
|
|
@@ -473,6 +551,8 @@ export async function executeCodeBuddyManualRequirement(action, context) {
|
|
|
473
551
|
ref,
|
|
474
552
|
attestationDir,
|
|
475
553
|
requiresInstalledClosure: Boolean(context.plan?.skillResourceClosure),
|
|
554
|
+
marketplace,
|
|
555
|
+
marketplaceSource,
|
|
476
556
|
});
|
|
477
557
|
|
|
478
558
|
// 统一 requirement 结构:不再包含隔离目录信息
|
|
@@ -484,6 +564,8 @@ export async function executeCodeBuddyManualRequirement(action, context) {
|
|
|
484
564
|
repo: action.repo,
|
|
485
565
|
ref,
|
|
486
566
|
entrySkill: action.entrySkill,
|
|
567
|
+
marketplace,
|
|
568
|
+
...(marketplaceSource ? { marketplaceSource } : {}),
|
|
487
569
|
planDigest,
|
|
488
570
|
attestationDir,
|
|
489
571
|
attestationFile: CODEBUDDY_ATTESTATION_FILE,
|
|
@@ -497,7 +579,7 @@ export async function executeCodeBuddyManualRequirement(action, context) {
|
|
|
497
579
|
...(context.plan?.skillResourceClosure
|
|
498
580
|
? {
|
|
499
581
|
installChannel: '<"desktop" or "cli">',
|
|
500
|
-
installPath: `<actual .workbuddy/plugins/marketplaces/${
|
|
582
|
+
installPath: `<actual .workbuddy/plugins/marketplaces/${marketplace}/plugins/${action.plugin} directory>`,
|
|
501
583
|
}
|
|
502
584
|
: {}),
|
|
503
585
|
note: '<optional note>',
|
|
@@ -359,9 +359,10 @@ const CODEBUDDY = Object.freeze({
|
|
|
359
359
|
marketplace: '.claude-plugin/marketplace.json',
|
|
360
360
|
}),
|
|
361
361
|
marketplaceSourceForm: null,
|
|
362
|
-
// codebuddy installs from a unified marketplace
|
|
363
|
-
//
|
|
364
|
-
// ./codebuddy.mjs); the
|
|
362
|
+
// codebuddy installs from a unified marketplace whose identity is optional
|
|
363
|
+
// on the action: a distribution may declare `marketplace` to override the
|
|
364
|
+
// default constant in ./codebuddy.mjs (resolveCodeBuddyMarketplace); the
|
|
365
|
+
// entry-version binding does not apply either way (null = N/A).
|
|
365
366
|
marketplaceEntryCarriesVersion: null,
|
|
366
367
|
// codebuddy has no marketplace add that can pin a frozen ref (attestation
|
|
367
368
|
// loop instead), so the marketplace ref form does not apply (null = N/A).
|