release-skill 0.9.17 → 0.9.19
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 +1 -1
- package/CHANGELOG.md +70 -2
- package/INSTALL.md +66 -9
- package/INSTALL.zh-CN.md +49 -8
- package/README.md +41 -20
- package/README.zh-CN.md +31 -19
- 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 +4425 -1519
- 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 +46 -7
- package/adapters/claude/skills/release-help/SKILL.md +47 -103
- 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 +4425 -1519
- 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 +46 -7
- package/adapters/codex/skills/release-help/SKILL.md +49 -105
- 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 +152352 -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 +181 -0
- package/adapters/cursor/skills/release-help/SKILL.md +98 -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 +4425 -1519
- 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 +46 -7
- package/adapters/kimi/skills/release-help/SKILL.md +49 -105
- 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 +1 -1
- package/adapters/qoder/bin/consumer-contract-vectors.json +7 -7
- package/adapters/qoder/bin/error-codes.json +1 -1
- package/adapters/qoder/bin/foundation-resource-binding.json +1 -1
- package/adapters/qoder/bin/prebuild-manifest.json +8 -4
- 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 +1 -1
- package/adapters/qoder/bin/release-skill.bundle.mjs +4425 -1519
- package/adapters/qoder/bin/rules.json +1 -1
- package/adapters/qoder/data/hosts/cursor/host-descriptor.json +34 -0
- package/adapters/qoder/data/hosts/registry.json +1 -0
- package/adapters/qoder/schemas/release-plan.schema.json +255 -25
- package/adapters/qoder/schemas/release-project.schema.json +228 -26
- package/adapters/qoder/skills/release-finish/SKILL.md +46 -7
- package/adapters/qoder/skills/release-help/SKILL.md +49 -105
- package/adapters/qoder/skills/release-verify/SKILL.md +2 -2
- package/adapters/qoder/src/schemas/host-descriptor.schema.json +9 -2
- 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 +4425 -1519
- 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 +46 -7
- package/adapters/workbuddy/skills/release-help/SKILL.md +47 -103
- 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 +115 -15
- package/bin/release-skill.bundle.mjs +4425 -1519
- 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 +7 -5
- package/platform-manifest.json +75 -9
- package/references/02-project-config.md +4 -0
- 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 +46 -7
- package/skills/release-help/SKILL.md +47 -103
- package/skills/release-verify/SKILL.md +2 -2
- package/skills-src/release-finish/SKILL.md +46 -7
- package/skills-src/release-help/SKILL.md +47 -103
- 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-finish.mjs +448 -0
- package/src/commands/post-release-local.mjs +312 -36
- package/src/commands/prepare.mjs +74 -9
- package/src/commands/publish.mjs +4 -1
- package/src/commands/ship.mjs +3 -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/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 +21 -26
- package/src/producers/foundation-resource-projection.mjs +3 -3
- package/src/schemas/host-descriptor.schema.json +9 -2
package/src/commands/ship.mjs
CHANGED
|
@@ -220,6 +220,7 @@ const ACTION_TARGET_FIELDS = Object.freeze({
|
|
|
220
220
|
'codex-marketplace-install': Object.freeze(['consumer', 'plugin', 'marketplace', 'repo', 'ref', 'version', 'entrySkill']),
|
|
221
221
|
'kimi-marketplace-install': Object.freeze(['consumer', 'plugin', 'repo', 'ref', 'version', 'entrySkill']),
|
|
222
222
|
'codebuddy-marketplace-install': Object.freeze(['consumer', 'plugin', 'repo', 'ref', 'version', 'entrySkill']),
|
|
223
|
+
'qoder-marketplace-install': Object.freeze(['consumer', 'plugin', 'marketplace', 'repo', 'ref', 'version', 'entrySkill']),
|
|
223
224
|
'set-default-branch': Object.freeze(['repo', 'oldBranch', 'newBranch', 'expectedNewBranchCommit']),
|
|
224
225
|
});
|
|
225
226
|
|
|
@@ -705,6 +706,7 @@ export async function advanceShip(options = {}, injected = {}) {
|
|
|
705
706
|
adapterRegistry: options.adapterRegistry,
|
|
706
707
|
root,
|
|
707
708
|
verificationGatesAuthorized: state.verificationGatesAuthorized === true,
|
|
709
|
+
cursorHostRuntime: options.cursorHostRuntime,
|
|
708
710
|
});
|
|
709
711
|
state = {
|
|
710
712
|
...state,
|
|
@@ -837,6 +839,7 @@ export async function advanceShip(options = {}, injected = {}) {
|
|
|
837
839
|
try {
|
|
838
840
|
postRelease = derivePostReleaseChecklist(finalPlan, {
|
|
839
841
|
root,
|
|
842
|
+
planPath: state.planPath,
|
|
840
843
|
statePath,
|
|
841
844
|
unitIds: state.selectedUnitIds,
|
|
842
845
|
runPath: localFinishRunPath,
|
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
|
}
|
|
@@ -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', 'qoder']);
|
|
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) {
|
|
@@ -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')) {
|