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
|
@@ -19947,7 +19947,7 @@ async function writePlanImmutable(planPath, plan) {
|
|
|
19947
19947
|
}
|
|
19948
19948
|
return { planPath, planDigest };
|
|
19949
19949
|
}
|
|
19950
|
-
function validatePlanActionCompleteness(plan) {
|
|
19950
|
+
function validatePlanActionCompleteness(plan, options = {}) {
|
|
19951
19951
|
const failures = [];
|
|
19952
19952
|
if (!plan || typeof plan !== "object") {
|
|
19953
19953
|
return { passed: false, details: { failures: ["plan is null or not an object"], expectedCount: 0, actualCount: 0 } };
|
|
@@ -20254,6 +20254,26 @@ function validatePlanActionCompleteness(plan) {
|
|
|
20254
20254
|
_checkRequired(action, "parameters.ref", action.parameters?.ref, expectedTag, unitId, failures);
|
|
20255
20255
|
_checkRequired(action, "parameters.manifestDigest", action.parameters?.manifestDigest, frozen?.manifestDigest, unitId, failures);
|
|
20256
20256
|
}
|
|
20257
|
+
{
|
|
20258
|
+
const raw = action.parameters?.timeoutMs;
|
|
20259
|
+
if (raw === void 0) {
|
|
20260
|
+
if (!options.legacyCompatibility) {
|
|
20261
|
+
failures.push(
|
|
20262
|
+
`unit "${unitId}", action "${action.id}": parameters.timeoutMs is missing, expected a valid timeout (30000-900000)`
|
|
20263
|
+
);
|
|
20264
|
+
}
|
|
20265
|
+
} else {
|
|
20266
|
+
if (typeof raw !== "number" || !Number.isFinite(raw) || !Number.isInteger(raw)) {
|
|
20267
|
+
failures.push(
|
|
20268
|
+
`unit "${unitId}", action "${action.id}": parameters.timeoutMs must be a finite integer, got: ${JSON.stringify(raw)}`
|
|
20269
|
+
);
|
|
20270
|
+
} else if (raw < 3e4 || raw > 9e5) {
|
|
20271
|
+
failures.push(
|
|
20272
|
+
`unit "${unitId}", action "${action.id}": parameters.timeoutMs must be between 30000 and 900000, got: ${raw}`
|
|
20273
|
+
);
|
|
20274
|
+
}
|
|
20275
|
+
}
|
|
20276
|
+
}
|
|
20257
20277
|
_checkRequired(action, "expected.installed", action.expected?.installed, true, unitId, failures);
|
|
20258
20278
|
_checkRequired(action, "expected.plugin", action.expected?.plugin, plugin, unitId, failures);
|
|
20259
20279
|
_checkRequired(action, "expected.marketplace", action.expected?.marketplace, marketplace, unitId, failures);
|
|
@@ -20322,6 +20342,26 @@ function validatePlanActionCompleteness(plan) {
|
|
|
20322
20342
|
_checkRequired(action, "parameters.ref", action.parameters?.ref, expectedTag, unitId, failures);
|
|
20323
20343
|
_checkRequired(action, "parameters.manifestDigest", action.parameters?.manifestDigest, frozen?.manifestDigest, unitId, failures);
|
|
20324
20344
|
}
|
|
20345
|
+
{
|
|
20346
|
+
const raw = action.parameters?.timeoutMs;
|
|
20347
|
+
if (raw === void 0) {
|
|
20348
|
+
if (!options.legacyCompatibility) {
|
|
20349
|
+
failures.push(
|
|
20350
|
+
`unit "${unitId}", action "${action.id}": parameters.timeoutMs is missing, expected a valid timeout (30000-900000)`
|
|
20351
|
+
);
|
|
20352
|
+
}
|
|
20353
|
+
} else {
|
|
20354
|
+
if (typeof raw !== "number" || !Number.isFinite(raw) || !Number.isInteger(raw)) {
|
|
20355
|
+
failures.push(
|
|
20356
|
+
`unit "${unitId}", action "${action.id}": parameters.timeoutMs must be a finite integer, got: ${JSON.stringify(raw)}`
|
|
20357
|
+
);
|
|
20358
|
+
} else if (raw < 3e4 || raw > 9e5) {
|
|
20359
|
+
failures.push(
|
|
20360
|
+
`unit "${unitId}", action "${action.id}": parameters.timeoutMs must be between 30000 and 900000, got: ${raw}`
|
|
20361
|
+
);
|
|
20362
|
+
}
|
|
20363
|
+
}
|
|
20364
|
+
}
|
|
20325
20365
|
_checkRequired(action, "expected.installed", action.expected?.installed, true, unitId, failures);
|
|
20326
20366
|
_checkRequired(action, "expected.plugin", action.expected?.plugin, plugin, unitId, failures);
|
|
20327
20367
|
_checkRequired(action, "expected.marketplace", action.expected?.marketplace, marketplace, unitId, failures);
|
|
@@ -68159,6 +68199,7 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
68159
68199
|
const claudeDist = (unit.distributions ?? []).find((d) => d.type === "claude-plugin");
|
|
68160
68200
|
if (claudeDist) {
|
|
68161
68201
|
const identity = marketplaceIdentity(claudeDist);
|
|
68202
|
+
const claudeTimeoutMs = Number.isInteger(claudeDist.timeoutMs) ? claudeDist.timeoutMs : 3e5;
|
|
68162
68203
|
actions.push({
|
|
68163
68204
|
id: `claude-marketplace-install-${unit.id}`,
|
|
68164
68205
|
type: "claude-marketplace-install",
|
|
@@ -68170,7 +68211,8 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
68170
68211
|
marketplace: identity.marketplace,
|
|
68171
68212
|
repo: unit.publicRepo,
|
|
68172
68213
|
version,
|
|
68173
|
-
entrySkill: identity.entrySkill
|
|
68214
|
+
entrySkill: identity.entrySkill,
|
|
68215
|
+
timeoutMs: claudeTimeoutMs
|
|
68174
68216
|
},
|
|
68175
68217
|
expected: {
|
|
68176
68218
|
installed: true,
|
|
@@ -68185,6 +68227,7 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
68185
68227
|
const codexDist = (unit.distributions ?? []).find((d) => d.type === "codex-plugin");
|
|
68186
68228
|
if (codexDist) {
|
|
68187
68229
|
const identity = marketplaceIdentity(codexDist);
|
|
68230
|
+
const codexTimeoutMs = Number.isInteger(codexDist.timeoutMs) ? codexDist.timeoutMs : 3e5;
|
|
68188
68231
|
actions.push({
|
|
68189
68232
|
id: `codex-marketplace-install-${unit.id}`,
|
|
68190
68233
|
type: "codex-marketplace-install",
|
|
@@ -68196,7 +68239,8 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
68196
68239
|
marketplace: identity.marketplace,
|
|
68197
68240
|
repo: unit.publicRepo,
|
|
68198
68241
|
version,
|
|
68199
|
-
entrySkill: identity.entrySkill
|
|
68242
|
+
entrySkill: identity.entrySkill,
|
|
68243
|
+
timeoutMs: codexTimeoutMs
|
|
68200
68244
|
},
|
|
68201
68245
|
expected: {
|
|
68202
68246
|
installed: true,
|
|
@@ -68336,6 +68380,7 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
68336
68380
|
const claudeDist = (unit.distributions ?? []).find((d) => d.type === "claude-plugin");
|
|
68337
68381
|
if (claudeDist) {
|
|
68338
68382
|
const identity = marketplaceIdentity(claudeDist);
|
|
68383
|
+
const claudeTimeoutMs = Number.isInteger(claudeDist.timeoutMs) ? claudeDist.timeoutMs : 3e5;
|
|
68339
68384
|
actions.push({
|
|
68340
68385
|
id: `claude-marketplace-install-${unit.id}`,
|
|
68341
68386
|
type: "claude-marketplace-install",
|
|
@@ -68350,7 +68395,8 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
68350
68395
|
version: unitVersion,
|
|
68351
68396
|
entrySkill: identity.entrySkill,
|
|
68352
68397
|
snapshotPath: asset.snapshotPath,
|
|
68353
|
-
manifestDigest: asset.manifestDigest
|
|
68398
|
+
manifestDigest: asset.manifestDigest,
|
|
68399
|
+
timeoutMs: claudeTimeoutMs
|
|
68354
68400
|
},
|
|
68355
68401
|
expected: {
|
|
68356
68402
|
installed: true,
|
|
@@ -68370,6 +68416,7 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
68370
68416
|
const codexDist = (unit.distributions ?? []).find((d) => d.type === "codex-plugin");
|
|
68371
68417
|
if (codexDist) {
|
|
68372
68418
|
const identity = marketplaceIdentity(codexDist);
|
|
68419
|
+
const codexTimeoutMs = Number.isInteger(codexDist.timeoutMs) ? codexDist.timeoutMs : 3e5;
|
|
68373
68420
|
actions.push({
|
|
68374
68421
|
id: `codex-marketplace-install-${unit.id}`,
|
|
68375
68422
|
type: "codex-marketplace-install",
|
|
@@ -68384,7 +68431,8 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
68384
68431
|
version: unitVersion,
|
|
68385
68432
|
entrySkill: identity.entrySkill,
|
|
68386
68433
|
snapshotPath: asset.snapshotPath,
|
|
68387
|
-
manifestDigest: asset.manifestDigest
|
|
68434
|
+
manifestDigest: asset.manifestDigest,
|
|
68435
|
+
timeoutMs: codexTimeoutMs
|
|
68388
68436
|
},
|
|
68389
68437
|
expected: {
|
|
68390
68438
|
installed: true,
|
|
@@ -69526,7 +69574,7 @@ async function reconcileRelease(options) {
|
|
|
69526
69574
|
}
|
|
69527
69575
|
await evidence.append({ phase: "safety-gate", gate: "plan-digest", status: "passed" });
|
|
69528
69576
|
await evidence.append({ phase: "safety-gate", gate: "action-completeness", status: "started" });
|
|
69529
|
-
const completenessResult = validatePlanActionCompleteness(plan);
|
|
69577
|
+
const completenessResult = validatePlanActionCompleteness(plan, { legacyCompatibility: true });
|
|
69530
69578
|
if (!completenessResult.passed) {
|
|
69531
69579
|
await evidence.append({
|
|
69532
69580
|
phase: "safety-gate",
|
|
@@ -71194,6 +71242,23 @@ function validateMarketplaceParams(params) {
|
|
|
71194
71242
|
}
|
|
71195
71243
|
return { valid: true, error: null };
|
|
71196
71244
|
}
|
|
71245
|
+
function resolveTimeoutMs(action) {
|
|
71246
|
+
const raw = action?.timeoutMs;
|
|
71247
|
+
if (raw === void 0) {
|
|
71248
|
+
return 3e5;
|
|
71249
|
+
}
|
|
71250
|
+
if (raw === null || typeof raw !== "number" || !Number.isFinite(raw) || !Number.isInteger(raw)) {
|
|
71251
|
+
throw new Error(
|
|
71252
|
+
`action.timeoutMs must be a finite integer, got: ${JSON.stringify(raw)}`
|
|
71253
|
+
);
|
|
71254
|
+
}
|
|
71255
|
+
if (raw < 3e4 || raw > 9e5) {
|
|
71256
|
+
throw new Error(
|
|
71257
|
+
`action.timeoutMs must be between 30000 and 900000, got: ${raw}`
|
|
71258
|
+
);
|
|
71259
|
+
}
|
|
71260
|
+
return raw;
|
|
71261
|
+
}
|
|
71197
71262
|
async function run4(cmd, args2, options = {}) {
|
|
71198
71263
|
return execFile9(cmd, args2, {
|
|
71199
71264
|
shell: false,
|
|
@@ -71663,11 +71728,21 @@ function createPluginMarketplaceAdapter(deps = {}) {
|
|
|
71663
71728
|
...baseEnv,
|
|
71664
71729
|
...consumer === "claude" ? { HOME: isolatedHome, CLAUDE_CONFIG_DIR: resolve18(isolatedHome, ".claude") } : { HOME: isolatedHome, CODEX_HOME: isolatedHome }
|
|
71665
71730
|
};
|
|
71731
|
+
let frozenTimeoutMs;
|
|
71732
|
+
try {
|
|
71733
|
+
frozenTimeoutMs = resolveTimeoutMs(action);
|
|
71734
|
+
} catch (timeoutErr) {
|
|
71735
|
+
return createResult({
|
|
71736
|
+
actionType,
|
|
71737
|
+
status: ActionStatus.EXECUTE_FAILED,
|
|
71738
|
+
error: timeoutErr.message
|
|
71739
|
+
});
|
|
71740
|
+
}
|
|
71666
71741
|
const ref = action.ref ?? `v${action.version}`;
|
|
71667
71742
|
let addOutput;
|
|
71668
71743
|
const marketplaceArgs = consumer === "claude" ? ["plugin", "marketplace", "add", `${action.repo}@${ref}`] : ["plugin", "marketplace", "add", action.repo, "--ref", ref, "--json"];
|
|
71669
71744
|
try {
|
|
71670
|
-
const addResult = await exec(cliCmd, marketplaceArgs, { env, cwd: context.root });
|
|
71745
|
+
const addResult = await exec(cliCmd, marketplaceArgs, { env, cwd: context.root, timeout: frozenTimeoutMs });
|
|
71671
71746
|
if (consumer === "codex") {
|
|
71672
71747
|
try {
|
|
71673
71748
|
addOutput = JSON.parse(addResult.stdout);
|
|
@@ -71703,7 +71778,7 @@ function createPluginMarketplaceAdapter(deps = {}) {
|
|
|
71703
71778
|
let installOutput;
|
|
71704
71779
|
const installArgs = consumer === "claude" ? ["plugin", "install", `${action.plugin}@${action.marketplace}`] : ["plugin", "add", `${action.plugin}@${action.marketplace}`, "--json"];
|
|
71705
71780
|
try {
|
|
71706
|
-
const installResult = await exec(cliCmd, installArgs, { env, cwd: context.root });
|
|
71781
|
+
const installResult = await exec(cliCmd, installArgs, { env, cwd: context.root, timeout: frozenTimeoutMs });
|
|
71707
71782
|
if (consumer === "codex") {
|
|
71708
71783
|
try {
|
|
71709
71784
|
installOutput = JSON.parse(installResult.stdout);
|
|
@@ -71893,6 +71968,17 @@ function createPluginMarketplaceAdapter(deps = {}) {
|
|
|
71893
71968
|
...baseEnv,
|
|
71894
71969
|
...consumer === "claude" ? { HOME: isolatedHome, CLAUDE_CONFIG_DIR: resolve18(isolatedHome, ".claude") } : { HOME: isolatedHome, CODEX_HOME: isolatedHome }
|
|
71895
71970
|
};
|
|
71971
|
+
let frozenTimeoutMs;
|
|
71972
|
+
try {
|
|
71973
|
+
frozenTimeoutMs = resolveTimeoutMs(action);
|
|
71974
|
+
} catch (timeoutErr) {
|
|
71975
|
+
return createResult({
|
|
71976
|
+
actionType,
|
|
71977
|
+
status: ActionStatus.OBSERVED,
|
|
71978
|
+
observation: { installed: false, error: timeoutErr.message },
|
|
71979
|
+
error: timeoutErr.message
|
|
71980
|
+
});
|
|
71981
|
+
}
|
|
71896
71982
|
let evidence = null;
|
|
71897
71983
|
try {
|
|
71898
71984
|
const evidenceRaw = await readFile16(resolve18(runDir, "evidence", `${consumer}-${action.plugin}`, "release-skill-install-evidence.json"), "utf8");
|
|
@@ -71920,7 +72006,7 @@ function createPluginMarketplaceAdapter(deps = {}) {
|
|
|
71920
72006
|
const listArgs = consumer === "claude" ? ["plugin", "list", "--json"] : ["plugin", "list", "--json"];
|
|
71921
72007
|
let listOutput;
|
|
71922
72008
|
try {
|
|
71923
|
-
const result = await exec(cliCmd, listArgs, { env, cwd: context.root });
|
|
72009
|
+
const result = await exec(cliCmd, listArgs, { env, cwd: context.root, timeout: frozenTimeoutMs });
|
|
71924
72010
|
listOutput = JSON.parse(result.stdout);
|
|
71925
72011
|
} catch (listErr) {
|
|
71926
72012
|
return createResult({
|
|
@@ -72248,6 +72334,7 @@ var init_plugin_marketplace = __esm({
|
|
|
72248
72334
|
STRICT_SEMVER_RE = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
|
|
72249
72335
|
__name(validateSafeRef, "validateSafeRef");
|
|
72250
72336
|
__name(validateMarketplaceParams, "validateMarketplaceParams");
|
|
72337
|
+
__name(resolveTimeoutMs, "resolveTimeoutMs");
|
|
72251
72338
|
__name(run4, "run");
|
|
72252
72339
|
__name(validateManifestFile, "validateManifestFile");
|
|
72253
72340
|
__name(checkRequiredFiles, "checkRequiredFiles");
|
|
@@ -72668,7 +72755,7 @@ async function verifyRelease(options) {
|
|
|
72668
72755
|
}
|
|
72669
72756
|
validateApproval(plan, approval, { clock: clockFn, requireUnexpired: false });
|
|
72670
72757
|
}
|
|
72671
|
-
const completenessResult = validatePlanActionCompleteness(plan);
|
|
72758
|
+
const completenessResult = validatePlanActionCompleteness(plan, { legacyCompatibility: true });
|
|
72672
72759
|
if (!completenessResult.passed) {
|
|
72673
72760
|
throw new ReleaseError(
|
|
72674
72761
|
GATE_FAILED,
|
|
@@ -200,6 +200,12 @@
|
|
|
200
200
|
},
|
|
201
201
|
"smokeExpectedJson": {
|
|
202
202
|
"type": "object"
|
|
203
|
+
},
|
|
204
|
+
"timeoutMs": {
|
|
205
|
+
"type": "integer",
|
|
206
|
+
"minimum": 30000,
|
|
207
|
+
"maximum": 900000,
|
|
208
|
+
"description": "Timeout in milliseconds for plugin marketplace install commands. Only valid for claude-plugin and codex-plugin distributions."
|
|
203
209
|
}
|
|
204
210
|
},
|
|
205
211
|
"allOf": [
|
|
@@ -219,6 +225,23 @@
|
|
|
219
225
|
]
|
|
220
226
|
}
|
|
221
227
|
},
|
|
228
|
+
{
|
|
229
|
+
"if": {
|
|
230
|
+
"required": [
|
|
231
|
+
"timeoutMs"
|
|
232
|
+
]
|
|
233
|
+
},
|
|
234
|
+
"then": {
|
|
235
|
+
"properties": {
|
|
236
|
+
"type": {
|
|
237
|
+
"enum": [
|
|
238
|
+
"claude-plugin",
|
|
239
|
+
"codex-plugin"
|
|
240
|
+
]
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
},
|
|
222
245
|
{
|
|
223
246
|
"if": {
|
|
224
247
|
"properties": {
|
|
@@ -19947,7 +19947,7 @@ async function writePlanImmutable(planPath, plan) {
|
|
|
19947
19947
|
}
|
|
19948
19948
|
return { planPath, planDigest };
|
|
19949
19949
|
}
|
|
19950
|
-
function validatePlanActionCompleteness(plan) {
|
|
19950
|
+
function validatePlanActionCompleteness(plan, options = {}) {
|
|
19951
19951
|
const failures = [];
|
|
19952
19952
|
if (!plan || typeof plan !== "object") {
|
|
19953
19953
|
return { passed: false, details: { failures: ["plan is null or not an object"], expectedCount: 0, actualCount: 0 } };
|
|
@@ -20254,6 +20254,26 @@ function validatePlanActionCompleteness(plan) {
|
|
|
20254
20254
|
_checkRequired(action, "parameters.ref", action.parameters?.ref, expectedTag, unitId, failures);
|
|
20255
20255
|
_checkRequired(action, "parameters.manifestDigest", action.parameters?.manifestDigest, frozen?.manifestDigest, unitId, failures);
|
|
20256
20256
|
}
|
|
20257
|
+
{
|
|
20258
|
+
const raw = action.parameters?.timeoutMs;
|
|
20259
|
+
if (raw === void 0) {
|
|
20260
|
+
if (!options.legacyCompatibility) {
|
|
20261
|
+
failures.push(
|
|
20262
|
+
`unit "${unitId}", action "${action.id}": parameters.timeoutMs is missing, expected a valid timeout (30000-900000)`
|
|
20263
|
+
);
|
|
20264
|
+
}
|
|
20265
|
+
} else {
|
|
20266
|
+
if (typeof raw !== "number" || !Number.isFinite(raw) || !Number.isInteger(raw)) {
|
|
20267
|
+
failures.push(
|
|
20268
|
+
`unit "${unitId}", action "${action.id}": parameters.timeoutMs must be a finite integer, got: ${JSON.stringify(raw)}`
|
|
20269
|
+
);
|
|
20270
|
+
} else if (raw < 3e4 || raw > 9e5) {
|
|
20271
|
+
failures.push(
|
|
20272
|
+
`unit "${unitId}", action "${action.id}": parameters.timeoutMs must be between 30000 and 900000, got: ${raw}`
|
|
20273
|
+
);
|
|
20274
|
+
}
|
|
20275
|
+
}
|
|
20276
|
+
}
|
|
20257
20277
|
_checkRequired(action, "expected.installed", action.expected?.installed, true, unitId, failures);
|
|
20258
20278
|
_checkRequired(action, "expected.plugin", action.expected?.plugin, plugin, unitId, failures);
|
|
20259
20279
|
_checkRequired(action, "expected.marketplace", action.expected?.marketplace, marketplace, unitId, failures);
|
|
@@ -20322,6 +20342,26 @@ function validatePlanActionCompleteness(plan) {
|
|
|
20322
20342
|
_checkRequired(action, "parameters.ref", action.parameters?.ref, expectedTag, unitId, failures);
|
|
20323
20343
|
_checkRequired(action, "parameters.manifestDigest", action.parameters?.manifestDigest, frozen?.manifestDigest, unitId, failures);
|
|
20324
20344
|
}
|
|
20345
|
+
{
|
|
20346
|
+
const raw = action.parameters?.timeoutMs;
|
|
20347
|
+
if (raw === void 0) {
|
|
20348
|
+
if (!options.legacyCompatibility) {
|
|
20349
|
+
failures.push(
|
|
20350
|
+
`unit "${unitId}", action "${action.id}": parameters.timeoutMs is missing, expected a valid timeout (30000-900000)`
|
|
20351
|
+
);
|
|
20352
|
+
}
|
|
20353
|
+
} else {
|
|
20354
|
+
if (typeof raw !== "number" || !Number.isFinite(raw) || !Number.isInteger(raw)) {
|
|
20355
|
+
failures.push(
|
|
20356
|
+
`unit "${unitId}", action "${action.id}": parameters.timeoutMs must be a finite integer, got: ${JSON.stringify(raw)}`
|
|
20357
|
+
);
|
|
20358
|
+
} else if (raw < 3e4 || raw > 9e5) {
|
|
20359
|
+
failures.push(
|
|
20360
|
+
`unit "${unitId}", action "${action.id}": parameters.timeoutMs must be between 30000 and 900000, got: ${raw}`
|
|
20361
|
+
);
|
|
20362
|
+
}
|
|
20363
|
+
}
|
|
20364
|
+
}
|
|
20325
20365
|
_checkRequired(action, "expected.installed", action.expected?.installed, true, unitId, failures);
|
|
20326
20366
|
_checkRequired(action, "expected.plugin", action.expected?.plugin, plugin, unitId, failures);
|
|
20327
20367
|
_checkRequired(action, "expected.marketplace", action.expected?.marketplace, marketplace, unitId, failures);
|
|
@@ -68159,6 +68199,7 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
68159
68199
|
const claudeDist = (unit.distributions ?? []).find((d) => d.type === "claude-plugin");
|
|
68160
68200
|
if (claudeDist) {
|
|
68161
68201
|
const identity = marketplaceIdentity(claudeDist);
|
|
68202
|
+
const claudeTimeoutMs = Number.isInteger(claudeDist.timeoutMs) ? claudeDist.timeoutMs : 3e5;
|
|
68162
68203
|
actions.push({
|
|
68163
68204
|
id: `claude-marketplace-install-${unit.id}`,
|
|
68164
68205
|
type: "claude-marketplace-install",
|
|
@@ -68170,7 +68211,8 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
68170
68211
|
marketplace: identity.marketplace,
|
|
68171
68212
|
repo: unit.publicRepo,
|
|
68172
68213
|
version,
|
|
68173
|
-
entrySkill: identity.entrySkill
|
|
68214
|
+
entrySkill: identity.entrySkill,
|
|
68215
|
+
timeoutMs: claudeTimeoutMs
|
|
68174
68216
|
},
|
|
68175
68217
|
expected: {
|
|
68176
68218
|
installed: true,
|
|
@@ -68185,6 +68227,7 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
68185
68227
|
const codexDist = (unit.distributions ?? []).find((d) => d.type === "codex-plugin");
|
|
68186
68228
|
if (codexDist) {
|
|
68187
68229
|
const identity = marketplaceIdentity(codexDist);
|
|
68230
|
+
const codexTimeoutMs = Number.isInteger(codexDist.timeoutMs) ? codexDist.timeoutMs : 3e5;
|
|
68188
68231
|
actions.push({
|
|
68189
68232
|
id: `codex-marketplace-install-${unit.id}`,
|
|
68190
68233
|
type: "codex-marketplace-install",
|
|
@@ -68196,7 +68239,8 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
68196
68239
|
marketplace: identity.marketplace,
|
|
68197
68240
|
repo: unit.publicRepo,
|
|
68198
68241
|
version,
|
|
68199
|
-
entrySkill: identity.entrySkill
|
|
68242
|
+
entrySkill: identity.entrySkill,
|
|
68243
|
+
timeoutMs: codexTimeoutMs
|
|
68200
68244
|
},
|
|
68201
68245
|
expected: {
|
|
68202
68246
|
installed: true,
|
|
@@ -68336,6 +68380,7 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
68336
68380
|
const claudeDist = (unit.distributions ?? []).find((d) => d.type === "claude-plugin");
|
|
68337
68381
|
if (claudeDist) {
|
|
68338
68382
|
const identity = marketplaceIdentity(claudeDist);
|
|
68383
|
+
const claudeTimeoutMs = Number.isInteger(claudeDist.timeoutMs) ? claudeDist.timeoutMs : 3e5;
|
|
68339
68384
|
actions.push({
|
|
68340
68385
|
id: `claude-marketplace-install-${unit.id}`,
|
|
68341
68386
|
type: "claude-marketplace-install",
|
|
@@ -68350,7 +68395,8 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
68350
68395
|
version: unitVersion,
|
|
68351
68396
|
entrySkill: identity.entrySkill,
|
|
68352
68397
|
snapshotPath: asset.snapshotPath,
|
|
68353
|
-
manifestDigest: asset.manifestDigest
|
|
68398
|
+
manifestDigest: asset.manifestDigest,
|
|
68399
|
+
timeoutMs: claudeTimeoutMs
|
|
68354
68400
|
},
|
|
68355
68401
|
expected: {
|
|
68356
68402
|
installed: true,
|
|
@@ -68370,6 +68416,7 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
68370
68416
|
const codexDist = (unit.distributions ?? []).find((d) => d.type === "codex-plugin");
|
|
68371
68417
|
if (codexDist) {
|
|
68372
68418
|
const identity = marketplaceIdentity(codexDist);
|
|
68419
|
+
const codexTimeoutMs = Number.isInteger(codexDist.timeoutMs) ? codexDist.timeoutMs : 3e5;
|
|
68373
68420
|
actions.push({
|
|
68374
68421
|
id: `codex-marketplace-install-${unit.id}`,
|
|
68375
68422
|
type: "codex-marketplace-install",
|
|
@@ -68384,7 +68431,8 @@ function buildExternalActions(unitResults, resolvedVersions, productionAssets) {
|
|
|
68384
68431
|
version: unitVersion,
|
|
68385
68432
|
entrySkill: identity.entrySkill,
|
|
68386
68433
|
snapshotPath: asset.snapshotPath,
|
|
68387
|
-
manifestDigest: asset.manifestDigest
|
|
68434
|
+
manifestDigest: asset.manifestDigest,
|
|
68435
|
+
timeoutMs: codexTimeoutMs
|
|
68388
68436
|
},
|
|
68389
68437
|
expected: {
|
|
68390
68438
|
installed: true,
|
|
@@ -69526,7 +69574,7 @@ async function reconcileRelease(options) {
|
|
|
69526
69574
|
}
|
|
69527
69575
|
await evidence.append({ phase: "safety-gate", gate: "plan-digest", status: "passed" });
|
|
69528
69576
|
await evidence.append({ phase: "safety-gate", gate: "action-completeness", status: "started" });
|
|
69529
|
-
const completenessResult = validatePlanActionCompleteness(plan);
|
|
69577
|
+
const completenessResult = validatePlanActionCompleteness(plan, { legacyCompatibility: true });
|
|
69530
69578
|
if (!completenessResult.passed) {
|
|
69531
69579
|
await evidence.append({
|
|
69532
69580
|
phase: "safety-gate",
|
|
@@ -71194,6 +71242,23 @@ function validateMarketplaceParams(params) {
|
|
|
71194
71242
|
}
|
|
71195
71243
|
return { valid: true, error: null };
|
|
71196
71244
|
}
|
|
71245
|
+
function resolveTimeoutMs(action) {
|
|
71246
|
+
const raw = action?.timeoutMs;
|
|
71247
|
+
if (raw === void 0) {
|
|
71248
|
+
return 3e5;
|
|
71249
|
+
}
|
|
71250
|
+
if (raw === null || typeof raw !== "number" || !Number.isFinite(raw) || !Number.isInteger(raw)) {
|
|
71251
|
+
throw new Error(
|
|
71252
|
+
`action.timeoutMs must be a finite integer, got: ${JSON.stringify(raw)}`
|
|
71253
|
+
);
|
|
71254
|
+
}
|
|
71255
|
+
if (raw < 3e4 || raw > 9e5) {
|
|
71256
|
+
throw new Error(
|
|
71257
|
+
`action.timeoutMs must be between 30000 and 900000, got: ${raw}`
|
|
71258
|
+
);
|
|
71259
|
+
}
|
|
71260
|
+
return raw;
|
|
71261
|
+
}
|
|
71197
71262
|
async function run4(cmd, args2, options = {}) {
|
|
71198
71263
|
return execFile9(cmd, args2, {
|
|
71199
71264
|
shell: false,
|
|
@@ -71663,11 +71728,21 @@ function createPluginMarketplaceAdapter(deps = {}) {
|
|
|
71663
71728
|
...baseEnv,
|
|
71664
71729
|
...consumer === "claude" ? { HOME: isolatedHome, CLAUDE_CONFIG_DIR: resolve18(isolatedHome, ".claude") } : { HOME: isolatedHome, CODEX_HOME: isolatedHome }
|
|
71665
71730
|
};
|
|
71731
|
+
let frozenTimeoutMs;
|
|
71732
|
+
try {
|
|
71733
|
+
frozenTimeoutMs = resolveTimeoutMs(action);
|
|
71734
|
+
} catch (timeoutErr) {
|
|
71735
|
+
return createResult({
|
|
71736
|
+
actionType,
|
|
71737
|
+
status: ActionStatus.EXECUTE_FAILED,
|
|
71738
|
+
error: timeoutErr.message
|
|
71739
|
+
});
|
|
71740
|
+
}
|
|
71666
71741
|
const ref = action.ref ?? `v${action.version}`;
|
|
71667
71742
|
let addOutput;
|
|
71668
71743
|
const marketplaceArgs = consumer === "claude" ? ["plugin", "marketplace", "add", `${action.repo}@${ref}`] : ["plugin", "marketplace", "add", action.repo, "--ref", ref, "--json"];
|
|
71669
71744
|
try {
|
|
71670
|
-
const addResult = await exec(cliCmd, marketplaceArgs, { env, cwd: context.root });
|
|
71745
|
+
const addResult = await exec(cliCmd, marketplaceArgs, { env, cwd: context.root, timeout: frozenTimeoutMs });
|
|
71671
71746
|
if (consumer === "codex") {
|
|
71672
71747
|
try {
|
|
71673
71748
|
addOutput = JSON.parse(addResult.stdout);
|
|
@@ -71703,7 +71778,7 @@ function createPluginMarketplaceAdapter(deps = {}) {
|
|
|
71703
71778
|
let installOutput;
|
|
71704
71779
|
const installArgs = consumer === "claude" ? ["plugin", "install", `${action.plugin}@${action.marketplace}`] : ["plugin", "add", `${action.plugin}@${action.marketplace}`, "--json"];
|
|
71705
71780
|
try {
|
|
71706
|
-
const installResult = await exec(cliCmd, installArgs, { env, cwd: context.root });
|
|
71781
|
+
const installResult = await exec(cliCmd, installArgs, { env, cwd: context.root, timeout: frozenTimeoutMs });
|
|
71707
71782
|
if (consumer === "codex") {
|
|
71708
71783
|
try {
|
|
71709
71784
|
installOutput = JSON.parse(installResult.stdout);
|
|
@@ -71893,6 +71968,17 @@ function createPluginMarketplaceAdapter(deps = {}) {
|
|
|
71893
71968
|
...baseEnv,
|
|
71894
71969
|
...consumer === "claude" ? { HOME: isolatedHome, CLAUDE_CONFIG_DIR: resolve18(isolatedHome, ".claude") } : { HOME: isolatedHome, CODEX_HOME: isolatedHome }
|
|
71895
71970
|
};
|
|
71971
|
+
let frozenTimeoutMs;
|
|
71972
|
+
try {
|
|
71973
|
+
frozenTimeoutMs = resolveTimeoutMs(action);
|
|
71974
|
+
} catch (timeoutErr) {
|
|
71975
|
+
return createResult({
|
|
71976
|
+
actionType,
|
|
71977
|
+
status: ActionStatus.OBSERVED,
|
|
71978
|
+
observation: { installed: false, error: timeoutErr.message },
|
|
71979
|
+
error: timeoutErr.message
|
|
71980
|
+
});
|
|
71981
|
+
}
|
|
71896
71982
|
let evidence = null;
|
|
71897
71983
|
try {
|
|
71898
71984
|
const evidenceRaw = await readFile16(resolve18(runDir, "evidence", `${consumer}-${action.plugin}`, "release-skill-install-evidence.json"), "utf8");
|
|
@@ -71920,7 +72006,7 @@ function createPluginMarketplaceAdapter(deps = {}) {
|
|
|
71920
72006
|
const listArgs = consumer === "claude" ? ["plugin", "list", "--json"] : ["plugin", "list", "--json"];
|
|
71921
72007
|
let listOutput;
|
|
71922
72008
|
try {
|
|
71923
|
-
const result = await exec(cliCmd, listArgs, { env, cwd: context.root });
|
|
72009
|
+
const result = await exec(cliCmd, listArgs, { env, cwd: context.root, timeout: frozenTimeoutMs });
|
|
71924
72010
|
listOutput = JSON.parse(result.stdout);
|
|
71925
72011
|
} catch (listErr) {
|
|
71926
72012
|
return createResult({
|
|
@@ -72248,6 +72334,7 @@ var init_plugin_marketplace = __esm({
|
|
|
72248
72334
|
STRICT_SEMVER_RE = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
|
|
72249
72335
|
__name(validateSafeRef, "validateSafeRef");
|
|
72250
72336
|
__name(validateMarketplaceParams, "validateMarketplaceParams");
|
|
72337
|
+
__name(resolveTimeoutMs, "resolveTimeoutMs");
|
|
72251
72338
|
__name(run4, "run");
|
|
72252
72339
|
__name(validateManifestFile, "validateManifestFile");
|
|
72253
72340
|
__name(checkRequiredFiles, "checkRequiredFiles");
|
|
@@ -72668,7 +72755,7 @@ async function verifyRelease(options) {
|
|
|
72668
72755
|
}
|
|
72669
72756
|
validateApproval(plan, approval, { clock: clockFn, requireUnexpired: false });
|
|
72670
72757
|
}
|
|
72671
|
-
const completenessResult = validatePlanActionCompleteness(plan);
|
|
72758
|
+
const completenessResult = validatePlanActionCompleteness(plan, { legacyCompatibility: true });
|
|
72672
72759
|
if (!completenessResult.passed) {
|
|
72673
72760
|
throw new ReleaseError(
|
|
72674
72761
|
GATE_FAILED,
|
package/package.json
CHANGED
|
@@ -200,6 +200,12 @@
|
|
|
200
200
|
},
|
|
201
201
|
"smokeExpectedJson": {
|
|
202
202
|
"type": "object"
|
|
203
|
+
},
|
|
204
|
+
"timeoutMs": {
|
|
205
|
+
"type": "integer",
|
|
206
|
+
"minimum": 30000,
|
|
207
|
+
"maximum": 900000,
|
|
208
|
+
"description": "Timeout in milliseconds for plugin marketplace install commands. Only valid for claude-plugin and codex-plugin distributions."
|
|
203
209
|
}
|
|
204
210
|
},
|
|
205
211
|
"allOf": [
|
|
@@ -219,6 +225,23 @@
|
|
|
219
225
|
]
|
|
220
226
|
}
|
|
221
227
|
},
|
|
228
|
+
{
|
|
229
|
+
"if": {
|
|
230
|
+
"required": [
|
|
231
|
+
"timeoutMs"
|
|
232
|
+
]
|
|
233
|
+
},
|
|
234
|
+
"then": {
|
|
235
|
+
"properties": {
|
|
236
|
+
"type": {
|
|
237
|
+
"enum": [
|
|
238
|
+
"claude-plugin",
|
|
239
|
+
"codex-plugin"
|
|
240
|
+
]
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
},
|
|
222
245
|
{
|
|
223
246
|
"if": {
|
|
224
247
|
"properties": {
|
|
@@ -185,6 +185,42 @@ function validateMarketplaceParams(params) {
|
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
|
|
188
|
+
/**
|
|
189
|
+
* Resolve and validate the frozen timeoutMs from the expanded adapter action.
|
|
190
|
+
*
|
|
191
|
+
* The publish/reconcile/verify call path expands plan actions as
|
|
192
|
+
* `{ actionType, ...action.parameters }`, so `parameters.timeoutMs` in the
|
|
193
|
+
* plan becomes `action.timeoutMs` at the adapter level. This function reads
|
|
194
|
+
* from the top-level action, not from a nested `parameters` sub-object.
|
|
195
|
+
*
|
|
196
|
+
* Rules:
|
|
197
|
+
* - Missing field (undefined): returns 300000 default (legacy compatibility).
|
|
198
|
+
* - Present but null/invalid (null, string, NaN, Infinity, non-integer,
|
|
199
|
+
* out of range): fail-closed, throws.
|
|
200
|
+
* - Valid integer in [30000, 900000]: returns the value as-is.
|
|
201
|
+
*
|
|
202
|
+
* @param {object} action - The expanded adapter action (top-level).
|
|
203
|
+
* @returns {number} Validated timeout in milliseconds.
|
|
204
|
+
* @throws {Error} If the value is present but invalid.
|
|
205
|
+
*/
|
|
206
|
+
function resolveTimeoutMs(action) {
|
|
207
|
+
const raw = action?.timeoutMs;
|
|
208
|
+
if (raw === undefined) {
|
|
209
|
+
return 300000;
|
|
210
|
+
}
|
|
211
|
+
if (raw === null || typeof raw !== 'number' || !Number.isFinite(raw) || !Number.isInteger(raw)) {
|
|
212
|
+
throw new Error(
|
|
213
|
+
`action.timeoutMs must be a finite integer, got: ${JSON.stringify(raw)}`,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
if (raw < 30000 || raw > 900000) {
|
|
217
|
+
throw new Error(
|
|
218
|
+
`action.timeoutMs must be between 30000 and 900000, got: ${raw}`,
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
return raw;
|
|
222
|
+
}
|
|
223
|
+
|
|
188
224
|
/**
|
|
189
225
|
* Run a CLI command using execFile (never shell: true).
|
|
190
226
|
*/
|
|
@@ -792,6 +828,23 @@ export function createPluginMarketplaceAdapter(deps = {}) {
|
|
|
792
828
|
};
|
|
793
829
|
// Ensure real HOME/CODEX_HOME don't leak back (already overridden above)
|
|
794
830
|
|
|
831
|
+
// Resolve frozen timeoutMs from the expanded action (top-level,
|
|
832
|
+
// not action.parameters -- the publish/reconcile/verify call path
|
|
833
|
+
// expands plan action as { actionType, ...action.parameters }).
|
|
834
|
+
// Default to 300000 for old plans that lack the field.
|
|
835
|
+
// Fail closed on invalid values (null, non-integer, non-finite,
|
|
836
|
+
// out of range).
|
|
837
|
+
let frozenTimeoutMs;
|
|
838
|
+
try {
|
|
839
|
+
frozenTimeoutMs = resolveTimeoutMs(action);
|
|
840
|
+
} catch (timeoutErr) {
|
|
841
|
+
return createResult({
|
|
842
|
+
actionType,
|
|
843
|
+
status: ActionStatus.EXECUTE_FAILED,
|
|
844
|
+
error: timeoutErr.message,
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
|
|
795
848
|
// Step 1: Add marketplace
|
|
796
849
|
const ref = action.ref ?? `v${action.version}`;
|
|
797
850
|
let addOutput;
|
|
@@ -799,7 +852,7 @@ export function createPluginMarketplaceAdapter(deps = {}) {
|
|
|
799
852
|
? ['plugin', 'marketplace', 'add', `${action.repo}@${ref}`]
|
|
800
853
|
: ['plugin', 'marketplace', 'add', action.repo, '--ref', ref, '--json'];
|
|
801
854
|
try {
|
|
802
|
-
const addResult = await exec(cliCmd, marketplaceArgs, { env, cwd: context.root });
|
|
855
|
+
const addResult = await exec(cliCmd, marketplaceArgs, { env, cwd: context.root, timeout: frozenTimeoutMs });
|
|
803
856
|
if (consumer === 'codex') {
|
|
804
857
|
try {
|
|
805
858
|
addOutput = JSON.parse(addResult.stdout);
|
|
@@ -839,7 +892,7 @@ export function createPluginMarketplaceAdapter(deps = {}) {
|
|
|
839
892
|
? ['plugin', 'install', `${action.plugin}@${action.marketplace}`]
|
|
840
893
|
: ['plugin', 'add', `${action.plugin}@${action.marketplace}`, '--json'];
|
|
841
894
|
try {
|
|
842
|
-
const installResult = await exec(cliCmd, installArgs, { env, cwd: context.root });
|
|
895
|
+
const installResult = await exec(cliCmd, installArgs, { env, cwd: context.root, timeout: frozenTimeoutMs });
|
|
843
896
|
if (consumer === 'codex') {
|
|
844
897
|
try {
|
|
845
898
|
installOutput = JSON.parse(installResult.stdout);
|
|
@@ -1053,6 +1106,20 @@ export function createPluginMarketplaceAdapter(deps = {}) {
|
|
|
1053
1106
|
: { HOME: isolatedHome, CODEX_HOME: isolatedHome }),
|
|
1054
1107
|
};
|
|
1055
1108
|
|
|
1109
|
+
// Resolve frozen timeoutMs from the expanded action (top-level).
|
|
1110
|
+
// Default to 300000 for old plans. Fail closed on invalid values.
|
|
1111
|
+
let frozenTimeoutMs;
|
|
1112
|
+
try {
|
|
1113
|
+
frozenTimeoutMs = resolveTimeoutMs(action);
|
|
1114
|
+
} catch (timeoutErr) {
|
|
1115
|
+
return createResult({
|
|
1116
|
+
actionType,
|
|
1117
|
+
status: ActionStatus.OBSERVED,
|
|
1118
|
+
observation: { installed: false, error: timeoutErr.message },
|
|
1119
|
+
error: timeoutErr.message,
|
|
1120
|
+
});
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1056
1123
|
// Read execute evidence — mandatory for observe validation
|
|
1057
1124
|
let evidence = null;
|
|
1058
1125
|
try {
|
|
@@ -1095,7 +1162,7 @@ export function createPluginMarketplaceAdapter(deps = {}) {
|
|
|
1095
1162
|
|
|
1096
1163
|
let listOutput;
|
|
1097
1164
|
try {
|
|
1098
|
-
const result = await exec(cliCmd, listArgs, { env, cwd: context.root });
|
|
1165
|
+
const result = await exec(cliCmd, listArgs, { env, cwd: context.root, timeout: frozenTimeoutMs });
|
|
1099
1166
|
listOutput = JSON.parse(result.stdout);
|
|
1100
1167
|
} catch (listErr) {
|
|
1101
1168
|
return createResult({
|