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,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Release-domain mapping for one frozen Cursor Skill. Foundation owns request
|
|
3
|
+
* preparation, installation, process supervision and bound stream reads.
|
|
4
|
+
*/
|
|
5
|
+
import { basename, join, isAbsolute } from 'node:path';
|
|
6
|
+
import { mkdir } from 'node:fs/promises';
|
|
7
|
+
import { prepareHostVerification, runHostVerification } from 'skill-family-engineering-kit';
|
|
8
|
+
import { canonicalJson } from 'skill-family-contracts';
|
|
9
|
+
import { createTemporaryWorkspace } from 'skill-family-harness-node';
|
|
10
|
+
|
|
11
|
+
import { verifyFrozenSnapshot } from '../snapshot/frozen.mjs';
|
|
12
|
+
import { canonicalPublicPath, publicPathCollisionKey } from '../snapshot/public-path.mjs';
|
|
13
|
+
import { CONSUMER_VERIFICATION_DEFERRED, POST_PUBLISH_VERIFY_FAILED, ReleaseError } from './errors.mjs';
|
|
14
|
+
|
|
15
|
+
function fail(message, details = {}) {
|
|
16
|
+
return new ReleaseError(POST_PUBLISH_VERIFY_FAILED, message, details);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Release-owned scenario policy, shared by freezing and consuming the contract. */
|
|
20
|
+
export function assertCursorHostScenario(scenario) {
|
|
21
|
+
const keys = ['workloadDocument', 'fixtureFiles', 'protectedWorkspaceFiles', 'platformManifest', 'effectivePrompt', 'expectedResult'];
|
|
22
|
+
if (!scenario || typeof scenario !== 'object' || Array.isArray(scenario)
|
|
23
|
+
|| Object.keys(scenario).length !== keys.length || keys.some((key) => !Object.hasOwn(scenario, key))) {
|
|
24
|
+
throw fail('Cursor host verification requires the complete frozen scenario');
|
|
25
|
+
}
|
|
26
|
+
for (const key of ['workloadDocument', 'effectivePrompt', 'expectedResult']) {
|
|
27
|
+
if (typeof scenario[key] !== 'string' || !scenario[key].isWellFormed()
|
|
28
|
+
|| (key !== 'expectedResult' && scenario[key].length === 0)
|
|
29
|
+
|| (key === 'effectivePrompt' && scenario[key].includes('\0'))) {
|
|
30
|
+
throw fail('Cursor scenario requires valid UTF-8 text', { field: key });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (!scenario.platformManifest || typeof scenario.platformManifest !== 'object' || Array.isArray(scenario.platformManifest)) {
|
|
34
|
+
throw fail('Cursor scenario platformManifest must be a JSON object');
|
|
35
|
+
}
|
|
36
|
+
canonicalJson(scenario.platformManifest);
|
|
37
|
+
for (const field of ['fixtureFiles', 'protectedWorkspaceFiles']) {
|
|
38
|
+
const files = scenario[field];
|
|
39
|
+
if (!Array.isArray(files) || files.length === 0) throw fail('Cursor scenario files must be non-empty', { field });
|
|
40
|
+
const paths = [];
|
|
41
|
+
for (const file of files) {
|
|
42
|
+
if (!file || Object.keys(file).length !== 2 || typeof file.content !== 'string' || !file.content.isWellFormed()) {
|
|
43
|
+
throw fail('Cursor scenario file requires path and UTF-8 content', { field });
|
|
44
|
+
}
|
|
45
|
+
let path;
|
|
46
|
+
try { path = canonicalPublicPath(file.path).path; } catch { throw fail('Cursor scenario file path is unsafe', { field }); }
|
|
47
|
+
const key = publicPathCollisionKey(path);
|
|
48
|
+
if (path !== file.path || key.split('/').includes('.cursor')
|
|
49
|
+
|| paths.some((other) => other === key || other.startsWith(key + '/') || key.startsWith(other + '/'))) {
|
|
50
|
+
throw fail('Cursor scenario files conflict or target a Cursor control path', { field });
|
|
51
|
+
}
|
|
52
|
+
paths.push(key);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Consume only frozen domain facts and this invocation's explicit private roots. */
|
|
58
|
+
export async function verifyFrozenCursorSkillWithFoundation({
|
|
59
|
+
plan, unitId, root, cursorHostRuntime,
|
|
60
|
+
runHostVerificationFn = runHostVerification,
|
|
61
|
+
clock = () => new Date().toISOString(),
|
|
62
|
+
} = {}) {
|
|
63
|
+
const unit = (plan?.units ?? []).find((candidate) => candidate.id === unitId);
|
|
64
|
+
const distribution = unit?.distributions?.find((candidate) => candidate.type === 'cursor-plugin');
|
|
65
|
+
const contract = distribution?.hostVerificationContract;
|
|
66
|
+
if (!unit?.frozenSnapshot?.path || !unit.frozenSnapshot.commit || !unit.frozenSnapshot.manifestDigest) {
|
|
67
|
+
throw fail('Cursor host verification requires a frozen unit snapshot', { unitId });
|
|
68
|
+
}
|
|
69
|
+
if (contract?.contractVersion !== 1 || contract.hostId !== 'cursor'
|
|
70
|
+
|| contract.entrySkill !== distribution.entrySkill
|
|
71
|
+
|| contract.payloadDigest !== unit.frozenSnapshot.manifestDigest
|
|
72
|
+
|| contract.manifestRelativePath !== 'skills/' + contract.entrySkill + '/SKILL.md') {
|
|
73
|
+
throw fail('Cursor host verification contract does not bind the frozen payload and entry Skill', { unitId });
|
|
74
|
+
}
|
|
75
|
+
assertCursorHostScenario(contract.scenario);
|
|
76
|
+
if (!cursorHostRuntime || Object.keys(cursorHostRuntime).length !== 2
|
|
77
|
+
|| !['executableRoot', 'existingUserStateRoot'].every((key) =>
|
|
78
|
+
typeof cursorHostRuntime[key] === 'string' && isAbsolute(cursorHostRuntime[key]))) {
|
|
79
|
+
throw fail('Cursor host verification requires explicit absolute executableRoot and existingUserStateRoot', { unitId });
|
|
80
|
+
}
|
|
81
|
+
const frozen = await verifyFrozenSnapshot({ root, snapshotPath: unit.frozenSnapshot.path, expectedDigest: contract.payloadDigest });
|
|
82
|
+
const prefix = 'skills/' + contract.entrySkill + '/';
|
|
83
|
+
const members = frozen.entries.filter((entry) => entry.type === 'file' && entry.path.startsWith(prefix))
|
|
84
|
+
.map((entry) => entry.path.slice(prefix.length));
|
|
85
|
+
if (!members.includes('SKILL.md')) throw fail('Cursor frozen entry Skill is missing SKILL.md', { unitId });
|
|
86
|
+
const scenario = contract.scenario;
|
|
87
|
+
const owned = await createTemporaryWorkspace({ prefix: 'release-skill-cursor-' });
|
|
88
|
+
let retain = false;
|
|
89
|
+
let prepared;
|
|
90
|
+
let result;
|
|
91
|
+
try {
|
|
92
|
+
const repositoryRoot = await owned.resolve('repository');
|
|
93
|
+
const workspaceRoot = join(repositoryRoot, 'workspace');
|
|
94
|
+
const sessionRoot = await owned.resolve('session');
|
|
95
|
+
await mkdir(workspaceRoot, { recursive: true, mode: 0o700 });
|
|
96
|
+
await mkdir(sessionRoot, { mode: 0o700 });
|
|
97
|
+
for (const file of scenario.protectedWorkspaceFiles) {
|
|
98
|
+
await owned.writeFile('repository/workspace/' + file.path, file.content, { mode: 0o600 });
|
|
99
|
+
}
|
|
100
|
+
prepared = await prepareHostVerification({
|
|
101
|
+
hostId: 'cursor',
|
|
102
|
+
verificationSetId: plan.digest + ':' + unitId + ':cursor',
|
|
103
|
+
candidate: {
|
|
104
|
+
ref: unit.frozenSnapshot.commit,
|
|
105
|
+
manifest: canonicalJson({
|
|
106
|
+
contractVersion: contract.contractVersion, unitId, candidateRef: unit.frozenSnapshot.commit,
|
|
107
|
+
payloadDigest: contract.payloadDigest, entrySkill: contract.entrySkill,
|
|
108
|
+
manifestRelativePath: contract.manifestRelativePath,
|
|
109
|
+
}),
|
|
110
|
+
},
|
|
111
|
+
skill: { root: join(frozen.snapshotDir, 'skills', contract.entrySkill), entrySkill: contract.entrySkill, members },
|
|
112
|
+
workloadDocument: scenario.workloadDocument,
|
|
113
|
+
fixtureFiles: scenario.fixtureFiles,
|
|
114
|
+
workspace: { repositoryRoot, root: workspaceRoot, protectedMembers: scenario.protectedWorkspaceFiles.map((file) => file.path) },
|
|
115
|
+
platformManifest: canonicalJson(scenario.platformManifest),
|
|
116
|
+
effectivePrompt: scenario.effectivePrompt,
|
|
117
|
+
executable: { root: cursorHostRuntime.executableRoot, relPath: 'cursor-agent' },
|
|
118
|
+
existingUserStateRoot: cursorHostRuntime.existingUserStateRoot,
|
|
119
|
+
sessionRoot,
|
|
120
|
+
timeoutPolicy: {
|
|
121
|
+
schemaVersion: 1, kind: 'skill-family.timeout-policy',
|
|
122
|
+
maxSeconds: (distribution.timeoutMs ?? 300000) / 1000, killGraceSeconds: 1,
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
// An unexpected exception after dispatch cannot establish process termination.
|
|
126
|
+
retain = true;
|
|
127
|
+
result = await runHostVerificationFn(prepared);
|
|
128
|
+
retain = !['observed', 'failed', 'rejected'].includes(result?.status);
|
|
129
|
+
if (retain) {
|
|
130
|
+
throw new ReleaseError(CONSUMER_VERIFICATION_DEFERRED,
|
|
131
|
+
'Cursor invocation is indeterminate; inspect the retained private scene before retrying with fresh runtime inputs', {
|
|
132
|
+
unitId,
|
|
133
|
+
requirements: [{ unitId, hostId: 'cursor', action: 'inspect-retained-cursor-scene', sceneId: basename(owned.root) }],
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
const stdout = result.streams ? await prepared.readInvocationStream(result, 'stdout') : null;
|
|
137
|
+
if (result.status !== 'observed') {
|
|
138
|
+
throw fail('Foundation Cursor invocation did not reach an observed result', { unitId, status: result.status, reason: result.reason });
|
|
139
|
+
}
|
|
140
|
+
if (!stdout) throw fail('Cursor invocation has no bound stdout evidence', { unitId });
|
|
141
|
+
let answer;
|
|
142
|
+
try { answer = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(stdout)); } catch {
|
|
143
|
+
throw fail('Cursor invocation did not return valid UTF-8 success JSON', { unitId });
|
|
144
|
+
}
|
|
145
|
+
if (answer?.type !== 'result' || answer.subtype !== 'success' || answer.is_error !== false
|
|
146
|
+
|| typeof answer.result !== 'string' || answer.result !== scenario.expectedResult) {
|
|
147
|
+
throw fail('Cursor result does not match the frozen expected result', { unitId });
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
planDigest: plan.digest, unitId, distributionType: 'cursor-plugin',
|
|
151
|
+
candidateRef: unit.frozenSnapshot.commit, payloadDigest: contract.payloadDigest,
|
|
152
|
+
manifestRelativePath: contract.manifestRelativePath, entrySkill: contract.entrySkill,
|
|
153
|
+
hostId: result.host.hostId, driverId: result.host.driverId, foundationStatus: result.status,
|
|
154
|
+
requestDigest: result.requestDigest, runtimeIdentities: result.runtimeIdentities,
|
|
155
|
+
execution: result.execution, snapshots: result.snapshots, streams: result.streams, observedAt: clock(),
|
|
156
|
+
};
|
|
157
|
+
} catch (error) {
|
|
158
|
+
if (error instanceof ReleaseError) throw error;
|
|
159
|
+
if (retain) {
|
|
160
|
+
throw new ReleaseError(CONSUMER_VERIFICATION_DEFERRED, 'Cursor invocation outcome is unknown; inspect the retained private scene', {
|
|
161
|
+
unitId, requirements: [{ unitId, hostId: 'cursor', action: 'inspect-retained-cursor-scene', sceneId: basename(owned.root) }],
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
throw fail('Foundation Cursor host verification failed closed', { unitId, foundationCode: error?.code ?? null });
|
|
165
|
+
} finally {
|
|
166
|
+
if (!retain) await owned.dispose();
|
|
167
|
+
}
|
|
168
|
+
}
|
package/src/core/plan.mjs
CHANGED
|
@@ -413,7 +413,9 @@ function buildExpectedAdapterMap() {
|
|
|
413
413
|
'create-tag': 'git-github',
|
|
414
414
|
'github-release': 'github',
|
|
415
415
|
'npm-publish': 'npm',
|
|
416
|
-
...Object.fromEntries(PLATFORMS
|
|
416
|
+
...Object.fromEntries(PLATFORMS
|
|
417
|
+
.filter((platform) => platform.actionType !== null)
|
|
418
|
+
.map((platform) => [platform.actionType, platform.adapter])),
|
|
417
419
|
'set-default-branch': 'git-github',
|
|
418
420
|
};
|
|
419
421
|
}
|
|
@@ -857,6 +859,22 @@ export function validatePlanActionCompleteness(plan, options = {}) {
|
|
|
857
859
|
for (const platform of PLATFORMS) {
|
|
858
860
|
const dist = distributions.find((d) => d.type === platform.distributionType);
|
|
859
861
|
if (!dist) continue;
|
|
862
|
+
if (platform.actionType === null) {
|
|
863
|
+
if (!dist.entrySkill) {
|
|
864
|
+
failures.push(`unit "${unitId}": ${platform.distributionType} distribution requires entrySkill`);
|
|
865
|
+
}
|
|
866
|
+
const contract = dist.hostVerificationContract;
|
|
867
|
+
if (
|
|
868
|
+
!contract
|
|
869
|
+
|| contract.hostId !== platform.id
|
|
870
|
+
|| contract.entrySkill !== dist.entrySkill
|
|
871
|
+
|| contract.manifestRelativePath !== `skills/${dist.entrySkill}/SKILL.md`
|
|
872
|
+
|| contract.payloadDigest !== frozen?.manifestDigest
|
|
873
|
+
) {
|
|
874
|
+
failures.push(`unit "${unitId}": ${platform.distributionType} distribution host verification contract does not match the frozen payload`);
|
|
875
|
+
}
|
|
876
|
+
continue;
|
|
877
|
+
}
|
|
860
878
|
const plugin = dist.plugin;
|
|
861
879
|
const marketplace = dist.marketplace;
|
|
862
880
|
const entrySkill = dist.entrySkill;
|
package/src/core/postpublish.mjs
CHANGED
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
resolvePresetRequiresApproval,
|
|
31
31
|
} from './presets.mjs';
|
|
32
32
|
import { checkGitRemoteUrl, describeGitRemoteUrlFailure } from './git-url-policy.mjs';
|
|
33
|
+
import { classifyPathInput } from 'skill-family-harness-node';
|
|
33
34
|
|
|
34
35
|
/** Secret-ish environment variable denylist (R3 credential hygiene). */
|
|
35
36
|
export const ENV_ALLOWLIST_DENYLIST = /TOKEN|SECRET|PASSWORD|PASSPHRASE|API_KEY|CREDENTIAL/i;
|
|
@@ -42,7 +43,7 @@ const SAFE_ID_RE = /^[a-z0-9][a-z0-9._-]*$/;
|
|
|
42
43
|
|
|
43
44
|
/** Branch pattern (leading alphanumeric blocks option-like names). */
|
|
44
45
|
const BRANCH_RE = /^[A-Za-z0-9][A-Za-z0-9._/-]*$/;
|
|
45
|
-
const LOCAL_HOSTS = new Set(['claude', 'codex', 'kimi', 'codebuddy', 'workbuddy']);
|
|
46
|
+
const LOCAL_HOSTS = new Set(['claude', 'codex', 'kimi', 'codebuddy', 'workbuddy', 'qoder', 'cursor']);
|
|
46
47
|
const HUB_HOST_RE = /^[A-Za-z0-9](?:[A-Za-z0-9.-]*[A-Za-z0-9])?$/u;
|
|
47
48
|
const HUB_REF_RE = /^refs\/heads\/[A-Za-z0-9][A-Za-z0-9._-]*(?:\/[A-Za-z0-9][A-Za-z0-9._-]*)*$/u;
|
|
48
49
|
|
|
@@ -500,6 +501,13 @@ export function validatePostPublishDeclaration(postPublish, options = {}) {
|
|
|
500
501
|
if (hosts.has(host)) fail(`${unitLabel}localHostUpdate.hosts contains duplicate host "${host}"`);
|
|
501
502
|
hosts.add(host);
|
|
502
503
|
}
|
|
504
|
+
if (hosts.has('cursor')) {
|
|
505
|
+
if (!/^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/u.test(localHostUpdate.plugin)) fail(`${unitLabel}Cursor plugin name must match the Cursor naming convention`);
|
|
506
|
+
const cursor = localHostUpdate.cursor;
|
|
507
|
+
if (!cursor || typeof cursor !== 'object' || Array.isArray(cursor)) fail(`${unitLabel}localHostUpdate.cursor is required`);
|
|
508
|
+
if (!classifyPathInput(cursor.sourcePath).ok) fail(`${unitLabel}localHostUpdate.cursor.sourcePath must be a safe relative path`);
|
|
509
|
+
if (cursor.dependencyInstall !== undefined && cursor.dependencyInstall !== 'npm-ci-ignore-scripts') fail(`${unitLabel}localHostUpdate.cursor.dependencyInstall is unsupported`);
|
|
510
|
+
} else if (localHostUpdate.cursor !== undefined) fail(`${unitLabel}localHostUpdate.cursor requires cursor in hosts`);
|
|
503
511
|
const hub = localHostUpdate.hub;
|
|
504
512
|
if (!hub || typeof hub !== 'object' || Array.isArray(hub)) {
|
|
505
513
|
fail(`${unitLabel}localHostUpdate.hub must be a non-null object`);
|
|
@@ -67,7 +67,7 @@ function postVerificationComplete(run) {
|
|
|
67
67
|
function publicationComplete(run) {
|
|
68
68
|
return run.checkpoints.every((cp) => COMPLETED_CHECKPOINTS.has(cp.status)
|
|
69
69
|
|| (['failed', 'deferred'].includes(cp.status)
|
|
70
|
-
&& ['claude-marketplace-install', 'codex-marketplace-install', 'kimi-marketplace-install', 'codebuddy-marketplace-install'].includes(cp.actionType)));
|
|
70
|
+
&& ['claude-marketplace-install', 'codex-marketplace-install', 'kimi-marketplace-install', 'codebuddy-marketplace-install', 'qoder-marketplace-install'].includes(cp.actionType)));
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
async function lineagePathsContained(run, runsRoot) {
|
package/src/core/run.mjs
CHANGED
|
@@ -464,7 +464,7 @@ async function validateStatePredecessorChain(run, runPath, options = {}) {
|
|
|
464
464
|
}
|
|
465
465
|
}
|
|
466
466
|
|
|
467
|
-
function validateSourceRunEdge(child, parent) {
|
|
467
|
+
export function validateSourceRunEdge(child, parent) {
|
|
468
468
|
if (child.command === 'reconcile') {
|
|
469
469
|
if (!['publish', 'reconcile'].includes(parent.command) || parent.status !== 'PARTIAL') {
|
|
470
470
|
throw new ReleaseError(
|
|
@@ -91,6 +91,7 @@ export function normalizeGenericSkillsRel(skillsRaw) {
|
|
|
91
91
|
const SKILLS_NORMALIZERS = {
|
|
92
92
|
claude: normalizeGenericSkillsRel,
|
|
93
93
|
codex: normalizeGenericSkillsRel,
|
|
94
|
+
qoder: normalizeGenericSkillsRel,
|
|
94
95
|
kimi: normalizeKimiSkillsRel,
|
|
95
96
|
codebuddy: normalizeCodeBuddySkillsRel,
|
|
96
97
|
};
|
|
@@ -57,7 +57,7 @@ function validateGate(gate) {
|
|
|
57
57
|
if (!gate.scope || typeof gate.scope.unit !== 'string') {
|
|
58
58
|
throw gateError(gate, 'must declare scope.unit');
|
|
59
59
|
}
|
|
60
|
-
if (gate.phase === 'consumer-verify' && !['npm', 'claude-plugin', 'codex-plugin', 'kimi-plugin', 'codebuddy-plugin'].includes(gate.scope.distribution)) {
|
|
60
|
+
if (gate.phase === 'consumer-verify' && !['npm', 'claude-plugin', 'codex-plugin', 'kimi-plugin', 'codebuddy-plugin', 'qoder-plugin'].includes(gate.scope.distribution)) {
|
|
61
61
|
throw gateError(gate, 'consumer-verify must declare a supported scope.distribution');
|
|
62
62
|
}
|
|
63
63
|
if (!Array.isArray(gate.command) || gate.command.length === 0 || gate.command.some((value) => typeof value !== 'string')) {
|
|
@@ -132,6 +132,70 @@ function codexCrossValidateListEntry(found, action) {
|
|
|
132
132
|
return { ok: true };
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
+
// --- qoder strategy -------------------------------------------------------
|
|
136
|
+
|
|
137
|
+
function qoderParseListOutput(listOutput, pluginId) {
|
|
138
|
+
if (!Array.isArray(listOutput)) {
|
|
139
|
+
return { ok: false, error: 'Qoder plugin list did not return an array' };
|
|
140
|
+
}
|
|
141
|
+
const matches = listOutput.filter((entry) => entry?.id === pluginId);
|
|
142
|
+
if (matches.length === 0) {
|
|
143
|
+
return { ok: false, error: `plugin "${pluginId}" not found in Qoder plugin list` };
|
|
144
|
+
}
|
|
145
|
+
if (matches.length !== 1) {
|
|
146
|
+
return { ok: false, error: `plugin "${pluginId}" has duplicate Qoder list entries` };
|
|
147
|
+
}
|
|
148
|
+
const [found] = matches;
|
|
149
|
+
if (typeof found.installPath !== 'string' || found.installPath.length === 0) {
|
|
150
|
+
return { ok: false, error: `plugin "${pluginId}" found but missing installPath` };
|
|
151
|
+
}
|
|
152
|
+
return { ok: true, found, installPath: found.installPath };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function qoderParseMarketplaceListOutput(listOutput, marketplace) {
|
|
156
|
+
if (!Array.isArray(listOutput)) {
|
|
157
|
+
return { ok: false, error: 'Qoder marketplace list did not return an array' };
|
|
158
|
+
}
|
|
159
|
+
const matches = listOutput.filter((entry) => entry?.name === marketplace);
|
|
160
|
+
if (matches.length === 0) {
|
|
161
|
+
return { ok: false, error: `marketplace "${marketplace}" not found in Qoder marketplace list` };
|
|
162
|
+
}
|
|
163
|
+
if (matches.length !== 1) {
|
|
164
|
+
return { ok: false, error: `marketplace "${marketplace}" has duplicate Qoder list entries` };
|
|
165
|
+
}
|
|
166
|
+
const [found] = matches;
|
|
167
|
+
if (found.source?.source !== 'git' || typeof found.source.url !== 'string' || found.source.url.length === 0) {
|
|
168
|
+
return { ok: false, error: `marketplace "${marketplace}" has invalid Qoder git source` };
|
|
169
|
+
}
|
|
170
|
+
if (typeof found.installLocation !== 'string' || found.installLocation.length === 0) {
|
|
171
|
+
return { ok: false, error: `marketplace "${marketplace}" found but missing installLocation` };
|
|
172
|
+
}
|
|
173
|
+
return { ok: true, found, installPath: found.installLocation };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function qoderExtractInstallPath({ listParsed }) {
|
|
177
|
+
return { ok: true, installPath: listParsed?.installPath };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function qoderExtractListIdentity(found) {
|
|
181
|
+
return {
|
|
182
|
+
plugin: found.name,
|
|
183
|
+
marketplace: String(found.id ?? '').split('@').slice(1).join('@'),
|
|
184
|
+
version: found.version,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function qoderCrossValidateListEntry(found, action) {
|
|
189
|
+
const selector = `${action.plugin}@${action.marketplace}`;
|
|
190
|
+
if (found.name !== action.plugin || found.source !== selector || found.scope !== 'user') {
|
|
191
|
+
return { ok: false, error: `Qoder plugin "${selector}" does not match its frozen user-scope identity` };
|
|
192
|
+
}
|
|
193
|
+
if (found.version !== action.version) {
|
|
194
|
+
return { ok: false, error: `list version "${found.version}" does not match action version "${action.version}"` };
|
|
195
|
+
}
|
|
196
|
+
return { ok: true };
|
|
197
|
+
}
|
|
198
|
+
|
|
135
199
|
// --- platform descriptors --------------------------------------------------
|
|
136
200
|
|
|
137
201
|
const CLAUDE = Object.freeze({
|
|
@@ -188,6 +252,7 @@ const CLAUDE = Object.freeze({
|
|
|
188
252
|
pluginDirName: '.claude-plugin',
|
|
189
253
|
templateFileName: 'plugin.json',
|
|
190
254
|
hasMarketplace: false,
|
|
255
|
+
enabled: true,
|
|
191
256
|
}),
|
|
192
257
|
strategy: Object.freeze({
|
|
193
258
|
parseListOutput: claudeParseListOutput,
|
|
@@ -249,6 +314,7 @@ const CODEX = Object.freeze({
|
|
|
249
314
|
templateFileName: 'plugin.json',
|
|
250
315
|
marketplaceFileName: null,
|
|
251
316
|
hasMarketplace: false,
|
|
317
|
+
enabled: true,
|
|
252
318
|
}),
|
|
253
319
|
strategy: Object.freeze({
|
|
254
320
|
parseListOutput: codexParseListOutput,
|
|
@@ -309,6 +375,7 @@ const KIMI = Object.freeze({
|
|
|
309
375
|
templateFileName: 'plugin.json',
|
|
310
376
|
marketplaceFileName: null,
|
|
311
377
|
hasMarketplace: false,
|
|
378
|
+
enabled: true,
|
|
312
379
|
}),
|
|
313
380
|
strategy: Object.freeze({
|
|
314
381
|
parseListOutput: null,
|
|
@@ -395,6 +462,7 @@ const CODEBUDDY = Object.freeze({
|
|
|
395
462
|
templateFileName: 'plugin.json',
|
|
396
463
|
marketplaceFileName: null,
|
|
397
464
|
hasMarketplace: false,
|
|
465
|
+
enabled: true,
|
|
398
466
|
}),
|
|
399
467
|
strategy: Object.freeze({
|
|
400
468
|
parseListOutput: null,
|
|
@@ -408,20 +476,126 @@ const CODEBUDDY = Object.freeze({
|
|
|
408
476
|
}),
|
|
409
477
|
});
|
|
410
478
|
|
|
411
|
-
|
|
412
|
-
|
|
479
|
+
const QODER = Object.freeze({
|
|
480
|
+
id: 'qoder',
|
|
481
|
+
skillProjectionSurface: 'platforms/qoder',
|
|
482
|
+
distributionType: 'qoder-plugin',
|
|
483
|
+
actionType: 'qoder-marketplace-install',
|
|
484
|
+
adapter: 'plugin-marketplace',
|
|
485
|
+
automatable: true,
|
|
486
|
+
installMethod: 'structured-cli',
|
|
487
|
+
// Qoder's marketplace-add command follows the marketplace default branch;
|
|
488
|
+
// the frozen commit is checked from the materialized Hub checkout before
|
|
489
|
+
// installation, so marketplace add itself is not treated as a ref pin.
|
|
490
|
+
refStrength: 'commit-sha',
|
|
491
|
+
outputProtocol: 'structured',
|
|
492
|
+
identityEvidence: 'list-record',
|
|
493
|
+
degradationPolicy: 'block',
|
|
494
|
+
cli: Object.freeze({
|
|
495
|
+
binary: 'qodercli',
|
|
496
|
+
binaryAliases: Object.freeze(['qoder']),
|
|
497
|
+
marketplaceAdd: (repo) => ['plugins', 'marketplace', 'add', repo, '--scope', 'user'],
|
|
498
|
+
install: (plugin, marketplace) => ['plugins', 'install', `${plugin}@${marketplace}`, '--scope', 'user', '--json'],
|
|
499
|
+
marketplaceList: () => ['plugins', 'marketplace', 'list', '--json'],
|
|
500
|
+
list: () => ['plugins', 'list', '--json'],
|
|
501
|
+
}),
|
|
502
|
+
jsonProtocol: Object.freeze({
|
|
503
|
+
listOutput: 'array',
|
|
504
|
+
installPathSource: 'list',
|
|
505
|
+
marketplaceAddOutput: null,
|
|
506
|
+
pluginInstallOutput: null,
|
|
507
|
+
}),
|
|
508
|
+
isolationEnv: (home) => ({ HOME: home }),
|
|
509
|
+
isolationSubdirs: Object.freeze(['.qoder']),
|
|
510
|
+
manifestPaths: Object.freeze({
|
|
511
|
+
plugin: '.qoder-plugin/plugin.json',
|
|
512
|
+
marketplace: null,
|
|
513
|
+
}),
|
|
514
|
+
marketplaceSourceForm: null,
|
|
515
|
+
marketplaceEntryCarriesVersion: false,
|
|
516
|
+
marketplaceRefForm: null,
|
|
517
|
+
knownHostArtifacts: Object.freeze(['.git']),
|
|
518
|
+
schemaRequiredFields: Object.freeze(['plugin', 'marketplace', 'entrySkill']),
|
|
519
|
+
skillRendering: Object.freeze({ mode: 'substitute', preamble: 'qoder', placeholder: '${CLAUDE_PLUGIN_ROOT}' }),
|
|
520
|
+
buildAdapter: Object.freeze({
|
|
521
|
+
name: 'qoder',
|
|
522
|
+
pluginDirName: '.qoder-plugin',
|
|
523
|
+
templateFileName: 'plugin.json',
|
|
524
|
+
marketplaceFileName: null,
|
|
525
|
+
hasMarketplace: false,
|
|
526
|
+
enabled: true,
|
|
527
|
+
}),
|
|
528
|
+
strategy: Object.freeze({
|
|
529
|
+
parseListOutput: qoderParseListOutput,
|
|
530
|
+
parseMarketplaceListOutput: qoderParseMarketplaceListOutput,
|
|
531
|
+
extractInstallPath: qoderExtractInstallPath,
|
|
532
|
+
extractListIdentity: qoderExtractListIdentity,
|
|
533
|
+
crossValidateListEntry: qoderCrossValidateListEntry,
|
|
534
|
+
buildManualRequirement: null,
|
|
535
|
+
readManifest: null,
|
|
536
|
+
}),
|
|
537
|
+
});
|
|
413
538
|
|
|
414
|
-
const
|
|
415
|
-
|
|
539
|
+
const CURSOR = Object.freeze({
|
|
540
|
+
id: 'cursor',
|
|
541
|
+
skillProjectionSurface: 'platforms/cursor',
|
|
542
|
+
distributionType: 'cursor-plugin',
|
|
543
|
+
actionType: null,
|
|
544
|
+
adapter: null,
|
|
545
|
+
automatable: true,
|
|
546
|
+
installMethod: 'foundation-host-verification',
|
|
547
|
+
refStrength: 'local-payload',
|
|
548
|
+
outputProtocol: 'structured',
|
|
549
|
+
identityEvidence: 'host-verification-result',
|
|
550
|
+
degradationPolicy: 'block',
|
|
551
|
+
cli: null,
|
|
552
|
+
jsonProtocol: Object.freeze({
|
|
553
|
+
listOutput: null,
|
|
554
|
+
installPathSource: null,
|
|
555
|
+
marketplaceAddOutput: null,
|
|
556
|
+
pluginInstallOutput: null,
|
|
557
|
+
}),
|
|
558
|
+
isolationEnv: null,
|
|
559
|
+
isolationSubdirs: Object.freeze([]),
|
|
560
|
+
manifestPaths: Object.freeze({ plugin: null, marketplace: null }),
|
|
561
|
+
marketplaceSourceForm: null,
|
|
562
|
+
marketplaceEntryCarriesVersion: null,
|
|
563
|
+
marketplaceRefForm: null,
|
|
564
|
+
knownHostArtifacts: Object.freeze([]),
|
|
565
|
+
schemaRequiredFields: Object.freeze(['entrySkill']),
|
|
566
|
+
skillRendering: null,
|
|
567
|
+
buildAdapter: Object.freeze({
|
|
568
|
+
name: 'cursor',
|
|
569
|
+
pluginDirName: '.cursor-plugin',
|
|
570
|
+
templateFileName: 'plugin.json',
|
|
571
|
+
marketplaceFileName: null,
|
|
572
|
+
hasMarketplace: false,
|
|
573
|
+
enabled: true,
|
|
574
|
+
}),
|
|
575
|
+
strategy: Object.freeze({
|
|
576
|
+
parseListOutput: null,
|
|
577
|
+
extractInstallPath: null,
|
|
578
|
+
extractListIdentity: null,
|
|
579
|
+
crossValidateListEntry: null,
|
|
580
|
+
buildManualRequirement: null,
|
|
581
|
+
readManifest: null,
|
|
582
|
+
}),
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
/** Ordered platform registry. Order is significant. */
|
|
586
|
+
export const PLATFORMS = Object.freeze([CLAUDE, CODEX, KIMI, CODEBUDDY, QODER, CURSOR]);
|
|
587
|
+
|
|
588
|
+
const VALID_DISTRIBUTION_TYPES = new Set(['claude-plugin', 'codex-plugin', 'kimi-plugin', 'codebuddy-plugin', 'qoder-plugin', 'cursor-plugin']);
|
|
589
|
+
const VALID_ACTION_TYPES = new Set(['claude-marketplace-install', 'codex-marketplace-install', 'kimi-marketplace-install', 'codebuddy-marketplace-install', 'qoder-marketplace-install', null]);
|
|
416
590
|
const VALID_SOURCE_FORMS = new Set(['string', 'local-path-object', null]);
|
|
417
591
|
const VALID_MARKETPLACE_REF_FORMS = new Set(['sha', 'name', null]);
|
|
418
592
|
const VALID_LIST_OUTPUTS = new Set(['array', 'installed-object', null]);
|
|
419
593
|
const VALID_CLI_OUTPUTS = new Set(['json', null]);
|
|
420
594
|
const VALID_ENTRY_VERSION_BINDING = new Set([true, false, null]);
|
|
421
|
-
const VALID_INSTALL_METHODS = new Set(['structured-cli', 'interactive-only', 'human-attestation']);
|
|
422
|
-
const VALID_REF_STRENGTHS = new Set(['commit-sha', 'name-ref', 'unfixable']);
|
|
595
|
+
const VALID_INSTALL_METHODS = new Set(['structured-cli', 'interactive-only', 'human-attestation', 'foundation-host-verification']);
|
|
596
|
+
const VALID_REF_STRENGTHS = new Set(['commit-sha', 'name-ref', 'unfixable', 'local-payload']);
|
|
423
597
|
const VALID_OUTPUT_PROTOCOLS = new Set(['structured', 'text', 'none']);
|
|
424
|
-
const VALID_IDENTITY_EVIDENCE = new Set(['list-record', 'install-output', 'filesystem-payload', 'human-attestation']);
|
|
598
|
+
const VALID_IDENTITY_EVIDENCE = new Set(['list-record', 'install-output', 'filesystem-payload', 'human-attestation', 'host-verification-result']);
|
|
425
599
|
const VALID_DEGRADATION_POLICIES = new Set(['block', 'human-attestation', 'human-attestation-with-fallback']);
|
|
426
600
|
const SKILL_PROJECTION_SURFACE_PATTERN = /^platforms\/[a-z0-9]+(?:-[a-z0-9]+)*$/u;
|
|
427
601
|
|
|
@@ -442,19 +616,19 @@ const STANDALONE_SHA_RE = /^[0-9a-f]{40}$/u;
|
|
|
442
616
|
function standaloneIdentityCore(platformOrId, fields) {
|
|
443
617
|
const platform = typeof platformOrId === 'string' ? getPlatform(platformOrId) : platformOrId;
|
|
444
618
|
const id = platform?.id;
|
|
445
|
-
if (
|
|
619
|
+
if (!['claude', 'codex', 'qoder'].includes(id)) {
|
|
446
620
|
throw new Error(`standalone-index install identity is unsupported for platform "${id ?? '<unknown>'}"`);
|
|
447
621
|
}
|
|
448
622
|
const { name, source, version } = fields;
|
|
449
623
|
if (typeof name !== 'string' || name.length === 0
|
|
450
624
|
|| !source || typeof source !== 'object' || Array.isArray(source)
|
|
451
625
|
|| typeof source.source !== 'string'
|
|
452
|
-
|| typeof source.ref !== 'string' || source.ref.length === 0
|
|
453
626
|
|| typeof source.sha !== 'string' || !STANDALONE_SHA_RE.test(source.sha)) {
|
|
454
627
|
throw new Error(`${id} standalone-index install identity has invalid owned fields`);
|
|
455
628
|
}
|
|
456
629
|
if (id === 'claude') {
|
|
457
|
-
if (
|
|
630
|
+
if (typeof source.ref !== 'string' || source.ref.length === 0
|
|
631
|
+
|| source.source !== 'github' || typeof source.repo !== 'string' || source.repo.length === 0
|
|
458
632
|
|| typeof version !== 'string' || version.length === 0) {
|
|
459
633
|
throw new Error('Claude standalone-index install identity requires github repo, ref, sha, and version');
|
|
460
634
|
}
|
|
@@ -465,6 +639,12 @@ function standaloneIdentityCore(platformOrId, fields) {
|
|
|
465
639
|
};
|
|
466
640
|
}
|
|
467
641
|
if (source.source !== 'url' || typeof source.url !== 'string' || source.url.length === 0) {
|
|
642
|
+
throw new Error(`${id === 'qoder' ? 'Qoder' : 'Codex'} standalone-index install identity requires url and sha`);
|
|
643
|
+
}
|
|
644
|
+
if (id === 'qoder') {
|
|
645
|
+
return { name, source: { source: 'url', url: source.url, sha: source.sha } };
|
|
646
|
+
}
|
|
647
|
+
if (typeof source.ref !== 'string' || source.ref.length === 0) {
|
|
468
648
|
throw new Error('Codex standalone-index install identity requires url, ref, and sha');
|
|
469
649
|
}
|
|
470
650
|
return {
|
|
@@ -494,6 +674,12 @@ export function buildExpectedStandaloneIndexInstallIdentity(platformOrId, frozen
|
|
|
494
674
|
source: { source: 'url', url: `https://github.com/${repo}.git`, ref: `refs/tags/${tag}`, sha },
|
|
495
675
|
});
|
|
496
676
|
}
|
|
677
|
+
if (id === 'qoder') {
|
|
678
|
+
return standaloneIdentityCore(platform, {
|
|
679
|
+
name,
|
|
680
|
+
source: { source: 'url', url: `https://github.com/${repo}.git`, sha },
|
|
681
|
+
});
|
|
682
|
+
}
|
|
497
683
|
return standaloneIdentityCore(platform, { name, source: {}, version });
|
|
498
684
|
}
|
|
499
685
|
|
|
@@ -531,6 +717,12 @@ export function projectObservedStandaloneIndexInstallIdentity(platformOrId, entr
|
|
|
531
717
|
},
|
|
532
718
|
});
|
|
533
719
|
}
|
|
720
|
+
if (id === 'qoder') {
|
|
721
|
+
return standaloneIdentityCore(platform, {
|
|
722
|
+
name: entry.name,
|
|
723
|
+
source: { source: source.source, url: source.url, sha: source.sha },
|
|
724
|
+
});
|
|
725
|
+
}
|
|
534
726
|
return standaloneIdentityCore(platform, { name: entry.name, source });
|
|
535
727
|
}
|
|
536
728
|
|
|
@@ -573,16 +765,22 @@ export function assertRegistry(registry = PLATFORMS) {
|
|
|
573
765
|
if (!VALID_ACTION_TYPES.has(platform.actionType)) {
|
|
574
766
|
throw new Error(`platform registry: ${label} has illegal actionType "${platform.actionType}"`);
|
|
575
767
|
}
|
|
576
|
-
if (
|
|
768
|
+
if (platform.installMethod !== 'foundation-host-verification'
|
|
769
|
+
&& (typeof platform.adapter !== 'string' || platform.adapter.length === 0)) {
|
|
577
770
|
throw new Error(`platform registry: ${label} needs a non-empty adapter id`);
|
|
578
771
|
}
|
|
772
|
+
if (platform.installMethod === 'foundation-host-verification'
|
|
773
|
+
&& (platform.actionType !== null || platform.adapter !== null)) {
|
|
774
|
+
throw new Error(`platform registry: ${label} host verification must not declare a checkpoint action or adapter`);
|
|
775
|
+
}
|
|
579
776
|
if (!VALID_ENTRY_VERSION_BINDING.has(platform.marketplaceEntryCarriesVersion)) {
|
|
580
777
|
throw new Error(`platform registry: ${label} has illegal marketplaceEntryCarriesVersion "${platform.marketplaceEntryCarriesVersion}"`);
|
|
581
778
|
}
|
|
582
779
|
if (typeof platform.automatable !== 'boolean') {
|
|
583
780
|
throw new Error(`platform registry: ${label} automatable must be boolean`);
|
|
584
781
|
}
|
|
585
|
-
if (
|
|
782
|
+
if (platform.installMethod !== 'foundation-host-verification'
|
|
783
|
+
&& typeof platform.isolationEnv !== 'function') {
|
|
586
784
|
throw new Error(`platform registry: ${label} isolationEnv must be a function`);
|
|
587
785
|
}
|
|
588
786
|
if (!VALID_SOURCE_FORMS.has(platform.marketplaceSourceForm)) {
|
|
@@ -603,6 +801,9 @@ export function assertRegistry(registry = PLATFORMS) {
|
|
|
603
801
|
if (!platform.buildAdapter || typeof platform.buildAdapter !== 'object') {
|
|
604
802
|
throw new Error(`platform registry: ${label} buildAdapter must be an object`);
|
|
605
803
|
}
|
|
804
|
+
if (typeof platform.buildAdapter.enabled !== 'boolean') {
|
|
805
|
+
throw new Error(`platform registry: ${label} buildAdapter.enabled must be boolean`);
|
|
806
|
+
}
|
|
606
807
|
// D6: the adapter directory name is always explicit — prepare's G4
|
|
607
808
|
// declared-host reconciliation and the build producer both key on it.
|
|
608
809
|
if (typeof platform.buildAdapter.name !== 'string' || platform.buildAdapter.name.length === 0) {
|
|
@@ -649,7 +850,11 @@ export function assertRegistry(registry = PLATFORMS) {
|
|
|
649
850
|
throw new Error(`platform registry: ${label} has illegal degradationPolicy "${platform.degradationPolicy}"`);
|
|
650
851
|
}
|
|
651
852
|
|
|
652
|
-
if (platform.
|
|
853
|
+
if (platform.installMethod === 'foundation-host-verification') {
|
|
854
|
+
if (platform.cli !== null) {
|
|
855
|
+
throw new Error(`platform registry: ${label} Foundation host verification must have cli === null`);
|
|
856
|
+
}
|
|
857
|
+
} else if (platform.automatable) {
|
|
653
858
|
if (!platform.cli || typeof platform.cli.marketplaceAdd !== 'function'
|
|
654
859
|
|| typeof platform.cli.install !== 'function' || typeof platform.cli.list !== 'function') {
|
|
655
860
|
throw new Error(`platform registry: automatable platform ${label} needs cli template functions`);
|
|
@@ -690,7 +895,8 @@ export function assertRegistry(registry = PLATFORMS) {
|
|
|
690
895
|
|
|
691
896
|
// --- capability contract consistency rules (能力契约一致性规则) -----------
|
|
692
897
|
// automatable === true 必须有 installMethod === 'structured-cli'
|
|
693
|
-
if (platform.automatable === true
|
|
898
|
+
if (platform.automatable === true
|
|
899
|
+
&& !['structured-cli', 'foundation-host-verification'].includes(platform.installMethod)) {
|
|
694
900
|
throw new Error(`platform registry: ${label} is automatable but installMethod is "${platform.installMethod}" (expected "structured-cli")`);
|
|
695
901
|
}
|
|
696
902
|
// automatable === false 必须有 installMethod !== 'structured-cli'
|
|
@@ -728,6 +934,9 @@ export function resolvePlatformRoute(platform) {
|
|
|
728
934
|
if (installMethod === 'interactive-only' || installMethod === 'human-attestation') {
|
|
729
935
|
return { route: 'human-attestation', reason: `installMethod is ${installMethod}` };
|
|
730
936
|
}
|
|
937
|
+
if (installMethod === 'foundation-host-verification') {
|
|
938
|
+
return { route: 'host-verification', reason: 'installMethod is foundation-host-verification' };
|
|
939
|
+
}
|
|
731
940
|
throw new Error(
|
|
732
941
|
`platform "${platform?.id ?? '<unknown>'}" with installMethod="${installMethod}" cannot be routed`,
|
|
733
942
|
);
|
|
@@ -745,7 +954,7 @@ export function resolveCapabilityConflicts(platform) {
|
|
|
745
954
|
const { id, automatable, installMethod, refStrength, identityEvidence, cli, strategy } = platform;
|
|
746
955
|
|
|
747
956
|
// automatable <-> installMethod 一致性
|
|
748
|
-
if (automatable === true &&
|
|
957
|
+
if (automatable === true && !['structured-cli', 'foundation-host-verification'].includes(installMethod)) {
|
|
749
958
|
conflicts.push(`automatable=true but installMethod="${installMethod}"`);
|
|
750
959
|
}
|
|
751
960
|
if (automatable === false && installMethod === 'structured-cli') {
|
|
@@ -763,7 +972,7 @@ export function resolveCapabilityConflicts(platform) {
|
|
|
763
972
|
}
|
|
764
973
|
|
|
765
974
|
// 自动化平台必须有 cli 和策略解析函数
|
|
766
|
-
if (automatable === true) {
|
|
975
|
+
if (automatable === true && installMethod !== 'foundation-host-verification') {
|
|
767
976
|
if (!cli || typeof cli !== 'object') {
|
|
768
977
|
conflicts.push(`automatable=true but cli is missing`);
|
|
769
978
|
}
|