release-skill 0.1.4 → 0.1.5
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/.codex-plugin/plugin.json +2 -2
- package/CHANGELOG.md +27 -0
- package/INSTALL.md +1 -1
- package/INSTALL.zh-CN.md +1 -1
- package/README.md +13 -3
- package/README.zh-CN.md +11 -3
- 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 +97 -10
- package/adapters/claude/schemas/release-project.schema.json +23 -0
- package/adapters/codex/.codex-plugin/plugin.json +2 -2
- package/adapters/codex/bin/release-skill.bundle.mjs +97 -10
- package/adapters/codex/schemas/release-project.schema.json +23 -0
- package/bin/release-skill.bundle.mjs +97 -10
- package/package.json +1 -1
- package/schemas/release-project.schema.json +23 -0
- package/src/adapters/plugin-marketplace.mjs +70 -3
- package/src/commands/prepare.mjs +8 -0
- package/src/commands/reconcile.mjs +4 -1
- package/src/commands/verify.mjs +4 -1
- package/src/core/plan.mjs +59 -1
package/src/commands/prepare.mjs
CHANGED
|
@@ -690,6 +690,7 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
690
690
|
const claudeDist = (unit.distributions ?? []).find((d) => d.type === 'claude-plugin');
|
|
691
691
|
if (claudeDist) {
|
|
692
692
|
const identity = marketplaceIdentity(claudeDist);
|
|
693
|
+
const claudeTimeoutMs = Number.isInteger(claudeDist.timeoutMs) ? claudeDist.timeoutMs : 300000;
|
|
693
694
|
actions.push({
|
|
694
695
|
id: `claude-marketplace-install-${unit.id}`,
|
|
695
696
|
type: 'claude-marketplace-install',
|
|
@@ -702,6 +703,7 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
702
703
|
repo: unit.publicRepo,
|
|
703
704
|
version,
|
|
704
705
|
entrySkill: identity.entrySkill,
|
|
706
|
+
timeoutMs: claudeTimeoutMs,
|
|
705
707
|
},
|
|
706
708
|
expected: {
|
|
707
709
|
installed: true,
|
|
@@ -716,6 +718,7 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
716
718
|
const codexDist = (unit.distributions ?? []).find((d) => d.type === 'codex-plugin');
|
|
717
719
|
if (codexDist) {
|
|
718
720
|
const identity = marketplaceIdentity(codexDist);
|
|
721
|
+
const codexTimeoutMs = Number.isInteger(codexDist.timeoutMs) ? codexDist.timeoutMs : 300000;
|
|
719
722
|
actions.push({
|
|
720
723
|
id: `codex-marketplace-install-${unit.id}`,
|
|
721
724
|
type: 'codex-marketplace-install',
|
|
@@ -728,6 +731,7 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
728
731
|
repo: unit.publicRepo,
|
|
729
732
|
version,
|
|
730
733
|
entrySkill: identity.entrySkill,
|
|
734
|
+
timeoutMs: codexTimeoutMs,
|
|
731
735
|
},
|
|
732
736
|
expected: {
|
|
733
737
|
installed: true,
|
|
@@ -884,6 +888,7 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
884
888
|
const claudeDist = (unit.distributions ?? []).find((d) => d.type === 'claude-plugin');
|
|
885
889
|
if (claudeDist) {
|
|
886
890
|
const identity = marketplaceIdentity(claudeDist);
|
|
891
|
+
const claudeTimeoutMs = Number.isInteger(claudeDist.timeoutMs) ? claudeDist.timeoutMs : 300000;
|
|
887
892
|
actions.push({
|
|
888
893
|
id: `claude-marketplace-install-${unit.id}`,
|
|
889
894
|
type: 'claude-marketplace-install',
|
|
@@ -899,6 +904,7 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
899
904
|
entrySkill: identity.entrySkill,
|
|
900
905
|
snapshotPath: asset.snapshotPath,
|
|
901
906
|
manifestDigest: asset.manifestDigest,
|
|
907
|
+
timeoutMs: claudeTimeoutMs,
|
|
902
908
|
},
|
|
903
909
|
expected: {
|
|
904
910
|
installed: true,
|
|
@@ -918,6 +924,7 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
918
924
|
const codexDist = (unit.distributions ?? []).find((d) => d.type === 'codex-plugin');
|
|
919
925
|
if (codexDist) {
|
|
920
926
|
const identity = marketplaceIdentity(codexDist);
|
|
927
|
+
const codexTimeoutMs = Number.isInteger(codexDist.timeoutMs) ? codexDist.timeoutMs : 300000;
|
|
921
928
|
actions.push({
|
|
922
929
|
id: `codex-marketplace-install-${unit.id}`,
|
|
923
930
|
type: 'codex-marketplace-install',
|
|
@@ -933,6 +940,7 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
933
940
|
entrySkill: identity.entrySkill,
|
|
934
941
|
snapshotPath: asset.snapshotPath,
|
|
935
942
|
manifestDigest: asset.manifestDigest,
|
|
943
|
+
timeoutMs: codexTimeoutMs,
|
|
936
944
|
},
|
|
937
945
|
expected: {
|
|
938
946
|
installed: true,
|
|
@@ -222,7 +222,10 @@ export async function reconcileRelease(options) {
|
|
|
222
222
|
// =======================================================================
|
|
223
223
|
await evidence.append({ phase: 'safety-gate', gate: 'action-completeness', status: 'started' });
|
|
224
224
|
|
|
225
|
-
|
|
225
|
+
// Use legacyCompatibility: old PARTIAL plans (pre-v0.1.5) lack
|
|
226
|
+
// parameters.timeoutMs. Reconcile must still pass these plans,
|
|
227
|
+
// while strict mode (prepare/approve/publish) rejects them.
|
|
228
|
+
const completenessResult = validatePlanActionCompleteness(plan, { legacyCompatibility: true });
|
|
226
229
|
if (!completenessResult.passed) {
|
|
227
230
|
await evidence.append({
|
|
228
231
|
phase: 'safety-gate',
|
package/src/commands/verify.mjs
CHANGED
|
@@ -669,7 +669,10 @@ export async function verifyRelease(options) {
|
|
|
669
669
|
}
|
|
670
670
|
|
|
671
671
|
// Validate plan action completeness before checkpoint mapping
|
|
672
|
-
|
|
672
|
+
// Use legacyCompatibility: old plans (pre-v0.1.5) lack
|
|
673
|
+
// parameters.timeoutMs. Verify must still pass these plans,
|
|
674
|
+
// while strict mode (prepare/approve/publish) rejects them.
|
|
675
|
+
const completenessResult = validatePlanActionCompleteness(plan, { legacyCompatibility: true });
|
|
673
676
|
if (!completenessResult.passed) {
|
|
674
677
|
throw new ReleaseError(
|
|
675
678
|
GATE_FAILED,
|
package/src/core/plan.mjs
CHANGED
|
@@ -312,9 +312,13 @@ const REQUIRED_ACTION_TYPES = ['push-snapshot', 'create-tag', 'github-release'];
|
|
|
312
312
|
* (e.g. v0.0.10 must not match expected version 0.0.1).
|
|
313
313
|
*
|
|
314
314
|
* @param {object} plan - A validated release plan object.
|
|
315
|
+
* @param {object} [options]
|
|
316
|
+
* @param {boolean} [options.legacyCompatibility] - When true, relax
|
|
317
|
+
* timeoutMs requirement for old plans (reconcile/verify paths).
|
|
318
|
+
* New prepare/approve/publish must not set this flag.
|
|
315
319
|
* @returns {{ passed: boolean, details: { failures: string[], expectedCount: number, actualCount: number } }}
|
|
316
320
|
*/
|
|
317
|
-
export function validatePlanActionCompleteness(plan) {
|
|
321
|
+
export function validatePlanActionCompleteness(plan, options = {}) {
|
|
318
322
|
const failures = [];
|
|
319
323
|
|
|
320
324
|
if (!plan || typeof plan !== 'object') {
|
|
@@ -670,6 +674,33 @@ export function validatePlanActionCompleteness(plan) {
|
|
|
670
674
|
_checkRequired(action, 'parameters.ref', action.parameters?.ref, expectedTag, unitId, failures);
|
|
671
675
|
_checkRequired(action, 'parameters.manifestDigest', action.parameters?.manifestDigest, frozen?.manifestDigest, unitId, failures);
|
|
672
676
|
}
|
|
677
|
+
// timeoutMs is mandatory for all marketplace install actions.
|
|
678
|
+
// Legacy plans (pre-v0.1.5) lack this field; legacyCompatibility
|
|
679
|
+
// relaxes the check for reconcile/verify paths only, and only when
|
|
680
|
+
// the property is genuinely absent (undefined). An explicit null is
|
|
681
|
+
// NOT "absent" -- it is an invalid value and always fails closed,
|
|
682
|
+
// like strings or out-of-range numbers, even in legacyCompatibility.
|
|
683
|
+
{
|
|
684
|
+
const raw = action.parameters?.timeoutMs;
|
|
685
|
+
if (raw === undefined) {
|
|
686
|
+
if (!options.legacyCompatibility) {
|
|
687
|
+
failures.push(
|
|
688
|
+
`unit "${unitId}", action "${action.id}": parameters.timeoutMs is missing, expected a valid timeout (30000-900000)`,
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
} else {
|
|
692
|
+
// Field is present -- always validate range/type, even in legacy mode
|
|
693
|
+
if (typeof raw !== 'number' || !Number.isFinite(raw) || !Number.isInteger(raw)) {
|
|
694
|
+
failures.push(
|
|
695
|
+
`unit "${unitId}", action "${action.id}": parameters.timeoutMs must be a finite integer, got: ${JSON.stringify(raw)}`,
|
|
696
|
+
);
|
|
697
|
+
} else if (raw < 30000 || raw > 900000) {
|
|
698
|
+
failures.push(
|
|
699
|
+
`unit "${unitId}", action "${action.id}": parameters.timeoutMs must be between 30000 and 900000, got: ${raw}`,
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
673
704
|
|
|
674
705
|
// Expected checks
|
|
675
706
|
_checkRequired(action, 'expected.installed', action.expected?.installed, true, unitId, failures);
|
|
@@ -746,6 +777,33 @@ export function validatePlanActionCompleteness(plan) {
|
|
|
746
777
|
_checkRequired(action, 'parameters.ref', action.parameters?.ref, expectedTag, unitId, failures);
|
|
747
778
|
_checkRequired(action, 'parameters.manifestDigest', action.parameters?.manifestDigest, frozen?.manifestDigest, unitId, failures);
|
|
748
779
|
}
|
|
780
|
+
// timeoutMs is mandatory for all marketplace install actions.
|
|
781
|
+
// Legacy plans (pre-v0.1.5) lack this field; legacyCompatibility
|
|
782
|
+
// relaxes the check for reconcile/verify paths only, and only when
|
|
783
|
+
// the property is genuinely absent (undefined). An explicit null is
|
|
784
|
+
// NOT "absent" -- it is an invalid value and always fails closed,
|
|
785
|
+
// like strings or out-of-range numbers, even in legacyCompatibility.
|
|
786
|
+
{
|
|
787
|
+
const raw = action.parameters?.timeoutMs;
|
|
788
|
+
if (raw === undefined) {
|
|
789
|
+
if (!options.legacyCompatibility) {
|
|
790
|
+
failures.push(
|
|
791
|
+
`unit "${unitId}", action "${action.id}": parameters.timeoutMs is missing, expected a valid timeout (30000-900000)`,
|
|
792
|
+
);
|
|
793
|
+
}
|
|
794
|
+
} else {
|
|
795
|
+
// Field is present -- always validate range/type, even in legacy mode
|
|
796
|
+
if (typeof raw !== 'number' || !Number.isFinite(raw) || !Number.isInteger(raw)) {
|
|
797
|
+
failures.push(
|
|
798
|
+
`unit "${unitId}", action "${action.id}": parameters.timeoutMs must be a finite integer, got: ${JSON.stringify(raw)}`,
|
|
799
|
+
);
|
|
800
|
+
} else if (raw < 30000 || raw > 900000) {
|
|
801
|
+
failures.push(
|
|
802
|
+
`unit "${unitId}", action "${action.id}": parameters.timeoutMs must be between 30000 and 900000, got: ${raw}`,
|
|
803
|
+
);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
}
|
|
749
807
|
|
|
750
808
|
// Expected checks
|
|
751
809
|
_checkRequired(action, 'expected.installed', action.expected?.installed, true, unitId, failures);
|