release-skill 0.3.0 → 0.4.0
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 +23 -3
- package/INSTALL.md +34 -110
- package/INSTALL.zh-CN.md +17 -83
- package/README.md +42 -65
- package/README.zh-CN.md +37 -57
- 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 +138 -231
- package/adapters/claude/schemas/release-plan.schema.json +7 -0
- package/adapters/claude/schemas/release-run.schema.json +43 -0
- package/adapters/claude/skills/release-help/SKILL.md +5 -5
- package/adapters/claude/skills/release-prepare/SKILL.md +6 -15
- package/adapters/claude/skills/release-publish/SKILL.md +5 -6
- package/adapters/claude/skills/release-reconcile/SKILL.md +2 -2
- package/adapters/claude/skills/release-verify/SKILL.md +4 -6
- package/adapters/codex/.codex-plugin/plugin.json +2 -2
- package/adapters/codex/bin/release-skill.bundle.mjs +138 -231
- package/adapters/codex/schemas/release-plan.schema.json +7 -0
- package/adapters/codex/schemas/release-run.schema.json +43 -0
- package/adapters/codex/skills/release-help/SKILL.md +5 -5
- package/adapters/codex/skills/release-prepare/SKILL.md +6 -15
- package/adapters/codex/skills/release-publish/SKILL.md +5 -6
- package/adapters/codex/skills/release-reconcile/SKILL.md +2 -2
- package/adapters/codex/skills/release-verify/SKILL.md +4 -6
- package/adapters/kimi/.kimi-plugin/plugin.json +1 -1
- package/adapters/kimi/bin/release-skill.bundle.mjs +138 -231
- package/adapters/kimi/schemas/release-plan.schema.json +7 -0
- package/adapters/kimi/schemas/release-run.schema.json +43 -0
- package/adapters/kimi/skills/release-help/SKILL.md +5 -5
- package/adapters/kimi/skills/release-prepare/SKILL.md +6 -15
- package/adapters/kimi/skills/release-publish/SKILL.md +5 -6
- package/adapters/kimi/skills/release-reconcile/SKILL.md +2 -2
- package/adapters/kimi/skills/release-verify/SKILL.md +4 -6
- package/adapters/workbuddy/.codebuddy-plugin/plugin.json +1 -1
- package/adapters/workbuddy/bin/release-skill.bundle.mjs +138 -231
- package/adapters/workbuddy/schemas/release-plan.schema.json +7 -0
- package/adapters/workbuddy/schemas/release-run.schema.json +43 -0
- package/adapters/workbuddy/skills/release-help/SKILL.md +5 -5
- package/adapters/workbuddy/skills/release-prepare/SKILL.md +6 -15
- package/adapters/workbuddy/skills/release-publish/SKILL.md +5 -6
- package/adapters/workbuddy/skills/release-reconcile/SKILL.md +2 -2
- package/adapters/workbuddy/skills/release-verify/SKILL.md +4 -6
- package/bin/release-skill-cli.mjs +45 -48
- package/bin/release-skill.bundle.mjs +138 -231
- package/package.json +1 -1
- package/references/01-state-machine.md +1 -1
- package/references/06-adapter-contract.md +6 -5
- package/schemas/release-plan.schema.json +7 -0
- package/schemas/release-run.schema.json +43 -0
- package/skills/release-help/SKILL.md +5 -5
- package/skills/release-prepare/SKILL.md +6 -15
- package/skills/release-publish/SKILL.md +5 -6
- package/skills/release-reconcile/SKILL.md +2 -2
- package/skills/release-verify/SKILL.md +4 -6
- package/skills-src/release-help/SKILL.md +5 -5
- package/skills-src/release-prepare/SKILL.md +6 -15
- package/skills-src/release-publish/SKILL.md +5 -6
- package/skills-src/release-reconcile/SKILL.md +2 -2
- package/skills-src/release-verify/SKILL.md +4 -6
- package/src/commands/approve.mjs +8 -6
- package/src/commands/hooks.mjs +4 -8
- package/src/commands/prepare.mjs +13 -50
- package/src/commands/publish.mjs +0 -8
- package/src/commands/reconcile.mjs +3 -37
- package/src/commands/ship.mjs +55 -77
- package/src/commands/verify.mjs +56 -19
- package/src/core/skill-resource-closure.mjs +7 -1
|
@@ -9,7 +9,7 @@ const __bundlePkgRoot = __bundleResolve(__bundleDirname(__bundleFileURLToPath(im
|
|
|
9
9
|
// Provide a real require() for CJS packages bundled into ESM (e.g. yaml, ajv).
|
|
10
10
|
const __bundleRealRequire = __bundleCreateRequire(import.meta.url);
|
|
11
11
|
// Package identity injected at build time — closure-independent --version probe.
|
|
12
|
-
const __bundlePkg = Object.freeze({"name":"release-skill","version":"0.
|
|
12
|
+
const __bundlePkg = Object.freeze({"name":"release-skill","version":"0.4.0"});
|
|
13
13
|
|
|
14
14
|
var __create = Object.create;
|
|
15
15
|
var __defProp = Object.defineProperty;
|
|
@@ -24274,10 +24274,11 @@ function evaluateConsumerSkillResourceClosureReceipts(plan, receipts) {
|
|
|
24274
24274
|
"kimi-plugin",
|
|
24275
24275
|
"codebuddy-plugin"
|
|
24276
24276
|
]);
|
|
24277
|
+
const humanConsumerTypes = plan.humanConsumersStrategy === "manualFollowUps" ? /* @__PURE__ */ new Set(["kimi-plugin", "codebuddy-plugin"]) : /* @__PURE__ */ new Set();
|
|
24277
24278
|
const expectedKeys = [];
|
|
24278
24279
|
for (const unit of plan.units ?? []) {
|
|
24279
24280
|
for (const distribution of unit.distributions ?? []) {
|
|
24280
|
-
if (supported.has(distribution.type)) {
|
|
24281
|
+
if (supported.has(distribution.type) && !humanConsumerTypes.has(distribution.type)) {
|
|
24281
24282
|
expectedKeys.push(`${unit.id}:${distribution.type}`);
|
|
24282
24283
|
}
|
|
24283
24284
|
}
|
|
@@ -40520,11 +40521,11 @@ var require_lib7 = __commonJS({
|
|
|
40520
40521
|
stream.pipe(checker);
|
|
40521
40522
|
stream.on("error", reject);
|
|
40522
40523
|
checker.on("error", reject);
|
|
40523
|
-
let
|
|
40524
|
+
let verified;
|
|
40524
40525
|
checker.on("verified", (s) => {
|
|
40525
|
-
|
|
40526
|
+
verified = s;
|
|
40526
40527
|
});
|
|
40527
|
-
checker.on("end", () => resolve33(
|
|
40528
|
+
checker.on("end", () => resolve33(verified));
|
|
40528
40529
|
checker.resume();
|
|
40529
40530
|
});
|
|
40530
40531
|
}
|
|
@@ -64312,8 +64313,8 @@ var require_timestamp3 = __commonJS({
|
|
|
64312
64313
|
verifySignature(key) {
|
|
64313
64314
|
const signedAttrs = this.signedAttrsObj.toDER();
|
|
64314
64315
|
signedAttrs[0] = 49;
|
|
64315
|
-
const
|
|
64316
|
-
if (!
|
|
64316
|
+
const verified = crypto.verify(signedAttrs, key, this.signatureValue, this.signatureAlgorithm);
|
|
64317
|
+
if (!verified) {
|
|
64317
64318
|
throw new error_1.RFC3161TimestampVerificationError("signature verification failed");
|
|
64318
64319
|
}
|
|
64319
64320
|
}
|
|
@@ -69374,8 +69375,8 @@ var require_sct2 = __commonJS({
|
|
|
69374
69375
|
logID: sct.logID,
|
|
69375
69376
|
targetDate: sct.datetime
|
|
69376
69377
|
});
|
|
69377
|
-
const
|
|
69378
|
-
if (!
|
|
69378
|
+
const verified = validCTLogs.some((log) => sct.verify(preCert.buffer, log.publicKey));
|
|
69379
|
+
if (!verified) {
|
|
69379
69380
|
throw new error_1.VerificationError({
|
|
69380
69381
|
code: "CERTIFICATE_ERROR",
|
|
69381
69382
|
message: "SCT verification failed"
|
|
@@ -69692,13 +69693,13 @@ var require_set2 = __commonJS({
|
|
|
69692
69693
|
logID: entry.logId.keyId,
|
|
69693
69694
|
targetDate: new Date(Number(entry.integratedTime) * 1e3)
|
|
69694
69695
|
});
|
|
69695
|
-
const
|
|
69696
|
+
const verified = validTLogs.some((tlog) => {
|
|
69696
69697
|
const payload = toVerificationPayload(entry);
|
|
69697
69698
|
const data = Buffer.from(core_1.json.canonicalize(payload), "utf8");
|
|
69698
69699
|
const signature = entry.inclusionPromise.signedEntryTimestamp;
|
|
69699
69700
|
return core_1.crypto.verify(data, tlog.publicKey, signature);
|
|
69700
69701
|
});
|
|
69701
|
-
if (!
|
|
69702
|
+
if (!verified) {
|
|
69702
69703
|
throw new error_1.VerificationError({
|
|
69703
69704
|
code: "TLOG_INCLUSION_PROMISE_ERROR",
|
|
69704
69705
|
message: "inclusion promise could not be verified"
|
|
@@ -69736,7 +69737,7 @@ var require_tsa3 = __commonJS({
|
|
|
69736
69737
|
serialNumber: timestamp.signerSerialNumber,
|
|
69737
69738
|
issuer: timestamp.signerIssuer
|
|
69738
69739
|
});
|
|
69739
|
-
const
|
|
69740
|
+
const verified = timestampAuthorities.some((ca) => {
|
|
69740
69741
|
try {
|
|
69741
69742
|
verifyTimestampForCA(timestamp, data, ca);
|
|
69742
69743
|
return true;
|
|
@@ -69744,7 +69745,7 @@ var require_tsa3 = __commonJS({
|
|
|
69744
69745
|
return false;
|
|
69745
69746
|
}
|
|
69746
69747
|
});
|
|
69747
|
-
if (!
|
|
69748
|
+
if (!verified) {
|
|
69748
69749
|
throw new error_1.VerificationError({
|
|
69749
69750
|
code: "TIMESTAMP_ERROR",
|
|
69750
69751
|
message: "timestamp could not be verified"
|
|
@@ -81249,39 +81250,16 @@ async function prepareRelease(options) {
|
|
|
81249
81250
|
if (declaredHooks.length > 0) {
|
|
81250
81251
|
await evidence.append({
|
|
81251
81252
|
phase: "hook-authorization",
|
|
81252
|
-
status: "
|
|
81253
|
+
status: "authorized",
|
|
81253
81254
|
hookCount: declaredHooks.length,
|
|
81254
81255
|
hooks: declaredHooks.map((h) => `${h.name}: ${h.executable} ${h.args.join(" ")}`)
|
|
81255
81256
|
});
|
|
81256
|
-
if (hooksAuthorized !== true) {
|
|
81257
|
-
const hookList = declaredHooks.map((h) => ` - ${h.name}: executable="${h.executable}", args=[${h.args.join(", ")}], cwd="${h.cwd}"`).join("\n");
|
|
81258
|
-
await evidence.append({
|
|
81259
|
-
phase: "hook-authorization",
|
|
81260
|
-
status: "denied",
|
|
81261
|
-
reason: "hooks not explicitly authorized"
|
|
81262
|
-
});
|
|
81263
|
-
throw new ReleaseError(
|
|
81264
|
-
GATE_FAILED,
|
|
81265
|
-
`project declares ${declaredHooks.length} hook(s) that will be executed as arbitrary local processes.
|
|
81266
|
-
These hooks are NOT sandboxed \u2014 they may write to the filesystem outside the project, access local credentials, or make network calls.
|
|
81267
|
-
The following hooks will run:
|
|
81268
|
-
${hookList}
|
|
81269
|
-
|
|
81270
|
-
To proceed, pass --acknowledge-hook-side-effects (CLI) or hooksAuthorized=true (API). Authorization means you accept hook side-effect risks; it does NOT make hooks safe.`,
|
|
81271
|
-
{ hookNames: declaredHooks.map((h) => h.name), hookCount: declaredHooks.length }
|
|
81272
|
-
);
|
|
81273
|
-
}
|
|
81274
|
-
await evidence.append({
|
|
81275
|
-
phase: "hook-authorization",
|
|
81276
|
-
status: "authorized",
|
|
81277
|
-
hookCount: declaredHooks.length
|
|
81278
|
-
});
|
|
81279
81257
|
}
|
|
81280
81258
|
const declaredVerificationGates = config.verificationGates ?? [];
|
|
81281
81259
|
if (declaredVerificationGates.length > 0) {
|
|
81282
81260
|
await evidence.append({
|
|
81283
81261
|
phase: "verification-gate-authorization",
|
|
81284
|
-
status: "
|
|
81262
|
+
status: "authorized",
|
|
81285
81263
|
gateCount: declaredVerificationGates.length,
|
|
81286
81264
|
gates: declaredVerificationGates.map((gate) => ({
|
|
81287
81265
|
id: gate.id,
|
|
@@ -81293,23 +81271,6 @@ To proceed, pass --acknowledge-hook-side-effects (CLI) or hooksAuthorized=true (
|
|
|
81293
81271
|
cwd: gate.cwd
|
|
81294
81272
|
}))
|
|
81295
81273
|
});
|
|
81296
|
-
if (verificationGatesAuthorized !== true) {
|
|
81297
|
-
await evidence.append({
|
|
81298
|
-
phase: "verification-gate-authorization",
|
|
81299
|
-
status: "denied",
|
|
81300
|
-
gateCount: declaredVerificationGates.length
|
|
81301
|
-
});
|
|
81302
|
-
throw new ReleaseError(
|
|
81303
|
-
GATE_FAILED,
|
|
81304
|
-
`project declares ${declaredVerificationGates.length} verification gate(s). They run local project commands without a network sandbox. To proceed, pass --acknowledge-gate-side-effects (CLI) or verificationGatesAuthorized=true (API).`,
|
|
81305
|
-
{ gateIds: declaredVerificationGates.map((gate) => gate.id) }
|
|
81306
|
-
);
|
|
81307
|
-
}
|
|
81308
|
-
await evidence.append({
|
|
81309
|
-
phase: "verification-gate-authorization",
|
|
81310
|
-
status: "authorized",
|
|
81311
|
-
gateCount: declaredVerificationGates.length
|
|
81312
|
-
});
|
|
81313
81274
|
}
|
|
81314
81275
|
await evidence.append({ phase: "hooks", status: "started" });
|
|
81315
81276
|
await runDeclaredHooks(config, realRoot, evidence, options.runHookFn ?? runHook, {
|
|
@@ -82080,6 +82041,9 @@ To proceed, pass --acknowledge-hook-side-effects (CLI) or hooksAuthorized=true (
|
|
|
82080
82041
|
const frozenDistributionsMap = new Map(units.map((u) => [u.id, u.distributions]));
|
|
82081
82042
|
const externalActions = buildExternalActions(unitResults, resolvedVersions, productionAssets, externalMarketplaceFreezes, frozenDistributionsMap);
|
|
82082
82043
|
const overallSnapshotDigest = sha256Hex(snapshotDigests.join(":"));
|
|
82044
|
+
const hasHumanConsumerActions = externalActions.some(
|
|
82045
|
+
(a) => a.type === "kimi-marketplace-install" || a.type === "codebuddy-marketplace-install"
|
|
82046
|
+
);
|
|
82083
82047
|
const plan = {
|
|
82084
82048
|
planVersion: 2,
|
|
82085
82049
|
status: "PREPARED",
|
|
@@ -82102,6 +82066,7 @@ To proceed, pass --acknowledge-hook-side-effects (CLI) or hooksAuthorized=true (
|
|
|
82102
82066
|
},
|
|
82103
82067
|
verificationGates: config.verificationGates ?? [],
|
|
82104
82068
|
snapshotDigest: overallSnapshotDigest,
|
|
82069
|
+
...hasHumanConsumerActions ? { humanConsumersStrategy: "manualFollowUps" } : {},
|
|
82105
82070
|
...production ? {
|
|
82106
82071
|
production: {
|
|
82107
82072
|
mode: "github-npm-v1",
|
|
@@ -82224,16 +82189,10 @@ import { resolve as resolve24 } from "node:path";
|
|
|
82224
82189
|
async function validateDeclaredHooks(options = {}) {
|
|
82225
82190
|
const {
|
|
82226
82191
|
root = process.cwd(),
|
|
82227
|
-
hooksAuthorized,
|
|
82192
|
+
hooksAuthorized: _hooksAuthorized,
|
|
82228
82193
|
hookCache = true,
|
|
82229
82194
|
runDir = resolve24(root, ".release-skill", "runs", `hooks-${Date.now()}`)
|
|
82230
82195
|
} = options;
|
|
82231
|
-
if (hooksAuthorized !== true) {
|
|
82232
|
-
throw new ReleaseError(
|
|
82233
|
-
GATE_FAILED,
|
|
82234
|
-
"hooks validate executes declared project commands; pass --acknowledge-hook-side-effects"
|
|
82235
|
-
);
|
|
82236
|
-
}
|
|
82237
82196
|
const { config, configDigest } = await loadProjectConfig({ root });
|
|
82238
82197
|
await mkdir12(runDir, { recursive: true });
|
|
82239
82198
|
const evidence = createEvidenceWriter({
|
|
@@ -82259,7 +82218,6 @@ var init_hooks2 = __esm({
|
|
|
82259
82218
|
await init_config();
|
|
82260
82219
|
init_evidence();
|
|
82261
82220
|
await init_prepare();
|
|
82262
|
-
init_errors();
|
|
82263
82221
|
__name(validateDeclaredHooks, "validateDeclaredHooks");
|
|
82264
82222
|
}
|
|
82265
82223
|
});
|
|
@@ -82560,7 +82518,7 @@ function defaultClock() {
|
|
|
82560
82518
|
async function approvePlan(options) {
|
|
82561
82519
|
const {
|
|
82562
82520
|
planPath,
|
|
82563
|
-
expectedDigest,
|
|
82521
|
+
expectedDigest: expectedDigestInput,
|
|
82564
82522
|
actor,
|
|
82565
82523
|
expiresInMs = 24 * 60 * 60 * 1e3,
|
|
82566
82524
|
// 24 hours
|
|
@@ -82571,9 +82529,6 @@ async function approvePlan(options) {
|
|
|
82571
82529
|
if (!planPath || typeof planPath !== "string") {
|
|
82572
82530
|
throw new ReleaseError(PLAN_DIGEST_MISMATCH, "planPath must be a non-empty string");
|
|
82573
82531
|
}
|
|
82574
|
-
if (!expectedDigest || typeof expectedDigest !== "string") {
|
|
82575
|
-
throw new ReleaseError(PLAN_DIGEST_MISMATCH, "expectedDigest must be a non-empty string");
|
|
82576
|
-
}
|
|
82577
82532
|
if (!actor || typeof actor !== "string") {
|
|
82578
82533
|
throw new ReleaseError(GATE_FAILED, "actor must be a non-empty string");
|
|
82579
82534
|
}
|
|
@@ -82599,6 +82554,7 @@ async function approvePlan(options) {
|
|
|
82599
82554
|
}
|
|
82600
82555
|
const actualDigest = computePlanDigest(plan);
|
|
82601
82556
|
assertImmutablePlanAuthority(planPath, plan);
|
|
82557
|
+
const expectedDigest = expectedDigestInput ?? actualDigest;
|
|
82602
82558
|
if (actualDigest !== expectedDigest) {
|
|
82603
82559
|
throw new ReleaseError(
|
|
82604
82560
|
PLAN_DIGEST_MISMATCH,
|
|
@@ -83234,7 +83190,6 @@ async function publishRelease(options) {
|
|
|
83234
83190
|
clock: clockOpt,
|
|
83235
83191
|
captureBaselineFn,
|
|
83236
83192
|
productionMode = false,
|
|
83237
|
-
productionConfirmation,
|
|
83238
83193
|
observePreviousPublicBaselineFn,
|
|
83239
83194
|
observeRetrySleep
|
|
83240
83195
|
} = options ?? {};
|
|
@@ -83291,13 +83246,6 @@ async function publishRelease(options) {
|
|
|
83291
83246
|
if (!plan.production.assetRoot || plan.production.assetRoot === ".") {
|
|
83292
83247
|
throw new ReleaseError(GATE_FAILED, "production plan requires a dedicated assetRoot");
|
|
83293
83248
|
}
|
|
83294
|
-
if (!productionConfirmation || productionConfirmation !== actualDigest) {
|
|
83295
|
-
throw new ReleaseError(
|
|
83296
|
-
GATE_FAILED,
|
|
83297
|
-
"production confirmation must exactly match the current plan digest",
|
|
83298
|
-
{ planDigest: actualDigest }
|
|
83299
|
-
);
|
|
83300
|
-
}
|
|
83301
83249
|
}
|
|
83302
83250
|
await evidence.append({ phase: "safety-gate", gate: "action-completeness", status: "started" });
|
|
83303
83251
|
const completenessResult = validatePlanActionCompleteness(plan);
|
|
@@ -84009,7 +83957,6 @@ async function reconcileRelease(options) {
|
|
|
84009
83957
|
root = process.cwd(),
|
|
84010
83958
|
clock: clockOpt,
|
|
84011
83959
|
captureBaselineFn,
|
|
84012
|
-
productionConfirmation,
|
|
84013
83960
|
observePreviousPublicBaselineFn,
|
|
84014
83961
|
observeRetrySleep
|
|
84015
83962
|
} = options ?? {};
|
|
@@ -84179,21 +84126,6 @@ async function reconcileRelease(options) {
|
|
|
84179
84126
|
{ sourceRunId: sourceRun.runId, sourceRunStatus: sourceRun.status }
|
|
84180
84127
|
);
|
|
84181
84128
|
}
|
|
84182
|
-
const planActionsById = new Map(
|
|
84183
|
-
(plan.externalActions ?? []).map((action) => [action.id, action])
|
|
84184
|
-
);
|
|
84185
|
-
const hasNonMarketplaceRetryCandidate = sourceRun.checkpoints.some((checkpoint) => {
|
|
84186
|
-
if (checkpoint.status === "succeeded") return false;
|
|
84187
|
-
const action = planActionsById.get(checkpoint.actionId);
|
|
84188
|
-
return action && !isMarketplaceAction(action.type);
|
|
84189
|
-
});
|
|
84190
|
-
if (plan.production?.mode === "github-npm-v1" && hasNonMarketplaceRetryCandidate && productionConfirmation !== actualDigest) {
|
|
84191
|
-
throw new ReleaseError(
|
|
84192
|
-
GATE_FAILED,
|
|
84193
|
-
"production reconcile confirmation must exactly match the current plan digest before retry",
|
|
84194
|
-
{ planDigest: actualDigest }
|
|
84195
|
-
);
|
|
84196
|
-
}
|
|
84197
84129
|
await evidence.append({
|
|
84198
84130
|
phase: "safety-gate",
|
|
84199
84131
|
gate: "source-run-load",
|
|
@@ -84622,13 +84554,6 @@ async function reconcileRelease(options) {
|
|
|
84622
84554
|
}
|
|
84623
84555
|
const nonMarketplaceRetries = actionsToRetry.filter((a) => !isMarketplaceAction(a.type));
|
|
84624
84556
|
if (nonMarketplaceRetries.length > 0) {
|
|
84625
|
-
if (plan.production?.mode === "github-npm-v1" && productionConfirmation !== actualDigest) {
|
|
84626
|
-
throw new ReleaseError(
|
|
84627
|
-
GATE_FAILED,
|
|
84628
|
-
"production reconcile confirmation must exactly match the current plan digest before retry",
|
|
84629
|
-
{ planDigest: actualDigest, actionsToRetry: nonMarketplaceRetries.map((action) => action.id) }
|
|
84630
|
-
);
|
|
84631
|
-
}
|
|
84632
84557
|
if (!approval) {
|
|
84633
84558
|
throw new ReleaseError(
|
|
84634
84559
|
GATE_FAILED,
|
|
@@ -85473,7 +85398,7 @@ async function verifyRelease(options) {
|
|
|
85473
85398
|
runDir: runDirOpt,
|
|
85474
85399
|
clock: clockOpt,
|
|
85475
85400
|
npmExecutor,
|
|
85476
|
-
verificationGatesAuthorized,
|
|
85401
|
+
verificationGatesAuthorized: _verificationGatesAuthorized,
|
|
85477
85402
|
gateEnv,
|
|
85478
85403
|
previousVerifyRun
|
|
85479
85404
|
} = options ?? {};
|
|
@@ -85522,13 +85447,6 @@ async function verifyRelease(options) {
|
|
|
85522
85447
|
await evidence.append({ phase: "verify", step: "plan-load", status: "started" });
|
|
85523
85448
|
const consumerGates = (plan.verificationGates ?? []).filter((gate) => gate.phase === "consumer-verify");
|
|
85524
85449
|
const configuredSmokeBins = (plan.units ?? []).flatMap((unit) => (unit.distributions ?? []).filter((distribution) => distribution.type === "npm" && distribution.smokeBin).map((distribution) => ({ unitId: unit.id, smokeBin: distribution.smokeBin })));
|
|
85525
|
-
if ((consumerGates.length > 0 || configuredSmokeBins.length > 0) && verificationGatesAuthorized !== true) {
|
|
85526
|
-
throw new ReleaseError(
|
|
85527
|
-
GATE_FAILED,
|
|
85528
|
-
`plan declares ${consumerGates.length} consumer verification gate(s) and ${configuredSmokeBins.length} npm CLI smoke process(es). They execute installed project code without an OS or network sandbox. To proceed, pass --acknowledge-gate-side-effects (CLI) or verificationGatesAuthorized=true (API).`,
|
|
85529
|
-
{ gateIds: consumerGates.map((gate) => gate.id), configuredSmokeBins }
|
|
85530
|
-
);
|
|
85531
|
-
}
|
|
85532
85450
|
await evidence.append({ phase: "verify", step: "plan-load", status: "passed" });
|
|
85533
85451
|
await evidence.append({ phase: "verify", step: "source-run-load", status: "started" });
|
|
85534
85452
|
const sourceRun = await loadRun(sourceRunPath, {
|
|
@@ -85723,7 +85641,8 @@ async function verifyRelease(options) {
|
|
|
85723
85641
|
}
|
|
85724
85642
|
}
|
|
85725
85643
|
}
|
|
85726
|
-
const
|
|
85644
|
+
const isHumanConsumerFollowUp = plan.humanConsumersStrategy === "manualFollowUps";
|
|
85645
|
+
const missingManualAttestations = isHumanConsumerFollowUp ? [] : await collectMissingManualAttestations({
|
|
85727
85646
|
actions,
|
|
85728
85647
|
adapterRegistry,
|
|
85729
85648
|
plan,
|
|
@@ -85744,6 +85663,7 @@ async function verifyRelease(options) {
|
|
|
85744
85663
|
{ requirements: missingManualAttestations }
|
|
85745
85664
|
);
|
|
85746
85665
|
}
|
|
85666
|
+
const manualFollowUps = [];
|
|
85747
85667
|
const actionResults = await Promise.allSettled(actions.map(async (action) => {
|
|
85748
85668
|
const adapterActionType = ADAPTER_ACTION_TYPE_MAP2[action.type];
|
|
85749
85669
|
if (!adapterActionType) {
|
|
@@ -85766,6 +85686,33 @@ async function verifyRelease(options) {
|
|
|
85766
85686
|
);
|
|
85767
85687
|
}
|
|
85768
85688
|
if (isMarketplaceAction(action.type)) {
|
|
85689
|
+
const isHumanConsumerPlatform = action.type === "kimi-marketplace-install" || action.type === "codebuddy-marketplace-install";
|
|
85690
|
+
if (isHumanConsumerFollowUp && isHumanConsumerPlatform) {
|
|
85691
|
+
const platform = action.type === "kimi-marketplace-install" ? "kimi" : "codebuddy";
|
|
85692
|
+
manualFollowUps.push({
|
|
85693
|
+
actionId: action.id,
|
|
85694
|
+
platform,
|
|
85695
|
+
plugin: action.parameters?.plugin,
|
|
85696
|
+
version: action.parameters?.version,
|
|
85697
|
+
unitId: action.unitId,
|
|
85698
|
+
verifiedBySystem: false,
|
|
85699
|
+
reason: "human consumer platform \u2014 installation is a manual post-release task; not verified by system"
|
|
85700
|
+
});
|
|
85701
|
+
adapterChecks.push({
|
|
85702
|
+
actionId: action.id,
|
|
85703
|
+
actionType: action.type,
|
|
85704
|
+
status: "SKIPPED",
|
|
85705
|
+
reason: "manual-follow-up"
|
|
85706
|
+
});
|
|
85707
|
+
await evidence.append({
|
|
85708
|
+
phase: "verify-marketplace",
|
|
85709
|
+
actionId: action.id,
|
|
85710
|
+
actionType: action.type,
|
|
85711
|
+
status: "SKIPPED",
|
|
85712
|
+
reason: "manual-follow-up"
|
|
85713
|
+
});
|
|
85714
|
+
return;
|
|
85715
|
+
}
|
|
85769
85716
|
const marketplaceContext = {
|
|
85770
85717
|
externalWritesAuthorized: false,
|
|
85771
85718
|
isolatedConsumerWritesAuthorized: true,
|
|
@@ -86143,6 +86090,7 @@ async function verifyRelease(options) {
|
|
|
86143
86090
|
gateResults: consumerGateResults,
|
|
86144
86091
|
consumerVerificationReceipts,
|
|
86145
86092
|
skillResourceClosureReceipts,
|
|
86093
|
+
...manualFollowUps.length > 0 ? { manualFollowUps } : {},
|
|
86146
86094
|
startedAt: clockFn(),
|
|
86147
86095
|
finishedAt: clockFn()
|
|
86148
86096
|
};
|
|
@@ -86163,7 +86111,8 @@ async function verifyRelease(options) {
|
|
|
86163
86111
|
status: VERIFIED,
|
|
86164
86112
|
adapterChecks,
|
|
86165
86113
|
smokeTest,
|
|
86166
|
-
gateResults: consumerGateResults
|
|
86114
|
+
gateResults: consumerGateResults,
|
|
86115
|
+
...manualFollowUps.length > 0 ? { manualFollowUps } : {}
|
|
86167
86116
|
};
|
|
86168
86117
|
} catch (err) {
|
|
86169
86118
|
await evidence.append({
|
|
@@ -86567,8 +86516,7 @@ function publicState(state) {
|
|
|
86567
86516
|
status: state.status,
|
|
86568
86517
|
statePath: state.statePath,
|
|
86569
86518
|
targetVersion: state.targetVersion,
|
|
86570
|
-
...state.
|
|
86571
|
-
hookAuthorizationDigest: state.hookAuthorizationDigest,
|
|
86519
|
+
...state.hooks && state.hooks.length > 0 ? {
|
|
86572
86520
|
hooks: state.hooks
|
|
86573
86521
|
} : {},
|
|
86574
86522
|
...state.planPath ? {
|
|
@@ -86577,25 +86525,32 @@ function publicState(state) {
|
|
|
86577
86525
|
evidenceDir: state.evidenceDir,
|
|
86578
86526
|
warnings: state.warnings ?? []
|
|
86579
86527
|
} : {},
|
|
86528
|
+
...state.approvalSummary ? { approvalSummary: state.approvalSummary } : {},
|
|
86580
86529
|
...state.approvalPath ? { approvalPath: state.approvalPath } : {},
|
|
86581
86530
|
...state.sourceRunPath ? { sourceRunPath: state.sourceRunPath } : {},
|
|
86582
86531
|
...state.requirements ? { requirements: state.requirements } : {},
|
|
86532
|
+
...state.manualFollowUps ? { manualFollowUps: state.manualFollowUps } : {},
|
|
86583
86533
|
...state.metadataUpdate ? { metadataUpdate: state.metadataUpdate } : {},
|
|
86584
|
-
verificationGateAuthorizationIncludedInPlanApproval:
|
|
86585
|
-
postVerifyMetadataUpdateIncludedInPlanApproval:
|
|
86534
|
+
verificationGateAuthorizationIncludedInPlanApproval: true,
|
|
86535
|
+
postVerifyMetadataUpdateIncludedInPlanApproval: true
|
|
86586
86536
|
};
|
|
86587
86537
|
}
|
|
86588
|
-
function
|
|
86589
|
-
|
|
86590
|
-
|
|
86591
|
-
|
|
86592
|
-
|
|
86593
|
-
|
|
86594
|
-
|
|
86595
|
-
|
|
86596
|
-
|
|
86597
|
-
|
|
86598
|
-
|
|
86538
|
+
async function buildApprovalSummary(planPath) {
|
|
86539
|
+
try {
|
|
86540
|
+
const plan = JSON.parse(await readFile27(planPath, "utf8"));
|
|
86541
|
+
const units = (plan.units ?? []).map((unit) => ({
|
|
86542
|
+
id: unit.id,
|
|
86543
|
+
targetVersion: unit.targetVersion ?? unit.version
|
|
86544
|
+
}));
|
|
86545
|
+
const actions = (plan.externalActions ?? []).map((action) => ({
|
|
86546
|
+
id: action.id,
|
|
86547
|
+
type: action.type,
|
|
86548
|
+
unitId: action.unitId
|
|
86549
|
+
}));
|
|
86550
|
+
return { units, actions };
|
|
86551
|
+
} catch {
|
|
86552
|
+
return { units: [], actions: [] };
|
|
86553
|
+
}
|
|
86599
86554
|
}
|
|
86600
86555
|
async function advanceShip(options = {}, injected = {}) {
|
|
86601
86556
|
const root = resolve29(options.root ?? process.cwd());
|
|
@@ -86609,65 +86564,21 @@ async function advanceShip(options = {}, injected = {}) {
|
|
|
86609
86564
|
}
|
|
86610
86565
|
if (!state) {
|
|
86611
86566
|
const loaded = await deps.loadProjectConfig({ root });
|
|
86612
|
-
const
|
|
86613
|
-
const hooks = authority.hooks;
|
|
86614
|
-
const hookAuthorizationDigest = authority.digest;
|
|
86567
|
+
const hooks = Object.keys(loaded.config.hooks ?? {}).sort();
|
|
86615
86568
|
state = {
|
|
86616
|
-
schemaVersion:
|
|
86569
|
+
schemaVersion: 2,
|
|
86617
86570
|
root,
|
|
86618
86571
|
statePath,
|
|
86619
86572
|
targetVersion: options.targetVersion ?? null,
|
|
86620
86573
|
configDigest: loaded.configDigest,
|
|
86621
86574
|
hooks,
|
|
86622
|
-
|
|
86623
|
-
status: hooks.length > 0 ? "NEEDS_HOOK_AUTHORIZATION" : "NEW",
|
|
86575
|
+
status: "NEW",
|
|
86624
86576
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
86625
86577
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
86626
86578
|
};
|
|
86627
86579
|
await writeJsonAtomic(statePath, state);
|
|
86628
|
-
if (hooks.length > 0 && options.hookAuthorizationDigest !== hookAuthorizationDigest) {
|
|
86629
|
-
return publicState(state);
|
|
86630
|
-
}
|
|
86631
86580
|
}
|
|
86632
86581
|
if (state.status === "NEEDS_HOOK_AUTHORIZATION") {
|
|
86633
|
-
const loaded = await deps.loadProjectConfig({ root });
|
|
86634
|
-
const current = hookAuthority(loaded, state.targetVersion);
|
|
86635
|
-
if (loaded.configDigest !== state.configDigest || current.digest !== state.hookAuthorizationDigest) {
|
|
86636
|
-
state = {
|
|
86637
|
-
...state,
|
|
86638
|
-
configDigest: loaded.configDigest,
|
|
86639
|
-
hooks: current.hooks,
|
|
86640
|
-
hookAuthorizationDigest: current.digest,
|
|
86641
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
86642
|
-
};
|
|
86643
|
-
await writeJsonAtomic(statePath, state);
|
|
86644
|
-
if (verified.status === "VERIFIED" && deps.updatePreviousPublicBaselines) {
|
|
86645
|
-
try {
|
|
86646
|
-
state.metadataUpdate = await deps.updatePreviousPublicBaselines({
|
|
86647
|
-
root,
|
|
86648
|
-
planPath: state.planPath
|
|
86649
|
-
});
|
|
86650
|
-
} catch (error) {
|
|
86651
|
-
state.metadataUpdate = {
|
|
86652
|
-
status: "FAILED",
|
|
86653
|
-
error: error.message
|
|
86654
|
-
};
|
|
86655
|
-
}
|
|
86656
|
-
state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
86657
|
-
await writeJsonAtomic(statePath, state);
|
|
86658
|
-
}
|
|
86659
|
-
return publicState(state);
|
|
86660
|
-
}
|
|
86661
|
-
if (options.hookAuthorizationDigest !== state.hookAuthorizationDigest) {
|
|
86662
|
-
if (options.hookAuthorizationDigest) {
|
|
86663
|
-
throw new ReleaseError(
|
|
86664
|
-
PLAN_DIGEST_MISMATCH,
|
|
86665
|
-
"hook authorization digest does not match the current config, hooks and target version"
|
|
86666
|
-
);
|
|
86667
|
-
}
|
|
86668
|
-
return publicState(state);
|
|
86669
|
-
}
|
|
86670
|
-
state.hookAuthorizedBy = options.actor ?? null;
|
|
86671
86582
|
state.status = "NEW";
|
|
86672
86583
|
state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
86673
86584
|
await writeJsonAtomic(statePath, state);
|
|
@@ -86675,17 +86586,15 @@ async function advanceShip(options = {}, injected = {}) {
|
|
|
86675
86586
|
if (state.status === "NEW") {
|
|
86676
86587
|
const loaded = await deps.loadProjectConfig({ root });
|
|
86677
86588
|
if (loaded.configDigest !== state.configDigest) {
|
|
86678
|
-
const
|
|
86589
|
+
const hooks = Object.keys(loaded.config.hooks ?? {}).sort();
|
|
86679
86590
|
state = {
|
|
86680
86591
|
...state,
|
|
86681
86592
|
configDigest: loaded.configDigest,
|
|
86682
|
-
hooks
|
|
86683
|
-
|
|
86684
|
-
status: current.hooks.length > 0 ? "NEEDS_HOOK_AUTHORIZATION" : "NEW",
|
|
86593
|
+
hooks,
|
|
86594
|
+
status: "NEW",
|
|
86685
86595
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
86686
86596
|
};
|
|
86687
86597
|
await writeJsonAtomic(statePath, state);
|
|
86688
|
-
if (state.status === "NEEDS_HOOK_AUTHORIZATION") return publicState(state);
|
|
86689
86598
|
}
|
|
86690
86599
|
const prepared = await deps.prepareRelease({
|
|
86691
86600
|
root,
|
|
@@ -86693,7 +86602,7 @@ async function advanceShip(options = {}, injected = {}) {
|
|
|
86693
86602
|
offline: false,
|
|
86694
86603
|
production: true,
|
|
86695
86604
|
hooksAuthorized: true,
|
|
86696
|
-
verificationGatesAuthorized:
|
|
86605
|
+
verificationGatesAuthorized: true,
|
|
86697
86606
|
hookCache: true
|
|
86698
86607
|
});
|
|
86699
86608
|
let transportPreflight = null;
|
|
@@ -86702,6 +86611,7 @@ async function advanceShip(options = {}, injected = {}) {
|
|
|
86702
86611
|
transportPreflight = await deps.preflightGitTransports(frozenPlan);
|
|
86703
86612
|
process.env.RELEASE_SKILL_GIT_TRANSPORT = transportPreflight.transport;
|
|
86704
86613
|
}
|
|
86614
|
+
const approvalSummary = await buildApprovalSummary(prepared.planPath);
|
|
86705
86615
|
state = {
|
|
86706
86616
|
...state,
|
|
86707
86617
|
status: "NEEDS_PLAN_APPROVAL",
|
|
@@ -86709,6 +86619,7 @@ async function advanceShip(options = {}, injected = {}) {
|
|
|
86709
86619
|
planDigest: prepared.planDigest,
|
|
86710
86620
|
evidenceDir: prepared.evidenceDir,
|
|
86711
86621
|
warnings: prepared.warnings,
|
|
86622
|
+
approvalSummary,
|
|
86712
86623
|
...transportPreflight ? {
|
|
86713
86624
|
gitTransport: transportPreflight.transport,
|
|
86714
86625
|
gitTransportPreflight: transportPreflight.repositories
|
|
@@ -86718,8 +86629,10 @@ async function advanceShip(options = {}, injected = {}) {
|
|
|
86718
86629
|
await writeJsonAtomic(statePath, state);
|
|
86719
86630
|
}
|
|
86720
86631
|
if (state.status === "NEEDS_PLAN_APPROVAL") {
|
|
86721
|
-
|
|
86722
|
-
if (
|
|
86632
|
+
const approveRequested = options.approve === true || typeof options.planApprovalDigest === "string" && options.planApprovalDigest.length > 0;
|
|
86633
|
+
if (!approveRequested) return publicState(state);
|
|
86634
|
+
if (options.approve === true) {
|
|
86635
|
+
} else if (options.planApprovalDigest !== state.planDigest) {
|
|
86723
86636
|
throw new ReleaseError(PLAN_DIGEST_MISMATCH, "ship plan approval digest does not match the frozen plan");
|
|
86724
86637
|
}
|
|
86725
86638
|
if (!options.actor) {
|
|
@@ -86751,8 +86664,7 @@ async function advanceShip(options = {}, injected = {}) {
|
|
|
86751
86664
|
approvalPath: state.approvalPath,
|
|
86752
86665
|
adapterRegistry: options.adapterRegistry,
|
|
86753
86666
|
root,
|
|
86754
|
-
productionMode: true
|
|
86755
|
-
productionConfirmation: state.planDigest
|
|
86667
|
+
productionMode: true
|
|
86756
86668
|
});
|
|
86757
86669
|
state = {
|
|
86758
86670
|
...state,
|
|
@@ -86768,8 +86680,7 @@ async function advanceShip(options = {}, injected = {}) {
|
|
|
86768
86680
|
sourceRunPath: state.sourceRunPath,
|
|
86769
86681
|
approvalPath: state.approvalPath,
|
|
86770
86682
|
adapterRegistry: options.adapterRegistry,
|
|
86771
|
-
root
|
|
86772
|
-
productionConfirmation: state.planDigest
|
|
86683
|
+
root
|
|
86773
86684
|
});
|
|
86774
86685
|
state = {
|
|
86775
86686
|
...state,
|
|
@@ -86781,7 +86692,7 @@ async function advanceShip(options = {}, injected = {}) {
|
|
|
86781
86692
|
}
|
|
86782
86693
|
if (state.status === "PUBLISHED" || state.status === "NEEDS_MANUAL_ATTESTATIONS") {
|
|
86783
86694
|
try {
|
|
86784
|
-
const
|
|
86695
|
+
const verified = await deps.verifyRelease({
|
|
86785
86696
|
planPath: state.planPath,
|
|
86786
86697
|
sourceRunPath: state.sourceRunPath,
|
|
86787
86698
|
adapterRegistry: options.adapterRegistry,
|
|
@@ -86790,9 +86701,10 @@ async function advanceShip(options = {}, injected = {}) {
|
|
|
86790
86701
|
});
|
|
86791
86702
|
state = {
|
|
86792
86703
|
...state,
|
|
86793
|
-
status:
|
|
86794
|
-
verifyRunPath:
|
|
86704
|
+
status: verified.status,
|
|
86705
|
+
verifyRunPath: verified.runPath,
|
|
86795
86706
|
requirements: void 0,
|
|
86707
|
+
manualFollowUps: verified.manualFollowUps ?? void 0,
|
|
86796
86708
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
86797
86709
|
};
|
|
86798
86710
|
await writeJsonAtomic(statePath, state);
|
|
@@ -86817,7 +86729,7 @@ var init_ship = __esm({
|
|
|
86817
86729
|
__name(readState, "readState");
|
|
86818
86730
|
__name(defaultDependencies, "defaultDependencies");
|
|
86819
86731
|
__name(publicState, "publicState");
|
|
86820
|
-
__name(
|
|
86732
|
+
__name(buildApprovalSummary, "buildApprovalSummary");
|
|
86821
86733
|
__name(advanceShip, "advanceShip");
|
|
86822
86734
|
}
|
|
86823
86735
|
});
|
|
@@ -90993,13 +90905,13 @@ async function performEnvironmentChecks() {
|
|
|
90993
90905
|
checks.kimi = {
|
|
90994
90906
|
...kimiCheck,
|
|
90995
90907
|
required: false,
|
|
90996
|
-
usage: "\u4EC5\
|
|
90908
|
+
usage: "\u4EC5\u4F9B\u53D1\u5E03\u540E\u7684\u4EBA\u5DE5\u5B89\u88C5\u4F7F\u7528\uFF1Brelease-skill \u4E0D\u6838\u9A8C Kimi \u5B89\u88C5"
|
|
90997
90909
|
};
|
|
90998
90910
|
const codebuddyCheck = await checkCodeBuddyDependency();
|
|
90999
90911
|
checks.codebuddy = {
|
|
91000
90912
|
...codebuddyCheck,
|
|
91001
90913
|
required: false,
|
|
91002
|
-
usage: "\u4EC5\
|
|
90914
|
+
usage: "\u4EC5\u4F9B\u53D1\u5E03\u540E\u7684\u4EBA\u5DE5\u5B89\u88C5\u4F7F\u7528\uFF1Brelease-skill \u4E0D\u6838\u9A8C CodeBuddy/WorkBuddy \u5B89\u88C5"
|
|
91003
90915
|
};
|
|
91004
90916
|
return checks;
|
|
91005
90917
|
}
|
|
@@ -91019,7 +90931,7 @@ function getCapabilityMaturity() {
|
|
|
91019
90931
|
prepare: {
|
|
91020
90932
|
available: true,
|
|
91021
90933
|
mode: "offline local writes",
|
|
91022
|
-
description: "Freeze a release plan with snapshots and gates"
|
|
90934
|
+
description: "Freeze a release plan with snapshots and gates; the command invocation authorizes hook and gate execution"
|
|
91023
90935
|
},
|
|
91024
90936
|
docs: {
|
|
91025
90937
|
available: true,
|
|
@@ -91029,7 +90941,7 @@ function getCapabilityMaturity() {
|
|
|
91029
90941
|
publish: {
|
|
91030
90942
|
available: true,
|
|
91031
90943
|
mode: "controlled production (protocol-tested; no OS/network sandbox)",
|
|
91032
|
-
description: "Publishes frozen GitHub/npm artifacts
|
|
90944
|
+
description: "Publishes frozen GitHub/npm artifacts after one readable-plan approval, runs automated Claude/Codex checkpoints, and emits non-blocking Kimi/CodeBuddy manual follow-ups"
|
|
91033
90945
|
},
|
|
91034
90946
|
reconcile: {
|
|
91035
90947
|
available: true,
|
|
@@ -91039,7 +90951,7 @@ function getCapabilityMaturity() {
|
|
|
91039
90951
|
verify: {
|
|
91040
90952
|
available: true,
|
|
91041
90953
|
mode: "fresh consumer verification (protocol-tested; no OS/network sandbox)",
|
|
91042
|
-
description: "Recheck remote state, exact npm installation, CLI help, and
|
|
90954
|
+
description: "Recheck remote state, exact npm installation, CLI help, and automated Claude/Codex installs before VERIFIED; Kimi/CodeBuddy remain unverified manual follow-ups"
|
|
91043
90955
|
}
|
|
91044
90956
|
};
|
|
91045
90957
|
}
|
|
@@ -91056,11 +90968,11 @@ Commands:
|
|
|
91056
90968
|
assess Read-only assessment of project release readiness
|
|
91057
90969
|
prepare Freeze a release plan (release-skill output to .release-skill/; hooks may do remote ops)
|
|
91058
90970
|
approve Record local approval for a frozen release plan
|
|
91059
|
-
publish Publish frozen GitHub/npm artifacts after approval
|
|
90971
|
+
publish Publish frozen GitHub/npm artifacts after approval
|
|
91060
90972
|
reconcile Resume PARTIAL state from evidence; conflicts require a human
|
|
91061
90973
|
verify Fresh remote and consumer verification; only this reaches VERIFIED
|
|
91062
90974
|
ship Resume one durable prepare -> approve -> publish -> verify flow
|
|
91063
|
-
attest
|
|
90975
|
+
attest Legacy only: record a Kimi/CodeBuddy result for an old frozen plan
|
|
91064
90976
|
hooks Run declared development hooks and populate reusable receipts
|
|
91065
90977
|
artifacts Artifact status, inspect, update/apply, resolution, and diagnostics
|
|
91066
90978
|
docs Refresh declared release documents (read-only dry-run by default)
|
|
@@ -91071,7 +90983,6 @@ Options:
|
|
|
91071
90983
|
--run <path> Path to the release run file (required for reconcile/verify)
|
|
91072
90984
|
--approval <path> Path to the approval record
|
|
91073
90985
|
--production Prepare immutable Git/npm production artifacts
|
|
91074
|
-
--confirm-production <digest> Confirm the exact production plan digest
|
|
91075
90986
|
--output <path> Override prepare/approve output path (non-production only)
|
|
91076
90987
|
--run-dir <path> Override prepare run directory; production requires one direct child of .release-skill/runs
|
|
91077
90988
|
--answers <path> Human-reviewed setup answers JSON
|
|
@@ -91080,16 +90991,13 @@ Options:
|
|
|
91080
90991
|
--unit <id> Release unit whose declared release documents are refreshed (docs refresh)
|
|
91081
90992
|
--confirm-refresh <sha256:...> Confirm the exact dry-run refreshDigest before any document write
|
|
91082
90993
|
--ack-local-document-write Acknowledge the explicit local release-document write (docs refresh --write)
|
|
91083
|
-
--
|
|
91084
|
-
--acknowledge-gate-side-effects Acknowledge unsandboxed local verification gate execution
|
|
91085
|
-
--platform <id> Manual attestation platform: kimi or codebuddy
|
|
90994
|
+
--platform <id> Legacy attestation platform: kimi or codebuddy
|
|
91086
90995
|
--plugin <id> Plugin id for a generated manual requirement
|
|
91087
90996
|
--actor <name> Person confirming an approval or manual result
|
|
91088
90997
|
--result <value> Manual result: passed or failed
|
|
91089
90998
|
--install-path <path> Actual managed plugin path when closure verification requires it
|
|
91090
90999
|
--install-channel <desktop|cli> CodeBuddy installation channel when required
|
|
91091
|
-
--
|
|
91092
|
-
--approve-plan <digest> Approve the exact ship plan and its verification gates
|
|
91000
|
+
--approve Approve the ship plan (boolean; plan digest is auto-resolved)
|
|
91093
91001
|
--state <path> Override the durable ship state file
|
|
91094
91002
|
--no-hook-cache Force every prepare hook to run in full; neither read nor write the hook cache
|
|
91095
91003
|
--json Output results as JSON
|
|
@@ -91098,14 +91006,16 @@ Options:
|
|
|
91098
91006
|
|
|
91099
91007
|
Safety:
|
|
91100
91008
|
Safe default: help -> setup (when config is absent) -> assess -> prepare --offline -> human review.
|
|
91101
|
-
Production happy end:
|
|
91009
|
+
Production happy end: ship --target-version <ver> -> ship --approve --actor <name>.
|
|
91010
|
+
The ship command runs configured hooks and gates automatically; the only human gate is plan approval.
|
|
91011
|
+
Kimi/CodeBuddy installations are non-blocking manual follow-up tasks (not verified by system).
|
|
91102
91012
|
prepare copies current public files into a local snapshot; it does not rewrite source files.
|
|
91103
91013
|
- Default mode is offline (release-skill pipeline does no remote writes)
|
|
91104
91014
|
- prepare output goes to .release-skill/ directory only
|
|
91105
91015
|
- User-configured hooks may write anywhere and perform remote operations
|
|
91106
91016
|
- To ensure zero remote writes, disable hooks or audit them separately
|
|
91107
91017
|
- docs refresh --write rewrites only declared README managed regions and the current CHANGELOG entry after exact refreshDigest confirmation; it never commits, pushes, tags, publishes, or installs.
|
|
91108
|
-
- publish requires explicit approval
|
|
91018
|
+
- publish requires explicit approval; plan digest is auto-read from the plan file
|
|
91109
91019
|
- publish consumes frozen Git/npm artifacts, never the live workspace
|
|
91110
91020
|
- existing remote objects and uncertain checks stop for human intervention
|
|
91111
91021
|
- production-equivalent protocol sandbox is verified; a real remote canary is not
|
|
@@ -91176,8 +91086,8 @@ if (!command || command === "help") {
|
|
|
91176
91086
|
conditionalConsumers: {
|
|
91177
91087
|
claude: "\u58F0\u660E claude-plugin distribution \u65F6\u5FC5\u987B\u53EF\u7528",
|
|
91178
91088
|
codex: "\u58F0\u660E codex-plugin distribution \u65F6\u5FC5\u987B\u53EF\u7528",
|
|
91179
|
-
kimi: "\
|
|
91180
|
-
codebuddy: "\
|
|
91089
|
+
kimi: "\u53D1\u5E03\u540E\u4EBA\u5DE5\u5B89\u88C5\u5F85\u529E\uFF1B\u4E0D\u5F71\u54CD\u751F\u4EA7\u53D1\u5E03\u5C31\u7EEA\u5EA6\uFF0C\u7CFB\u7EDF\u4E0D\u6838\u9A8C",
|
|
91090
|
+
codebuddy: "\u53D1\u5E03\u540E\u4EBA\u5DE5\u5B89\u88C5\u5F85\u529E\uFF1B\u4E0D\u5F71\u54CD\u751F\u4EA7\u53D1\u5E03\u5C31\u7EEA\u5EA6\uFF0C\u7CFB\u7EDF\u4E0D\u6838\u9A8C"
|
|
91181
91091
|
}
|
|
91182
91092
|
}
|
|
91183
91093
|
},
|
|
@@ -91186,12 +91096,12 @@ if (!command || command === "help") {
|
|
|
91186
91096
|
maturity: {
|
|
91187
91097
|
setup: "read-only by default; create-once requires answers plus exact setupDigest confirmation",
|
|
91188
91098
|
assess: "read-only (default); --output writes local report",
|
|
91189
|
-
prepare: "offline local writes;
|
|
91099
|
+
prepare: "offline local writes; the command invocation authorizes configured hook and gate execution",
|
|
91190
91100
|
docs: "read-only dry-run by default; write requires --write, exact --confirm-refresh, and --ack-local-document-write; never commits, pushes, or publishes",
|
|
91191
91101
|
onlinePrepare: "previous-public-baseline observation available; production mode freezes publish artifacts and fails closed on drift or unknown state",
|
|
91192
|
-
publish: "GitHub/npm plus
|
|
91102
|
+
publish: "GitHub/npm plus automated Claude/Codex consumer checkpoints are protocol-tested without an OS/network sandbox; one approval is required and the internal plan digest is checked automatically",
|
|
91193
91103
|
reconcile: "PARTIAL recovery is protocol-tested without an OS/network sandbox; remote conflicts require human intervention",
|
|
91194
|
-
verify: "fresh exact npm and Claude/Codex
|
|
91104
|
+
verify: "fresh exact npm and Claude/Codex consumer installation checks are protocol-tested without an OS/network sandbox; Kimi/CodeBuddy are unverified manual follow-ups; command invocation authorizes configured gates"
|
|
91195
91105
|
},
|
|
91196
91106
|
recommendations: []
|
|
91197
91107
|
};
|
|
@@ -91218,12 +91128,6 @@ if (!command || command === "help") {
|
|
|
91218
91128
|
if (!checks.codex.available) {
|
|
91219
91129
|
output.recommendations.push("Install Codex CLI before releasing a configured codex-plugin distribution");
|
|
91220
91130
|
}
|
|
91221
|
-
if (!checks.kimi.available) {
|
|
91222
|
-
output.recommendations.push("Install Kimi Code CLI before releasing a configured kimi-plugin distribution");
|
|
91223
|
-
}
|
|
91224
|
-
if (!checks.codebuddy.available) {
|
|
91225
|
-
output.recommendations.push("Install WorkBuddy (bundled codebuddy CLI) before releasing a configured codebuddy-plugin distribution; the install is a manual attestation closed loop because the CLI cannot pin a frozen ref");
|
|
91226
|
-
}
|
|
91227
91131
|
console.log(JSON.stringify(output, null, 2));
|
|
91228
91132
|
process.exit(readiness.status === "READY" ? 0 : 1);
|
|
91229
91133
|
} else {
|
|
@@ -91325,6 +91229,7 @@ if (command === "hooks") {
|
|
|
91325
91229
|
const { validateDeclaredHooks: validateDeclaredHooks2 } = await init_hooks2().then(() => hooks_exports);
|
|
91326
91230
|
const result = await validateDeclaredHooks2({
|
|
91327
91231
|
root,
|
|
91232
|
+
// --acknowledge-hook-side-effects is accepted as a no-effect compatibility input
|
|
91328
91233
|
hooksAuthorized: args.includes("--acknowledge-hook-side-effects"),
|
|
91329
91234
|
hookCache: !args.includes("--no-hook-cache")
|
|
91330
91235
|
});
|
|
@@ -91378,7 +91283,7 @@ if (command === "ship") {
|
|
|
91378
91283
|
root,
|
|
91379
91284
|
statePath: value("--state"),
|
|
91380
91285
|
targetVersion: value("--target-version") ?? value("--version"),
|
|
91381
|
-
|
|
91286
|
+
approve: args.includes("--approve"),
|
|
91382
91287
|
planApprovalDigest: value("--approve-plan"),
|
|
91383
91288
|
actor: value("--actor"),
|
|
91384
91289
|
adapterRegistry
|
|
@@ -91388,11 +91293,11 @@ if (command === "ship") {
|
|
|
91388
91293
|
} else {
|
|
91389
91294
|
console.log(`Ship status: ${result.status}`);
|
|
91390
91295
|
console.log(`State: ${result.statePath}`);
|
|
91391
|
-
if (result.hookAuthorizationDigest && result.status === "NEEDS_HOOK_AUTHORIZATION") {
|
|
91392
|
-
console.log(`Authorize hooks: --authorize-hooks ${result.hookAuthorizationDigest}`);
|
|
91393
|
-
}
|
|
91394
91296
|
if (result.planDigest && result.status === "NEEDS_PLAN_APPROVAL") {
|
|
91395
|
-
console.log(`Approve plan
|
|
91297
|
+
console.log(`Approve plan: ship --approve --actor <person>`);
|
|
91298
|
+
}
|
|
91299
|
+
for (const followUp of result.manualFollowUps ?? []) {
|
|
91300
|
+
console.log(`Manual follow-up [${followUp.platform}] ${followUp.plugin}: not verified by system`);
|
|
91396
91301
|
}
|
|
91397
91302
|
for (const requirement of result.requirements ?? []) {
|
|
91398
91303
|
console.log(`Manual requirement [${requirement.platform}]: ${requirement.requirementPath}`);
|
|
@@ -91542,8 +91447,8 @@ if (command === "approve") {
|
|
|
91542
91447
|
const actor = actorIdx !== -1 && args[actorIdx + 1] ? args[actorIdx + 1] : void 0;
|
|
91543
91448
|
const outputIdx = args.indexOf("--output");
|
|
91544
91449
|
const outputPath = outputIdx !== -1 && args[outputIdx + 1] ? resolve32(args[outputIdx + 1]) : void 0;
|
|
91545
|
-
if (!planPath || !
|
|
91546
|
-
const msg = "approve requires --plan <path
|
|
91450
|
+
if (!planPath || !actor) {
|
|
91451
|
+
const msg = "approve requires --plan <path> and --actor <name>";
|
|
91547
91452
|
if (hasJson) {
|
|
91548
91453
|
console.log(JSON.stringify({ error: "MISSING_PARAMETERS", message: msg, exitCode: 1 }));
|
|
91549
91454
|
} else {
|
|
@@ -91553,11 +91458,19 @@ if (command === "approve") {
|
|
|
91553
91458
|
}
|
|
91554
91459
|
try {
|
|
91555
91460
|
const { approvePlan: approvePlan2 } = await init_approve().then(() => approve_exports);
|
|
91461
|
+
const { computePlanDigest: computePlanDigest2 } = await init_plan().then(() => plan_exports);
|
|
91462
|
+
const { readFile: readFileFs } = await import("node:fs/promises");
|
|
91463
|
+
let resolvedDigest = expectedDigest;
|
|
91464
|
+
if (!resolvedDigest) {
|
|
91465
|
+
const planRaw = await readFileFs(resolve32(planPath), "utf8");
|
|
91466
|
+
const planObj = JSON.parse(planRaw);
|
|
91467
|
+
resolvedDigest = computePlanDigest2(planObj);
|
|
91468
|
+
}
|
|
91556
91469
|
const resolvedPlanPath = resolve32(planPath);
|
|
91557
91470
|
const planDir = dirname16(resolvedPlanPath);
|
|
91558
|
-
const releaseDir = basename10(planDir) === "plans" && basename10(resolvedPlanPath) === `${
|
|
91471
|
+
const releaseDir = basename10(planDir) === "plans" && basename10(resolvedPlanPath) === `${resolvedDigest}.json` ? dirname16(planDir) : planDir;
|
|
91559
91472
|
const approvalPath = outputPath ?? join30(releaseDir, "approval-record.json");
|
|
91560
|
-
const record = await approvePlan2({ planPath, expectedDigest, actor, outputPath: approvalPath });
|
|
91473
|
+
const record = await approvePlan2({ planPath, expectedDigest: resolvedDigest, actor, outputPath: approvalPath });
|
|
91561
91474
|
if (hasJson) {
|
|
91562
91475
|
console.log(JSON.stringify(record, null, 2));
|
|
91563
91476
|
} else {
|
|
@@ -91590,8 +91503,6 @@ if (command === "reconcile") {
|
|
|
91590
91503
|
const runPath = runIdx !== -1 && args[runIdx + 1] ? resolve32(args[runIdx + 1]) : void 0;
|
|
91591
91504
|
const approvalIdx = args.indexOf("--approval");
|
|
91592
91505
|
const approvalPath = approvalIdx !== -1 && args[approvalIdx + 1] ? resolve32(args[approvalIdx + 1]) : void 0;
|
|
91593
|
-
const confirmationIdx = args.indexOf("--confirm-production");
|
|
91594
|
-
const productionConfirmation = confirmationIdx !== -1 && args[confirmationIdx + 1] ? args[confirmationIdx + 1] : void 0;
|
|
91595
91506
|
if (!planPath || !runPath) {
|
|
91596
91507
|
const msg = "reconcile requires --plan <path> and --run <path>";
|
|
91597
91508
|
if (hasJson) {
|
|
@@ -91619,8 +91530,7 @@ if (command === "reconcile") {
|
|
|
91619
91530
|
sourceRunPath: runPath,
|
|
91620
91531
|
approvalPath,
|
|
91621
91532
|
adapterRegistry: registry,
|
|
91622
|
-
root
|
|
91623
|
-
productionConfirmation
|
|
91533
|
+
root
|
|
91624
91534
|
});
|
|
91625
91535
|
if (hasJson) {
|
|
91626
91536
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -91713,10 +91623,8 @@ if (command === "publish") {
|
|
|
91713
91623
|
const planPath = planIdx !== -1 && args[planIdx + 1] ? resolve32(args[planIdx + 1]) : void 0;
|
|
91714
91624
|
const approvalIdx = args.indexOf("--approval");
|
|
91715
91625
|
const approvalPath = approvalIdx !== -1 && args[approvalIdx + 1] ? resolve32(args[approvalIdx + 1]) : void 0;
|
|
91716
|
-
|
|
91717
|
-
|
|
91718
|
-
if (!planPath || !approvalPath || !productionConfirmation) {
|
|
91719
|
-
const msg = "publish requires --plan <path>, --approval <path>, and --confirm-production <plan-digest>";
|
|
91626
|
+
if (!planPath || !approvalPath) {
|
|
91627
|
+
const msg = "publish requires --plan <path> and --approval <path>";
|
|
91720
91628
|
if (hasJson) {
|
|
91721
91629
|
console.log(JSON.stringify({ error: "MISSING_PARAMETERS", message: msg, exitCode: 1 }));
|
|
91722
91630
|
} else {
|
|
@@ -91742,8 +91650,7 @@ if (command === "publish") {
|
|
|
91742
91650
|
approvalPath,
|
|
91743
91651
|
adapterRegistry: registry,
|
|
91744
91652
|
root,
|
|
91745
|
-
productionMode: true
|
|
91746
|
-
productionConfirmation
|
|
91653
|
+
productionMode: true
|
|
91747
91654
|
});
|
|
91748
91655
|
if (hasJson) {
|
|
91749
91656
|
console.log(JSON.stringify(result, null, 2));
|