openplanr 3.2.0 → 3.4.0
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/CHANGELOG.md +73 -0
- package/dist/cli/commands/artifact-design-share.d.ts +9 -0
- package/dist/cli/commands/artifact-design-share.d.ts.map +1 -0
- package/dist/cli/commands/artifact-design-share.js +200 -0
- package/dist/cli/commands/artifact-design-share.js.map +1 -0
- package/dist/cli/commands/artifact.d.ts.map +1 -1
- package/dist/cli/commands/artifact.js +5 -18
- package/dist/cli/commands/artifact.js.map +1 -1
- package/dist/cli/commands/ship.d.ts.map +1 -1
- package/dist/cli/commands/ship.js +2 -0
- package/dist/cli/commands/ship.js.map +1 -1
- package/dist/cli/commands/spec.d.ts +2 -1
- package/dist/cli/commands/spec.d.ts.map +1 -1
- package/dist/cli/commands/spec.js +45 -5
- package/dist/cli/commands/spec.js.map +1 -1
- package/dist/dashboard/.vite/manifest.json +2 -2
- package/dist/dashboard/assets/index-Cv4Vwhuw.css +2 -0
- package/dist/dashboard/assets/index-CvQAlBy3.js +75 -0
- package/dist/dashboard/assets/index-CvQAlBy3.js.map +1 -0
- package/dist/dashboard/dashboard-manifest.json +14 -14
- package/dist/dashboard/index.html +2 -2
- package/dist/services/claude-plugin-service.d.ts +5 -0
- package/dist/services/claude-plugin-service.d.ts.map +1 -1
- package/dist/services/claude-plugin-service.js +18 -2
- package/dist/services/claude-plugin-service.js.map +1 -1
- package/dist/services/codex-plugin-service.d.ts.map +1 -1
- package/dist/services/codex-plugin-service.js +11 -3
- package/dist/services/codex-plugin-service.js.map +1 -1
- package/dist/services/design-artifact-service.d.ts +20 -1
- package/dist/services/design-artifact-service.d.ts.map +1 -1
- package/dist/services/design-artifact-service.js +137 -18
- package/dist/services/design-artifact-service.js.map +1 -1
- package/dist/services/runtime-manager/codex-discovery.d.ts +1 -3
- package/dist/services/runtime-manager/codex-discovery.d.ts.map +1 -1
- package/dist/services/runtime-manager/codex-discovery.js +3 -16
- package/dist/services/runtime-manager/codex-discovery.js.map +1 -1
- package/dist/services/runtime-manager/doctor.d.ts +25 -0
- package/dist/services/runtime-manager/doctor.d.ts.map +1 -1
- package/dist/services/runtime-manager/doctor.js +480 -0
- package/dist/services/runtime-manager/doctor.js.map +1 -1
- package/dist/services/runtime-manager/errors.d.ts +12 -0
- package/dist/services/runtime-manager/errors.d.ts.map +1 -0
- package/dist/services/runtime-manager/errors.js +14 -0
- package/dist/services/runtime-manager/errors.js.map +1 -0
- package/dist/services/runtime-manager/global-state.d.ts +7 -0
- package/dist/services/runtime-manager/global-state.d.ts.map +1 -1
- package/dist/services/runtime-manager/global-state.js +116 -0
- package/dist/services/runtime-manager/global-state.js.map +1 -1
- package/dist/services/runtime-manager/host-version-probe.d.ts +8 -0
- package/dist/services/runtime-manager/host-version-probe.d.ts.map +1 -0
- package/dist/services/runtime-manager/host-version-probe.js +14 -0
- package/dist/services/runtime-manager/host-version-probe.js.map +1 -0
- package/dist/services/runtime-manager/install-plan.d.ts +25 -0
- package/dist/services/runtime-manager/install-plan.d.ts.map +1 -1
- package/dist/services/runtime-manager/install-plan.js +305 -0
- package/dist/services/runtime-manager/install-plan.js.map +1 -1
- package/dist/services/runtime-manager/inventory.d.ts +6 -0
- package/dist/services/runtime-manager/inventory.d.ts.map +1 -1
- package/dist/services/runtime-manager/inventory.js +16 -1
- package/dist/services/runtime-manager/inventory.js.map +1 -1
- package/dist/services/runtime-manager/legacy-adapters.d.ts +9 -0
- package/dist/services/runtime-manager/legacy-adapters.d.ts.map +1 -0
- package/dist/services/runtime-manager/legacy-adapters.js +187 -0
- package/dist/services/runtime-manager/legacy-adapters.js.map +1 -0
- package/dist/services/runtime-manager/paths.d.ts +18 -0
- package/dist/services/runtime-manager/paths.d.ts.map +1 -0
- package/dist/services/runtime-manager/paths.js +83 -0
- package/dist/services/runtime-manager/paths.js.map +1 -0
- package/dist/services/runtime-manager/runtime-package.d.ts +21 -0
- package/dist/services/runtime-manager/runtime-package.d.ts.map +1 -1
- package/dist/services/runtime-manager/runtime-package.js +77 -0
- package/dist/services/runtime-manager/runtime-package.js.map +1 -1
- package/dist/services/runtime-manager/storage.d.ts +47 -0
- package/dist/services/runtime-manager/storage.d.ts.map +1 -0
- package/dist/services/runtime-manager/storage.js +604 -0
- package/dist/services/runtime-manager/storage.js.map +1 -0
- package/dist/services/runtime-manager-service.d.ts +7 -17
- package/dist/services/runtime-manager-service.d.ts.map +1 -1
- package/dist/services/runtime-manager-service.js +32 -1695
- package/dist/services/runtime-manager-service.js.map +1 -1
- package/dist/services/ship-checks/contract.d.ts +15 -1
- package/dist/services/ship-checks/contract.d.ts.map +1 -1
- package/dist/services/ship-checks/contract.js +1 -1
- package/dist/services/ship-checks/contract.js.map +1 -1
- package/dist/services/ship-checks/coverage.d.ts +4 -0
- package/dist/services/ship-checks/coverage.d.ts.map +1 -0
- package/dist/services/ship-checks/coverage.js +113 -0
- package/dist/services/ship-checks/coverage.js.map +1 -0
- package/dist/services/ship-checks/discover.d.ts.map +1 -1
- package/dist/services/ship-checks/discover.js +5 -1
- package/dist/services/ship-checks/discover.js.map +1 -1
- package/dist/services/ship-checks/package-contents.d.ts +4 -0
- package/dist/services/ship-checks/package-contents.d.ts.map +1 -0
- package/dist/services/ship-checks/package-contents.js +91 -0
- package/dist/services/ship-checks/package-contents.js.map +1 -0
- package/dist/services/ship-checks/packages.d.ts +2 -0
- package/dist/services/ship-checks/packages.d.ts.map +1 -1
- package/dist/services/ship-checks/packages.js +4 -0
- package/dist/services/ship-checks/packages.js.map +1 -1
- package/dist/services/ship-checks/scope.js +2 -1
- package/dist/services/ship-checks/scope.js.map +1 -1
- package/dist/services/spec-service.d.ts +18 -0
- package/dist/services/spec-service.d.ts.map +1 -1
- package/dist/services/spec-service.js +174 -9
- package/dist/services/spec-service.js.map +1 -1
- package/dist/templates/spec/spec-shaped.md.hbs +1 -1
- package/dist/templates/spec/spec.md.hbs +2 -2
- package/dist/utils/splice-managed-block.js +1 -1
- package/dist/utils/splice-managed-block.js.map +1 -1
- package/docs/CLI.md +86 -2
- package/lib/host-packages/adapter-registry.json +5 -5
- package/lib/host-packages/capability-map.json +3 -3
- package/lib/host-packages/claude/.claude-plugin/marketplace.json +3 -3
- package/lib/host-packages/claude/openplanr/.claude-plugin/plugin.json +6 -6
- package/lib/host-packages/claude/openplanr/.openplanr-content.json +94 -146
- package/lib/host-packages/claude/openplanr/README.md +12 -12
- package/lib/host-packages/claude/openplanr/agents/planr-qa.md +5 -3
- package/lib/host-packages/claude/openplanr/references/agents/shared/modes/shared/task-context-resolution.md +4 -4
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-artifact-shell.mjs +2 -4
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-document.mjs +110 -25
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-handoff.mjs +851 -57
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-review-state-store.mjs +45 -0
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-review.mjs +65 -74
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-runtime-home.mjs +0 -1
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-share-cli-bridge.mjs +321 -0
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-d707e49b.mjs +1652 -0
- package/lib/host-packages/{openai/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs → claude/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-9f6918b0.mjs} +537 -5
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-design-support-0bac378d.mjs +137 -0
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/design.mjs +374 -61
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +32 -59
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/02-artifact-review-ui.js +138 -133
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +1 -5608
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/04-artifact-review-ui.js +2568 -0
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +10 -74
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/package.json +4 -4
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/share.js +8 -2
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +2 -2
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/09-react-dom-client-public-roots.js +5 -5
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-protocol-contracts.js +72 -2
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-design-review-experience.js +14 -7
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-canvas-engine.js +71 -34
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/21-design-studio.js +28 -14
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +12 -12
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +6 -2
- package/lib/host-packages/{openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.20.0 → claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0}/design-document.schema.json +131 -4
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0/design-review-bundle.schema.json +822 -0
- package/lib/host-packages/claude/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +616 -4775
- package/lib/host-packages/claude/openplanr/runtime/plan/scripts/design.mjs +219 -424
- package/lib/host-packages/claude/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +6 -2
- package/lib/host-packages/claude/openplanr/skills/delegate/SKILL.md +2 -1
- package/lib/host-packages/claude/openplanr/skills/delegate/references/integration-review.md +26 -20
- package/lib/host-packages/claude/openplanr/skills/delegate/references/operator-guide.md +25 -1
- package/lib/host-packages/claude/openplanr/skills/delegate/references/run-handoff.md +2 -2
- package/lib/host-packages/claude/openplanr/skills/delegate/references/worktree-custody.md +17 -9
- package/lib/host-packages/claude/openplanr/skills/delegate/scripts/adapters/claude.mjs +15 -3
- package/lib/host-packages/claude/openplanr/skills/delegate/scripts/adapters/codex.mjs +38 -2
- package/lib/host-packages/claude/openplanr/skills/delegate/scripts/adapters/native.mjs +5 -0
- package/lib/host-packages/claude/openplanr/skills/delegate/scripts/custody.mjs +217 -10
- package/lib/host-packages/claude/openplanr/skills/delegate/scripts/handoff.mjs +1080 -0
- package/lib/host-packages/claude/openplanr/skills/delegate/scripts/integrate.mjs +96 -201
- package/lib/host-packages/claude/openplanr/skills/delegate/scripts/integration-files.mjs +3 -382
- package/lib/host-packages/claude/openplanr/skills/delegate/scripts/presentation.mjs +29 -12
- package/lib/host-packages/claude/openplanr/skills/delegate/scripts/run-contract.mjs +11 -0
- package/lib/host-packages/claude/openplanr/skills/delegate/scripts/run-execution.mjs +1 -1
- package/lib/host-packages/claude/openplanr/skills/delegate/scripts/run-lifecycle.mjs +14 -10
- package/lib/host-packages/claude/openplanr/skills/delegate/scripts/run-preparation.mjs +4 -0
- package/lib/host-packages/claude/openplanr/skills/delegate/scripts/run-record.mjs +2 -2
- package/lib/host-packages/claude/openplanr/skills/design/references/design-system.md +17 -2
- package/lib/host-packages/claude/openplanr/skills/design/references/generation.md +60 -2
- package/lib/host-packages/claude/openplanr/skills/design/references/utilities.md +23 -7
- package/lib/host-packages/claude/openplanr/skills/design/schemas/design-document.schema.json +131 -4
- package/lib/host-packages/claude/openplanr/skills/design-loop/references/design-system.md +17 -2
- package/lib/host-packages/claude/openplanr/skills/design-loop/references/generation.md +60 -2
- package/lib/host-packages/claude/openplanr/skills/design-loop/references/utilities.md +23 -7
- package/lib/host-packages/claude/openplanr/skills/design-loop/schemas/design-document.schema.json +131 -4
- package/lib/host-packages/claude/openplanr/skills/design-review/references/design-system.md +17 -2
- package/lib/host-packages/claude/openplanr/skills/design-review/references/generation.md +60 -2
- package/lib/host-packages/claude/openplanr/skills/design-review/references/utilities.md +23 -7
- package/lib/host-packages/claude/openplanr/skills/design-review/schemas/design-document.schema.json +131 -4
- package/lib/host-packages/claude/openplanr/skills/investigate/SKILL.md +2 -1
- package/lib/host-packages/claude/openplanr/skills/investigate/references/fail-first.md +40 -0
- package/lib/host-packages/claude/openplanr/skills/plan/SKILL.md +21 -11
- package/lib/host-packages/claude/openplanr/skills/plan/schemas/design-document.schema.json +131 -4
- package/lib/host-packages/claude/openplanr/skills/ship/SKILL.md +51 -18
- package/lib/host-packages/claude/openplanr/skills/ship/references/fail-first.md +40 -0
- package/lib/host-packages/claude/openplanr/skills/ship/references/result-contract.md +7 -3
- package/lib/host-packages/claude/openplanr/skills/spec/SKILL.md +6 -0
- package/lib/host-packages/claude/openplanr/skills/spec/references/specification-contract.md +3 -1
- package/lib/host-packages/cursor/openplanr/.openplanr-content.json +91 -143
- package/lib/host-packages/cursor/openplanr/manifest.json +1 -1
- package/lib/host-packages/cursor/openplanr/rules/planr-delegate/references/integration-review.md +26 -20
- package/lib/host-packages/cursor/openplanr/rules/planr-delegate/references/operator-guide.md +25 -1
- package/lib/host-packages/cursor/openplanr/rules/planr-delegate/references/run-handoff.md +2 -2
- package/lib/host-packages/cursor/openplanr/rules/planr-delegate/references/worktree-custody.md +17 -9
- package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/adapters/claude.mjs +15 -3
- package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/adapters/codex.mjs +38 -2
- package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/adapters/native.mjs +5 -0
- package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/custody.mjs +217 -10
- package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/handoff.mjs +1080 -0
- package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/integrate.mjs +96 -201
- package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/integration-files.mjs +3 -382
- package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/presentation.mjs +29 -12
- package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/run-contract.mjs +11 -0
- package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/run-execution.mjs +1 -1
- package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/run-lifecycle.mjs +14 -10
- package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/run-preparation.mjs +4 -0
- package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/run-record.mjs +2 -2
- package/lib/host-packages/cursor/openplanr/rules/planr-delegate.mdc +2 -1
- package/lib/host-packages/cursor/openplanr/rules/planr-design/references/design-system.md +17 -2
- package/lib/host-packages/cursor/openplanr/rules/planr-design/references/generation.md +60 -2
- package/lib/host-packages/cursor/openplanr/rules/planr-design/references/utilities.md +23 -7
- package/lib/host-packages/cursor/openplanr/rules/planr-design/schemas/design-document.schema.json +131 -4
- package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/design-system.md +17 -2
- package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/generation.md +60 -2
- package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/references/utilities.md +23 -7
- package/lib/host-packages/cursor/openplanr/rules/planr-design-loop/schemas/design-document.schema.json +131 -4
- package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/design-system.md +17 -2
- package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/generation.md +60 -2
- package/lib/host-packages/cursor/openplanr/rules/planr-design-review/references/utilities.md +23 -7
- package/lib/host-packages/cursor/openplanr/rules/planr-design-review/schemas/design-document.schema.json +131 -4
- package/lib/host-packages/cursor/openplanr/rules/planr-investigate/references/fail-first.md +40 -0
- package/lib/host-packages/cursor/openplanr/rules/planr-investigate.mdc +2 -1
- package/lib/host-packages/cursor/openplanr/rules/planr-plan/schemas/design-document.schema.json +131 -4
- package/lib/host-packages/cursor/openplanr/rules/planr-plan.mdc +21 -11
- package/lib/host-packages/cursor/openplanr/rules/planr-ship/references/fail-first.md +40 -0
- package/lib/host-packages/cursor/openplanr/rules/planr-ship/references/result-contract.md +7 -3
- package/lib/host-packages/cursor/openplanr/rules/planr-ship.mdc +51 -18
- package/lib/host-packages/cursor/openplanr/rules/planr-spec/references/specification-contract.md +3 -1
- package/lib/host-packages/cursor/openplanr/rules/planr-spec.mdc +6 -0
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-artifact-shell.mjs +2 -4
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-document.mjs +110 -25
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-handoff.mjs +851 -57
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-review-state-store.mjs +45 -0
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-review.mjs +65 -74
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-runtime-home.mjs +0 -1
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-share-cli-bridge.mjs +321 -0
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-d707e49b.mjs +1652 -0
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/{design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs → design-shared-artifact-support-protocol-contracts-9f6918b0.mjs} +537 -5
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-design-support-0bac378d.mjs +137 -0
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design.mjs +374 -61
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +32 -59
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/02-artifact-review-ui.js +138 -133
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +1 -5608
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/04-artifact-review-ui.js +2568 -0
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +10 -74
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/package.json +4 -4
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/share.js +8 -2
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +2 -2
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/09-react-dom-client-public-roots.js +5 -5
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-protocol-contracts.js +72 -2
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-design-review-experience.js +14 -7
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-canvas-engine.js +71 -34
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/21-design-studio.js +28 -14
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +12 -12
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +6 -2
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/{v1.20.0 → v1.22.0}/design-document.schema.json +131 -4
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0/design-review-bundle.schema.json +822 -0
- package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +616 -4775
- package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/design.mjs +219 -424
- package/lib/host-packages/cursor/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +6 -2
- package/lib/host-packages/openai/.claude-plugin/marketplace.json +3 -3
- package/lib/host-packages/openai/openplanr/.codex-plugin/plugin.json +2 -2
- package/lib/host-packages/openai/openplanr/.openplanr-content.json +98 -150
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-artifact-shell.mjs +2 -4
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-document.mjs +110 -25
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-handoff.mjs +851 -57
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-review-state-store.mjs +45 -0
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-review.mjs +65 -74
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-runtime-home.mjs +0 -1
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-share-cli-bridge.mjs +321 -0
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-d707e49b.mjs +1652 -0
- package/lib/host-packages/{claude/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-ea2cd15e.mjs → openai/openplanr/runtime/design/scripts/design-shared-artifact-support-protocol-contracts-9f6918b0.mjs} +537 -5
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-design-support-0bac378d.mjs +137 -0
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/design.mjs +374 -61
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/notices/THIRD_PARTY_NOTICES.txt +32 -59
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/02-artifact-review-ui.js +138 -133
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/03-protocol-contracts.js +1 -5608
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/04-artifact-review-ui.js +2568 -0
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources.json +10 -74
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/package.json +4 -4
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/share.js +8 -2
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/02-react.js +2 -2
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/09-react-dom-client-public-roots.js +5 -5
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/12-protocol-contracts.js +72 -2
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/13-design-review-experience.js +14 -7
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/15-canvas-engine.js +71 -34
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources/21-design-studio.js +28 -14
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/design/templates/studio/studio.js.sources.json +12 -12
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/package.json +6 -2
- package/lib/host-packages/{claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.20.0 → openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0}/design-document.schema.json +131 -4
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.22.0/design-review-bundle.schema.json +822 -0
- package/lib/host-packages/openai/openplanr/runtime/plan/scripts/design-protocol-contracts.mjs +616 -4775
- package/lib/host-packages/openai/openplanr/runtime/plan/scripts/design.mjs +219 -424
- package/lib/host-packages/openai/openplanr/runtime/plan/scripts/runtime/packages/protocol/package.json +6 -2
- package/lib/host-packages/openai/openplanr/skills/delegate/SKILL.md +2 -1
- package/lib/host-packages/openai/openplanr/skills/delegate/openplanr.skill.json +1 -1
- package/lib/host-packages/openai/openplanr/skills/delegate/references/integration-review.md +26 -20
- package/lib/host-packages/openai/openplanr/skills/delegate/references/operator-guide.md +25 -1
- package/lib/host-packages/openai/openplanr/skills/delegate/references/run-handoff.md +2 -2
- package/lib/host-packages/openai/openplanr/skills/delegate/references/worktree-custody.md +17 -9
- package/lib/host-packages/openai/openplanr/skills/delegate/scripts/adapters/claude.mjs +15 -3
- package/lib/host-packages/openai/openplanr/skills/delegate/scripts/adapters/codex.mjs +38 -2
- package/lib/host-packages/openai/openplanr/skills/delegate/scripts/adapters/native.mjs +5 -0
- package/lib/host-packages/openai/openplanr/skills/delegate/scripts/custody.mjs +217 -10
- package/lib/host-packages/openai/openplanr/skills/delegate/scripts/handoff.mjs +1080 -0
- package/lib/host-packages/openai/openplanr/skills/delegate/scripts/integrate.mjs +96 -201
- package/lib/host-packages/openai/openplanr/skills/delegate/scripts/integration-files.mjs +3 -382
- package/lib/host-packages/openai/openplanr/skills/delegate/scripts/presentation.mjs +29 -12
- package/lib/host-packages/openai/openplanr/skills/delegate/scripts/run-contract.mjs +11 -0
- package/lib/host-packages/openai/openplanr/skills/delegate/scripts/run-execution.mjs +1 -1
- package/lib/host-packages/openai/openplanr/skills/delegate/scripts/run-lifecycle.mjs +14 -10
- package/lib/host-packages/openai/openplanr/skills/delegate/scripts/run-preparation.mjs +4 -0
- package/lib/host-packages/openai/openplanr/skills/delegate/scripts/run-record.mjs +2 -2
- package/lib/host-packages/openai/openplanr/skills/design/references/design-system.md +17 -2
- package/lib/host-packages/openai/openplanr/skills/design/references/generation.md +60 -2
- package/lib/host-packages/openai/openplanr/skills/design/references/utilities.md +23 -7
- package/lib/host-packages/openai/openplanr/skills/design/schemas/design-document.schema.json +131 -4
- package/lib/host-packages/openai/openplanr/skills/design-loop/references/design-system.md +17 -2
- package/lib/host-packages/openai/openplanr/skills/design-loop/references/generation.md +60 -2
- package/lib/host-packages/openai/openplanr/skills/design-loop/references/utilities.md +23 -7
- package/lib/host-packages/openai/openplanr/skills/design-loop/schemas/design-document.schema.json +131 -4
- package/lib/host-packages/openai/openplanr/skills/design-review/references/design-system.md +17 -2
- package/lib/host-packages/openai/openplanr/skills/design-review/references/generation.md +60 -2
- package/lib/host-packages/openai/openplanr/skills/design-review/references/utilities.md +23 -7
- package/lib/host-packages/openai/openplanr/skills/design-review/schemas/design-document.schema.json +131 -4
- package/lib/host-packages/openai/openplanr/skills/investigate/SKILL.md +2 -1
- package/lib/host-packages/openai/openplanr/skills/investigate/agents/openai.yaml +1 -1
- package/lib/host-packages/openai/openplanr/skills/investigate/openplanr.skill.json +12 -1
- package/lib/host-packages/openai/openplanr/skills/investigate/references/fail-first.md +40 -0
- package/lib/host-packages/openai/openplanr/skills/plan/SKILL.md +21 -11
- package/lib/host-packages/openai/openplanr/skills/plan/openplanr.skill.json +1 -1
- package/lib/host-packages/openai/openplanr/skills/plan/schemas/design-document.schema.json +131 -4
- package/lib/host-packages/openai/openplanr/skills/ship/SKILL.md +51 -18
- package/lib/host-packages/openai/openplanr/skills/ship/agents/openai.yaml +1 -1
- package/lib/host-packages/openai/openplanr/skills/ship/openplanr.skill.json +12 -1
- package/lib/host-packages/openai/openplanr/skills/ship/references/fail-first.md +40 -0
- package/lib/host-packages/openai/openplanr/skills/ship/references/result-contract.md +7 -3
- package/lib/host-packages/openai/openplanr/skills/spec/SKILL.md +6 -0
- package/lib/host-packages/openai/openplanr/skills/spec/openplanr.skill.json +1 -1
- package/lib/host-packages/openai/openplanr/skills/spec/references/specification-contract.md +3 -1
- package/lib/json-schema.mjs +4 -0
- package/package.json +16 -16
- package/dist/dashboard/assets/index-BU5fzjyz.css +0 -1
- package/dist/dashboard/assets/index-L8qtwqv6.js +0 -572
- package/dist/dashboard/assets/index-L8qtwqv6.js.map +0 -1
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-chunked-workspace-client.mjs +0 -555
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-compression.mjs +0 -4180
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-encrypted-workspace-client.mjs +0 -647
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-owner-custody.mjs +0 -129
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-resource-pack.mjs +0 -698
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-runtime-support-6774fd3d5d02.mjs +0 -24
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-share.mjs +0 -1993
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs +0 -1020
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-protocol-contracts-75a938cc.mjs +0 -222
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-shared-protocol-contracts-b5f28f94.mjs +0 -5778
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/design-upload-spool.mjs +0 -198
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/04-compression.js +0 -4175
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/05-artifact-sharing.js +0 -65
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/06-artifact-review-ui.js +0 -1755
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/07-artifact-sharing.js +0 -62
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/08-artifact-review-ui.js +0 -2633
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-paste.schema.json +0 -49
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-workspace.schema.json +0 -108
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-create.schema.json +0 -170
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-event.schema.json +0 -97
- package/lib/host-packages/claude/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-revision.schema.json +0 -56
- package/lib/host-packages/claude/openplanr/skills/delegate/scripts/integration-transaction.mjs +0 -958
- package/lib/host-packages/cursor/openplanr/rules/planr-delegate/scripts/integration-transaction.mjs +0 -958
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-chunked-workspace-client.mjs +0 -555
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-compression.mjs +0 -4180
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-encrypted-workspace-client.mjs +0 -647
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-owner-custody.mjs +0 -129
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-resource-pack.mjs +0 -698
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-runtime-support-6774fd3d5d02.mjs +0 -24
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-share.mjs +0 -1993
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs +0 -1020
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-protocol-contracts-75a938cc.mjs +0 -222
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-shared-protocol-contracts-b5f28f94.mjs +0 -5778
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/design-upload-spool.mjs +0 -198
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/04-compression.js +0 -4175
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/05-artifact-sharing.js +0 -65
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/06-artifact-review-ui.js +0 -1755
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/07-artifact-sharing.js +0 -62
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/08-artifact-review-ui.js +0 -2633
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-paste.schema.json +0 -49
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-workspace.schema.json +0 -108
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-create.schema.json +0 -170
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-event.schema.json +0 -97
- package/lib/host-packages/cursor/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-revision.schema.json +0 -56
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-chunked-workspace-client.mjs +0 -555
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-compression.mjs +0 -4180
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-encrypted-workspace-client.mjs +0 -647
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-owner-custody.mjs +0 -129
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-resource-pack.mjs +0 -698
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-runtime-support-6774fd3d5d02.mjs +0 -24
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-share.mjs +0 -1993
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-artifact-support-dependencies-design-support-protocol-contracts-3d9b1a86.mjs +0 -1020
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-protocol-contracts-75a938cc.mjs +0 -222
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-shared-protocol-contracts-b5f28f94.mjs +0 -5778
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/design-upload-spool.mjs +0 -198
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/04-compression.js +0 -4175
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/05-artifact-sharing.js +0 -65
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/06-artifact-review-ui.js +0 -1755
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/07-artifact-sharing.js +0 -62
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/artifact/templates/artifact-review-stage.js.sources/08-artifact-review-ui.js +0 -2633
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.1.0/artifact-paste.schema.json +0 -49
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-review-workspace.schema.json +0 -108
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-create.schema.json +0 -170
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-event.schema.json +0 -97
- package/lib/host-packages/openai/openplanr/runtime/design/scripts/runtime/packages/protocol/schemas/v1.9.0/design-workspace-revision.schema.json +0 -56
- package/lib/host-packages/openai/openplanr/skills/delegate/scripts/integration-transaction.mjs +0 -958
|
@@ -0,0 +1,604 @@
|
|
|
1
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
+
import { existsSync, constants as fsConstants, lstatSync, readdirSync, readFileSync, realpathSync, } from 'node:fs';
|
|
3
|
+
import { mkdir, open, rename, unlink, writeFile } from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { RuntimeManagerError } from './errors.js';
|
|
6
|
+
import { actionBytes } from './install-plan.js';
|
|
7
|
+
import { canonicalProjectPath, codexBookkeepingTarget, codexRuntimeRoot, codexSkillsRoot, effectiveCodexHome, pathIsWithin, planrCustodyAnchor, projectBackupsRoot, projectKey, runtimeRoot, statePath, } from './paths.js';
|
|
8
|
+
export function hash(value) {
|
|
9
|
+
return createHash('sha256').update(value).digest('hex');
|
|
10
|
+
}
|
|
11
|
+
export function managedBlockBytes(content, marker = 'runtime') {
|
|
12
|
+
const text = Buffer.isBuffer(content) ? content.toString('utf8') : content;
|
|
13
|
+
const begin = `<!-- ##planr-${marker}:begin##`;
|
|
14
|
+
const end = `<!-- ##planr-${marker}:end## -->`;
|
|
15
|
+
const start = text.indexOf(begin);
|
|
16
|
+
const finish = text.indexOf(end, start);
|
|
17
|
+
if (start === -1 || finish === -1)
|
|
18
|
+
return Buffer.alloc(0);
|
|
19
|
+
return Buffer.from(text.slice(start, finish + end.length));
|
|
20
|
+
}
|
|
21
|
+
export function ownershipHash(content, kind, marker) {
|
|
22
|
+
return hash(kind === 'managed-block' ? managedBlockBytes(content, marker) : content);
|
|
23
|
+
}
|
|
24
|
+
export function assertApprovedTargetCustody(target, approvedRoot, anchor, code, label) {
|
|
25
|
+
const selected = path.resolve(target);
|
|
26
|
+
const root = path.resolve(approvedRoot);
|
|
27
|
+
const boundary = path.resolve(anchor);
|
|
28
|
+
if (!pathIsWithin(selected, root) || !pathIsWithin(root, boundary)) {
|
|
29
|
+
throw new RuntimeManagerError(code, `${label} target ${selected} leaves its approved root ${root}.`, 'Restore valid runtime ownership state and keep managed targets inside the exact approved bundle root.');
|
|
30
|
+
}
|
|
31
|
+
let canonicalBoundary;
|
|
32
|
+
try {
|
|
33
|
+
const boundaryMetadata = lstatSync(boundary);
|
|
34
|
+
if (boundaryMetadata.isSymbolicLink() || !boundaryMetadata.isDirectory())
|
|
35
|
+
throw new Error('invalid boundary');
|
|
36
|
+
canonicalBoundary = realpathSync(boundary);
|
|
37
|
+
}
|
|
38
|
+
catch (cause) {
|
|
39
|
+
if (cause.code === 'ENOENT')
|
|
40
|
+
return;
|
|
41
|
+
throw new RuntimeManagerError(code, `${label} boundary ${boundary} is unavailable, non-directory, or symbolic.`, 'Use one real user/project root and replace symbolic managed-root parents before retrying.');
|
|
42
|
+
}
|
|
43
|
+
let current = boundary;
|
|
44
|
+
const segments = path.relative(boundary, selected).split(path.sep).filter(Boolean);
|
|
45
|
+
for (const [index, segment] of segments.entries()) {
|
|
46
|
+
current = path.join(current, segment);
|
|
47
|
+
let metadata;
|
|
48
|
+
try {
|
|
49
|
+
metadata = lstatSync(current);
|
|
50
|
+
}
|
|
51
|
+
catch (cause) {
|
|
52
|
+
if (cause.code === 'ENOENT')
|
|
53
|
+
return;
|
|
54
|
+
throw cause;
|
|
55
|
+
}
|
|
56
|
+
if (metadata.isSymbolicLink()) {
|
|
57
|
+
throw new RuntimeManagerError(code, `${label} target ${selected} traverses symbolic component ${current}.`, 'Replace symbolic managed-root parents with real directories before retrying.');
|
|
58
|
+
}
|
|
59
|
+
const isLeaf = index === segments.length - 1;
|
|
60
|
+
if (!isLeaf && !metadata.isDirectory()) {
|
|
61
|
+
throw new RuntimeManagerError(code, `${label} target ${selected} traverses non-directory component ${current}.`, 'Repair the managed bundle root before retrying.');
|
|
62
|
+
}
|
|
63
|
+
const canonical = realpathSync(current);
|
|
64
|
+
if (canonical !== canonicalBoundary &&
|
|
65
|
+
!canonical.startsWith(`${canonicalBoundary}${path.sep}`)) {
|
|
66
|
+
throw new RuntimeManagerError(code, `${label} target ${selected} escapes its canonical boundary.`, 'Repair the managed bundle root before retrying.');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export function assertMutableOwnedTarget(target, projectDir, code) {
|
|
71
|
+
if (pathIsWithin(target, runtimeRoot())) {
|
|
72
|
+
assertApprovedTargetCustody(target, runtimeRoot(), planrCustodyAnchor(), code, 'Global runtime ownership');
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (pathIsWithin(target, codexSkillsRoot())) {
|
|
76
|
+
assertApprovedTargetCustody(target, codexSkillsRoot(), effectiveCodexHome(), code, 'Global Codex bundle ownership');
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (pathIsWithin(target, projectDir)) {
|
|
80
|
+
assertApprovedTargetCustody(target, projectDir, projectDir, code, 'Project runtime ownership');
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
throw new RuntimeManagerError(code, `Managed mutation target ${path.resolve(target)} is outside every approved runtime root.`, 'Restore a valid ownership/backup manifest before retrying.');
|
|
84
|
+
}
|
|
85
|
+
export function assertBackupDirectoryCustody(selected, projectDir, code, requireExisting = false) {
|
|
86
|
+
const directory = path.resolve(selected);
|
|
87
|
+
const approvedRoot = path.resolve(projectBackupsRoot(projectDir));
|
|
88
|
+
if (path.dirname(directory) !== approvedRoot) {
|
|
89
|
+
throw new RuntimeManagerError(code, `Runtime backup ${directory} is not one direct child of ${approvedRoot}.`, 'Select only the exact project backup created by OpenPlanr.');
|
|
90
|
+
}
|
|
91
|
+
assertApprovedTargetCustody(directory, approvedRoot, planrCustodyAnchor(), code, 'Runtime backup');
|
|
92
|
+
if (requireExisting) {
|
|
93
|
+
let metadata;
|
|
94
|
+
try {
|
|
95
|
+
metadata = lstatSync(directory);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
throw new RuntimeManagerError(code, `Runtime backup ${directory} is unavailable.`);
|
|
99
|
+
}
|
|
100
|
+
if (metadata.isSymbolicLink() || !metadata.isDirectory()) {
|
|
101
|
+
throw new RuntimeManagerError(code, `Runtime backup ${directory} is not one real directory.`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return directory;
|
|
105
|
+
}
|
|
106
|
+
function backupEntryPath(directory, index, target) {
|
|
107
|
+
return path.join(directory, 'files', `${String(index).padStart(3, '0')}-${path.basename(target)}`);
|
|
108
|
+
}
|
|
109
|
+
export function backupManifestIdentity(manifest) {
|
|
110
|
+
return `sha256:${hash(JSON.stringify({
|
|
111
|
+
schemaVersion: manifest.schemaVersion,
|
|
112
|
+
projectDir: manifest.projectDir,
|
|
113
|
+
createdAt: manifest.createdAt,
|
|
114
|
+
files: manifest.files.map(({ target, backup, existed, beforeHash, afterHash }) => ({
|
|
115
|
+
target,
|
|
116
|
+
existed,
|
|
117
|
+
...(backup ? { backup } : {}),
|
|
118
|
+
...(beforeHash ? { beforeHash } : {}),
|
|
119
|
+
...(path.resolve(target) === path.resolve(statePath())
|
|
120
|
+
? {}
|
|
121
|
+
: { expectedAfterHash: afterHash ?? null }),
|
|
122
|
+
})),
|
|
123
|
+
}))}`;
|
|
124
|
+
}
|
|
125
|
+
export function assertClosedBackupManifest(value, directory, projectDir, code, requireFinalStateHash = false) {
|
|
126
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
127
|
+
throw new RuntimeManagerError(code, 'Runtime backup manifest is not one closed object.');
|
|
128
|
+
}
|
|
129
|
+
const manifest = value;
|
|
130
|
+
if (JSON.stringify(Object.keys(manifest).sort()) !==
|
|
131
|
+
JSON.stringify(['createdAt', 'files', 'projectDir', 'schemaVersion']) ||
|
|
132
|
+
manifest.schemaVersion !== '1.0.0' ||
|
|
133
|
+
typeof manifest.projectDir !== 'string' ||
|
|
134
|
+
canonicalProjectPath(manifest.projectDir) !== canonicalProjectPath(projectDir) ||
|
|
135
|
+
typeof manifest.createdAt !== 'string' ||
|
|
136
|
+
manifest.createdAt.length > 64 ||
|
|
137
|
+
Number.isNaN(Date.parse(manifest.createdAt)) ||
|
|
138
|
+
!Array.isArray(manifest.files) ||
|
|
139
|
+
manifest.files.length > 10_000) {
|
|
140
|
+
throw new RuntimeManagerError(code, 'Runtime backup manifest identity is invalid.');
|
|
141
|
+
}
|
|
142
|
+
const seenTargets = new Set();
|
|
143
|
+
const files = manifest.files.map((candidate, index) => {
|
|
144
|
+
if (candidate === null || typeof candidate !== 'object' || Array.isArray(candidate)) {
|
|
145
|
+
throw new RuntimeManagerError(code, 'Runtime backup manifest contains a non-object entry.');
|
|
146
|
+
}
|
|
147
|
+
const entry = candidate;
|
|
148
|
+
const keys = Object.keys(entry).sort();
|
|
149
|
+
if (keys.some((key) => !['afterHash', 'backup', 'beforeHash', 'existed', 'target'].includes(key)) ||
|
|
150
|
+
!keys.includes('existed') ||
|
|
151
|
+
!keys.includes('target') ||
|
|
152
|
+
typeof entry.target !== 'string' ||
|
|
153
|
+
path.resolve(entry.target) !== entry.target ||
|
|
154
|
+
typeof entry.existed !== 'boolean' ||
|
|
155
|
+
(entry.afterHash !== undefined &&
|
|
156
|
+
(typeof entry.afterHash !== 'string' || !/^[a-f0-9]{64}$/u.test(entry.afterHash)))) {
|
|
157
|
+
throw new RuntimeManagerError(code, 'Runtime backup manifest entry is invalid.');
|
|
158
|
+
}
|
|
159
|
+
assertMutableOwnedTarget(entry.target, projectDir, code);
|
|
160
|
+
if (seenTargets.has(entry.target)) {
|
|
161
|
+
throw new RuntimeManagerError(code, `Runtime backup repeats target ${entry.target}.`);
|
|
162
|
+
}
|
|
163
|
+
seenTargets.add(entry.target);
|
|
164
|
+
if (entry.existed) {
|
|
165
|
+
const expected = backupEntryPath(directory, index, entry.target);
|
|
166
|
+
if (typeof entry.backup !== 'string' ||
|
|
167
|
+
path.resolve(entry.backup) !== expected ||
|
|
168
|
+
typeof entry.beforeHash !== 'string' ||
|
|
169
|
+
!/^[a-f0-9]{64}$/u.test(entry.beforeHash)) {
|
|
170
|
+
throw new RuntimeManagerError(code, `Runtime backup source for ${entry.target} is not exactly bound to its manifest slot.`);
|
|
171
|
+
}
|
|
172
|
+
assertApprovedTargetCustody(entry.backup, path.join(directory, 'files'), directory, code, 'Runtime backup file');
|
|
173
|
+
}
|
|
174
|
+
else if (entry.backup !== undefined || entry.beforeHash !== undefined) {
|
|
175
|
+
throw new RuntimeManagerError(code, `Runtime backup records bytes for absent target ${entry.target}.`);
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
target: entry.target,
|
|
179
|
+
existed: entry.existed,
|
|
180
|
+
...(typeof entry.backup === 'string' ? { backup: entry.backup } : {}),
|
|
181
|
+
...(typeof entry.beforeHash === 'string' ? { beforeHash: entry.beforeHash } : {}),
|
|
182
|
+
...(typeof entry.afterHash === 'string' ? { afterHash: entry.afterHash } : {}),
|
|
183
|
+
};
|
|
184
|
+
});
|
|
185
|
+
const stateEntries = files.filter((entry) => path.resolve(entry.target) === path.resolve(statePath()));
|
|
186
|
+
if (files.length === 0 || stateEntries.length !== 1) {
|
|
187
|
+
throw new RuntimeManagerError(code, 'Runtime backup manifest must bind exactly one global ownership-state target.');
|
|
188
|
+
}
|
|
189
|
+
const [stateEntry] = stateEntries;
|
|
190
|
+
if ((requireFinalStateHash && !stateEntry.afterHash) ||
|
|
191
|
+
(!stateEntry.existed && files.every((entry) => entry === stateEntry))) {
|
|
192
|
+
throw new RuntimeManagerError(code, 'Runtime backup manifest does not bind one complete setup transition.');
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
schemaVersion: '1.0.0',
|
|
196
|
+
projectDir: manifest.projectDir,
|
|
197
|
+
createdAt: manifest.createdAt,
|
|
198
|
+
files,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
export function assertClosedBackupTree(directory, manifest, projectDir, code) {
|
|
202
|
+
assertBackupDirectoryCustody(directory, projectDir, code, true);
|
|
203
|
+
const expectedFiles = new Set([
|
|
204
|
+
path.join(directory, 'migration-manifest.json'),
|
|
205
|
+
...manifest.files.flatMap((entry) => (entry.backup ? [entry.backup] : [])),
|
|
206
|
+
].map((entry) => path.resolve(entry)));
|
|
207
|
+
const actualFiles = new Set();
|
|
208
|
+
const walk = (current) => {
|
|
209
|
+
assertApprovedTargetCustody(current, directory, planrCustodyAnchor(), code, 'Runtime backup tree');
|
|
210
|
+
for (const entry of readdirSync(current, { withFileTypes: true })) {
|
|
211
|
+
const absolute = path.join(current, entry.name);
|
|
212
|
+
const metadata = lstatSync(absolute);
|
|
213
|
+
if (metadata.isSymbolicLink() || (!metadata.isDirectory() && !metadata.isFile())) {
|
|
214
|
+
throw new RuntimeManagerError(code, `Runtime backup tree contains an unsupported entry at ${absolute}.`);
|
|
215
|
+
}
|
|
216
|
+
if (metadata.isDirectory())
|
|
217
|
+
walk(absolute);
|
|
218
|
+
else
|
|
219
|
+
actualFiles.add(path.resolve(absolute));
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
walk(directory);
|
|
223
|
+
if (actualFiles.size !== expectedFiles.size ||
|
|
224
|
+
[...actualFiles].some((entry) => !expectedFiles.has(entry))) {
|
|
225
|
+
throw new RuntimeManagerError(code, 'Runtime backup tree does not exactly match its closed manifest.');
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
export async function readCustodiedRegularFile(target, custody, code, label, maxBytes = 64 * 1024 * 1024) {
|
|
229
|
+
custody();
|
|
230
|
+
let handle;
|
|
231
|
+
try {
|
|
232
|
+
handle = await open(target, fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0));
|
|
233
|
+
}
|
|
234
|
+
catch (cause) {
|
|
235
|
+
throw new RuntimeManagerError(code, `${label} ${target} cannot be opened as a real file: ${cause instanceof Error ? cause.message : String(cause)}`);
|
|
236
|
+
}
|
|
237
|
+
try {
|
|
238
|
+
const metadata = await handle.stat();
|
|
239
|
+
if (!metadata.isFile() || metadata.size > maxBytes) {
|
|
240
|
+
throw new RuntimeManagerError(code, `${label} ${target} is not one bounded regular file.`);
|
|
241
|
+
}
|
|
242
|
+
const bytes = await handle.readFile();
|
|
243
|
+
custody();
|
|
244
|
+
return bytes;
|
|
245
|
+
}
|
|
246
|
+
finally {
|
|
247
|
+
await handle.close();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
export async function readBackupEntryBytes(directory, entry, _projectDir, code) {
|
|
251
|
+
if (!entry.backup || !entry.beforeHash) {
|
|
252
|
+
throw new RuntimeManagerError(code, `Runtime backup for ${entry.target} has no byte custody.`);
|
|
253
|
+
}
|
|
254
|
+
const bytes = await readCustodiedRegularFile(entry.backup, () => assertApprovedTargetCustody(entry.backup, path.join(directory, 'files'), directory, code, 'Runtime backup file'), code, 'Runtime backup file');
|
|
255
|
+
if (hash(bytes) !== entry.beforeHash) {
|
|
256
|
+
throw new RuntimeManagerError(code, `Runtime backup bytes for ${entry.target} do not match their recorded hash.`);
|
|
257
|
+
}
|
|
258
|
+
return bytes;
|
|
259
|
+
}
|
|
260
|
+
export function assertUserOwnedTarget(file, runtime, code = 'E_RUNTIME_STATE_INVALID', nativeHome = effectiveCodexHome()) {
|
|
261
|
+
const approvedRoot = runtime === 'codex' ? codexRuntimeRoot(nativeHome) : runtimeRoot();
|
|
262
|
+
if (runtime === 'codex'
|
|
263
|
+
? codexBookkeepingTarget(file.target, nativeHome)
|
|
264
|
+
: pathIsWithin(file.target, approvedRoot)) {
|
|
265
|
+
assertApprovedTargetCustody(file.target, approvedRoot, planrCustodyAnchor(), code, 'Global runtime ownership');
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
if (runtime === 'codex' && pathIsWithin(file.target, path.join(nativeHome, 'skills'))) {
|
|
269
|
+
assertApprovedTargetCustody(file.target, path.join(nativeHome, 'skills'), nativeHome, code, 'Global Codex bundle ownership');
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
throw new RuntimeManagerError(code, `Global ${runtime} ownership target ${path.resolve(file.target)} is outside every approved bundle root.`, 'Restore valid global ownership state before setup, rollback, retirement, or removal.');
|
|
273
|
+
}
|
|
274
|
+
export function assertActionCustody(actions, projectDir) {
|
|
275
|
+
for (const action of actions) {
|
|
276
|
+
if (action.scope === 'user') {
|
|
277
|
+
assertUserOwnedTarget(action, action.runtime, 'E_MIGRATION_CONFLICT');
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
assertApprovedTargetCustody(action.target, projectDir, projectDir, 'E_MIGRATION_CONFLICT', 'Project runtime ownership');
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
function assertRuntimeStateCustody(state, nativeHome = effectiveCodexHome()) {
|
|
285
|
+
for (const runtime of ['claude-code', 'codex', 'cursor']) {
|
|
286
|
+
for (const file of state.userBundles?.[runtime]?.ownedFiles ?? []) {
|
|
287
|
+
assertUserOwnedTarget(file, runtime, 'E_RUNTIME_STATE_INVALID', nativeHome);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
for (const project of Object.values(state.projects)) {
|
|
291
|
+
for (const file of project.ownedFiles) {
|
|
292
|
+
const runtime = file.runtime;
|
|
293
|
+
if (file.scope === 'user' || (runtime !== 'core' && isUserOwnedFile(file, runtime))) {
|
|
294
|
+
assertUserOwnedTarget(file, runtime, 'E_RUNTIME_STATE_INVALID', nativeHome);
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
assertApprovedTargetCustody(file.target, project.projectDir, project.projectDir, 'E_RUNTIME_STATE_INVALID', 'Project runtime ownership');
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
export function assertRuntimeStateValue(value, code = 'E_RUNTIME_STATE_INVALID', allowLegacyProjectKeys = false, nativeHome = effectiveCodexHome(), inspectCustody = true) {
|
|
303
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
304
|
+
throw new RuntimeManagerError(code, 'Runtime ownership state is not one closed object.');
|
|
305
|
+
}
|
|
306
|
+
const state = value;
|
|
307
|
+
if (Object.keys(state).some((key) => !['projects', 'schemaVersion', 'userBundles', 'codexProfiles'].includes(key)) ||
|
|
308
|
+
!['1.0.0', '2.0.0'].includes(String(state.schemaVersion)) ||
|
|
309
|
+
state.projects === null ||
|
|
310
|
+
typeof state.projects !== 'object' ||
|
|
311
|
+
Array.isArray(state.projects) ||
|
|
312
|
+
(state.userBundles !== undefined &&
|
|
313
|
+
(state.userBundles === null ||
|
|
314
|
+
typeof state.userBundles !== 'object' ||
|
|
315
|
+
Array.isArray(state.userBundles)))) {
|
|
316
|
+
throw new RuntimeManagerError(code, 'Runtime ownership state identity is invalid.');
|
|
317
|
+
}
|
|
318
|
+
const legacyProjectKeysAllowed = allowLegacyProjectKeys && state.schemaVersion === '1.0.0';
|
|
319
|
+
const runtimeIds = new Set(['claude-code', 'codex', 'cursor']);
|
|
320
|
+
const assertOwnedFile = (candidate) => {
|
|
321
|
+
if (candidate === null || typeof candidate !== 'object' || Array.isArray(candidate))
|
|
322
|
+
return false;
|
|
323
|
+
const file = candidate;
|
|
324
|
+
return (Object.keys(file).every((key) => ['hash', 'kind', 'marker', 'runtime', 'scope', 'target'].includes(key)) &&
|
|
325
|
+
['claude-code', 'codex', 'core', 'cursor'].includes(String(file.runtime)) &&
|
|
326
|
+
['file', 'managed-block'].includes(String(file.kind)) &&
|
|
327
|
+
(file.scope === undefined || ['user', 'project'].includes(String(file.scope))) &&
|
|
328
|
+
(file.marker === undefined || typeof file.marker === 'string') &&
|
|
329
|
+
typeof file.target === 'string' &&
|
|
330
|
+
path.resolve(file.target) === file.target &&
|
|
331
|
+
typeof file.hash === 'string' &&
|
|
332
|
+
/^[a-f0-9]{64}$/u.test(file.hash));
|
|
333
|
+
};
|
|
334
|
+
const canonicalProjects = new Set();
|
|
335
|
+
for (const [key, project] of Object.entries(state.projects)) {
|
|
336
|
+
if (project === null || typeof project !== 'object' || Array.isArray(project)) {
|
|
337
|
+
throw new RuntimeManagerError(code, 'Runtime project ownership record is invalid.');
|
|
338
|
+
}
|
|
339
|
+
const record = project;
|
|
340
|
+
const canonicalProject = typeof record.projectDir === 'string' ? canonicalProjectPath(record.projectDir) : '';
|
|
341
|
+
if (Object.keys(record).some((key) => ![
|
|
342
|
+
'activeRuntime',
|
|
343
|
+
'backupDir',
|
|
344
|
+
'backupManifestHash',
|
|
345
|
+
'commandPrefix',
|
|
346
|
+
'codexHome',
|
|
347
|
+
'ownedFiles',
|
|
348
|
+
'projectDir',
|
|
349
|
+
'runtimeScopes',
|
|
350
|
+
'runtimes',
|
|
351
|
+
'skillModes',
|
|
352
|
+
'updatedAt',
|
|
353
|
+
].includes(key)) ||
|
|
354
|
+
typeof record.projectDir !== 'string' ||
|
|
355
|
+
path.resolve(record.projectDir) !== record.projectDir ||
|
|
356
|
+
(!legacyProjectKeysAllowed && key !== projectKey(canonicalProject)) ||
|
|
357
|
+
canonicalProjects.has(canonicalProject) ||
|
|
358
|
+
typeof record.updatedAt !== 'string' ||
|
|
359
|
+
(record.codexHome !== undefined &&
|
|
360
|
+
(typeof record.codexHome !== 'string' ||
|
|
361
|
+
path.resolve(record.codexHome) !== record.codexHome)) ||
|
|
362
|
+
!Array.isArray(record.runtimes) ||
|
|
363
|
+
record.runtimes.some((runtime) => !runtimeIds.has(runtime)) ||
|
|
364
|
+
!Array.isArray(record.ownedFiles) ||
|
|
365
|
+
record.ownedFiles.some((file) => !assertOwnedFile(file)) ||
|
|
366
|
+
(record.backupDir !== undefined && typeof record.backupDir !== 'string') ||
|
|
367
|
+
(record.backupManifestHash !== undefined &&
|
|
368
|
+
(typeof record.backupManifestHash !== 'string' ||
|
|
369
|
+
!/^sha256:[a-f0-9]{64}$/u.test(record.backupManifestHash))) ||
|
|
370
|
+
(record.commandPrefix !== undefined &&
|
|
371
|
+
!['bare', 'namespaced'].includes(String(record.commandPrefix))) ||
|
|
372
|
+
(record.skillModes !== undefined &&
|
|
373
|
+
(record.skillModes === null ||
|
|
374
|
+
typeof record.skillModes !== 'object' ||
|
|
375
|
+
Array.isArray(record.skillModes) ||
|
|
376
|
+
Object.entries(record.skillModes).some(([runtime, mode]) => !runtimeIds.has(runtime) ||
|
|
377
|
+
!['direct', 'unified-plugin', 'project-rule'].includes(String(mode))))) ||
|
|
378
|
+
(record.activeRuntime !== undefined && !runtimeIds.has(record.activeRuntime))) {
|
|
379
|
+
throw new RuntimeManagerError(code, 'Runtime project ownership record is invalid.');
|
|
380
|
+
}
|
|
381
|
+
canonicalProjects.add(canonicalProject);
|
|
382
|
+
}
|
|
383
|
+
const bundles = (state.userBundles ?? {});
|
|
384
|
+
if (Object.keys(bundles).some((runtime) => !runtimeIds.has(runtime))) {
|
|
385
|
+
throw new RuntimeManagerError(code, 'Runtime global ownership bundle identity is invalid.');
|
|
386
|
+
}
|
|
387
|
+
for (const [runtime, candidate] of Object.entries(bundles)) {
|
|
388
|
+
if (candidate === null || typeof candidate !== 'object' || Array.isArray(candidate)) {
|
|
389
|
+
throw new RuntimeManagerError(code, 'Runtime global ownership bundle is invalid.');
|
|
390
|
+
}
|
|
391
|
+
const bundle = candidate;
|
|
392
|
+
if (Object.keys(bundle).some((key) => ![
|
|
393
|
+
'commandPrefix',
|
|
394
|
+
'installMode',
|
|
395
|
+
'ownedFiles',
|
|
396
|
+
'pipelineVersion',
|
|
397
|
+
'runtime',
|
|
398
|
+
'scope',
|
|
399
|
+
'updatedAt',
|
|
400
|
+
].includes(key)) ||
|
|
401
|
+
bundle.runtime !== runtime ||
|
|
402
|
+
bundle.scope !== 'user' ||
|
|
403
|
+
typeof bundle.updatedAt !== 'string' ||
|
|
404
|
+
typeof bundle.pipelineVersion !== 'string' ||
|
|
405
|
+
!['bare', 'namespaced'].includes(String(bundle.commandPrefix)) ||
|
|
406
|
+
(bundle.installMode !== undefined &&
|
|
407
|
+
!['direct', 'unified-plugin', 'project-rule'].includes(String(bundle.installMode))) ||
|
|
408
|
+
!Array.isArray(bundle.ownedFiles) ||
|
|
409
|
+
bundle.ownedFiles.some((file) => !assertOwnedFile(file)) ||
|
|
410
|
+
(runtime === 'codex' &&
|
|
411
|
+
bundle.ownedFiles.some((file) => {
|
|
412
|
+
const target = file.target;
|
|
413
|
+
return (!codexBookkeepingTarget(target, nativeHome) &&
|
|
414
|
+
!pathIsWithin(target, path.join(nativeHome, 'skills')));
|
|
415
|
+
}))) {
|
|
416
|
+
throw new RuntimeManagerError(code, 'Runtime global ownership bundle is invalid.');
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
if (state.codexProfiles !== undefined) {
|
|
420
|
+
if (!state.codexProfiles ||
|
|
421
|
+
typeof state.codexProfiles !== 'object' ||
|
|
422
|
+
Array.isArray(state.codexProfiles))
|
|
423
|
+
throw new RuntimeManagerError(code, 'Codex profile ownership is invalid.');
|
|
424
|
+
for (const [key, candidate] of Object.entries(state.codexProfiles)) {
|
|
425
|
+
if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate))
|
|
426
|
+
throw new RuntimeManagerError(code, 'Codex profile ownership is invalid.');
|
|
427
|
+
const profile = candidate;
|
|
428
|
+
if (Object.keys(profile).some((field) => !['home', 'bundle'].includes(field)) ||
|
|
429
|
+
typeof profile.home !== 'string' ||
|
|
430
|
+
path.resolve(profile.home) !== profile.home ||
|
|
431
|
+
hash(profile.home).slice(0, 16) !== key)
|
|
432
|
+
throw new RuntimeManagerError(code, 'Codex profile identity is invalid.');
|
|
433
|
+
// Decode every record, but only inspect the selected native home's filesystem.
|
|
434
|
+
if (profile.bundle !== undefined)
|
|
435
|
+
assertRuntimeStateValue({ schemaVersion: '2.0.0', projects: {}, userBundles: { codex: profile.bundle } }, code, false, profile.home, profile.home === effectiveCodexHome());
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
const decoded = value;
|
|
439
|
+
if (inspectCustody)
|
|
440
|
+
assertRuntimeStateCustody(decoded, nativeHome);
|
|
441
|
+
return decoded;
|
|
442
|
+
}
|
|
443
|
+
export function isUserOwnedFile(file, runtime, nativeHome = effectiveCodexHome()) {
|
|
444
|
+
if (file.scope)
|
|
445
|
+
return file.scope === 'user';
|
|
446
|
+
if (pathIsWithin(file.target, runtimeRoot()))
|
|
447
|
+
return true;
|
|
448
|
+
return runtime === 'codex' && pathIsWithin(file.target, path.join(nativeHome, 'skills'));
|
|
449
|
+
}
|
|
450
|
+
export function assertRequestedProjectBinding(projectDir, key, project) {
|
|
451
|
+
const canonical = canonicalProjectPath(projectDir);
|
|
452
|
+
if (key !== projectKey(canonical) || canonicalProjectPath(project.projectDir) !== canonical) {
|
|
453
|
+
throw new RuntimeManagerError('E_RUNTIME_STATE_INVALID', 'Runtime ownership state is bound to a different canonical project.', 'Repair the project ownership record before preview, rollback, removal, or cleanup.');
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
/** Preserve modified or unknown professional project assets for every coding agent. */
|
|
457
|
+
export function assertProfessionalSkillTransition(state, projectDir, actions) {
|
|
458
|
+
const desired = actions.filter((action) => action.scope === 'project' && action.custody === 'professional-skill');
|
|
459
|
+
if (desired.length === 0)
|
|
460
|
+
return;
|
|
461
|
+
const tracked = new Map((state.projects[projectKey(projectDir)]?.ownedFiles ?? []).map((file) => [
|
|
462
|
+
path.resolve(file.target),
|
|
463
|
+
file,
|
|
464
|
+
]));
|
|
465
|
+
for (const action of desired) {
|
|
466
|
+
assertMutableOwnedTarget(action.target, projectDir, 'E_MIGRATION_CONFLICT');
|
|
467
|
+
if (!existsSync(action.target))
|
|
468
|
+
continue;
|
|
469
|
+
const metadata = lstatSync(action.target);
|
|
470
|
+
if (metadata.isSymbolicLink() || !metadata.isFile()) {
|
|
471
|
+
throw new RuntimeManagerError('E_MIGRATION_CONFLICT', `Refusing to replace non-file professional skill target ${action.target}.`, 'Preserve or move the existing entry outside the managed skill directory before rerunning setup.');
|
|
472
|
+
}
|
|
473
|
+
const currentHash = ownershipHash(readFileSync(action.target), action.kind, action.marker);
|
|
474
|
+
const owned = tracked.get(path.resolve(action.target));
|
|
475
|
+
if (owned) {
|
|
476
|
+
if (currentHash !== owned.hash) {
|
|
477
|
+
throw new RuntimeManagerError('E_MIGRATION_CONFLICT', `Refusing to replace modified managed professional skill ${action.target}.`, 'Preserve the modified file or restore the last managed bytes before rerunning setup.');
|
|
478
|
+
}
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
const expectedHash = ownershipHash(actionBytes(action), action.kind, action.marker);
|
|
482
|
+
if (currentHash !== expectedHash) {
|
|
483
|
+
throw new RuntimeManagerError('E_MIGRATION_CONFLICT', `Refusing to overwrite unknown Cursor professional skill bytes at ${action.target}.`, 'Move the user-owned file aside or explicitly reconcile it before rerunning setup.');
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
export async function atomicWrite(target, content, verifyCurrent) {
|
|
488
|
+
await mkdir(path.dirname(target), { recursive: true });
|
|
489
|
+
verifyCurrent?.();
|
|
490
|
+
const stagedPackage = immutableRuntimeTarget(target);
|
|
491
|
+
const stagingRoot = path.join(runtimeRoot(), 'setup-staging');
|
|
492
|
+
if (stagedPackage) {
|
|
493
|
+
assertApprovedTargetCustody(stagingRoot, runtimeRoot(), planrCustodyAnchor(), 'E_MIGRATION_CONFLICT', 'Runtime package staging');
|
|
494
|
+
await mkdir(stagingRoot, { recursive: true });
|
|
495
|
+
}
|
|
496
|
+
const temp = stagedPackage
|
|
497
|
+
? path.join(stagingRoot, `${randomUUID()}.tmp`)
|
|
498
|
+
: `${target}.${process.pid}.tmp`;
|
|
499
|
+
const verifyStaging = () => {
|
|
500
|
+
if (stagedPackage)
|
|
501
|
+
assertApprovedTargetCustody(temp, runtimeRoot(), planrCustodyAnchor(), 'E_MIGRATION_CONFLICT', 'Runtime package staging');
|
|
502
|
+
};
|
|
503
|
+
let staged = false;
|
|
504
|
+
try {
|
|
505
|
+
verifyStaging();
|
|
506
|
+
await writeFile(temp, content, { mode: 0o600, flag: 'wx' });
|
|
507
|
+
staged = true;
|
|
508
|
+
verifyCurrent?.();
|
|
509
|
+
verifyStaging();
|
|
510
|
+
await rename(temp, target);
|
|
511
|
+
staged = false;
|
|
512
|
+
}
|
|
513
|
+
finally {
|
|
514
|
+
if (staged) {
|
|
515
|
+
verifyStaging();
|
|
516
|
+
await unlink(temp);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
/** Immutable packages are retained beyond discovery rollback, including pins held by other projects or runs. */
|
|
521
|
+
export function immutableRuntimeTarget(target) {
|
|
522
|
+
return pathIsWithin(target, path.join(runtimeRoot(), 'packages'));
|
|
523
|
+
}
|
|
524
|
+
export async function createBackup(projectDir, actions) {
|
|
525
|
+
const stamp = new Date().toISOString().replaceAll(':', '-');
|
|
526
|
+
const dir = assertBackupDirectoryCustody(path.join(projectBackupsRoot(projectDir), stamp), projectDir, 'E_BACKUP_FAILED');
|
|
527
|
+
const manifest = {
|
|
528
|
+
schemaVersion: '1.0.0',
|
|
529
|
+
projectDir: path.resolve(projectDir),
|
|
530
|
+
createdAt: new Date().toISOString(),
|
|
531
|
+
files: [],
|
|
532
|
+
};
|
|
533
|
+
await mkdir(dir, { recursive: true, mode: 0o700 });
|
|
534
|
+
assertBackupDirectoryCustody(dir, projectDir, 'E_BACKUP_FAILED', true);
|
|
535
|
+
for (const [index, action] of actions.entries()) {
|
|
536
|
+
assertMutableOwnedTarget(action.target, projectDir, 'E_MIGRATION_CONFLICT');
|
|
537
|
+
const entry = { target: action.target, existed: existsSync(action.target) };
|
|
538
|
+
if (entry.existed) {
|
|
539
|
+
const backup = backupEntryPath(dir, index, action.target);
|
|
540
|
+
const bytes = await readCustodiedRegularFile(action.target, () => assertMutableOwnedTarget(action.target, projectDir, 'E_MIGRATION_CONFLICT'), 'E_BACKUP_FAILED', 'Managed setup source');
|
|
541
|
+
assertApprovedTargetCustody(backup, path.join(dir, 'files'), dir, 'E_BACKUP_FAILED', 'Runtime backup file');
|
|
542
|
+
await mkdir(path.dirname(backup), { recursive: true, mode: 0o700 });
|
|
543
|
+
assertApprovedTargetCustody(path.dirname(backup), path.join(dir, 'files'), dir, 'E_BACKUP_FAILED', 'Runtime backup files directory');
|
|
544
|
+
await atomicWrite(backup, bytes);
|
|
545
|
+
assertApprovedTargetCustody(backup, path.join(dir, 'files'), dir, 'E_BACKUP_FAILED', 'Runtime backup file');
|
|
546
|
+
entry.backup = backup;
|
|
547
|
+
entry.beforeHash = hash(bytes);
|
|
548
|
+
}
|
|
549
|
+
manifest.files.push(entry);
|
|
550
|
+
}
|
|
551
|
+
const manifestPath = path.join(dir, 'migration-manifest.json');
|
|
552
|
+
assertApprovedTargetCustody(manifestPath, dir, planrCustodyAnchor(), 'E_BACKUP_FAILED', 'Runtime backup manifest');
|
|
553
|
+
await atomicWrite(manifestPath, Buffer.from(`${JSON.stringify(manifest, null, 2)}\n`));
|
|
554
|
+
assertClosedBackupTree(dir, assertClosedBackupManifest(manifest, dir, projectDir, 'E_BACKUP_FAILED'), projectDir, 'E_BACKUP_FAILED');
|
|
555
|
+
return { dir, manifest };
|
|
556
|
+
}
|
|
557
|
+
function assertRestoreTargetIdentity(entry, retiredTargets) {
|
|
558
|
+
const present = existsSync(entry.target);
|
|
559
|
+
const currentHash = present ? hash(readFileSync(entry.target)) : undefined;
|
|
560
|
+
const matches = present
|
|
561
|
+
? currentHash === entry.beforeHash || currentHash === entry.afterHash
|
|
562
|
+
: !entry.existed || retiredTargets.has(entry.target);
|
|
563
|
+
if (!matches)
|
|
564
|
+
throw new RuntimeManagerError('E_MIGRATION_CONFLICT', `Concurrent bytes prevent automatic restoration: ${entry.target}.`, 'Your current files were preserved. Compare the retained backup before retrying.');
|
|
565
|
+
}
|
|
566
|
+
export async function restoreBackup(backup, retiredTargets) {
|
|
567
|
+
const directory = assertBackupDirectoryCustody(backup.dir, backup.manifest.projectDir, 'E_RUNTIME_STATE_INVALID', true);
|
|
568
|
+
const manifest = assertClosedBackupManifest(backup.manifest, directory, backup.manifest.projectDir, 'E_RUNTIME_STATE_INVALID');
|
|
569
|
+
assertClosedBackupTree(directory, manifest, backup.manifest.projectDir, 'E_RUNTIME_STATE_INVALID');
|
|
570
|
+
const restoreBytes = new Map();
|
|
571
|
+
for (const entry of manifest.files) {
|
|
572
|
+
assertMutableOwnedTarget(entry.target, manifest.projectDir, 'E_RUNTIME_STATE_INVALID');
|
|
573
|
+
if (immutableRuntimeTarget(entry.target))
|
|
574
|
+
continue;
|
|
575
|
+
assertRestoreTargetIdentity(entry, retiredTargets);
|
|
576
|
+
if (entry.existed) {
|
|
577
|
+
restoreBytes.set(entry.target, await readBackupEntryBytes(directory, entry, manifest.projectDir, 'E_RUNTIME_STATE_INVALID'));
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
const restored = [];
|
|
581
|
+
for (const entry of [...manifest.files].reverse()) {
|
|
582
|
+
if (immutableRuntimeTarget(entry.target))
|
|
583
|
+
continue;
|
|
584
|
+
const verifyCurrent = () => {
|
|
585
|
+
assertMutableOwnedTarget(entry.target, manifest.projectDir, 'E_RUNTIME_STATE_INVALID');
|
|
586
|
+
assertRestoreTargetIdentity(entry, retiredTargets);
|
|
587
|
+
};
|
|
588
|
+
verifyCurrent();
|
|
589
|
+
if (entry.existed && entry.backup) {
|
|
590
|
+
const bytes = restoreBytes.get(entry.target);
|
|
591
|
+
if (!bytes)
|
|
592
|
+
throw new RuntimeManagerError('E_RUNTIME_STATE_INVALID', 'Backup preflight lost validated bytes.');
|
|
593
|
+
await mkdir(path.dirname(entry.target), { recursive: true });
|
|
594
|
+
assertMutableOwnedTarget(entry.target, manifest.projectDir, 'E_RUNTIME_STATE_INVALID');
|
|
595
|
+
await atomicWrite(entry.target, bytes, verifyCurrent);
|
|
596
|
+
}
|
|
597
|
+
else if (existsSync(entry.target)) {
|
|
598
|
+
await unlink(entry.target);
|
|
599
|
+
}
|
|
600
|
+
restored.push(entry.target);
|
|
601
|
+
}
|
|
602
|
+
return restored;
|
|
603
|
+
}
|
|
604
|
+
//# sourceMappingURL=storage.js.map
|