create-principles-disciple 1.94.0 → 1.96.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 +33 -0
- package/console/dist/server/config/pd-config-store.js +196 -0
- package/console/dist/server/index.js +19 -4
- 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 +52 -0
- package/console/dist/server/models/IntentPageModel.js +292 -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/intent-decisions.d.ts +33 -0
- package/console/dist/server/routes/intent-decisions.js +499 -0
- package/console/dist/server/routes/intent.d.ts +7 -0
- package/console/dist/server/routes/intent.js +223 -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/types.d.ts +1 -0
- package/console/dist/ui/App.js +2 -60
- package/console/dist/ui/api.d.ts +58 -18
- package/console/dist/ui/api.js +78 -6
- package/console/dist/ui/components/layout/app-sidebar.js +13 -12
- 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 +306 -3
- package/console/dist/ui/i18n/zh-CN.json +306 -3
- package/console/dist/ui/pages/activation/ActivationPage.js +2 -1
- package/console/dist/ui/pages/control-center/AgentCard.d.ts +31 -0
- package/console/dist/ui/pages/control-center/AgentCard.js +156 -0
- package/console/dist/ui/pages/control-center/AgentGroup.d.ts +26 -0
- package/console/dist/ui/pages/control-center/AgentGroup.js +38 -0
- package/console/dist/ui/pages/control-center/ControlCenterPage.js +103 -41
- 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/control-center/WorkflowDiagram.d.ts +17 -0
- package/console/dist/ui/pages/control-center/WorkflowDiagram.js +55 -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/IntentOnboarding.d.ts +67 -0
- package/console/dist/ui/pages/intent/IntentOnboarding.js +289 -0
- package/console/dist/ui/pages/intent/IntentPage.d.ts +1 -0
- package/console/dist/ui/pages/intent/IntentPage.js +258 -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/agent-metadata.d.ts +58 -0
- package/console/dist/ui/utils/agent-metadata.js +275 -0
- package/console/dist/ui/utils/control-center-helpers.d.ts +19 -0
- package/console/dist/ui/utils/control-center-helpers.js +37 -0
- package/console/dist/ui/utils/validators.d.ts +200 -0
- package/console/dist/ui/utils/validators.js +563 -0
- package/console/dist/web/assets/app.css +498 -3
- package/console/dist/web/assets/app.js +5063 -1418
- package/console/package.json +3 -0
- 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__/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/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/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/runtime-v2/__tests__/architecture-regression.test.js +143 -65
- package/core/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/evaluator-runner-vslice-v2.test.js +85 -7
- package/core/dist/runtime-v2/__tests__/evaluator-runner-vslice-v2.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__/golden-trace-replay-validator.test.js +70 -0
- package/core/dist/runtime-v2/__tests__/golden-trace-replay-validator.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/golden-trace.test.js +136 -1
- package/core/dist/runtime-v2/__tests__/golden-trace.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/pain-signal-bridge-result-shaping.test.js +105 -0
- package/core/dist/runtime-v2/__tests__/pain-signal-bridge-result-shaping.test.js.map +1 -1
- 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/__tests__/v2-adversarial-cases.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/v2-adversarial-cases.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/v2-adversarial-cases.test.js +211 -0
- package/core/dist/runtime-v2/__tests__/v2-adversarial-cases.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 +158 -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 +11 -0
- 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 +55 -11
- package/core/dist/runtime-v2/activation/writers/rule-host-writer.js.map +1 -1
- 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/source-descriptors.d.ts +1 -1
- package/core/dist/runtime-v2/evidence-triage/source-descriptors.js +1 -1
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js +23 -0
- 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/__tests__/rulecode-context-v2-flag.test.d.ts +2 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/rulecode-context-v2-flag.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/rulecode-context-v2-flag.test.js +74 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/rulecode-context-v2-flag.test.js.map +1 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/surface-guard-policy.test.d.ts +2 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/surface-guard-policy.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/surface-guard-policy.test.js +246 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/surface-guard-policy.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 +9 -0
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/index.d.ts +2 -0
- package/core/dist/runtime-v2/feature-flags/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/feature-flags/index.js +2 -0
- package/core/dist/runtime-v2/feature-flags/index.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/{plugin/dist/core/surface-guard.d.ts → core/dist/runtime-v2/feature-flags/surface-guard-policy.d.ts} +15 -5
- package/core/dist/runtime-v2/feature-flags/surface-guard-policy.d.ts.map +1 -0
- package/{plugin/dist/core/surface-guard.js → core/dist/runtime-v2/feature-flags/surface-guard-policy.js} +14 -2
- package/core/dist/runtime-v2/feature-flags/surface-guard-policy.js.map +1 -0
- package/core/dist/runtime-v2/golden-trace-replay-validator.js +1 -1
- package/core/dist/runtime-v2/golden-trace-replay-validator.js.map +1 -1
- package/core/dist/runtime-v2/golden-trace.d.ts +19 -3
- package/core/dist/runtime-v2/golden-trace.d.ts.map +1 -1
- package/core/dist/runtime-v2/golden-trace.js +2 -0
- package/core/dist/runtime-v2/golden-trace.js.map +1 -1
- package/core/dist/runtime-v2/index.d.ts +21 -4
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +21 -3
- 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-version.test.d.ts +2 -0
- package/core/dist/runtime-v2/intent/__tests__/intent-doc-version.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/intent/__tests__/intent-doc-version.test.js +88 -0
- package/core/dist/runtime-v2/intent/__tests__/intent-doc-version.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 +181 -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 +8 -0
- package/core/dist/runtime-v2/intent/index.d.ts.map +1 -0
- package/core/dist/runtime-v2/intent/index.js +8 -0
- package/core/dist/runtime-v2/intent/index.js.map +1 -0
- package/core/dist/runtime-v2/intent/intent-browser.d.ts +23 -0
- package/core/dist/runtime-v2/intent/intent-browser.d.ts.map +1 -0
- package/core/dist/runtime-v2/intent/intent-browser.js +21 -0
- package/core/dist/runtime-v2/intent/intent-browser.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-version.d.ts +28 -0
- package/core/dist/runtime-v2/intent/intent-doc-version.d.ts.map +1 -0
- package/core/dist/runtime-v2/intent/intent-doc-version.js +21 -0
- package/core/dist/runtime-v2/intent/intent-doc-version.js.map +1 -0
- package/core/dist/runtime-v2/intent/intent-doc.d.ts +35 -0
- package/core/dist/runtime-v2/intent/intent-doc.d.ts.map +1 -0
- package/core/dist/runtime-v2/intent/intent-doc.js +158 -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-hash.d.ts +2 -0
- package/core/dist/runtime-v2/intent/intent-hash.d.ts.map +1 -0
- package/core/dist/runtime-v2/intent/intent-hash.js +10 -0
- package/core/dist/runtime-v2/intent/intent-hash.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__/artificer-prompt-builder.test.js +41 -1
- package/core/dist/runtime-v2/internalization/__tests__/artificer-prompt-builder.test.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/artificer-rule-output.test.js +130 -2
- package/core/dist/runtime-v2/internalization/__tests__/artificer-rule-output.test.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/behavior-example-pack.test.d.ts +2 -0
- package/core/dist/runtime-v2/internalization/__tests__/behavior-example-pack.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/__tests__/behavior-example-pack.test.js +228 -0
- package/core/dist/runtime-v2/internalization/__tests__/behavior-example-pack.test.js.map +1 -0
- package/core/dist/runtime-v2/internalization/__tests__/diag-chain-e2e.test.js +41 -11
- package/core/dist/runtime-v2/internalization/__tests__/diag-chain-e2e.test.js.map +1 -1
- 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/__tests__/refiner-sandbox-wrapper.test.js +135 -0
- package/core/dist/runtime-v2/internalization/__tests__/refiner-sandbox-wrapper.test.js.map +1 -1
- package/core/dist/runtime-v2/internalization/__tests__/rule-context-v2.test.d.ts +2 -0
- package/core/dist/runtime-v2/internalization/__tests__/rule-context-v2.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/__tests__/rule-context-v2.test.js +449 -0
- package/core/dist/runtime-v2/internalization/__tests__/rule-context-v2.test.js.map +1 -0
- package/core/dist/runtime-v2/internalization/adversarial-case.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/adversarial-case.js +24 -0
- package/core/dist/runtime-v2/internalization/adversarial-case.js.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-output.d.ts +10 -0
- package/core/dist/runtime-v2/internalization/artificer-output.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-output.js +45 -0
- package/core/dist/runtime-v2/internalization/artificer-output.js.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-prompt-builder.d.ts +2 -2
- package/core/dist/runtime-v2/internalization/artificer-prompt-builder.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-prompt-builder.js +7 -2
- package/core/dist/runtime-v2/internalization/artificer-prompt-builder.js.map +1 -1
- package/core/dist/runtime-v2/internalization/behavior-example-pack.d.ts +66 -0
- package/core/dist/runtime-v2/internalization/behavior-example-pack.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/behavior-example-pack.js +183 -0
- package/core/dist/runtime-v2/internalization/behavior-example-pack.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/evaluator-output.d.ts +8 -0
- package/core/dist/runtime-v2/internalization/evaluator-output.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-output.js +10 -0
- package/core/dist/runtime-v2/internalization/evaluator-output.js.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-runner.d.ts +17 -0
- package/core/dist/runtime-v2/internalization/evaluator-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-runner.js +118 -24
- package/core/dist/runtime-v2/internalization/evaluator-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/refiner-sandbox-wrapper.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/refiner-sandbox-wrapper.js +1 -1
- package/core/dist/runtime-v2/internalization/refiner-sandbox-wrapper.js.map +1 -1
- package/core/dist/runtime-v2/internalization/rule-context-v2.d.ts +61 -0
- package/core/dist/runtime-v2/internalization/rule-context-v2.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/rule-context-v2.js +301 -0
- package/core/dist/runtime-v2/internalization/rule-context-v2.js.map +1 -0
- package/core/dist/runtime-v2/internalization/rule-host-contracts.d.ts +9 -0
- package/core/dist/runtime-v2/internalization/rule-host-contracts.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/v2-adversarial-cases.d.ts +55 -0
- package/core/dist/runtime-v2/internalization/v2-adversarial-cases.d.ts.map +1 -0
- package/core/dist/runtime-v2/internalization/v2-adversarial-cases.js +131 -0
- package/core/dist/runtime-v2/internalization/v2-adversarial-cases.js.map +1 -0
- package/core/dist/runtime-v2/pain-signal-observability.d.ts.map +1 -1
- package/core/dist/runtime-v2/pain-signal-observability.js +280 -56
- 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/risk/__tests__/risk-calculator-policy.test.d.ts +2 -0
- package/core/dist/runtime-v2/risk/__tests__/risk-calculator-policy.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/risk/__tests__/risk-calculator-policy.test.js +95 -0
- package/core/dist/runtime-v2/risk/__tests__/risk-calculator-policy.test.js.map +1 -0
- package/core/dist/runtime-v2/risk/index.d.ts +7 -0
- package/core/dist/runtime-v2/risk/index.d.ts.map +1 -0
- package/core/dist/runtime-v2/risk/index.js +6 -0
- package/core/dist/runtime-v2/risk/index.js.map +1 -0
- package/core/dist/runtime-v2/risk/risk-calculator-policy.d.ts +18 -0
- package/core/dist/runtime-v2/risk/risk-calculator-policy.d.ts.map +1 -0
- package/core/dist/runtime-v2/risk/risk-calculator-policy.js +47 -0
- package/core/dist/runtime-v2/risk/risk-calculator-policy.js.map +1 -0
- 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/__tests__/sqlite-intent-doc-version-store.test.d.ts +2 -0
- package/core/dist/runtime-v2/store/intent/__tests__/sqlite-intent-doc-version-store.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/store/intent/__tests__/sqlite-intent-doc-version-store.test.js +83 -0
- package/core/dist/runtime-v2/store/intent/__tests__/sqlite-intent-doc-version-store.test.js.map +1 -0
- package/core/dist/runtime-v2/store/intent/index.d.ts +7 -0
- package/core/dist/runtime-v2/store/intent/index.d.ts.map +1 -0
- package/core/dist/runtime-v2/store/intent/index.js +6 -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/intent/sqlite-intent-doc-version-store.d.ts +28 -0
- package/core/dist/runtime-v2/store/intent/sqlite-intent-doc-version-store.d.ts.map +1 -0
- package/core/dist/runtime-v2/store/intent/sqlite-intent-doc-version-store.js +88 -0
- package/core/dist/runtime-v2/store/intent/sqlite-intent-doc-version-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 +138 -12
- package/core/dist/runtime-v2/store/sqlite-connection.js.map +1 -1
- package/core/dist/runtime-v2/thinking-models/__tests__/thinking-models-policy.test.d.ts +2 -0
- package/core/dist/runtime-v2/thinking-models/__tests__/thinking-models-policy.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/thinking-models/__tests__/thinking-models-policy.test.js +149 -0
- package/core/dist/runtime-v2/thinking-models/__tests__/thinking-models-policy.test.js.map +1 -0
- package/core/dist/runtime-v2/thinking-models/index.d.ts +3 -0
- package/core/dist/runtime-v2/thinking-models/index.d.ts.map +1 -0
- package/core/dist/runtime-v2/thinking-models/index.js +3 -0
- package/core/dist/runtime-v2/thinking-models/index.js.map +1 -0
- package/core/dist/runtime-v2/thinking-models/thinking-models-policy.d.ts +73 -0
- package/core/dist/runtime-v2/thinking-models/thinking-models-policy.d.ts.map +1 -0
- package/core/dist/runtime-v2/thinking-models/thinking-models-policy.js +227 -0
- package/core/dist/runtime-v2/thinking-models/thinking-models-policy.js.map +1 -0
- package/core/dist/runtime-v2/tools/__tests__/artificer-l2-tool-contract.test.js +40 -1
- package/core/dist/runtime-v2/tools/__tests__/artificer-l2-tool-contract.test.js.map +1 -1
- package/core/dist/runtime-v2/tools/artificer-l2-tool-contract.d.ts.map +1 -1
- package/core/dist/runtime-v2/tools/artificer-l2-tool-contract.js +28 -1
- package/core/dist/runtime-v2/tools/artificer-l2-tool-contract.js.map +1 -1
- package/core/dist/runtime-v2/tools/artificer-output-typebox.d.ts +3 -0
- package/core/dist/runtime-v2/tools/artificer-output-typebox.d.ts.map +1 -1
- package/core/dist/runtime-v2/tools/artificer-output-typebox.js +3 -0
- package/core/dist/runtime-v2/tools/artificer-output-typebox.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 -34
- package/core/dist/runtime-v2/types/event-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/types/event-types.js +0 -19
- 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 +5 -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/workflow-funnel-loader.d.ts +2 -2
- package/core/dist/workflow-funnel-loader.d.ts.map +1 -1
- package/core/package.json +4 -0
- package/dist/installer.d.ts.map +1 -1
- package/dist/installer.js +16 -0
- package/dist/installer.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 +237 -0
- package/pd-cli/dist/commands/__tests__/intent-flag-wiring.test.js.map +1 -0
- package/pd-cli/dist/commands/intent.d.ts +76 -0
- package/pd-cli/dist/commands/intent.d.ts.map +1 -0
- package/pd-cli/dist/commands/intent.js +411 -0
- package/pd-cli/dist/commands/intent.js.map +1 -0
- 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/index.js +25 -0
- package/pd-cli/dist/index.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/package.json +1 -0
- package/plugin/dist/commands/pain.js +2 -0
- package/plugin/dist/core/behavior-example-pack-assembler.d.ts +43 -0
- package/plugin/dist/core/behavior-example-pack-assembler.js +247 -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/event-log.js +0 -5
- package/plugin/dist/core/intent-doc-reader-adapter.d.ts +36 -0
- package/plugin/dist/core/intent-doc-reader-adapter.js +76 -0
- package/plugin/dist/core/intent-doc-reader.d.ts +89 -0
- package/plugin/dist/core/intent-doc-reader.js +210 -0
- 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/rule-context-assembler.d.ts +45 -0
- package/plugin/dist/core/rule-context-assembler.js +148 -0
- package/plugin/dist/core/thinking-models.d.ts +12 -57
- package/plugin/dist/core/thinking-models.js +18 -224
- package/plugin/dist/core/trajectory-types.d.ts +18 -0
- package/plugin/dist/core/trajectory.d.ts +50 -2
- package/plugin/dist/core/trajectory.js +435 -254
- package/plugin/dist/core/workspace-context.d.ts +2 -3
- package/plugin/dist/hooks/gate.js +59 -2
- package/plugin/dist/hooks/pain.js +5 -0
- package/plugin/dist/hooks/prompt-helpers.d.ts +19 -1
- package/plugin/dist/hooks/prompt-helpers.js +39 -2
- package/plugin/dist/hooks/prompt-types.d.ts +8 -0
- package/plugin/dist/hooks/prompt.js +81 -21
- package/plugin/dist/index.d.ts +3 -1
- package/plugin/dist/index.js +10 -6
- package/plugin/dist/service/runtime-summary-service.js +1 -1
- 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/dist/core/evolution-migration.d.ts +0 -5
- package/plugin/dist/core/evolution-migration.js +0 -65
- 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/core/risk-calculator.d.ts +0 -22
- package/plugin/dist/core/risk-calculator.js +0 -88
- package/plugin/dist/core/rule-host-helpers.d.ts +0 -8
- package/plugin/dist/core/rule-host-helpers.js +0 -7
- package/plugin/dist/core/rule-host-types.d.ts +0 -7
- package/plugin/dist/core/rule-host-types.js +0 -7
- package/plugin/dist/core/schema/db-types.d.ts +0 -11
- package/plugin/dist/core/schema/db-types.js +0 -5
- package/plugin/dist/core/schema/index.d.ts +0 -17
- package/plugin/dist/core/schema/index.js +0 -15
- package/plugin/dist/core/schema/migration-runner.d.ts +0 -53
- package/plugin/dist/core/schema/migration-runner.js +0 -170
- package/plugin/dist/core/schema/migrations/001-init-trajectory.d.ts +0 -6
- package/plugin/dist/core/schema/migrations/001-init-trajectory.js +0 -190
- package/plugin/dist/core/schema/migrations/002-init-central.d.ts +0 -5
- package/plugin/dist/core/schema/migrations/002-init-central.js +0 -108
- package/plugin/dist/core/schema/migrations/003-init-workflow.d.ts +0 -5
- package/plugin/dist/core/schema/migrations/003-init-workflow.js +0 -50
- package/plugin/dist/core/schema/migrations/004-add-thinking-and-gfi.d.ts +0 -8
- package/plugin/dist/core/schema/migrations/004-add-thinking-and-gfi.js +0 -66
- package/plugin/dist/core/schema/migrations/index.d.ts +0 -16
- package/plugin/dist/core/schema/migrations/index.js +0 -27
- package/plugin/dist/core/schema/schema-definitions.d.ts +0 -46
- package/plugin/dist/core/schema/schema-definitions.js +0 -599
- 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/db-migrate.mjs +0 -170
- package/plugin/scripts/validate-live-path.ts +0 -462
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect, useCallback } from "react";
|
|
3
|
+
import { useTranslation } from "react-i18next";
|
|
4
|
+
import { toast } from "sonner";
|
|
5
|
+
import { PageShell } from "../../components/layout/page-shell.js";
|
|
6
|
+
import { PageLoading } from "../../components/layout/page-loading.js";
|
|
7
|
+
import { SectionTitle } from "../../components/layout/section-title.js";
|
|
8
|
+
import { fetchIntentSummary, fetchIntentDecisionSummary, patchFeatureFlag, fetchIntentContent, fetchIntentVersions } from "../../api.js";
|
|
9
|
+
import { IntentEditor, CreateIntentButton, EditButton } from "./IntentOnboarding.js";
|
|
10
|
+
import { computeVersionDiff } from "@principles/core/runtime-v2/intent-browser";
|
|
11
|
+
// ── Sub-components ────────────────────────────────────────────────────────────
|
|
12
|
+
function FlagStatusBadge({ enabled }) {
|
|
13
|
+
const { t } = useTranslation();
|
|
14
|
+
// SPEC §22.1.1: Intent Page must show intent_engineering flag status.
|
|
15
|
+
// Badge has a text label, not color-only (SPEC §23.14.10).
|
|
16
|
+
const label = enabled
|
|
17
|
+
? t("pages.intent.flagStatus.enabled")
|
|
18
|
+
: t("pages.intent.flagStatus.disabled");
|
|
19
|
+
return (_jsxs("span", { className: `inline-flex items-center gap-1.5 px-2 py-0.5 rounded-[3px] text-[11px] font-mono border ${enabled
|
|
20
|
+
? "border-emerald/40 text-emerald bg-emerald/5"
|
|
21
|
+
: "border-line text-ink-3 bg-surface"}`, role: "status", "aria-label": t("pages.intent.flagStatus.ariaLabel"), children: [_jsx("span", { className: `w-1.5 h-1.5 rounded-full ${enabled ? "bg-emerald" : "bg-ink-4"}`, "aria-hidden": "true" }), label] }));
|
|
22
|
+
}
|
|
23
|
+
function EditEntry({ filePath }) {
|
|
24
|
+
const { t } = useTranslation();
|
|
25
|
+
// SPEC §22.1.1 line 1402: Intent Page must show "edit INTENT.md 入口".
|
|
26
|
+
// INTENT.md is Owner-owned; PD never auto-modifies it. This entry only
|
|
27
|
+
// surfaces the file path so the Owner can edit it in their own editor.
|
|
28
|
+
return (_jsxs("div", { className: "bg-panel border border-line rounded-[6px] p-4", children: [_jsx("h3", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3 mb-2", children: t("pages.intent.editEntry.title") }), _jsx("p", { className: "text-ink-3 text-[13px] leading-relaxed mb-2", children: t("pages.intent.editEntry.description") }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("code", { className: "text-[12px] text-ink-2 bg-surface border border-line rounded-[3px] px-2 py-1 break-all", children: filePath }), _jsx("button", { type: "button", onClick: () => {
|
|
29
|
+
// Copy to clipboard — Owner pastes into their editor.
|
|
30
|
+
void navigator.clipboard?.writeText(filePath);
|
|
31
|
+
}, className: "shrink-0 border border-line bg-surface text-ink-2 rounded-[3px] px-2 py-1 text-[11px] hover:border-line-2 transition-colors focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", "aria-label": t("pages.intent.editEntry.copyAriaLabel"), children: t("pages.intent.editEntry.copy") })] })] }));
|
|
32
|
+
}
|
|
33
|
+
function FlagToggleCard({ flagEnabled, onAfterEnable }) {
|
|
34
|
+
const { t } = useTranslation();
|
|
35
|
+
const [busy, setBusy] = useState(false);
|
|
36
|
+
const [acknowledged, setAcknowledged] = useState(false);
|
|
37
|
+
// Only show when disabled and not yet acknowledged.
|
|
38
|
+
// flagEnabled === true → already on, nothing to toggle.
|
|
39
|
+
// acknowledged === true → owner just enabled, parent will re-fetch and
|
|
40
|
+
// flagEnabled will flip to true; this prevents a flash of the card.
|
|
41
|
+
if (flagEnabled || acknowledged)
|
|
42
|
+
return null;
|
|
43
|
+
return (_jsxs("div", { className: "bg-panel border border-amber/20 border-l-2 border-l-amber rounded-[6px] p-4 mb-5", children: [_jsx("h2", { className: "text-ink text-[15px] font-semibold mb-2", children: t("pages.intent.flagDisabled.title") }), _jsx("p", { className: "text-ink-3 text-[13px] leading-relaxed mb-3", children: t("pages.intent.flagDisabled.description") }), _jsx("button", { type: "button", disabled: busy, onClick: async () => {
|
|
44
|
+
setBusy(true);
|
|
45
|
+
try {
|
|
46
|
+
const res = await patchFeatureFlag("intent_engineering", true);
|
|
47
|
+
if (!res.success) {
|
|
48
|
+
toast.error(res.error ?? t("pages.intent.flagStatus.enableFailed"));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
setAcknowledged(true);
|
|
52
|
+
onAfterEnable?.();
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
setBusy(false);
|
|
56
|
+
}
|
|
57
|
+
}, className: "border border-gov bg-gov text-paper rounded-[3px] px-[14px] py-[6px] text-[12.5px] font-medium hover:bg-gov-2 transition-colors disabled:opacity-50 focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", "aria-label": t("pages.intent.flagStatus.enable"), children: busy ? t("pages.intent.flagStatus.enabling") : t("pages.intent.flagStatus.enable") })] }));
|
|
58
|
+
}
|
|
59
|
+
function NotFoundBanner({ onCreated, lang }) {
|
|
60
|
+
const { t } = useTranslation();
|
|
61
|
+
return (_jsxs("div", { className: "bg-panel border border-line rounded-[6px] p-5", children: [_jsx("h2", { className: "text-ink text-[15px] font-semibold mb-2", children: t("pages.intent.notFound.title") }), _jsx("p", { className: "text-ink-3 text-[13px] leading-relaxed mb-3", children: t("pages.intent.notFound.description") }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx(CreateIntentButton, { onCreated: onCreated, showOnboarding: true, lang: lang }), _jsx("span", { className: "text-ink-4 text-[12px] font-mono", children: t("pages.intent.notFound.nextAction") })] })] }));
|
|
62
|
+
}
|
|
63
|
+
function OversizedBanner() {
|
|
64
|
+
const { t } = useTranslation();
|
|
65
|
+
return (_jsxs("div", { className: "bg-panel border border-amber/30 rounded-[6px] p-5", children: [_jsx("h2", { className: "text-ink text-[15px] font-semibold mb-2", children: t("pages.intent.oversized.title") }), _jsx("p", { className: "text-ink-3 text-[13px] leading-relaxed mb-3", children: t("pages.intent.oversized.description") }), _jsx("div", { className: "font-mono text-[12px] text-ink-2 bg-surface border border-line rounded-[3px] px-3 py-2", children: t("pages.intent.oversized.nextAction") })] }));
|
|
66
|
+
}
|
|
67
|
+
function WarningItem({ warning }) {
|
|
68
|
+
const { t } = useTranslation();
|
|
69
|
+
// SPEC: warnings are rendered as governance hints via i18n code key,
|
|
70
|
+
// not raw server-side English message text (P2 i18n fix).
|
|
71
|
+
const labelKey = `pages.intent.warnings.${warning.code}`;
|
|
72
|
+
return (_jsxs("li", { className: "flex items-start gap-2 text-ink-2 text-[13px]", children: [_jsx("span", { className: "text-amber shrink-0 mt-0.5", "aria-hidden": "true", children: "!" }), _jsxs("span", { children: [_jsx("span", { className: "font-medium", children: t(labelKey) }), warning.section && (_jsxs("span", { className: "text-ink-3 font-mono ml-2", children: ["[", warning.section, "]"] }))] })] }));
|
|
73
|
+
}
|
|
74
|
+
function SectionContent({ label, content }) {
|
|
75
|
+
if (content === undefined || content.trim() === "")
|
|
76
|
+
return null;
|
|
77
|
+
return (_jsxs("div", { children: [_jsx("h3", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3 mb-1.5", children: label }), _jsx("p", { className: "text-ink-2 text-[13px] leading-relaxed whitespace-pre-wrap", children: content })] }));
|
|
78
|
+
}
|
|
79
|
+
function MetaRow({ label, value }) {
|
|
80
|
+
return (_jsxs("div", { className: "flex items-baseline gap-3", children: [_jsx("span", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3 w-32 shrink-0", children: label }), _jsx("span", { className: "text-ink-2 text-[12px] font-mono break-all", children: value })] }));
|
|
81
|
+
}
|
|
82
|
+
function VersionEntry({ version, previousContent, reasonLabel, defaultExpanded = false }) {
|
|
83
|
+
const { t } = useTranslation();
|
|
84
|
+
const [expanded, setExpanded] = useState(defaultExpanded);
|
|
85
|
+
// Compute section-level diff between previous and this version.
|
|
86
|
+
// For the oldest version (no previous), diff against "" so all non-empty
|
|
87
|
+
// sections show as "changed" — gives the user a visual of what was filled.
|
|
88
|
+
const diff = computeVersionDiff(previousContent, version.contentSnapshot);
|
|
89
|
+
// Localize the timestamp for display (avoid showing raw UTC to end users).
|
|
90
|
+
const localizedTime = (() => {
|
|
91
|
+
try {
|
|
92
|
+
return new Date(version.createdAt).toLocaleString(undefined, {
|
|
93
|
+
year: 'numeric', month: '2-digit', day: '2-digit',
|
|
94
|
+
hour: '2-digit', minute: '2-digit',
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return version.createdAt.slice(0, 19).replace('T', ' ');
|
|
99
|
+
}
|
|
100
|
+
})();
|
|
101
|
+
return (_jsxs("div", { className: "border-b border-line last:border-b-0", children: [_jsxs("button", { type: "button", onClick: () => setExpanded((prev) => !prev), className: "w-full flex items-center gap-3 py-1.5 text-[12px] font-mono text-ink-2 hover:bg-surface-2/50 transition-colors text-left", "aria-expanded": expanded, "aria-label": expanded ? t("pages.intent.versionDiff.collapseHint") : t("pages.intent.versionDiff.expandHint"), title: version.contentHash, children: [_jsx("span", { className: "text-ink-3 shrink-0 w-4 inline-block", children: expanded ? "▾" : "▸" }), _jsx("span", { className: "text-ink-3 shrink-0", children: localizedTime }), _jsx("span", { className: "px-1.5 py-0.5 rounded-[2px] bg-surface-2 text-ink-3 shrink-0", children: reasonLabel }), _jsx("span", { className: "text-ink-4 text-[11px] ml-auto shrink-0 hidden sm:inline", children: expanded ? t("pages.intent.versionDiff.collapseHint") : t("pages.intent.versionDiff.expandHint") })] }), expanded && (_jsx("div", { className: "pb-2.5 pl-7 pr-2", children: _jsx("div", { className: "flex flex-wrap gap-1.5 mb-2", children: diff.map((d) => {
|
|
102
|
+
// d.section is one of the 5 section keys from computeVersionDiff's
|
|
103
|
+
// SECTION_KEYS — safe to construct the i18n key dynamically.
|
|
104
|
+
const labelKey = `pages.intent.wizard.stepLabels.${d.section}`;
|
|
105
|
+
return (_jsxs("span", { className: `inline-flex items-center gap-1 px-1.5 py-0.5 rounded-[2px] text-[11px] font-mono border ${d.changed
|
|
106
|
+
? "border-amber/40 text-amber bg-amber/5"
|
|
107
|
+
: "border-line text-ink-3 bg-surface"}`, children: [_jsx("span", { className: `w-1.5 h-1.5 rounded-full ${d.changed ? "bg-amber" : "bg-ink-4"}`, "aria-hidden": "true" }), t(labelKey), _jsx("span", { className: "text-ink-4 ml-0.5", children: d.changed ? t("pages.intent.versionDiff.changed") : t("pages.intent.versionDiff.unchanged") })] }, d.section));
|
|
108
|
+
}) }) }))] }));
|
|
109
|
+
}
|
|
110
|
+
// Static mapping from ownerAction enum value to its i18n label key.
|
|
111
|
+
// Avoids dynamic string construction so i18n extraction tools can find keys.
|
|
112
|
+
const DECISION_COUNT_LABEL_KEYS = [
|
|
113
|
+
{ action: "confirm_drift", labelKey: "pages.intent.decisions.countConfirmDrift" },
|
|
114
|
+
{ action: "revise_intent", labelKey: "pages.intent.decisions.countReviseIntent" },
|
|
115
|
+
{ action: "observe", labelKey: "pages.intent.decisions.countObserve" },
|
|
116
|
+
{ action: "dismiss", labelKey: "pages.intent.decisions.countDismiss" },
|
|
117
|
+
{ action: "promote_to_principle", labelKey: "pages.intent.decisions.countPromoteToPrinciple" },
|
|
118
|
+
{ action: "promote_to_rulehost", labelKey: "pages.intent.decisions.countPromoteToRulehost" },
|
|
119
|
+
];
|
|
120
|
+
function DecisionSummarySection() {
|
|
121
|
+
const { t } = useTranslation();
|
|
122
|
+
const [state, setState] = useState("loading");
|
|
123
|
+
const [summary, setSummary] = useState(null);
|
|
124
|
+
const loadSummary = useCallback(async () => {
|
|
125
|
+
setState("loading");
|
|
126
|
+
const result = await fetchIntentDecisionSummary();
|
|
127
|
+
if (!result.success) {
|
|
128
|
+
// ERR-002: graceful degradation with reason; section collapses to a single line.
|
|
129
|
+
setState("error");
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
setSummary(result.data);
|
|
133
|
+
setState("loaded");
|
|
134
|
+
}, []);
|
|
135
|
+
useEffect(() => {
|
|
136
|
+
loadSummary();
|
|
137
|
+
}, [loadSummary]);
|
|
138
|
+
return (_jsxs("section", { className: "mt-8", "aria-labelledby": "section-decisions", children: [_jsx(SectionTitle, { id: "section-decisions", children: t("pages.intent.decisions.sectionTitle") }), _jsx("p", { className: "text-ink-3 text-[13px] leading-relaxed mb-3", children: t("pages.intent.decisions.sectionSubtitle") }), state === "loading" && (_jsx("div", { className: "bg-panel border border-line rounded-[6px] p-4 text-ink-3 text-[13px]", children: t("common.loading") })), state === "error" && (_jsx("div", { className: "bg-panel border border-line rounded-[6px] p-4 text-ink-3 text-[13px]", children: t("pages.intent.decisions.loadError") })), state === "loaded" && summary && (_jsxs("div", { className: "bg-panel border border-line rounded-[6px] p-4", children: [_jsx("dl", { className: "grid grid-cols-2 gap-x-6 gap-y-2 sm:grid-cols-3", children: DECISION_COUNT_LABEL_KEYS.map(({ action, labelKey }) => {
|
|
139
|
+
const count = summary.counts[action];
|
|
140
|
+
return (_jsxs("div", { className: "flex items-baseline gap-2", children: [_jsx("dt", { className: "text-ink-3 text-[12px]", children: t(labelKey) }), _jsx("dd", { className: "text-ink font-mono text-[13px]", children: count })] }, action));
|
|
141
|
+
}) }), _jsx("div", { className: "mt-4 pt-3 border-t border-line", children: summary.lastDecisionAt === null ? (_jsx("p", { className: "text-ink-4 text-[12px]", children: t("pages.intent.decisions.noDecisions") })) : (_jsxs("div", { className: "flex items-baseline gap-2", children: [_jsx("span", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-3", children: t("pages.intent.decisions.lastDecisionAtLabel") }), _jsx("span", { className: "text-ink-2 text-[12px] font-mono break-all", children: summary.lastDecisionAt })] })) })] }))] }));
|
|
142
|
+
}
|
|
143
|
+
// ── Main page component ──────────────────────────────────────────────────────
|
|
144
|
+
export function IntentPage() {
|
|
145
|
+
const { t } = useTranslation();
|
|
146
|
+
const [data, setData] = useState(null);
|
|
147
|
+
const [pageState, setPageState] = useState("loading");
|
|
148
|
+
const [errorMsg, setErrorMsg] = useState(null);
|
|
149
|
+
// PRI-477: inline editor state
|
|
150
|
+
const [isEditing, setIsEditing] = useState(false);
|
|
151
|
+
const [editorContent, setEditorContent] = useState("");
|
|
152
|
+
const [editorLoading, setEditorLoading] = useState(false);
|
|
153
|
+
// Bilingual: language selector state
|
|
154
|
+
const [lang, setLang] = useState('zh-CN');
|
|
155
|
+
// Version history
|
|
156
|
+
const [versions, setVersions] = useState([]);
|
|
157
|
+
// Map raw backend reason codes to localized labels for the version history panel.
|
|
158
|
+
// Unknown reasons fall back to the raw string (observability over silent masking).
|
|
159
|
+
const versionReasonLabel = useCallback((reason) => {
|
|
160
|
+
if (reason === 'init')
|
|
161
|
+
return t("pages.intent.versionHistory.reasonInit");
|
|
162
|
+
if (reason === 'save')
|
|
163
|
+
return t("pages.intent.versionHistory.reasonSave");
|
|
164
|
+
return reason;
|
|
165
|
+
}, [t]);
|
|
166
|
+
const loadData = useCallback(async () => {
|
|
167
|
+
setPageState("loading");
|
|
168
|
+
setErrorMsg(null);
|
|
169
|
+
const result = await fetchIntentSummary(lang);
|
|
170
|
+
if (!result.success) {
|
|
171
|
+
// ERR-002: graceful degradation with reason
|
|
172
|
+
setErrorMsg(result.error ?? t("pages.intent.loadError"));
|
|
173
|
+
setPageState("error");
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
// result.data is already validated by validateIntentSummary in the API layer
|
|
177
|
+
setData(result.data);
|
|
178
|
+
setPageState("loaded");
|
|
179
|
+
// Load version history in parallel (best-effort, never blocks page)
|
|
180
|
+
fetchIntentVersions(lang).then(v => {
|
|
181
|
+
if (v.success && v.data?.versions) {
|
|
182
|
+
setVersions(v.data.versions);
|
|
183
|
+
}
|
|
184
|
+
}).catch(() => { });
|
|
185
|
+
}, [t, lang]);
|
|
186
|
+
useEffect(() => {
|
|
187
|
+
loadData();
|
|
188
|
+
}, [loadData]);
|
|
189
|
+
// P0 fix: when language changes, reset editor state and stale versions.
|
|
190
|
+
// Without this, switching language while editing would keep the editor open
|
|
191
|
+
// with the old language's content — and saving would write that content
|
|
192
|
+
// into the NEW language's file (data corruption).
|
|
193
|
+
// Also clears stale versions so the panel doesn't show the old language's
|
|
194
|
+
// history while the new language's fetch is in flight or has failed.
|
|
195
|
+
useEffect(() => {
|
|
196
|
+
setIsEditing(false);
|
|
197
|
+
setEditorContent("");
|
|
198
|
+
setVersions([]);
|
|
199
|
+
}, [lang]);
|
|
200
|
+
// PRI-477: Called when user clicks "Edit" — fetch raw content and open editor
|
|
201
|
+
const handleStartEdit = useCallback(async () => {
|
|
202
|
+
setEditorLoading(true);
|
|
203
|
+
const result = await fetchIntentContent(lang);
|
|
204
|
+
setEditorLoading(false);
|
|
205
|
+
if (!result.success) {
|
|
206
|
+
toast.error(t("pages.intent.loadError"));
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
setEditorContent(result.data.content);
|
|
210
|
+
setIsEditing(true);
|
|
211
|
+
}, [t, lang]);
|
|
212
|
+
// PRI-477: Called when template is created — refresh summary; optionally
|
|
213
|
+
// open the editor immediately so the user can start filling.
|
|
214
|
+
//
|
|
215
|
+
// PR-1083 review (CodeRabbit A5): `openEditor` lets CreateIntentButton
|
|
216
|
+
// distinguish "Start filling" (open editor) from "Skip" (just refresh the
|
|
217
|
+
// summary so NotFoundBanner re-renders to the sections view — otherwise the
|
|
218
|
+
// user would see a stale "file not found" banner even though INTENT.md now
|
|
219
|
+
// exists on disk).
|
|
220
|
+
const handleCreated = useCallback(async (openEditor) => {
|
|
221
|
+
await loadData();
|
|
222
|
+
if (!openEditor)
|
|
223
|
+
return;
|
|
224
|
+
setEditorLoading(true);
|
|
225
|
+
const result = await fetchIntentContent(lang);
|
|
226
|
+
setEditorLoading(false);
|
|
227
|
+
if (result.success) {
|
|
228
|
+
setEditorContent(result.data.content);
|
|
229
|
+
setIsEditing(true);
|
|
230
|
+
}
|
|
231
|
+
}, [loadData, lang]);
|
|
232
|
+
// PRI-477: Called after successful save — close editor and refresh summary
|
|
233
|
+
const handleSaved = useCallback(() => {
|
|
234
|
+
setIsEditing(false);
|
|
235
|
+
void loadData();
|
|
236
|
+
}, [loadData]);
|
|
237
|
+
// PRI-477: Called when user cancels editing
|
|
238
|
+
const handleCancelEdit = useCallback(() => {
|
|
239
|
+
setIsEditing(false);
|
|
240
|
+
}, []);
|
|
241
|
+
// ── Loading state ────────────────────────────────────────────────────────
|
|
242
|
+
if (pageState === "loading") {
|
|
243
|
+
return (_jsx(PageShell, { children: _jsx(PageLoading, { cardCount: 3, label: t("common.loading") }) }));
|
|
244
|
+
}
|
|
245
|
+
// ── Error state (ERR-002: degradation with reason) ───────────────────────
|
|
246
|
+
if (pageState === "error") {
|
|
247
|
+
return (_jsxs(PageShell, { children: [_jsx("div", { className: "font-mono text-[12px] tracking-[0.14em] text-ink-3 uppercase mb-3", children: t("pages.intent.eyebrow") }), _jsx("h1", { className: "text-[29px] font-semibold tracking-tight text-ink mb-2", children: t("pages.intent.title") }), _jsxs("div", { className: "mt-6 p-4 bg-panel border border-line rounded-[6px] text-ink-2 text-sm", children: [_jsx("p", { children: t("pages.intent.loadError") }), errorMsg && (_jsx("p", { className: "mt-2 text-ink-4 text-[13px] font-mono", children: errorMsg }))] }), _jsx("div", { className: "mt-4", children: _jsx("button", { type: "button", onClick: loadData, className: "border border-line bg-surface text-ink rounded-[3px] px-[14px] py-[6px] text-[12.5px] hover:border-line-2 transition-colors focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2", children: t("common.refresh") }) })] }));
|
|
248
|
+
}
|
|
249
|
+
// ── Loaded state ─────────────────────────────────────────────────────────
|
|
250
|
+
const summary = data;
|
|
251
|
+
return (_jsx(PageShell, { children: _jsxs("div", { className: "animate-[pdFadeIn_400ms_ease-out]", children: [_jsx("div", { className: "font-mono text-[12px] tracking-[0.14em] text-ink-3 uppercase mb-3", children: t("pages.intent.eyebrow") }), _jsxs("div", { className: "flex items-center gap-3 mb-2", children: [_jsx("h1", { className: "text-[29px] font-semibold tracking-tight text-ink", children: t("pages.intent.title") }), summary && (_jsx(FlagStatusBadge, { enabled: summary.flagEnabled })), _jsxs("select", { value: lang, onChange: (e) => setLang(e.target.value), disabled: isEditing || editorLoading, className: "ml-auto border border-line bg-surface text-ink-2 rounded-[3px] px-2 py-1 text-[12px] font-mono focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2 disabled:opacity-50 disabled:cursor-not-allowed", "aria-label": t("pages.intent.langSelector.ariaLabel"), title: isEditing || editorLoading ? t("pages.intent.langSelector.disabledWhileEditing") : undefined, children: [_jsx("option", { value: "zh-CN", children: "\u4E2D\u6587" }), _jsx("option", { value: "en", children: "English" })] })] }), _jsx("p", { className: "text-ink-3 text-[14px] max-w-[760px] leading-relaxed mb-7", children: t("pages.intent.subtitle") }), summary && !summary.flagEnabled && (_jsx(FlagToggleCard, { flagEnabled: summary.flagEnabled, onAfterEnable: loadData })), summary && summary.flagEnabled && !summary.found && summary.reason === "not_found" && (_jsx(NotFoundBanner, { onCreated: handleCreated, lang: lang })), summary && summary.flagEnabled && summary.found && summary.reason === "oversized" && (_jsx(OversizedBanner, {})), summary && summary.flagEnabled && summary.ok && summary.sections && (_jsxs(_Fragment, { children: [isEditing && (_jsx("section", { "aria-labelledby": "section-editor", className: "mb-8", children: _jsx(IntentEditor, { initialContent: editorContent, onSaved: handleSaved, onCancel: handleCancelEdit, lang: lang }) })), !isEditing && (_jsxs(_Fragment, { children: [_jsxs("section", { "aria-labelledby": "section-content", children: [_jsxs("div", { className: "flex items-center justify-between mb-3", children: [_jsx(SectionTitle, { id: "section-content", children: t("pages.intent.title") }), _jsx(EditButton, { onClick: handleStartEdit, loading: editorLoading })] }), _jsxs("div", { className: "bg-panel border border-line rounded-[6px] p-5 space-y-5", children: [_jsx(SectionContent, { label: t("pages.intent.sections.why"), content: summary.sections.why }), _jsx(SectionContent, { label: t("pages.intent.sections.desiredOutcome"), content: summary.sections.desiredOutcome }), _jsx(SectionContent, { label: t("pages.intent.sections.nonNegotiables"), content: summary.sections.nonNegotiables }), _jsx(SectionContent, { label: t("pages.intent.sections.stopEscalation"), content: summary.sections.stopEscalation }), _jsx(SectionContent, { label: t("pages.intent.sections.currentStrategicFocus"), content: summary.sections.currentStrategicFocus })] })] }), _jsxs("section", { className: "mt-8", "aria-labelledby": "section-warnings", children: [_jsx(SectionTitle, { id: "section-warnings", children: t("pages.intent.warnings.title") }), summary.warnings.length === 0 ? (_jsx("p", { className: "text-ink-3 text-[13px] leading-relaxed", children: t("pages.intent.warnings.empty") })) : (_jsx("ul", { className: "bg-panel border border-line rounded-[6px] p-4 space-y-2", children: summary.warnings.map((w, i) => (_jsx(WarningItem, { warning: w }, i))) }))] }), _jsxs("section", { className: "mt-8", "aria-labelledby": "section-meta", children: [_jsx(SectionTitle, { id: "section-meta", children: t("pages.intent.meta.title") }), _jsxs("div", { className: "bg-panel border border-line rounded-[6px] p-4 space-y-2", children: [summary.lastEditedAt && (_jsx(MetaRow, { label: t("pages.intent.meta.lastEditedAt"), value: summary.lastEditedAt })), summary.contentHash && (_jsx(MetaRow, { label: t("pages.intent.meta.contentHash"), value: summary.contentHash })), summary.path && (_jsx(MetaRow, { label: t("pages.intent.meta.path"), value: summary.path }))] })] }), summary.path && (_jsxs("section", { className: "mt-8", "aria-labelledby": "section-edit", children: [_jsx(SectionTitle, { id: "section-edit", children: t("pages.intent.editEntry.heading") }), _jsx(EditEntry, { filePath: summary.path })] }))] }))] })), summary && summary.flagEnabled && !summary.ok && summary.reason && summary.reason !== "not_found" && summary.reason !== "oversized" && (_jsxs("div", { className: "bg-panel border border-red-200 rounded-[6px] p-5", children: [_jsx("h2", { className: "text-ink text-[15px] font-semibold mb-2", children: t("pages.intent.loadError") }), _jsx("p", { className: "text-ink-3 text-[13px] leading-relaxed mb-3 font-mono", children: summary.reason }), summary.nextAction && (_jsx("p", { className: "text-ink-2 text-[13px] leading-relaxed", children: summary.nextAction }))] })), summary && summary.flagEnabled && (_jsx(DecisionSummarySection, {})), versions.length > 0 && (_jsxs("details", { className: "border border-line rounded-[3px] mt-6", children: [_jsxs("summary", { className: "cursor-pointer px-4 py-2 text-[13px] font-medium text-ink-2 select-none", children: [t("pages.intent.versionHistory.title"), " (", versions.length, ")"] }), _jsx("div", { className: "px-4 py-2 border-t border-line", children: versions.map((v, idx) => {
|
|
252
|
+
// versions are sorted newest-first; previous = idx + 1.
|
|
253
|
+
// For the oldest version (no previous), diff against "" so
|
|
254
|
+
// all filled sections show as "changed".
|
|
255
|
+
const previousContent = versions[idx + 1]?.contentSnapshot ?? "";
|
|
256
|
+
return (_jsx(VersionEntry, { version: v, previousContent: previousContent, reasonLabel: versionReasonLabel(v.reason), defaultExpanded: idx === 0 }, v.id));
|
|
257
|
+
}) })] }))] }) }));
|
|
258
|
+
}
|
|
@@ -17,9 +17,10 @@ import { PageLoading } from '../../components/layout/page-loading.js';
|
|
|
17
17
|
import { Badge } from '../../components/ui/badge.js';
|
|
18
18
|
import { Card, CardContent, CardHeader, CardTitle } from '../../components/ui/card.js';
|
|
19
19
|
import { Button } from '../../components/ui/button.js';
|
|
20
|
-
import {
|
|
20
|
+
import { ShinyText } from '../../components/ui/shiny-text.js';
|
|
21
|
+
import { fetchEvidenceChain, recordIntentDecision, listIntentDecisionsByPainId, listIntentDecisionsByTaskId, dispatchFollowUp } from '../../api.js';
|
|
21
22
|
import { formatDate } from '../../utils/format.js';
|
|
22
|
-
import { buildCardLayers, buildDebugIdSummary, isLayer2EffectivelyEmpty } from './pain-card-helpers.js';
|
|
23
|
+
import { buildCardLayers, buildDebugIdSummary, isLayer2EffectivelyEmpty, shouldRenderIntentTensionPanel, shouldRenderFollowUpActions, buildIntentDecisionPayload } from './pain-card-helpers.js';
|
|
23
24
|
import { enumLabel } from '../../utils/enum-labels.js';
|
|
24
25
|
function groupForState(state) {
|
|
25
26
|
switch (state) {
|
|
@@ -84,7 +85,7 @@ export function PainPage() {
|
|
|
84
85
|
return next;
|
|
85
86
|
});
|
|
86
87
|
};
|
|
87
|
-
return (_jsxs(PageShell, { children: [_jsxs("div", { className: "mb-8", children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.14em] text-ink-3", children: t('pages.pain.eyebrow') }), _jsx("h1",
|
|
88
|
+
return (_jsxs(PageShell, { children: [_jsxs("div", { className: "mb-8", children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.14em] text-ink-3", children: t('pages.pain.eyebrow') }), _jsx(ShinyText, { as: "h1", className: "text-[29px] font-semibold tracking-tight text-ink mt-3 mb-2", duration: 4.5, brightness: 0.5, disabled: state.status !== 'loaded' || state.data.records.length === 0, children: t('pages.pain.title') }), _jsx("p", { className: "text-ink-3 text-sm leading-relaxed max-w-[712px]", children: t('pages.pain.description') })] }), _jsx("div", { className: "mb-6 p-3 bg-panel border border-line rounded-[var(--radius-md)] text-ink-3 text-[13px] leading-relaxed", children: t('pages.pain.honestyNote') }), state.status === 'loading' && (_jsx(PageLoading, { cardCount: 4, label: t('common.loading') })), state.status === 'error' && (_jsxs("div", { className: "py-8", children: [_jsxs("div", { className: "text-danger text-sm mb-2", children: [t('pages.pain.loadError'), ": ", state.message] }), _jsx(Button, { variant: "outline", size: "sm", onClick: loadData, children: t('common.refresh') })] })), state.status === 'loaded' && (_jsx("div", { className: "animate-[pdFadeIn_400ms_ease-out]", children: _jsx(LoadedContent, { data: state.data, expandedIds: expandedIds, onToggle: toggleExpanded, onRefresh: loadData, t: t }) }))] }));
|
|
88
89
|
}
|
|
89
90
|
function LoadedContent({ data, expandedIds, onToggle, onRefresh, t }) {
|
|
90
91
|
const [reviewQueueExpanded, setReviewQueueExpanded] = useState(false);
|
|
@@ -132,7 +133,7 @@ function EvidenceChainCard({ record, expanded, onToggle, t }) {
|
|
|
132
133
|
const confidenceDisplay = layers.layer2.confidence
|
|
133
134
|
? `${enumLabel('confidence', layers.layer2.confidence.label, t)} (${layers.layer2.confidence.raw.toFixed(2)})`
|
|
134
135
|
: null;
|
|
135
|
-
return (_jsxs(Card, { className: "overflow-hidden", children: [_jsx(CardHeader, { children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx(Badge, { variant: stateVariant, children: stateLabel }), _jsx(Badge, { variant: "outline", children: sourceLabel }), record.admissionDecision && (_jsx(Badge, { variant: "secondary", children: enumLabel('admission', record.admissionDecision, t) }))] }), _jsx("span", { className: "font-mono text-[11px] text-ink-4 whitespace-nowrap", children: formatDate(record.observedAt) })] }) }), _jsxs(CardContent, { children: [_jsxs("div", { className: "space-y-3 mb-4", children: [_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldTrigger') }), layer2Empty ? (_jsx("p", { className: "text-ink-3 text-sm italic leading-relaxed", children: t('pages.pain.noHumanSummary') })) : (_jsx(CardTitle, { className: "text-[15px] leading-relaxed", children: layers.layer2.triggerSummary }))] }), layers.layer2.conclusion && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldConclusion') }), _jsx("p", { className: "text-ink text-sm leading-relaxed font-medium", children: layers.layer2.conclusion })] })), layers.layer2.applicability && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldApplicability') }), _jsx("p", { className: "text-ink-2 text-sm leading-relaxed", children: layers.layer2.applicability })] })), confidenceDisplay && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldConfidence') }), _jsx("p", { className: "text-ink-2 text-sm", children: confidenceDisplay })] })), layers.layer2.failureReason && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldFailureReason') }), _jsx("p", { className: "text-danger text-sm leading-relaxed", children: layers.layer2.failureReason })] })), layers.layer2.degradedReason && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldDegradedReason') }), _jsx("p", { className: "text-amber text-sm leading-relaxed", children: layers.layer2.degradedReason })] })), layers.layer2.nextAction && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldNextAction') }), _jsx("p", { className: "text-ink-2 text-sm leading-relaxed", children: layers.layer2.nextAction })] }))] }), _jsxs("div", { className: "mt-4 pt-3 border-t border-line", children: [_jsxs("div", { className: "flex items-center gap-3 flex-wrap", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: async () => {
|
|
136
|
+
return (_jsxs(Card, { className: "overflow-hidden", children: [_jsx(CardHeader, { children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [_jsx(Badge, { variant: stateVariant, children: stateLabel }), _jsx(Badge, { variant: "outline", children: sourceLabel }), record.admissionDecision && (_jsx(Badge, { variant: "secondary", children: enumLabel('admission', record.admissionDecision, t) }))] }), _jsx("span", { className: "font-mono text-[11px] text-ink-4 whitespace-nowrap", children: formatDate(record.observedAt) })] }) }), _jsxs(CardContent, { children: [_jsxs("div", { className: "space-y-3 mb-4", children: [_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldTrigger') }), layer2Empty ? (_jsx("p", { className: "text-ink-3 text-sm italic leading-relaxed", children: t('pages.pain.noHumanSummary') })) : (_jsx(CardTitle, { className: "text-[15px] leading-relaxed", children: layers.layer2.triggerSummary }))] }), layers.layer2.conclusion && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldConclusion') }), _jsx("p", { className: "text-ink text-sm leading-relaxed font-medium", children: layers.layer2.conclusion })] })), layers.layer2.applicability && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldApplicability') }), _jsx("p", { className: "text-ink-2 text-sm leading-relaxed", children: layers.layer2.applicability })] })), confidenceDisplay && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldConfidence') }), _jsx("p", { className: "text-ink-2 text-sm", children: confidenceDisplay })] })), layers.layer2.failureReason && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldFailureReason') }), _jsx("p", { className: "text-danger text-sm leading-relaxed", children: layers.layer2.failureReason })] })), layers.layer2.degradedReason && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldDegradedReason') }), _jsx("p", { className: "text-amber text-sm leading-relaxed", children: layers.layer2.degradedReason })] })), layers.layer2.nextAction && (_jsxs("div", { children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.fieldNextAction') }), _jsx("p", { className: "text-ink-2 text-sm leading-relaxed", children: layers.layer2.nextAction })] }))] }), shouldRenderIntentTensionPanel(layers.layer2.intentTension) && (_jsx(IntentTensionPanel, { tension: layers.layer2.intentTension, recordId: record.id, painId: record.id, taskId: record.linkedTaskId ?? undefined, linkedCandidateId: record.linkedCandidateId ?? undefined, t: t })), _jsxs("div", { className: "mt-4 pt-3 border-t border-line", children: [_jsxs("div", { className: "flex items-center gap-3 flex-wrap", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: async () => {
|
|
136
137
|
try {
|
|
137
138
|
await navigator.clipboard.writeText(buildDebugIdSummary(record));
|
|
138
139
|
setCopied(true);
|
|
@@ -173,3 +174,232 @@ function stateToVariant(state) {
|
|
|
173
174
|
return 'secondary';
|
|
174
175
|
}
|
|
175
176
|
}
|
|
177
|
+
// ── PRI-469: Intent Tension panel (SPEC §22.1) ───────────────────────────────
|
|
178
|
+
/**
|
|
179
|
+
* Convert a snake_case enum value to a PascalCase suffix for i18n keys.
|
|
180
|
+
* E.g. 'action_drift' → 'ActionDrift', 'none' → 'None'.
|
|
181
|
+
*/
|
|
182
|
+
function snakeToPascal(value) {
|
|
183
|
+
return value
|
|
184
|
+
.split('_')
|
|
185
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
186
|
+
.join('');
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Resolve an intentTension enum value to its localized label.
|
|
190
|
+
* kind determines the i18n key prefix:
|
|
191
|
+
* - 'source' → pages.pain.intentTensionSource{Pascal}
|
|
192
|
+
* - 'evidenceStrength' → pages.pain.intentTensionEvidenceStrength{Pascal}
|
|
193
|
+
* - 'suggestedAction' → pages.pain.intentTensionSuggestedAction{Pascal}
|
|
194
|
+
*/
|
|
195
|
+
function intentTensionEnumLabel(value, kind, t) {
|
|
196
|
+
const keyPrefix = kind === 'source'
|
|
197
|
+
? 'intentTensionSource'
|
|
198
|
+
: kind === 'evidenceStrength'
|
|
199
|
+
? 'intentTensionEvidenceStrength'
|
|
200
|
+
: 'intentTensionSuggestedAction';
|
|
201
|
+
return t(`pages.pain.${keyPrefix}${snakeToPascal(value)}`);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* IntentTensionPanel — renders the intent tension decision panel (SPEC §22.1.2).
|
|
205
|
+
*
|
|
206
|
+
* This panel is rendered only when shouldRenderIntentTensionPanel returns true
|
|
207
|
+
* (i.e., tension is non-null AND source !== 'none' per SPEC §22.1.3).
|
|
208
|
+
*
|
|
209
|
+
* Follow-up actions (SPEC §22.1.4) appear only after a decision is persisted
|
|
210
|
+
* (PRI-471). The FollowUpActions component is rendered inside OwnerDecisionPanel
|
|
211
|
+
* when shouldRenderFollowUpActions returns true.
|
|
212
|
+
*
|
|
213
|
+
* Accessibility (EP-09):
|
|
214
|
+
* - Uses semantic <section> with aria-label
|
|
215
|
+
* - Uses <dl>/<dt>/<dd> for label-value pairs
|
|
216
|
+
* - Color is not the only indicator (text labels always present)
|
|
217
|
+
*/
|
|
218
|
+
function IntentTensionPanel({ tension, recordId, painId, taskId, linkedCandidateId, t }) {
|
|
219
|
+
const sourceLabel = intentTensionEnumLabel(tension.source, 'source', t);
|
|
220
|
+
const strengthLabel = intentTensionEnumLabel(tension.evidenceStrength, 'evidenceStrength', t);
|
|
221
|
+
const actionLabel = intentTensionEnumLabel(tension.suggestedOwnerAction, 'suggestedAction', t);
|
|
222
|
+
return (_jsxs("section", { className: "mt-4 p-4 border border-line rounded-[var(--radius-sm)] bg-paper-2", "aria-label": t('pages.pain.intentTensionTitle'), children: [_jsxs("h4", { className: "text-[13px] font-semibold text-ink mb-3 flex items-center gap-2", children: [_jsx("span", { "aria-hidden": "true", className: "inline-block w-1.5 h-1.5 rounded-full bg-amber" }), t('pages.pain.intentTensionTitle')] }), _jsxs("dl", { className: "grid grid-cols-[auto_1fr] gap-x-4 gap-y-2 text-[13px]", children: [_jsx("dt", { className: "font-mono text-ink-4", children: t('pages.pain.intentTensionSourceLabel') }), _jsx("dd", { className: "text-ink-2", children: sourceLabel }), _jsx("dt", { className: "font-mono text-ink-4", children: t('pages.pain.intentTensionEvidenceStrengthLabel') }), _jsx("dd", { className: "text-ink-2", children: strengthLabel }), _jsx("dt", { className: "font-mono text-ink-4", children: t('pages.pain.intentTensionSuggestedActionLabel') }), _jsx("dd", { className: "text-ink-2 font-medium", children: actionLabel })] }), tension.relatedIntentFields.length > 0 && (_jsxs("div", { className: "mt-3", children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.intentTensionRelatedIntentFieldsLabel') }), _jsx("div", { className: "flex flex-wrap gap-1.5", children: tension.relatedIntentFields.map((field, idx) => (_jsx(Badge, { variant: "outline", children: field }, `${field}-${idx}`))) })] })), tension.evidence.length > 0 && (_jsxs("div", { className: "mt-3", children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.intentTensionEvidenceLabel') }), _jsx("ul", { className: "text-ink-2 text-sm leading-relaxed space-y-1", children: tension.evidence.map((item, idx) => (_jsx("li", { className: "pl-3 relative before:content-[''] before:absolute before:left-0 before:top-2 before:w-1 before:h-1 before:rounded-full before:bg-ink-4", children: item }, `${idx}-${item.slice(0, 12)}`))) })] })), _jsxs("div", { className: "mt-3", children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.intentTensionExplanationLabel') }), _jsx("p", { className: "text-ink-2 text-sm leading-relaxed", children: tension.explanation })] }), tension.intentDocHash && (_jsxs("div", { className: "mt-3", children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.intentTensionIntentDocHashLabel') }), _jsx("p", { className: "font-mono text-[11px] text-ink-3 break-all", children: tension.intentDocHash })] })), _jsx(OwnerDecisionPanel, { tension: tension, recordId: recordId, painId: painId, taskId: taskId, linkedCandidateId: linkedCandidateId, t: t })] }));
|
|
223
|
+
}
|
|
224
|
+
const OWNER_ACTION_BUTTONS = [
|
|
225
|
+
{ action: 'confirm_drift', labelKey: 'pages.pain.ownerDecisionSubmitConfirmDrift' },
|
|
226
|
+
{ action: 'revise_intent', labelKey: 'pages.pain.ownerDecisionSubmitReviseIntent' },
|
|
227
|
+
{ action: 'observe', labelKey: 'pages.pain.ownerDecisionSubmitObserve' },
|
|
228
|
+
{ action: 'dismiss', labelKey: 'pages.pain.ownerDecisionSubmitDismiss' },
|
|
229
|
+
{ action: 'promote_to_principle', labelKey: 'pages.pain.ownerDecisionSubmitPromoteToPrinciple' },
|
|
230
|
+
{ action: 'promote_to_rulehost', labelKey: 'pages.pain.ownerDecisionSubmitPromoteToRulehost' },
|
|
231
|
+
];
|
|
232
|
+
/**
|
|
233
|
+
* SPEC §22.1.3 + §24.5: each `source` value has exactly ONE primary action.
|
|
234
|
+
* - action_drift → Confirm Drift (primary)
|
|
235
|
+
* - intent_suspect → Revise Intent (primary)
|
|
236
|
+
* - healthy_tension → Observe (primary)
|
|
237
|
+
* - none → (no decision panel rendered — handled by shouldRenderIntentTensionPanel)
|
|
238
|
+
*
|
|
239
|
+
* The primary button uses `variant="default"` (the Button component's primary
|
|
240
|
+
* style: bg-gov text-paper); all others use `variant="outline"`.
|
|
241
|
+
* This satisfies §24.5 acceptance criterion 4: "primary action 不相同,且每种状态只有一个 primary".
|
|
242
|
+
*/
|
|
243
|
+
const PRIMARY_ACTION_BY_SOURCE = {
|
|
244
|
+
action_drift: 'confirm_drift',
|
|
245
|
+
intent_suspect: 'revise_intent',
|
|
246
|
+
healthy_tension: 'observe',
|
|
247
|
+
};
|
|
248
|
+
/**
|
|
249
|
+
* OwnerDecisionPanel — renders the Owner decision flow for an intent tension.
|
|
250
|
+
*
|
|
251
|
+
* State machine: 'idle' | 'submitting' | 'recorded' | 'error'
|
|
252
|
+
* - On mount, fetches existing decisions by painId (or taskId fallback).
|
|
253
|
+
* - Shows 6 action buttons + optional note input.
|
|
254
|
+
* - On submit, calls buildIntentDecisionPayload + recordIntentDecision.
|
|
255
|
+
* - Follow-up actions placeholder appears when existingDecisions is non-empty.
|
|
256
|
+
*
|
|
257
|
+
* Accessibility (EP-09):
|
|
258
|
+
* - Uses semantic <section> with aria-label
|
|
259
|
+
* - Buttons have descriptive text labels
|
|
260
|
+
*/
|
|
261
|
+
function OwnerDecisionPanel({ tension, recordId, painId, taskId, linkedCandidateId, t }) {
|
|
262
|
+
const [panelState, setPanelState] = useState('idle');
|
|
263
|
+
const [loadState, setLoadState] = useState('loading');
|
|
264
|
+
const [existingDecisions, setExistingDecisions] = useState([]);
|
|
265
|
+
const [note, setNote] = useState('');
|
|
266
|
+
const [errorMsg, setErrorMsg] = useState(null);
|
|
267
|
+
// Fetch existing decisions on mount — use painId when available, fall back to taskId.
|
|
268
|
+
useEffect(() => {
|
|
269
|
+
let cancelled = false;
|
|
270
|
+
const loadExisting = async () => {
|
|
271
|
+
setLoadState('loading');
|
|
272
|
+
const hasPainId = painId !== undefined && painId.length > 0;
|
|
273
|
+
const hasTaskId = taskId !== undefined && taskId.length > 0;
|
|
274
|
+
if (!hasPainId && !hasTaskId) {
|
|
275
|
+
// Nothing to query by — skip loading, treat as empty.
|
|
276
|
+
if (!cancelled)
|
|
277
|
+
setLoadState('loaded');
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
const result = hasPainId
|
|
281
|
+
? await listIntentDecisionsByPainId(painId)
|
|
282
|
+
: await listIntentDecisionsByTaskId(taskId);
|
|
283
|
+
if (cancelled)
|
|
284
|
+
return;
|
|
285
|
+
if (!result.success) {
|
|
286
|
+
setLoadState('error');
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
setExistingDecisions(result.data);
|
|
290
|
+
setLoadState('loaded');
|
|
291
|
+
};
|
|
292
|
+
void loadExisting();
|
|
293
|
+
return () => { cancelled = true; };
|
|
294
|
+
}, [painId, taskId]);
|
|
295
|
+
const handleSubmit = async (ownerAction) => {
|
|
296
|
+
setPanelState('submitting');
|
|
297
|
+
setErrorMsg(null);
|
|
298
|
+
// P0 fix (PRI-471): server requires a caller-supplied decision id.
|
|
299
|
+
// Use crypto.randomUUID() — available in modern browsers and Node 19+.
|
|
300
|
+
// Fallback to a timestamp-based id if crypto is unavailable (defensive).
|
|
301
|
+
const decisionId = (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function')
|
|
302
|
+
? crypto.randomUUID()
|
|
303
|
+
: 'decision-' + Date.now() + '-' + Math.random().toString(36).slice(2, 10);
|
|
304
|
+
const context = {
|
|
305
|
+
id: decisionId,
|
|
306
|
+
recordId,
|
|
307
|
+
painId,
|
|
308
|
+
taskId,
|
|
309
|
+
intentDocHash: tension.intentDocHash,
|
|
310
|
+
};
|
|
311
|
+
const payload = buildIntentDecisionPayload(tension, context, { ownerAction, note });
|
|
312
|
+
const result = await recordIntentDecision(payload);
|
|
313
|
+
if (!result.success) {
|
|
314
|
+
setPanelState('error');
|
|
315
|
+
setErrorMsg(result.error ?? t('pages.pain.ownerDecisionFailed'));
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
setPanelState('recorded');
|
|
319
|
+
// Add the new decision so follow-up actions appear.
|
|
320
|
+
setExistingDecisions([result.data.record, ...existingDecisions]);
|
|
321
|
+
};
|
|
322
|
+
const hasExisting = existingDecisions.length > 0;
|
|
323
|
+
const showFollowUp = shouldRenderFollowUpActions(existingDecisions);
|
|
324
|
+
// PRI-471: the most recent decision drives which follow-up actions are shown.
|
|
325
|
+
// Decisions are sorted DESC by createdAt (server side), so [0] is the latest.
|
|
326
|
+
const latestDecision = existingDecisions[0];
|
|
327
|
+
return (_jsxs("div", { className: "mt-4 pt-3 border-t border-line", children: [_jsx("h5", { className: "text-[13px] font-semibold text-ink mb-1", children: t('pages.pain.ownerDecisionPanelTitle') }), _jsx("p", { className: "text-ink-3 text-[12px] leading-relaxed mb-3", children: t('pages.pain.ownerDecisionPanelSubtitle') }), loadState === 'loading' && (_jsx("p", { className: "text-ink-4 text-[12px] italic", children: t('pages.pain.ownerDecisionLoadingExisting') })), loadState === 'error' && (_jsx("p", { className: "text-amber text-[12px]", children: t('pages.pain.ownerDecisionLoadFailed') })), loadState === 'loaded' && hasExisting && panelState !== 'recorded' && (_jsx("p", { className: "text-ink-3 text-[12px] mb-3 italic", children: t('pages.pain.ownerDecisionExisting') })), panelState === 'recorded' && (_jsx("p", { className: "text-emerald text-[12px] mb-3 font-medium", children: t('pages.pain.ownerDecisionRecorded') })), panelState === 'error' && errorMsg && (_jsxs("p", { className: "text-danger text-[12px] mb-3", children: [t('pages.pain.ownerDecisionFailed'), ": ", errorMsg] })), panelState !== 'recorded' && loadState === 'loaded' && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "mb-3", children: [_jsx("label", { className: "block font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.ownerDecisionNoteLabel') }), _jsx("input", { type: "text", value: note, onChange: (e) => setNote(e.target.value), placeholder: t('pages.pain.ownerDecisionNotePlaceholder'), disabled: panelState === 'submitting', className: "w-full px-3 py-1.5 text-[13px] bg-surface border border-line rounded-[var(--radius-sm)] text-ink-2 focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2 disabled:opacity-50" })] }), _jsx("div", { className: "flex flex-wrap gap-2", children: OWNER_ACTION_BUTTONS.map(({ action, labelKey }) => {
|
|
328
|
+
// SPEC §22.1.3: the source determines which single button is primary.
|
|
329
|
+
const isPrimary = PRIMARY_ACTION_BY_SOURCE[tension.source] === action;
|
|
330
|
+
return (_jsx(Button, { variant: isPrimary ? 'default' : 'outline', size: "sm", disabled: panelState === 'submitting', onClick: () => void handleSubmit(action), children: panelState === 'submitting'
|
|
331
|
+
? t('pages.pain.ownerDecisionSubmitting')
|
|
332
|
+
: t(labelKey) }, action));
|
|
333
|
+
}) })] })), showFollowUp && latestDecision && (_jsx(FollowUpActions, { decision: latestDecision, linkedCandidateId: linkedCandidateId, onDecisionUpdated: (updated) => {
|
|
334
|
+
// Replace the updated decision in the list (idempotent on id).
|
|
335
|
+
setExistingDecisions((prev) => prev.map((d) => (d.id === updated.id ? updated : d)));
|
|
336
|
+
}, t: t }))] }));
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* FollowUpActions — renders the governed follow-up actions available after an
|
|
340
|
+
* Owner decision has been persisted (SPEC §22.1.4).
|
|
341
|
+
*
|
|
342
|
+
* Which actions are shown depends on the decision's `ownerAction`:
|
|
343
|
+
* - `confirm_drift` → "Link Existing Candidate" (links to the evidence chain's
|
|
344
|
+
* linkedCandidateId, or prompts the Owner to enter one if not available).
|
|
345
|
+
* - `promote_to_rulehost` → "View RuleHost Guidance" (returns CLI command).
|
|
346
|
+
* - `revise_intent` → "View Intent Patch Proposal" (returns read-only markdown).
|
|
347
|
+
* - `observe` / `dismiss` → no follow-up actions rendered (SPEC §22.1.4).
|
|
348
|
+
*
|
|
349
|
+
* Boundaries respected:
|
|
350
|
+
* - No new activation channel — `link_candidate` only records an audit link.
|
|
351
|
+
* - No SkillFileWriter, no auto-modification of INTENT.md — the patch proposal
|
|
352
|
+
* is display-only.
|
|
353
|
+
* - No direct rule creation — `guide_rulehost` only returns CLI guidance.
|
|
354
|
+
*
|
|
355
|
+
* Accessibility (EP-09):
|
|
356
|
+
* - Uses semantic <section> with aria-label
|
|
357
|
+
* - Buttons have descriptive text labels
|
|
358
|
+
* - Status messages use role="status" for screen readers
|
|
359
|
+
*/
|
|
360
|
+
function FollowUpActions({ decision, linkedCandidateId, onDecisionUpdated, t }) {
|
|
361
|
+
const [busyState, setBusyState] = useState('idle');
|
|
362
|
+
const [errorMsg, setErrorMsg] = useState(null);
|
|
363
|
+
const [response, setResponse] = useState(null);
|
|
364
|
+
const [candidateIdInput, setCandidateIdInput] = useState(linkedCandidateId ?? '');
|
|
365
|
+
const ownerAction = decision.ownerAction;
|
|
366
|
+
// SPEC §22.1.4: observe and dismiss record decisions without follow-up actions.
|
|
367
|
+
if (ownerAction === 'observe' || ownerAction === 'dismiss') {
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
const handleDispatch = async (type) => {
|
|
371
|
+
setBusyState('dispatching');
|
|
372
|
+
setErrorMsg(null);
|
|
373
|
+
setResponse(null);
|
|
374
|
+
// Trim the candidate id so leading/trailing whitespace never reaches the
|
|
375
|
+
// audit trail (the disable-check already trims; the payload must match it).
|
|
376
|
+
// The server re-trims as the trust-boundary authority (EP-01).
|
|
377
|
+
const payload = type === 'link_candidate'
|
|
378
|
+
? { type, candidateId: candidateIdInput.trim() }
|
|
379
|
+
: { type };
|
|
380
|
+
const result = await dispatchFollowUp(decision.id, payload);
|
|
381
|
+
if (!result.success) {
|
|
382
|
+
setBusyState('error');
|
|
383
|
+
setErrorMsg(result.error ?? t('pages.pain.followUpDispatchFailed'));
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
setBusyState('dispatched');
|
|
387
|
+
setResponse(result.data);
|
|
388
|
+
// For follow-up types that update the record (link_candidate,
|
|
389
|
+
// generate_patch_proposal), propagate the updated record up so the
|
|
390
|
+
// parent's existingDecisions list stays in sync.
|
|
391
|
+
if (result.data.type === 'link_candidate' || result.data.type === 'generate_patch_proposal') {
|
|
392
|
+
onDecisionUpdated(result.data.record);
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
const isDispatching = busyState === 'dispatching';
|
|
396
|
+
return (_jsxs("div", { className: "mt-4 p-3 bg-paper-2 border border-line rounded-[var(--radius-sm)]", children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-2", children: t('pages.pain.followUpActionsTitle') }), ownerAction === 'confirm_drift' && (_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-ink-2 text-[13px] leading-relaxed", children: t('pages.pain.followUpLinkCandidateDescription') }), _jsxs("div", { className: "flex gap-2 items-start", children: [_jsx("input", { type: "text", value: candidateIdInput, onChange: (e) => setCandidateIdInput(e.target.value), placeholder: t('pages.pain.followUpCandidateIdPlaceholder'), "aria-label": t('pages.pain.followUpCandidateIdAriaLabel'), disabled: isDispatching, className: "flex-1 px-3 py-1.5 text-[13px] bg-surface border border-line rounded-[var(--radius-sm)] text-ink-2 focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2 disabled:opacity-50 font-mono" }), _jsx(Button, { variant: "outline", size: "sm", disabled: isDispatching || candidateIdInput.trim() === '', onClick: () => void handleDispatch('link_candidate'), children: isDispatching
|
|
397
|
+
? t('pages.pain.followUpDispatching')
|
|
398
|
+
: t('pages.pain.followUpLinkCandidateButton') })] }), linkedCandidateId && (_jsx("p", { className: "text-ink-4 text-[11px] italic", children: t('pages.pain.followUpPrefilledFromEvidenceChain') })), busyState === 'dispatched' && response?.type === 'link_candidate' && (_jsxs("p", { role: "status", className: "text-emerald text-[12px] font-medium", children: [t('pages.pain.followUpLinkedSuccess'), ": ", _jsx("span", { className: "font-mono", children: response.linkedCandidateId })] }))] })), ownerAction === 'promote_to_rulehost' && (_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-ink-2 text-[13px] leading-relaxed", children: t('pages.pain.followUpGuideRulehostDescription') }), _jsx(Button, { variant: "outline", size: "sm", disabled: isDispatching, onClick: () => void handleDispatch('guide_rulehost'), children: isDispatching
|
|
399
|
+
? t('pages.pain.followUpDispatching')
|
|
400
|
+
: t('pages.pain.followUpGuideRulehostButton') }), busyState === 'dispatched' && response?.type === 'guide_rulehost' && (_jsxs("div", { role: "status", className: "mt-2 p-2 bg-surface border border-line rounded-[var(--radius-sm)]", children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4 mb-1", children: t('pages.pain.followUpCliCommandLabel') }), _jsx("pre", { className: "font-mono text-[12px] text-ink-2 whitespace-pre-wrap break-all", children: response.cliCommand }), _jsx("p", { className: "text-ink-3 text-[12px] mt-2 leading-relaxed", children: response.note })] }))] })), ownerAction === 'revise_intent' && (_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-ink-2 text-[13px] leading-relaxed", children: t('pages.pain.followUpPatchProposalDescription') }), _jsx(Button, { variant: "outline", size: "sm", disabled: isDispatching, onClick: () => void handleDispatch('generate_patch_proposal'), children: isDispatching
|
|
401
|
+
? t('pages.pain.followUpDispatching')
|
|
402
|
+
: t('pages.pain.followUpViewPatchProposalButton') }), busyState === 'dispatched' && response?.type === 'generate_patch_proposal' && (_jsxs("div", { role: "status", className: "mt-2 p-2 bg-surface border border-line rounded-[var(--radius-sm)]", children: [_jsxs("div", { className: "flex items-center gap-2 mb-2", children: [_jsx("div", { className: "font-mono text-[11px] uppercase tracking-[0.08em] text-ink-4", children: t('pages.pain.followUpPatchProposalLabel') }), _jsx(Badge, { variant: "outline", className: "text-[10px]", children: t('pages.pain.followUpPatchProposalReadOnlyBadge') })] }), _jsx("pre", { className: "font-mono text-[11px] text-ink-2 whitespace-pre-wrap break-all bg-paper-2 p-2 rounded-[var(--radius-sm)] border border-line max-h-80 overflow-y-auto", children: response.patchProposal.markdown }), _jsx("p", { className: "text-amber text-[11px] mt-2 italic", children: t('pages.pain.followUpPatchProposalWarning') })] }))] })), ownerAction === 'promote_to_principle' && (_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-ink-2 text-[13px] leading-relaxed", children: t('pages.pain.followUpPromoteToPrincipleDescription') }), _jsxs("div", { className: "flex gap-2 items-start", children: [_jsx("input", { type: "text", value: candidateIdInput, onChange: (e) => setCandidateIdInput(e.target.value), placeholder: t('pages.pain.followUpCandidateIdPlaceholder'), "aria-label": t('pages.pain.followUpCandidateIdAriaLabel'), disabled: isDispatching, className: "flex-1 px-3 py-1.5 text-[13px] bg-surface border border-line rounded-[var(--radius-sm)] text-ink-2 focus-visible:outline-2 focus-visible:outline-gov focus-visible:outline-offset-2 disabled:opacity-50 font-mono" }), _jsx(Button, { variant: "outline", size: "sm", disabled: isDispatching || candidateIdInput.trim() === '', onClick: () => void handleDispatch('link_candidate'), children: isDispatching
|
|
403
|
+
? t('pages.pain.followUpDispatching')
|
|
404
|
+
: t('pages.pain.followUpLinkCandidateButton') })] }), linkedCandidateId && (_jsx("p", { className: "text-ink-4 text-[11px] italic", children: t('pages.pain.followUpPrefilledFromEvidenceChain') })), busyState === 'dispatched' && response?.type === 'link_candidate' && (_jsxs("p", { role: "status", className: "text-emerald text-[12px] font-medium", children: [t('pages.pain.followUpLinkedSuccess'), ": ", _jsx("span", { className: "font-mono", children: response.linkedCandidateId })] }))] })), busyState === 'error' && errorMsg && (_jsxs("p", { role: "alert", className: "text-danger text-[12px] mt-2", children: [t('pages.pain.followUpDispatchFailed'), ": ", errorMsg] }))] }));
|
|
405
|
+
}
|