release-skill 0.3.0 → 0.4.1
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 +6 -2
- package/.claude-plugin/plugin.json +2 -2
- package/.codebuddy-plugin/plugin.json +2 -2
- package/.codex-plugin/plugin.json +4 -4
- package/.kimi-plugin/plugin.json +3 -3
- package/CHANGELOG.md +36 -3
- package/INSTALL.md +34 -110
- package/INSTALL.zh-CN.md +17 -83
- package/LICENSE +183 -18
- package/NOTICE +4 -2
- package/README.md +61 -75
- package/README.zh-CN.md +48 -63
- package/adapters/claude/.claude-plugin/marketplace.json +6 -2
- package/adapters/claude/.claude-plugin/plugin.json +2 -2
- package/adapters/claude/bin/release-skill.bundle.mjs +157 -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-setup/SKILL.md +6 -0
- package/adapters/claude/skills/release-verify/SKILL.md +4 -6
- package/adapters/codex/.codex-plugin/plugin.json +4 -4
- package/adapters/codex/bin/release-skill.bundle.mjs +157 -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-setup/SKILL.md +6 -0
- package/adapters/codex/skills/release-verify/SKILL.md +4 -6
- package/adapters/kimi/.kimi-plugin/plugin.json +3 -3
- package/adapters/kimi/bin/release-skill.bundle.mjs +157 -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-setup/SKILL.md +6 -0
- package/adapters/kimi/skills/release-verify/SKILL.md +4 -6
- package/adapters/workbuddy/.codebuddy-plugin/plugin.json +2 -2
- package/adapters/workbuddy/bin/release-skill.bundle.mjs +157 -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-setup/SKILL.md +6 -0
- package/adapters/workbuddy/skills/release-verify/SKILL.md +4 -6
- package/bin/release-skill-cli.mjs +45 -48
- package/bin/release-skill.bundle.mjs +157 -231
- package/package.json +2 -2
- 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-setup/SKILL.md +6 -0
- 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-setup/SKILL.md +6 -0
- package/skills-src/release-verify/SKILL.md +4 -6
- package/src/adapters/npm.mjs +31 -0
- 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.1"});
|
|
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"
|
|
@@ -71133,6 +71134,7 @@ function extractManifestFromTarball(tarballBuffer, expected) {
|
|
|
71133
71134
|
}
|
|
71134
71135
|
let offset = 0;
|
|
71135
71136
|
let manifest = null;
|
|
71137
|
+
let readme = null;
|
|
71136
71138
|
while (offset + 512 <= data.length) {
|
|
71137
71139
|
let allZero = true;
|
|
71138
71140
|
for (let i = 0; i < 512; i++) {
|
|
@@ -71182,6 +71184,20 @@ function extractManifestFromTarball(tarballBuffer, expected) {
|
|
|
71182
71184
|
throw new Error(`tarball manifest version "${manifest.version}" does not match expected "${expected.version}"`);
|
|
71183
71185
|
}
|
|
71184
71186
|
}
|
|
71187
|
+
if (entryName.toLowerCase() === "package/readme.md") {
|
|
71188
|
+
if (readme) throw new Error("tarball contains conflicting package README entries");
|
|
71189
|
+
if (!(typeFlag === 0 || typeFlag === 48)) {
|
|
71190
|
+
throw new Error("tarball package README must be a regular file");
|
|
71191
|
+
}
|
|
71192
|
+
const bodyStart = offset + 512;
|
|
71193
|
+
const bodyEnd = bodyStart + size;
|
|
71194
|
+
if (bodyEnd > data.length) throw new Error("frozen npm tarball entry exceeds archive bounds");
|
|
71195
|
+
if (size > 10 * 1024 * 1024) throw new Error("tarball package README is unreasonably large");
|
|
71196
|
+
readme = {
|
|
71197
|
+
content: data.subarray(bodyStart, bodyEnd).toString("utf8"),
|
|
71198
|
+
filename: entryName.slice("package/".length)
|
|
71199
|
+
};
|
|
71200
|
+
}
|
|
71185
71201
|
const nextOffset = offset + 512 + Math.ceil(size / 512) * 512;
|
|
71186
71202
|
if (!Number.isSafeInteger(nextOffset) || nextOffset > data.length) {
|
|
71187
71203
|
throw new Error("frozen npm tarball entry exceeds archive bounds");
|
|
@@ -71189,6 +71205,10 @@ function extractManifestFromTarball(tarballBuffer, expected) {
|
|
|
71189
71205
|
offset = nextOffset;
|
|
71190
71206
|
}
|
|
71191
71207
|
if (!manifest) throw new Error("tarball does not contain package/package.json");
|
|
71208
|
+
if (readme) {
|
|
71209
|
+
manifest.readme = readme.content;
|
|
71210
|
+
manifest.readmeFilename = readme.filename;
|
|
71211
|
+
}
|
|
71192
71212
|
return manifest;
|
|
71193
71213
|
}
|
|
71194
71214
|
async function verifyFrozenNpmTarballIdentity(action, root) {
|
|
@@ -81249,39 +81269,16 @@ async function prepareRelease(options) {
|
|
|
81249
81269
|
if (declaredHooks.length > 0) {
|
|
81250
81270
|
await evidence.append({
|
|
81251
81271
|
phase: "hook-authorization",
|
|
81252
|
-
status: "
|
|
81272
|
+
status: "authorized",
|
|
81253
81273
|
hookCount: declaredHooks.length,
|
|
81254
81274
|
hooks: declaredHooks.map((h) => `${h.name}: ${h.executable} ${h.args.join(" ")}`)
|
|
81255
81275
|
});
|
|
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
81276
|
}
|
|
81280
81277
|
const declaredVerificationGates = config.verificationGates ?? [];
|
|
81281
81278
|
if (declaredVerificationGates.length > 0) {
|
|
81282
81279
|
await evidence.append({
|
|
81283
81280
|
phase: "verification-gate-authorization",
|
|
81284
|
-
status: "
|
|
81281
|
+
status: "authorized",
|
|
81285
81282
|
gateCount: declaredVerificationGates.length,
|
|
81286
81283
|
gates: declaredVerificationGates.map((gate) => ({
|
|
81287
81284
|
id: gate.id,
|
|
@@ -81293,23 +81290,6 @@ To proceed, pass --acknowledge-hook-side-effects (CLI) or hooksAuthorized=true (
|
|
|
81293
81290
|
cwd: gate.cwd
|
|
81294
81291
|
}))
|
|
81295
81292
|
});
|
|
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
81293
|
}
|
|
81314
81294
|
await evidence.append({ phase: "hooks", status: "started" });
|
|
81315
81295
|
await runDeclaredHooks(config, realRoot, evidence, options.runHookFn ?? runHook, {
|
|
@@ -82080,6 +82060,9 @@ To proceed, pass --acknowledge-hook-side-effects (CLI) or hooksAuthorized=true (
|
|
|
82080
82060
|
const frozenDistributionsMap = new Map(units.map((u) => [u.id, u.distributions]));
|
|
82081
82061
|
const externalActions = buildExternalActions(unitResults, resolvedVersions, productionAssets, externalMarketplaceFreezes, frozenDistributionsMap);
|
|
82082
82062
|
const overallSnapshotDigest = sha256Hex(snapshotDigests.join(":"));
|
|
82063
|
+
const hasHumanConsumerActions = externalActions.some(
|
|
82064
|
+
(a) => a.type === "kimi-marketplace-install" || a.type === "codebuddy-marketplace-install"
|
|
82065
|
+
);
|
|
82083
82066
|
const plan = {
|
|
82084
82067
|
planVersion: 2,
|
|
82085
82068
|
status: "PREPARED",
|
|
@@ -82102,6 +82085,7 @@ To proceed, pass --acknowledge-hook-side-effects (CLI) or hooksAuthorized=true (
|
|
|
82102
82085
|
},
|
|
82103
82086
|
verificationGates: config.verificationGates ?? [],
|
|
82104
82087
|
snapshotDigest: overallSnapshotDigest,
|
|
82088
|
+
...hasHumanConsumerActions ? { humanConsumersStrategy: "manualFollowUps" } : {},
|
|
82105
82089
|
...production ? {
|
|
82106
82090
|
production: {
|
|
82107
82091
|
mode: "github-npm-v1",
|
|
@@ -82224,16 +82208,10 @@ import { resolve as resolve24 } from "node:path";
|
|
|
82224
82208
|
async function validateDeclaredHooks(options = {}) {
|
|
82225
82209
|
const {
|
|
82226
82210
|
root = process.cwd(),
|
|
82227
|
-
hooksAuthorized,
|
|
82211
|
+
hooksAuthorized: _hooksAuthorized,
|
|
82228
82212
|
hookCache = true,
|
|
82229
82213
|
runDir = resolve24(root, ".release-skill", "runs", `hooks-${Date.now()}`)
|
|
82230
82214
|
} = 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
82215
|
const { config, configDigest } = await loadProjectConfig({ root });
|
|
82238
82216
|
await mkdir12(runDir, { recursive: true });
|
|
82239
82217
|
const evidence = createEvidenceWriter({
|
|
@@ -82259,7 +82237,6 @@ var init_hooks2 = __esm({
|
|
|
82259
82237
|
await init_config();
|
|
82260
82238
|
init_evidence();
|
|
82261
82239
|
await init_prepare();
|
|
82262
|
-
init_errors();
|
|
82263
82240
|
__name(validateDeclaredHooks, "validateDeclaredHooks");
|
|
82264
82241
|
}
|
|
82265
82242
|
});
|
|
@@ -82560,7 +82537,7 @@ function defaultClock() {
|
|
|
82560
82537
|
async function approvePlan(options) {
|
|
82561
82538
|
const {
|
|
82562
82539
|
planPath,
|
|
82563
|
-
expectedDigest,
|
|
82540
|
+
expectedDigest: expectedDigestInput,
|
|
82564
82541
|
actor,
|
|
82565
82542
|
expiresInMs = 24 * 60 * 60 * 1e3,
|
|
82566
82543
|
// 24 hours
|
|
@@ -82571,9 +82548,6 @@ async function approvePlan(options) {
|
|
|
82571
82548
|
if (!planPath || typeof planPath !== "string") {
|
|
82572
82549
|
throw new ReleaseError(PLAN_DIGEST_MISMATCH, "planPath must be a non-empty string");
|
|
82573
82550
|
}
|
|
82574
|
-
if (!expectedDigest || typeof expectedDigest !== "string") {
|
|
82575
|
-
throw new ReleaseError(PLAN_DIGEST_MISMATCH, "expectedDigest must be a non-empty string");
|
|
82576
|
-
}
|
|
82577
82551
|
if (!actor || typeof actor !== "string") {
|
|
82578
82552
|
throw new ReleaseError(GATE_FAILED, "actor must be a non-empty string");
|
|
82579
82553
|
}
|
|
@@ -82599,6 +82573,7 @@ async function approvePlan(options) {
|
|
|
82599
82573
|
}
|
|
82600
82574
|
const actualDigest = computePlanDigest(plan);
|
|
82601
82575
|
assertImmutablePlanAuthority(planPath, plan);
|
|
82576
|
+
const expectedDigest = expectedDigestInput ?? actualDigest;
|
|
82602
82577
|
if (actualDigest !== expectedDigest) {
|
|
82603
82578
|
throw new ReleaseError(
|
|
82604
82579
|
PLAN_DIGEST_MISMATCH,
|
|
@@ -83234,7 +83209,6 @@ async function publishRelease(options) {
|
|
|
83234
83209
|
clock: clockOpt,
|
|
83235
83210
|
captureBaselineFn,
|
|
83236
83211
|
productionMode = false,
|
|
83237
|
-
productionConfirmation,
|
|
83238
83212
|
observePreviousPublicBaselineFn,
|
|
83239
83213
|
observeRetrySleep
|
|
83240
83214
|
} = options ?? {};
|
|
@@ -83291,13 +83265,6 @@ async function publishRelease(options) {
|
|
|
83291
83265
|
if (!plan.production.assetRoot || plan.production.assetRoot === ".") {
|
|
83292
83266
|
throw new ReleaseError(GATE_FAILED, "production plan requires a dedicated assetRoot");
|
|
83293
83267
|
}
|
|
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
83268
|
}
|
|
83302
83269
|
await evidence.append({ phase: "safety-gate", gate: "action-completeness", status: "started" });
|
|
83303
83270
|
const completenessResult = validatePlanActionCompleteness(plan);
|
|
@@ -84009,7 +83976,6 @@ async function reconcileRelease(options) {
|
|
|
84009
83976
|
root = process.cwd(),
|
|
84010
83977
|
clock: clockOpt,
|
|
84011
83978
|
captureBaselineFn,
|
|
84012
|
-
productionConfirmation,
|
|
84013
83979
|
observePreviousPublicBaselineFn,
|
|
84014
83980
|
observeRetrySleep
|
|
84015
83981
|
} = options ?? {};
|
|
@@ -84179,21 +84145,6 @@ async function reconcileRelease(options) {
|
|
|
84179
84145
|
{ sourceRunId: sourceRun.runId, sourceRunStatus: sourceRun.status }
|
|
84180
84146
|
);
|
|
84181
84147
|
}
|
|
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
84148
|
await evidence.append({
|
|
84198
84149
|
phase: "safety-gate",
|
|
84199
84150
|
gate: "source-run-load",
|
|
@@ -84622,13 +84573,6 @@ async function reconcileRelease(options) {
|
|
|
84622
84573
|
}
|
|
84623
84574
|
const nonMarketplaceRetries = actionsToRetry.filter((a) => !isMarketplaceAction(a.type));
|
|
84624
84575
|
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
84576
|
if (!approval) {
|
|
84633
84577
|
throw new ReleaseError(
|
|
84634
84578
|
GATE_FAILED,
|
|
@@ -85473,7 +85417,7 @@ async function verifyRelease(options) {
|
|
|
85473
85417
|
runDir: runDirOpt,
|
|
85474
85418
|
clock: clockOpt,
|
|
85475
85419
|
npmExecutor,
|
|
85476
|
-
verificationGatesAuthorized,
|
|
85420
|
+
verificationGatesAuthorized: _verificationGatesAuthorized,
|
|
85477
85421
|
gateEnv,
|
|
85478
85422
|
previousVerifyRun
|
|
85479
85423
|
} = options ?? {};
|
|
@@ -85522,13 +85466,6 @@ async function verifyRelease(options) {
|
|
|
85522
85466
|
await evidence.append({ phase: "verify", step: "plan-load", status: "started" });
|
|
85523
85467
|
const consumerGates = (plan.verificationGates ?? []).filter((gate) => gate.phase === "consumer-verify");
|
|
85524
85468
|
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
85469
|
await evidence.append({ phase: "verify", step: "plan-load", status: "passed" });
|
|
85533
85470
|
await evidence.append({ phase: "verify", step: "source-run-load", status: "started" });
|
|
85534
85471
|
const sourceRun = await loadRun(sourceRunPath, {
|
|
@@ -85723,7 +85660,8 @@ async function verifyRelease(options) {
|
|
|
85723
85660
|
}
|
|
85724
85661
|
}
|
|
85725
85662
|
}
|
|
85726
|
-
const
|
|
85663
|
+
const isHumanConsumerFollowUp = plan.humanConsumersStrategy === "manualFollowUps";
|
|
85664
|
+
const missingManualAttestations = isHumanConsumerFollowUp ? [] : await collectMissingManualAttestations({
|
|
85727
85665
|
actions,
|
|
85728
85666
|
adapterRegistry,
|
|
85729
85667
|
plan,
|
|
@@ -85744,6 +85682,7 @@ async function verifyRelease(options) {
|
|
|
85744
85682
|
{ requirements: missingManualAttestations }
|
|
85745
85683
|
);
|
|
85746
85684
|
}
|
|
85685
|
+
const manualFollowUps = [];
|
|
85747
85686
|
const actionResults = await Promise.allSettled(actions.map(async (action) => {
|
|
85748
85687
|
const adapterActionType = ADAPTER_ACTION_TYPE_MAP2[action.type];
|
|
85749
85688
|
if (!adapterActionType) {
|
|
@@ -85766,6 +85705,33 @@ async function verifyRelease(options) {
|
|
|
85766
85705
|
);
|
|
85767
85706
|
}
|
|
85768
85707
|
if (isMarketplaceAction(action.type)) {
|
|
85708
|
+
const isHumanConsumerPlatform = action.type === "kimi-marketplace-install" || action.type === "codebuddy-marketplace-install";
|
|
85709
|
+
if (isHumanConsumerFollowUp && isHumanConsumerPlatform) {
|
|
85710
|
+
const platform = action.type === "kimi-marketplace-install" ? "kimi" : "codebuddy";
|
|
85711
|
+
manualFollowUps.push({
|
|
85712
|
+
actionId: action.id,
|
|
85713
|
+
platform,
|
|
85714
|
+
plugin: action.parameters?.plugin,
|
|
85715
|
+
version: action.parameters?.version,
|
|
85716
|
+
unitId: action.unitId,
|
|
85717
|
+
verifiedBySystem: false,
|
|
85718
|
+
reason: "human consumer platform \u2014 installation is a manual post-release task; not verified by system"
|
|
85719
|
+
});
|
|
85720
|
+
adapterChecks.push({
|
|
85721
|
+
actionId: action.id,
|
|
85722
|
+
actionType: action.type,
|
|
85723
|
+
status: "SKIPPED",
|
|
85724
|
+
reason: "manual-follow-up"
|
|
85725
|
+
});
|
|
85726
|
+
await evidence.append({
|
|
85727
|
+
phase: "verify-marketplace",
|
|
85728
|
+
actionId: action.id,
|
|
85729
|
+
actionType: action.type,
|
|
85730
|
+
status: "SKIPPED",
|
|
85731
|
+
reason: "manual-follow-up"
|
|
85732
|
+
});
|
|
85733
|
+
return;
|
|
85734
|
+
}
|
|
85769
85735
|
const marketplaceContext = {
|
|
85770
85736
|
externalWritesAuthorized: false,
|
|
85771
85737
|
isolatedConsumerWritesAuthorized: true,
|
|
@@ -86143,6 +86109,7 @@ async function verifyRelease(options) {
|
|
|
86143
86109
|
gateResults: consumerGateResults,
|
|
86144
86110
|
consumerVerificationReceipts,
|
|
86145
86111
|
skillResourceClosureReceipts,
|
|
86112
|
+
...manualFollowUps.length > 0 ? { manualFollowUps } : {},
|
|
86146
86113
|
startedAt: clockFn(),
|
|
86147
86114
|
finishedAt: clockFn()
|
|
86148
86115
|
};
|
|
@@ -86163,7 +86130,8 @@ async function verifyRelease(options) {
|
|
|
86163
86130
|
status: VERIFIED,
|
|
86164
86131
|
adapterChecks,
|
|
86165
86132
|
smokeTest,
|
|
86166
|
-
gateResults: consumerGateResults
|
|
86133
|
+
gateResults: consumerGateResults,
|
|
86134
|
+
...manualFollowUps.length > 0 ? { manualFollowUps } : {}
|
|
86167
86135
|
};
|
|
86168
86136
|
} catch (err) {
|
|
86169
86137
|
await evidence.append({
|
|
@@ -86567,8 +86535,7 @@ function publicState(state) {
|
|
|
86567
86535
|
status: state.status,
|
|
86568
86536
|
statePath: state.statePath,
|
|
86569
86537
|
targetVersion: state.targetVersion,
|
|
86570
|
-
...state.
|
|
86571
|
-
hookAuthorizationDigest: state.hookAuthorizationDigest,
|
|
86538
|
+
...state.hooks && state.hooks.length > 0 ? {
|
|
86572
86539
|
hooks: state.hooks
|
|
86573
86540
|
} : {},
|
|
86574
86541
|
...state.planPath ? {
|
|
@@ -86577,25 +86544,32 @@ function publicState(state) {
|
|
|
86577
86544
|
evidenceDir: state.evidenceDir,
|
|
86578
86545
|
warnings: state.warnings ?? []
|
|
86579
86546
|
} : {},
|
|
86547
|
+
...state.approvalSummary ? { approvalSummary: state.approvalSummary } : {},
|
|
86580
86548
|
...state.approvalPath ? { approvalPath: state.approvalPath } : {},
|
|
86581
86549
|
...state.sourceRunPath ? { sourceRunPath: state.sourceRunPath } : {},
|
|
86582
86550
|
...state.requirements ? { requirements: state.requirements } : {},
|
|
86551
|
+
...state.manualFollowUps ? { manualFollowUps: state.manualFollowUps } : {},
|
|
86583
86552
|
...state.metadataUpdate ? { metadataUpdate: state.metadataUpdate } : {},
|
|
86584
|
-
verificationGateAuthorizationIncludedInPlanApproval:
|
|
86585
|
-
postVerifyMetadataUpdateIncludedInPlanApproval:
|
|
86553
|
+
verificationGateAuthorizationIncludedInPlanApproval: true,
|
|
86554
|
+
postVerifyMetadataUpdateIncludedInPlanApproval: true
|
|
86586
86555
|
};
|
|
86587
86556
|
}
|
|
86588
|
-
function
|
|
86589
|
-
|
|
86590
|
-
|
|
86591
|
-
|
|
86592
|
-
|
|
86593
|
-
|
|
86594
|
-
|
|
86595
|
-
|
|
86596
|
-
|
|
86597
|
-
|
|
86598
|
-
|
|
86557
|
+
async function buildApprovalSummary(planPath) {
|
|
86558
|
+
try {
|
|
86559
|
+
const plan = JSON.parse(await readFile27(planPath, "utf8"));
|
|
86560
|
+
const units = (plan.units ?? []).map((unit) => ({
|
|
86561
|
+
id: unit.id,
|
|
86562
|
+
targetVersion: unit.targetVersion ?? unit.version
|
|
86563
|
+
}));
|
|
86564
|
+
const actions = (plan.externalActions ?? []).map((action) => ({
|
|
86565
|
+
id: action.id,
|
|
86566
|
+
type: action.type,
|
|
86567
|
+
unitId: action.unitId
|
|
86568
|
+
}));
|
|
86569
|
+
return { units, actions };
|
|
86570
|
+
} catch {
|
|
86571
|
+
return { units: [], actions: [] };
|
|
86572
|
+
}
|
|
86599
86573
|
}
|
|
86600
86574
|
async function advanceShip(options = {}, injected = {}) {
|
|
86601
86575
|
const root = resolve29(options.root ?? process.cwd());
|
|
@@ -86609,65 +86583,21 @@ async function advanceShip(options = {}, injected = {}) {
|
|
|
86609
86583
|
}
|
|
86610
86584
|
if (!state) {
|
|
86611
86585
|
const loaded = await deps.loadProjectConfig({ root });
|
|
86612
|
-
const
|
|
86613
|
-
const hooks = authority.hooks;
|
|
86614
|
-
const hookAuthorizationDigest = authority.digest;
|
|
86586
|
+
const hooks = Object.keys(loaded.config.hooks ?? {}).sort();
|
|
86615
86587
|
state = {
|
|
86616
|
-
schemaVersion:
|
|
86588
|
+
schemaVersion: 2,
|
|
86617
86589
|
root,
|
|
86618
86590
|
statePath,
|
|
86619
86591
|
targetVersion: options.targetVersion ?? null,
|
|
86620
86592
|
configDigest: loaded.configDigest,
|
|
86621
86593
|
hooks,
|
|
86622
|
-
|
|
86623
|
-
status: hooks.length > 0 ? "NEEDS_HOOK_AUTHORIZATION" : "NEW",
|
|
86594
|
+
status: "NEW",
|
|
86624
86595
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
86625
86596
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
86626
86597
|
};
|
|
86627
86598
|
await writeJsonAtomic(statePath, state);
|
|
86628
|
-
if (hooks.length > 0 && options.hookAuthorizationDigest !== hookAuthorizationDigest) {
|
|
86629
|
-
return publicState(state);
|
|
86630
|
-
}
|
|
86631
86599
|
}
|
|
86632
86600
|
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
86601
|
state.status = "NEW";
|
|
86672
86602
|
state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
86673
86603
|
await writeJsonAtomic(statePath, state);
|
|
@@ -86675,17 +86605,15 @@ async function advanceShip(options = {}, injected = {}) {
|
|
|
86675
86605
|
if (state.status === "NEW") {
|
|
86676
86606
|
const loaded = await deps.loadProjectConfig({ root });
|
|
86677
86607
|
if (loaded.configDigest !== state.configDigest) {
|
|
86678
|
-
const
|
|
86608
|
+
const hooks = Object.keys(loaded.config.hooks ?? {}).sort();
|
|
86679
86609
|
state = {
|
|
86680
86610
|
...state,
|
|
86681
86611
|
configDigest: loaded.configDigest,
|
|
86682
|
-
hooks
|
|
86683
|
-
|
|
86684
|
-
status: current.hooks.length > 0 ? "NEEDS_HOOK_AUTHORIZATION" : "NEW",
|
|
86612
|
+
hooks,
|
|
86613
|
+
status: "NEW",
|
|
86685
86614
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
86686
86615
|
};
|
|
86687
86616
|
await writeJsonAtomic(statePath, state);
|
|
86688
|
-
if (state.status === "NEEDS_HOOK_AUTHORIZATION") return publicState(state);
|
|
86689
86617
|
}
|
|
86690
86618
|
const prepared = await deps.prepareRelease({
|
|
86691
86619
|
root,
|
|
@@ -86693,7 +86621,7 @@ async function advanceShip(options = {}, injected = {}) {
|
|
|
86693
86621
|
offline: false,
|
|
86694
86622
|
production: true,
|
|
86695
86623
|
hooksAuthorized: true,
|
|
86696
|
-
verificationGatesAuthorized:
|
|
86624
|
+
verificationGatesAuthorized: true,
|
|
86697
86625
|
hookCache: true
|
|
86698
86626
|
});
|
|
86699
86627
|
let transportPreflight = null;
|
|
@@ -86702,6 +86630,7 @@ async function advanceShip(options = {}, injected = {}) {
|
|
|
86702
86630
|
transportPreflight = await deps.preflightGitTransports(frozenPlan);
|
|
86703
86631
|
process.env.RELEASE_SKILL_GIT_TRANSPORT = transportPreflight.transport;
|
|
86704
86632
|
}
|
|
86633
|
+
const approvalSummary = await buildApprovalSummary(prepared.planPath);
|
|
86705
86634
|
state = {
|
|
86706
86635
|
...state,
|
|
86707
86636
|
status: "NEEDS_PLAN_APPROVAL",
|
|
@@ -86709,6 +86638,7 @@ async function advanceShip(options = {}, injected = {}) {
|
|
|
86709
86638
|
planDigest: prepared.planDigest,
|
|
86710
86639
|
evidenceDir: prepared.evidenceDir,
|
|
86711
86640
|
warnings: prepared.warnings,
|
|
86641
|
+
approvalSummary,
|
|
86712
86642
|
...transportPreflight ? {
|
|
86713
86643
|
gitTransport: transportPreflight.transport,
|
|
86714
86644
|
gitTransportPreflight: transportPreflight.repositories
|
|
@@ -86718,8 +86648,10 @@ async function advanceShip(options = {}, injected = {}) {
|
|
|
86718
86648
|
await writeJsonAtomic(statePath, state);
|
|
86719
86649
|
}
|
|
86720
86650
|
if (state.status === "NEEDS_PLAN_APPROVAL") {
|
|
86721
|
-
|
|
86722
|
-
if (
|
|
86651
|
+
const approveRequested = options.approve === true || typeof options.planApprovalDigest === "string" && options.planApprovalDigest.length > 0;
|
|
86652
|
+
if (!approveRequested) return publicState(state);
|
|
86653
|
+
if (options.approve === true) {
|
|
86654
|
+
} else if (options.planApprovalDigest !== state.planDigest) {
|
|
86723
86655
|
throw new ReleaseError(PLAN_DIGEST_MISMATCH, "ship plan approval digest does not match the frozen plan");
|
|
86724
86656
|
}
|
|
86725
86657
|
if (!options.actor) {
|
|
@@ -86751,8 +86683,7 @@ async function advanceShip(options = {}, injected = {}) {
|
|
|
86751
86683
|
approvalPath: state.approvalPath,
|
|
86752
86684
|
adapterRegistry: options.adapterRegistry,
|
|
86753
86685
|
root,
|
|
86754
|
-
productionMode: true
|
|
86755
|
-
productionConfirmation: state.planDigest
|
|
86686
|
+
productionMode: true
|
|
86756
86687
|
});
|
|
86757
86688
|
state = {
|
|
86758
86689
|
...state,
|
|
@@ -86768,8 +86699,7 @@ async function advanceShip(options = {}, injected = {}) {
|
|
|
86768
86699
|
sourceRunPath: state.sourceRunPath,
|
|
86769
86700
|
approvalPath: state.approvalPath,
|
|
86770
86701
|
adapterRegistry: options.adapterRegistry,
|
|
86771
|
-
root
|
|
86772
|
-
productionConfirmation: state.planDigest
|
|
86702
|
+
root
|
|
86773
86703
|
});
|
|
86774
86704
|
state = {
|
|
86775
86705
|
...state,
|
|
@@ -86781,7 +86711,7 @@ async function advanceShip(options = {}, injected = {}) {
|
|
|
86781
86711
|
}
|
|
86782
86712
|
if (state.status === "PUBLISHED" || state.status === "NEEDS_MANUAL_ATTESTATIONS") {
|
|
86783
86713
|
try {
|
|
86784
|
-
const
|
|
86714
|
+
const verified = await deps.verifyRelease({
|
|
86785
86715
|
planPath: state.planPath,
|
|
86786
86716
|
sourceRunPath: state.sourceRunPath,
|
|
86787
86717
|
adapterRegistry: options.adapterRegistry,
|
|
@@ -86790,9 +86720,10 @@ async function advanceShip(options = {}, injected = {}) {
|
|
|
86790
86720
|
});
|
|
86791
86721
|
state = {
|
|
86792
86722
|
...state,
|
|
86793
|
-
status:
|
|
86794
|
-
verifyRunPath:
|
|
86723
|
+
status: verified.status,
|
|
86724
|
+
verifyRunPath: verified.runPath,
|
|
86795
86725
|
requirements: void 0,
|
|
86726
|
+
manualFollowUps: verified.manualFollowUps ?? void 0,
|
|
86796
86727
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
86797
86728
|
};
|
|
86798
86729
|
await writeJsonAtomic(statePath, state);
|
|
@@ -86817,7 +86748,7 @@ var init_ship = __esm({
|
|
|
86817
86748
|
__name(readState, "readState");
|
|
86818
86749
|
__name(defaultDependencies, "defaultDependencies");
|
|
86819
86750
|
__name(publicState, "publicState");
|
|
86820
|
-
__name(
|
|
86751
|
+
__name(buildApprovalSummary, "buildApprovalSummary");
|
|
86821
86752
|
__name(advanceShip, "advanceShip");
|
|
86822
86753
|
}
|
|
86823
86754
|
});
|
|
@@ -90993,13 +90924,13 @@ async function performEnvironmentChecks() {
|
|
|
90993
90924
|
checks.kimi = {
|
|
90994
90925
|
...kimiCheck,
|
|
90995
90926
|
required: false,
|
|
90996
|
-
usage: "\u4EC5\
|
|
90927
|
+
usage: "\u4EC5\u4F9B\u53D1\u5E03\u540E\u7684\u4EBA\u5DE5\u5B89\u88C5\u4F7F\u7528\uFF1Brelease-skill \u4E0D\u6838\u9A8C Kimi \u5B89\u88C5"
|
|
90997
90928
|
};
|
|
90998
90929
|
const codebuddyCheck = await checkCodeBuddyDependency();
|
|
90999
90930
|
checks.codebuddy = {
|
|
91000
90931
|
...codebuddyCheck,
|
|
91001
90932
|
required: false,
|
|
91002
|
-
usage: "\u4EC5\
|
|
90933
|
+
usage: "\u4EC5\u4F9B\u53D1\u5E03\u540E\u7684\u4EBA\u5DE5\u5B89\u88C5\u4F7F\u7528\uFF1Brelease-skill \u4E0D\u6838\u9A8C CodeBuddy/WorkBuddy \u5B89\u88C5"
|
|
91003
90934
|
};
|
|
91004
90935
|
return checks;
|
|
91005
90936
|
}
|
|
@@ -91019,7 +90950,7 @@ function getCapabilityMaturity() {
|
|
|
91019
90950
|
prepare: {
|
|
91020
90951
|
available: true,
|
|
91021
90952
|
mode: "offline local writes",
|
|
91022
|
-
description: "Freeze a release plan with snapshots and gates"
|
|
90953
|
+
description: "Freeze a release plan with snapshots and gates; the command invocation authorizes hook and gate execution"
|
|
91023
90954
|
},
|
|
91024
90955
|
docs: {
|
|
91025
90956
|
available: true,
|
|
@@ -91029,7 +90960,7 @@ function getCapabilityMaturity() {
|
|
|
91029
90960
|
publish: {
|
|
91030
90961
|
available: true,
|
|
91031
90962
|
mode: "controlled production (protocol-tested; no OS/network sandbox)",
|
|
91032
|
-
description: "Publishes frozen GitHub/npm artifacts
|
|
90963
|
+
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
90964
|
},
|
|
91034
90965
|
reconcile: {
|
|
91035
90966
|
available: true,
|
|
@@ -91039,7 +90970,7 @@ function getCapabilityMaturity() {
|
|
|
91039
90970
|
verify: {
|
|
91040
90971
|
available: true,
|
|
91041
90972
|
mode: "fresh consumer verification (protocol-tested; no OS/network sandbox)",
|
|
91042
|
-
description: "Recheck remote state, exact npm installation, CLI help, and
|
|
90973
|
+
description: "Recheck remote state, exact npm installation, CLI help, and automated Claude/Codex installs before VERIFIED; Kimi/CodeBuddy remain unverified manual follow-ups"
|
|
91043
90974
|
}
|
|
91044
90975
|
};
|
|
91045
90976
|
}
|
|
@@ -91056,11 +90987,11 @@ Commands:
|
|
|
91056
90987
|
assess Read-only assessment of project release readiness
|
|
91057
90988
|
prepare Freeze a release plan (release-skill output to .release-skill/; hooks may do remote ops)
|
|
91058
90989
|
approve Record local approval for a frozen release plan
|
|
91059
|
-
publish Publish frozen GitHub/npm artifacts after approval
|
|
90990
|
+
publish Publish frozen GitHub/npm artifacts after approval
|
|
91060
90991
|
reconcile Resume PARTIAL state from evidence; conflicts require a human
|
|
91061
90992
|
verify Fresh remote and consumer verification; only this reaches VERIFIED
|
|
91062
90993
|
ship Resume one durable prepare -> approve -> publish -> verify flow
|
|
91063
|
-
attest
|
|
90994
|
+
attest Legacy only: record a Kimi/CodeBuddy result for an old frozen plan
|
|
91064
90995
|
hooks Run declared development hooks and populate reusable receipts
|
|
91065
90996
|
artifacts Artifact status, inspect, update/apply, resolution, and diagnostics
|
|
91066
90997
|
docs Refresh declared release documents (read-only dry-run by default)
|
|
@@ -91071,7 +91002,6 @@ Options:
|
|
|
91071
91002
|
--run <path> Path to the release run file (required for reconcile/verify)
|
|
91072
91003
|
--approval <path> Path to the approval record
|
|
91073
91004
|
--production Prepare immutable Git/npm production artifacts
|
|
91074
|
-
--confirm-production <digest> Confirm the exact production plan digest
|
|
91075
91005
|
--output <path> Override prepare/approve output path (non-production only)
|
|
91076
91006
|
--run-dir <path> Override prepare run directory; production requires one direct child of .release-skill/runs
|
|
91077
91007
|
--answers <path> Human-reviewed setup answers JSON
|
|
@@ -91080,16 +91010,13 @@ Options:
|
|
|
91080
91010
|
--unit <id> Release unit whose declared release documents are refreshed (docs refresh)
|
|
91081
91011
|
--confirm-refresh <sha256:...> Confirm the exact dry-run refreshDigest before any document write
|
|
91082
91012
|
--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
|
|
91013
|
+
--platform <id> Legacy attestation platform: kimi or codebuddy
|
|
91086
91014
|
--plugin <id> Plugin id for a generated manual requirement
|
|
91087
91015
|
--actor <name> Person confirming an approval or manual result
|
|
91088
91016
|
--result <value> Manual result: passed or failed
|
|
91089
91017
|
--install-path <path> Actual managed plugin path when closure verification requires it
|
|
91090
91018
|
--install-channel <desktop|cli> CodeBuddy installation channel when required
|
|
91091
|
-
--
|
|
91092
|
-
--approve-plan <digest> Approve the exact ship plan and its verification gates
|
|
91019
|
+
--approve Approve the ship plan (boolean; plan digest is auto-resolved)
|
|
91093
91020
|
--state <path> Override the durable ship state file
|
|
91094
91021
|
--no-hook-cache Force every prepare hook to run in full; neither read nor write the hook cache
|
|
91095
91022
|
--json Output results as JSON
|
|
@@ -91098,14 +91025,16 @@ Options:
|
|
|
91098
91025
|
|
|
91099
91026
|
Safety:
|
|
91100
91027
|
Safe default: help -> setup (when config is absent) -> assess -> prepare --offline -> human review.
|
|
91101
|
-
Production happy end:
|
|
91028
|
+
Production happy end: ship --target-version <ver> -> ship --approve --actor <name>.
|
|
91029
|
+
The ship command runs configured hooks and gates automatically; the only human gate is plan approval.
|
|
91030
|
+
Kimi/CodeBuddy installations are non-blocking manual follow-up tasks (not verified by system).
|
|
91102
91031
|
prepare copies current public files into a local snapshot; it does not rewrite source files.
|
|
91103
91032
|
- Default mode is offline (release-skill pipeline does no remote writes)
|
|
91104
91033
|
- prepare output goes to .release-skill/ directory only
|
|
91105
91034
|
- User-configured hooks may write anywhere and perform remote operations
|
|
91106
91035
|
- To ensure zero remote writes, disable hooks or audit them separately
|
|
91107
91036
|
- 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
|
|
91037
|
+
- publish requires explicit approval; plan digest is auto-read from the plan file
|
|
91109
91038
|
- publish consumes frozen Git/npm artifacts, never the live workspace
|
|
91110
91039
|
- existing remote objects and uncertain checks stop for human intervention
|
|
91111
91040
|
- production-equivalent protocol sandbox is verified; a real remote canary is not
|
|
@@ -91176,8 +91105,8 @@ if (!command || command === "help") {
|
|
|
91176
91105
|
conditionalConsumers: {
|
|
91177
91106
|
claude: "\u58F0\u660E claude-plugin distribution \u65F6\u5FC5\u987B\u53EF\u7528",
|
|
91178
91107
|
codex: "\u58F0\u660E codex-plugin distribution \u65F6\u5FC5\u987B\u53EF\u7528",
|
|
91179
|
-
kimi: "\
|
|
91180
|
-
codebuddy: "\
|
|
91108
|
+
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",
|
|
91109
|
+
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
91110
|
}
|
|
91182
91111
|
}
|
|
91183
91112
|
},
|
|
@@ -91186,12 +91115,12 @@ if (!command || command === "help") {
|
|
|
91186
91115
|
maturity: {
|
|
91187
91116
|
setup: "read-only by default; create-once requires answers plus exact setupDigest confirmation",
|
|
91188
91117
|
assess: "read-only (default); --output writes local report",
|
|
91189
|
-
prepare: "offline local writes;
|
|
91118
|
+
prepare: "offline local writes; the command invocation authorizes configured hook and gate execution",
|
|
91190
91119
|
docs: "read-only dry-run by default; write requires --write, exact --confirm-refresh, and --ack-local-document-write; never commits, pushes, or publishes",
|
|
91191
91120
|
onlinePrepare: "previous-public-baseline observation available; production mode freezes publish artifacts and fails closed on drift or unknown state",
|
|
91192
|
-
publish: "GitHub/npm plus
|
|
91121
|
+
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
91122
|
reconcile: "PARTIAL recovery is protocol-tested without an OS/network sandbox; remote conflicts require human intervention",
|
|
91194
|
-
verify: "fresh exact npm and Claude/Codex
|
|
91123
|
+
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
91124
|
},
|
|
91196
91125
|
recommendations: []
|
|
91197
91126
|
};
|
|
@@ -91218,12 +91147,6 @@ if (!command || command === "help") {
|
|
|
91218
91147
|
if (!checks.codex.available) {
|
|
91219
91148
|
output.recommendations.push("Install Codex CLI before releasing a configured codex-plugin distribution");
|
|
91220
91149
|
}
|
|
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
91150
|
console.log(JSON.stringify(output, null, 2));
|
|
91228
91151
|
process.exit(readiness.status === "READY" ? 0 : 1);
|
|
91229
91152
|
} else {
|
|
@@ -91325,6 +91248,7 @@ if (command === "hooks") {
|
|
|
91325
91248
|
const { validateDeclaredHooks: validateDeclaredHooks2 } = await init_hooks2().then(() => hooks_exports);
|
|
91326
91249
|
const result = await validateDeclaredHooks2({
|
|
91327
91250
|
root,
|
|
91251
|
+
// --acknowledge-hook-side-effects is accepted as a no-effect compatibility input
|
|
91328
91252
|
hooksAuthorized: args.includes("--acknowledge-hook-side-effects"),
|
|
91329
91253
|
hookCache: !args.includes("--no-hook-cache")
|
|
91330
91254
|
});
|
|
@@ -91378,7 +91302,7 @@ if (command === "ship") {
|
|
|
91378
91302
|
root,
|
|
91379
91303
|
statePath: value("--state"),
|
|
91380
91304
|
targetVersion: value("--target-version") ?? value("--version"),
|
|
91381
|
-
|
|
91305
|
+
approve: args.includes("--approve"),
|
|
91382
91306
|
planApprovalDigest: value("--approve-plan"),
|
|
91383
91307
|
actor: value("--actor"),
|
|
91384
91308
|
adapterRegistry
|
|
@@ -91388,11 +91312,11 @@ if (command === "ship") {
|
|
|
91388
91312
|
} else {
|
|
91389
91313
|
console.log(`Ship status: ${result.status}`);
|
|
91390
91314
|
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
91315
|
if (result.planDigest && result.status === "NEEDS_PLAN_APPROVAL") {
|
|
91395
|
-
console.log(`Approve plan
|
|
91316
|
+
console.log(`Approve plan: ship --approve --actor <person>`);
|
|
91317
|
+
}
|
|
91318
|
+
for (const followUp of result.manualFollowUps ?? []) {
|
|
91319
|
+
console.log(`Manual follow-up [${followUp.platform}] ${followUp.plugin}: not verified by system`);
|
|
91396
91320
|
}
|
|
91397
91321
|
for (const requirement of result.requirements ?? []) {
|
|
91398
91322
|
console.log(`Manual requirement [${requirement.platform}]: ${requirement.requirementPath}`);
|
|
@@ -91542,8 +91466,8 @@ if (command === "approve") {
|
|
|
91542
91466
|
const actor = actorIdx !== -1 && args[actorIdx + 1] ? args[actorIdx + 1] : void 0;
|
|
91543
91467
|
const outputIdx = args.indexOf("--output");
|
|
91544
91468
|
const outputPath = outputIdx !== -1 && args[outputIdx + 1] ? resolve32(args[outputIdx + 1]) : void 0;
|
|
91545
|
-
if (!planPath || !
|
|
91546
|
-
const msg = "approve requires --plan <path
|
|
91469
|
+
if (!planPath || !actor) {
|
|
91470
|
+
const msg = "approve requires --plan <path> and --actor <name>";
|
|
91547
91471
|
if (hasJson) {
|
|
91548
91472
|
console.log(JSON.stringify({ error: "MISSING_PARAMETERS", message: msg, exitCode: 1 }));
|
|
91549
91473
|
} else {
|
|
@@ -91553,11 +91477,19 @@ if (command === "approve") {
|
|
|
91553
91477
|
}
|
|
91554
91478
|
try {
|
|
91555
91479
|
const { approvePlan: approvePlan2 } = await init_approve().then(() => approve_exports);
|
|
91480
|
+
const { computePlanDigest: computePlanDigest2 } = await init_plan().then(() => plan_exports);
|
|
91481
|
+
const { readFile: readFileFs } = await import("node:fs/promises");
|
|
91482
|
+
let resolvedDigest = expectedDigest;
|
|
91483
|
+
if (!resolvedDigest) {
|
|
91484
|
+
const planRaw = await readFileFs(resolve32(planPath), "utf8");
|
|
91485
|
+
const planObj = JSON.parse(planRaw);
|
|
91486
|
+
resolvedDigest = computePlanDigest2(planObj);
|
|
91487
|
+
}
|
|
91556
91488
|
const resolvedPlanPath = resolve32(planPath);
|
|
91557
91489
|
const planDir = dirname16(resolvedPlanPath);
|
|
91558
|
-
const releaseDir = basename10(planDir) === "plans" && basename10(resolvedPlanPath) === `${
|
|
91490
|
+
const releaseDir = basename10(planDir) === "plans" && basename10(resolvedPlanPath) === `${resolvedDigest}.json` ? dirname16(planDir) : planDir;
|
|
91559
91491
|
const approvalPath = outputPath ?? join30(releaseDir, "approval-record.json");
|
|
91560
|
-
const record = await approvePlan2({ planPath, expectedDigest, actor, outputPath: approvalPath });
|
|
91492
|
+
const record = await approvePlan2({ planPath, expectedDigest: resolvedDigest, actor, outputPath: approvalPath });
|
|
91561
91493
|
if (hasJson) {
|
|
91562
91494
|
console.log(JSON.stringify(record, null, 2));
|
|
91563
91495
|
} else {
|
|
@@ -91590,8 +91522,6 @@ if (command === "reconcile") {
|
|
|
91590
91522
|
const runPath = runIdx !== -1 && args[runIdx + 1] ? resolve32(args[runIdx + 1]) : void 0;
|
|
91591
91523
|
const approvalIdx = args.indexOf("--approval");
|
|
91592
91524
|
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
91525
|
if (!planPath || !runPath) {
|
|
91596
91526
|
const msg = "reconcile requires --plan <path> and --run <path>";
|
|
91597
91527
|
if (hasJson) {
|
|
@@ -91619,8 +91549,7 @@ if (command === "reconcile") {
|
|
|
91619
91549
|
sourceRunPath: runPath,
|
|
91620
91550
|
approvalPath,
|
|
91621
91551
|
adapterRegistry: registry,
|
|
91622
|
-
root
|
|
91623
|
-
productionConfirmation
|
|
91552
|
+
root
|
|
91624
91553
|
});
|
|
91625
91554
|
if (hasJson) {
|
|
91626
91555
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -91713,10 +91642,8 @@ if (command === "publish") {
|
|
|
91713
91642
|
const planPath = planIdx !== -1 && args[planIdx + 1] ? resolve32(args[planIdx + 1]) : void 0;
|
|
91714
91643
|
const approvalIdx = args.indexOf("--approval");
|
|
91715
91644
|
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>";
|
|
91645
|
+
if (!planPath || !approvalPath) {
|
|
91646
|
+
const msg = "publish requires --plan <path> and --approval <path>";
|
|
91720
91647
|
if (hasJson) {
|
|
91721
91648
|
console.log(JSON.stringify({ error: "MISSING_PARAMETERS", message: msg, exitCode: 1 }));
|
|
91722
91649
|
} else {
|
|
@@ -91742,8 +91669,7 @@ if (command === "publish") {
|
|
|
91742
91669
|
approvalPath,
|
|
91743
91670
|
adapterRegistry: registry,
|
|
91744
91671
|
root,
|
|
91745
|
-
productionMode: true
|
|
91746
|
-
productionConfirmation
|
|
91672
|
+
productionMode: true
|
|
91747
91673
|
});
|
|
91748
91674
|
if (hasJson) {
|
|
91749
91675
|
console.log(JSON.stringify(result, null, 2));
|