create-principles-disciple 1.121.7 → 1.121.9
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/README.md +13 -1
- package/console/dist/server/config/pd-config-store.d.ts +1 -3
- package/console/dist/server/config/pd-config-store.js +4 -4
- package/console/dist/server/feedback/channels.d.ts +2 -8
- package/console/dist/server/feedback/channels.js +0 -11
- package/console/dist/server/index.js +34 -5
- package/console/dist/server/models/ActivationsConsoleModel.d.ts +28 -1
- package/console/dist/server/models/ActivationsConsoleModel.js +72 -30
- package/console/dist/server/models/GovernanceExperienceCollector.d.ts +28 -0
- package/console/dist/server/models/GovernanceExperienceCollector.js +305 -0
- package/console/dist/server/models/GovernanceProjectionCollector.d.ts +60 -2
- package/console/dist/server/models/GovernanceProjectionCollector.js +323 -285
- package/console/dist/server/models/PrincipleClassifier.d.ts +1 -1
- package/console/dist/server/models/PrincipleClassifier.js +7 -4
- package/console/dist/server/models/PrinciplesConsoleModel.d.ts +2 -1
- package/console/dist/server/models/ReceiptsConsoleModel.d.ts +5 -0
- package/console/dist/server/models/ReceiptsConsoleModel.js +140 -13
- package/console/dist/server/routes/activations.js +1 -1
- package/console/dist/server/routes/failed-tasks.js +28 -11
- package/console/dist/server/routes/governance.d.ts +26 -0
- package/console/dist/server/routes/governance.js +51 -0
- package/console/dist/server/routes/owner-identity.d.ts +31 -0
- package/console/dist/server/routes/owner-identity.js +76 -0
- package/console/dist/server/routes/update-history.d.ts +5 -0
- package/console/dist/server/routes/update-history.js +50 -4
- package/console/dist/server/routes/update.js +186 -32
- package/console/dist/shared/feedback-channel-ids.d.ts +13 -0
- package/console/dist/shared/feedback-channel-ids.js +12 -0
- package/console/dist/shared/feedback-contract.d.ts +46 -0
- package/console/dist/shared/feedback-contract.js +45 -0
- package/console/dist/ui/App.js +1 -1
- package/console/dist/ui/api.d.ts +22 -3
- package/console/dist/ui/api.js +63 -3
- package/console/dist/ui/components/receipts/ReceiptCoverageDisclosure.d.ts +6 -0
- package/console/dist/ui/components/receipts/ReceiptCoverageDisclosure.js +66 -0
- package/console/dist/ui/i18n/en.json +198 -2
- package/console/dist/ui/i18n/zh-CN.json +196 -0
- package/console/dist/ui/pages/activation/ActivationPage.js +14 -2
- package/console/dist/ui/pages/failed-tasks/FailedTasksPage.js +25 -5
- package/console/dist/ui/pages/focus/FocusPage.d.ts +28 -1
- package/console/dist/ui/pages/focus/FocusPage.js +128 -15
- package/console/dist/ui/pages/principles/PrincipleDetailPage.d.ts +30 -0
- package/console/dist/ui/pages/principles/PrincipleDetailPage.js +49 -6
- package/console/dist/ui/pages/settings/SettingsPage.js +67 -2
- package/console/dist/ui/pages/settings/UpdatePage.js +7 -7
- package/console/dist/ui/utils/enum-labels.js +0 -1
- package/console/dist/ui/utils/validators.d.ts +53 -21
- package/console/dist/ui/utils/validators.js +248 -21
- package/console/dist/web/assets/app.css +6 -0
- package/console/dist/web/assets/app.js +2721 -1664
- package/console/package.json +4 -2
- package/core/dist/host/host-adapter.d.ts +1 -1
- package/core/dist/host/host-adapter.d.ts.map +1 -1
- package/core/dist/host/host-adapter.js +1 -0
- package/core/dist/host/host-adapter.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/architecture-regression.test.js +12 -2
- package/core/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/attack-e2e-pipeline-smoke.test.js +1 -1
- package/core/dist/runtime-v2/__tests__/attack-e2e-pipeline-smoke.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/governance-experience.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/governance-experience.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/governance-experience.test.js +300 -0
- package/core/dist/runtime-v2/__tests__/governance-experience.test.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/owner-identity.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/owner-identity.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/owner-identity.test.js +147 -0
- package/core/dist/runtime-v2/__tests__/owner-identity.test.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/product-telemetry-contract.test.d.ts +18 -0
- package/core/dist/runtime-v2/__tests__/product-telemetry-contract.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/product-telemetry-contract.test.js +303 -0
- package/core/dist/runtime-v2/__tests__/product-telemetry-contract.test.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/recovery-actions-log.test.js +40 -0
- package/core/dist/runtime-v2/__tests__/recovery-actions-log.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/status-contract.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/status-contract.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/status-contract.test.js +107 -0
- package/core/dist/runtime-v2/__tests__/status-contract.test.js.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/promotion-evidence-snapshot.test.d.ts +2 -0
- package/core/dist/runtime-v2/activation/__tests__/promotion-evidence-snapshot.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/promotion-evidence-snapshot.test.js +104 -0
- package/core/dist/runtime-v2/activation/__tests__/promotion-evidence-snapshot.test.js.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/promotion-readiness-evaluator.test.js +19 -0
- package/core/dist/runtime-v2/activation/__tests__/promotion-readiness-evaluator.test.js.map +1 -1
- package/core/dist/runtime-v2/activation/__tests__/rulecode-owner-decision-service.test.js +20 -0
- package/core/dist/runtime-v2/activation/__tests__/rulecode-owner-decision-service.test.js.map +1 -1
- package/core/dist/runtime-v2/activation/__tests__/sqlite-activation-safety-store.test.js +40 -0
- package/core/dist/runtime-v2/activation/__tests__/sqlite-activation-safety-store.test.js.map +1 -1
- package/core/dist/runtime-v2/activation/index.d.ts +2 -0
- package/core/dist/runtime-v2/activation/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/index.js +1 -0
- package/core/dist/runtime-v2/activation/index.js.map +1 -1
- package/core/dist/runtime-v2/activation/promotion-evidence-snapshot.d.ts +30 -0
- package/core/dist/runtime-v2/activation/promotion-evidence-snapshot.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/promotion-evidence-snapshot.js +87 -0
- package/core/dist/runtime-v2/activation/promotion-evidence-snapshot.js.map +1 -0
- package/core/dist/runtime-v2/activation/promotion-readiness-evaluator.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/promotion-readiness-evaluator.js +3 -0
- package/core/dist/runtime-v2/activation/promotion-readiness-evaluator.js.map +1 -1
- package/core/dist/runtime-v2/activation/promotion-readiness-reader.d.ts +1 -1
- package/core/dist/runtime-v2/activation/promotion-readiness-reader.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/promotion-readiness-reader.js +2 -2
- package/core/dist/runtime-v2/activation/promotion-readiness-reader.js.map +1 -1
- package/core/dist/runtime-v2/activation/rulecode-owner-decision-service.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/rulecode-owner-decision-service.js +18 -9
- package/core/dist/runtime-v2/activation/rulecode-owner-decision-service.js.map +1 -1
- package/core/dist/runtime-v2/adapter/__tests__/chaos-json-repair.test.js +1 -1
- package/core/dist/runtime-v2/adapter/__tests__/chaos-json-repair.test.js.map +1 -1
- package/core/dist/runtime-v2/adapter/__tests__/json-extractor.test.js +91 -1
- package/core/dist/runtime-v2/adapter/__tests__/json-extractor.test.js.map +1 -1
- package/core/dist/runtime-v2/adapter/__tests__/pi-ai-runtime-adapter.test.js +59 -12
- package/core/dist/runtime-v2/adapter/__tests__/pi-ai-runtime-adapter.test.js.map +1 -1
- package/core/dist/runtime-v2/adapter/__tests__/runtime-config-contract.test.js +10 -9
- package/core/dist/runtime-v2/adapter/__tests__/runtime-config-contract.test.js.map +1 -1
- package/core/dist/runtime-v2/adapter/__tests__/structured-output-repair.test.js +42 -1
- package/core/dist/runtime-v2/adapter/__tests__/structured-output-repair.test.js.map +1 -1
- package/core/dist/runtime-v2/adapter/json-extractor.d.ts +25 -0
- package/core/dist/runtime-v2/adapter/json-extractor.d.ts.map +1 -1
- package/core/dist/runtime-v2/adapter/json-extractor.js +126 -0
- package/core/dist/runtime-v2/adapter/json-extractor.js.map +1 -1
- package/core/dist/runtime-v2/adapter/l2-agent-loop-adapter.d.ts +9 -4
- package/core/dist/runtime-v2/adapter/l2-agent-loop-adapter.d.ts.map +1 -1
- package/core/dist/runtime-v2/adapter/l2-agent-loop-adapter.js +9 -4
- package/core/dist/runtime-v2/adapter/l2-agent-loop-adapter.js.map +1 -1
- package/core/dist/runtime-v2/adapter/output-repair-contract.d.ts +5 -1
- package/core/dist/runtime-v2/adapter/output-repair-contract.d.ts.map +1 -1
- package/core/dist/runtime-v2/adapter/output-repair-contract.js +4 -1
- package/core/dist/runtime-v2/adapter/output-repair-contract.js.map +1 -1
- package/core/dist/runtime-v2/adapter/pi-ai-catalog.d.ts +7 -0
- package/core/dist/runtime-v2/adapter/pi-ai-catalog.d.ts.map +1 -0
- package/core/dist/runtime-v2/adapter/pi-ai-catalog.js +19 -0
- package/core/dist/runtime-v2/adapter/pi-ai-catalog.js.map +1 -0
- package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.d.ts +13 -15
- package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.d.ts.map +1 -1
- package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js +104 -37
- package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js.map +1 -1
- package/core/dist/runtime-v2/adapter/structured-output-repair.d.ts +16 -1
- package/core/dist/runtime-v2/adapter/structured-output-repair.d.ts.map +1 -1
- package/core/dist/runtime-v2/adapter/structured-output-repair.js +38 -6
- package/core/dist/runtime-v2/adapter/structured-output-repair.js.map +1 -1
- package/core/dist/runtime-v2/adapter/tools/diagnostician-tool.d.ts +1 -1
- package/core/dist/runtime-v2/adapter/tools/diagnostician-tool.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/__tests__/pd-config-agent-binding.test.js +8 -9
- package/core/dist/runtime-v2/config/__tests__/pd-config-agent-binding.test.js.map +1 -1
- package/core/dist/runtime-v2/config/__tests__/pd-config-contract.test.js +27 -3
- package/core/dist/runtime-v2/config/__tests__/pd-config-contract.test.js.map +1 -1
- package/core/dist/runtime-v2/config/__tests__/pd-config-principles.test.d.ts +11 -0
- package/core/dist/runtime-v2/config/__tests__/pd-config-principles.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/config/__tests__/pd-config-principles.test.js +93 -0
- package/core/dist/runtime-v2/config/__tests__/pd-config-principles.test.js.map +1 -0
- package/core/dist/runtime-v2/config/__tests__/pd-config-workspace.test.js +41 -0
- package/core/dist/runtime-v2/config/__tests__/pd-config-workspace.test.js.map +1 -1
- package/core/dist/runtime-v2/config/index.d.ts +2 -2
- package/core/dist/runtime-v2/config/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/index.js +2 -0
- package/core/dist/runtime-v2/config/index.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-agent-binding.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-agent-binding.js +4 -13
- package/core/dist/runtime-v2/config/pd-config-agent-binding.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-effective.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-effective.js +14 -7
- package/core/dist/runtime-v2/config/pd-config-effective.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-feature-flags.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-feature-flags.js +5 -12
- package/core/dist/runtime-v2/config/pd-config-feature-flags.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-types.d.ts +8 -0
- package/core/dist/runtime-v2/config/pd-config-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-types.js +2 -0
- package/core/dist/runtime-v2/config/pd-config-types.js.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-validate.d.ts.map +1 -1
- package/core/dist/runtime-v2/config/pd-config-validate.js +48 -3
- package/core/dist/runtime-v2/config/pd-config-validate.js.map +1 -1
- package/core/dist/runtime-v2/core-principles/__tests__/core-axiom-block.test.js +36 -8
- package/core/dist/runtime-v2/core-principles/__tests__/core-axiom-block.test.js.map +1 -1
- package/core/dist/runtime-v2/core-principles/__tests__/core-principle-registry.test.js +36 -12
- package/core/dist/runtime-v2/core-principles/__tests__/core-principle-registry.test.js.map +1 -1
- package/core/dist/runtime-v2/core-principles/core-axiom-block.d.ts +22 -8
- package/core/dist/runtime-v2/core-principles/core-axiom-block.d.ts.map +1 -1
- package/core/dist/runtime-v2/core-principles/core-axiom-block.js +28 -13
- package/core/dist/runtime-v2/core-principles/core-axiom-block.js.map +1 -1
- package/core/dist/runtime-v2/core-principles/core-principle-registry.d.ts +29 -4
- package/core/dist/runtime-v2/core-principles/core-principle-registry.d.ts.map +1 -1
- package/core/dist/runtime-v2/core-principles/core-principle-registry.js +68 -33
- package/core/dist/runtime-v2/core-principles/core-principle-registry.js.map +1 -1
- package/core/dist/runtime-v2/core-principles/index.d.ts +3 -3
- package/core/dist/runtime-v2/core-principles/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/core-principles/index.js +1 -1
- package/core/dist/runtime-v2/core-principles/index.js.map +1 -1
- package/core/dist/runtime-v2/evolution/evolution-types.d.ts +2 -1
- package/core/dist/runtime-v2/evolution/evolution-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/evolution/evolution-types.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/__tests__/anonymous-product-telemetry-flag.test.d.ts +2 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/anonymous-product-telemetry-flag.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/anonymous-product-telemetry-flag.test.js +48 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/anonymous-product-telemetry-flag.test.js.map +1 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/codex-conversation-ingestion-flag.test.d.ts +2 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/codex-conversation-ingestion-flag.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/codex-conversation-ingestion-flag.test.js +46 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/codex-conversation-ingestion-flag.test.js.map +1 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js +86 -31
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-lifecycle.test.d.ts +2 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-lifecycle.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-lifecycle.test.js +83 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-lifecycle.test.js.map +1 -0
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.d.ts +19 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.d.ts.map +1 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js +128 -10
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.d.ts +37 -0
- package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.d.ts.map +1 -0
- package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.js +304 -0
- package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.js.map +1 -0
- package/core/dist/runtime-v2/feature-flags/index.d.ts +4 -2
- package/core/dist/runtime-v2/feature-flags/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/feature-flags/index.js +3 -1
- package/core/dist/runtime-v2/feature-flags/index.js.map +1 -1
- package/core/dist/runtime-v2/governance-experience-contract.d.ts +468 -0
- package/core/dist/runtime-v2/governance-experience-contract.d.ts.map +1 -0
- package/core/dist/runtime-v2/governance-experience-contract.js +208 -0
- package/core/dist/runtime-v2/governance-experience-contract.js.map +1 -0
- package/core/dist/runtime-v2/governance-experience.d.ts +11 -0
- package/core/dist/runtime-v2/governance-experience.d.ts.map +1 -0
- package/core/dist/runtime-v2/governance-experience.js +276 -0
- package/core/dist/runtime-v2/governance-experience.js.map +1 -0
- package/core/dist/runtime-v2/index.d.ts +20 -8
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +20 -6
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/artificer-output-retry-flag.test.js +29 -10
- package/core/dist/runtime-v2/internalization/__tests__/artificer-output-retry-flag.test.js.map +1 -1
- package/core/dist/runtime-v2/owner-identity.d.ts +69 -0
- package/core/dist/runtime-v2/owner-identity.d.ts.map +1 -0
- package/core/dist/runtime-v2/owner-identity.js +179 -0
- package/core/dist/runtime-v2/owner-identity.js.map +1 -0
- package/core/dist/runtime-v2/pain-signal-runtime-factory.d.ts.map +1 -1
- package/core/dist/runtime-v2/pain-signal-runtime-factory.js +2 -3
- package/core/dist/runtime-v2/pain-signal-runtime-factory.js.map +1 -1
- package/core/dist/runtime-v2/product-telemetry/daily-identity.d.ts +70 -0
- package/core/dist/runtime-v2/product-telemetry/daily-identity.d.ts.map +1 -0
- package/core/dist/runtime-v2/product-telemetry/daily-identity.js +89 -0
- package/core/dist/runtime-v2/product-telemetry/daily-identity.js.map +1 -0
- package/core/dist/runtime-v2/product-telemetry/snapshot-contract.d.ts +110 -0
- package/core/dist/runtime-v2/product-telemetry/snapshot-contract.d.ts.map +1 -0
- package/core/dist/runtime-v2/product-telemetry/snapshot-contract.js +250 -0
- package/core/dist/runtime-v2/product-telemetry/snapshot-contract.js.map +1 -0
- package/core/dist/runtime-v2/pruning-read-model.d.ts +2 -1
- package/core/dist/runtime-v2/pruning-read-model.d.ts.map +1 -1
- package/core/dist/runtime-v2/pruning-read-model.js.map +1 -1
- package/core/dist/runtime-v2/receipt-coverage.d.ts +63 -0
- package/core/dist/runtime-v2/receipt-coverage.d.ts.map +1 -0
- package/core/dist/runtime-v2/receipt-coverage.js +19 -0
- package/core/dist/runtime-v2/receipt-coverage.js.map +1 -0
- package/core/dist/runtime-v2/recovery-actions-log.d.ts +7 -0
- package/core/dist/runtime-v2/recovery-actions-log.d.ts.map +1 -1
- package/core/dist/runtime-v2/recovery-actions-log.js +6 -0
- package/core/dist/runtime-v2/recovery-actions-log.js.map +1 -1
- package/core/dist/runtime-v2/runtime-protocol.js +1 -1
- package/core/dist/runtime-v2/runtime-protocol.js.map +1 -1
- package/core/dist/runtime-v2/store/task/__tests__/sqlite-task-store.failed-tasks.test.js +17 -1
- package/core/dist/runtime-v2/store/task/__tests__/sqlite-task-store.failed-tasks.test.js.map +1 -1
- package/core/dist/runtime-v2/store/task/sqlite-task-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/task/sqlite-task-store.js +10 -0
- package/core/dist/runtime-v2/store/task/sqlite-task-store.js.map +1 -1
- package/core/dist/runtime-v2/store/task/task-types.d.ts +2 -0
- package/core/dist/runtime-v2/store/task/task-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/task-status.d.ts +9 -5
- package/core/dist/runtime-v2/task-status.d.ts.map +1 -1
- package/core/dist/runtime-v2/task-status.js +15 -7
- package/core/dist/runtime-v2/task-status.js.map +1 -1
- package/core/dist/runtime-v2/types/event-types.d.ts +4 -0
- package/core/dist/runtime-v2/types/event-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/event-types.js.map +1 -1
- package/core/dist/runtime-v2/types/index.d.ts +1 -1
- package/core/dist/runtime-v2/types/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/index.js +1 -1
- package/core/dist/runtime-v2/types/index.js.map +1 -1
- package/core/dist/runtime-v2/types/principle-enums.d.ts +3 -2
- package/core/dist/runtime-v2/types/principle-enums.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/principle-enums.js +11 -5
- package/core/dist/runtime-v2/types/principle-enums.js.map +1 -1
- package/core/dist/runtime-v2/types/principle-schema.d.ts +1 -1
- package/core/dist/runtime-v2/types/principle-tree-store.d.ts +1 -1
- package/core/dist/runtime-v2/utils/cli-process-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/utils/cli-process-runner.js +3 -2
- package/core/dist/runtime-v2/utils/cli-process-runner.js.map +1 -1
- package/core/package.json +4 -5
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +4 -2
- package/dist/i18n.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +47 -11
- package/dist/index.js.map +1 -1
- package/dist/installer.d.ts +31 -5
- package/dist/installer.d.ts.map +1 -1
- package/dist/installer.js +472 -161
- package/dist/installer.js.map +1 -1
- package/dist/installers/codex-host-installer.d.ts.map +1 -1
- package/dist/installers/codex-host-installer.js +4 -0
- package/dist/installers/codex-host-installer.js.map +1 -1
- package/dist/mvp-config.d.ts +10 -0
- package/dist/mvp-config.d.ts.map +1 -1
- package/dist/mvp-config.js +30 -3
- package/dist/mvp-config.js.map +1 -1
- package/dist/uninstaller.d.ts +9 -1
- package/dist/uninstaller.d.ts.map +1 -1
- package/dist/uninstaller.js +103 -23
- package/dist/uninstaller.js.map +1 -1
- package/dist/update/atomic-file.d.ts +35 -0
- package/dist/update/atomic-file.d.ts.map +1 -0
- package/dist/update/atomic-file.js +120 -0
- package/dist/update/atomic-file.js.map +1 -0
- package/dist/update/bootstrap-protocol.d.ts +55 -0
- package/dist/update/bootstrap-protocol.d.ts.map +1 -0
- package/dist/update/bootstrap-protocol.js +132 -0
- package/dist/update/bootstrap-protocol.js.map +1 -0
- package/dist/update/channel-metadata.d.ts +28 -0
- package/dist/update/channel-metadata.d.ts.map +1 -0
- package/dist/update/channel-metadata.js +90 -0
- package/dist/update/channel-metadata.js.map +1 -0
- package/dist/update/channel-promotion.d.ts +39 -0
- package/dist/update/channel-promotion.d.ts.map +1 -0
- package/dist/update/channel-promotion.js +55 -0
- package/dist/update/channel-promotion.js.map +1 -0
- package/dist/update/data-compatibility.d.ts +35 -0
- package/dist/update/data-compatibility.d.ts.map +1 -0
- package/dist/update/data-compatibility.js +45 -0
- package/dist/update/data-compatibility.js.map +1 -0
- package/dist/update/install-layout.d.ts +59 -0
- package/dist/update/install-layout.d.ts.map +1 -0
- package/dist/update/install-layout.js +127 -0
- package/dist/update/install-layout.js.map +1 -0
- package/dist/update/legacy-migration.d.ts +56 -0
- package/dist/update/legacy-migration.d.ts.map +1 -0
- package/dist/update/legacy-migration.js +254 -0
- package/dist/update/legacy-migration.js.map +1 -0
- package/dist/update/product-identity.d.ts +50 -0
- package/dist/update/product-identity.d.ts.map +1 -0
- package/dist/update/product-identity.js +63 -0
- package/dist/update/product-identity.js.map +1 -0
- package/dist/update/release-asset-manifest.d.ts +31 -0
- package/dist/update/release-asset-manifest.d.ts.map +1 -0
- package/dist/update/release-asset-manifest.js +161 -0
- package/dist/update/release-asset-manifest.js.map +1 -0
- package/dist/update/release-identity.d.ts +33 -0
- package/dist/update/release-identity.d.ts.map +1 -0
- package/dist/update/release-identity.js +108 -0
- package/dist/update/release-identity.js.map +1 -0
- package/dist/update/release-manager.d.ts +96 -0
- package/dist/update/release-manager.d.ts.map +1 -0
- package/dist/update/release-manager.js +253 -0
- package/dist/update/release-manager.js.map +1 -0
- package/dist/update/release-metadata.d.ts +57 -0
- package/dist/update/release-metadata.d.ts.map +1 -0
- package/dist/update/release-metadata.js +200 -0
- package/dist/update/release-metadata.js.map +1 -0
- package/dist/update/release-policy.d.ts +51 -0
- package/dist/update/release-policy.d.ts.map +1 -0
- package/dist/update/release-policy.js +103 -0
- package/dist/update/release-policy.js.map +1 -0
- package/dist/update/rollback-policy.d.ts +56 -0
- package/dist/update/rollback-policy.d.ts.map +1 -0
- package/dist/update/rollback-policy.js +61 -0
- package/dist/update/rollback-policy.js.map +1 -0
- package/dist/update/transaction-journal.d.ts +121 -0
- package/dist/update/transaction-journal.d.ts.map +1 -0
- package/dist/update/transaction-journal.js +333 -0
- package/dist/update/transaction-journal.js.map +1 -0
- package/dist/update/trust-metadata.d.ts +55 -0
- package/dist/update/trust-metadata.d.ts.map +1 -0
- package/dist/update/trust-metadata.js +170 -0
- package/dist/update/trust-metadata.js.map +1 -0
- package/dist/update/update-history.d.ts +46 -0
- package/dist/update/update-history.d.ts.map +1 -0
- package/dist/update/update-history.js +123 -0
- package/dist/update/update-history.js.map +1 -0
- package/dist/utils/env.d.ts +7 -0
- package/dist/utils/env.d.ts.map +1 -1
- package/dist/utils/env.js +134 -44
- package/dist/utils/env.js.map +1 -1
- package/host-runtime/dist/governance-observation-store.d.ts +172 -0
- package/host-runtime/dist/governance-observation-store.js +649 -0
- package/host-runtime/dist/index.d.ts +6 -0
- package/host-runtime/dist/index.js +8 -0
- package/host-runtime/dist/product-telemetry/consent-store.d.ts +107 -0
- package/host-runtime/dist/product-telemetry/consent-store.js +329 -0
- package/host-runtime/dist/product-telemetry/eligibility.d.ts +53 -0
- package/host-runtime/dist/product-telemetry/eligibility.js +69 -0
- package/host-runtime/dist/product-telemetry/exporter.d.ts +46 -0
- package/host-runtime/dist/product-telemetry/exporter.js +71 -0
- package/host-runtime/dist/product-telemetry/milestone-readers.d.ts +61 -0
- package/host-runtime/dist/product-telemetry/milestone-readers.js +234 -0
- package/host-runtime/dist/product-telemetry/service.d.ts +142 -0
- package/host-runtime/dist/product-telemetry/service.js +532 -0
- package/host-runtime/dist/product-telemetry/workspace-scope.d.ts +38 -0
- package/host-runtime/dist/product-telemetry/workspace-scope.js +64 -0
- package/host-runtime/package.json +7 -2
- package/install-layout/dist/index.d.ts +48 -0
- package/install-layout/dist/index.js +81 -0
- package/install-layout/dist/index.test.d.ts +1 -0
- package/install-layout/dist/index.test.js +34 -0
- package/install-layout/package.json +33 -0
- package/package.json +16 -6
- package/pd-cli/dist/commands/__tests__/telemetry-flag-wiring.test.d.ts +9 -0
- package/pd-cli/dist/commands/__tests__/telemetry-flag-wiring.test.d.ts.map +1 -0
- package/pd-cli/dist/commands/__tests__/telemetry-flag-wiring.test.js +76 -0
- package/pd-cli/dist/commands/__tests__/telemetry-flag-wiring.test.js.map +1 -0
- package/pd-cli/dist/commands/__tests__/version.test.d.ts +2 -0
- package/pd-cli/dist/commands/__tests__/version.test.d.ts.map +1 -0
- package/pd-cli/dist/commands/__tests__/version.test.js +134 -0
- package/pd-cli/dist/commands/__tests__/version.test.js.map +1 -0
- package/pd-cli/dist/commands/console.d.ts.map +1 -1
- package/pd-cli/dist/commands/console.js +29 -10
- package/pd-cli/dist/commands/console.js.map +1 -1
- package/pd-cli/dist/commands/pain-record.d.ts.map +1 -1
- package/pd-cli/dist/commands/pain-record.js +6 -15
- package/pd-cli/dist/commands/pain-record.js.map +1 -1
- package/pd-cli/dist/commands/runtime-activation.d.ts +29 -0
- package/pd-cli/dist/commands/runtime-activation.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-activation.js +70 -31
- package/pd-cli/dist/commands/runtime-activation.js.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-enqueue-successors.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-enqueue-successors.js +2 -2
- package/pd-cli/dist/commands/runtime-internalization-enqueue-successors.js.map +1 -1
- package/pd-cli/dist/commands/telemetry.d.ts +82 -0
- package/pd-cli/dist/commands/telemetry.d.ts.map +1 -0
- package/pd-cli/dist/commands/telemetry.js +268 -0
- package/pd-cli/dist/commands/telemetry.js.map +1 -0
- package/pd-cli/dist/commands/version.d.ts +11 -0
- package/pd-cli/dist/commands/version.d.ts.map +1 -0
- package/pd-cli/dist/commands/version.js +48 -0
- package/pd-cli/dist/commands/version.js.map +1 -0
- package/pd-cli/dist/index.js +35 -2
- package/pd-cli/dist/index.js.map +1 -1
- package/pd-cli/dist/services/version-report.d.ts +44 -0
- package/pd-cli/dist/services/version-report.d.ts.map +1 -0
- package/pd-cli/dist/services/version-report.js +152 -0
- package/pd-cli/dist/services/version-report.js.map +1 -0
- package/pd-cli/package.json +3 -2
- package/plugin/dist/bundle.js +870 -932
- package/plugin/dist/core/init.d.ts +2 -1
- package/plugin/dist/core/principle-application-ledger.d.ts +10 -0
- package/plugin/dist/core/product-telemetry-trigger.d.ts +14 -0
- package/plugin/dist/core/thinking-os-parser.d.ts +5 -2
- package/plugin/dist/governance-audit.js +386 -0
- package/plugin/dist/hooks/gate-block-helper.d.ts +25 -1
- package/plugin/dist/hooks/gate.d.ts +22 -0
- package/plugin/dist/openclaw.plugin.json +1 -1
- package/plugin/dist/rulehost-evidence.js +832 -0
- package/plugin/dist/templates/langs/en/principles/THINKING_OS.md +53 -45
- package/plugin/dist/templates/langs/en/skills/pd-mentor/SKILL.md +1 -1
- package/plugin/dist/templates/langs/zh/principles/THINKING_OS.md +62 -46
- package/plugin/dist/templates/langs/zh/skills/pd-mentor/SKILL.md +1 -1
- package/plugin/dist/templates/workspace/.principles/THINKING_OS.md +66 -38
- package/plugin/openclaw.plugin.json +1 -1
- package/plugin/package.json +1 -1
- package/plugin/templates/langs/en/principles/THINKING_OS.md +53 -45
- package/plugin/templates/langs/en/skills/pd-mentor/SKILL.md +1 -1
- package/plugin/templates/langs/zh/principles/THINKING_OS.md +62 -46
- package/plugin/templates/langs/zh/skills/pd-mentor/SKILL.md +1 -1
- package/plugin/templates/workspace/.principles/THINKING_OS.md +66 -38
package/dist/installer.js
CHANGED
|
@@ -2,15 +2,17 @@ import { existsSync, readdirSync, statSync, readFileSync, writeFileSync, mkdirSy
|
|
|
2
2
|
import fse from 'fs-extra';
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import * as http from 'http';
|
|
5
|
-
import {
|
|
5
|
+
import { execFileSync, spawn } from 'child_process';
|
|
6
6
|
import ora from 'ora';
|
|
7
7
|
import { select } from '@inquirer/prompts';
|
|
8
8
|
import { logger } from './utils/logger.js';
|
|
9
9
|
import { checkOpenClawGateway, stopOpenClawGateway, restartOpenClawGateway } from './utils/env.js';
|
|
10
10
|
import { t } from './i18n.js';
|
|
11
|
-
import { generateConfigYamlContent, HostRuntimeConfigMigrationInfraError, migrateHostRuntimeFlagsInConfigYaml, getConfigYamlPath, readEnabledChannelsFromConfigYaml, getOpenClawDir, getPluginExtDir, getPdBackupsDir, getInstalledPdCliDir, getInstalledBinDir, getInstalledConsoleDir, isWindows, } from './mvp-config.js';
|
|
11
|
+
import { generateConfigYamlContent, HostRuntimeConfigMigrationInfraError, migrateHostRuntimeFlagsInConfigYaml, getConfigYamlPath, readEnabledChannelsFromConfigYaml, getOpenClawDir, getPdDir, getPdRuntimeDir, getInstallManifestPath, getPdRuntimeBackupsDir, getPluginExtDir, getInstalledPluginDir, getInstalledLayoutPackageDir, getPdBackupsDir, getInstalledPdCliDir, getInstalledBinDir, getInstalledConsoleDir, isWindows, } from './mvp-config.js';
|
|
12
12
|
import { getHostInstallers } from './installers/index.js';
|
|
13
|
+
import { parseInstallManifest } from '@principles/install-layout';
|
|
13
14
|
import { applySkillLanguageSelection } from './skill-language.js';
|
|
15
|
+
import { parseReleaseAssetIdentity, parseReleaseAssetManifest, ReleaseAssetManifestError, verifyReleaseAssetManifestAsync, verifyReleaseAssetTarget, } from './update/release-asset-manifest.js';
|
|
14
16
|
/** PRI-343: Keep in sync with @principles/core CONVERSATION_ACCESS_CONFIG_KEY */
|
|
15
17
|
export const CONVERSATION_ACCESS_CONFIG_KEY = 'allowConversationAccess';
|
|
16
18
|
function isRecord(value) {
|
|
@@ -56,35 +58,125 @@ export function ensureConversationAccess(config) {
|
|
|
56
58
|
}
|
|
57
59
|
const INSTALL_TIMEOUT_MS = parseInt(process.env.PD_INSTALL_TIMEOUT_MS || '300000', 10);
|
|
58
60
|
// 超时常量
|
|
59
|
-
const PD_CLI_VERIFICATION_TIMEOUT_MS =
|
|
61
|
+
const PD_CLI_VERIFICATION_TIMEOUT_MS = 30_000;
|
|
60
62
|
const STORY_A_VERIFICATION_TIMEOUT_MS = 30_000;
|
|
61
63
|
const CONSOLE_HEALTH_CHECK_TIMEOUT_MS = 8_000;
|
|
62
64
|
const CONSOLE_WARMUP_TIME_MS = 6_000;
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
// 端口范围常量。PD_CONSOLE_PORT_BASE 允许在操作系统保留了大段端口
|
|
66
|
+
// (如 Windows excludedportrange) 的机器上整体平移探测窗口;未设置时
|
|
67
|
+
// 保持历史默认 3100–3199。resolveConsolePortBase() 是唯一 resolved
|
|
68
|
+
// base:安装验证窗口、console 健康检查、autolaunch 扫描、测试全部
|
|
69
|
+
// 消费它——任何新窗口不得再硬编码第二个 base。
|
|
70
|
+
export function resolveConsolePortBase() {
|
|
71
|
+
const raw = process.env.PD_CONSOLE_PORT_BASE;
|
|
72
|
+
if (raw === undefined)
|
|
73
|
+
return 3100;
|
|
74
|
+
// Number() (not parseInt) so '3300.5' is rejected instead of silently
|
|
75
|
+
// truncating to 3300.
|
|
76
|
+
const parsed = Number(raw);
|
|
77
|
+
if (!Number.isInteger(parsed) || parsed < 1024 || parsed > 65000) {
|
|
78
|
+
throw new Error(`PD_CONSOLE_PORT_BASE must be an integer in [1024, 65000], got: ${JSON.stringify(raw)}`);
|
|
79
|
+
}
|
|
80
|
+
return parsed;
|
|
81
|
+
}
|
|
82
|
+
const CONSOLE_PORT_RANGE_MIN = resolveConsolePortBase();
|
|
83
|
+
const CONSOLE_PORT_RANGE_MAX = CONSOLE_PORT_RANGE_MIN + 99;
|
|
84
|
+
// Task 8: auto-launch console via `pd console open` after successful install.
|
|
85
|
+
// Derived from the SAME resolved base as the verification window above.
|
|
86
|
+
const CONSOLE_AUTOLAUNCH_BASE_PORT = CONSOLE_PORT_RANGE_MIN;
|
|
87
|
+
const CONSOLE_AUTOLAUNCH_PORT_SCAN_LIMIT = 20; // base..base+19 (matches pd console open PORT_FALLBACK_LIMIT)
|
|
69
88
|
const CONSOLE_AUTOLAUNCH_READY_TIMEOUT_MS = 12_000;
|
|
70
89
|
const CONSOLE_AUTOLAUNCH_POLL_INTERVAL_MS = 500;
|
|
71
90
|
// 允许的原生模块白名单
|
|
72
91
|
const ALLOWED_NATIVE_MODULES = ['better-sqlite3'];
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
92
|
+
// Shared components use ~/.pd/runtime. The plugin package is host-neutral for
|
|
93
|
+
// Codex-only installs; OpenClaw/all still receive their adapter copy under
|
|
94
|
+
// ~/.openclaw/extensions for host discovery.
|
|
95
|
+
let activeHostTarget = 'openclaw';
|
|
96
|
+
function installsOpenClaw(host) {
|
|
97
|
+
return host === 'openclaw' || host === 'all';
|
|
98
|
+
}
|
|
99
|
+
function installedPluginDir() {
|
|
100
|
+
return getInstalledPluginDir();
|
|
101
|
+
}
|
|
102
|
+
function pluginInstallDirs() {
|
|
103
|
+
return installsOpenClaw(activeHostTarget)
|
|
104
|
+
? [getInstalledPluginDir(), getPluginExtDir()]
|
|
105
|
+
: [getInstalledPluginDir()];
|
|
106
|
+
}
|
|
107
|
+
export function mergeInstallManifestHosts(current, host) {
|
|
108
|
+
const hosts = new Set();
|
|
109
|
+
const parsed = parseInstallManifest(current);
|
|
110
|
+
if (current !== undefined && !parsed.manifest) {
|
|
111
|
+
throw new Error(parsed.error ?? 'install_manifest_malformed');
|
|
112
|
+
}
|
|
113
|
+
for (const existingHost of parsed.manifest?.hosts ?? [])
|
|
114
|
+
hosts.add(existingHost);
|
|
115
|
+
if (host === 'all' || host === 'codex')
|
|
116
|
+
hosts.add('codex');
|
|
117
|
+
if (host === 'all' || host === 'openclaw')
|
|
118
|
+
hosts.add('openclaw');
|
|
119
|
+
return [...hosts];
|
|
120
|
+
}
|
|
121
|
+
function resolveInstallManifestHosts(host) {
|
|
122
|
+
let current;
|
|
123
|
+
try {
|
|
124
|
+
current = JSON.parse(readFileSync(getInstallManifestPath(), 'utf8'));
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
if (existsSync(getInstallManifestPath()))
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
return mergeInstallManifestHosts(current, host);
|
|
131
|
+
}
|
|
132
|
+
function writeInstallManifest(hosts) {
|
|
133
|
+
mkdirSync(getPdDir(), { recursive: true });
|
|
134
|
+
writeFileSync(getInstallManifestPath(), JSON.stringify({ layoutVersion: 1, mode: 'canonical', hosts }, null, 2) + '\n', 'utf8');
|
|
135
|
+
}
|
|
136
|
+
function installBundledLayoutPackage(pluginDir) {
|
|
137
|
+
const source = path.join(pluginDir, 'install-layout');
|
|
138
|
+
const destination = getInstalledLayoutPackageDir();
|
|
139
|
+
if (!existsSync(path.join(source, 'package.json')) || !existsSync(path.join(source, 'dist'))) {
|
|
140
|
+
throw new Error('Bundled @principles/install-layout is incomplete. Re-run the installer with a current package.');
|
|
141
|
+
}
|
|
142
|
+
rmSync(destination, { recursive: true, force: true });
|
|
143
|
+
cpSync(source, destination, { recursive: true });
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Run npm with array-form argv, no shell (PRI-569 hardening).
|
|
147
|
+
*
|
|
148
|
+
* On Windows `npm` is an npm.cmd shim: Node cannot spawn .cmd without a
|
|
149
|
+
* shell (EINVAL/ENOENT), so win32 routes through cmd.exe with CONSTANT argv
|
|
150
|
+
* elements — args are compile-time literals at every call site; the one
|
|
151
|
+
* external-derived value (registry version) is regex-guarded before use.
|
|
152
|
+
* Returns captured stdout (encoding utf-8).
|
|
153
|
+
*/
|
|
154
|
+
function execNpm(args, cwd, timeoutOverride) {
|
|
155
|
+
// encoding:'utf-8' resolves the string overload of execFileSync (TS-typed);
|
|
156
|
+
// callers and tests must honor that contract (string output).
|
|
157
|
+
return (process.platform === 'win32'
|
|
158
|
+
? execFileSync('cmd.exe', ['/c', 'npm', ...args], {
|
|
159
|
+
cwd,
|
|
160
|
+
encoding: 'utf-8',
|
|
161
|
+
stdio: 'pipe',
|
|
162
|
+
env: process.env,
|
|
163
|
+
windowsHide: true,
|
|
164
|
+
timeout: timeoutOverride ?? INSTALL_TIMEOUT_MS,
|
|
165
|
+
})
|
|
166
|
+
: execFileSync('npm', args, {
|
|
167
|
+
cwd,
|
|
168
|
+
encoding: 'utf-8',
|
|
169
|
+
stdio: 'pipe',
|
|
170
|
+
env: process.env,
|
|
171
|
+
timeout: timeoutOverride ?? INSTALL_TIMEOUT_MS,
|
|
172
|
+
})).trim();
|
|
80
173
|
}
|
|
81
174
|
/**
|
|
82
175
|
* 执行 npm install 并提供友好的错误提示
|
|
83
176
|
*/
|
|
84
177
|
async function runNpmInstall(cwd, componentName = 'npm') {
|
|
85
|
-
const execOpts = getCapturingExecOptions(cwd);
|
|
86
178
|
try {
|
|
87
|
-
|
|
179
|
+
execNpm(['install', '--ignore-scripts', '--legacy-peer-deps'], cwd);
|
|
88
180
|
}
|
|
89
181
|
catch (e) {
|
|
90
182
|
const errorMsg = e instanceof Error ? e.message : String(e);
|
|
@@ -101,23 +193,10 @@ async function runNpmInstall(cwd, componentName = 'npm') {
|
|
|
101
193
|
}
|
|
102
194
|
}
|
|
103
195
|
/**
|
|
104
|
-
*
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const modPath = path.join(cwd, 'node_modules', mod);
|
|
109
|
-
if (!existsSync(modPath))
|
|
110
|
-
continue;
|
|
111
|
-
try {
|
|
112
|
-
execSync(`npm rebuild ${mod}`, getCapturingExecOptions(cwd));
|
|
113
|
-
}
|
|
114
|
-
catch (e) {
|
|
115
|
-
throw new Error(`${componentName} native module ${mod} rebuild failed: ${e instanceof Error ? e.message : String(e)}. Try manually: cd ${cwd} && npm rebuild ${mod}`, { cause: e });
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* 验证原生模块
|
|
196
|
+
* 验证原生模块:better-sqlite3 随发布资产携带 prebuilt 二进制
|
|
197
|
+
* (prebuilds/*.node),node-gyp-build 在 require 时解析——无需(也没有)
|
|
198
|
+
* npm rebuild 步骤。本函数的 require 探针就是唯一验证(历史上存在一个
|
|
199
|
+
* 名为 rebuildNativeModules 的空壳函数,已删除以避免误导维护者)。
|
|
121
200
|
*/
|
|
122
201
|
export function verifyNativeModules(cwd, componentName) {
|
|
123
202
|
for (const nativeMod of ALLOWED_NATIVE_MODULES) {
|
|
@@ -128,10 +207,147 @@ export function verifyNativeModules(cwd, componentName) {
|
|
|
128
207
|
execFileSync(process.execPath, ['-e', `require('${nativeMod}')`], { cwd, stdio: 'pipe' });
|
|
129
208
|
}
|
|
130
209
|
catch {
|
|
131
|
-
throw new Error(`${componentName} native module ${nativeMod}
|
|
210
|
+
throw new Error(`${componentName} native module ${nativeMod} failed its require probe: the prebuilt binary for this Node.js ABI is missing or incompatible (no rebuild step exists by design). Install the platform release asset matching this OS, architecture, and ABI.`);
|
|
132
211
|
}
|
|
133
212
|
}
|
|
134
213
|
}
|
|
214
|
+
const SELF_CONTAINED_DEPENDENCY_NEXT_ACTION = 'Install a complete platform release asset for this Node.js ABI and re-run the installer.';
|
|
215
|
+
const SELF_CONTAINED_NATIVE_NEXT_ACTION = 'Install the platform release asset matching this operating system, architecture, and Node.js ABI.';
|
|
216
|
+
export class SelfContainedDependencyError extends Error {
|
|
217
|
+
reason;
|
|
218
|
+
nextAction;
|
|
219
|
+
component;
|
|
220
|
+
dependency;
|
|
221
|
+
constructor(options) {
|
|
222
|
+
super(options.message, { cause: options.cause });
|
|
223
|
+
this.name = 'SelfContainedDependencyError';
|
|
224
|
+
this.reason = options.reason;
|
|
225
|
+
this.nextAction = options.nextAction;
|
|
226
|
+
this.component = options.component;
|
|
227
|
+
this.dependency = options.dependency;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function legacyNpmInstallEnabled() {
|
|
231
|
+
const value = process.env.PD_ALLOW_LEGACY_NPM_INSTALL;
|
|
232
|
+
return value === '1' || value === 'true';
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Supported release assets are self-contained: installation validates the
|
|
236
|
+
* copied component and never resolves dependencies or runs lifecycle scripts.
|
|
237
|
+
* The old npm path remains opt-in for development/legacy recovery only.
|
|
238
|
+
*/
|
|
239
|
+
export async function prepareBundledComponentDependencies(cwd, componentName) {
|
|
240
|
+
const packageJsonPath = path.join(cwd, 'package.json');
|
|
241
|
+
let packageJsonRaw;
|
|
242
|
+
try {
|
|
243
|
+
packageJsonRaw = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
244
|
+
}
|
|
245
|
+
catch (error) {
|
|
246
|
+
throw new SelfContainedDependencyError({
|
|
247
|
+
reason: 'self_contained_package_manifest_invalid',
|
|
248
|
+
nextAction: SELF_CONTAINED_DEPENDENCY_NEXT_ACTION,
|
|
249
|
+
message: `${componentName} package.json is missing or malformed after copy.`,
|
|
250
|
+
component: componentName,
|
|
251
|
+
cause: error,
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
if (!isRecord(packageJsonRaw)) {
|
|
255
|
+
throw new SelfContainedDependencyError({
|
|
256
|
+
reason: 'self_contained_package_manifest_invalid',
|
|
257
|
+
nextAction: SELF_CONTAINED_DEPENDENCY_NEXT_ACTION,
|
|
258
|
+
message: `${componentName} package.json must contain an object.`,
|
|
259
|
+
component: componentName,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
const { dependencies } = packageJsonRaw;
|
|
263
|
+
if (dependencies !== undefined && !isRecord(dependencies)) {
|
|
264
|
+
throw new SelfContainedDependencyError({
|
|
265
|
+
reason: 'self_contained_package_manifest_invalid',
|
|
266
|
+
nextAction: SELF_CONTAINED_DEPENDENCY_NEXT_ACTION,
|
|
267
|
+
message: `${componentName} package.json dependencies must contain an object.`,
|
|
268
|
+
component: componentName,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
for (const dependency of Object.keys(dependencies ?? {})) {
|
|
272
|
+
if (!existsSync(path.join(cwd, 'node_modules', dependency))) {
|
|
273
|
+
throw new SelfContainedDependencyError({
|
|
274
|
+
reason: 'self_contained_runtime_dependency_missing',
|
|
275
|
+
nextAction: SELF_CONTAINED_DEPENDENCY_NEXT_ACTION,
|
|
276
|
+
message: `${componentName} self-contained release asset is missing declared runtime dependency ${dependency}.`,
|
|
277
|
+
component: componentName,
|
|
278
|
+
dependency,
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
try {
|
|
283
|
+
verifyNativeModules(cwd, componentName);
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
throw new SelfContainedDependencyError({
|
|
287
|
+
reason: 'self_contained_native_module_unloadable',
|
|
288
|
+
nextAction: SELF_CONTAINED_NATIVE_NEXT_ACTION,
|
|
289
|
+
message: `${componentName} bundled better-sqlite3 cannot be loaded by this Node.js runtime.`,
|
|
290
|
+
component: componentName,
|
|
291
|
+
dependency: 'better-sqlite3',
|
|
292
|
+
cause: error,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
const SELF_CONTAINED_COMPONENTS = [
|
|
297
|
+
['Core', 'core'],
|
|
298
|
+
['Host runtime', 'host-runtime'],
|
|
299
|
+
['Plugin', 'plugin'],
|
|
300
|
+
['PD CLI', 'pd-cli'],
|
|
301
|
+
['Console', 'console'],
|
|
302
|
+
['Install layout', 'install-layout'],
|
|
303
|
+
];
|
|
304
|
+
export async function preflightSelfContainedReleaseAsset(assetDir) {
|
|
305
|
+
const identityPath = path.join(assetDir, '_release', 'asset.json');
|
|
306
|
+
let identityValue;
|
|
307
|
+
try {
|
|
308
|
+
identityValue = JSON.parse(readFileSync(identityPath, 'utf8'));
|
|
309
|
+
const identity = parseReleaseAssetIdentity(identityValue);
|
|
310
|
+
verifyReleaseAssetTarget(identity, {
|
|
311
|
+
platform: process.platform,
|
|
312
|
+
arch: process.arch,
|
|
313
|
+
nodeAbi: process.versions.modules,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
const targetMismatch = error instanceof ReleaseAssetManifestError && error.code === 'asset_target_mismatch';
|
|
318
|
+
throw new SelfContainedDependencyError({
|
|
319
|
+
reason: targetMismatch ? 'self_contained_asset_target_mismatch' : 'self_contained_asset_identity_invalid',
|
|
320
|
+
nextAction: targetMismatch ? SELF_CONTAINED_NATIVE_NEXT_ACTION : SELF_CONTAINED_DEPENDENCY_NEXT_ACTION,
|
|
321
|
+
message: error instanceof Error ? error.message : 'Release asset identity is missing or malformed.',
|
|
322
|
+
component: 'Release asset',
|
|
323
|
+
cause: error,
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
try {
|
|
327
|
+
const manifestValue = JSON.parse(readFileSync(path.join(assetDir, '_release', 'manifest.json'), 'utf8'));
|
|
328
|
+
await verifyReleaseAssetManifestAsync(assetDir, parseReleaseAssetManifest(manifestValue));
|
|
329
|
+
}
|
|
330
|
+
catch (error) {
|
|
331
|
+
throw new SelfContainedDependencyError({
|
|
332
|
+
reason: 'self_contained_asset_integrity_invalid',
|
|
333
|
+
nextAction: SELF_CONTAINED_DEPENDENCY_NEXT_ACTION,
|
|
334
|
+
message: error instanceof Error ? error.message : 'Release asset manifest is missing, malformed, or does not match its files.',
|
|
335
|
+
component: 'Release asset',
|
|
336
|
+
cause: error,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
for (const [componentName, componentDirectory] of SELF_CONTAINED_COMPONENTS) {
|
|
340
|
+
await prepareBundledComponentDependencies(path.join(assetDir, componentDirectory), componentName);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
async function prepareComponentDependencies(cwd, componentName) {
|
|
344
|
+
if (!legacyNpmInstallEnabled()) {
|
|
345
|
+
await prepareBundledComponentDependencies(cwd, componentName);
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
await runNpmInstall(cwd, componentName);
|
|
349
|
+
verifyNativeModules(cwd, componentName);
|
|
350
|
+
}
|
|
135
351
|
/**
|
|
136
352
|
* 验证路径是否在工作区目录内,防止路径遍历攻击
|
|
137
353
|
*/
|
|
@@ -147,17 +363,18 @@ const INSTALL_STEPS = [
|
|
|
147
363
|
{ name: 'Checking workspace rule compatibility', weight: 1 },
|
|
148
364
|
{ name: 'Backing up existing install', weight: 3 },
|
|
149
365
|
{ name: 'Installing bundled @principles/core', weight: 8 },
|
|
366
|
+
{ name: 'Validating bundled core dependencies', weight: 5 },
|
|
150
367
|
{ name: 'Installing bundled @principles/host-runtime', weight: 3 },
|
|
151
|
-
{ name: '
|
|
368
|
+
{ name: 'Validating bundled host runtime dependencies', weight: 5 },
|
|
152
369
|
{ name: 'Installing plugin', weight: 10 },
|
|
153
370
|
{ name: 'Preparing core library for plugin', weight: 3 },
|
|
154
|
-
{ name: '
|
|
371
|
+
{ name: 'Validating bundled plugin dependencies', weight: 10 },
|
|
155
372
|
{ name: 'Installing pd CLI', weight: 8 },
|
|
156
373
|
{ name: 'Preparing core library for pd-cli', weight: 3 },
|
|
157
374
|
{ name: 'Verifying pd CLI', weight: 3 },
|
|
158
375
|
{ name: 'Installing pd-console', weight: 8 },
|
|
159
376
|
{ name: 'Preparing core library for console', weight: 3 },
|
|
160
|
-
{ name: '
|
|
377
|
+
{ name: 'Validating bundled console dependencies', weight: 5 },
|
|
161
378
|
{ name: 'Verifying pd-console', weight: 3 },
|
|
162
379
|
{ name: 'Copying templates', weight: 3 },
|
|
163
380
|
{ name: 'Generating config.yaml', weight: 2 },
|
|
@@ -224,34 +441,51 @@ export function migrateLegacyPdBackups() {
|
|
|
224
441
|
/**
|
|
225
442
|
* Exported for real-filesystem tests (tests/backup-location.test.ts).
|
|
226
443
|
*/
|
|
227
|
-
export function backupExistingInstall() {
|
|
444
|
+
export function backupExistingInstall(host = 'openclaw') {
|
|
228
445
|
const extDir = getPluginExtDir();
|
|
229
|
-
|
|
446
|
+
const runtimeDir = getPdRuntimeDir();
|
|
447
|
+
const hasExt = installsOpenClaw(host) && existsSync(extDir);
|
|
448
|
+
const hasRuntime = existsSync(runtimeDir);
|
|
449
|
+
if (!hasExt && !hasRuntime)
|
|
230
450
|
return { type: 'no_existing', backupDir: null };
|
|
231
451
|
// The backup must live OUTSIDE the extensions dir (see getPdBackupsDir):
|
|
232
452
|
// OpenClaw plugin discovery scans every extensions/ child directory and
|
|
233
453
|
// would discover the backup as a second principles-disciple plugin.
|
|
234
|
-
const backupsDir = getPdBackupsDir();
|
|
235
|
-
const
|
|
454
|
+
const backupsDir = hasExt ? getPdBackupsDir() : getPdRuntimeBackupsDir();
|
|
455
|
+
const timestamp = Date.now();
|
|
456
|
+
const backupDir = hasExt ? path.join(backupsDir, `principles-disciple.backup.${timestamp}`) : null;
|
|
457
|
+
const runtimeBackupDir = hasRuntime ? path.join(getPdRuntimeBackupsDir(), `runtime.backup.${timestamp}`) : null;
|
|
236
458
|
try {
|
|
237
459
|
mkdirSync(backupsDir, { recursive: true });
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
460
|
+
if (backupDir)
|
|
461
|
+
renameSync(extDir, backupDir);
|
|
462
|
+
if (runtimeBackupDir) {
|
|
463
|
+
mkdirSync(getPdRuntimeBackupsDir(), { recursive: true });
|
|
464
|
+
renameSync(runtimeDir, runtimeBackupDir);
|
|
465
|
+
}
|
|
466
|
+
logger.info(`Backed up existing install to ${backupDir ?? runtimeBackupDir}`);
|
|
467
|
+
return { type: 'backed_up', backupDir, runtimeBackupDir };
|
|
241
468
|
}
|
|
242
469
|
catch (e) {
|
|
243
470
|
throw new Error(`Could not backup existing install at ${extDir}: ${e instanceof Error ? e.message : String(e)}. Aborting to prevent data loss — resolve the lock or rename manually and re-run.`, { cause: e });
|
|
244
471
|
}
|
|
245
472
|
}
|
|
246
|
-
function restoreBackup(backupDir) {
|
|
247
|
-
if (!backupDir || !existsSync(backupDir))
|
|
473
|
+
function restoreBackup(backupDir, runtimeBackupDir) {
|
|
474
|
+
if ((!backupDir || !existsSync(backupDir)) && (!runtimeBackupDir || !existsSync(runtimeBackupDir)))
|
|
248
475
|
return { restored: true };
|
|
249
476
|
const extDir = getPluginExtDir();
|
|
477
|
+
const runtimeDir = getPdRuntimeDir();
|
|
250
478
|
try {
|
|
251
|
-
if (existsSync(extDir)) {
|
|
479
|
+
if (backupDir && existsSync(extDir)) {
|
|
252
480
|
rmSync(extDir, { recursive: true, force: true });
|
|
253
481
|
}
|
|
254
|
-
|
|
482
|
+
if (backupDir && existsSync(backupDir))
|
|
483
|
+
renameSync(backupDir, extDir);
|
|
484
|
+
if (runtimeBackupDir && existsSync(runtimeBackupDir)) {
|
|
485
|
+
if (existsSync(runtimeDir))
|
|
486
|
+
rmSync(runtimeDir, { recursive: true, force: true });
|
|
487
|
+
renameSync(runtimeBackupDir, runtimeDir);
|
|
488
|
+
}
|
|
255
489
|
logger.info('Restored previous install from backup');
|
|
256
490
|
return { restored: true };
|
|
257
491
|
}
|
|
@@ -261,14 +495,16 @@ function restoreBackup(backupDir) {
|
|
|
261
495
|
return { restored: false, error: msg };
|
|
262
496
|
}
|
|
263
497
|
}
|
|
264
|
-
function cleanupBackup(backupDir) {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
498
|
+
function cleanupBackup(backupDir, runtimeBackupDir) {
|
|
499
|
+
for (const backup of [backupDir, runtimeBackupDir]) {
|
|
500
|
+
if (!backup || !existsSync(backup))
|
|
501
|
+
continue;
|
|
502
|
+
try {
|
|
503
|
+
rmSync(backup, { recursive: true, force: true });
|
|
504
|
+
}
|
|
505
|
+
catch {
|
|
506
|
+
// non-fatal
|
|
507
|
+
}
|
|
272
508
|
}
|
|
273
509
|
}
|
|
274
510
|
/**
|
|
@@ -532,17 +768,28 @@ export async function checkBuiltPlugin(pluginDir) {
|
|
|
532
768
|
}
|
|
533
769
|
}
|
|
534
770
|
export async function installPluginToStaging(pluginDir, language) {
|
|
535
|
-
const extDir = getPluginExtDir();
|
|
536
771
|
const builtPluginDir = path.join(pluginDir, 'plugin');
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
772
|
+
for (const targetDir of pluginInstallDirs()) {
|
|
773
|
+
await fse.ensureDir(targetDir);
|
|
774
|
+
await fse.copy(builtPluginDir, targetDir, { overwrite: true });
|
|
775
|
+
// The published plugin declares its bundled core as file:./core. Keep that
|
|
776
|
+
// package-local contract while storing the actual core once in the shared
|
|
777
|
+
// host-neutral runtime directory.
|
|
778
|
+
const pluginCoreLink = path.join(targetDir, 'core');
|
|
779
|
+
if (!existsSync(pluginCoreLink)) {
|
|
780
|
+
const coreDir = path.join(getPdRuntimeDir(), 'core');
|
|
781
|
+
if (isWindows())
|
|
782
|
+
symlinkSync(coreDir, pluginCoreLink, 'junction');
|
|
783
|
+
else
|
|
784
|
+
symlinkSync(path.relative(targetDir, coreDir), pluginCoreLink, 'dir');
|
|
785
|
+
}
|
|
786
|
+
// OpenClaw publishes skills by name with no locale mechanism. Applying the
|
|
787
|
+
// same selected language to both copies also keeps the canonical package
|
|
788
|
+
// ready if another host is attached later.
|
|
789
|
+
const selection = applySkillLanguageSelection(targetDir, language);
|
|
790
|
+
if (!selection.applied) {
|
|
791
|
+
logger.warn(`Skill language "${language}" not applied at ${targetDir} (${selection.note ?? 'unknown'}) — published skills stay at the manifest default`);
|
|
792
|
+
}
|
|
546
793
|
}
|
|
547
794
|
}
|
|
548
795
|
// ADR-0020 §2.3: The OpenClaw config write logic previously lived here as
|
|
@@ -551,42 +798,13 @@ export async function installPluginToStaging(pluginDir, language) {
|
|
|
551
798
|
// `runHostInstallers()` below. This file no longer writes openclaw.json
|
|
552
799
|
// directly — the HostInstaller interface keeps install/uninstall host-agnostic.
|
|
553
800
|
async function installPluginDependencies() {
|
|
554
|
-
const extDir
|
|
555
|
-
|
|
556
|
-
const nodeModulesPath = path.join(extDir, 'node_modules');
|
|
557
|
-
if (!existsSync(packageJsonPath)) {
|
|
558
|
-
throw new Error('Plugin package.json not found after copy — install is corrupted');
|
|
559
|
-
}
|
|
560
|
-
const packageJsonRaw = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
561
|
-
if (typeof packageJsonRaw !== 'object' || packageJsonRaw === null || Array.isArray(packageJsonRaw)) {
|
|
562
|
-
throw new Error('Plugin package.json is malformed');
|
|
563
|
-
}
|
|
564
|
-
const pkg = packageJsonRaw;
|
|
565
|
-
const deps = (typeof pkg.dependencies === 'object' && pkg.dependencies !== null && !Array.isArray(pkg.dependencies))
|
|
566
|
-
? Object.keys(pkg.dependencies)
|
|
567
|
-
: [];
|
|
568
|
-
const devDeps = (typeof pkg.devDependencies === 'object' && pkg.devDependencies !== null && !Array.isArray(pkg.devDependencies))
|
|
569
|
-
? Object.keys(pkg.devDependencies)
|
|
570
|
-
: [];
|
|
571
|
-
const allDeps = [...deps, ...devDeps];
|
|
572
|
-
let needsInstall = !existsSync(nodeModulesPath);
|
|
573
|
-
if (!needsInstall) {
|
|
574
|
-
for (const dep of allDeps) {
|
|
575
|
-
if (!existsSync(path.join(extDir, 'node_modules', dep))) {
|
|
576
|
-
needsInstall = true;
|
|
577
|
-
break;
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
if (needsInstall) {
|
|
582
|
-
await runNpmInstall(extDir, 'Plugin');
|
|
801
|
+
for (const extDir of pluginInstallDirs()) {
|
|
802
|
+
await prepareComponentDependencies(extDir, 'Plugin');
|
|
583
803
|
}
|
|
584
|
-
await rebuildNativeModules(extDir, 'Plugin');
|
|
585
|
-
verifyNativeModules(extDir, 'Plugin');
|
|
586
804
|
}
|
|
587
805
|
function getNpmGlobalBinDir() {
|
|
588
806
|
try {
|
|
589
|
-
const prefix =
|
|
807
|
+
const prefix = execNpm(['prefix', '-g']).trim();
|
|
590
808
|
if (!prefix)
|
|
591
809
|
return null;
|
|
592
810
|
return process.platform === 'win32' ? prefix : path.join(prefix, 'bin');
|
|
@@ -596,6 +814,10 @@ function getNpmGlobalBinDir() {
|
|
|
596
814
|
}
|
|
597
815
|
}
|
|
598
816
|
function installGlobalPdShim() {
|
|
817
|
+
if (!legacyNpmInstallEnabled()) {
|
|
818
|
+
logger.info('Skipping npm global shim discovery for the self-contained release asset.');
|
|
819
|
+
return false;
|
|
820
|
+
}
|
|
599
821
|
// Allow skipping global shim installation in smoke tests to avoid
|
|
600
822
|
// polluting the host's npm global bin dir. The bundled pd-cli is
|
|
601
823
|
// still installed locally (getInstalledBinDir); only the global
|
|
@@ -630,6 +852,10 @@ function installGlobalPdShim() {
|
|
|
630
852
|
}
|
|
631
853
|
}
|
|
632
854
|
function tryUpgradePdCliFromNpm(installedPdCliDir) {
|
|
855
|
+
if (!legacyNpmInstallEnabled()) {
|
|
856
|
+
logger.info('Skipping npm pd-cli upgrade for the self-contained release asset.');
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
633
859
|
// Allow skipping the npm upgrade in smoke tests / offline environments.
|
|
634
860
|
// The bundled pd-cli is built from the current repo state and is the
|
|
635
861
|
// authoritative version for testing. Upgrading to an npm-published version
|
|
@@ -640,12 +866,11 @@ function tryUpgradePdCliFromNpm(installedPdCliDir) {
|
|
|
640
866
|
return;
|
|
641
867
|
}
|
|
642
868
|
try {
|
|
643
|
-
const npmVersion =
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
if (!npmVersion || !/^\d+\.\d+\.\d+/.test(npmVersion))
|
|
869
|
+
const npmVersion = execNpm(['view', '@principles/pd-cli', 'version'], undefined, 15_000).trim();
|
|
870
|
+
// Fully anchored semver: this value is interpolated into a cmd.exe
|
|
871
|
+
// command line below, so a registry response carrying shell
|
|
872
|
+
// metacharacters after a valid-looking prefix must be rejected outright.
|
|
873
|
+
if (!npmVersion || !/^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$/.test(npmVersion))
|
|
649
874
|
return;
|
|
650
875
|
const localPkgPath = path.join(installedPdCliDir, 'package.json');
|
|
651
876
|
const localPkg = JSON.parse(readFileSync(localPkgPath, 'utf-8'));
|
|
@@ -656,11 +881,29 @@ function tryUpgradePdCliFromNpm(installedPdCliDir) {
|
|
|
656
881
|
const tmpDir = path.join(installedPdCliDir, '__npm_upgrade_tmp');
|
|
657
882
|
try {
|
|
658
883
|
mkdirSync(tmpDir, { recursive: true });
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
884
|
+
// Platform dispatch (CodeRabbit review): cmd.exe does not exist on
|
|
885
|
+
// POSIX, where npm is a real executable and can be spawned directly.
|
|
886
|
+
// The only registry-derived value on this command line is npmVersion,
|
|
887
|
+
// restricted to a metacharacter-free semver charset by the anchored
|
|
888
|
+
// check above; tmpDir is the local install root (profile-derived, not
|
|
889
|
+
// attacker-controlled). CodeQL's js/indirect-command-line-injection
|
|
890
|
+
// cannot model the regex sanitizer — see the evidence-based dismissal
|
|
891
|
+
// on alert 431.
|
|
892
|
+
const packArgs = ['pack', `@principles/pd-cli@${npmVersion}`, '--pack-destination', tmpDir];
|
|
893
|
+
if (process.platform === 'win32') {
|
|
894
|
+
execFileSync('cmd.exe', ['/d', '/s', '/c', 'npm', ...packArgs], {
|
|
895
|
+
encoding: 'utf-8',
|
|
896
|
+
timeout: 30_000,
|
|
897
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
else {
|
|
901
|
+
execFileSync('npm', packArgs, {
|
|
902
|
+
encoding: 'utf-8',
|
|
903
|
+
timeout: 30_000,
|
|
904
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
905
|
+
});
|
|
906
|
+
}
|
|
664
907
|
const tgzFiles = readdirSync(tmpDir).filter(f => f.endsWith('.tgz'));
|
|
665
908
|
const [tgzFile] = tgzFiles;
|
|
666
909
|
if (!tgzFile) {
|
|
@@ -669,7 +912,7 @@ function tryUpgradePdCliFromNpm(installedPdCliDir) {
|
|
|
669
912
|
}
|
|
670
913
|
const extractDir = path.join(tmpDir, 'extracted');
|
|
671
914
|
mkdirSync(extractDir, { recursive: true });
|
|
672
|
-
|
|
915
|
+
execFileSync('tar', ['-xzf', path.join(tmpDir, tgzFile), '-C', extractDir], {
|
|
673
916
|
encoding: 'utf-8',
|
|
674
917
|
timeout: 15_000,
|
|
675
918
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
@@ -706,12 +949,16 @@ function syncPdCli(pluginDir) {
|
|
|
706
949
|
mkdirSync(installedPdCliDir, { recursive: true });
|
|
707
950
|
cpSync(distDir, path.join(installedPdCliDir, 'dist'), { recursive: true });
|
|
708
951
|
copyFileSync(path.join(pdCliSourceDir, 'package.json'), path.join(installedPdCliDir, 'package.json'));
|
|
952
|
+
const bundledNodeModules = path.join(pdCliSourceDir, 'node_modules');
|
|
953
|
+
if (existsSync(bundledNodeModules)) {
|
|
954
|
+
cpSync(bundledNodeModules, path.join(installedPdCliDir, 'node_modules'), { recursive: true });
|
|
955
|
+
}
|
|
709
956
|
// Create node_modules/@principles/core symlink so pd-cli can resolve
|
|
710
957
|
// its @principles/core dependency (rewritten to "file:../core" by bundle-plugin.mjs).
|
|
711
958
|
// Without this, `node dist/index.js --version` fails because static imports
|
|
712
959
|
// from @principles/core/runtime-v2 cannot be resolved.
|
|
713
960
|
const coreLinkDir = path.join(installedPdCliDir, 'node_modules', '@principles');
|
|
714
|
-
const coreLinkTarget = path.join(
|
|
961
|
+
const coreLinkTarget = path.join(getPdRuntimeDir(), 'core');
|
|
715
962
|
mkdirSync(coreLinkDir, { recursive: true });
|
|
716
963
|
const coreLinkPath = path.join(coreLinkDir, 'core');
|
|
717
964
|
if (!existsSync(coreLinkPath)) {
|
|
@@ -731,7 +978,7 @@ function syncPdCli(pluginDir) {
|
|
|
731
978
|
// host-runtime's own better-sqlite3 / js-yaml / @principles/core dependencies
|
|
732
979
|
// resolve through the plugin's <ext>/node_modules/ (shared via Node's upward
|
|
733
980
|
// module resolution), so no separate npm install is needed.
|
|
734
|
-
const hostRuntimeLinkTarget = path.join(
|
|
981
|
+
const hostRuntimeLinkTarget = path.join(getPdRuntimeDir(), 'host-runtime');
|
|
735
982
|
const hostRuntimeLinkPath = path.join(coreLinkDir, 'host-runtime');
|
|
736
983
|
if (!existsSync(hostRuntimeLinkPath)) {
|
|
737
984
|
if (isWindows()) {
|
|
@@ -750,7 +997,7 @@ function syncPdCli(pluginDir) {
|
|
|
750
997
|
// Without this, `pd runtime init` crashes with ERR_MODULE_NOT_FOUND
|
|
751
998
|
// because runtime-init.ts statically imports initTrajectorySchema/initWorkflowSchema.
|
|
752
999
|
const pdLinkDir = path.join(installedPdCliDir, 'node_modules');
|
|
753
|
-
const pdLinkTarget =
|
|
1000
|
+
const pdLinkTarget = installedPluginDir();
|
|
754
1001
|
mkdirSync(pdLinkDir, { recursive: true });
|
|
755
1002
|
const pdLinkPath = path.join(pdLinkDir, 'principles-disciple');
|
|
756
1003
|
if (!existsSync(pdLinkPath)) {
|
|
@@ -798,20 +1045,35 @@ function syncPdCli(pluginDir) {
|
|
|
798
1045
|
function verifyPdCliShim() {
|
|
799
1046
|
const localShim = path.join(getInstalledBinDir(), isWindows() ? 'pd.cmd' : 'pd');
|
|
800
1047
|
let localOk = false;
|
|
1048
|
+
let localError;
|
|
801
1049
|
try {
|
|
802
1050
|
const installedEntry = path.join(getInstalledPdCliDir(), 'dist', 'index.js');
|
|
803
1051
|
execFileSync(process.execPath, [installedEntry, '--version'], { stdio: 'pipe', timeout: PD_CLI_VERIFICATION_TIMEOUT_MS });
|
|
804
1052
|
localOk = true;
|
|
805
1053
|
}
|
|
806
1054
|
catch (e) {
|
|
807
|
-
|
|
808
|
-
|
|
1055
|
+
let detail = 'unknown error';
|
|
1056
|
+
if (typeof e === 'object' && e !== null) {
|
|
1057
|
+
const stderr = Object.hasOwn(e, 'stderr') ? Reflect.get(e, 'stderr') : undefined;
|
|
1058
|
+
const message = Object.hasOwn(e, 'message') ? Reflect.get(e, 'message') : undefined;
|
|
1059
|
+
const stderrText = Buffer.isBuffer(stderr) ? stderr.toString().trim().slice(0, 500) : '';
|
|
1060
|
+
if (stderrText.length > 0)
|
|
1061
|
+
detail = stderrText;
|
|
1062
|
+
else if (typeof message === 'string' && message.trim().length > 0)
|
|
1063
|
+
detail = message.trim().slice(0, 500);
|
|
1064
|
+
}
|
|
1065
|
+
else if (typeof e === 'string' && e.trim().length > 0) {
|
|
1066
|
+
detail = e.trim().slice(0, 500);
|
|
1067
|
+
}
|
|
1068
|
+
localError = detail;
|
|
809
1069
|
logger.warn(`PD CLI local verification failed: ${detail}`);
|
|
810
1070
|
}
|
|
811
1071
|
const globalOk = (() => {
|
|
812
1072
|
try {
|
|
813
1073
|
if (isWindows()) {
|
|
814
|
-
|
|
1074
|
+
// 'pd' is an npm .cmd shim on Windows — resolve via cmd.exe with a
|
|
1075
|
+
// constant argv array (no shell string, no interpolation).
|
|
1076
|
+
execFileSync('cmd.exe', ['/c', 'pd', '--version'], { stdio: 'pipe', timeout: PD_CLI_VERIFICATION_TIMEOUT_MS, windowsHide: true });
|
|
815
1077
|
}
|
|
816
1078
|
else {
|
|
817
1079
|
execFileSync('pd', ['--version'], { stdio: 'pipe', timeout: PD_CLI_VERIFICATION_TIMEOUT_MS });
|
|
@@ -822,7 +1084,7 @@ function verifyPdCliShim() {
|
|
|
822
1084
|
return false;
|
|
823
1085
|
}
|
|
824
1086
|
})();
|
|
825
|
-
return { localOk, globalOk, localPath: localShim };
|
|
1087
|
+
return { localOk, globalOk, localPath: localShim, localError };
|
|
826
1088
|
}
|
|
827
1089
|
function installConsole(consoleDir) {
|
|
828
1090
|
const consoleSrc = path.join(consoleDir, 'console');
|
|
@@ -844,18 +1106,18 @@ function installConsole(consoleDir) {
|
|
|
844
1106
|
mkdirSync(path.dirname(pluginLinkPath), { recursive: true });
|
|
845
1107
|
if (!existsSync(pluginLinkPath)) {
|
|
846
1108
|
if (isWindows()) {
|
|
847
|
-
symlinkSync(
|
|
1109
|
+
symlinkSync(installedPluginDir(), pluginLinkPath, 'junction');
|
|
848
1110
|
}
|
|
849
1111
|
else {
|
|
850
|
-
symlinkSync(
|
|
1112
|
+
symlinkSync(path.relative(path.dirname(pluginLinkPath), installedPluginDir()), pluginLinkPath, 'dir');
|
|
851
1113
|
}
|
|
852
1114
|
}
|
|
853
1115
|
}
|
|
854
1116
|
function getInstalledCoreDir() {
|
|
855
|
-
return path.join(
|
|
1117
|
+
return path.join(getPdRuntimeDir(), 'core');
|
|
856
1118
|
}
|
|
857
1119
|
function getInstalledHostRuntimeDir() {
|
|
858
|
-
return path.join(
|
|
1120
|
+
return path.join(getPdRuntimeDir(), 'host-runtime');
|
|
859
1121
|
}
|
|
860
1122
|
function installBundledCore(pluginDir) {
|
|
861
1123
|
const coreSrc = path.join(pluginDir, 'core');
|
|
@@ -893,22 +1155,19 @@ function ensureCoreDependency(_targetDir) {
|
|
|
893
1155
|
}
|
|
894
1156
|
async function installCoreDependencies() {
|
|
895
1157
|
const coreDir = getInstalledCoreDir();
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
await
|
|
901
|
-
|
|
902
|
-
|
|
1158
|
+
await prepareComponentDependencies(coreDir, 'Core');
|
|
1159
|
+
}
|
|
1160
|
+
async function installHostRuntimeDependencies() {
|
|
1161
|
+
const hostRuntimeDir = getInstalledHostRuntimeDir();
|
|
1162
|
+
await prepareComponentDependencies(hostRuntimeDir, 'Host runtime');
|
|
1163
|
+
}
|
|
1164
|
+
async function installPdCliDependencies() {
|
|
1165
|
+
const pdCliDir = getInstalledPdCliDir();
|
|
1166
|
+
await prepareComponentDependencies(pdCliDir, 'PD CLI');
|
|
903
1167
|
}
|
|
904
1168
|
async function installConsoleDependencies() {
|
|
905
1169
|
const consoleDest = getInstalledConsoleDir();
|
|
906
|
-
|
|
907
|
-
if (!existsSync(packageJsonPath)) {
|
|
908
|
-
throw new Error('Console package.json not found after copy — install is corrupted');
|
|
909
|
-
}
|
|
910
|
-
await runNpmInstall(consoleDest, 'Console');
|
|
911
|
-
await rebuildNativeModules(consoleDest, 'Console');
|
|
1170
|
+
await prepareComponentDependencies(consoleDest, 'Console');
|
|
912
1171
|
}
|
|
913
1172
|
const CONSOLE_PORT_MAX_RETRIES = 3;
|
|
914
1173
|
async function verifyConsole(workspaceDir) {
|
|
@@ -1336,11 +1595,44 @@ export async function install(options, pluginDir, mode = {}) {
|
|
|
1336
1595
|
// because jsonMode always implies non-interactive.
|
|
1337
1596
|
const quiet = mode.quiet === true;
|
|
1338
1597
|
const nonInteractive = mode.nonInteractive ?? quiet;
|
|
1598
|
+
activeHostTarget = options.host;
|
|
1599
|
+
if (!legacyNpmInstallEnabled()) {
|
|
1600
|
+
try {
|
|
1601
|
+
await preflightSelfContainedReleaseAsset(pluginDir);
|
|
1602
|
+
}
|
|
1603
|
+
catch (error) {
|
|
1604
|
+
const preflightError = error instanceof SelfContainedDependencyError
|
|
1605
|
+
? error
|
|
1606
|
+
: new SelfContainedDependencyError({
|
|
1607
|
+
reason: 'self_contained_asset_preflight_failed',
|
|
1608
|
+
nextAction: SELF_CONTAINED_DEPENDENCY_NEXT_ACTION,
|
|
1609
|
+
message: error instanceof Error ? error.message : String(error),
|
|
1610
|
+
component: 'Release asset',
|
|
1611
|
+
cause: error,
|
|
1612
|
+
});
|
|
1613
|
+
return {
|
|
1614
|
+
success: false,
|
|
1615
|
+
workspaceDir: options.workspaceDir,
|
|
1616
|
+
configYamlPath: getConfigYamlPath(options.workspaceDir),
|
|
1617
|
+
templatesCount: 0,
|
|
1618
|
+
components: { plugin: 'skipped', cli: 'skipped', console: 'skipped' },
|
|
1619
|
+
verification: { features: 'skipped', storyA: 'skipped' },
|
|
1620
|
+
enabledChannels: options.channels,
|
|
1621
|
+
nextAction: preflightError.nextAction,
|
|
1622
|
+
reason: preflightError.reason,
|
|
1623
|
+
component: preflightError.component,
|
|
1624
|
+
dependency: preflightError.dependency,
|
|
1625
|
+
error: `${preflightError.message} — ${t('rollback_no_changes')}`,
|
|
1626
|
+
};
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1339
1629
|
// Gateway lock pre-flight: a running gateway holds native-module file handles
|
|
1340
1630
|
// that make the backup rename fail with EPERM. Decide stop/abort/proceed
|
|
1341
1631
|
// BEFORE mutating anything (cli-5: abort/stop-failed paths must not mutate).
|
|
1342
1632
|
let restartedGateway = false;
|
|
1343
|
-
const gatewayStatus =
|
|
1633
|
+
const gatewayStatus = installsOpenClaw(options.host)
|
|
1634
|
+
? await checkOpenClawGateway()
|
|
1635
|
+
: { isRunning: false };
|
|
1344
1636
|
if (gatewayStatus.isRunning) {
|
|
1345
1637
|
const action = await resolveGatewayAction(gatewayStatus, {
|
|
1346
1638
|
stopGateway: options.stopGateway,
|
|
@@ -1376,6 +1668,8 @@ export async function install(options, pluginDir, mode = {}) {
|
|
|
1376
1668
|
}
|
|
1377
1669
|
const spinner = quiet ? null : ora('Installing...').start();
|
|
1378
1670
|
let backupDir = null;
|
|
1671
|
+
let runtimeBackupDir = null;
|
|
1672
|
+
let installManifestHosts;
|
|
1379
1673
|
const components = { plugin: 'skipped', cli: 'skipped', console: 'skipped' };
|
|
1380
1674
|
const verification = { features: 'skipped', storyA: 'skipped' };
|
|
1381
1675
|
let consoleProcess = null;
|
|
@@ -1416,22 +1710,33 @@ export async function install(options, pluginDir, mode = {}) {
|
|
|
1416
1710
|
stepIndex++;
|
|
1417
1711
|
if (spinner)
|
|
1418
1712
|
updateProgress(spinner, stepIndex, 'Backing up existing install...');
|
|
1419
|
-
|
|
1420
|
-
|
|
1713
|
+
// Validate the existing host-ownership record before mutating runtime or
|
|
1714
|
+
// host config. A malformed manifest must not be discovered only after the
|
|
1715
|
+
// old installation has already been replaced (rc-3/rc-9).
|
|
1716
|
+
installManifestHosts = resolveInstallManifestHosts(options.host);
|
|
1717
|
+
if (installsOpenClaw(options.host))
|
|
1718
|
+
migrateLegacyPdBackups();
|
|
1719
|
+
const { backupDir: backupDirFromResult, runtimeBackupDir: runtimeBackupDirFromResult } = backupExistingInstall(options.host);
|
|
1421
1720
|
backupDir = backupDirFromResult;
|
|
1721
|
+
runtimeBackupDir = runtimeBackupDirFromResult ?? null;
|
|
1422
1722
|
stepIndex++;
|
|
1423
1723
|
if (spinner)
|
|
1424
1724
|
updateProgress(spinner, stepIndex, 'Installing bundled @principles/core...');
|
|
1425
1725
|
installBundledCore(pluginDir);
|
|
1426
1726
|
stepIndex++;
|
|
1727
|
+
if (spinner)
|
|
1728
|
+
updateProgress(spinner, stepIndex, 'Validating bundled core dependencies...');
|
|
1729
|
+
await installCoreDependencies();
|
|
1730
|
+
stepIndex++;
|
|
1427
1731
|
if (spinner)
|
|
1428
1732
|
updateProgress(spinner, stepIndex, 'Installing bundled @principles/host-runtime...');
|
|
1429
1733
|
installBundledHostRuntime(pluginDir);
|
|
1430
1734
|
stepIndex++;
|
|
1431
1735
|
if (spinner)
|
|
1432
|
-
updateProgress(spinner, stepIndex, '
|
|
1433
|
-
await
|
|
1736
|
+
updateProgress(spinner, stepIndex, 'Validating bundled host runtime dependencies...');
|
|
1737
|
+
await installHostRuntimeDependencies();
|
|
1434
1738
|
stepIndex++;
|
|
1739
|
+
installBundledLayoutPackage(pluginDir);
|
|
1435
1740
|
if (spinner)
|
|
1436
1741
|
updateProgress(spinner, stepIndex, 'Installing plugin...');
|
|
1437
1742
|
await installPluginToStaging(pluginDir, options.language);
|
|
@@ -1441,13 +1746,14 @@ export async function install(options, pluginDir, mode = {}) {
|
|
|
1441
1746
|
ensureCoreDependency(getPluginExtDir());
|
|
1442
1747
|
stepIndex++;
|
|
1443
1748
|
if (spinner)
|
|
1444
|
-
updateProgress(spinner, stepIndex, '
|
|
1749
|
+
updateProgress(spinner, stepIndex, 'Validating bundled plugin dependencies...');
|
|
1445
1750
|
await installPluginDependencies();
|
|
1446
1751
|
components.plugin = 'verified';
|
|
1447
1752
|
stepIndex++;
|
|
1448
1753
|
if (spinner)
|
|
1449
1754
|
updateProgress(spinner, stepIndex, 'Installing pd CLI...');
|
|
1450
1755
|
syncPdCli(pluginDir);
|
|
1756
|
+
await installPdCliDependencies();
|
|
1451
1757
|
stepIndex++;
|
|
1452
1758
|
if (spinner)
|
|
1453
1759
|
updateProgress(spinner, stepIndex, 'Preparing core library for pd-cli...');
|
|
@@ -1457,7 +1763,7 @@ export async function install(options, pluginDir, mode = {}) {
|
|
|
1457
1763
|
updateProgress(spinner, stepIndex, 'Verifying pd CLI...');
|
|
1458
1764
|
const cliVerify = verifyPdCliShim();
|
|
1459
1765
|
if (!cliVerify.localOk) {
|
|
1460
|
-
throw new Error(
|
|
1766
|
+
throw new Error(`PD CLI verification failed — local shim is not executable after install: ${cliVerify.localError ?? 'unknown error'}. Check Node.js and PATH configuration.`);
|
|
1461
1767
|
}
|
|
1462
1768
|
if (cliVerify.globalOk) {
|
|
1463
1769
|
components.cli = 'verified';
|
|
@@ -1477,7 +1783,7 @@ export async function install(options, pluginDir, mode = {}) {
|
|
|
1477
1783
|
ensureCoreDependency(getInstalledConsoleDir());
|
|
1478
1784
|
stepIndex++;
|
|
1479
1785
|
if (spinner)
|
|
1480
|
-
updateProgress(spinner, stepIndex, '
|
|
1786
|
+
updateProgress(spinner, stepIndex, 'Validating bundled console dependencies...');
|
|
1481
1787
|
await installConsoleDependencies();
|
|
1482
1788
|
stepIndex++;
|
|
1483
1789
|
if (spinner)
|
|
@@ -1594,14 +1900,13 @@ export async function install(options, pluginDir, mode = {}) {
|
|
|
1594
1900
|
logger.info(`Host "${hr.hostId}" install: ${hr.reason ?? 'skipped'}. Next: ${hr.nextAction}`);
|
|
1595
1901
|
}
|
|
1596
1902
|
}
|
|
1597
|
-
|
|
1903
|
+
if (hostFailures.length > 0) {
|
|
1904
|
+
throw new Error(`Host installation failed: ${hostFailures.join(' | ')}`);
|
|
1905
|
+
}
|
|
1906
|
+
writeInstallManifest(installManifestHosts);
|
|
1907
|
+
cleanupBackup(backupDir, runtimeBackupDir);
|
|
1598
1908
|
if (spinner) {
|
|
1599
|
-
|
|
1600
|
-
spinner.warn('Install complete with host warnings');
|
|
1601
|
-
}
|
|
1602
|
-
else {
|
|
1603
|
-
spinner.succeed('Install complete!');
|
|
1604
|
-
}
|
|
1909
|
+
spinner.succeed('Install complete!');
|
|
1605
1910
|
}
|
|
1606
1911
|
killConsoleChild();
|
|
1607
1912
|
// Task 8: auto-launch console via `pd console open` (reuses PRI-300
|
|
@@ -1614,7 +1919,6 @@ export async function install(options, pluginDir, mode = {}) {
|
|
|
1614
1919
|
// A host installer failure means the install is not fully successful,
|
|
1615
1920
|
// even if all component verifications passed. The operator should see
|
|
1616
1921
|
// success=false and be guided to fix the failed host.
|
|
1617
|
-
const hasHostFailures = hostFailures.length > 0;
|
|
1618
1922
|
const nextActions = [];
|
|
1619
1923
|
if (components.cli === 'verified') {
|
|
1620
1924
|
nextActions.push(`pd runtime canary --workspace "${options.workspaceDir}" --json`);
|
|
@@ -1635,10 +1939,8 @@ export async function install(options, pluginDir, mode = {}) {
|
|
|
1635
1939
|
if (launchResult.fallbackAction) {
|
|
1636
1940
|
nextActions.push(launchResult.fallbackAction);
|
|
1637
1941
|
}
|
|
1638
|
-
// Append host-failure remediation actions so the operator knows what to fix.
|
|
1639
|
-
nextActions.push(...hostFailures);
|
|
1640
1942
|
return {
|
|
1641
|
-
success: isComplete
|
|
1943
|
+
success: isComplete,
|
|
1642
1944
|
workspaceDir: options.workspaceDir,
|
|
1643
1945
|
configYamlPath,
|
|
1644
1946
|
templatesCount: templatesCount + principlesCount,
|
|
@@ -1654,7 +1956,7 @@ export async function install(options, pluginDir, mode = {}) {
|
|
|
1654
1956
|
if (spinner)
|
|
1655
1957
|
spinner.fail('Install failed');
|
|
1656
1958
|
killConsoleChild();
|
|
1657
|
-
const restoreResult = restoreBackup(backupDir);
|
|
1959
|
+
const restoreResult = restoreBackup(backupDir, runtimeBackupDir);
|
|
1658
1960
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
1659
1961
|
// ERR-046 / rc-9: never claim a restore that didn't happen. When backupDir
|
|
1660
1962
|
// is null, the backup step never completed (it threw — e.g. EPERM — or
|
|
@@ -1664,15 +1966,16 @@ export async function install(options, pluginDir, mode = {}) {
|
|
|
1664
1966
|
const isLockError = /EPERM|EBUSY|EACCES|operation not permitted/i.test(errorMsg);
|
|
1665
1967
|
const extDir = getPluginExtDir();
|
|
1666
1968
|
// EP-11: all operator-visible failure/rollback text goes through t().
|
|
1667
|
-
const
|
|
1969
|
+
const hasBackup = Boolean(backupDir || runtimeBackupDir);
|
|
1970
|
+
const rollbackSuffix = !hasBackup
|
|
1668
1971
|
? t('rollback_no_changes')
|
|
1669
1972
|
: restoreResult.restored
|
|
1670
1973
|
? t('rollback_restored')
|
|
1671
1974
|
: t('rollback_failed')
|
|
1672
1975
|
.replace('{restoreError}', restoreResult.error ?? '')
|
|
1673
1976
|
.replace('{extDir}', extDir)
|
|
1674
|
-
.replace('{backupDir}', backupDir);
|
|
1675
|
-
const
|
|
1977
|
+
.replace('{backupDir}', backupDir ?? runtimeBackupDir ?? '');
|
|
1978
|
+
const rollbackNextAction = !hasBackup
|
|
1676
1979
|
? (isLockError
|
|
1677
1980
|
? t('next_no_changes_lock')
|
|
1678
1981
|
: t('next_no_changes_other'))
|
|
@@ -1680,13 +1983,19 @@ export async function install(options, pluginDir, mode = {}) {
|
|
|
1680
1983
|
? t('next_restored')
|
|
1681
1984
|
: t('next_restore_failed')
|
|
1682
1985
|
.replace('{extDir}', extDir)
|
|
1683
|
-
.replace('{backupDir}', backupDir)
|
|
1986
|
+
.replace('{backupDir}', backupDir ?? runtimeBackupDir ?? '')
|
|
1684
1987
|
.replace('{errorMsg}', errorMsg);
|
|
1685
|
-
const
|
|
1988
|
+
const rollbackReason = !hasBackup
|
|
1686
1989
|
? (isLockError ? `install_aborted_lock: ${errorMsg}` : `install_failed_before_mutation: ${errorMsg}`)
|
|
1687
1990
|
: restoreResult.restored
|
|
1688
1991
|
? errorMsg
|
|
1689
1992
|
: `install_failed_rollback_failed: ${errorMsg}`;
|
|
1993
|
+
const nextAction = error instanceof SelfContainedDependencyError
|
|
1994
|
+
? restoreResult.restored || !hasBackup
|
|
1995
|
+
? error.nextAction
|
|
1996
|
+
: `${error.nextAction} ${rollbackNextAction}`
|
|
1997
|
+
: rollbackNextAction;
|
|
1998
|
+
const reason = error instanceof SelfContainedDependencyError ? error.reason : rollbackReason;
|
|
1690
1999
|
return {
|
|
1691
2000
|
success: false,
|
|
1692
2001
|
workspaceDir: options.workspaceDir,
|
|
@@ -1697,6 +2006,8 @@ export async function install(options, pluginDir, mode = {}) {
|
|
|
1697
2006
|
enabledChannels: options.channels,
|
|
1698
2007
|
nextAction,
|
|
1699
2008
|
reason,
|
|
2009
|
+
component: error instanceof SelfContainedDependencyError ? error.component : undefined,
|
|
2010
|
+
dependency: error instanceof SelfContainedDependencyError ? error.dependency : undefined,
|
|
1700
2011
|
error: `${errorMsg} — ${rollbackSuffix}`,
|
|
1701
2012
|
};
|
|
1702
2013
|
}
|