release-skill 0.9.16 → 0.9.18
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/plugin.json +1 -1
- package/.codebuddy-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +2 -2
- package/.cursor-plugin/plugin.json +10 -0
- package/.kimi-plugin/plugin.json +1 -1
- package/.qoder-plugin/plugin.json +10 -0
- package/CHANGELOG.md +64 -0
- package/INSTALL.md +104 -9
- package/INSTALL.zh-CN.md +78 -7
- package/README.md +87 -32
- package/README.zh-CN.md +71 -30
- package/adapters/claude/.claude-plugin/plugin.json +1 -1
- package/adapters/claude/bin/consumer-contract-vectors.json +7 -7
- package/adapters/claude/bin/error-codes.json +1 -1
- package/adapters/claude/bin/foundation-resource-binding.json +1 -1
- package/adapters/claude/bin/prebuild-manifest.json +8 -4
- package/adapters/claude/bin/prebuilds/darwin-arm64/bound_read.darwin-arm64.node +0 -0
- package/adapters/claude/bin/prebuilds/darwin-x64/bound_read.darwin-x64.node +0 -0
- package/adapters/claude/bin/prebuilds/linux-arm64-gnu/bound_read.linux-arm64-gnu.node +0 -0
- package/adapters/claude/bin/prebuilds/linux-x64-gnu/bound_read.linux-x64-gnu.node +0 -0
- package/adapters/claude/bin/registry.json +1 -1
- package/adapters/claude/bin/release-skill.bundle.mjs +4950 -1819
- package/adapters/claude/bin/rules.json +1 -1
- package/adapters/claude/data/hosts/cursor/host-descriptor.json +34 -0
- package/adapters/claude/data/hosts/registry.json +1 -0
- package/adapters/claude/schemas/release-plan.schema.json +255 -25
- package/adapters/claude/schemas/release-project.schema.json +228 -26
- package/adapters/claude/skills/release-finish/SKILL.md +29 -15
- package/adapters/claude/skills/release-help/SKILL.md +40 -39
- package/adapters/claude/skills/release-verify/SKILL.md +2 -2
- package/adapters/claude/src/schemas/host-descriptor.schema.json +9 -2
- package/adapters/codex/.codex-plugin/plugin.json +2 -2
- package/adapters/codex/bin/consumer-contract-vectors.json +7 -7
- package/adapters/codex/bin/error-codes.json +1 -1
- package/adapters/codex/bin/foundation-resource-binding.json +1 -1
- package/adapters/codex/bin/prebuild-manifest.json +8 -4
- package/adapters/codex/bin/prebuilds/darwin-arm64/bound_read.darwin-arm64.node +0 -0
- package/adapters/codex/bin/prebuilds/darwin-x64/bound_read.darwin-x64.node +0 -0
- package/adapters/codex/bin/prebuilds/linux-arm64-gnu/bound_read.linux-arm64-gnu.node +0 -0
- package/adapters/codex/bin/prebuilds/linux-x64-gnu/bound_read.linux-x64-gnu.node +0 -0
- package/adapters/codex/bin/registry.json +1 -1
- package/adapters/codex/bin/release-skill.bundle.mjs +4950 -1819
- package/adapters/codex/bin/rules.json +1 -1
- package/adapters/codex/data/hosts/cursor/host-descriptor.json +34 -0
- package/adapters/codex/data/hosts/registry.json +1 -0
- package/adapters/codex/schemas/release-plan.schema.json +255 -25
- package/adapters/codex/schemas/release-project.schema.json +228 -26
- package/adapters/codex/skills/release-finish/SKILL.md +29 -15
- package/adapters/codex/skills/release-help/SKILL.md +40 -39
- package/adapters/codex/skills/release-verify/SKILL.md +2 -2
- package/adapters/codex/src/schemas/host-descriptor.schema.json +9 -2
- package/adapters/cursor/.cursor-plugin/plugin.json +10 -0
- package/adapters/cursor/bin/consumer-contract-vectors.json +110 -0
- package/adapters/cursor/bin/error-codes.json +161 -0
- package/adapters/cursor/bin/foundation-legal/skill-family-contracts/LICENSE +202 -0
- package/adapters/cursor/bin/foundation-legal/skill-family-contracts/NOTICE +10 -0
- package/adapters/cursor/bin/foundation-legal/skill-family-engineering-kit/LICENSE +202 -0
- package/adapters/cursor/bin/foundation-legal/skill-family-engineering-kit/NOTICE +10 -0
- package/adapters/cursor/bin/foundation-legal/skill-family-engineering-kit/THIRD_PARTY_NOTICES +142 -0
- package/adapters/cursor/bin/foundation-legal/skill-family-harness-node/LICENSE +202 -0
- package/adapters/cursor/bin/foundation-legal/skill-family-harness-node/NOTICE +10 -0
- package/adapters/cursor/bin/foundation-legal/skill-family-harness-node/native-NOTICE +2 -0
- package/adapters/cursor/bin/foundation-resource-binding.json +1 -0
- package/adapters/cursor/bin/kernel-protocol.json +60 -0
- package/adapters/cursor/bin/license-texts/Apache-2.0.txt +201 -0
- package/adapters/cursor/bin/license-texts/MIT.txt +21 -0
- package/adapters/cursor/bin/prebuild-manifest.json +83 -0
- package/adapters/cursor/bin/prebuilds/darwin-arm64/bound_read.darwin-arm64.node +0 -0
- package/adapters/cursor/bin/prebuilds/darwin-x64/bound_read.darwin-x64.node +0 -0
- package/adapters/cursor/bin/prebuilds/linux-arm64-gnu/bound_read.linux-arm64-gnu.node +0 -0
- package/adapters/cursor/bin/prebuilds/linux-x64-gnu/bound_read.linux-x64-gnu.node +0 -0
- package/adapters/cursor/bin/registry.json +347 -0
- package/adapters/cursor/bin/release-skill-local-finish.mjs +4 -0
- package/adapters/cursor/bin/release-skill.bundle.mjs +151806 -0
- package/adapters/cursor/bin/release-skill.mjs +54 -0
- package/adapters/cursor/bin/rules.json +104 -0
- package/adapters/cursor/bin/schemas/consumer-contract-vector.schema.json +149 -0
- package/adapters/cursor/data/hosts/claude/host-descriptor.json +45 -0
- package/adapters/cursor/data/hosts/codebuddy/host-descriptor.json +26 -0
- package/adapters/cursor/data/hosts/codex/host-descriptor.json +45 -0
- package/adapters/cursor/data/hosts/cursor/host-descriptor.json +34 -0
- package/adapters/cursor/data/hosts/deepseek-harness/host-descriptor.json +23 -0
- package/adapters/cursor/data/hosts/kimi-code/host-descriptor.json +36 -0
- package/adapters/cursor/data/hosts/qoder/host-descriptor.json +26 -0
- package/adapters/cursor/data/hosts/registry.json +14 -0
- package/adapters/cursor/data/hosts/workbuddy/host-descriptor.json +34 -0
- package/adapters/cursor/data/licensing/registry.json +211 -0
- package/adapters/cursor/data/licensing/schema.json +207 -0
- package/adapters/cursor/native/safe-write/binding.gyp +41 -0
- package/adapters/cursor/native/safe-write/prebuilds/darwin-arm64/safe_write.node +0 -0
- package/adapters/cursor/native/safe-write/prebuilds.json +24 -0
- package/adapters/cursor/native/safe-write/src/safe_write.cc +2032 -0
- package/adapters/cursor/schemas/.render-manifest.json +41 -0
- package/adapters/cursor/schemas/approval-record.schema.json +115 -0
- package/adapters/cursor/schemas/artifact-lock.schema.json +111 -0
- package/adapters/cursor/schemas/artifact-plan.schema.json +52 -0
- package/adapters/cursor/schemas/artifact-policy.schema.json +76 -0
- package/adapters/cursor/schemas/evidence-event-v2.schema.json +164 -0
- package/adapters/cursor/schemas/evidence-event.schema.json +89 -0
- package/adapters/cursor/schemas/postpublish-approval-record.schema.json +47 -0
- package/adapters/cursor/schemas/release-plan.schema.json +2226 -0
- package/adapters/cursor/schemas/release-project.schema.json +1815 -0
- package/adapters/cursor/schemas/release-run.schema.json +777 -0
- package/adapters/cursor/skills/release-assess/SKILL.md +61 -0
- package/adapters/cursor/skills/release-config/SKILL.md +151 -0
- package/adapters/cursor/skills/release-docs/SKILL.md +120 -0
- package/adapters/cursor/skills/release-finish/SKILL.md +155 -0
- package/adapters/cursor/skills/release-help/SKILL.md +155 -0
- package/adapters/cursor/skills/release-marketplace/SKILL.md +157 -0
- package/adapters/cursor/skills/release-prepare/SKILL.md +136 -0
- package/adapters/cursor/skills/release-publish/SKILL.md +92 -0
- package/adapters/cursor/skills/release-reconcile/SKILL.md +81 -0
- package/adapters/cursor/skills/release-setup/SKILL.md +132 -0
- package/adapters/cursor/skills/release-verify/SKILL.md +110 -0
- package/adapters/cursor/src/schemas/adapter-build-manifest.schema.json +41 -0
- package/adapters/cursor/src/schemas/adapter-peer-verification-request.schema.json +54 -0
- package/adapters/cursor/src/schemas/adapter-peer-verification-result.schema.json +54 -0
- package/adapters/cursor/src/schemas/adapter-source.schema.json +47 -0
- package/adapters/cursor/src/schemas/audit-baseline-pin.schema.json +163 -0
- package/adapters/cursor/src/schemas/declared-read-surface-result.schema.json +61 -0
- package/adapters/cursor/src/schemas/engineering-baseline.schema.json +77 -0
- package/adapters/cursor/src/schemas/executable-identity-observation.schema.json +162 -0
- package/adapters/cursor/src/schemas/filesystem-root-binding.schema.json +14 -0
- package/adapters/cursor/src/schemas/filesystem-tree-observation.schema.json +71 -0
- package/adapters/cursor/src/schemas/fixed-set-publication-manifest.schema.json +108 -0
- package/adapters/cursor/src/schemas/fixed-set-publication-receipt.schema.json +148 -0
- package/adapters/cursor/src/schemas/host-capability-fact.schema.json +31 -0
- package/adapters/cursor/src/schemas/host-descriptor.schema.json +144 -0
- package/adapters/cursor/src/schemas/host-operation-plan.schema.json +57 -0
- package/adapters/cursor/src/schemas/host-operation-receipt.schema.json +81 -0
- package/adapters/cursor/src/schemas/host-probe-result.schema.json +30 -0
- package/adapters/cursor/src/schemas/host-registry.schema.json +18 -0
- package/adapters/cursor/src/schemas/host-verification-request.schema.json +67 -0
- package/adapters/cursor/src/schemas/host-verification-result.schema.json +149 -0
- package/adapters/cursor/src/schemas/managed-file-lock.schema.json +77 -0
- package/adapters/cursor/src/schemas/migration-manifest.schema.json +412 -0
- package/adapters/cursor/src/schemas/observation-scope.schema.json +91 -0
- package/adapters/cursor/src/schemas/operation-request.schema.json +58 -0
- package/adapters/cursor/src/schemas/operation-result.schema.json +130 -0
- package/adapters/cursor/src/schemas/platform-difference-registry.schema.json +110 -0
- package/adapters/cursor/src/schemas/plugin-verification-request.schema.json +499 -0
- package/adapters/cursor/src/schemas/plugin-verification-result.schema.json +1217 -0
- package/adapters/cursor/src/schemas/profile-adoption-declaration.schema.json +111 -0
- package/adapters/cursor/src/schemas/profile-descriptor.schema.json +99 -0
- package/adapters/cursor/src/schemas/project-manifest.schema.json +67 -0
- package/adapters/cursor/src/schemas/project-profile.schema.json +25 -0
- package/adapters/cursor/src/schemas/public-boundary-declaration.schema.json +73 -0
- package/adapters/cursor/src/schemas/report-binding.schema.json +42 -0
- package/adapters/cursor/src/schemas/report-model.schema.json +308 -0
- package/adapters/cursor/src/schemas/skill-family-directory-verification-request.schema.json +100 -0
- package/adapters/cursor/src/schemas/skill-family-directory-verification-result.schema.json +193 -0
- package/adapters/cursor/src/schemas/source-authority-receipt.schema.json +31 -0
- package/adapters/cursor/src/schemas/state-event-envelope.schema.json +38 -0
- package/adapters/cursor/src/schemas/state-snapshot-metadata.schema.json +25 -0
- package/adapters/cursor/src/schemas/structured-scan-policy.schema.json +97 -0
- package/adapters/cursor/src/schemas/surface-scan-policy.schema.json +42 -0
- package/adapters/cursor/src/schemas/timeout-policy.schema.json +24 -0
- package/adapters/cursor/src/schemas/token-estimate-record.schema.json +75 -0
- package/adapters/cursor/src/schemas/token-estimate-result.schema.json +43 -0
- package/adapters/cursor/src/schemas/watchdog-termination-envelope.schema.json +156 -0
- package/adapters/kimi/.kimi-plugin/plugin.json +1 -1
- package/adapters/kimi/bin/consumer-contract-vectors.json +7 -7
- package/adapters/kimi/bin/error-codes.json +1 -1
- package/adapters/kimi/bin/foundation-resource-binding.json +1 -1
- package/adapters/kimi/bin/prebuild-manifest.json +8 -4
- package/adapters/kimi/bin/prebuilds/darwin-arm64/bound_read.darwin-arm64.node +0 -0
- package/adapters/kimi/bin/prebuilds/darwin-x64/bound_read.darwin-x64.node +0 -0
- package/adapters/kimi/bin/prebuilds/linux-arm64-gnu/bound_read.linux-arm64-gnu.node +0 -0
- package/adapters/kimi/bin/prebuilds/linux-x64-gnu/bound_read.linux-x64-gnu.node +0 -0
- package/adapters/kimi/bin/registry.json +1 -1
- package/adapters/kimi/bin/release-skill.bundle.mjs +4950 -1819
- package/adapters/kimi/bin/rules.json +1 -1
- package/adapters/kimi/data/hosts/cursor/host-descriptor.json +34 -0
- package/adapters/kimi/data/hosts/registry.json +1 -0
- package/adapters/kimi/schemas/release-plan.schema.json +255 -25
- package/adapters/kimi/schemas/release-project.schema.json +228 -26
- package/adapters/kimi/skills/release-finish/SKILL.md +29 -15
- package/adapters/kimi/skills/release-help/SKILL.md +40 -39
- package/adapters/kimi/skills/release-verify/SKILL.md +2 -2
- package/adapters/kimi/src/schemas/host-descriptor.schema.json +9 -2
- package/adapters/qoder/.qoder-plugin/plugin.json +10 -0
- package/adapters/qoder/bin/consumer-contract-vectors.json +110 -0
- package/adapters/qoder/bin/error-codes.json +161 -0
- package/adapters/qoder/bin/foundation-legal/skill-family-contracts/LICENSE +202 -0
- package/adapters/qoder/bin/foundation-legal/skill-family-contracts/NOTICE +10 -0
- package/adapters/qoder/bin/foundation-legal/skill-family-engineering-kit/LICENSE +202 -0
- package/adapters/qoder/bin/foundation-legal/skill-family-engineering-kit/NOTICE +10 -0
- package/adapters/qoder/bin/foundation-legal/skill-family-engineering-kit/THIRD_PARTY_NOTICES +142 -0
- package/adapters/qoder/bin/foundation-legal/skill-family-harness-node/LICENSE +202 -0
- package/adapters/qoder/bin/foundation-legal/skill-family-harness-node/NOTICE +10 -0
- package/adapters/qoder/bin/foundation-legal/skill-family-harness-node/native-NOTICE +2 -0
- package/adapters/qoder/bin/foundation-resource-binding.json +1 -0
- package/adapters/qoder/bin/kernel-protocol.json +60 -0
- package/adapters/qoder/bin/license-texts/Apache-2.0.txt +201 -0
- package/adapters/qoder/bin/license-texts/MIT.txt +21 -0
- package/adapters/qoder/bin/prebuild-manifest.json +83 -0
- package/adapters/qoder/bin/prebuilds/darwin-arm64/bound_read.darwin-arm64.node +0 -0
- package/adapters/qoder/bin/prebuilds/darwin-x64/bound_read.darwin-x64.node +0 -0
- package/adapters/qoder/bin/prebuilds/linux-arm64-gnu/bound_read.linux-arm64-gnu.node +0 -0
- package/adapters/qoder/bin/prebuilds/linux-x64-gnu/bound_read.linux-x64-gnu.node +0 -0
- package/adapters/qoder/bin/registry.json +347 -0
- package/adapters/qoder/bin/release-skill-local-finish.mjs +4 -0
- package/adapters/qoder/bin/release-skill.bundle.mjs +151806 -0
- package/adapters/qoder/bin/release-skill.mjs +54 -0
- package/adapters/qoder/bin/rules.json +104 -0
- package/adapters/qoder/bin/schemas/consumer-contract-vector.schema.json +149 -0
- package/adapters/qoder/data/hosts/claude/host-descriptor.json +45 -0
- package/adapters/qoder/data/hosts/codebuddy/host-descriptor.json +26 -0
- package/adapters/qoder/data/hosts/codex/host-descriptor.json +45 -0
- package/adapters/qoder/data/hosts/cursor/host-descriptor.json +34 -0
- package/adapters/qoder/data/hosts/deepseek-harness/host-descriptor.json +23 -0
- package/adapters/qoder/data/hosts/kimi-code/host-descriptor.json +36 -0
- package/adapters/qoder/data/hosts/qoder/host-descriptor.json +26 -0
- package/adapters/qoder/data/hosts/registry.json +14 -0
- package/adapters/qoder/data/hosts/workbuddy/host-descriptor.json +34 -0
- package/adapters/qoder/data/licensing/registry.json +211 -0
- package/adapters/qoder/data/licensing/schema.json +207 -0
- package/adapters/qoder/native/safe-write/binding.gyp +41 -0
- package/adapters/qoder/native/safe-write/prebuilds/darwin-arm64/safe_write.node +0 -0
- package/adapters/qoder/native/safe-write/prebuilds.json +24 -0
- package/adapters/qoder/native/safe-write/src/safe_write.cc +2032 -0
- package/adapters/qoder/schemas/.render-manifest.json +41 -0
- package/adapters/qoder/schemas/approval-record.schema.json +115 -0
- package/adapters/qoder/schemas/artifact-lock.schema.json +111 -0
- package/adapters/qoder/schemas/artifact-plan.schema.json +52 -0
- package/adapters/qoder/schemas/artifact-policy.schema.json +76 -0
- package/adapters/qoder/schemas/evidence-event-v2.schema.json +164 -0
- package/adapters/qoder/schemas/evidence-event.schema.json +89 -0
- package/adapters/qoder/schemas/postpublish-approval-record.schema.json +47 -0
- package/adapters/qoder/schemas/release-plan.schema.json +2226 -0
- package/adapters/qoder/schemas/release-project.schema.json +1815 -0
- package/adapters/qoder/schemas/release-run.schema.json +777 -0
- package/adapters/qoder/skills/release-assess/SKILL.md +60 -0
- package/adapters/qoder/skills/release-config/SKILL.md +150 -0
- package/adapters/qoder/skills/release-docs/SKILL.md +119 -0
- package/adapters/qoder/skills/release-finish/SKILL.md +154 -0
- package/adapters/qoder/skills/release-help/SKILL.md +154 -0
- package/adapters/qoder/skills/release-marketplace/SKILL.md +156 -0
- package/adapters/qoder/skills/release-prepare/SKILL.md +135 -0
- package/adapters/qoder/skills/release-publish/SKILL.md +91 -0
- package/adapters/qoder/skills/release-reconcile/SKILL.md +80 -0
- package/adapters/qoder/skills/release-setup/SKILL.md +131 -0
- package/adapters/qoder/skills/release-verify/SKILL.md +109 -0
- package/adapters/qoder/src/schemas/adapter-build-manifest.schema.json +41 -0
- package/adapters/qoder/src/schemas/adapter-peer-verification-request.schema.json +54 -0
- package/adapters/qoder/src/schemas/adapter-peer-verification-result.schema.json +54 -0
- package/adapters/qoder/src/schemas/adapter-source.schema.json +47 -0
- package/adapters/qoder/src/schemas/audit-baseline-pin.schema.json +163 -0
- package/adapters/qoder/src/schemas/declared-read-surface-result.schema.json +61 -0
- package/adapters/qoder/src/schemas/engineering-baseline.schema.json +77 -0
- package/adapters/qoder/src/schemas/executable-identity-observation.schema.json +162 -0
- package/adapters/qoder/src/schemas/filesystem-root-binding.schema.json +14 -0
- package/adapters/qoder/src/schemas/filesystem-tree-observation.schema.json +71 -0
- package/adapters/qoder/src/schemas/fixed-set-publication-manifest.schema.json +108 -0
- package/adapters/qoder/src/schemas/fixed-set-publication-receipt.schema.json +148 -0
- package/adapters/qoder/src/schemas/host-capability-fact.schema.json +31 -0
- package/adapters/qoder/src/schemas/host-descriptor.schema.json +144 -0
- package/adapters/qoder/src/schemas/host-operation-plan.schema.json +57 -0
- package/adapters/qoder/src/schemas/host-operation-receipt.schema.json +81 -0
- package/adapters/qoder/src/schemas/host-probe-result.schema.json +30 -0
- package/adapters/qoder/src/schemas/host-registry.schema.json +18 -0
- package/adapters/qoder/src/schemas/host-verification-request.schema.json +67 -0
- package/adapters/qoder/src/schemas/host-verification-result.schema.json +149 -0
- package/adapters/qoder/src/schemas/managed-file-lock.schema.json +77 -0
- package/adapters/qoder/src/schemas/migration-manifest.schema.json +412 -0
- package/adapters/qoder/src/schemas/observation-scope.schema.json +91 -0
- package/adapters/qoder/src/schemas/operation-request.schema.json +58 -0
- package/adapters/qoder/src/schemas/operation-result.schema.json +130 -0
- package/adapters/qoder/src/schemas/platform-difference-registry.schema.json +110 -0
- package/adapters/qoder/src/schemas/plugin-verification-request.schema.json +499 -0
- package/adapters/qoder/src/schemas/plugin-verification-result.schema.json +1217 -0
- package/adapters/qoder/src/schemas/profile-adoption-declaration.schema.json +111 -0
- package/adapters/qoder/src/schemas/profile-descriptor.schema.json +99 -0
- package/adapters/qoder/src/schemas/project-manifest.schema.json +67 -0
- package/adapters/qoder/src/schemas/project-profile.schema.json +25 -0
- package/adapters/qoder/src/schemas/public-boundary-declaration.schema.json +73 -0
- package/adapters/qoder/src/schemas/report-binding.schema.json +42 -0
- package/adapters/qoder/src/schemas/report-model.schema.json +308 -0
- package/adapters/qoder/src/schemas/skill-family-directory-verification-request.schema.json +100 -0
- package/adapters/qoder/src/schemas/skill-family-directory-verification-result.schema.json +193 -0
- package/adapters/qoder/src/schemas/source-authority-receipt.schema.json +31 -0
- package/adapters/qoder/src/schemas/state-event-envelope.schema.json +38 -0
- package/adapters/qoder/src/schemas/state-snapshot-metadata.schema.json +25 -0
- package/adapters/qoder/src/schemas/structured-scan-policy.schema.json +97 -0
- package/adapters/qoder/src/schemas/surface-scan-policy.schema.json +42 -0
- package/adapters/qoder/src/schemas/timeout-policy.schema.json +24 -0
- package/adapters/qoder/src/schemas/token-estimate-record.schema.json +75 -0
- package/adapters/qoder/src/schemas/token-estimate-result.schema.json +43 -0
- package/adapters/qoder/src/schemas/watchdog-termination-envelope.schema.json +156 -0
- package/adapters/workbuddy/.codebuddy-plugin/plugin.json +1 -1
- package/adapters/workbuddy/bin/consumer-contract-vectors.json +7 -7
- package/adapters/workbuddy/bin/error-codes.json +1 -1
- package/adapters/workbuddy/bin/foundation-resource-binding.json +1 -1
- package/adapters/workbuddy/bin/prebuild-manifest.json +8 -4
- package/adapters/workbuddy/bin/prebuilds/darwin-arm64/bound_read.darwin-arm64.node +0 -0
- package/adapters/workbuddy/bin/prebuilds/darwin-x64/bound_read.darwin-x64.node +0 -0
- package/adapters/workbuddy/bin/prebuilds/linux-arm64-gnu/bound_read.linux-arm64-gnu.node +0 -0
- package/adapters/workbuddy/bin/prebuilds/linux-x64-gnu/bound_read.linux-x64-gnu.node +0 -0
- package/adapters/workbuddy/bin/registry.json +1 -1
- package/adapters/workbuddy/bin/release-skill.bundle.mjs +4950 -1819
- package/adapters/workbuddy/bin/rules.json +1 -1
- package/adapters/workbuddy/data/hosts/cursor/host-descriptor.json +34 -0
- package/adapters/workbuddy/data/hosts/registry.json +1 -0
- package/adapters/workbuddy/schemas/release-plan.schema.json +255 -25
- package/adapters/workbuddy/schemas/release-project.schema.json +228 -26
- package/adapters/workbuddy/skills/release-finish/SKILL.md +29 -15
- package/adapters/workbuddy/skills/release-help/SKILL.md +40 -39
- package/adapters/workbuddy/skills/release-verify/SKILL.md +2 -2
- package/adapters/workbuddy/src/schemas/host-descriptor.schema.json +9 -2
- package/bin/consumer-contract-vectors.json +7 -7
- package/bin/error-codes.json +1 -1
- package/bin/foundation-resource-binding.json +1 -1
- package/bin/prebuild-manifest.json +8 -4
- package/bin/prebuilds/darwin-arm64/bound_read.darwin-arm64.node +0 -0
- package/bin/prebuilds/darwin-x64/bound_read.darwin-x64.node +0 -0
- package/bin/prebuilds/linux-arm64-gnu/bound_read.linux-arm64-gnu.node +0 -0
- package/bin/prebuilds/linux-x64-gnu/bound_read.linux-x64-gnu.node +0 -0
- package/bin/registry.json +1 -1
- package/bin/release-skill-cli.mjs +148 -6
- package/bin/release-skill.bundle.mjs +4950 -1819
- package/bin/rules.json +1 -1
- package/data/hosts/cursor/host-descriptor.json +34 -0
- package/data/hosts/registry.json +1 -0
- package/package.json +9 -5
- package/platform-manifest.json +140 -8
- package/references/02-project-config.md +9 -2
- package/schemas/release-plan.schema.json +255 -25
- package/schemas/release-project.schema.json +228 -26
- package/scripts/sync-public-files.mjs +3 -22
- package/skills/release-finish/SKILL.md +29 -15
- package/skills/release-help/SKILL.md +40 -39
- package/skills/release-verify/SKILL.md +2 -2
- package/skills-src/release-finish/SKILL.md +29 -15
- package/skills-src/release-help/SKILL.md +40 -39
- package/skills-src/release-verify/SKILL.md +2 -2
- package/src/adapters/contract.mjs +1 -0
- package/src/adapters/plugin-marketplace.mjs +201 -9
- package/src/commands/post-release-local.mjs +618 -53
- package/src/commands/prepare.mjs +74 -9
- package/src/commands/publish.mjs +4 -1
- package/src/commands/ship.mjs +2 -0
- package/src/commands/verify-records.mjs +467 -0
- package/src/commands/verify.mjs +73 -0
- package/src/core/checkpoints.mjs +5 -2
- package/src/core/config.mjs +1 -1
- package/src/core/foundation-host-verification.mjs +168 -0
- package/src/core/plan.mjs +19 -1
- package/src/core/postpublish.mjs +9 -1
- package/src/core/run-retention.mjs +1 -1
- package/src/core/run.mjs +1 -1
- package/src/core/surface-host-bindings.mjs +1 -0
- package/src/core/verification-gates.mjs +1 -1
- package/src/platforms/registry.mjs +225 -16
- package/src/producers/build-adapters.mjs +43 -25
- package/src/producers/foundation-resource-projection.mjs +3 -3
- package/src/schemas/host-descriptor.schema.json +9 -2
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure, offline verification of caller-supplied release records.
|
|
3
|
+
*
|
|
4
|
+
* This module never discovers records or performs I/O. The CLI layer supplies
|
|
5
|
+
* the exact bytes and source labels selected by the caller.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { digestBytes } from 'skill-family-harness-node';
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
computeApprovalDigest,
|
|
12
|
+
validateApproval,
|
|
13
|
+
validateApprovalRecordSchema,
|
|
14
|
+
validateApprovalTimeWindow,
|
|
15
|
+
} from '../core/approval.mjs';
|
|
16
|
+
import { isMarketplaceAction, isRemoteWriteAction } from '../core/checkpoints.mjs';
|
|
17
|
+
import { computePlanDigest, validatePlan } from '../core/plan.mjs';
|
|
18
|
+
import {
|
|
19
|
+
computeRunDigest,
|
|
20
|
+
validateRun,
|
|
21
|
+
validateRunCheckpointMapping,
|
|
22
|
+
validateRunPlanDigest,
|
|
23
|
+
validateSourceRunEdge,
|
|
24
|
+
} from '../core/run.mjs';
|
|
25
|
+
|
|
26
|
+
export const VERIFY_RECORDS_EXIT_CODES = Object.freeze({
|
|
27
|
+
CONSISTENT: 0,
|
|
28
|
+
CONTRADICTED: 1,
|
|
29
|
+
INSUFFICIENT: 2,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const SUPPORTED_PLAN_VERSIONS = new Set([1, 2, 3]);
|
|
33
|
+
const SUPPORTED_RUN_COMMANDS = new Set(['publish', 'reconcile', 'verify']);
|
|
34
|
+
const SUPPORTED_TERMINAL_STATUSES = new Set(['PARTIAL', 'PUBLISHED', 'VERIFIED']);
|
|
35
|
+
const FINDING_ORDER = Object.freeze([
|
|
36
|
+
'INPUT_MISSING',
|
|
37
|
+
'INPUT_DAMAGED',
|
|
38
|
+
'FORMAT_UNSUPPORTED',
|
|
39
|
+
'PLAN_DIGEST_MISMATCH',
|
|
40
|
+
'APPROVAL_DIGEST_MISMATCH',
|
|
41
|
+
'RUN_DIGEST_MISMATCH',
|
|
42
|
+
'IDENTITY_MISMATCH',
|
|
43
|
+
'PLAN_BINDING_MISMATCH',
|
|
44
|
+
'APPROVAL_ACTION_MISMATCH',
|
|
45
|
+
'RUN_LINEAGE_MISMATCH',
|
|
46
|
+
'TRANSITION_MISMATCH',
|
|
47
|
+
'CHECKPOINT_MISMATCH',
|
|
48
|
+
'HISTORICAL_TIME_MISSING',
|
|
49
|
+
'HISTORICAL_TIME_OUTSIDE_WINDOW',
|
|
50
|
+
]);
|
|
51
|
+
const FINDING_RANK = new Map(FINDING_ORDER.map((code, index) => [code, index]));
|
|
52
|
+
|
|
53
|
+
function sourceLabel(source) {
|
|
54
|
+
if (typeof source !== 'string' || source.length === 0) return null;
|
|
55
|
+
return source.replaceAll('\\', '/').split('/').filter(Boolean).at(-1) ?? null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function parseInput(input, role, addFinding) {
|
|
59
|
+
const summary = { role, source: sourceLabel(input?.source) };
|
|
60
|
+
if (!input || input.bytes === undefined || input.bytes === null) {
|
|
61
|
+
addFinding('INPUT_MISSING', role, `required ${role} input was not provided`, 'INSUFFICIENT');
|
|
62
|
+
return { summary, digest: null, document: null, bytes: null, usable: false };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let bytes;
|
|
66
|
+
try {
|
|
67
|
+
bytes = Buffer.isBuffer(input.bytes)
|
|
68
|
+
? Buffer.from(input.bytes)
|
|
69
|
+
: Buffer.from(input.bytes);
|
|
70
|
+
} catch {
|
|
71
|
+
addFinding('INPUT_DAMAGED', role, `${role} input is not byte-compatible`);
|
|
72
|
+
return { summary, digest: null, document: null, bytes: null, usable: false };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const bytesSha256 = digestBytes(bytes);
|
|
76
|
+
try {
|
|
77
|
+
const document = JSON.parse(bytes.toString('utf8'));
|
|
78
|
+
if (!document || typeof document !== 'object' || Array.isArray(document)) {
|
|
79
|
+
addFinding('INPUT_DAMAGED', role, `${role} input must be a JSON object`);
|
|
80
|
+
return {
|
|
81
|
+
summary,
|
|
82
|
+
digest: { bytesSha256, carriedDomainDigest: null, recomputedDomainDigest: null },
|
|
83
|
+
document: null,
|
|
84
|
+
bytes,
|
|
85
|
+
usable: false,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
summary,
|
|
90
|
+
digest: { bytesSha256, carriedDomainDigest: null, recomputedDomainDigest: null },
|
|
91
|
+
document,
|
|
92
|
+
bytes,
|
|
93
|
+
usable: true,
|
|
94
|
+
};
|
|
95
|
+
} catch {
|
|
96
|
+
addFinding('INPUT_DAMAGED', role, `${role} input is not valid JSON`);
|
|
97
|
+
return {
|
|
98
|
+
summary,
|
|
99
|
+
digest: { bytesSha256, carriedDomainDigest: null, recomputedDomainDigest: null },
|
|
100
|
+
document: null,
|
|
101
|
+
bytes,
|
|
102
|
+
usable: false,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function sameStringSet(left, right) {
|
|
108
|
+
return JSON.stringify([...new Set(left)].sort()) === JSON.stringify([...new Set(right)].sort());
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function commandStatusIsValid(run) {
|
|
112
|
+
if (run.command === 'publish' || run.command === 'reconcile') {
|
|
113
|
+
return run.status === 'PARTIAL' || run.status === 'PUBLISHED';
|
|
114
|
+
}
|
|
115
|
+
return run.command === 'verify' && run.status === 'VERIFIED';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function checkpointStatusIsValid(run) {
|
|
119
|
+
if (run.status === 'VERIFIED') {
|
|
120
|
+
return run.checkpoints.every((checkpoint) => ['succeeded', 'skipped'].includes(checkpoint.status));
|
|
121
|
+
}
|
|
122
|
+
if (run.status === 'PUBLISHED') {
|
|
123
|
+
return run.checkpoints.every((checkpoint) => (
|
|
124
|
+
isRemoteWriteAction(checkpoint.actionType)
|
|
125
|
+
? ['succeeded', 'skipped'].includes(checkpoint.status)
|
|
126
|
+
: isMarketplaceAction(checkpoint.actionType)
|
|
127
|
+
? ['succeeded', 'skipped', 'deferred', 'failed'].includes(checkpoint.status)
|
|
128
|
+
: true
|
|
129
|
+
));
|
|
130
|
+
}
|
|
131
|
+
if (run.status === 'PARTIAL') {
|
|
132
|
+
return run.checkpoints.some((checkpoint) => !['succeeded', 'skipped', 'deferred'].includes(checkpoint.status));
|
|
133
|
+
}
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Verify one explicitly supplied record set without filesystem, network, or
|
|
139
|
+
* process access.
|
|
140
|
+
*
|
|
141
|
+
* @param {object} request
|
|
142
|
+
* @param {{bytes: Buffer|string, source?: string}} request.plan
|
|
143
|
+
* @param {{bytes: Buffer|string, source?: string}} request.approval
|
|
144
|
+
* @param {{bytes: Buffer|string, source?: string}} request.targetRun
|
|
145
|
+
* @param {Array<{bytes: Buffer|string, source?: string}>} [request.sourceRuns]
|
|
146
|
+
* @param {string} request.unitId
|
|
147
|
+
* @param {string} request.targetVersion
|
|
148
|
+
*/
|
|
149
|
+
export function verifyReleaseRecords(request = {}) {
|
|
150
|
+
const findings = [];
|
|
151
|
+
const addFinding = (code, role, message, outcome = 'CONTRADICTED') => {
|
|
152
|
+
findings.push({ code, role, message, _outcome: outcome });
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const planInput = parseInput(request.plan, 'plan', addFinding);
|
|
156
|
+
const approvalInput = parseInput(request.approval, 'approval', addFinding);
|
|
157
|
+
const targetInput = parseInput(request.targetRun, 'targetRun', addFinding);
|
|
158
|
+
const sourceInputs = Array.isArray(request.sourceRuns)
|
|
159
|
+
? request.sourceRuns.map((input, index) => parseInput(input, `sourceRun[${index}]`, addFinding))
|
|
160
|
+
: [];
|
|
161
|
+
|
|
162
|
+
const plan = planInput.document;
|
|
163
|
+
const approval = approvalInput.document;
|
|
164
|
+
const targetRun = targetInput.document;
|
|
165
|
+
|
|
166
|
+
let planSupported = false;
|
|
167
|
+
if (planInput.usable) {
|
|
168
|
+
if (!SUPPORTED_PLAN_VERSIONS.has(plan?.planVersion)) {
|
|
169
|
+
addFinding('FORMAT_UNSUPPORTED', 'plan', `unsupported release plan version: ${String(plan?.planVersion)}`, 'INSUFFICIENT');
|
|
170
|
+
} else {
|
|
171
|
+
planSupported = true;
|
|
172
|
+
try {
|
|
173
|
+
validatePlan(plan);
|
|
174
|
+
} catch (error) {
|
|
175
|
+
addFinding('INPUT_DAMAGED', 'plan', error.message);
|
|
176
|
+
planSupported = false;
|
|
177
|
+
}
|
|
178
|
+
const recomputed = computePlanDigest(plan);
|
|
179
|
+
planInput.digest.carriedDomainDigest = plan?.digest ?? null;
|
|
180
|
+
planInput.digest.recomputedDomainDigest = recomputed;
|
|
181
|
+
if (!plan?.digest || plan.digest !== recomputed) {
|
|
182
|
+
addFinding('PLAN_DIGEST_MISMATCH', 'plan', 'plan digest does not match its binding content');
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
let approvalSupported = false;
|
|
188
|
+
let approvalDigest = null;
|
|
189
|
+
if (approvalInput.usable) {
|
|
190
|
+
approvalDigest = computeApprovalDigest(approvalInput.bytes);
|
|
191
|
+
approvalInput.digest.recomputedDomainDigest = approvalDigest;
|
|
192
|
+
try {
|
|
193
|
+
validateApprovalRecordSchema(approval);
|
|
194
|
+
approvalSupported = true;
|
|
195
|
+
} catch (error) {
|
|
196
|
+
addFinding('INPUT_DAMAGED', 'approval', error.message);
|
|
197
|
+
}
|
|
198
|
+
if (approvalSupported) {
|
|
199
|
+
try {
|
|
200
|
+
validateApprovalTimeWindow(approval, {
|
|
201
|
+
clock: () => approval.approvedAt,
|
|
202
|
+
requireUnexpired: false,
|
|
203
|
+
});
|
|
204
|
+
} catch (error) {
|
|
205
|
+
addFinding('INPUT_DAMAGED', 'approval', error.message);
|
|
206
|
+
approvalSupported = false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const runEntries = [
|
|
212
|
+
{ input: targetInput, role: 'targetRun', isTarget: true },
|
|
213
|
+
...sourceInputs.map((input, index) => ({ input, role: `sourceRun[${index}]`, isTarget: false })),
|
|
214
|
+
];
|
|
215
|
+
const usableRuns = [];
|
|
216
|
+
let trustedTargetTerminalStatus = null;
|
|
217
|
+
for (const entry of runEntries) {
|
|
218
|
+
const run = entry.input.document;
|
|
219
|
+
if (!entry.input.usable) continue;
|
|
220
|
+
entry.input.digest.carriedDomainDigest = run?.runDigest ?? null;
|
|
221
|
+
entry.input.digest.recomputedDomainDigest = computeRunDigest(run);
|
|
222
|
+
|
|
223
|
+
if (!SUPPORTED_RUN_COMMANDS.has(run?.command) || !SUPPORTED_TERMINAL_STATUSES.has(run?.status)) {
|
|
224
|
+
addFinding(
|
|
225
|
+
'FORMAT_UNSUPPORTED',
|
|
226
|
+
entry.role,
|
|
227
|
+
`unsupported release run command/status: ${String(run?.command)}/${String(run?.status)}`,
|
|
228
|
+
'INSUFFICIENT',
|
|
229
|
+
);
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const { runDigest: _runDigest, ...unsignedRun } = run;
|
|
234
|
+
try {
|
|
235
|
+
validateRun(unsignedRun);
|
|
236
|
+
} catch (error) {
|
|
237
|
+
addFinding('INPUT_DAMAGED', entry.role, error.message);
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const digestMatches = Boolean(run.runDigest)
|
|
242
|
+
&& run.runDigest === entry.input.digest.recomputedDomainDigest;
|
|
243
|
+
const transitionIsValid = commandStatusIsValid(run);
|
|
244
|
+
const terminalCheckpointsAreValid = checkpointStatusIsValid(run);
|
|
245
|
+
if (!digestMatches) {
|
|
246
|
+
addFinding('RUN_DIGEST_MISMATCH', entry.role, 'run digest does not match its content');
|
|
247
|
+
}
|
|
248
|
+
if (!transitionIsValid) {
|
|
249
|
+
addFinding('TRANSITION_MISMATCH', entry.role, `run command ${run.command} cannot terminate as ${run.status}`);
|
|
250
|
+
}
|
|
251
|
+
if (!terminalCheckpointsAreValid) {
|
|
252
|
+
addFinding('CHECKPOINT_MISMATCH', entry.role, `checkpoint results do not support terminal status ${run.status}`);
|
|
253
|
+
}
|
|
254
|
+
if (entry.isTarget && digestMatches && transitionIsValid && terminalCheckpointsAreValid) {
|
|
255
|
+
trustedTargetTerminalStatus = run.status;
|
|
256
|
+
}
|
|
257
|
+
usableRuns.push({ ...entry, run });
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (planSupported && typeof request.unitId === 'string' && typeof request.targetVersion === 'string') {
|
|
261
|
+
const expectedUnit = (plan.units ?? []).find((unit) => unit.id === request.unitId);
|
|
262
|
+
if (!expectedUnit || expectedUnit.targetVersion !== request.targetVersion) {
|
|
263
|
+
addFinding('IDENTITY_MISMATCH', 'plan', 'expected release unit and version do not match the plan');
|
|
264
|
+
}
|
|
265
|
+
} else if (typeof request.unitId !== 'string' || typeof request.targetVersion !== 'string') {
|
|
266
|
+
addFinding('INPUT_MISSING', 'identity', 'unitId and targetVersion are required', 'INSUFFICIENT');
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (planSupported && approvalSupported) {
|
|
270
|
+
const planDigest = computePlanDigest(plan);
|
|
271
|
+
if (approval.planDigest !== planDigest) {
|
|
272
|
+
addFinding('PLAN_BINDING_MISMATCH', 'approval', 'approval planDigest does not match the supplied plan');
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const expectedUnitVersions = Object.fromEntries((plan.units ?? []).map((unit) => [unit.id, unit.targetVersion]));
|
|
276
|
+
const approvedUnitVersions = approval.unitVersions
|
|
277
|
+
?? ((plan.units ?? []).length === 1 ? { [plan.units[0].id]: approval.targetVersion } : {});
|
|
278
|
+
const identityMatches = sameStringSet(Object.keys(expectedUnitVersions), Object.keys(approvedUnitVersions))
|
|
279
|
+
&& Object.entries(expectedUnitVersions).every(([unitId, version]) => approvedUnitVersions[unitId] === version)
|
|
280
|
+
&& (approval.targetVersion === undefined
|
|
281
|
+
|| new Set(Object.values(expectedUnitVersions)).size !== 1
|
|
282
|
+
|| approval.targetVersion === Object.values(expectedUnitVersions)[0]);
|
|
283
|
+
if (!identityMatches) {
|
|
284
|
+
addFinding('IDENTITY_MISMATCH', 'approval', 'approval unit/version identity does not match the plan');
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const planActions = (plan.externalActions ?? []).map((action) => action.id);
|
|
288
|
+
if (!sameStringSet(approval.approvedActions ?? [], planActions)) {
|
|
289
|
+
addFinding('APPROVAL_ACTION_MISMATCH', 'approval', 'approved actions do not exactly match the plan actions');
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
try {
|
|
293
|
+
validateApproval(plan, approval, {
|
|
294
|
+
clock: () => approval.approvedAt,
|
|
295
|
+
requireUnexpired: false,
|
|
296
|
+
});
|
|
297
|
+
} catch (error) {
|
|
298
|
+
const alreadyRepresented = (
|
|
299
|
+
(/planDigest/i.test(error.message)
|
|
300
|
+
&& findings.some((finding) => finding.role === 'approval' && finding.code === 'PLAN_BINDING_MISMATCH'))
|
|
301
|
+
|| (/version|unitVersions/i.test(error.message)
|
|
302
|
+
&& findings.some((finding) => finding.role === 'approval' && finding.code === 'IDENTITY_MISMATCH'))
|
|
303
|
+
|| (/approved|action/i.test(error.message)
|
|
304
|
+
&& findings.some((finding) => finding.role === 'approval' && finding.code === 'APPROVAL_ACTION_MISMATCH'))
|
|
305
|
+
);
|
|
306
|
+
if (!alreadyRepresented) {
|
|
307
|
+
addFinding('INPUT_DAMAGED', 'approval', error.message);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (planSupported) {
|
|
313
|
+
for (const entry of usableRuns) {
|
|
314
|
+
try {
|
|
315
|
+
validateRunPlanDigest(entry.run, plan);
|
|
316
|
+
} catch (error) {
|
|
317
|
+
addFinding('PLAN_BINDING_MISMATCH', entry.role, error.message);
|
|
318
|
+
}
|
|
319
|
+
try {
|
|
320
|
+
validateRunCheckpointMapping(entry.run, plan.externalActions ?? []);
|
|
321
|
+
} catch (error) {
|
|
322
|
+
addFinding('CHECKPOINT_MISMATCH', entry.role, error.message);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (approvalDigest) {
|
|
328
|
+
for (const entry of usableRuns) {
|
|
329
|
+
if (!entry.run.approvalDigest) {
|
|
330
|
+
addFinding('INPUT_MISSING', entry.role, 'run does not carry the approval digest needed to bind the supplied approval', 'INSUFFICIENT');
|
|
331
|
+
} else if (entry.run.approvalDigest !== approvalDigest) {
|
|
332
|
+
addFinding('APPROVAL_DIGEST_MISMATCH', entry.role, 'run approvalDigest does not match the supplied approval bytes');
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const supportingRuns = usableRuns.filter((entry) => !entry.isTarget);
|
|
338
|
+
const chain = [];
|
|
339
|
+
let lineageComplete = false;
|
|
340
|
+
if (targetRun && usableRuns.some((entry) => entry.isTarget)) {
|
|
341
|
+
let current = usableRuns.find((entry) => entry.isTarget);
|
|
342
|
+
const visited = new Set();
|
|
343
|
+
for (let depth = 0; depth <= 16 && current; depth += 1) {
|
|
344
|
+
chain.push(current.run);
|
|
345
|
+
const visitKey = `${current.run.runId}:${current.run.runDigest}`;
|
|
346
|
+
if (visited.has(visitKey)) {
|
|
347
|
+
addFinding('RUN_LINEAGE_MISMATCH', current.role, 'release run lineage contains a cycle');
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
visited.add(visitKey);
|
|
351
|
+
|
|
352
|
+
if (current.run.command === 'publish') {
|
|
353
|
+
lineageComplete = true;
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
356
|
+
if (!current.run.sourceRunId || !current.run.sourceRunDigest || !current.run.sourceRunPath) {
|
|
357
|
+
addFinding('INPUT_MISSING', current.role, 'run is missing complete source-run lineage fields', 'INSUFFICIENT');
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
const exactParent = supportingRuns.find((candidate) => (
|
|
361
|
+
candidate.run.runId === current.run.sourceRunId
|
|
362
|
+
&& candidate.run.runDigest === current.run.sourceRunDigest
|
|
363
|
+
));
|
|
364
|
+
if (!exactParent) {
|
|
365
|
+
const sameId = supportingRuns.find((candidate) => candidate.run.runId === current.run.sourceRunId);
|
|
366
|
+
if (sameId) {
|
|
367
|
+
addFinding('RUN_LINEAGE_MISMATCH', current.role, 'source run id is present but its digest does not match');
|
|
368
|
+
} else {
|
|
369
|
+
addFinding('INPUT_MISSING', current.role, 'explicit source run required by lineage was not supplied', 'INSUFFICIENT');
|
|
370
|
+
}
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
try {
|
|
374
|
+
validateSourceRunEdge(current.run, exactParent.run);
|
|
375
|
+
} catch (error) {
|
|
376
|
+
addFinding('TRANSITION_MISMATCH', current.role, error.message);
|
|
377
|
+
break;
|
|
378
|
+
}
|
|
379
|
+
current = exactParent;
|
|
380
|
+
}
|
|
381
|
+
if (!lineageComplete && chain.length > 16) {
|
|
382
|
+
addFinding('RUN_LINEAGE_MISMATCH', 'targetRun', 'release run lineage exceeds maximum depth');
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
for (const entry of usableRuns) {
|
|
387
|
+
const run = entry.run;
|
|
388
|
+
if (run.stateSequence === undefined) {
|
|
389
|
+
if (run.previousStateDigest !== undefined) {
|
|
390
|
+
addFinding('RUN_LINEAGE_MISMATCH', entry.role, 'non-state run claims a previous state digest');
|
|
391
|
+
}
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
if (run.stateSequence === 0) {
|
|
395
|
+
if (run.previousStateDigest !== undefined) {
|
|
396
|
+
addFinding('RUN_LINEAGE_MISMATCH', entry.role, 'initial state run claims a previous state digest');
|
|
397
|
+
}
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
const predecessor = supportingRuns.find((candidate) => (
|
|
401
|
+
candidate.run.runId === run.runId
|
|
402
|
+
&& candidate.run.stateSequence === run.stateSequence - 1
|
|
403
|
+
));
|
|
404
|
+
if (!predecessor) {
|
|
405
|
+
addFinding('INPUT_MISSING', entry.role, 'explicit predecessor state snapshot was not supplied', 'INSUFFICIENT');
|
|
406
|
+
} else if (
|
|
407
|
+
predecessor.run.runDigest !== run.previousStateDigest
|
|
408
|
+
|| predecessor.run.command !== run.command
|
|
409
|
+
|| predecessor.run.planDigest !== run.planDigest
|
|
410
|
+
) {
|
|
411
|
+
addFinding('RUN_LINEAGE_MISMATCH', entry.role, 'state predecessor identity or digest does not match');
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (approvalSupported) {
|
|
416
|
+
const executionRun = [...chain].reverse().find((run) => (
|
|
417
|
+
['publish', 'reconcile'].includes(run.command)
|
|
418
|
+
&& (run.checkpoints ?? []).some((checkpoint) => isRemoteWriteAction(checkpoint.actionType))
|
|
419
|
+
));
|
|
420
|
+
if (!lineageComplete || !executionRun?.startedAt || !executionRun?.finishedAt) {
|
|
421
|
+
addFinding('HISTORICAL_TIME_MISSING', 'approval', 'historical publish execution interval cannot be proven', 'INSUFFICIENT');
|
|
422
|
+
} else {
|
|
423
|
+
const approvedAt = Date.parse(approval.approvedAt);
|
|
424
|
+
const expiresAt = Date.parse(approval.expiresAt);
|
|
425
|
+
const startedAt = Date.parse(executionRun.startedAt);
|
|
426
|
+
const finishedAt = Date.parse(executionRun.finishedAt);
|
|
427
|
+
if (
|
|
428
|
+
!Number.isFinite(startedAt)
|
|
429
|
+
|| !Number.isFinite(finishedAt)
|
|
430
|
+
|| startedAt < approvedAt
|
|
431
|
+
|| finishedAt > expiresAt
|
|
432
|
+
|| finishedAt < startedAt
|
|
433
|
+
) {
|
|
434
|
+
addFinding('HISTORICAL_TIME_OUTSIDE_WINDOW', 'approval', 'publish execution interval is outside the approval window');
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
findings.sort((left, right) => (
|
|
440
|
+
(FINDING_RANK.get(left.code) ?? 999) - (FINDING_RANK.get(right.code) ?? 999)
|
|
441
|
+
|| left.role.localeCompare(right.role)
|
|
442
|
+
|| left.message.localeCompare(right.message)
|
|
443
|
+
));
|
|
444
|
+
const hasContradiction = findings.some((finding) => finding._outcome === 'CONTRADICTED');
|
|
445
|
+
const hasInsufficient = findings.some((finding) => finding._outcome === 'INSUFFICIENT');
|
|
446
|
+
const status = hasContradiction ? 'CONTRADICTED' : hasInsufficient ? 'INSUFFICIENT' : 'CONSISTENT';
|
|
447
|
+
|
|
448
|
+
return {
|
|
449
|
+
status,
|
|
450
|
+
unitId: typeof request.unitId === 'string' ? request.unitId : null,
|
|
451
|
+
targetVersion: typeof request.targetVersion === 'string' ? request.targetVersion : null,
|
|
452
|
+
historicalTerminalStatus: trustedTargetTerminalStatus,
|
|
453
|
+
inputs: {
|
|
454
|
+
plan: planInput.summary,
|
|
455
|
+
approval: approvalInput.summary,
|
|
456
|
+
targetRun: targetInput.summary,
|
|
457
|
+
sourceRuns: sourceInputs.map((input) => input.summary),
|
|
458
|
+
},
|
|
459
|
+
digests: {
|
|
460
|
+
plan: planInput.digest,
|
|
461
|
+
approval: approvalInput.digest,
|
|
462
|
+
targetRun: targetInput.digest,
|
|
463
|
+
sourceRuns: sourceInputs.map((input) => input.digest),
|
|
464
|
+
},
|
|
465
|
+
findings: findings.map(({ _outcome, ...finding }) => finding),
|
|
466
|
+
};
|
|
467
|
+
}
|
package/src/commands/verify.mjs
CHANGED
|
@@ -72,6 +72,7 @@ import {
|
|
|
72
72
|
isFoundationPluginVerificationEligible,
|
|
73
73
|
verifyFrozenPluginWithFoundation,
|
|
74
74
|
} from '../core/foundation-plugin-verification.mjs';
|
|
75
|
+
import { verifyFrozenCursorSkillWithFoundation } from '../core/foundation-host-verification.mjs';
|
|
75
76
|
import { resolveUnitScopedPath } from '../snapshot/public-path.mjs';
|
|
76
77
|
import { canonicalJson } from '../core/digest.mjs';
|
|
77
78
|
import {
|
|
@@ -130,6 +131,53 @@ export const VERIFICATION_RESOLVED_TYPES = Object.freeze({
|
|
|
130
131
|
NOT_REQUIRED_UNCHANGED: 'NOT_REQUIRED_UNCHANGED',
|
|
131
132
|
});
|
|
132
133
|
|
|
134
|
+
/** Verify actionless Cursor distributions through their frozen host contract. */
|
|
135
|
+
export async function verifyCursorHostDistributions({
|
|
136
|
+
plan,
|
|
137
|
+
root,
|
|
138
|
+
cursorHostRuntime,
|
|
139
|
+
runHostVerificationFn,
|
|
140
|
+
clock = defaultClock,
|
|
141
|
+
evidence,
|
|
142
|
+
} = {}) {
|
|
143
|
+
const checks = [];
|
|
144
|
+
for (const unit of plan?.units ?? []) {
|
|
145
|
+
const cursorDistribution = (unit.distributions ?? []).find(
|
|
146
|
+
(distribution) => distribution.type === 'cursor-plugin',
|
|
147
|
+
);
|
|
148
|
+
if (!cursorDistribution) continue;
|
|
149
|
+
const result = await verifyFrozenCursorSkillWithFoundation({
|
|
150
|
+
plan,
|
|
151
|
+
unitId: unit.id,
|
|
152
|
+
root,
|
|
153
|
+
cursorHostRuntime,
|
|
154
|
+
...(runHostVerificationFn ? { runHostVerificationFn } : {}),
|
|
155
|
+
clock,
|
|
156
|
+
});
|
|
157
|
+
checks.push({
|
|
158
|
+
actionId: `cursor-host-verification-${unit.id}`,
|
|
159
|
+
actionType: 'cursor-host-verification',
|
|
160
|
+
unitId: unit.id,
|
|
161
|
+
distributionType: cursorDistribution.type,
|
|
162
|
+
status: VERIFICATION_RESOLVED_TYPES.PASSED_AUTOMATIC,
|
|
163
|
+
observation: result,
|
|
164
|
+
});
|
|
165
|
+
await evidence?.append({
|
|
166
|
+
phase: 'verify-host',
|
|
167
|
+
unitId: unit.id,
|
|
168
|
+
distributionType: cursorDistribution.type,
|
|
169
|
+
status: VERIFICATION_RESOLVED_TYPES.PASSED_AUTOMATIC,
|
|
170
|
+
hostId: result.hostId,
|
|
171
|
+
driverId: result.driverId,
|
|
172
|
+
requestDigest: result.requestDigest,
|
|
173
|
+
payloadDigest: result.payloadDigest,
|
|
174
|
+
entrySkill: result.entrySkill,
|
|
175
|
+
observation: result,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
return checks;
|
|
179
|
+
}
|
|
180
|
+
|
|
133
181
|
/** Re-read every frozen subject tarball before consuming the public receipt. */
|
|
134
182
|
export async function verifyPublicSourceAuthorityReceiptOffline({ plan, root }) {
|
|
135
183
|
const descriptor = plan.publicSourceAuthorityReceipt;
|
|
@@ -179,6 +227,7 @@ const ADAPTER_ACTION_TYPE_MAP = {
|
|
|
179
227
|
'codex-marketplace-install': 'codex-marketplace-install',
|
|
180
228
|
'kimi-marketplace-install': 'kimi-marketplace-install',
|
|
181
229
|
'codebuddy-marketplace-install': 'codebuddy-marketplace-install',
|
|
230
|
+
'qoder-marketplace-install': 'qoder-marketplace-install',
|
|
182
231
|
};
|
|
183
232
|
|
|
184
233
|
// ---------------------------------------------------------------------------
|
|
@@ -349,6 +398,7 @@ async function collectMissingManualAttestations({
|
|
|
349
398
|
const manual = actions.filter((action) => (
|
|
350
399
|
action.type === 'kimi-marketplace-install'
|
|
351
400
|
|| action.type === 'codebuddy-marketplace-install'
|
|
401
|
+
|| action.type === 'qoder-marketplace-install'
|
|
352
402
|
));
|
|
353
403
|
if (manual.length === 0) return [];
|
|
354
404
|
|
|
@@ -1097,6 +1147,8 @@ export async function verifyRelease(options) {
|
|
|
1097
1147
|
execFn,
|
|
1098
1148
|
configPath: configPathOpt,
|
|
1099
1149
|
runPluginVerificationFn,
|
|
1150
|
+
runHostVerificationFn,
|
|
1151
|
+
cursorHostRuntime,
|
|
1100
1152
|
observeFirstReleaseMarketplaceHeadFn,
|
|
1101
1153
|
fetchFirstReleaseMarketplaceIndexFn,
|
|
1102
1154
|
} = options ?? {};
|
|
@@ -1576,6 +1628,20 @@ export async function verifyRelease(options) {
|
|
|
1576
1628
|
const manualFollowUps = [];
|
|
1577
1629
|
const foundationPluginVerificationReceipts = [];
|
|
1578
1630
|
|
|
1631
|
+
// Cursor has no marketplace action or publish checkpoint. Verify each
|
|
1632
|
+
// declared Cursor distribution directly from its frozen unit contract,
|
|
1633
|
+
// using explicit runtime roots that never enter the release run record.
|
|
1634
|
+
// Plans without Cursor distributions do not enter
|
|
1635
|
+
// this branch and retain their existing action-only behavior.
|
|
1636
|
+
adapterChecks.push(...await verifyCursorHostDistributions({
|
|
1637
|
+
plan,
|
|
1638
|
+
root,
|
|
1639
|
+
cursorHostRuntime,
|
|
1640
|
+
runHostVerificationFn,
|
|
1641
|
+
clock: clockFn,
|
|
1642
|
+
evidence,
|
|
1643
|
+
}));
|
|
1644
|
+
|
|
1579
1645
|
// Every action is identity-bound and adapters receive read-only or
|
|
1580
1646
|
// per-action isolated consumer paths. Run independent checks concurrently;
|
|
1581
1647
|
// the evidence writer serializes append operations and result arrays are
|
|
@@ -1710,6 +1776,7 @@ export async function verifyRelease(options) {
|
|
|
1710
1776
|
'codex-marketplace-install': 'codex-plugin',
|
|
1711
1777
|
'kimi-marketplace-install': 'kimi-plugin',
|
|
1712
1778
|
'codebuddy-marketplace-install': 'codebuddy-plugin',
|
|
1779
|
+
'qoder-marketplace-install': 'qoder-plugin',
|
|
1713
1780
|
};
|
|
1714
1781
|
const dist = unit?.distributions?.find((d) => d.type === typeToDist[action.type]);
|
|
1715
1782
|
|
|
@@ -1896,6 +1963,8 @@ export async function verifyRelease(options) {
|
|
|
1896
1963
|
? 'codex-plugin'
|
|
1897
1964
|
: action.type === 'codebuddy-marketplace-install'
|
|
1898
1965
|
? 'codebuddy-plugin'
|
|
1966
|
+
: action.type === 'qoder-marketplace-install'
|
|
1967
|
+
? 'qoder-plugin'
|
|
1899
1968
|
: 'kimi-plugin';
|
|
1900
1969
|
const installPath = verifyResult.observation?.installPath;
|
|
1901
1970
|
consumerGateResults.push(...await runConsumerVerificationGates({
|
|
@@ -1919,6 +1988,10 @@ export async function verifyRelease(options) {
|
|
|
1919
1988
|
? {
|
|
1920
1989
|
HOME: resolve(runDir, 'consumers', `codebuddy-${action.parameters.plugin}`),
|
|
1921
1990
|
}
|
|
1991
|
+
: action.type === 'qoder-marketplace-install'
|
|
1992
|
+
? {
|
|
1993
|
+
HOME: resolve(runDir, 'consumers', `qoder-${action.parameters.plugin}`),
|
|
1994
|
+
}
|
|
1922
1995
|
: {
|
|
1923
1996
|
HOME: resolve(runDir, 'consumers', `kimi-${action.parameters.plugin}`),
|
|
1924
1997
|
},
|
package/src/core/checkpoints.mjs
CHANGED
|
@@ -34,6 +34,7 @@ export const CHECKPOINT_ORDER = [
|
|
|
34
34
|
'codex-marketplace-install',
|
|
35
35
|
'kimi-marketplace-install',
|
|
36
36
|
'codebuddy-marketplace-install',
|
|
37
|
+
'qoder-marketplace-install',
|
|
37
38
|
];
|
|
38
39
|
|
|
39
40
|
/**
|
|
@@ -54,6 +55,7 @@ export const ADAPTER_ACTION_TYPE_MAP = {
|
|
|
54
55
|
'codex-marketplace-install': 'codex-marketplace-install',
|
|
55
56
|
'kimi-marketplace-install': 'kimi-marketplace-install',
|
|
56
57
|
'codebuddy-marketplace-install': 'codebuddy-marketplace-install',
|
|
58
|
+
'qoder-marketplace-install': 'qoder-marketplace-install',
|
|
57
59
|
};
|
|
58
60
|
|
|
59
61
|
/**
|
|
@@ -68,7 +70,7 @@ export const ADAPTER_ACTION_TYPE_MAP = {
|
|
|
68
70
|
* placed in Tier 1 only for conservative scheduling.
|
|
69
71
|
* - Tier 2 `github-release` depends on Tier 1 `create-tag` (release `--verify-tag`).
|
|
70
72
|
*
|
|
71
|
-
* Marketplace actions (claude/codex/kimi/codebuddy-marketplace-install) are
|
|
73
|
+
* Marketplace actions (claude/codex/kimi/codebuddy/qoder-marketplace-install) are
|
|
72
74
|
* included in the tier table for ADAPTER_ACTION_TYPE_MAP lookup but are
|
|
73
75
|
* filtered out before tier grouping in both publish and reconcile. They are
|
|
74
76
|
* recorded as DEFERRED with CONSUMER_VERIFICATION_DEFERRED reason and never
|
|
@@ -82,7 +84,7 @@ export const TIER_TABLE = [
|
|
|
82
84
|
['push-commit', 'push-snapshot'], // Tier 0
|
|
83
85
|
['set-default-branch', 'create-tag', 'npm-publish'], // Tier 1
|
|
84
86
|
['github-release', 'claude-marketplace-install', 'codex-marketplace-install'], // Tier 2
|
|
85
|
-
['kimi-marketplace-install', 'codebuddy-marketplace-install'],
|
|
87
|
+
['kimi-marketplace-install', 'codebuddy-marketplace-install', 'qoder-marketplace-install'], // Tier 3
|
|
86
88
|
];
|
|
87
89
|
|
|
88
90
|
/** Fast reverse lookup: action type -> tier index (-1 when unknown). */
|
|
@@ -170,6 +172,7 @@ export const MARKETPLACE_ACTION_TYPES = new Set([
|
|
|
170
172
|
'codex-marketplace-install',
|
|
171
173
|
'kimi-marketplace-install',
|
|
172
174
|
'codebuddy-marketplace-install',
|
|
175
|
+
'qoder-marketplace-install',
|
|
173
176
|
]);
|
|
174
177
|
|
|
175
178
|
/**
|
package/src/core/config.mjs
CHANGED
|
@@ -401,7 +401,7 @@ export async function loadProjectConfig({ root, configPath } = {}) {
|
|
|
401
401
|
for (const unit of config.releaseUnits) {
|
|
402
402
|
if (!unit?.distributions) continue;
|
|
403
403
|
for (const dist of unit.distributions) {
|
|
404
|
-
if (dist.type === 'npm') continue;
|
|
404
|
+
if (dist.type === 'npm' || dist.type === 'cursor-plugin') continue;
|
|
405
405
|
if (dist.marketplaceSourceType === undefined || dist.marketplaceSourceType === null) {
|
|
406
406
|
dist.marketplaceSourceType = dist.marketplaceRepo ? 'standalone-index' : 'bundled-family';
|
|
407
407
|
}
|