release-skill 0.2.2 → 0.2.4
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 +4 -2
- package/.codex-plugin/plugin.json +2 -2
- package/.kimi-plugin/plugin.json +1 -1
- package/CHANGELOG.md +41 -0
- package/CONTRIBUTING.md +27 -0
- package/INSTALL.md +95 -139
- package/INSTALL.zh-CN.md +70 -121
- package/README.md +265 -916
- package/README.zh-CN.md +222 -537
- 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 +18710 -16694
- package/adapters/claude/schemas/release-plan.schema.json +137 -0
- package/adapters/claude/schemas/release-project.schema.json +93 -0
- package/adapters/claude/schemas/release-run.schema.json +70 -2
- package/adapters/codex/.codex-plugin/plugin.json +2 -2
- package/adapters/codex/bin/release-skill.bundle.mjs +18710 -16694
- package/adapters/codex/schemas/release-plan.schema.json +137 -0
- package/adapters/codex/schemas/release-project.schema.json +93 -0
- package/adapters/codex/schemas/release-run.schema.json +70 -2
- package/adapters/kimi/.kimi-plugin/plugin.json +1 -1
- package/adapters/kimi/bin/release-skill.bundle.mjs +18710 -16694
- package/adapters/kimi/schemas/release-plan.schema.json +137 -0
- package/adapters/kimi/schemas/release-project.schema.json +93 -0
- package/adapters/kimi/schemas/release-run.schema.json +70 -2
- package/adapters/workbuddy/.codebuddy-plugin/plugin.json +1 -1
- package/adapters/workbuddy/bin/release-skill.bundle.mjs +18710 -16694
- package/adapters/workbuddy/schemas/release-plan.schema.json +137 -0
- package/adapters/workbuddy/schemas/release-project.schema.json +93 -0
- package/adapters/workbuddy/schemas/release-run.schema.json +70 -2
- package/bin/release-skill.bundle.mjs +18710 -16694
- package/package.json +1 -1
- package/schemas/release-plan.schema.json +137 -0
- package/schemas/release-project.schema.json +93 -0
- package/schemas/release-run.schema.json +70 -2
- package/src/adapters/plugin-marketplace.mjs +1602 -605
- package/src/commands/prepare.mjs +441 -32
- package/src/commands/publish.mjs +107 -75
- package/src/commands/reconcile.mjs +92 -327
- package/src/commands/setup.mjs +148 -20
- package/src/commands/verify.mjs +315 -25
- package/src/core/baseline.mjs +21 -1
- package/src/core/checkpoints.mjs +50 -7
- package/src/core/config.mjs +15 -0
- package/src/core/errors.mjs +2 -0
- package/src/core/installation-contract.mjs +341 -0
- package/src/core/plan.mjs +307 -6
- package/src/platforms/codebuddy.mjs +191 -238
- package/src/platforms/codex.mjs +369 -0
- package/src/platforms/kimi.mjs +164 -119
- package/src/platforms/registry.mjs +180 -4
- package/src/producers/build-adapters.mjs +9 -2
|
@@ -42,6 +42,10 @@ import {
|
|
|
42
42
|
executeCodeBuddyManualRequirement,
|
|
43
43
|
readCodeBuddyManifest,
|
|
44
44
|
} from './codebuddy.mjs';
|
|
45
|
+
import {
|
|
46
|
+
executeCodexManualRequirement,
|
|
47
|
+
readCodexManifest,
|
|
48
|
+
} from './codex.mjs';
|
|
45
49
|
|
|
46
50
|
// --- claude strategy -------------------------------------------------------
|
|
47
51
|
|
|
@@ -137,6 +141,12 @@ const CLAUDE = Object.freeze({
|
|
|
137
141
|
// actionType -> adapter map from it (T2.2 step 3).
|
|
138
142
|
adapter: 'plugin-marketplace',
|
|
139
143
|
automatable: true,
|
|
144
|
+
// --- capability contract (平台能力契约) ------------------------------------
|
|
145
|
+
installMethod: 'structured-cli',
|
|
146
|
+
refStrength: 'name-ref',
|
|
147
|
+
outputProtocol: 'text',
|
|
148
|
+
identityEvidence: 'list-record',
|
|
149
|
+
degradationPolicy: 'block',
|
|
140
150
|
cli: Object.freeze({
|
|
141
151
|
binary: 'claude',
|
|
142
152
|
marketplaceAdd: (repo, ref) => ['plugin', 'marketplace', 'add', `${repo}@${ref}`],
|
|
@@ -190,6 +200,12 @@ const CODEX = Object.freeze({
|
|
|
190
200
|
actionType: 'codex-marketplace-install',
|
|
191
201
|
adapter: 'plugin-marketplace',
|
|
192
202
|
automatable: true,
|
|
203
|
+
// --- capability contract (平台能力契约) ------------------------------------
|
|
204
|
+
installMethod: 'structured-cli',
|
|
205
|
+
refStrength: 'commit-sha',
|
|
206
|
+
outputProtocol: 'structured',
|
|
207
|
+
identityEvidence: 'install-output',
|
|
208
|
+
degradationPolicy: 'human-attestation-with-fallback',
|
|
193
209
|
cli: Object.freeze({
|
|
194
210
|
binary: 'codex',
|
|
195
211
|
marketplaceAdd: (repo, ref) => ['plugin', 'marketplace', 'add', repo, '--ref', ref, '--json'],
|
|
@@ -231,8 +247,9 @@ const CODEX = Object.freeze({
|
|
|
231
247
|
extractInstallPath: codexExtractInstallPath,
|
|
232
248
|
extractListIdentity: codexExtractListIdentity,
|
|
233
249
|
crossValidateListEntry: codexCrossValidateListEntry,
|
|
234
|
-
|
|
235
|
-
|
|
250
|
+
// codex's human-attestation fallback strategy lives in ./codex.mjs
|
|
251
|
+
buildManualRequirement: executeCodexManualRequirement,
|
|
252
|
+
readManifest: readCodexManifest,
|
|
236
253
|
}),
|
|
237
254
|
});
|
|
238
255
|
|
|
@@ -242,6 +259,12 @@ const KIMI = Object.freeze({
|
|
|
242
259
|
actionType: 'kimi-marketplace-install',
|
|
243
260
|
adapter: 'plugin-marketplace',
|
|
244
261
|
automatable: false,
|
|
262
|
+
// --- capability contract (平台能力契约) ------------------------------------
|
|
263
|
+
installMethod: 'interactive-only',
|
|
264
|
+
refStrength: 'unfixable',
|
|
265
|
+
outputProtocol: 'none',
|
|
266
|
+
identityEvidence: 'filesystem-payload',
|
|
267
|
+
degradationPolicy: 'human-attestation',
|
|
245
268
|
cli: null,
|
|
246
269
|
jsonProtocol: Object.freeze({
|
|
247
270
|
listOutput: null,
|
|
@@ -249,7 +272,7 @@ const KIMI = Object.freeze({
|
|
|
249
272
|
marketplaceAddOutput: null,
|
|
250
273
|
pluginInstallOutput: null,
|
|
251
274
|
}),
|
|
252
|
-
isolationEnv: (home) => ({ HOME: home
|
|
275
|
+
isolationEnv: (home) => ({ HOME: home }),
|
|
253
276
|
// kimi never execs a CLI; its stable home is created by the
|
|
254
277
|
// manual-requirement strategy under the attestation authority.
|
|
255
278
|
isolationSubdirs: Object.freeze([]),
|
|
@@ -307,6 +330,12 @@ const CODEBUDDY = Object.freeze({
|
|
|
307
330
|
actionType: 'codebuddy-marketplace-install',
|
|
308
331
|
adapter: 'plugin-marketplace',
|
|
309
332
|
automatable: false,
|
|
333
|
+
// --- capability contract (平台能力契约) ------------------------------------
|
|
334
|
+
installMethod: 'human-attestation',
|
|
335
|
+
refStrength: 'unfixable',
|
|
336
|
+
outputProtocol: 'none',
|
|
337
|
+
identityEvidence: 'human-attestation',
|
|
338
|
+
degradationPolicy: 'human-attestation',
|
|
310
339
|
cli: null,
|
|
311
340
|
jsonProtocol: Object.freeze({
|
|
312
341
|
listOutput: null,
|
|
@@ -324,7 +353,10 @@ const CODEBUDDY = Object.freeze({
|
|
|
324
353
|
manifestPaths: Object.freeze({
|
|
325
354
|
// Single authoritative manifest (no precedence chain, unlike kimi).
|
|
326
355
|
plugin: '.codebuddy-plugin/plugin.json',
|
|
327
|
-
marketplace
|
|
356
|
+
// CodeBuddy bundled-family uses the skill-family marketplace path.
|
|
357
|
+
// This ensures bundled-family installation contracts always include a
|
|
358
|
+
// marketplace entry without requiring an explicit marketplaceIndexPath.
|
|
359
|
+
marketplace: '.claude-plugin/marketplace.json',
|
|
328
360
|
}),
|
|
329
361
|
marketplaceSourceForm: null,
|
|
330
362
|
// codebuddy installs from a unified marketplace but carries no marketplace
|
|
@@ -373,6 +405,11 @@ const VALID_MARKETPLACE_REF_FORMS = new Set(['sha', 'name', null]);
|
|
|
373
405
|
const VALID_LIST_OUTPUTS = new Set(['array', 'installed-object', null]);
|
|
374
406
|
const VALID_CLI_OUTPUTS = new Set(['json', null]);
|
|
375
407
|
const VALID_ENTRY_VERSION_BINDING = new Set([true, false, null]);
|
|
408
|
+
const VALID_INSTALL_METHODS = new Set(['structured-cli', 'interactive-only', 'human-attestation']);
|
|
409
|
+
const VALID_REF_STRENGTHS = new Set(['commit-sha', 'name-ref', 'unfixable']);
|
|
410
|
+
const VALID_OUTPUT_PROTOCOLS = new Set(['structured', 'text', 'none']);
|
|
411
|
+
const VALID_IDENTITY_EVIDENCE = new Set(['list-record', 'install-output', 'filesystem-payload', 'human-attestation']);
|
|
412
|
+
const VALID_DEGRADATION_POLICIES = new Set(['block', 'human-attestation', 'human-attestation-with-fallback']);
|
|
376
413
|
|
|
377
414
|
/**
|
|
378
415
|
* Look up a platform descriptor by id.
|
|
@@ -453,6 +490,23 @@ export function assertRegistry(registry = PLATFORMS) {
|
|
|
453
490
|
throw new Error(`platform registry: ${label} isolationSubdirs must be an array`);
|
|
454
491
|
}
|
|
455
492
|
|
|
493
|
+
// --- capability contract validation (能力契约验证) -----------------------
|
|
494
|
+
if (!VALID_INSTALL_METHODS.has(platform.installMethod)) {
|
|
495
|
+
throw new Error(`platform registry: ${label} has illegal installMethod "${platform.installMethod}"`);
|
|
496
|
+
}
|
|
497
|
+
if (!VALID_REF_STRENGTHS.has(platform.refStrength)) {
|
|
498
|
+
throw new Error(`platform registry: ${label} has illegal refStrength "${platform.refStrength}"`);
|
|
499
|
+
}
|
|
500
|
+
if (!VALID_OUTPUT_PROTOCOLS.has(platform.outputProtocol)) {
|
|
501
|
+
throw new Error(`platform registry: ${label} has illegal outputProtocol "${platform.outputProtocol}"`);
|
|
502
|
+
}
|
|
503
|
+
if (!VALID_IDENTITY_EVIDENCE.has(platform.identityEvidence)) {
|
|
504
|
+
throw new Error(`platform registry: ${label} has illegal identityEvidence "${platform.identityEvidence}"`);
|
|
505
|
+
}
|
|
506
|
+
if (!VALID_DEGRADATION_POLICIES.has(platform.degradationPolicy)) {
|
|
507
|
+
throw new Error(`platform registry: ${label} has illegal degradationPolicy "${platform.degradationPolicy}"`);
|
|
508
|
+
}
|
|
509
|
+
|
|
456
510
|
if (platform.automatable) {
|
|
457
511
|
if (!platform.cli || typeof platform.cli.marketplaceAdd !== 'function'
|
|
458
512
|
|| typeof platform.cli.install !== 'function' || typeof platform.cli.list !== 'function') {
|
|
@@ -467,6 +521,16 @@ export function assertRegistry(registry = PLATFORMS) {
|
|
|
467
521
|
if (typeof platform.strategy.extractInstallPath !== 'function') {
|
|
468
522
|
throw new Error(`platform registry: automatable platform ${label} needs strategy.extractInstallPath`);
|
|
469
523
|
}
|
|
524
|
+
// Platforms with degradationPolicy 'human-attestation-with-fallback'
|
|
525
|
+
// (codex) also need manual-requirement strategies for the fallback path.
|
|
526
|
+
if (platform.degradationPolicy === 'human-attestation-with-fallback') {
|
|
527
|
+
if (typeof platform.strategy.buildManualRequirement !== 'function') {
|
|
528
|
+
throw new Error(`platform registry: ${label} with human-attestation-with-fallback needs strategy.buildManualRequirement`);
|
|
529
|
+
}
|
|
530
|
+
if (typeof platform.strategy.readManifest !== 'function') {
|
|
531
|
+
throw new Error(`platform registry: ${label} with human-attestation-with-fallback needs strategy.readManifest`);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
470
534
|
} else {
|
|
471
535
|
if (platform.cli !== null) {
|
|
472
536
|
throw new Error(`platform registry: non-automatable platform ${label} must have cli === null`);
|
|
@@ -481,8 +545,120 @@ export function assertRegistry(registry = PLATFORMS) {
|
|
|
481
545
|
throw new Error(`platform registry: non-automatable platform ${label} needs strategy.readManifest`);
|
|
482
546
|
}
|
|
483
547
|
}
|
|
548
|
+
|
|
549
|
+
// --- capability contract consistency rules (能力契约一致性规则) -----------
|
|
550
|
+
// automatable === true 必须有 installMethod === 'structured-cli'
|
|
551
|
+
if (platform.automatable === true && platform.installMethod !== 'structured-cli') {
|
|
552
|
+
throw new Error(`platform registry: ${label} is automatable but installMethod is "${platform.installMethod}" (expected "structured-cli")`);
|
|
553
|
+
}
|
|
554
|
+
// automatable === false 必须有 installMethod !== 'structured-cli'
|
|
555
|
+
if (platform.automatable === false && platform.installMethod === 'structured-cli') {
|
|
556
|
+
throw new Error(`platform registry: ${label} is not automatable but installMethod is "structured-cli"`);
|
|
557
|
+
}
|
|
558
|
+
// installMethod === 'structured-cli' 必须有 refStrength !== 'unfixable'
|
|
559
|
+
if (platform.installMethod === 'structured-cli' && platform.refStrength === 'unfixable') {
|
|
560
|
+
throw new Error(`platform registry: ${label} has structured-cli install but unfixable refStrength`);
|
|
561
|
+
}
|
|
562
|
+
// installMethod === 'human-attestation' 必须有 identityEvidence === 'human-attestation'
|
|
563
|
+
if (platform.installMethod === 'human-attestation' && platform.identityEvidence !== 'human-attestation') {
|
|
564
|
+
throw new Error(`platform registry: ${label} has human-attestation install but identityEvidence is "${platform.identityEvidence}"`);
|
|
565
|
+
}
|
|
484
566
|
}
|
|
485
567
|
}
|
|
486
568
|
|
|
487
569
|
// Self-validate at import time: a malformed registry never reaches runtime.
|
|
488
570
|
assertRegistry();
|
|
571
|
+
|
|
572
|
+
// --- capability-driven routing & conflict detection (能力驱动路由与矛盾检测) --
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* 根据平台描述符的 installMethod 决定执行路由。
|
|
576
|
+
*
|
|
577
|
+
* @param {object} platform - 平台描述符
|
|
578
|
+
* @returns {{ route: string, reason: string }}
|
|
579
|
+
* @throws {Error} 无法路由时抛出
|
|
580
|
+
*/
|
|
581
|
+
export function resolvePlatformRoute(platform) {
|
|
582
|
+
const { installMethod } = platform;
|
|
583
|
+
if (installMethod === 'structured-cli') {
|
|
584
|
+
return { route: 'structured-cli', reason: `installMethod is structured-cli` };
|
|
585
|
+
}
|
|
586
|
+
if (installMethod === 'interactive-only' || installMethod === 'human-attestation') {
|
|
587
|
+
return { route: 'human-attestation', reason: `installMethod is ${installMethod}` };
|
|
588
|
+
}
|
|
589
|
+
throw new Error(
|
|
590
|
+
`platform "${platform?.id ?? '<unknown>'}" with installMethod="${installMethod}" cannot be routed`,
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* 检测平台能力描述符中的矛盾。
|
|
596
|
+
*
|
|
597
|
+
* @param {object} platform - 平台描述符
|
|
598
|
+
* @returns {{ hasConflict: boolean, conflicts: string[] }}
|
|
599
|
+
* @throws {Error} 发现矛盾时抛出
|
|
600
|
+
*/
|
|
601
|
+
export function resolveCapabilityConflicts(platform) {
|
|
602
|
+
const conflicts = [];
|
|
603
|
+
const { id, automatable, installMethod, refStrength, identityEvidence, cli, strategy } = platform;
|
|
604
|
+
|
|
605
|
+
// automatable <-> installMethod 一致性
|
|
606
|
+
if (automatable === true && installMethod !== 'structured-cli') {
|
|
607
|
+
conflicts.push(`automatable=true but installMethod="${installMethod}"`);
|
|
608
|
+
}
|
|
609
|
+
if (automatable === false && installMethod === 'structured-cli') {
|
|
610
|
+
conflicts.push(`automatable=false but installMethod="structured-cli"`);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// installMethod <-> refStrength 一致性
|
|
614
|
+
if (installMethod === 'structured-cli' && refStrength === 'unfixable') {
|
|
615
|
+
conflicts.push(`structured-cli with unfixable refStrength`);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// installMethod <-> identityEvidence 一致性
|
|
619
|
+
if (installMethod === 'human-attestation' && identityEvidence !== 'human-attestation') {
|
|
620
|
+
conflicts.push(`human-attestation install but identityEvidence="${identityEvidence}"`);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// 自动化平台必须有 cli 和策略解析函数
|
|
624
|
+
if (automatable === true) {
|
|
625
|
+
if (!cli || typeof cli !== 'object') {
|
|
626
|
+
conflicts.push(`automatable=true but cli is missing`);
|
|
627
|
+
}
|
|
628
|
+
if (!strategy || typeof strategy.parseListOutput !== 'function') {
|
|
629
|
+
conflicts.push(`automatable=true but strategy.parseListOutput is missing`);
|
|
630
|
+
}
|
|
631
|
+
if (!strategy || typeof strategy.extractInstallPath !== 'function') {
|
|
632
|
+
conflicts.push(`automatable=true but strategy.extractInstallPath is missing`);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// 非自动化平台必须 cli === null,且有手动策略函数
|
|
637
|
+
if (automatable === false) {
|
|
638
|
+
if (cli !== null) {
|
|
639
|
+
conflicts.push(`automatable=false but cli is not null`);
|
|
640
|
+
}
|
|
641
|
+
if (!strategy || typeof strategy.buildManualRequirement !== 'function') {
|
|
642
|
+
conflicts.push(`automatable=false but strategy.buildManualRequirement is missing`);
|
|
643
|
+
}
|
|
644
|
+
if (!strategy || typeof strategy.readManifest !== 'function') {
|
|
645
|
+
conflicts.push(`automatable=false but strategy.readManifest is missing`);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
if (conflicts.length > 0) {
|
|
650
|
+
throw new Error(`capability conflict in platform "${id}": ${conflicts.join('; ')}`);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
return { hasConflict: false, conflicts: [] };
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* 从 installMethod 派生 automatable 标志。
|
|
658
|
+
*
|
|
659
|
+
* @param {object} platform - 平台描述符
|
|
660
|
+
* @returns {boolean}
|
|
661
|
+
*/
|
|
662
|
+
export function deriveAutomatable(platform) {
|
|
663
|
+
return platform.installMethod === 'structured-cli';
|
|
664
|
+
}
|
|
@@ -438,9 +438,16 @@ async function generateAdapterFiles(platform, skills, templateJson, root, market
|
|
|
438
438
|
if (typeof adapted.skills === 'string') {
|
|
439
439
|
adapted.skills = platform.name === 'workbuddy' ? ['./skills/'] : './skills/';
|
|
440
440
|
} else if (Array.isArray(adapted.skills)) {
|
|
441
|
-
|
|
441
|
+
// Handle both string array and object array forms
|
|
442
|
+
adapted.skills = adapted.skills.map((skill) => {
|
|
443
|
+
if (typeof skill === 'string') {
|
|
444
|
+
// String array: transform to relative path for the adapter
|
|
445
|
+
return platform.name === 'workbuddy' ? './skills/' : skill;
|
|
446
|
+
}
|
|
447
|
+
// Object array: preserve existing behavior
|
|
442
448
|
skill.source = `../skills/${skill.name}/SKILL.md`;
|
|
443
|
-
|
|
449
|
+
return skill;
|
|
450
|
+
});
|
|
444
451
|
}
|
|
445
452
|
|
|
446
453
|
const pluginJsonContent = JSON.stringify(adapted, null, 2) + '\n';
|