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
|
@@ -7,7 +7,15 @@ export * from './pd-config.js';
|
|
|
7
7
|
export * from './production-rulehost-gate.js';
|
|
8
8
|
export * from './rule-implementation-runtime.js';
|
|
9
9
|
export * from './production-pain-evidence.js';
|
|
10
|
+
export * from './governance-observation-store.js';
|
|
10
11
|
export * from './host-liveness-contract.js';
|
|
12
|
+
// Anonymous Product Telemetry v1 (PRI-595~603) — opt-in, default-off,
|
|
13
|
+
// read-only with respect to all PD governance facts.
|
|
14
|
+
export * from './product-telemetry/consent-store.js';
|
|
15
|
+
export * from './product-telemetry/eligibility.js';
|
|
16
|
+
export * from './product-telemetry/exporter.js';
|
|
17
|
+
export * from './product-telemetry/milestone-readers.js';
|
|
18
|
+
export * from './product-telemetry/service.js';
|
|
11
19
|
export const HOST_RUNTIME_ROUTES = [
|
|
12
20
|
'before_prompt_build',
|
|
13
21
|
'before_tool_call',
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Product telemetry control-state store — Anonymous Product Telemetry v1
|
|
3
|
+
* (PRI-597, SPEC §44; review remediation: workspace-scoped export state).
|
|
4
|
+
*
|
|
5
|
+
* Persists the telemetry control state to `~/.pd/product-telemetry.json`.
|
|
6
|
+
* This file is Telemetry Control State — it never enters
|
|
7
|
+
* Principle/Pain/receipt/governance stores, and the secret never leaves the
|
|
8
|
+
* machine.
|
|
9
|
+
*
|
|
10
|
+
* Scope model (schema v2, review remediation P1-1):
|
|
11
|
+
* - MACHINE scope: consent, consentVersion, telemetrySecret.
|
|
12
|
+
* - WORKSPACE scope: `workspaceExports[scopeId]` — per-workspace dedup,
|
|
13
|
+
* retry, and attempt bookkeeping keyed by the opaque local scope ID
|
|
14
|
+
* (HMAC(secret, canonical workspace path); never uploaded). One
|
|
15
|
+
* workspace succeeding must never suppress another workspace's export.
|
|
16
|
+
*
|
|
17
|
+
* Migration from schema v1: consent, consentVersion, and telemetrySecret are
|
|
18
|
+
* preserved; legacy machine-global export bookkeeping (lastSucceededAt,
|
|
19
|
+
* retry state, attempt counters) is DISCARDED — it cannot be attributed to a
|
|
20
|
+
* workspace, and it is operational state, not a governance fact. Dropping it
|
|
21
|
+
* can cause at most one extra same-day snapshot per installation.
|
|
22
|
+
*/
|
|
23
|
+
export declare const PRODUCT_TELEMETRY_STATE_FILENAME = "product-telemetry.json";
|
|
24
|
+
export declare const PRODUCT_TELEMETRY_CONTROL_SCHEMA_VERSION = "2";
|
|
25
|
+
/** v1 files are still read (then migrated in memory and rewritten as v2). */
|
|
26
|
+
export declare const PRODUCT_TELEMETRY_LEGACY_CONTROL_SCHEMA_VERSION = "1";
|
|
27
|
+
/** Hard bound on tracked workspaces so the file cannot grow unboundedly. */
|
|
28
|
+
export declare const MAX_WORKSPACE_EXPORT_ENTRIES = 200;
|
|
29
|
+
/**
|
|
30
|
+
* Entries untouched for this long are pruned on the next write. This is local
|
|
31
|
+
* telemetry operational state only — no workspace history is retained.
|
|
32
|
+
*/
|
|
33
|
+
export declare const WORKSPACE_EXPORT_STATE_MAX_AGE_DAYS = 30;
|
|
34
|
+
export type ProductTelemetryConsent = 'unset' | 'granted' | 'denied';
|
|
35
|
+
/** Per-workspace export bookkeeping (operational state; never exported). */
|
|
36
|
+
export interface WorkspaceExportState {
|
|
37
|
+
lastAttemptedAt?: string;
|
|
38
|
+
lastSucceededAt?: string;
|
|
39
|
+
/** Coarse failure code (TelemetryFailureCode). No response bodies. */
|
|
40
|
+
lastFailureCode?: string;
|
|
41
|
+
nextRetryAt?: string;
|
|
42
|
+
/** Failed export attempts in the current attemptBucketDate (0–99; hard cap enforced by the service). */
|
|
43
|
+
dailyAttemptCount?: number;
|
|
44
|
+
/** UTC date bucket the dailyAttemptCount belongs to (resets on day change). */
|
|
45
|
+
attemptBucketDate?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface ProductTelemetryControlState {
|
|
48
|
+
consent: ProductTelemetryConsent;
|
|
49
|
+
consentVersion: string;
|
|
50
|
+
/** Cryptographically random hex secret. Never uploaded. */
|
|
51
|
+
telemetrySecret?: string;
|
|
52
|
+
/** Per-workspace export bookkeeping keyed by opaque local scope ID. */
|
|
53
|
+
workspaceExports?: Record<string, WorkspaceExportState>;
|
|
54
|
+
schemaVersion: string;
|
|
55
|
+
}
|
|
56
|
+
export type ControlStateRead = {
|
|
57
|
+
ok: true;
|
|
58
|
+
state: ProductTelemetryControlState;
|
|
59
|
+
existed: boolean;
|
|
60
|
+
} | {
|
|
61
|
+
ok: false;
|
|
62
|
+
reason: string;
|
|
63
|
+
nextAction: string;
|
|
64
|
+
};
|
|
65
|
+
export type ControlStateWrite = {
|
|
66
|
+
ok: true;
|
|
67
|
+
} | {
|
|
68
|
+
ok: false;
|
|
69
|
+
reason: string;
|
|
70
|
+
nextAction: string;
|
|
71
|
+
};
|
|
72
|
+
export declare function defaultProductTelemetryControlState(): ProductTelemetryControlState;
|
|
73
|
+
export declare function getProductTelemetryStatePath(homeDir: string): string;
|
|
74
|
+
/**
|
|
75
|
+
* Read and validate the control state. A missing file is the normal
|
|
76
|
+
* never-configured case (defaults, existed=false). A malformed file is a
|
|
77
|
+
* loud failure — silently treating it as "unset" could re-prompt or re-export
|
|
78
|
+
* against the user's recorded decision (rc-3/rc-9).
|
|
79
|
+
*
|
|
80
|
+
* v1 files are migrated in memory (export bookkeeping dropped, consent
|
|
81
|
+
* identity preserved); the migration is persisted on the next write.
|
|
82
|
+
*/
|
|
83
|
+
export declare function readProductTelemetryControlState(homeDir: string): ControlStateRead;
|
|
84
|
+
/**
|
|
85
|
+
* Drop `workspaceExports` entries whose most recent activity (attempt or
|
|
86
|
+
* success) is older than WORKSPACE_EXPORT_STATE_MAX_AGE_DAYS. Bounded local
|
|
87
|
+
* operational state only — this is not a workspace history database.
|
|
88
|
+
*/
|
|
89
|
+
export declare function pruneWorkspaceExports(state: ProductTelemetryControlState, nowMs: number): ProductTelemetryControlState;
|
|
90
|
+
/** Atomic write (temp file + rename) so a crash never truncates the state. */
|
|
91
|
+
export declare function writeProductTelemetryControlState(homeDir: string, state: ProductTelemetryControlState): ControlStateWrite;
|
|
92
|
+
/** State after `pd telemetry enable`: explicit granted consent + secret. */
|
|
93
|
+
export declare function grantedControlState(previous: ProductTelemetryControlState): ProductTelemetryControlState;
|
|
94
|
+
/**
|
|
95
|
+
* State after `pd telemetry disable`: consent denied and all export identity
|
|
96
|
+
* removed (SPEC §19). The explicit `denied` choice is preserved so PD never
|
|
97
|
+
* re-prompts.
|
|
98
|
+
*/
|
|
99
|
+
export declare function deniedControlState(): ProductTelemetryControlState;
|
|
100
|
+
/**
|
|
101
|
+
* State after `pd telemetry reset` (SPEC §18): secret and export status are
|
|
102
|
+
* deleted — no future daily ID relates to previous ones. The consent choice
|
|
103
|
+
* is preserved; a fresh secret is generated only while telemetry remains
|
|
104
|
+
* enabled. Workspace bookkeeping keyed under the OLD secret's scope IDs is
|
|
105
|
+
* dropped with it (the IDs are meaningless under a new secret).
|
|
106
|
+
*/
|
|
107
|
+
export declare function resetControlState(previous: ProductTelemetryControlState): ProductTelemetryControlState;
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Product telemetry control-state store — Anonymous Product Telemetry v1
|
|
3
|
+
* (PRI-597, SPEC §44; review remediation: workspace-scoped export state).
|
|
4
|
+
*
|
|
5
|
+
* Persists the telemetry control state to `~/.pd/product-telemetry.json`.
|
|
6
|
+
* This file is Telemetry Control State — it never enters
|
|
7
|
+
* Principle/Pain/receipt/governance stores, and the secret never leaves the
|
|
8
|
+
* machine.
|
|
9
|
+
*
|
|
10
|
+
* Scope model (schema v2, review remediation P1-1):
|
|
11
|
+
* - MACHINE scope: consent, consentVersion, telemetrySecret.
|
|
12
|
+
* - WORKSPACE scope: `workspaceExports[scopeId]` — per-workspace dedup,
|
|
13
|
+
* retry, and attempt bookkeeping keyed by the opaque local scope ID
|
|
14
|
+
* (HMAC(secret, canonical workspace path); never uploaded). One
|
|
15
|
+
* workspace succeeding must never suppress another workspace's export.
|
|
16
|
+
*
|
|
17
|
+
* Migration from schema v1: consent, consentVersion, and telemetrySecret are
|
|
18
|
+
* preserved; legacy machine-global export bookkeeping (lastSucceededAt,
|
|
19
|
+
* retry state, attempt counters) is DISCARDED — it cannot be attributed to a
|
|
20
|
+
* workspace, and it is operational state, not a governance fact. Dropping it
|
|
21
|
+
* can cause at most one extra same-day snapshot per installation.
|
|
22
|
+
*/
|
|
23
|
+
import fs from 'node:fs';
|
|
24
|
+
import path from 'node:path';
|
|
25
|
+
import { generateTelemetrySecretHex, isValidBucketDate, isValidTelemetrySecretHex, PRODUCT_TELEMETRY_CONSENT_VERSION, } from '@principles/core/runtime-v2';
|
|
26
|
+
export const PRODUCT_TELEMETRY_STATE_FILENAME = 'product-telemetry.json';
|
|
27
|
+
export const PRODUCT_TELEMETRY_CONTROL_SCHEMA_VERSION = '2';
|
|
28
|
+
/** v1 files are still read (then migrated in memory and rewritten as v2). */
|
|
29
|
+
export const PRODUCT_TELEMETRY_LEGACY_CONTROL_SCHEMA_VERSION = '1';
|
|
30
|
+
/** Hard bound on tracked workspaces so the file cannot grow unboundedly. */
|
|
31
|
+
export const MAX_WORKSPACE_EXPORT_ENTRIES = 200;
|
|
32
|
+
/**
|
|
33
|
+
* Entries untouched for this long are pruned on the next write. This is local
|
|
34
|
+
* telemetry operational state only — no workspace history is retained.
|
|
35
|
+
*/
|
|
36
|
+
export const WORKSPACE_EXPORT_STATE_MAX_AGE_DAYS = 30;
|
|
37
|
+
export function defaultProductTelemetryControlState() {
|
|
38
|
+
return { consent: 'unset', consentVersion: PRODUCT_TELEMETRY_CONSENT_VERSION, schemaVersion: PRODUCT_TELEMETRY_CONTROL_SCHEMA_VERSION };
|
|
39
|
+
}
|
|
40
|
+
export function getProductTelemetryStatePath(homeDir) {
|
|
41
|
+
return path.join(path.resolve(homeDir), '.pd', PRODUCT_TELEMETRY_STATE_FILENAME);
|
|
42
|
+
}
|
|
43
|
+
function isConsent(value) {
|
|
44
|
+
return value === 'unset' || value === 'granted' || value === 'denied';
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Optional timestamp fields must be parseable dates, not just short strings —
|
|
48
|
+
* a "garbage" lastSucceededAt/nextRetryAt would otherwise slip validation and
|
|
49
|
+
* turn into NaN inside Date.parse, silently skipping same-day dedup or retry
|
|
50
|
+
* backoff (fail-loud contract, review round 2).
|
|
51
|
+
*/
|
|
52
|
+
function isOptionalIsoString(value) {
|
|
53
|
+
if (value === undefined)
|
|
54
|
+
return true;
|
|
55
|
+
if (typeof value !== 'string' || value.length === 0 || value.length > 40)
|
|
56
|
+
return false;
|
|
57
|
+
return !Number.isNaN(Date.parse(value));
|
|
58
|
+
}
|
|
59
|
+
function isOptionalAttemptBucketDate(value) {
|
|
60
|
+
if (value === undefined)
|
|
61
|
+
return true;
|
|
62
|
+
return isValidBucketDate(value);
|
|
63
|
+
}
|
|
64
|
+
function isOptionalAttemptCount(value) {
|
|
65
|
+
return value === undefined || (typeof value === 'number' && Number.isInteger(value) && value >= 0 && value <= 99);
|
|
66
|
+
}
|
|
67
|
+
function isOptionalFailureCode(value) {
|
|
68
|
+
return value === undefined || (typeof value === 'string' && value.length > 0 && value.length <= 40);
|
|
69
|
+
}
|
|
70
|
+
function isScopeKey(value) {
|
|
71
|
+
return typeof value === 'string' && /^[0-9a-f]{4,32}$/.test(value);
|
|
72
|
+
}
|
|
73
|
+
/** Validate one `workspaceExports` entry; collect errors under `prefix`. */
|
|
74
|
+
function workspaceExportErrors(entry, prefix) {
|
|
75
|
+
const errors = [];
|
|
76
|
+
for (const key of Object.keys(entry)) {
|
|
77
|
+
if (!['lastAttemptedAt', 'lastSucceededAt', 'lastFailureCode', 'nextRetryAt', 'dailyAttemptCount', 'attemptBucketDate'].includes(key)) {
|
|
78
|
+
errors.push(`${prefix}: unknown field '${key}'`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (!isOptionalIsoString(entry.lastAttemptedAt) || !isOptionalIsoString(entry.lastSucceededAt) || !isOptionalIsoString(entry.nextRetryAt)) {
|
|
82
|
+
errors.push(`${prefix}: timestamps must be parseable ISO-8601 strings (≤40 chars) when present`);
|
|
83
|
+
}
|
|
84
|
+
if (!isOptionalAttemptCount(entry.dailyAttemptCount))
|
|
85
|
+
errors.push(`${prefix}: dailyAttemptCount must be an integer 0–99 when present`);
|
|
86
|
+
if (!isOptionalAttemptBucketDate(entry.attemptBucketDate))
|
|
87
|
+
errors.push(`${prefix}: attemptBucketDate must be a valid YYYY-MM-DD UTC date when present`);
|
|
88
|
+
if (!isOptionalFailureCode(entry.lastFailureCode))
|
|
89
|
+
errors.push(`${prefix}: lastFailureCode must be a short non-empty string when present`);
|
|
90
|
+
return errors;
|
|
91
|
+
}
|
|
92
|
+
function isPlainRecord(value) {
|
|
93
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Read and validate the control state. A missing file is the normal
|
|
97
|
+
* never-configured case (defaults, existed=false). A malformed file is a
|
|
98
|
+
* loud failure — silently treating it as "unset" could re-prompt or re-export
|
|
99
|
+
* against the user's recorded decision (rc-3/rc-9).
|
|
100
|
+
*
|
|
101
|
+
* v1 files are migrated in memory (export bookkeeping dropped, consent
|
|
102
|
+
* identity preserved); the migration is persisted on the next write.
|
|
103
|
+
*/
|
|
104
|
+
export function readProductTelemetryControlState(homeDir) {
|
|
105
|
+
const filePath = getProductTelemetryStatePath(homeDir);
|
|
106
|
+
let raw;
|
|
107
|
+
try {
|
|
108
|
+
raw = fs.readFileSync(filePath, 'utf8');
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
// Guarded code access (rc-1/rc-2: runtime check before use; rc-5:
|
|
112
|
+
// Object.hasOwn on untrusted objects; no NodeJS namespace in this config).
|
|
113
|
+
const codeValue = typeof error === 'object' && error !== null && Object.hasOwn(error, 'code')
|
|
114
|
+
? error.code
|
|
115
|
+
: undefined;
|
|
116
|
+
const code = typeof codeValue === 'string' ? codeValue : undefined;
|
|
117
|
+
if (code === 'ENOENT') {
|
|
118
|
+
return { ok: true, state: defaultProductTelemetryControlState(), existed: false };
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
ok: false,
|
|
122
|
+
reason: `product_telemetry_state_unreadable: ${code ?? String(error)}`,
|
|
123
|
+
nextAction: `Check permissions on ${filePath}`,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
let parsed;
|
|
127
|
+
try {
|
|
128
|
+
parsed = JSON.parse(raw);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
return {
|
|
132
|
+
ok: false,
|
|
133
|
+
reason: 'product_telemetry_state_malformed_json',
|
|
134
|
+
nextAction: `Fix or delete ${filePath} (delete = consent returns to unset)`,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
138
|
+
return {
|
|
139
|
+
ok: false,
|
|
140
|
+
reason: 'product_telemetry_state_malformed_shape',
|
|
141
|
+
nextAction: `Fix or delete ${filePath} (delete = consent returns to unset)`,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
const obj = parsed;
|
|
145
|
+
const { schemaVersion } = obj;
|
|
146
|
+
const isV1 = schemaVersion === PRODUCT_TELEMETRY_LEGACY_CONTROL_SCHEMA_VERSION;
|
|
147
|
+
const isV2 = schemaVersion === PRODUCT_TELEMETRY_CONTROL_SCHEMA_VERSION;
|
|
148
|
+
if (!isV1 && !isV2) {
|
|
149
|
+
return {
|
|
150
|
+
ok: false,
|
|
151
|
+
reason: `product_telemetry_state_malformed: schemaVersion must be '${PRODUCT_TELEMETRY_CONTROL_SCHEMA_VERSION}' or legacy '${PRODUCT_TELEMETRY_LEGACY_CONTROL_SCHEMA_VERSION}'`,
|
|
152
|
+
nextAction: `Fix or delete ${filePath} (delete = consent returns to unset)`,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
// v1 machine-global export fields exist only in v1 files; v2 files carry
|
|
156
|
+
// workspaceExports instead. Unknown keys are rejected per shape.
|
|
157
|
+
const allowedKeys = isV1
|
|
158
|
+
? ['consent', 'consentVersion', 'telemetrySecret', 'lastAttemptedAt', 'lastSucceededAt', 'lastFailureCode', 'nextRetryAt', 'dailyAttemptCount', 'attemptBucketDate', 'schemaVersion']
|
|
159
|
+
: ['consent', 'consentVersion', 'telemetrySecret', 'workspaceExports', 'schemaVersion'];
|
|
160
|
+
const errors = [];
|
|
161
|
+
for (const key of Object.keys(obj)) {
|
|
162
|
+
if (!allowedKeys.includes(key)) {
|
|
163
|
+
errors.push(`unknown field '${key}'`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (!isConsent(obj.consent))
|
|
167
|
+
errors.push('consent must be unset|granted|denied');
|
|
168
|
+
if (typeof obj.consentVersion !== 'string' || obj.consentVersion.length === 0 || obj.consentVersion.length > 8)
|
|
169
|
+
errors.push('consentVersion must be a short non-empty string');
|
|
170
|
+
if (!isValidTelemetrySecretHex(obj.telemetrySecret) && obj.telemetrySecret !== undefined)
|
|
171
|
+
errors.push('telemetrySecret must be 64 hex chars when present');
|
|
172
|
+
if (isV1) {
|
|
173
|
+
// v1 legacy export fields are migrated by DISCARDING them — validating
|
|
174
|
+
// values that are about to be dropped would only turn a smooth migration
|
|
175
|
+
// into a hard failure (the identity fields carry the user's decision).
|
|
176
|
+
// Only the field-NAME allowlist above still applies to v1 files.
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
if (obj.workspaceExports !== undefined) {
|
|
180
|
+
if (typeof obj.workspaceExports !== 'object' || obj.workspaceExports === null || Array.isArray(obj.workspaceExports)) {
|
|
181
|
+
errors.push('workspaceExports must be an object');
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
const entries = obj.workspaceExports;
|
|
185
|
+
const scopeKeys = Object.keys(entries);
|
|
186
|
+
if (scopeKeys.length > MAX_WORKSPACE_EXPORT_ENTRIES) {
|
|
187
|
+
errors.push(`workspaceExports must track at most ${MAX_WORKSPACE_EXPORT_ENTRIES} workspaces`);
|
|
188
|
+
}
|
|
189
|
+
for (const scopeKey of scopeKeys) {
|
|
190
|
+
if (!isScopeKey(scopeKey)) {
|
|
191
|
+
errors.push(`workspaceExports key '${scopeKey}' must be 4–32 hex chars`);
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
const entry = entries[scopeKey];
|
|
195
|
+
if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) {
|
|
196
|
+
errors.push(`workspaceExports['${scopeKey}'] must be an object`);
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
errors.push(...workspaceExportErrors(entry, `workspaceExports['${scopeKey}']`));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (errors.length > 0) {
|
|
205
|
+
return {
|
|
206
|
+
ok: false,
|
|
207
|
+
reason: `product_telemetry_state_malformed: ${errors.join('; ')}`,
|
|
208
|
+
nextAction: `Fix or delete ${filePath} (delete = consent returns to unset)`,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
// Post-validation reconstruction from guard-narrowed fields — no `as` on
|
|
212
|
+
// the untrusted parsed object (rc-2). isConsent is a type guard; the
|
|
213
|
+
// optional-field spreads carry only guard-passing values. v1 export
|
|
214
|
+
// bookkeeping is deliberately NOT carried over (see module doc).
|
|
215
|
+
const state = {
|
|
216
|
+
consent: isConsent(obj.consent) ? obj.consent : 'unset',
|
|
217
|
+
consentVersion: typeof obj.consentVersion === 'string' ? obj.consentVersion : PRODUCT_TELEMETRY_CONSENT_VERSION,
|
|
218
|
+
...(isValidTelemetrySecretHex(obj.telemetrySecret) ? { telemetrySecret: obj.telemetrySecret } : {}),
|
|
219
|
+
...(isV2 && isPlainRecord(obj.workspaceExports)
|
|
220
|
+
? {
|
|
221
|
+
workspaceExports: Object.fromEntries(Object.entries(obj.workspaceExports)
|
|
222
|
+
.filter(([scopeKey, entry]) => isScopeKey(scopeKey) && isPlainRecord(entry))
|
|
223
|
+
.map(([scopeKey, entry]) => {
|
|
224
|
+
const record = entry;
|
|
225
|
+
return [
|
|
226
|
+
scopeKey,
|
|
227
|
+
{
|
|
228
|
+
...(isOptionalIsoString(record.lastAttemptedAt) && record.lastAttemptedAt !== undefined ? { lastAttemptedAt: record.lastAttemptedAt } : {}),
|
|
229
|
+
...(isOptionalIsoString(record.lastSucceededAt) && record.lastSucceededAt !== undefined ? { lastSucceededAt: record.lastSucceededAt } : {}),
|
|
230
|
+
...(isOptionalIsoString(record.nextRetryAt) && record.nextRetryAt !== undefined ? { nextRetryAt: record.nextRetryAt } : {}),
|
|
231
|
+
...(isOptionalFailureCode(record.lastFailureCode) && record.lastFailureCode !== undefined ? { lastFailureCode: record.lastFailureCode } : {}),
|
|
232
|
+
...(isOptionalAttemptCount(record.dailyAttemptCount) && record.dailyAttemptCount !== undefined ? { dailyAttemptCount: record.dailyAttemptCount } : {}),
|
|
233
|
+
...(isOptionalAttemptBucketDate(record.attemptBucketDate) && record.attemptBucketDate !== undefined ? { attemptBucketDate: record.attemptBucketDate } : {}),
|
|
234
|
+
},
|
|
235
|
+
];
|
|
236
|
+
})),
|
|
237
|
+
}
|
|
238
|
+
: {}),
|
|
239
|
+
schemaVersion: PRODUCT_TELEMETRY_CONTROL_SCHEMA_VERSION,
|
|
240
|
+
};
|
|
241
|
+
if (state.workspaceExports !== undefined && Object.keys(state.workspaceExports).length === 0) {
|
|
242
|
+
delete state.workspaceExports;
|
|
243
|
+
}
|
|
244
|
+
return { ok: true, state, existed: true };
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Drop `workspaceExports` entries whose most recent activity (attempt or
|
|
248
|
+
* success) is older than WORKSPACE_EXPORT_STATE_MAX_AGE_DAYS. Bounded local
|
|
249
|
+
* operational state only — this is not a workspace history database.
|
|
250
|
+
*/
|
|
251
|
+
export function pruneWorkspaceExports(state, nowMs) {
|
|
252
|
+
const exports = state.workspaceExports;
|
|
253
|
+
if (exports === undefined)
|
|
254
|
+
return state;
|
|
255
|
+
const cutoff = nowMs - WORKSPACE_EXPORT_STATE_MAX_AGE_DAYS * 24 * 60 * 60 * 1000;
|
|
256
|
+
const kept = {};
|
|
257
|
+
for (const [scopeKey, entry] of Object.entries(exports)) {
|
|
258
|
+
const stamps = [entry.lastAttemptedAt, entry.lastSucceededAt].filter((s) => s !== undefined).map((s) => Date.parse(s));
|
|
259
|
+
const latest = stamps.length > 0 ? Math.max(...stamps) : Number.NEGATIVE_INFINITY;
|
|
260
|
+
if (Number.isNaN(latest) || latest < cutoff)
|
|
261
|
+
continue;
|
|
262
|
+
kept[scopeKey] = entry;
|
|
263
|
+
}
|
|
264
|
+
const next = { ...state };
|
|
265
|
+
if (Object.keys(kept).length > 0)
|
|
266
|
+
next.workspaceExports = kept;
|
|
267
|
+
else
|
|
268
|
+
delete next.workspaceExports;
|
|
269
|
+
return next;
|
|
270
|
+
}
|
|
271
|
+
/** Atomic write (temp file + rename) so a crash never truncates the state. */
|
|
272
|
+
export function writeProductTelemetryControlState(homeDir, state) {
|
|
273
|
+
const filePath = getProductTelemetryStatePath(homeDir);
|
|
274
|
+
const dir = path.dirname(filePath);
|
|
275
|
+
const tmpPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
276
|
+
try {
|
|
277
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
278
|
+
fs.writeFileSync(tmpPath, `${JSON.stringify(state, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 });
|
|
279
|
+
fs.renameSync(tmpPath, filePath);
|
|
280
|
+
return { ok: true };
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
284
|
+
try {
|
|
285
|
+
fs.rmSync(tmpPath, { force: true });
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
// best-effort cleanup; the write failure below is the loud signal
|
|
289
|
+
}
|
|
290
|
+
return {
|
|
291
|
+
ok: false,
|
|
292
|
+
reason: `product_telemetry_state_write_failed: ${message}`,
|
|
293
|
+
nextAction: `Check permissions on ${dir}`,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
/** State after `pd telemetry enable`: explicit granted consent + secret. */
|
|
298
|
+
export function grantedControlState(previous) {
|
|
299
|
+
return {
|
|
300
|
+
consent: 'granted',
|
|
301
|
+
consentVersion: PRODUCT_TELEMETRY_CONSENT_VERSION,
|
|
302
|
+
telemetrySecret: isValidTelemetrySecretHex(previous.telemetrySecret) ? previous.telemetrySecret : generateTelemetrySecretHex(),
|
|
303
|
+
...(previous.workspaceExports !== undefined ? { workspaceExports: previous.workspaceExports } : {}),
|
|
304
|
+
schemaVersion: PRODUCT_TELEMETRY_CONTROL_SCHEMA_VERSION,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* State after `pd telemetry disable`: consent denied and all export identity
|
|
309
|
+
* removed (SPEC §19). The explicit `denied` choice is preserved so PD never
|
|
310
|
+
* re-prompts.
|
|
311
|
+
*/
|
|
312
|
+
export function deniedControlState() {
|
|
313
|
+
return { consent: 'denied', consentVersion: PRODUCT_TELEMETRY_CONSENT_VERSION, schemaVersion: PRODUCT_TELEMETRY_CONTROL_SCHEMA_VERSION };
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* State after `pd telemetry reset` (SPEC §18): secret and export status are
|
|
317
|
+
* deleted — no future daily ID relates to previous ones. The consent choice
|
|
318
|
+
* is preserved; a fresh secret is generated only while telemetry remains
|
|
319
|
+
* enabled. Workspace bookkeeping keyed under the OLD secret's scope IDs is
|
|
320
|
+
* dropped with it (the IDs are meaningless under a new secret).
|
|
321
|
+
*/
|
|
322
|
+
export function resetControlState(previous) {
|
|
323
|
+
return {
|
|
324
|
+
consent: previous.consent,
|
|
325
|
+
consentVersion: PRODUCT_TELEMETRY_CONSENT_VERSION,
|
|
326
|
+
...(previous.consent === 'granted' ? { telemetrySecret: generateTelemetrySecretHex() } : {}),
|
|
327
|
+
schemaVersion: PRODUCT_TELEMETRY_CONTROL_SCHEMA_VERSION,
|
|
328
|
+
};
|
|
329
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Production eligibility — Anonymous Product Telemetry v1
|
|
3
|
+
* (PRI-597, SPEC §35-§37).
|
|
4
|
+
*
|
|
5
|
+
* Environment suppression is evaluated independently of consent and the
|
|
6
|
+
* feature flag (both are AND-ed by the service). Every suppression reason is
|
|
7
|
+
* named in the result so `pd telemetry status` can show exactly why export is
|
|
8
|
+
* off (rc-9 — no silent suppression).
|
|
9
|
+
*
|
|
10
|
+
* Dev/CI/test detection follows the repository's explicit-marker philosophy
|
|
11
|
+
* (PD_E2E_MODE precedent): env markers and build-layout facts, never
|
|
12
|
+
* user-path heuristics.
|
|
13
|
+
*/
|
|
14
|
+
export type TelemetrySuppressionReason = 'env_kill_switch' | 'ci_environment' | 'vitest_environment' | 'e2e_mode' | 'workspace_environment' | 'install_layout_missing' | 'repo_checkout';
|
|
15
|
+
export interface TelemetryEnvironmentInput {
|
|
16
|
+
env: {
|
|
17
|
+
/** PD_TELEMETRY_DISABLED raw value. */
|
|
18
|
+
killSwitch?: string;
|
|
19
|
+
/** process.env.CI raw value. */
|
|
20
|
+
ci?: string;
|
|
21
|
+
/** process.env.VITEST raw value (set by vitest workers). */
|
|
22
|
+
vitest?: string;
|
|
23
|
+
/** PD_E2E_MODE raw value. */
|
|
24
|
+
e2eMode?: string;
|
|
25
|
+
};
|
|
26
|
+
/** workspace.environment from .pd/config.yaml (PRI-587); 'unknown' when absent. */
|
|
27
|
+
workspaceEnvironment: 'production' | 'development' | 'demo' | 'test' | 'unknown';
|
|
28
|
+
/** Install layout mode; 'missing' = nothing installed. */
|
|
29
|
+
installMode: 'canonical' | 'legacy' | 'missing';
|
|
30
|
+
/** Directory of the executing telemetry module (repo-checkout detection). */
|
|
31
|
+
moduleDir: string;
|
|
32
|
+
}
|
|
33
|
+
export interface TelemetryEnvironmentResult {
|
|
34
|
+
suppressed: boolean;
|
|
35
|
+
reasons: TelemetrySuppressionReason[];
|
|
36
|
+
}
|
|
37
|
+
/** Boolean-style env flags follow the PD_SKIP_* convention: '1' or 'true'. */
|
|
38
|
+
export declare function isEnvFlagActive(value: string | undefined): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* True when the executing module lives inside a PD monorepo checkout.
|
|
41
|
+
*
|
|
42
|
+
* Build-layout fact, not a path heuristic: an installed runtime (canonical
|
|
43
|
+
* `~/.pd/runtime/host-runtime/...` or legacy extension dir) never has a
|
|
44
|
+
* sibling `packages/principles-core` + `packages/host-runtime` tree, while
|
|
45
|
+
* a checkout always does. Prevents maintainer/AI development activity from
|
|
46
|
+
* polluting production telemetry.
|
|
47
|
+
*/
|
|
48
|
+
export declare function isRepoCheckoutModuleDir(moduleDir: string): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Evaluate environment suppression. Kill switch outranks everything; the
|
|
51
|
+
* result lists every active reason.
|
|
52
|
+
*/
|
|
53
|
+
export declare function computeTelemetryEnvironment(input: TelemetryEnvironmentInput): TelemetryEnvironmentResult;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Production eligibility — Anonymous Product Telemetry v1
|
|
3
|
+
* (PRI-597, SPEC §35-§37).
|
|
4
|
+
*
|
|
5
|
+
* Environment suppression is evaluated independently of consent and the
|
|
6
|
+
* feature flag (both are AND-ed by the service). Every suppression reason is
|
|
7
|
+
* named in the result so `pd telemetry status` can show exactly why export is
|
|
8
|
+
* off (rc-9 — no silent suppression).
|
|
9
|
+
*
|
|
10
|
+
* Dev/CI/test detection follows the repository's explicit-marker philosophy
|
|
11
|
+
* (PD_E2E_MODE precedent): env markers and build-layout facts, never
|
|
12
|
+
* user-path heuristics.
|
|
13
|
+
*/
|
|
14
|
+
import fs from 'node:fs';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
/** Boolean-style env flags follow the PD_SKIP_* convention: '1' or 'true'. */
|
|
17
|
+
export function isEnvFlagActive(value) {
|
|
18
|
+
return value === '1' || value === 'true';
|
|
19
|
+
}
|
|
20
|
+
function isTruthyEnv(value) {
|
|
21
|
+
return value !== undefined && value !== '' && value !== 'false' && value !== '0';
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* True when the executing module lives inside a PD monorepo checkout.
|
|
25
|
+
*
|
|
26
|
+
* Build-layout fact, not a path heuristic: an installed runtime (canonical
|
|
27
|
+
* `~/.pd/runtime/host-runtime/...` or legacy extension dir) never has a
|
|
28
|
+
* sibling `packages/principles-core` + `packages/host-runtime` tree, while
|
|
29
|
+
* a checkout always does. Prevents maintainer/AI development activity from
|
|
30
|
+
* polluting production telemetry.
|
|
31
|
+
*/
|
|
32
|
+
export function isRepoCheckoutModuleDir(moduleDir) {
|
|
33
|
+
let current = path.resolve(moduleDir);
|
|
34
|
+
for (let depth = 0; depth < 8; depth += 1) {
|
|
35
|
+
const hasCore = fs.existsSync(path.join(current, 'packages', 'principles-core'));
|
|
36
|
+
const hasHostRuntime = fs.existsSync(path.join(current, 'packages', 'host-runtime'));
|
|
37
|
+
if (hasCore && hasHostRuntime) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
const parent = path.dirname(current);
|
|
41
|
+
if (parent === current)
|
|
42
|
+
break;
|
|
43
|
+
current = parent;
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Evaluate environment suppression. Kill switch outranks everything; the
|
|
49
|
+
* result lists every active reason.
|
|
50
|
+
*/
|
|
51
|
+
export function computeTelemetryEnvironment(input) {
|
|
52
|
+
const reasons = [];
|
|
53
|
+
if (isEnvFlagActive(input.env.killSwitch))
|
|
54
|
+
reasons.push('env_kill_switch');
|
|
55
|
+
if (isTruthyEnv(input.env.ci))
|
|
56
|
+
reasons.push('ci_environment');
|
|
57
|
+
if (isTruthyEnv(input.env.vitest))
|
|
58
|
+
reasons.push('vitest_environment');
|
|
59
|
+
if (input.env.e2eMode === '1')
|
|
60
|
+
reasons.push('e2e_mode');
|
|
61
|
+
if (input.workspaceEnvironment === 'test' || input.workspaceEnvironment === 'demo' || input.workspaceEnvironment === 'development') {
|
|
62
|
+
reasons.push('workspace_environment');
|
|
63
|
+
}
|
|
64
|
+
if (input.installMode === 'missing')
|
|
65
|
+
reasons.push('install_layout_missing');
|
|
66
|
+
if (isRepoCheckoutModuleDir(input.moduleDir))
|
|
67
|
+
reasons.push('repo_checkout');
|
|
68
|
+
return { suppressed: reasons.length > 0, reasons };
|
|
69
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded asynchronous telemetry export client — Anonymous Product Telemetry
|
|
3
|
+
* v1 (PRI-599, SPEC §29-§34).
|
|
4
|
+
*
|
|
5
|
+
* One HTTPS POST per invocation, bounded by AbortController, never throwing.
|
|
6
|
+
* Failure mapping is coarse (SPEC §34): codes only, never messages, stacks,
|
|
7
|
+
* or response bodies. The injectable fetchFn keeps unit tests offline.
|
|
8
|
+
*/
|
|
9
|
+
import type { ProductTelemetrySnapshotV1 } from '@principles/core/runtime-v2';
|
|
10
|
+
export declare const DEFAULT_PRODUCT_TELEMETRY_ENDPOINT = "https://principles-website.pages.dev/api/product-telemetry/snapshot";
|
|
11
|
+
export declare const PRODUCT_TELEMETRY_TIMEOUT_MS = 8000;
|
|
12
|
+
export declare const PRODUCT_TELEMETRY_MAX_BODY_BYTES = 4096;
|
|
13
|
+
export type TelemetryFailureCode = 'timeout' | 'network_error' | 'http_400' | 'http_429' | 'http_5xx' | 'http_unexpected_status' | 'invalid_response';
|
|
14
|
+
export type TelemetryExportResult = {
|
|
15
|
+
ok: true;
|
|
16
|
+
status: number;
|
|
17
|
+
} | {
|
|
18
|
+
ok: false;
|
|
19
|
+
code: TelemetryFailureCode;
|
|
20
|
+
retryable: boolean;
|
|
21
|
+
};
|
|
22
|
+
export type TelemetryFetchFn = (url: string, init: {
|
|
23
|
+
method: 'POST';
|
|
24
|
+
headers: Record<string, string>;
|
|
25
|
+
body: string;
|
|
26
|
+
signal: AbortSignal;
|
|
27
|
+
}) => Promise<{
|
|
28
|
+
status: number;
|
|
29
|
+
}>;
|
|
30
|
+
export interface ExportSnapshotArgs {
|
|
31
|
+
snapshot: ProductTelemetrySnapshotV1;
|
|
32
|
+
endpoint?: string;
|
|
33
|
+
timeoutMs?: number;
|
|
34
|
+
fetchFn?: TelemetryFetchFn;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Export one snapshot. Never throws; every failure maps to a coarse code
|
|
38
|
+
* with a retryable hint the service uses for backoff.
|
|
39
|
+
*/
|
|
40
|
+
export declare function exportSnapshot(args: ExportSnapshotArgs): Promise<TelemetryExportResult>;
|
|
41
|
+
/**
|
|
42
|
+
* First failure retries after 1h; any further failure within 24h backs off 6h.
|
|
43
|
+
* Combined with the service's dailyAttemptCount hard cap this bounds a bad day
|
|
44
|
+
* to at most 5 attempts (0h/1h/7h/13h/19h), independent of clock skew.
|
|
45
|
+
*/
|
|
46
|
+
export declare function nextRetryDelayMs(previousFailureWithin24h: boolean): number;
|