release-skill 0.9.5 → 0.9.7
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 +55 -0
- package/INSTALL.md +2 -2
- package/INSTALL.zh-CN.md +2 -2
- package/README.md +19 -19
- package/README.zh-CN.md +17 -18
- 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 +249 -17
- package/adapters/claude/skills/release-help/SKILL.md +5 -1
- package/adapters/claude/skills/release-verify/SKILL.md +13 -1
- package/adapters/codex/.codex-plugin/plugin.json +2 -2
- package/adapters/codex/bin/release-skill.bundle.mjs +249 -17
- package/adapters/codex/skills/release-help/SKILL.md +5 -1
- package/adapters/codex/skills/release-verify/SKILL.md +13 -1
- package/adapters/kimi/.kimi-plugin/plugin.json +1 -1
- package/adapters/kimi/bin/release-skill.bundle.mjs +249 -17
- package/adapters/kimi/skills/release-help/SKILL.md +5 -1
- package/adapters/kimi/skills/release-verify/SKILL.md +13 -1
- package/adapters/workbuddy/.codebuddy-plugin/plugin.json +1 -1
- package/adapters/workbuddy/bin/release-skill.bundle.mjs +249 -17
- package/adapters/workbuddy/skills/release-help/SKILL.md +5 -1
- package/adapters/workbuddy/skills/release-verify/SKILL.md +13 -1
- package/bin/release-skill-cli.mjs +130 -6
- package/bin/release-skill.bundle.mjs +249 -17
- package/package.json +1 -1
- package/platform-manifest.json +4 -4
- package/skills/release-help/SKILL.md +5 -1
- package/skills/release-verify/SKILL.md +13 -1
- package/skills-src/release-help/SKILL.md +5 -1
- package/skills-src/release-verify/SKILL.md +13 -1
- package/src/adapters/plugin-marketplace.mjs +54 -5
- package/src/commands/prepare.mjs +5 -3
- package/src/commands/publish.mjs +30 -3
- package/src/commands/verify.mjs +14 -7
- package/src/core/skill-resource-closure.mjs +19 -1
- package/src/core/surface-host-bindings.mjs +35 -0
|
@@ -5,7 +5,7 @@ import { basename, dirname, join, resolve } from 'node:path';
|
|
|
5
5
|
import { execFile as execFileCb } from 'node:child_process';
|
|
6
6
|
import { promisify } from 'node:util';
|
|
7
7
|
import { parseNodeMajor, meetsMinimum, computeReadinessStatus } from '../src/core/node-version.mjs';
|
|
8
|
-
import { registerPathRedactor } from '../src/core/errors.mjs';
|
|
8
|
+
import { EXIT_CODE_MAP, MISSING_PARAMETERS, registerPathRedactor } from '../src/core/errors.mjs';
|
|
9
9
|
import { redactSensitivePaths } from '../src/core/redact.mjs';
|
|
10
10
|
|
|
11
11
|
// Process output errors can be emitted immediately after a large console
|
|
@@ -37,7 +37,7 @@ registerPathRedactor(redactSensitivePaths);
|
|
|
37
37
|
|
|
38
38
|
const execFile = promisify(execFileCb);
|
|
39
39
|
|
|
40
|
-
const COMMANDS = new Set(['help', 'setup', 'assess', 'prepare', 'approve', 'publish', 'reconcile', 'verify', 'ship', 'post-release', 'attest', 'hooks', 'artifacts', 'docs', 'distribute', 'route', 'lineage']);
|
|
40
|
+
const COMMANDS = new Set(['help', 'setup', 'assess', 'prepare', 'approve', 'publish', 'reconcile', 'verify', 'postverify', 'ship', 'post-release', 'attest', 'hooks', 'artifacts', 'docs', 'distribute', 'route', 'lineage']);
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* Wait until writes already queued on a process output stream have reached
|
|
@@ -307,6 +307,11 @@ function getCapabilityMaturity() {
|
|
|
307
307
|
mode: 'fresh consumer verification (protocol-tested; no OS/network sandbox)',
|
|
308
308
|
description: 'Recheck remote state, exact npm installation, CLI help, and automated Claude/Codex installs before VERIFIED; Kimi/CodeBuddy remain unverified manual follow-ups',
|
|
309
309
|
},
|
|
310
|
+
postverify: {
|
|
311
|
+
available: true,
|
|
312
|
+
mode: 'independent postVerify execution',
|
|
313
|
+
description: 'Run approved postVerify hooks from a VERIFIED run in an independent run; never reads or writes ship state',
|
|
314
|
+
},
|
|
310
315
|
distribute: {
|
|
311
316
|
available: true,
|
|
312
317
|
mode: 'controlled production (protocol-tested; no OS/network sandbox)',
|
|
@@ -340,6 +345,7 @@ Commands:
|
|
|
340
345
|
publish Publish frozen GitHub/npm artifacts after approval
|
|
341
346
|
reconcile Resume PARTIAL state from evidence; conflicts require a human
|
|
342
347
|
verify Fresh remote and consumer verification; only this reaches VERIFIED
|
|
348
|
+
postverify Run approved postVerify hooks from a VERIFIED run in an independent run
|
|
343
349
|
ship Resume one durable prepare -> approve -> publish -> verify flow; completes a parked
|
|
344
350
|
postVerify hook once its checkpoint approval is provided (--hook-approval)
|
|
345
351
|
post-release Inspect optional local finishing work after VERIFIED; update installed host plugins
|
|
@@ -354,10 +360,10 @@ Commands:
|
|
|
354
360
|
|
|
355
361
|
Options:
|
|
356
362
|
--root <path> Project root directory (default: cwd)
|
|
357
|
-
--plan <path> Path to the release plan file
|
|
363
|
+
--plan <path> Path to the release plan file (required for approve/publish/reconcile/verify/postverify)
|
|
358
364
|
--run <path> Path to the release run file, or a run directory whose release-run.json
|
|
359
|
-
is resolved automatically (required for reconcile/verify)
|
|
360
|
-
--approval <path> Path to the approval record
|
|
365
|
+
is resolved automatically (required for reconcile/verify/postverify)
|
|
366
|
+
--approval <path> Path to the release-level approval record (required for publish/postverify)
|
|
361
367
|
--production Prepare immutable Git/npm production artifacts
|
|
362
368
|
--output <path> Override prepare/approve output path (non-production only)
|
|
363
369
|
--run-dir <path> Override prepare run directory; production requires one direct child of .release-skill/runs
|
|
@@ -394,7 +400,7 @@ Options:
|
|
|
394
400
|
--install-path <path> Actual managed plugin path when closure verification requires it
|
|
395
401
|
--install-channel <desktop|cli> CodeBuddy installation channel when required
|
|
396
402
|
--approve Approve the ship plan (boolean; plan digest is auto-resolved)
|
|
397
|
-
--hook-approval <path> Checkpoint approval for
|
|
403
|
+
--hook-approval <path> Checkpoint approval for one requiresApproval hook (ship/distribute/postverify; repeatable)
|
|
398
404
|
--state <path> Override the durable ship state file
|
|
399
405
|
--update-local-hosts Update installed plugins for selected local hosts after VERIFIED
|
|
400
406
|
--hosts <ids> Comma-separated local hosts for post-release update. No local host is updated unless --hosts contains at least one id
|
|
@@ -1539,6 +1545,124 @@ if (command === 'verify') {
|
|
|
1539
1545
|
}
|
|
1540
1546
|
}
|
|
1541
1547
|
|
|
1548
|
+
// --- PostVerify command routing ---
|
|
1549
|
+
if (command === 'postverify') {
|
|
1550
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
1551
|
+
const helpText = `release-skill postverify - Run approved postVerify hooks from a VERIFIED run
|
|
1552
|
+
|
|
1553
|
+
Usage:
|
|
1554
|
+
release-skill postverify [--root <path>] --plan <path> --approval <path> --run <path> [options]
|
|
1555
|
+
|
|
1556
|
+
Required options:
|
|
1557
|
+
--plan <path> Path to the release plan file
|
|
1558
|
+
--approval <path> Path to the release-level approval record
|
|
1559
|
+
--run <path> Path to the VERIFIED verify run file or directory
|
|
1560
|
+
|
|
1561
|
+
Optional options:
|
|
1562
|
+
--root <path> Project root directory (default: cwd)
|
|
1563
|
+
--hook-approval <path> Checkpoint approval for a requiresApproval postVerify hook (repeatable)
|
|
1564
|
+
--json Output results as JSON
|
|
1565
|
+
-h, --help Show this help message and exit
|
|
1566
|
+
|
|
1567
|
+
This command creates an independent postVerify run and never reads or writes ship state.`;
|
|
1568
|
+
if (hasJson) {
|
|
1569
|
+
console.log(JSON.stringify({
|
|
1570
|
+
command: 'postverify',
|
|
1571
|
+
status: 'HELP',
|
|
1572
|
+
usage: 'release-skill postverify [--root <path>] --plan <path> --approval <path> --run <path> [options]',
|
|
1573
|
+
options: {
|
|
1574
|
+
'--root': 'Project root directory (default: cwd)',
|
|
1575
|
+
'--plan': 'Path to the release plan file (required)',
|
|
1576
|
+
'--approval': 'Path to the release-level approval record (required)',
|
|
1577
|
+
'--run': 'Path to the VERIFIED verify run file or directory (required)',
|
|
1578
|
+
'--hook-approval': 'Checkpoint approval for a requiresApproval postVerify hook (repeatable)',
|
|
1579
|
+
'--json': 'Output results as JSON',
|
|
1580
|
+
'-h, --help': 'Show this help message and exit',
|
|
1581
|
+
},
|
|
1582
|
+
message: 'Creates an independent postVerify run and never reads or writes ship state.',
|
|
1583
|
+
}, null, 2));
|
|
1584
|
+
} else {
|
|
1585
|
+
console.log(helpText);
|
|
1586
|
+
}
|
|
1587
|
+
await exitAfterFlush(0);
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
let malformedValuedFlag;
|
|
1591
|
+
const value = (flag) => {
|
|
1592
|
+
let firstValue;
|
|
1593
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
1594
|
+
if (args[i] !== flag) continue;
|
|
1595
|
+
const next = args[i + 1];
|
|
1596
|
+
if (!next || next.startsWith('-')) {
|
|
1597
|
+
malformedValuedFlag ??= flag;
|
|
1598
|
+
continue;
|
|
1599
|
+
}
|
|
1600
|
+
firstValue ??= next;
|
|
1601
|
+
}
|
|
1602
|
+
return firstValue;
|
|
1603
|
+
};
|
|
1604
|
+
const root = resolve(value('--root') ?? process.cwd());
|
|
1605
|
+
const planPath = value('--plan');
|
|
1606
|
+
const approvalPath = value('--approval');
|
|
1607
|
+
const runPath = value('--run');
|
|
1608
|
+
const postpublishApprovalPaths = [];
|
|
1609
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
1610
|
+
if (args[i] === '--hook-approval') {
|
|
1611
|
+
const next = args[i + 1];
|
|
1612
|
+
if (!next || next.startsWith('-')) {
|
|
1613
|
+
malformedValuedFlag ??= '--hook-approval';
|
|
1614
|
+
} else {
|
|
1615
|
+
postpublishApprovalPaths.push(resolve(next));
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
if (malformedValuedFlag || !planPath || !approvalPath || !runPath) {
|
|
1621
|
+
const msg = 'postverify requires --plan <path>, --approval <path>, and --run <path>';
|
|
1622
|
+
if (hasJson) {
|
|
1623
|
+
console.log(JSON.stringify({ error: MISSING_PARAMETERS, message: msg, exitCode: EXIT_CODE_MAP[MISSING_PARAMETERS] }));
|
|
1624
|
+
} else {
|
|
1625
|
+
console.error(`Error: ${msg}`);
|
|
1626
|
+
}
|
|
1627
|
+
await exitAfterFlush(EXIT_CODE_MAP[MISSING_PARAMETERS]);
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
try {
|
|
1631
|
+
const { postVerifyRelease } = await import('../src/commands/postverify.mjs');
|
|
1632
|
+
const result = await postVerifyRelease({
|
|
1633
|
+
planPath: resolve(planPath),
|
|
1634
|
+
approvalPath: resolve(approvalPath),
|
|
1635
|
+
sourceRunPath: resolve(runPath),
|
|
1636
|
+
root,
|
|
1637
|
+
...(postpublishApprovalPaths.length > 0 ? { postpublishApprovalPaths } : {}),
|
|
1638
|
+
});
|
|
1639
|
+
|
|
1640
|
+
if (hasJson) {
|
|
1641
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1642
|
+
} else {
|
|
1643
|
+
console.log(`PostVerify status: ${result.status}`);
|
|
1644
|
+
for (const cp of result.checkpoints ?? []) {
|
|
1645
|
+
console.log(` ${cp.actionId}: ${cp.status}`);
|
|
1646
|
+
}
|
|
1647
|
+
if (result.runPath) console.log(`PostVerify run: ${result.runPath}`);
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
await exitAfterFlush(result.status === 'DISTRIBUTED' ? 0 : 1);
|
|
1651
|
+
} catch (err) {
|
|
1652
|
+
if (hasJson) {
|
|
1653
|
+
console.log(JSON.stringify({
|
|
1654
|
+
error: err.code ?? 'UNKNOWN_ERROR',
|
|
1655
|
+
message: err.message,
|
|
1656
|
+
details: err.details ?? {},
|
|
1657
|
+
exitCode: err.exitCode ?? 1,
|
|
1658
|
+
}));
|
|
1659
|
+
} else {
|
|
1660
|
+
console.error(`Error: ${err.message}`);
|
|
1661
|
+
}
|
|
1662
|
+
await exitAfterFlush(err.exitCode ?? 1);
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1542
1666
|
// --- Publish command routing ---
|
|
1543
1667
|
if (command === 'publish') {
|
|
1544
1668
|
|
|
@@ -9,9 +9,9 @@ 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.9.
|
|
12
|
+
const __bundlePkg = Object.freeze({"name":"release-skill","version":"0.9.7"});
|
|
13
13
|
// Build-time source digest for the BUNDLE_STALE freshness gate (see above).
|
|
14
|
-
const __bundleSourceDigest = "
|
|
14
|
+
const __bundleSourceDigest = "938bc6828f17e2248a4fe167bcd3353b43848ec1a494dc17dc663d390847150c";
|
|
15
15
|
|
|
16
16
|
var __create = Object.create;
|
|
17
17
|
var __defProp = Object.defineProperty;
|
|
@@ -109520,9 +109520,27 @@ async function checkSkillResourceClosure({
|
|
|
109520
109520
|
result2.receiptDigest = digestDocument(receiptProjection(result2));
|
|
109521
109521
|
return result2;
|
|
109522
109522
|
}
|
|
109523
|
-
function evaluateDeclaredHostSurfaceCoverage(expectedHosts, surfaces) {
|
|
109523
|
+
function evaluateDeclaredHostSurfaceCoverage(expectedHosts, surfaces, coverageClaims = []) {
|
|
109524
109524
|
const missing = [];
|
|
109525
|
+
const observedById = new Map((surfaces ?? []).map((surface) => [surface.id, surface]));
|
|
109526
|
+
const claimsByHost = /* @__PURE__ */ new Map();
|
|
109527
|
+
for (const claim of coverageClaims ?? []) {
|
|
109528
|
+
const hostClaims = claimsByHost.get(claim.host) ?? [];
|
|
109529
|
+
hostClaims.push(claim);
|
|
109530
|
+
claimsByHost.set(claim.host, hostClaims);
|
|
109531
|
+
}
|
|
109525
109532
|
for (const expectedHost of [...new Set(expectedHosts ?? [])].sort((a, b) => a.localeCompare(b))) {
|
|
109533
|
+
const declaredClaims = claimsByHost.get(expectedHost) ?? [];
|
|
109534
|
+
if (declaredClaims.length > 0) {
|
|
109535
|
+
const missingClaim = declaredClaims.find((claim) => {
|
|
109536
|
+
const surface3 = observedById.get(claim.surfaceId);
|
|
109537
|
+
return !surface3 || !(surface3.skillCount >= 1);
|
|
109538
|
+
});
|
|
109539
|
+
if (!missingClaim) continue;
|
|
109540
|
+
const surface2 = observedById.get(missingClaim.surfaceId);
|
|
109541
|
+
missing.push({ host: expectedHost, skillCount: surface2?.skillCount ?? 0 });
|
|
109542
|
+
continue;
|
|
109543
|
+
}
|
|
109526
109544
|
const surface = (surfaces ?? []).find((item) => item.host === expectedHost);
|
|
109527
109545
|
if (!surface || !(surface.skillCount >= 1)) {
|
|
109528
109546
|
missing.push({ host: expectedHost, skillCount: surface?.skillCount ?? 0 });
|
|
@@ -109640,6 +109658,39 @@ function transportPayload(entries) {
|
|
|
109640
109658
|
contentDigest
|
|
109641
109659
|
}));
|
|
109642
109660
|
}
|
|
109661
|
+
function foundationPayloadMembers(observation) {
|
|
109662
|
+
return observation.members.map((member) => {
|
|
109663
|
+
if (member.type === "file") {
|
|
109664
|
+
return {
|
|
109665
|
+
path: member.path,
|
|
109666
|
+
type: member.type,
|
|
109667
|
+
mode: member.statMode & ~146,
|
|
109668
|
+
size: member.bytes,
|
|
109669
|
+
contentDigest: member.sha256
|
|
109670
|
+
};
|
|
109671
|
+
}
|
|
109672
|
+
if (member.type === "directory") {
|
|
109673
|
+
return { path: member.path, type: member.type, mode: member.statMode };
|
|
109674
|
+
}
|
|
109675
|
+
return {
|
|
109676
|
+
path: member.path,
|
|
109677
|
+
type: member.type,
|
|
109678
|
+
mode: member.statMode,
|
|
109679
|
+
size: member.bytes,
|
|
109680
|
+
targetBase64: member.targetBase64
|
|
109681
|
+
};
|
|
109682
|
+
});
|
|
109683
|
+
}
|
|
109684
|
+
async function observeMarketplaceInstallTree(installPath) {
|
|
109685
|
+
const canonicalInstallPath = await realpath22(installPath);
|
|
109686
|
+
const rootBinding = await createFilesystemRootBinding(canonicalInstallPath);
|
|
109687
|
+
const observation = await observeFilesystemTree({
|
|
109688
|
+
root: canonicalInstallPath,
|
|
109689
|
+
rootBinding,
|
|
109690
|
+
symlinkPolicy: { mode: "record" }
|
|
109691
|
+
});
|
|
109692
|
+
return foundationPayloadMembers(observation);
|
|
109693
|
+
}
|
|
109643
109694
|
function resolveMarketplaceRoot(platform, marketplaceIndexPath) {
|
|
109644
109695
|
const defaultMarketplace = platform.manifestPaths.marketplace;
|
|
109645
109696
|
if (!defaultMarketplace) {
|
|
@@ -109869,10 +109920,10 @@ async function verifyInstalledMarketplacePayload(action, context, installPath, c
|
|
|
109869
109920
|
throw new Error(`unsupported marketplace payload contract: ${JSON.stringify(payloadContract)}`);
|
|
109870
109921
|
}
|
|
109871
109922
|
if (payloadContract === PAYLOAD_CONTRACT_DECLARED_MANIFEST || payloadContract === PAYLOAD_CONTRACT_EXTERNAL_MARKETPLACE) {
|
|
109872
|
-
const
|
|
109923
|
+
const installedMembers = await observeMarketplaceInstallTree(installPath);
|
|
109873
109924
|
const authorityPayload = transportPayload(authorityEntries);
|
|
109874
109925
|
const installedByPath = new Map(
|
|
109875
|
-
|
|
109926
|
+
installedMembers.map((entry) => [entry.path, entry])
|
|
109876
109927
|
);
|
|
109877
109928
|
const conflicts = [];
|
|
109878
109929
|
for (const authorityEntry of authorityPayload) {
|
|
@@ -109897,11 +109948,19 @@ async function verifyInstalledMarketplacePayload(action, context, installPath, c
|
|
|
109897
109948
|
);
|
|
109898
109949
|
}
|
|
109899
109950
|
const authorityPaths = new Set(authorityPayload.map((entry) => entry.path));
|
|
109900
|
-
const
|
|
109951
|
+
const extraMembers = installedMembers.filter((entry) => entry.type !== "directory" && !authorityPaths.has(entry.path));
|
|
109952
|
+
const extraPaths = extraMembers.map((entry) => entry.path);
|
|
109901
109953
|
const extraInstalledPaths = extraPaths.slice(0, EXTRA_INSTALLED_PATHS_CAP);
|
|
109954
|
+
const extraInstalledLinks = extraMembers.filter((entry) => entry.type === "symlink").slice(0, EXTRA_INSTALLED_PATHS_CAP).map((entry) => ({
|
|
109955
|
+
path: entry.path,
|
|
109956
|
+
targetBase64: entry.targetBase64,
|
|
109957
|
+
bytes: entry.size,
|
|
109958
|
+
statMode: entry.mode
|
|
109959
|
+
}));
|
|
109902
109960
|
return {
|
|
109903
109961
|
manifestDigest: action.manifestDigest,
|
|
109904
109962
|
extraInstalledPaths,
|
|
109963
|
+
...extraInstalledLinks.length > 0 ? { extraInstalledLinks } : {},
|
|
109905
109964
|
...extraPaths.length > EXTRA_INSTALLED_PATHS_CAP ? { extraInstalledPathsTotal: extraPaths.length } : {}
|
|
109906
109965
|
};
|
|
109907
109966
|
}
|
|
@@ -109917,6 +109976,7 @@ function extraInstalledPathsAudit(binding) {
|
|
|
109917
109976
|
if (!binding || !Array.isArray(binding.extraInstalledPaths)) return {};
|
|
109918
109977
|
return {
|
|
109919
109978
|
extraInstalledPaths: binding.extraInstalledPaths,
|
|
109979
|
+
...Array.isArray(binding.extraInstalledLinks) && binding.extraInstalledLinks.length > 0 ? { extraInstalledLinks: binding.extraInstalledLinks } : {},
|
|
109920
109980
|
...binding.extraInstalledPathsTotal !== void 0 ? { extraInstalledPathsTotal: binding.extraInstalledPathsTotal } : {}
|
|
109921
109981
|
};
|
|
109922
109982
|
}
|
|
@@ -112320,6 +112380,7 @@ var init_plugin_marketplace = __esm({
|
|
|
112320
112380
|
async "src/adapters/plugin-marketplace.mjs"() {
|
|
112321
112381
|
init_contract();
|
|
112322
112382
|
init_installation_contract();
|
|
112383
|
+
init_src2();
|
|
112323
112384
|
init_frozen();
|
|
112324
112385
|
await init_registry2();
|
|
112325
112386
|
await init_kimi();
|
|
@@ -112332,6 +112393,8 @@ var init_plugin_marketplace = __esm({
|
|
|
112332
112393
|
PAYLOAD_CONTRACT_EXTERNAL_MARKETPLACE = "external-marketplace-v1";
|
|
112333
112394
|
EXTRA_INSTALLED_PATHS_CAP = 200;
|
|
112334
112395
|
PAYLOAD_CONFLICT_REPORT_CAP = 10;
|
|
112396
|
+
__name(foundationPayloadMembers, "foundationPayloadMembers");
|
|
112397
|
+
__name(observeMarketplaceInstallTree, "observeMarketplaceInstallTree");
|
|
112335
112398
|
CONSUMER_INSTALL_RECIPE_VERSION = "consumer-install-v1";
|
|
112336
112399
|
__name(resolveMarketplaceRoot, "resolveMarketplaceRoot");
|
|
112337
112400
|
__name(extractDeclaredPluginSource, "extractDeclaredPluginSource");
|
|
@@ -112451,6 +112514,23 @@ async function deriveSurfaceHostBinding({ manifest, pluginRoot, platform, snapsh
|
|
|
112451
112514
|
const host = await normalizeHostId(platform.buildAdapter.name);
|
|
112452
112515
|
return { surfaceId, host };
|
|
112453
112516
|
}
|
|
112517
|
+
function groupSurfaceHostBindings(claims = []) {
|
|
112518
|
+
if (!Array.isArray(claims)) {
|
|
112519
|
+
throw new TypeError("surfaceHostBindings must be an array");
|
|
112520
|
+
}
|
|
112521
|
+
const bySurface = /* @__PURE__ */ new Map();
|
|
112522
|
+
for (const claim of claims) {
|
|
112523
|
+
if (!claim || typeof claim !== "object" || typeof claim.surfaceId !== "string" || typeof claim.host !== "string") {
|
|
112524
|
+
throw new TypeError("surfaceHostBindings entries must be objects with string surfaceId and host");
|
|
112525
|
+
}
|
|
112526
|
+
const existing = bySurface.get(claim.surfaceId) ?? [];
|
|
112527
|
+
existing.push({ surfaceId: claim.surfaceId, host: claim.host });
|
|
112528
|
+
bySurface.set(claim.surfaceId, existing);
|
|
112529
|
+
}
|
|
112530
|
+
const coverageClaims = [...bySurface.values()].flat().sort((left, right) => left.surfaceId.localeCompare(right.surfaceId) || left.host.localeCompare(right.host));
|
|
112531
|
+
const checkerBindings = [...bySurface.values()].filter((surfaceClaims) => surfaceClaims.length === 1).map(([claim]) => claim).sort((left, right) => left.surfaceId.localeCompare(right.surfaceId) || left.host.localeCompare(right.host));
|
|
112532
|
+
return { coverageClaims, checkerBindings };
|
|
112533
|
+
}
|
|
112454
112534
|
var SKILLS_NORMALIZERS;
|
|
112455
112535
|
var init_surface_host_bindings = __esm({
|
|
112456
112536
|
async "src/core/surface-host-bindings.mjs"() {
|
|
@@ -112468,6 +112548,7 @@ var init_surface_host_bindings = __esm({
|
|
|
112468
112548
|
__name(pluginRootFromManifestRelativePath, "pluginRootFromManifestRelativePath");
|
|
112469
112549
|
__name(assertDeclaredSkillsDirExists, "assertDeclaredSkillsDirExists");
|
|
112470
112550
|
__name(deriveSurfaceHostBinding, "deriveSurfaceHostBinding");
|
|
112551
|
+
__name(groupSurfaceHostBindings, "groupSurfaceHostBindings");
|
|
112471
112552
|
}
|
|
112472
112553
|
});
|
|
112473
112554
|
|
|
@@ -113898,11 +113979,16 @@ async function verifyRelease(options) {
|
|
|
113898
113979
|
const unit = (plan.units ?? []).find((u) => u.id === unitId);
|
|
113899
113980
|
const dist = unit?.distributions?.find((d) => d.type === platform.distributionType);
|
|
113900
113981
|
let binding = null;
|
|
113982
|
+
let frozenPluginRoot = null;
|
|
113901
113983
|
const contract2 = dist?.installationContract;
|
|
113902
113984
|
if (contract2?.normalizedManifest) {
|
|
113985
|
+
frozenPluginRoot = pluginRootFromManifestRelativePath(contract2.manifestRelativePath);
|
|
113903
113986
|
binding = await deriveSurfaceHostBinding({
|
|
113904
113987
|
manifest: contract2.normalizedManifest,
|
|
113905
|
-
|
|
113988
|
+
// Adapter observations are already rooted at the installed
|
|
113989
|
+
// plugin. The frozen manifest's skills path is therefore
|
|
113990
|
+
// relative to '.', not to the snapshot-root manifest path.
|
|
113991
|
+
pluginRoot: ".",
|
|
113906
113992
|
platform,
|
|
113907
113993
|
snapshotDir: check.observation.installPath
|
|
113908
113994
|
});
|
|
@@ -113915,6 +114001,7 @@ async function verifyRelease(options) {
|
|
|
113915
114001
|
unitId,
|
|
113916
114002
|
surfaceId: binding?.surfaceId ?? ".",
|
|
113917
114003
|
binding,
|
|
114004
|
+
frozenPluginRoot,
|
|
113918
114005
|
unit
|
|
113919
114006
|
});
|
|
113920
114007
|
}
|
|
@@ -113997,7 +114084,7 @@ async function verifyRelease(options) {
|
|
|
113997
114084
|
);
|
|
113998
114085
|
}
|
|
113999
114086
|
const pluginDistCount = (surface.unit?.distributions ?? []).filter((d) => d.type !== "npm").length;
|
|
114000
|
-
if (pluginDistCount === 1) {
|
|
114087
|
+
if (pluginDistCount === 1 && surface.frozenPluginRoot === ".") {
|
|
114001
114088
|
const observedReceipt = createSkillResourceClosureReceipt(closureResult, {
|
|
114002
114089
|
unitId: surface.unitId,
|
|
114003
114090
|
preparedAt: expectedUnitReceipt.preparedAt ?? null,
|
|
@@ -129591,10 +129678,11 @@ async function runPrepareSkillResourceClosureGate({
|
|
|
129591
129678
|
});
|
|
129592
129679
|
if (binding) surfaceHostBindings.push(binding);
|
|
129593
129680
|
}
|
|
129681
|
+
const { checkerBindings, coverageClaims } = groupSurfaceHostBindings(surfaceHostBindings);
|
|
129594
129682
|
const closureResult = await checkSkillResourceClosure({
|
|
129595
129683
|
snapshotDir: manifest.outputDir,
|
|
129596
129684
|
host: "root",
|
|
129597
|
-
surfaceHostBindings
|
|
129685
|
+
surfaceHostBindings: checkerBindings
|
|
129598
129686
|
});
|
|
129599
129687
|
const receipt = createSkillResourceClosureReceipt(closureResult, {
|
|
129600
129688
|
unitId: unit.id,
|
|
@@ -129639,7 +129727,8 @@ async function runPrepareSkillResourceClosureGate({
|
|
|
129639
129727
|
}
|
|
129640
129728
|
const hostCoverage = evaluateDeclaredHostSurfaceCoverage(
|
|
129641
129729
|
expectedHosts,
|
|
129642
|
-
closureResult.surfaces
|
|
129730
|
+
closureResult.surfaces,
|
|
129731
|
+
coverageClaims
|
|
129643
129732
|
);
|
|
129644
129733
|
if (!hostCoverage.passed) {
|
|
129645
129734
|
await evidence.append({
|
|
@@ -129663,7 +129752,7 @@ async function runPrepareSkillResourceClosureGate({
|
|
|
129663
129752
|
}
|
|
129664
129753
|
);
|
|
129665
129754
|
}
|
|
129666
|
-
for (const binding of
|
|
129755
|
+
for (const binding of coverageClaims) {
|
|
129667
129756
|
const boundSurface = closureResult.surfaces.find(
|
|
129668
129757
|
(surface) => surface.id === binding.surfaceId
|
|
129669
129758
|
);
|
|
@@ -133273,10 +133362,11 @@ async function publishRelease(options) {
|
|
|
133273
133362
|
});
|
|
133274
133363
|
if (binding) surfaceHostBindings.push(binding);
|
|
133275
133364
|
}
|
|
133365
|
+
const { checkerBindings, coverageClaims } = groupSurfaceHostBindings(surfaceHostBindings);
|
|
133276
133366
|
const closureResult = await checkSkillResourceClosure({
|
|
133277
133367
|
snapshotDir,
|
|
133278
133368
|
host: "root",
|
|
133279
|
-
surfaceHostBindings
|
|
133369
|
+
surfaceHostBindings: checkerBindings
|
|
133280
133370
|
});
|
|
133281
133371
|
if (closureResult.findings.length > 0) {
|
|
133282
133372
|
await evidence.append({
|
|
@@ -133292,6 +133382,31 @@ async function publishRelease(options) {
|
|
|
133292
133382
|
{ unitId, findings: closureResult.findings }
|
|
133293
133383
|
);
|
|
133294
133384
|
}
|
|
133385
|
+
const expectedHosts = [];
|
|
133386
|
+
for (const distribution of frozenUnit?.distributions ?? []) {
|
|
133387
|
+
const platform = PLATFORMS.find((item) => item.distributionType === distribution.type);
|
|
133388
|
+
if (platform) expectedHosts.push(await normalizeHostId(platform.buildAdapter.name));
|
|
133389
|
+
}
|
|
133390
|
+
const hostCoverage = evaluateDeclaredHostSurfaceCoverage(
|
|
133391
|
+
expectedHosts,
|
|
133392
|
+
closureResult.surfaces,
|
|
133393
|
+
coverageClaims
|
|
133394
|
+
);
|
|
133395
|
+
if (!hostCoverage.passed) {
|
|
133396
|
+
await evidence.append({
|
|
133397
|
+
phase: "safety-gate",
|
|
133398
|
+
gate: "skill-resource-closure",
|
|
133399
|
+
status: "failed",
|
|
133400
|
+
unitId,
|
|
133401
|
+
reason: "declared-host-surface-missing",
|
|
133402
|
+
missingHosts: hostCoverage.missing
|
|
133403
|
+
});
|
|
133404
|
+
throw new ReleaseError(
|
|
133405
|
+
GATE_FAILED,
|
|
133406
|
+
`skill resource closure recheck failed for unit "${unitId}": declared host surface(s) missing or empty: ${hostCoverage.missing.map((item) => item.host).join(", ")}`,
|
|
133407
|
+
{ unitId, missingHosts: hostCoverage.missing }
|
|
133408
|
+
);
|
|
133409
|
+
}
|
|
133295
133410
|
const observed = createSkillResourceClosureReceipt(closureResult, {
|
|
133296
133411
|
unitId,
|
|
133297
133412
|
preparedAt: expected.preparedAt ?? null,
|
|
@@ -145779,7 +145894,7 @@ guardOutputStream(process.stdout);
|
|
|
145779
145894
|
guardOutputStream(process.stderr);
|
|
145780
145895
|
registerPathRedactor(redactSensitivePaths);
|
|
145781
145896
|
var execFile19 = promisify26(execFileCb22);
|
|
145782
|
-
var COMMANDS = /* @__PURE__ */ new Set(["help", "setup", "assess", "prepare", "approve", "publish", "reconcile", "verify", "ship", "post-release", "attest", "hooks", "artifacts", "docs", "distribute", "route", "lineage"]);
|
|
145897
|
+
var COMMANDS = /* @__PURE__ */ new Set(["help", "setup", "assess", "prepare", "approve", "publish", "reconcile", "verify", "postverify", "ship", "post-release", "attest", "hooks", "artifacts", "docs", "distribute", "route", "lineage"]);
|
|
145783
145898
|
function flushOutputStream(stream) {
|
|
145784
145899
|
if (!stream?.writable || stream.destroyed || stream.writableEnded || outputStreamStates.get(stream)?.failed) {
|
|
145785
145900
|
return Promise.resolve();
|
|
@@ -145970,6 +146085,11 @@ function getCapabilityMaturity() {
|
|
|
145970
146085
|
mode: "fresh consumer verification (protocol-tested; no OS/network sandbox)",
|
|
145971
146086
|
description: "Recheck remote state, exact npm installation, CLI help, and automated Claude/Codex installs before VERIFIED; Kimi/CodeBuddy remain unverified manual follow-ups"
|
|
145972
146087
|
},
|
|
146088
|
+
postverify: {
|
|
146089
|
+
available: true,
|
|
146090
|
+
mode: "independent postVerify execution",
|
|
146091
|
+
description: "Run approved postVerify hooks from a VERIFIED run in an independent run; never reads or writes ship state"
|
|
146092
|
+
},
|
|
145973
146093
|
distribute: {
|
|
145974
146094
|
available: true,
|
|
145975
146095
|
mode: "controlled production (protocol-tested; no OS/network sandbox)",
|
|
@@ -146003,6 +146123,7 @@ Commands:
|
|
|
146003
146123
|
publish Publish frozen GitHub/npm artifacts after approval
|
|
146004
146124
|
reconcile Resume PARTIAL state from evidence; conflicts require a human
|
|
146005
146125
|
verify Fresh remote and consumer verification; only this reaches VERIFIED
|
|
146126
|
+
postverify Run approved postVerify hooks from a VERIFIED run in an independent run
|
|
146006
146127
|
ship Resume one durable prepare -> approve -> publish -> verify flow; completes a parked
|
|
146007
146128
|
postVerify hook once its checkpoint approval is provided (--hook-approval)
|
|
146008
146129
|
post-release Inspect optional local finishing work after VERIFIED; update installed host plugins
|
|
@@ -146017,10 +146138,10 @@ Commands:
|
|
|
146017
146138
|
|
|
146018
146139
|
Options:
|
|
146019
146140
|
--root <path> Project root directory (default: cwd)
|
|
146020
|
-
--plan <path> Path to the release plan file
|
|
146141
|
+
--plan <path> Path to the release plan file (required for approve/publish/reconcile/verify/postverify)
|
|
146021
146142
|
--run <path> Path to the release run file, or a run directory whose release-run.json
|
|
146022
|
-
is resolved automatically (required for reconcile/verify)
|
|
146023
|
-
--approval <path> Path to the approval record
|
|
146143
|
+
is resolved automatically (required for reconcile/verify/postverify)
|
|
146144
|
+
--approval <path> Path to the release-level approval record (required for publish/postverify)
|
|
146024
146145
|
--production Prepare immutable Git/npm production artifacts
|
|
146025
146146
|
--output <path> Override prepare/approve output path (non-production only)
|
|
146026
146147
|
--run-dir <path> Override prepare run directory; production requires one direct child of .release-skill/runs
|
|
@@ -146057,7 +146178,7 @@ Options:
|
|
|
146057
146178
|
--install-path <path> Actual managed plugin path when closure verification requires it
|
|
146058
146179
|
--install-channel <desktop|cli> CodeBuddy installation channel when required
|
|
146059
146180
|
--approve Approve the ship plan (boolean; plan digest is auto-resolved)
|
|
146060
|
-
--hook-approval <path> Checkpoint approval for
|
|
146181
|
+
--hook-approval <path> Checkpoint approval for one requiresApproval hook (ship/distribute/postverify; repeatable)
|
|
146061
146182
|
--state <path> Override the durable ship state file
|
|
146062
146183
|
--update-local-hosts Update installed plugins for selected local hosts after VERIFIED
|
|
146063
146184
|
--hosts <ids> Comma-separated local hosts for post-release update. No local host is updated unless --hosts contains at least one id
|
|
@@ -147076,6 +147197,117 @@ if (command === "verify") {
|
|
|
147076
147197
|
await exitAfterFlush(err.exitCode ?? 1);
|
|
147077
147198
|
}
|
|
147078
147199
|
}
|
|
147200
|
+
if (command === "postverify") {
|
|
147201
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
147202
|
+
const helpText = `release-skill postverify - Run approved postVerify hooks from a VERIFIED run
|
|
147203
|
+
|
|
147204
|
+
Usage:
|
|
147205
|
+
release-skill postverify [--root <path>] --plan <path> --approval <path> --run <path> [options]
|
|
147206
|
+
|
|
147207
|
+
Required options:
|
|
147208
|
+
--plan <path> Path to the release plan file
|
|
147209
|
+
--approval <path> Path to the release-level approval record
|
|
147210
|
+
--run <path> Path to the VERIFIED verify run file or directory
|
|
147211
|
+
|
|
147212
|
+
Optional options:
|
|
147213
|
+
--root <path> Project root directory (default: cwd)
|
|
147214
|
+
--hook-approval <path> Checkpoint approval for a requiresApproval postVerify hook (repeatable)
|
|
147215
|
+
--json Output results as JSON
|
|
147216
|
+
-h, --help Show this help message and exit
|
|
147217
|
+
|
|
147218
|
+
This command creates an independent postVerify run and never reads or writes ship state.`;
|
|
147219
|
+
if (hasJson) {
|
|
147220
|
+
console.log(JSON.stringify({
|
|
147221
|
+
command: "postverify",
|
|
147222
|
+
status: "HELP",
|
|
147223
|
+
usage: "release-skill postverify [--root <path>] --plan <path> --approval <path> --run <path> [options]",
|
|
147224
|
+
options: {
|
|
147225
|
+
"--root": "Project root directory (default: cwd)",
|
|
147226
|
+
"--plan": "Path to the release plan file (required)",
|
|
147227
|
+
"--approval": "Path to the release-level approval record (required)",
|
|
147228
|
+
"--run": "Path to the VERIFIED verify run file or directory (required)",
|
|
147229
|
+
"--hook-approval": "Checkpoint approval for a requiresApproval postVerify hook (repeatable)",
|
|
147230
|
+
"--json": "Output results as JSON",
|
|
147231
|
+
"-h, --help": "Show this help message and exit"
|
|
147232
|
+
},
|
|
147233
|
+
message: "Creates an independent postVerify run and never reads or writes ship state."
|
|
147234
|
+
}, null, 2));
|
|
147235
|
+
} else {
|
|
147236
|
+
console.log(helpText);
|
|
147237
|
+
}
|
|
147238
|
+
await exitAfterFlush(0);
|
|
147239
|
+
}
|
|
147240
|
+
let malformedValuedFlag;
|
|
147241
|
+
const value = /* @__PURE__ */ __name((flag) => {
|
|
147242
|
+
let firstValue;
|
|
147243
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
147244
|
+
if (args[i] !== flag) continue;
|
|
147245
|
+
const next = args[i + 1];
|
|
147246
|
+
if (!next || next.startsWith("-")) {
|
|
147247
|
+
malformedValuedFlag ??= flag;
|
|
147248
|
+
continue;
|
|
147249
|
+
}
|
|
147250
|
+
firstValue ??= next;
|
|
147251
|
+
}
|
|
147252
|
+
return firstValue;
|
|
147253
|
+
}, "value");
|
|
147254
|
+
const root = resolve41(value("--root") ?? process.cwd());
|
|
147255
|
+
const planPath = value("--plan");
|
|
147256
|
+
const approvalPath = value("--approval");
|
|
147257
|
+
const runPath = value("--run");
|
|
147258
|
+
const postpublishApprovalPaths = [];
|
|
147259
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
147260
|
+
if (args[i] === "--hook-approval") {
|
|
147261
|
+
const next = args[i + 1];
|
|
147262
|
+
if (!next || next.startsWith("-")) {
|
|
147263
|
+
malformedValuedFlag ??= "--hook-approval";
|
|
147264
|
+
} else {
|
|
147265
|
+
postpublishApprovalPaths.push(resolve41(next));
|
|
147266
|
+
}
|
|
147267
|
+
}
|
|
147268
|
+
}
|
|
147269
|
+
if (malformedValuedFlag || !planPath || !approvalPath || !runPath) {
|
|
147270
|
+
const msg = "postverify requires --plan <path>, --approval <path>, and --run <path>";
|
|
147271
|
+
if (hasJson) {
|
|
147272
|
+
console.log(JSON.stringify({ error: MISSING_PARAMETERS, message: msg, exitCode: EXIT_CODE_MAP[MISSING_PARAMETERS] }));
|
|
147273
|
+
} else {
|
|
147274
|
+
console.error(`Error: ${msg}`);
|
|
147275
|
+
}
|
|
147276
|
+
await exitAfterFlush(EXIT_CODE_MAP[MISSING_PARAMETERS]);
|
|
147277
|
+
}
|
|
147278
|
+
try {
|
|
147279
|
+
const { postVerifyRelease: postVerifyRelease2 } = await init_postverify().then(() => postverify_exports);
|
|
147280
|
+
const result2 = await postVerifyRelease2({
|
|
147281
|
+
planPath: resolve41(planPath),
|
|
147282
|
+
approvalPath: resolve41(approvalPath),
|
|
147283
|
+
sourceRunPath: resolve41(runPath),
|
|
147284
|
+
root,
|
|
147285
|
+
...postpublishApprovalPaths.length > 0 ? { postpublishApprovalPaths } : {}
|
|
147286
|
+
});
|
|
147287
|
+
if (hasJson) {
|
|
147288
|
+
console.log(JSON.stringify(result2, null, 2));
|
|
147289
|
+
} else {
|
|
147290
|
+
console.log(`PostVerify status: ${result2.status}`);
|
|
147291
|
+
for (const cp4 of result2.checkpoints ?? []) {
|
|
147292
|
+
console.log(` ${cp4.actionId}: ${cp4.status}`);
|
|
147293
|
+
}
|
|
147294
|
+
if (result2.runPath) console.log(`PostVerify run: ${result2.runPath}`);
|
|
147295
|
+
}
|
|
147296
|
+
await exitAfterFlush(result2.status === "DISTRIBUTED" ? 0 : 1);
|
|
147297
|
+
} catch (err) {
|
|
147298
|
+
if (hasJson) {
|
|
147299
|
+
console.log(JSON.stringify({
|
|
147300
|
+
error: err.code ?? "UNKNOWN_ERROR",
|
|
147301
|
+
message: err.message,
|
|
147302
|
+
details: err.details ?? {},
|
|
147303
|
+
exitCode: err.exitCode ?? 1
|
|
147304
|
+
}));
|
|
147305
|
+
} else {
|
|
147306
|
+
console.error(`Error: ${err.message}`);
|
|
147307
|
+
}
|
|
147308
|
+
await exitAfterFlush(err.exitCode ?? 1);
|
|
147309
|
+
}
|
|
147310
|
+
}
|
|
147079
147311
|
if (command === "publish") {
|
|
147080
147312
|
const rootIdx = args.indexOf("--root");
|
|
147081
147313
|
const rawRoot = rootIdx !== -1 && args[rootIdx + 1] ? args[rootIdx + 1] : process.cwd();
|
package/package.json
CHANGED
package/platform-manifest.json
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"schemaVersion": "1.0.0",
|
|
3
3
|
"platformId": "release-skill",
|
|
4
4
|
"platformName": "release-skill Plugin Platform",
|
|
5
|
-
"version": "0.9.
|
|
5
|
+
"version": "0.9.7",
|
|
6
6
|
"logicalRoot": "skills-src/",
|
|
7
|
-
"logicalRootDigest": "
|
|
8
|
-
"projectionDigest": "
|
|
9
|
-
"projectionId": "release-skill:platform:0.9.
|
|
7
|
+
"logicalRootDigest": "4338c7c5a7efd38ca372049526e5bdd198087491f76702cd21d491741bfad835",
|
|
8
|
+
"projectionDigest": "c4d40afd481d78907d51ef9be1dc2238834d566b9a9792f1d25da19f57368d7d",
|
|
9
|
+
"projectionId": "release-skill:platform:0.9.7",
|
|
10
10
|
"manifestRequired": true,
|
|
11
11
|
"projectionSources": {
|
|
12
12
|
"skills-src-root": {
|