create-principles-disciple 1.93.0 → 1.95.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/console/dist/server/config/WorkspaceConfigStore.js +2 -1
- package/console/dist/server/config/pd-config-store.d.ts +40 -1
- package/console/dist/server/config/pd-config-store.js +170 -1
- package/console/dist/server/index.js +28 -10
- package/console/dist/server/models/ApprovalsConsoleModel.js +4 -12
- package/console/dist/server/models/EvidenceChainConsoleModel.d.ts +0 -2
- package/console/dist/server/models/EvidenceChainConsoleModel.js +36 -2
- package/console/dist/server/models/HealthCheckModel.js +5 -3
- package/console/dist/server/models/IntentDecisionModel.d.ts +66 -0
- package/console/dist/server/models/IntentDecisionModel.js +207 -0
- package/console/dist/server/models/IntentPageModel.d.ts +18 -0
- package/console/dist/server/models/IntentPageModel.js +90 -0
- package/console/dist/server/models/PrinciplesConsoleModel.d.ts +2 -0
- package/console/dist/server/models/PrinciplesConsoleModel.js +37 -1
- package/console/dist/server/models/WorkspaceService.d.ts +0 -28
- package/console/dist/server/models/WorkspaceService.js +0 -115
- package/console/dist/server/routes/config.js +55 -1
- package/console/dist/server/routes/feedback-reports.js +1 -1
- package/console/dist/server/routes/intent-decisions.d.ts +33 -0
- package/console/dist/server/routes/intent-decisions.js +499 -0
- package/console/dist/server/routes/intent.d.ts +3 -0
- package/console/dist/server/routes/intent.js +35 -0
- package/console/dist/server/routes/principles.js +67 -1
- package/console/dist/server/routes/update.d.ts +0 -1
- package/console/dist/server/routes/update.js +14 -11
- package/console/dist/ui/App.js +2 -7
- package/console/dist/ui/api.d.ts +44 -18
- package/console/dist/ui/api.js +44 -5
- package/console/dist/ui/components/layout/app-sidebar.js +2 -1
- package/console/dist/ui/components/ui/badge.d.ts +1 -1
- package/console/dist/ui/components/ui/button.d.ts +1 -1
- package/console/dist/ui/components/ui/shiny-text.d.ts +28 -0
- package/console/dist/ui/components/ui/shiny-text.js +46 -0
- package/console/dist/ui/i18n/en.json +167 -3
- package/console/dist/ui/i18n/zh-CN.json +167 -3
- package/console/dist/ui/pages/activation/ActivationPage.js +2 -1
- package/console/dist/ui/pages/control-center/ControlCenterPage.js +28 -2
- package/console/dist/ui/pages/control-center/EmpathyObserverCostHint.d.ts +28 -0
- package/console/dist/ui/pages/control-center/EmpathyObserverCostHint.js +38 -0
- package/console/dist/ui/pages/debt/DebtPage.js +219 -2
- package/console/dist/ui/pages/focus/FocusPage.js +2 -1
- package/console/dist/ui/pages/intent/IntentPage.d.ts +1 -0
- package/console/dist/ui/pages/intent/IntentPage.js +147 -0
- package/console/dist/ui/pages/pain/PainPage.js +234 -4
- package/console/dist/ui/pages/pain/pain-card-helpers.d.ts +75 -0
- package/console/dist/ui/pages/pain/pain-card-helpers.js +78 -0
- package/console/dist/ui/pages/principles/PrinciplesPage.js +2 -1
- package/console/dist/ui/utils/validators.d.ts +163 -0
- package/console/dist/ui/utils/validators.js +433 -0
- package/console/dist/web/assets/app.css +138 -0
- package/console/dist/web/assets/app.js +3124 -1288
- package/console/package.json +3 -0
- package/core/dist/index.d.ts +2 -2
- package/core/dist/index.d.ts.map +1 -1
- package/core/dist/index.js +1 -1
- package/core/dist/index.js.map +1 -1
- package/core/dist/principle-tree-ledger.d.ts +55 -4
- package/core/dist/principle-tree-ledger.d.ts.map +1 -1
- package/core/dist/principle-tree-ledger.js +472 -13
- package/core/dist/principle-tree-ledger.js.map +1 -1
- package/core/dist/prompt-builder/__tests__/model-config.test.d.ts +2 -0
- package/core/dist/prompt-builder/__tests__/model-config.test.d.ts.map +1 -0
- package/core/dist/prompt-builder/__tests__/model-config.test.js +158 -0
- package/core/dist/prompt-builder/__tests__/model-config.test.js.map +1 -0
- package/core/dist/prompt-builder/__tests__/prompt-builder-core.test.js +58 -0
- package/core/dist/prompt-builder/__tests__/prompt-builder-core.test.js.map +1 -1
- package/core/dist/prompt-builder/__tests__/xml-escape.test.d.ts +2 -0
- package/core/dist/prompt-builder/__tests__/xml-escape.test.d.ts.map +1 -0
- package/core/dist/prompt-builder/__tests__/xml-escape.test.js +42 -0
- package/core/dist/prompt-builder/__tests__/xml-escape.test.js.map +1 -0
- package/core/dist/prompt-builder/empathy-keyword-matching.d.ts.map +1 -1
- package/core/dist/prompt-builder/empathy-keyword-matching.js +9 -6
- package/core/dist/prompt-builder/empathy-keyword-matching.js.map +1 -1
- package/core/dist/prompt-builder/index.d.ts +3 -0
- package/core/dist/prompt-builder/index.d.ts.map +1 -1
- package/core/dist/prompt-builder/index.js +2 -0
- package/core/dist/prompt-builder/index.js.map +1 -1
- package/core/dist/prompt-builder/model-config.d.ts +42 -0
- package/core/dist/prompt-builder/model-config.d.ts.map +1 -0
- package/core/dist/prompt-builder/model-config.js +84 -0
- package/core/dist/prompt-builder/model-config.js.map +1 -0
- package/core/dist/prompt-builder/size-guard.d.ts +1 -0
- package/core/dist/prompt-builder/size-guard.d.ts.map +1 -1
- package/core/dist/prompt-builder/size-guard.js +21 -0
- package/core/dist/prompt-builder/size-guard.js.map +1 -1
- package/core/dist/prompt-builder/types.d.ts +2 -0
- package/core/dist/prompt-builder/types.d.ts.map +1 -1
- package/core/dist/prompt-builder/xml-escape.d.ts +12 -0
- package/core/dist/prompt-builder/xml-escape.d.ts.map +1 -0
- package/core/dist/prompt-builder/xml-escape.js +19 -0
- package/core/dist/prompt-builder/xml-escape.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/architecture-regression.test.js +205 -48
- package/core/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/evidence-chain-intent-tension.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/evidence-chain-intent-tension.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/evidence-chain-intent-tension.test.js +284 -0
- package/core/dist/runtime-v2/__tests__/evidence-chain-intent-tension.test.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/pain-signal-bridge-result-shaping.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/pain-signal-bridge-result-shaping.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/pain-signal-bridge-result-shaping.test.js +500 -0
- package/core/dist/runtime-v2/__tests__/pain-signal-bridge-result-shaping.test.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/pain-signal-observability.test.js +7 -5
- package/core/dist/runtime-v2/__tests__/pain-signal-observability.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/pi-artifact-store.test.js +11 -0
- package/core/dist/runtime-v2/__tests__/pi-artifact-store.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/proven-channel-baseline.test.js +15 -2
- package/core/dist/runtime-v2/__tests__/proven-channel-baseline.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/schema-float-precision.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/schema-float-precision.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/schema-float-precision.test.js +290 -0
- package/core/dist/runtime-v2/__tests__/schema-float-precision.test.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/schema-orphan-detection.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/schema-orphan-detection.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/schema-orphan-detection.test.js +158 -0
- package/core/dist/runtime-v2/__tests__/schema-orphan-detection.test.js.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/approval-store-extended.test.js +15 -1
- package/core/dist/runtime-v2/activation/__tests__/approval-store-extended.test.js.map +1 -1
- package/core/dist/runtime-v2/activation/__tests__/sqlite-activation-state-store-fk.test.d.ts +2 -0
- package/core/dist/runtime-v2/activation/__tests__/sqlite-activation-state-store-fk.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/sqlite-activation-state-store-fk.test.js +62 -0
- package/core/dist/runtime-v2/activation/__tests__/sqlite-activation-state-store-fk.test.js.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/sqlite-activation-state-store.test.js +12 -2
- package/core/dist/runtime-v2/activation/__tests__/sqlite-activation-state-store.test.js.map +1 -1
- package/core/dist/runtime-v2/activation/__tests__/sqlite-approval-store-fk.test.d.ts +2 -0
- package/core/dist/runtime-v2/activation/__tests__/sqlite-approval-store-fk.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/sqlite-approval-store-fk.test.js +56 -0
- package/core/dist/runtime-v2/activation/__tests__/sqlite-approval-store-fk.test.js.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/sqlite-approval-store.test.js +8 -0
- package/core/dist/runtime-v2/activation/__tests__/sqlite-approval-store.test.js.map +1 -1
- package/core/dist/runtime-v2/activation/__tests__/story-a-acceptance.test.js +20 -0
- package/core/dist/runtime-v2/activation/__tests__/story-a-acceptance.test.js.map +1 -1
- package/core/dist/runtime-v2/activation/sqlite-activation-state-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/sqlite-activation-state-store.js +6 -0
- package/core/dist/runtime-v2/activation/sqlite-activation-state-store.js.map +1 -1
- package/core/dist/runtime-v2/activation/sqlite-approval-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/sqlite-approval-store.js +86 -32
- package/core/dist/runtime-v2/activation/sqlite-approval-store.js.map +1 -1
- package/core/dist/runtime-v2/activation/writers/__tests__/rule-host-writer.test.js +65 -1
- package/core/dist/runtime-v2/activation/writers/__tests__/rule-host-writer.test.js.map +1 -1
- package/core/dist/runtime-v2/activation/writers/rule-host-writer.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/writers/rule-host-writer.js +33 -11
- package/core/dist/runtime-v2/activation/writers/rule-host-writer.js.map +1 -1
- package/core/dist/runtime-v2/bridge-result-shaper.d.ts +53 -0
- package/core/dist/runtime-v2/bridge-result-shaper.d.ts.map +1 -0
- package/core/dist/runtime-v2/bridge-result-shaper.js +117 -0
- package/core/dist/runtime-v2/bridge-result-shaper.js.map +1 -0
- package/core/dist/runtime-v2/detection/__tests__/detection-funnel-policy.test.d.ts +13 -0
- package/core/dist/runtime-v2/detection/__tests__/detection-funnel-policy.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/detection/__tests__/detection-funnel-policy.test.js +111 -0
- package/core/dist/runtime-v2/detection/__tests__/detection-funnel-policy.test.js.map +1 -0
- package/core/dist/runtime-v2/detection/detection-funnel-policy.d.ts +103 -0
- package/core/dist/runtime-v2/detection/detection-funnel-policy.d.ts.map +1 -0
- package/core/dist/runtime-v2/detection/detection-funnel-policy.js +135 -0
- package/core/dist/runtime-v2/detection/detection-funnel-policy.js.map +1 -0
- package/core/dist/runtime-v2/detection/index.d.ts +10 -0
- package/core/dist/runtime-v2/detection/index.d.ts.map +1 -0
- package/core/dist/runtime-v2/detection/index.js +9 -0
- package/core/dist/runtime-v2/detection/index.js.map +1 -0
- package/core/dist/runtime-v2/diagnostician/__tests__/diag-rootcause-output.test.js +134 -15
- package/core/dist/runtime-v2/diagnostician/__tests__/diag-rootcause-output.test.js.map +1 -1
- package/core/dist/runtime-v2/diagnostician/__tests__/intent-tension-schema.test.d.ts +18 -0
- package/core/dist/runtime-v2/diagnostician/__tests__/intent-tension-schema.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/diagnostician/__tests__/intent-tension-schema.test.js +251 -0
- package/core/dist/runtime-v2/diagnostician/__tests__/intent-tension-schema.test.js.map +1 -0
- package/core/dist/runtime-v2/diagnostician/__tests__/rootcause-prompt-builder.test.js +73 -0
- package/core/dist/runtime-v2/diagnostician/__tests__/rootcause-prompt-builder.test.js.map +1 -1
- package/core/dist/runtime-v2/diagnostician/diag-rootcause-output.d.ts +98 -0
- package/core/dist/runtime-v2/diagnostician/diag-rootcause-output.d.ts.map +1 -1
- package/core/dist/runtime-v2/diagnostician/diag-rootcause-output.js +131 -0
- package/core/dist/runtime-v2/diagnostician/diag-rootcause-output.js.map +1 -1
- package/core/dist/runtime-v2/diagnostician/rootcause-prompt-builder.d.ts +8 -0
- package/core/dist/runtime-v2/diagnostician/rootcause-prompt-builder.d.ts.map +1 -1
- package/core/dist/runtime-v2/diagnostician/rootcause-prompt-builder.js +66 -3
- package/core/dist/runtime-v2/diagnostician/rootcause-prompt-builder.js.map +1 -1
- package/core/dist/runtime-v2/diagnostician-output.d.ts +23 -0
- package/core/dist/runtime-v2/diagnostician-output.d.ts.map +1 -1
- package/core/dist/runtime-v2/diagnostician-output.js +16 -0
- package/core/dist/runtime-v2/diagnostician-output.js.map +1 -1
- package/core/dist/runtime-v2/diagnostician-prompt-builder.d.ts +32 -0
- package/core/dist/runtime-v2/diagnostician-prompt-builder.d.ts.map +1 -1
- package/core/dist/runtime-v2/diagnostician-prompt-builder.js.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/__tests__/observation-resolver.test.d.ts +12 -0
- package/core/dist/runtime-v2/evidence-triage/__tests__/observation-resolver.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/evidence-triage/__tests__/observation-resolver.test.js +181 -0
- package/core/dist/runtime-v2/evidence-triage/__tests__/observation-resolver.test.js.map +1 -0
- package/core/dist/runtime-v2/evidence-triage/__tests__/triage-policy.test.js +104 -1
- package/core/dist/runtime-v2/evidence-triage/__tests__/triage-policy.test.js.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/index.d.ts +3 -0
- package/core/dist/runtime-v2/evidence-triage/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/index.js +3 -0
- package/core/dist/runtime-v2/evidence-triage/index.js.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/observation-resolver.d.ts +128 -0
- package/core/dist/runtime-v2/evidence-triage/observation-resolver.d.ts.map +1 -0
- package/core/dist/runtime-v2/evidence-triage/observation-resolver.js +203 -0
- package/core/dist/runtime-v2/evidence-triage/observation-resolver.js.map +1 -0
- package/core/dist/runtime-v2/evidence-triage/source-descriptors.d.ts +1 -1
- package/core/dist/runtime-v2/evidence-triage/source-descriptors.js +1 -1
- package/core/dist/runtime-v2/evidence-triage/triage-policy.d.ts +4 -0
- package/core/dist/runtime-v2/evidence-triage/triage-policy.d.ts.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/triage-policy.js +66 -9
- package/core/dist/runtime-v2/evidence-triage/triage-policy.js.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/types.d.ts +14 -0
- package/core/dist/runtime-v2/evidence-triage/types.d.ts.map +1 -1
- package/core/dist/runtime-v2/evidence-triage/types.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js +56 -4
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/__tests__/intent-engineering-flag.test.d.ts +2 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/intent-engineering-flag.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/intent-engineering-flag.test.js +30 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/intent-engineering-flag.test.js.map +1 -0
- 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 +11 -2
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/plugin-surface-registry.d.ts.map +1 -1
- package/core/dist/runtime-v2/feature-flags/plugin-surface-registry.js +0 -9
- package/core/dist/runtime-v2/feature-flags/plugin-surface-registry.js.map +1 -1
- package/core/dist/runtime-v2/feedback/__tests__/redact-sensitive.test.d.ts +15 -0
- package/core/dist/runtime-v2/feedback/__tests__/redact-sensitive.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/feedback/__tests__/redact-sensitive.test.js +450 -0
- package/core/dist/runtime-v2/feedback/__tests__/redact-sensitive.test.js.map +1 -0
- package/core/dist/runtime-v2/feedback/__tests__/render-github-url.test.d.ts +13 -0
- package/core/dist/runtime-v2/feedback/__tests__/render-github-url.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/feedback/__tests__/render-github-url.test.js +243 -0
- package/core/dist/runtime-v2/feedback/__tests__/render-github-url.test.js.map +1 -0
- package/core/dist/runtime-v2/feedback/__tests__/safe-stringify.test.d.ts +12 -0
- package/core/dist/runtime-v2/feedback/__tests__/safe-stringify.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/feedback/__tests__/safe-stringify.test.js +172 -0
- package/core/dist/runtime-v2/feedback/__tests__/safe-stringify.test.js.map +1 -0
- package/core/dist/runtime-v2/index.d.ts +15 -6
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +15 -4
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/intent/__tests__/intent-decision-record.test.d.ts +2 -0
- package/core/dist/runtime-v2/intent/__tests__/intent-decision-record.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/intent/__tests__/intent-decision-record.test.js +185 -0
- package/core/dist/runtime-v2/intent/__tests__/intent-decision-record.test.js.map +1 -0
- package/core/dist/runtime-v2/intent/__tests__/intent-doc.test.d.ts +2 -0
- package/core/dist/runtime-v2/intent/__tests__/intent-doc.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/intent/__tests__/intent-doc.test.js +91 -0
- package/core/dist/runtime-v2/intent/__tests__/intent-doc.test.js.map +1 -0
- package/core/dist/runtime-v2/intent/__tests__/intent-friction-block.test.d.ts +2 -0
- package/core/dist/runtime-v2/intent/__tests__/intent-friction-block.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/intent/__tests__/intent-friction-block.test.js +168 -0
- package/core/dist/runtime-v2/intent/__tests__/intent-friction-block.test.js.map +1 -0
- package/core/dist/runtime-v2/intent/__tests__/intent-patch-proposal.test.d.ts +2 -0
- package/core/dist/runtime-v2/intent/__tests__/intent-patch-proposal.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/intent/__tests__/intent-patch-proposal.test.js +121 -0
- package/core/dist/runtime-v2/intent/__tests__/intent-patch-proposal.test.js.map +1 -0
- package/core/dist/runtime-v2/intent/index.d.ts +6 -0
- package/core/dist/runtime-v2/intent/index.d.ts.map +1 -0
- package/core/dist/runtime-v2/intent/index.js +6 -0
- package/core/dist/runtime-v2/intent/index.js.map +1 -0
- package/core/dist/runtime-v2/intent/intent-decision-record.d.ts +125 -0
- package/core/dist/runtime-v2/intent/intent-decision-record.d.ts.map +1 -0
- package/core/dist/runtime-v2/intent/intent-decision-record.js +21 -0
- package/core/dist/runtime-v2/intent/intent-decision-record.js.map +1 -0
- package/core/dist/runtime-v2/intent/intent-doc-reader-port.d.ts +95 -0
- package/core/dist/runtime-v2/intent/intent-doc-reader-port.d.ts.map +1 -0
- package/core/dist/runtime-v2/intent/intent-doc-reader-port.js +43 -0
- package/core/dist/runtime-v2/intent/intent-doc-reader-port.js.map +1 -0
- package/core/dist/runtime-v2/intent/intent-doc.d.ts +19 -0
- package/core/dist/runtime-v2/intent/intent-doc.d.ts.map +1 -0
- package/core/dist/runtime-v2/intent/intent-doc.js +70 -0
- package/core/dist/runtime-v2/intent/intent-doc.js.map +1 -0
- package/core/dist/runtime-v2/intent/intent-friction-block.d.ts +63 -0
- package/core/dist/runtime-v2/intent/intent-friction-block.d.ts.map +1 -0
- package/core/dist/runtime-v2/intent/intent-friction-block.js +129 -0
- package/core/dist/runtime-v2/intent/intent-friction-block.js.map +1 -0
- package/core/dist/runtime-v2/intent/intent-patch-proposal.d.ts +42 -0
- package/core/dist/runtime-v2/intent/intent-patch-proposal.d.ts.map +1 -0
- package/core/dist/runtime-v2/intent/intent-patch-proposal.js +81 -0
- package/core/dist/runtime-v2/intent/intent-patch-proposal.js.map +1 -0
- package/core/dist/runtime-v2/internalization/__tests__/__fixtures__/intent-tension-cases.d.ts +54 -0
- package/core/dist/runtime-v2/internalization/__tests__/__fixtures__/intent-tension-cases.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/__tests__/__fixtures__/intent-tension-cases.js +219 -0
- package/core/dist/runtime-v2/internalization/__tests__/__fixtures__/intent-tension-cases.js.map +1 -0
- package/core/dist/runtime-v2/internalization/__tests__/c2-live-runner-chain.test.d.ts +2 -0
- package/core/dist/runtime-v2/internalization/__tests__/c2-live-runner-chain.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/__tests__/c2-live-runner-chain.test.js +306 -0
- package/core/dist/runtime-v2/internalization/__tests__/c2-live-runner-chain.test.js.map +1 -0
- package/core/dist/runtime-v2/internalization/__tests__/diag-rootcause-intent-tension.test.d.ts +2 -0
- package/core/dist/runtime-v2/internalization/__tests__/diag-rootcause-intent-tension.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/__tests__/diag-rootcause-intent-tension.test.js +360 -0
- package/core/dist/runtime-v2/internalization/__tests__/diag-rootcause-intent-tension.test.js.map +1 -0
- package/core/dist/runtime-v2/internalization/__tests__/diag-router-intent-tension.test.d.ts +2 -0
- package/core/dist/runtime-v2/internalization/__tests__/diag-router-intent-tension.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/__tests__/diag-router-intent-tension.test.js +333 -0
- package/core/dist/runtime-v2/internalization/__tests__/diag-router-intent-tension.test.js.map +1 -0
- package/core/dist/runtime-v2/internalization/__tests__/intent-tension-cases.test.d.ts +2 -0
- package/core/dist/runtime-v2/internalization/__tests__/intent-tension-cases.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/__tests__/intent-tension-cases.test.js +113 -0
- package/core/dist/runtime-v2/internalization/__tests__/intent-tension-cases.test.js.map +1 -0
- package/core/dist/runtime-v2/internalization/diag-rootcause-runner.d.ts +13 -0
- package/core/dist/runtime-v2/internalization/diag-rootcause-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/diag-rootcause-runner.js +42 -0
- package/core/dist/runtime-v2/internalization/diag-rootcause-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/diag-router-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/diag-router-runner.js +27 -0
- package/core/dist/runtime-v2/internalization/diag-router-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/index.d.ts +0 -16
- package/core/dist/runtime-v2/internalization/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/index.js +0 -8
- package/core/dist/runtime-v2/internalization/index.js.map +1 -1
- package/core/dist/runtime-v2/pain-gate/__tests__/pain-diagnostic-gate-policy.test.d.ts +15 -0
- package/core/dist/runtime-v2/pain-gate/__tests__/pain-diagnostic-gate-policy.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/pain-gate/__tests__/pain-diagnostic-gate-policy.test.js +179 -0
- package/core/dist/runtime-v2/pain-gate/__tests__/pain-diagnostic-gate-policy.test.js.map +1 -0
- package/core/dist/runtime-v2/pain-gate/index.d.ts +10 -0
- package/core/dist/runtime-v2/pain-gate/index.d.ts.map +1 -0
- package/core/dist/runtime-v2/pain-gate/index.js +9 -0
- package/core/dist/runtime-v2/pain-gate/index.js.map +1 -0
- package/core/dist/runtime-v2/pain-gate/pain-diagnostic-gate-policy.d.ts +121 -0
- package/core/dist/runtime-v2/pain-gate/pain-diagnostic-gate-policy.d.ts.map +1 -0
- package/core/dist/runtime-v2/pain-gate/pain-diagnostic-gate-policy.js +157 -0
- package/core/dist/runtime-v2/pain-gate/pain-diagnostic-gate-policy.js.map +1 -0
- package/core/dist/runtime-v2/pain-signal-bridge.d.ts.map +1 -1
- package/core/dist/runtime-v2/pain-signal-bridge.js +14 -88
- package/core/dist/runtime-v2/pain-signal-bridge.js.map +1 -1
- package/core/dist/runtime-v2/pain-signal-observability.d.ts.map +1 -1
- package/core/dist/runtime-v2/pain-signal-observability.js +272 -61
- package/core/dist/runtime-v2/pain-signal-observability.js.map +1 -1
- package/core/dist/runtime-v2/pain-signal-runtime-factory.d.ts +12 -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 +1 -1
- package/core/dist/runtime-v2/pain-signal-runtime-factory.js.map +1 -1
- package/core/dist/runtime-v2/pain-to-principle-service.d.ts +6 -0
- package/core/dist/runtime-v2/pain-to-principle-service.d.ts.map +1 -1
- package/core/dist/runtime-v2/pain-to-principle-service.js +2 -0
- package/core/dist/runtime-v2/pain-to-principle-service.js.map +1 -1
- package/core/dist/runtime-v2/principle-tree/ledger-codec.js.map +1 -1
- package/core/dist/runtime-v2/proven-channel-baseline.js +1 -1
- package/core/dist/runtime-v2/proven-channel-baseline.js.map +1 -1
- package/core/dist/runtime-v2/store/artifact/__tests__/sqlite-pi-artifact-store-fk.test.d.ts +2 -0
- package/core/dist/runtime-v2/store/artifact/__tests__/sqlite-pi-artifact-store-fk.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/store/artifact/__tests__/sqlite-pi-artifact-store-fk.test.js +55 -0
- package/core/dist/runtime-v2/store/artifact/__tests__/sqlite-pi-artifact-store-fk.test.js.map +1 -0
- package/core/dist/runtime-v2/store/artifact/sqlite-pi-artifact-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/artifact/sqlite-pi-artifact-store.js +6 -0
- package/core/dist/runtime-v2/store/artifact/sqlite-pi-artifact-store.js.map +1 -1
- package/core/dist/runtime-v2/store/intent/__tests__/sqlite-intent-decision-store.test.d.ts +2 -0
- package/core/dist/runtime-v2/store/intent/__tests__/sqlite-intent-decision-store.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/store/intent/__tests__/sqlite-intent-decision-store.test.js +272 -0
- package/core/dist/runtime-v2/store/intent/__tests__/sqlite-intent-decision-store.test.js.map +1 -0
- package/core/dist/runtime-v2/store/intent/index.d.ts +6 -0
- package/core/dist/runtime-v2/store/intent/index.d.ts.map +1 -0
- package/core/dist/runtime-v2/store/intent/index.js +5 -0
- package/core/dist/runtime-v2/store/intent/index.js.map +1 -0
- package/core/dist/runtime-v2/store/intent/sqlite-intent-decision-store.d.ts +51 -0
- package/core/dist/runtime-v2/store/intent/sqlite-intent-decision-store.d.ts.map +1 -0
- package/core/dist/runtime-v2/store/intent/sqlite-intent-decision-store.js +306 -0
- package/core/dist/runtime-v2/store/intent/sqlite-intent-decision-store.js.map +1 -0
- package/core/dist/runtime-v2/store/sqlite-connection-pragma.test.js +14 -3
- package/core/dist/runtime-v2/store/sqlite-connection-pragma.test.js.map +1 -1
- package/core/dist/runtime-v2/store/sqlite-connection-schema-version.test.d.ts +2 -0
- package/core/dist/runtime-v2/store/sqlite-connection-schema-version.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/store/sqlite-connection-schema-version.test.js +72 -0
- package/core/dist/runtime-v2/store/sqlite-connection-schema-version.test.js.map +1 -0
- package/core/dist/runtime-v2/store/sqlite-connection.d.ts +27 -0
- package/core/dist/runtime-v2/store/sqlite-connection.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/sqlite-connection.js +124 -12
- package/core/dist/runtime-v2/store/sqlite-connection.js.map +1 -1
- package/core/dist/runtime-v2/types/event-payload.d.ts +1 -20
- package/core/dist/runtime-v2/types/event-payload.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/event-payload.js +0 -12
- package/core/dist/runtime-v2/types/event-payload.js.map +1 -1
- package/core/dist/runtime-v2/types/event-types.d.ts +5 -61
- package/core/dist/runtime-v2/types/event-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/event-types.js +2 -36
- package/core/dist/runtime-v2/types/event-types.js.map +1 -1
- package/core/dist/runtime-v2/types/evidence-chain-contract.d.ts +63 -0
- package/core/dist/runtime-v2/types/evidence-chain-contract.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/evidence-chain-contract.js +234 -9
- package/core/dist/runtime-v2/types/evidence-chain-contract.js.map +1 -1
- package/core/dist/runtime-v2/types/index.d.ts +5 -5
- package/core/dist/runtime-v2/types/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/index.js +7 -3
- package/core/dist/runtime-v2/types/index.js.map +1 -1
- package/core/dist/runtime-v2/types/ledger-store.d.ts +30 -30
- package/core/dist/runtime-v2/types/ledger-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/ledger-store.js +10 -5
- package/core/dist/runtime-v2/types/ledger-store.js.map +1 -1
- package/core/dist/runtime-v2/types/pain-signal.d.ts +2 -2
- package/core/dist/runtime-v2/types/pain-signal.js +2 -2
- package/core/dist/workflow-funnel-loader.d.ts +2 -2
- package/core/dist/workflow-funnel-loader.d.ts.map +1 -1
- package/dist/installer.d.ts.map +1 -1
- package/dist/installer.js +16 -0
- package/dist/installer.js.map +1 -1
- package/dist/mvp-config.d.ts +0 -10
- package/dist/mvp-config.d.ts.map +1 -1
- package/dist/mvp-config.js +0 -65
- package/dist/mvp-config.js.map +1 -1
- package/package.json +1 -1
- package/pd-cli/dist/commands/__tests__/intent-flag-wiring.test.d.ts +9 -0
- package/pd-cli/dist/commands/__tests__/intent-flag-wiring.test.d.ts.map +1 -0
- package/pd-cli/dist/commands/__tests__/intent-flag-wiring.test.js +166 -0
- package/pd-cli/dist/commands/__tests__/intent-flag-wiring.test.js.map +1 -0
- package/pd-cli/dist/commands/intent.d.ts +59 -0
- package/pd-cli/dist/commands/intent.d.ts.map +1 -0
- package/pd-cli/dist/commands/intent.js +350 -0
- package/pd-cli/dist/commands/intent.js.map +1 -0
- package/pd-cli/dist/commands/mvp-smoke.js +1 -1
- package/pd-cli/dist/commands/mvp-smoke.js.map +1 -1
- package/pd-cli/dist/commands/rulecode.js +1 -1
- package/pd-cli/dist/commands/rulecode.js.map +1 -1
- package/pd-cli/dist/commands/runtime-canary.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-canary.js +10 -11
- package/pd-cli/dist/commands/runtime-canary.js.map +1 -1
- package/pd-cli/dist/commands/runtime-init.d.ts +43 -0
- package/pd-cli/dist/commands/runtime-init.d.ts.map +1 -0
- package/pd-cli/dist/commands/runtime-init.js +264 -0
- package/pd-cli/dist/commands/runtime-init.js.map +1 -0
- package/pd-cli/dist/commands/runtime-internalization-queue.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-queue.js +13 -16
- package/pd-cli/dist/commands/runtime-internalization-queue.js.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-run-once.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-run-once.js +3 -0
- package/pd-cli/dist/commands/runtime-internalization-run-once.js.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-run-rulehost.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-run-rulehost.js +61 -7
- package/pd-cli/dist/commands/runtime-internalization-run-rulehost.js.map +1 -1
- package/pd-cli/dist/commands/runtime.js +1 -1
- package/pd-cli/dist/commands/runtime.js.map +1 -1
- package/pd-cli/dist/index.js +92 -34
- package/pd-cli/dist/index.js.map +1 -1
- package/pd-cli/dist/services/__tests__/rulehost-readiness.test.d.ts +2 -0
- package/pd-cli/dist/services/__tests__/rulehost-readiness.test.d.ts.map +1 -0
- package/pd-cli/dist/services/__tests__/rulehost-readiness.test.js +314 -0
- package/pd-cli/dist/services/__tests__/rulehost-readiness.test.js.map +1 -0
- package/pd-cli/dist/services/__tests__/runtime-adapter-resolver.test.js +20 -12
- package/pd-cli/dist/services/__tests__/runtime-adapter-resolver.test.js.map +1 -1
- package/pd-cli/dist/services/demo-story-a-runner.d.ts.map +1 -1
- package/pd-cli/dist/services/demo-story-a-runner.js +6 -0
- package/pd-cli/dist/services/demo-story-a-runner.js.map +1 -1
- package/pd-cli/dist/services/rulehost-readiness.d.ts +62 -0
- package/pd-cli/dist/services/rulehost-readiness.d.ts.map +1 -0
- package/pd-cli/dist/services/rulehost-readiness.js +214 -0
- package/pd-cli/dist/services/rulehost-readiness.js.map +1 -0
- package/pd-cli/dist/services/runtime-adapter-resolver.d.ts +1 -1
- package/pd-cli/dist/services/runtime-adapter-resolver.js +3 -3
- package/pd-cli/dist/services/runtime-adapter-resolver.js.map +1 -1
- package/pd-cli/package.json +1 -0
- package/plugin/dist/commands/evolution-status.js +0 -2
- package/plugin/dist/commands/pain.js +2 -0
- package/plugin/dist/core/control-ui-db.d.ts +11 -0
- package/plugin/dist/core/control-ui-db.js +40 -16
- package/plugin/dist/core/detection-funnel.d.ts +25 -11
- package/plugin/dist/core/detection-funnel.js +32 -80
- package/plugin/dist/core/event-log.d.ts +1 -3
- package/plugin/dist/core/event-log.js +5 -21
- package/plugin/dist/core/evolution-reducer.d.ts +0 -8
- package/plugin/dist/core/evolution-reducer.js +9 -19
- package/plugin/dist/core/intent-doc-reader-adapter.d.ts +28 -0
- package/plugin/dist/core/intent-doc-reader-adapter.js +56 -0
- package/plugin/dist/core/intent-doc-reader.d.ts +80 -0
- package/plugin/dist/core/intent-doc-reader.js +189 -0
- package/plugin/dist/core/pain-diagnostic-gate.d.ts +37 -28
- package/plugin/dist/core/pain-diagnostic-gate.js +53 -89
- package/plugin/dist/core/pain.d.ts +0 -63
- package/plugin/dist/core/pain.js +0 -167
- package/plugin/dist/core/paths.d.ts +0 -1
- package/plugin/dist/core/paths.js +2 -1
- package/plugin/dist/core/principle-tree-ledger.d.ts +27 -79
- package/plugin/dist/core/principle-tree-ledger.js +39 -524
- package/plugin/dist/core/reflection/reflection-context.d.ts +2 -2
- package/plugin/dist/core/schema/migrations/001-init-trajectory.js +3 -6
- package/plugin/dist/core/schema/schema-definitions.js +4 -9
- package/plugin/dist/core/trajectory.d.ts +16 -16
- package/plugin/dist/core/trajectory.js +338 -311
- package/plugin/dist/core/workspace-context.d.ts +2 -3
- package/plugin/dist/hooks/after-tool-call-helpers.d.ts +4 -1
- package/plugin/dist/hooks/after-tool-call-helpers.js +13 -17
- package/plugin/dist/hooks/gate-block-helper.js +57 -17
- package/plugin/dist/hooks/lifecycle.js +3 -6
- package/plugin/dist/hooks/llm.js +66 -26
- package/plugin/dist/hooks/pain.d.ts +3 -1
- package/plugin/dist/hooks/pain.js +124 -49
- package/plugin/dist/hooks/prompt-helpers.d.ts +105 -0
- package/plugin/dist/hooks/prompt-helpers.js +288 -0
- package/plugin/dist/hooks/prompt-types.d.ts +74 -0
- package/plugin/dist/hooks/prompt-types.js +12 -0
- package/plugin/dist/hooks/prompt.d.ts +7 -38
- package/plugin/dist/hooks/prompt.js +433 -338
- package/plugin/dist/hooks/raw-observation-adapter.d.ts +9 -50
- package/plugin/dist/hooks/raw-observation-adapter.js +9 -164
- package/plugin/dist/hooks/raw-observation-types.d.ts +6 -57
- package/plugin/dist/hooks/raw-observation-types.js +5 -9
- package/plugin/dist/hooks/triage-adapter.js +6 -26
- package/plugin/dist/hooks/trigger-cooldown-tracker.d.ts +12 -0
- package/plugin/dist/hooks/trigger-cooldown-tracker.js +25 -0
- package/plugin/dist/index.d.ts +3 -1
- package/plugin/dist/index.js +9 -5
- package/plugin/dist/service/evolution-worker.js +6 -64
- package/plugin/dist/service/runtime-summary-service.d.ts +0 -2
- package/plugin/dist/service/runtime-summary-service.js +1 -5
- package/plugin/dist/service/subagent-workflow/workflow-store.d.ts +14 -0
- package/plugin/dist/service/subagent-workflow/workflow-store.js +91 -2
- package/plugin/dist/types/event-types.d.ts +1 -1
- package/plugin/package.json +6 -3
- package/plugin/scripts/acceptance-test.mjs +3 -3
- package/plugin/scripts/sync-plugin.mjs +33 -22
- package/plugin/templates/langs/en/skills/pd-cli-operator/SKILL.md +20 -11
- package/plugin/templates/langs/en/skills/pd-runtime-v2/SKILL.md +10 -0
- package/plugin/templates/langs/zh/skills/pd-cli-operator/SKILL.md +20 -11
- package/plugin/templates/langs/zh/skills/pd-runtime-v2/SKILL.md +10 -0
- package/console/dist/server/config/feature-flags.d.ts +0 -25
- package/console/dist/server/config/feature-flags.js +0 -101
- package/pd-cli/dist/commands/central-sync.d.ts +0 -10
- package/pd-cli/dist/commands/central-sync.d.ts.map +0 -1
- package/pd-cli/dist/commands/central-sync.js +0 -32
- package/pd-cli/dist/commands/central-sync.js.map +0 -1
- package/pd-cli/dist/services/feature-flag-loader.d.ts +0 -6
- package/pd-cli/dist/services/feature-flag-loader.d.ts.map +0 -1
- package/pd-cli/dist/services/feature-flag-loader.js +0 -53
- package/pd-cli/dist/services/feature-flag-loader.js.map +0 -1
- package/plugin/dist/core/observability.d.ts +0 -40
- package/plugin/dist/core/observability.js +0 -164
- package/plugin/dist/core/principle-tree-ledger-adapter.d.ts +0 -32
- package/plugin/dist/core/principle-tree-ledger-adapter.js +0 -125
- package/plugin/dist/hooks/subagent.d.ts +0 -9
- package/plugin/dist/hooks/subagent.js +0 -122
- package/plugin/dist/service/central-database.d.ts +0 -138
- package/plugin/dist/service/central-database.js +0 -731
- package/plugin/dist/service/central-sync-service.d.ts +0 -8
- package/plugin/dist/service/central-sync-service.js +0 -71
- package/plugin/scripts/validate-live-path.ts +0 -480
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IntentDecisions route — HTTP surface for IntentDecisionRecord (PRI-470, SPEC §21.7).
|
|
3
|
+
*
|
|
4
|
+
* Endpoints (all gated by the `intent_engineering` feature flag):
|
|
5
|
+
* - POST /api/v1/intent-decisions → create (201) or idempotent replay (200)
|
|
6
|
+
* - GET /api/v1/intent-decisions?painId=… → list by painId
|
|
7
|
+
* - GET /api/v1/intent-decisions?taskId=… → list by taskId
|
|
8
|
+
* - GET /api/v1/intent-decisions/summary → tallied summary (MUST precede /:id)
|
|
9
|
+
* - GET /api/v1/intent-decisions/:id → single record
|
|
10
|
+
* - POST /api/v1/intent-decisions/:id/follow-up → dispatch governed follow-up (PRI-471)
|
|
11
|
+
*
|
|
12
|
+
* PRI-471 follow-up types (SPEC §22.1.4):
|
|
13
|
+
* - link_candidate — record which existing principle candidate the Owner
|
|
14
|
+
* chose to link. Does NOT create a candidate.
|
|
15
|
+
* - guide_rulehost — returns the CLI guidance for promoting to RuleHost.
|
|
16
|
+
* Does NOT create a rule or approval directly.
|
|
17
|
+
* - generate_patch_proposal — generates a read-only Intent Patch Proposal and
|
|
18
|
+
* records its id on the decision. Does NOT modify
|
|
19
|
+
* `.principles/INTENT.md`.
|
|
20
|
+
*
|
|
21
|
+
* Runtime Contract rules applied:
|
|
22
|
+
* - Rule 1: parsed JSON body treated as `unknown` (ERR-001)
|
|
23
|
+
* - Rule 2: enum fields validated via core type guards, never `as` (ERR-001/ERR-005)
|
|
24
|
+
* - Rule 3: required fields fail loud → 400 with reason (ERR-009/ERR-010)
|
|
25
|
+
* - Rule 5: `Object.hasOwn()` for untrusted object keys (ERR-013)
|
|
26
|
+
* - Rule 9: every degraded path carries reason + nextAction (ERR-002)
|
|
27
|
+
*/
|
|
28
|
+
import { isIntentTensionSource, isEvidenceStrength, isIntentRelatedField, isSuggestedOwnerAction, generateIntentPatchProposal, } from '@principles/core/runtime-v2';
|
|
29
|
+
import { IntentDecisionModel } from '../models/IntentDecisionModel.js';
|
|
30
|
+
import { sendJson, sendSuccess, sendError, sendNotFound, sendBadRequest } from '../utils/response.js';
|
|
31
|
+
import { parseQuery, readBody } from '../utils/request.js';
|
|
32
|
+
import { loadPdConfig, computeFlagsFromLoadResult } from '../config/pd-config-store.js';
|
|
33
|
+
// Per-workspace model cache (same pattern as approvals.ts). IntentDecisionModel
|
|
34
|
+
// holds workspaceDir, so each workspace needs its own instance.
|
|
35
|
+
const models = new Map();
|
|
36
|
+
function getModel(workspaceDir) {
|
|
37
|
+
let model = models.get(workspaceDir);
|
|
38
|
+
if (!model) {
|
|
39
|
+
model = new IntentDecisionModel(workspaceDir);
|
|
40
|
+
models.set(workspaceDir, model);
|
|
41
|
+
}
|
|
42
|
+
return model;
|
|
43
|
+
}
|
|
44
|
+
function getErrorMessage(err) {
|
|
45
|
+
return err instanceof Error ? err.message : String(err);
|
|
46
|
+
}
|
|
47
|
+
function isRecord(value) {
|
|
48
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
49
|
+
}
|
|
50
|
+
function tryParseJson(body) {
|
|
51
|
+
try {
|
|
52
|
+
return JSON.parse(body);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function parseJsonBody(body, res) {
|
|
59
|
+
const raw = tryParseJson(body);
|
|
60
|
+
if (raw === undefined) {
|
|
61
|
+
sendBadRequest(res, 'Invalid JSON body');
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
if (!isRecord(raw)) {
|
|
65
|
+
sendBadRequest(res, 'Request body must be a JSON object');
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
return raw;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Feature flag gate: `intent_engineering` MUST be enabled for any
|
|
72
|
+
* intent-decisions operation. Fail-closed with a structured reason (ERR-002).
|
|
73
|
+
* Returns true when the caller may proceed.
|
|
74
|
+
*/
|
|
75
|
+
function checkFlag(workspaceDir, res) {
|
|
76
|
+
const configResult = loadPdConfig(workspaceDir);
|
|
77
|
+
const flagsResult = computeFlagsFromLoadResult(configResult);
|
|
78
|
+
const flagEnabled = flagsResult.flags.intent_engineering?.enabled === true;
|
|
79
|
+
if (!flagEnabled) {
|
|
80
|
+
sendError(res, 403, 'Feature intent_engineering is disabled', 'Feature intent_engineering is disabled', {
|
|
81
|
+
reason: 'flag_disabled',
|
|
82
|
+
nextAction: 'Enable intent_engineering flag to use this endpoint',
|
|
83
|
+
});
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Validate an untrusted JSON object into a fully-typed IntentDecisionInput.
|
|
90
|
+
* Returns null (after sending a 400) on any validation failure.
|
|
91
|
+
*
|
|
92
|
+
* Required fields are destructured first (satisfies prefer-destructuring) then
|
|
93
|
+
* narrowed by type guards on the LOCAL binding — this keeps TypeScript's control
|
|
94
|
+
* flow narrowing reliable across subsequent function calls (Rule 2: no `as`).
|
|
95
|
+
* Optional fields use Object.hasOwn to distinguish present-vs-absent (Rule 5).
|
|
96
|
+
*/
|
|
97
|
+
function validateInput(parsed, res) {
|
|
98
|
+
const { id, source, evidenceStrength, ownerAction, relatedIntentFields, evidenceRefs } = parsed;
|
|
99
|
+
// id — required non-empty string
|
|
100
|
+
if (typeof id !== 'string' || id === '') {
|
|
101
|
+
sendBadRequest(res, 'id is required and must be a non-empty string');
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
// source — required IntentTensionSource (Rule 2: type guard, no `as`)
|
|
105
|
+
if (!isIntentTensionSource(source)) {
|
|
106
|
+
sendBadRequest(res, 'source is required and must be a valid IntentTensionSource');
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
// evidenceStrength — required EvidenceStrength
|
|
110
|
+
if (!isEvidenceStrength(evidenceStrength)) {
|
|
111
|
+
sendBadRequest(res, 'evidenceStrength is required and must be a valid EvidenceStrength');
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
// ownerAction — required SuggestedOwnerAction
|
|
115
|
+
if (!isSuggestedOwnerAction(ownerAction)) {
|
|
116
|
+
sendBadRequest(res, 'ownerAction is required and must be a valid SuggestedOwnerAction');
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
// relatedIntentFields — required IntentRelatedField[] (Rule 4: element-wise)
|
|
120
|
+
if (!Array.isArray(relatedIntentFields)) {
|
|
121
|
+
sendBadRequest(res, 'relatedIntentFields is required and must be an array');
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
const typedFields = [];
|
|
125
|
+
for (const field of relatedIntentFields) {
|
|
126
|
+
if (!isIntentRelatedField(field)) {
|
|
127
|
+
sendBadRequest(res, 'relatedIntentFields contains an invalid IntentRelatedField: ' + String(field));
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
typedFields.push(field);
|
|
131
|
+
}
|
|
132
|
+
// evidenceRefs — required string[] (Rule 4: element-wise)
|
|
133
|
+
if (!Array.isArray(evidenceRefs)) {
|
|
134
|
+
sendBadRequest(res, 'evidenceRefs is required and must be an array');
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
const typedRefs = [];
|
|
138
|
+
for (const ref of evidenceRefs) {
|
|
139
|
+
if (typeof ref !== 'string') {
|
|
140
|
+
sendBadRequest(res, 'evidenceRefs must contain only strings');
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
typedRefs.push(ref);
|
|
144
|
+
}
|
|
145
|
+
// Optional string fields — validated only when present (Rule 5: Object.hasOwn)
|
|
146
|
+
const optionalStringFields = ['painId', 'taskId', 'runId', 'intentDocHash', 'note'];
|
|
147
|
+
const optional = {};
|
|
148
|
+
for (const key of optionalStringFields) {
|
|
149
|
+
if (Object.hasOwn(parsed, key)) {
|
|
150
|
+
const value = parsed[key];
|
|
151
|
+
if (typeof value !== 'string') {
|
|
152
|
+
sendBadRequest(res, key + ' must be a string when present');
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
optional[key] = value;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
id,
|
|
160
|
+
source,
|
|
161
|
+
evidenceStrength,
|
|
162
|
+
ownerAction,
|
|
163
|
+
relatedIntentFields: typedFields,
|
|
164
|
+
evidenceRefs: typedRefs,
|
|
165
|
+
painId: optional.painId,
|
|
166
|
+
taskId: optional.taskId,
|
|
167
|
+
runId: optional.runId,
|
|
168
|
+
intentDocHash: optional.intentDocHash,
|
|
169
|
+
note: optional.note,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Map a model-level failure (IntentDecisionRecordResultModel ok:false) to an
|
|
174
|
+
* HTTP error with reason + nextAction (Rule 9).
|
|
175
|
+
*/
|
|
176
|
+
function sendModelFailure(res, result) {
|
|
177
|
+
if (result.reason === 'state_db_not_found') {
|
|
178
|
+
sendError(res, 409, 'workspace_not_initialized', result.reason, {
|
|
179
|
+
reason: result.reason,
|
|
180
|
+
nextAction: result.nextAction,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
sendError(res, 500, 'intent_decision_store_error', result.reason, {
|
|
185
|
+
reason: result.reason,
|
|
186
|
+
nextAction: result.nextAction,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const FOLLOW_UP_TYPES = new Set([
|
|
191
|
+
'link_candidate',
|
|
192
|
+
'guide_rulehost',
|
|
193
|
+
'generate_patch_proposal',
|
|
194
|
+
]);
|
|
195
|
+
/**
|
|
196
|
+
* Validate the body of POST /api/v1/intent-decisions/:id/follow-up.
|
|
197
|
+
*
|
|
198
|
+
* Body shape: `{ type: 'link_candidate' | 'guide_rulehost' | 'generate_patch_proposal', candidateId?: string }`
|
|
199
|
+
*
|
|
200
|
+
* - `type` is required and must be one of the three allowed values (Rule 2).
|
|
201
|
+
* - `candidateId` is REQUIRED when `type === 'link_candidate'` (Rule 3: fail loud).
|
|
202
|
+
* - `candidateId` is IGNORED for other types (not an error — the frontend may
|
|
203
|
+
* send it as part of a generic payload).
|
|
204
|
+
*/
|
|
205
|
+
function validateFollowUpInput(parsed, res) {
|
|
206
|
+
if (!Object.hasOwn(parsed, 'type')) {
|
|
207
|
+
sendBadRequest(res, 'type is required');
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
const { type } = parsed;
|
|
211
|
+
if (typeof type !== 'string' || !FOLLOW_UP_TYPES.has(type)) {
|
|
212
|
+
sendBadRequest(res, 'type must be one of: link_candidate, guide_rulehost, generate_patch_proposal');
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
const typedType = type;
|
|
216
|
+
// candidateId: required for link_candidate, optional otherwise.
|
|
217
|
+
if (typedType === 'link_candidate') {
|
|
218
|
+
if (!Object.hasOwn(parsed, 'candidateId')) {
|
|
219
|
+
sendBadRequest(res, 'candidateId is required when type is link_candidate');
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
const { candidateId } = parsed;
|
|
223
|
+
if (typeof candidateId !== 'string') {
|
|
224
|
+
sendBadRequest(res, 'candidateId must be a string when type is link_candidate');
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
// Normalize at the trust boundary (EP-01): trim, then reject
|
|
228
|
+
// whitespace-only ids so they cannot pollute the audit trail.
|
|
229
|
+
const trimmed = candidateId.trim();
|
|
230
|
+
if (trimmed === '') {
|
|
231
|
+
sendBadRequest(res, 'candidateId must be a non-empty string when type is link_candidate');
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
return { type: typedType, candidateId: trimmed };
|
|
235
|
+
}
|
|
236
|
+
// For other types, candidateId is optional and ignored if present.
|
|
237
|
+
// We do not validate its type here — it is simply not read.
|
|
238
|
+
return { type: typedType, candidateId: '' };
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Map a follow-up model-level failure to an HTTP error with reason + nextAction (Rule 9).
|
|
242
|
+
*/
|
|
243
|
+
function sendFollowUpModelFailure(res, result) {
|
|
244
|
+
if (result.reason === 'decision_not_found') {
|
|
245
|
+
sendNotFound(res, result.nextAction);
|
|
246
|
+
}
|
|
247
|
+
else if (result.reason === 'state_db_not_found') {
|
|
248
|
+
sendError(res, 409, 'workspace_not_initialized', result.reason, {
|
|
249
|
+
reason: result.reason,
|
|
250
|
+
nextAction: result.nextAction,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
sendError(res, 500, 'intent_decision_follow_up_store_error', result.reason, {
|
|
255
|
+
reason: result.reason,
|
|
256
|
+
nextAction: result.nextAction,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/* eslint-disable @typescript-eslint/max-params */
|
|
261
|
+
export async function handleIntentDecisionsRoute(req, res, workspaceDir, subPath) {
|
|
262
|
+
// Feature flag gate applies to every method on this route.
|
|
263
|
+
if (!checkFlag(workspaceDir, res))
|
|
264
|
+
return;
|
|
265
|
+
const model = getModel(workspaceDir);
|
|
266
|
+
// POST /api/v1/intent-decisions — create / idempotent replay
|
|
267
|
+
if (req.method === 'POST' && (subPath === '' || subPath === '/')) {
|
|
268
|
+
try {
|
|
269
|
+
const body = await readBody(req);
|
|
270
|
+
const parsed = parseJsonBody(body, res);
|
|
271
|
+
if (!parsed)
|
|
272
|
+
return;
|
|
273
|
+
const input = validateInput(parsed, res);
|
|
274
|
+
if (!input)
|
|
275
|
+
return;
|
|
276
|
+
const result = await model.record(input);
|
|
277
|
+
if (!result.ok) {
|
|
278
|
+
sendModelFailure(res, result);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
// Response envelope matches IntentDecisionResultData: { record, created }.
|
|
282
|
+
// The `created` flag lets the frontend distinguish a fresh write from a
|
|
283
|
+
// replay (200 vs 201 HTTP status also conveys this).
|
|
284
|
+
const responseData = { record: result.record, created: result.created };
|
|
285
|
+
if (result.created) {
|
|
286
|
+
// Fresh create → 201 (sendJson with explicit status; sendSuccess is 200-only).
|
|
287
|
+
sendJson(res, 201, { success: true, data: responseData });
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
// Idempotent replay → 200 with the pre-existing record.
|
|
291
|
+
sendSuccess(res, responseData);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
catch (err) {
|
|
295
|
+
const message = getErrorMessage(err);
|
|
296
|
+
if (message === 'Request body too large') {
|
|
297
|
+
sendError(res, 413, 'payload_too_large', message);
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
sendError(res, 500, 'intent_decision_create_error', message);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
// GET /api/v1/intent-decisions — list by painId OR taskId (exactly one required)
|
|
306
|
+
if (req.method === 'GET' && (subPath === '' || subPath === '/')) {
|
|
307
|
+
try {
|
|
308
|
+
const query = parseQuery(req.url ?? '');
|
|
309
|
+
const hasPainId = Object.hasOwn(query, 'painId');
|
|
310
|
+
const hasTaskId = Object.hasOwn(query, 'taskId');
|
|
311
|
+
if (!hasPainId && !hasTaskId) {
|
|
312
|
+
sendBadRequest(res, 'Either painId or taskId query parameter is required');
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
if (hasPainId && hasTaskId) {
|
|
316
|
+
sendBadRequest(res, 'Provide either painId or taskId, not both');
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
if (hasPainId) {
|
|
320
|
+
const { painId } = query;
|
|
321
|
+
if (!painId) {
|
|
322
|
+
sendBadRequest(res, 'painId must not be empty');
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
const items = await model.listByPainId(painId);
|
|
326
|
+
sendSuccess(res, items);
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
const { taskId } = query;
|
|
330
|
+
if (!taskId) {
|
|
331
|
+
sendBadRequest(res, 'taskId must not be empty');
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
const items = await model.listByTaskId(taskId);
|
|
335
|
+
sendSuccess(res, items);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
catch (err) {
|
|
339
|
+
sendError(res, 500, 'intent_decision_list_error', getErrorMessage(err));
|
|
340
|
+
}
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
// GET /api/v1/intent-decisions/summary — MUST be matched before /:id
|
|
344
|
+
if (req.method === 'GET' && subPath === '/summary') {
|
|
345
|
+
try {
|
|
346
|
+
const summary = await model.getSummary();
|
|
347
|
+
sendSuccess(res, summary);
|
|
348
|
+
}
|
|
349
|
+
catch (err) {
|
|
350
|
+
sendError(res, 500, 'intent_decision_summary_error', getErrorMessage(err));
|
|
351
|
+
}
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
// GET /api/v1/intent-decisions/:id — single record
|
|
355
|
+
const detailMatch = /^[/]([^/]+)$/.exec(subPath);
|
|
356
|
+
if (req.method === 'GET' && detailMatch) {
|
|
357
|
+
const [, rawId] = detailMatch;
|
|
358
|
+
if (!rawId) {
|
|
359
|
+
sendError(res, 400, 'invalid_id', 'Intent decision id is missing');
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
let recordId;
|
|
363
|
+
try {
|
|
364
|
+
recordId = decodeURIComponent(rawId);
|
|
365
|
+
}
|
|
366
|
+
catch {
|
|
367
|
+
sendError(res, 400, 'invalid_id', 'Intent decision id contains invalid URI encoding');
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
try {
|
|
371
|
+
const record = await model.getById(recordId);
|
|
372
|
+
if (!record) {
|
|
373
|
+
sendNotFound(res, 'Intent decision ' + recordId + ' not found');
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
sendSuccess(res, record);
|
|
377
|
+
}
|
|
378
|
+
catch (err) {
|
|
379
|
+
sendError(res, 500, 'intent_decision_detail_error', getErrorMessage(err));
|
|
380
|
+
}
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
// POST /api/v1/intent-decisions/:id/follow-up — PRI-471 governed follow-up
|
|
384
|
+
// (SPEC §22.1.4). MUST be matched before the catch-all 404 below.
|
|
385
|
+
const followUpMatch = /^[/]([^/]+)[/]follow-up$/.exec(subPath);
|
|
386
|
+
if (req.method === 'POST' && followUpMatch) {
|
|
387
|
+
try {
|
|
388
|
+
const [, rawId] = followUpMatch;
|
|
389
|
+
if (!rawId) {
|
|
390
|
+
sendError(res, 400, 'invalid_id', 'Intent decision id is missing');
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
let decisionId;
|
|
394
|
+
try {
|
|
395
|
+
decisionId = decodeURIComponent(rawId);
|
|
396
|
+
}
|
|
397
|
+
catch {
|
|
398
|
+
sendError(res, 400, 'invalid_id', 'Intent decision id contains invalid URI encoding');
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
const body = await readBody(req);
|
|
402
|
+
const parsed = parseJsonBody(body, res);
|
|
403
|
+
if (!parsed)
|
|
404
|
+
return;
|
|
405
|
+
const followUpInput = validateFollowUpInput(parsed, res);
|
|
406
|
+
if (!followUpInput)
|
|
407
|
+
return;
|
|
408
|
+
// ── guide_rulehost: pure guidance, no DB write ──────────────────────
|
|
409
|
+
// SPEC §22.1.4: promote_to_rulehost goes through the existing RuleHost
|
|
410
|
+
// candidate/approval path. PD does NOT create a rule or approval here —
|
|
411
|
+
// the Owner runs the CLI command, which enqueues a code_tool_hook
|
|
412
|
+
// approval that the Owner can review in the Governance Queue.
|
|
413
|
+
if (followUpInput.type === 'guide_rulehost') {
|
|
414
|
+
// Verify the decision exists so we don't return guidance for a
|
|
415
|
+
// non-existent record (fail loud, ERR-009).
|
|
416
|
+
const existing = await model.getById(decisionId);
|
|
417
|
+
if (!existing) {
|
|
418
|
+
sendNotFound(res, 'Intent decision ' + decisionId + ' not found');
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
sendSuccess(res, {
|
|
422
|
+
type: 'guide_rulehost',
|
|
423
|
+
cliCommand: 'pd runtime rulehost',
|
|
424
|
+
note: 'Run this command in your workspace terminal. PD will create a RuleHost approval that you can review in the Governance Queue. After approval, the resulting rule candidate id can be linked back to this decision.',
|
|
425
|
+
decisionId,
|
|
426
|
+
});
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
// ── generate_patch_proposal: pure function + DB write ───────────────
|
|
430
|
+
// SPEC §10 + §22.1.4: revise_intent creates a read-only patch proposal
|
|
431
|
+
// that the Owner can review and manually apply. PD does NOT auto-apply
|
|
432
|
+
// the patch to .principles/INTENT.md.
|
|
433
|
+
if (followUpInput.type === 'generate_patch_proposal') {
|
|
434
|
+
const existing = await model.getById(decisionId);
|
|
435
|
+
if (!existing) {
|
|
436
|
+
sendNotFound(res, 'Intent decision ' + decisionId + ' not found');
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
const proposal = generateIntentPatchProposal(existing);
|
|
440
|
+
const patch = { patchProposalId: proposal.id };
|
|
441
|
+
const result = await model.updateFollowUp(decisionId, patch);
|
|
442
|
+
if (!result.ok) {
|
|
443
|
+
sendFollowUpModelFailure(res, result);
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
sendSuccess(res, {
|
|
447
|
+
type: 'generate_patch_proposal',
|
|
448
|
+
decisionId,
|
|
449
|
+
record: result.record,
|
|
450
|
+
patchProposal: { id: proposal.id, markdown: proposal.markdown },
|
|
451
|
+
});
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
// ── link_candidate: record which candidate the Owner chose ─────────
|
|
455
|
+
// SPEC §22.1.4: confirm_drift can link to an existing principle
|
|
456
|
+
// candidate. PD does NOT create a candidate here — candidates are
|
|
457
|
+
// created by the diagnostician committer during normal pain →
|
|
458
|
+
// diagnosis flow. The Owner links an existing candidate so the audit
|
|
459
|
+
// trail records which candidate the Owner chose to sediment this
|
|
460
|
+
// decision into.
|
|
461
|
+
if (followUpInput.type === 'link_candidate') {
|
|
462
|
+
const { candidateId } = followUpInput;
|
|
463
|
+
const patch = { resultingCandidateId: candidateId };
|
|
464
|
+
const result = await model.updateFollowUp(decisionId, patch);
|
|
465
|
+
if (!result.ok) {
|
|
466
|
+
sendFollowUpModelFailure(res, result);
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
sendSuccess(res, {
|
|
470
|
+
type: 'link_candidate',
|
|
471
|
+
decisionId,
|
|
472
|
+
record: result.record,
|
|
473
|
+
linkedCandidateId: candidateId,
|
|
474
|
+
});
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
// Unreachable: validateFollowUpInput already narrowed the union.
|
|
478
|
+
// Defensive guard for future enum additions.
|
|
479
|
+
sendBadRequest(res, 'Unknown follow-up type: ' + String(followUpInput.type));
|
|
480
|
+
}
|
|
481
|
+
catch (err) {
|
|
482
|
+
const message = getErrorMessage(err);
|
|
483
|
+
if (message === 'Request body too large') {
|
|
484
|
+
sendError(res, 413, 'payload_too_large', message);
|
|
485
|
+
}
|
|
486
|
+
else {
|
|
487
|
+
sendError(res, 500, 'intent_decision_follow_up_error', message);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
sendNotFound(res, 'Route /api/v1/intent-decisions' + subPath + ' not found');
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Dispose hook for graceful shutdown — clears the per-workspace model cache.
|
|
496
|
+
*/
|
|
497
|
+
export function disposeIntentDecisionModels() {
|
|
498
|
+
models.clear();
|
|
499
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { IntentPageModel } from '../models/IntentPageModel.js';
|
|
2
|
+
import { sendSuccess, sendError } from '../utils/response.js';
|
|
3
|
+
import { loadPdConfig, computeFlagsFromLoadResult } from '../config/pd-config-store.js';
|
|
4
|
+
const MODEL_CACHE_TTL_MS = 30 * 1000;
|
|
5
|
+
const models = new Map();
|
|
6
|
+
function getModel(workspaceDir) {
|
|
7
|
+
const cached = models.get(workspaceDir);
|
|
8
|
+
if (cached && Date.now() - cached.cachedAt < MODEL_CACHE_TTL_MS) {
|
|
9
|
+
return cached.model;
|
|
10
|
+
}
|
|
11
|
+
const model = new IntentPageModel(workspaceDir);
|
|
12
|
+
models.set(workspaceDir, { model, cachedAt: Date.now() });
|
|
13
|
+
return model;
|
|
14
|
+
}
|
|
15
|
+
export async function handleIntentRoute(req, res, workspaceDir) {
|
|
16
|
+
if (req.method !== 'GET') {
|
|
17
|
+
sendError(res, 405, 'method_not_allowed', 'Only GET method is allowed');
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
const configResult = loadPdConfig(workspaceDir);
|
|
22
|
+
const flagsResult = computeFlagsFromLoadResult(configResult);
|
|
23
|
+
const flagEnabled = flagsResult.flags.intent_engineering?.enabled === true;
|
|
24
|
+
const model = getModel(workspaceDir);
|
|
25
|
+
const summary = await model.getSummary(flagEnabled);
|
|
26
|
+
sendSuccess(res, summary);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
sendError(res, 500, 'intent_route_error', err instanceof Error ? err.message : 'Unknown error');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function disposeIntentModels() {
|
|
33
|
+
// IntentPageModel holds no persistent resources; just clear the cache.
|
|
34
|
+
models.clear();
|
|
35
|
+
}
|
|
@@ -73,11 +73,77 @@ async function getDecidedPrincipleIds(workspaceDir) {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
export async function handlePrinciplesRoute({ req, res, workspaceDir, subPath, }) {
|
|
76
|
+
const model = getModel(workspaceDir);
|
|
77
|
+
// ── POST Routes ─────────────────────────────────────────────────────────────
|
|
78
|
+
if (req.method === 'POST') {
|
|
79
|
+
// POST /api/principles/:id/archive
|
|
80
|
+
const archiveMatch = /^\/([^/]*)\/archive$/.exec(subPath);
|
|
81
|
+
if (archiveMatch) {
|
|
82
|
+
const [, rawPrincipleId] = archiveMatch;
|
|
83
|
+
if (!rawPrincipleId) {
|
|
84
|
+
sendError(res, 400, 'invalid_principle_id', 'Principle ID is missing');
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
let principleId;
|
|
88
|
+
try {
|
|
89
|
+
principleId = decodeURIComponent(rawPrincipleId);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
sendError(res, 400, 'invalid_principle_id', 'Principle ID contains invalid URL encoding');
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
const ok = await model.archivePrinciple(principleId);
|
|
97
|
+
if (ok) {
|
|
98
|
+
sendSuccess(res, { success: true, principleId });
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
sendError(res, 500, 'archive_failed', `Failed to archive principle "${principleId}"`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
sendError(res, 500, 'archive_failed', err instanceof Error ? err.message : String(err));
|
|
106
|
+
}
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// POST /api/principles/:id/unarchive
|
|
110
|
+
const unarchiveMatch = /^\/([^/]*)\/unarchive$/.exec(subPath);
|
|
111
|
+
if (unarchiveMatch) {
|
|
112
|
+
const [, rawPrincipleId] = unarchiveMatch;
|
|
113
|
+
if (!rawPrincipleId) {
|
|
114
|
+
sendError(res, 400, 'invalid_principle_id', 'Principle ID is missing');
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
let principleId;
|
|
118
|
+
try {
|
|
119
|
+
principleId = decodeURIComponent(rawPrincipleId);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
sendError(res, 400, 'invalid_principle_id', 'Principle ID contains invalid URL encoding');
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
try {
|
|
126
|
+
const ok = await model.unarchivePrinciple(principleId);
|
|
127
|
+
if (ok) {
|
|
128
|
+
sendSuccess(res, { success: true, principleId });
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
sendError(res, 500, 'unarchive_failed', `Failed to unarchive principle "${principleId}"`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
sendError(res, 500, 'unarchive_failed', err instanceof Error ? err.message : String(err));
|
|
136
|
+
}
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
sendNotFound(res, `Route ${req.method} /api/principles${subPath} not found`);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
// ── GET Routes ──────────────────────────────────────────────────────────────
|
|
76
143
|
if (req.method !== 'GET') {
|
|
77
144
|
sendNotFound(res, `Route /api/principles${subPath} not found`);
|
|
78
145
|
return;
|
|
79
146
|
}
|
|
80
|
-
const model = getModel(workspaceDir);
|
|
81
147
|
if (subPath === '' || subPath === '/') {
|
|
82
148
|
try {
|
|
83
149
|
// Parse query string for filter parameter
|
|
@@ -183,6 +183,11 @@ async function doCheckForUpdates(currentVersion) {
|
|
|
183
183
|
return {
|
|
184
184
|
hasUpdate: false,
|
|
185
185
|
currentVersion,
|
|
186
|
+
// Contract with the UI (UpdatePage.tsx) requires latestVersion to be a
|
|
187
|
+
// string. When the registry check fails we don't know the latest version,
|
|
188
|
+
// so emit an empty string to keep the response shape stable and let the
|
|
189
|
+
// UI surface `error` instead of crashing the whole page.
|
|
190
|
+
latestVersion: '',
|
|
186
191
|
error: error instanceof Error ? error.message : 'Unknown error',
|
|
187
192
|
};
|
|
188
193
|
}
|
|
@@ -369,9 +374,17 @@ export async function handleUpdateRoute(req, res, workspaceDir, subPath) {
|
|
|
369
374
|
return;
|
|
370
375
|
}
|
|
371
376
|
try {
|
|
377
|
+
// ERR-002 / Runtime Contract Rule 9: 当无法确定当前版本时(如插件未安装),
|
|
378
|
+
// 返回 degraded 状态 + reason,而非 500。前端 validateUpdateStatus 要求
|
|
379
|
+
// currentVersion/latestVersion 为 string,hasUpdate 为 boolean。
|
|
372
380
|
const currentVersion = readCurrentVersion(pluginDir);
|
|
373
381
|
if (!currentVersion) {
|
|
374
|
-
|
|
382
|
+
sendSuccess(res, {
|
|
383
|
+
hasUpdate: false,
|
|
384
|
+
currentVersion: 'unknown',
|
|
385
|
+
latestVersion: '',
|
|
386
|
+
error: 'Could not determine current version (plugin not installed)',
|
|
387
|
+
});
|
|
375
388
|
return;
|
|
376
389
|
}
|
|
377
390
|
const result = await doCheckForUpdates(currentVersion);
|
|
@@ -427,16 +440,6 @@ export async function handleUpdateRoute(req, res, workspaceDir, subPath) {
|
|
|
427
440
|
}
|
|
428
441
|
return;
|
|
429
442
|
}
|
|
430
|
-
// GET /status
|
|
431
|
-
if (subPath === '/status') {
|
|
432
|
-
if (req.method !== 'GET') {
|
|
433
|
-
sendMethodNotAllowed(res);
|
|
434
|
-
return;
|
|
435
|
-
}
|
|
436
|
-
const currentVersion = readCurrentVersion(pluginDir) ?? 'unknown';
|
|
437
|
-
sendSuccess(res, { checking: false, updating: false, currentVersion });
|
|
438
|
-
return;
|
|
439
|
-
}
|
|
440
443
|
// POST /rollback
|
|
441
444
|
if (subPath === '/rollback') {
|
|
442
445
|
if (req.method !== 'POST') {
|