principles-disciple 1.8.0 → 1.8.2
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/ADVANCED_CONFIG_ZH.md +97 -0
- package/AGENT_INSTALL.md +173 -0
- package/AGENT_INSTALL_EN.md +173 -0
- package/INSTALL.md +256 -0
- package/SKILL.md +63 -0
- package/docs/COMMAND_REFERENCE.md +76 -0
- package/docs/COMMAND_REFERENCE_EN.md +79 -0
- package/esbuild.config.js +75 -0
- package/openclaw.plugin.json +6 -1
- package/package.json +13 -15
- package/scripts/build-web.mjs +46 -0
- package/scripts/install-dependencies.cjs +47 -0
- package/scripts/sync-plugin.mjs +802 -0
- package/scripts/verify-build.mjs +109 -0
- package/src/agents/nocturnal-dreamer.md +152 -0
- package/src/agents/nocturnal-philosopher.md +138 -0
- package/src/agents/nocturnal-reflector.md +126 -0
- package/src/agents/nocturnal-scribe.md +164 -0
- package/src/commands/capabilities.ts +85 -0
- package/{dist/commands/context.js → src/commands/context.ts} +78 -38
- package/src/commands/evolution-status.ts +146 -0
- package/src/commands/export.ts +111 -0
- package/src/commands/focus.ts +533 -0
- package/src/commands/nocturnal-review.ts +311 -0
- package/src/commands/nocturnal-rollout.ts +763 -0
- package/src/commands/nocturnal-train.ts +1002 -0
- package/{dist/commands/pain.js → src/commands/pain.ts} +68 -49
- package/src/commands/principle-rollback.ts +27 -0
- package/{dist/commands/rollback.js → src/commands/rollback.ts} +44 -12
- package/src/commands/samples.ts +60 -0
- package/src/commands/strategy.ts +38 -0
- package/{dist/commands/thinking-os.js → src/commands/thinking-os.ts} +59 -36
- package/src/commands/workflow-debug.ts +128 -0
- package/{dist/config/defaults/runtime.js → src/config/defaults/runtime.ts} +12 -5
- package/src/config/errors.ts +163 -0
- package/{dist/config/index.d.ts → src/config/index.ts} +2 -1
- package/src/constants/diagnostician.ts +66 -0
- package/src/constants/tools.ts +62 -0
- package/src/core/adaptive-thresholds.ts +476 -0
- package/{dist/core/config-service.js → src/core/config-service.ts} +7 -4
- package/{dist/core/config.js → src/core/config.ts} +158 -46
- package/src/core/control-ui-db.ts +435 -0
- package/{dist/core/detection-funnel.js → src/core/detection-funnel.ts} +36 -21
- package/{dist/core/detection-service.js → src/core/detection-service.ts} +7 -4
- package/{dist/core/dictionary-service.js → src/core/dictionary-service.ts} +7 -4
- package/{dist/core/dictionary.js → src/core/dictionary.ts} +57 -34
- package/src/core/empathy-keyword-matcher.ts +327 -0
- package/src/core/empathy-types.ts +218 -0
- package/src/core/event-log.ts +544 -0
- package/src/core/evolution-engine.ts +612 -0
- package/src/core/evolution-logger.ts +353 -0
- package/src/core/evolution-migration.ts +77 -0
- package/src/core/evolution-reducer.ts +731 -0
- package/src/core/evolution-types.ts +456 -0
- package/src/core/external-training-contract.ts +527 -0
- package/src/core/focus-history.ts +1458 -0
- package/src/core/hygiene/tracker.ts +117 -0
- package/{dist/core/init.js → src/core/init.ts} +39 -26
- package/src/core/local-worker-routing.ts +617 -0
- package/{dist/core/migration.js → src/core/migration.ts} +18 -11
- package/src/core/model-deployment-registry.ts +722 -0
- package/src/core/model-training-registry.ts +813 -0
- package/src/core/nocturnal-arbiter.ts +706 -0
- package/src/core/nocturnal-candidate-scoring.ts +392 -0
- package/src/core/nocturnal-compliance.ts +1075 -0
- package/src/core/nocturnal-dataset.ts +668 -0
- package/src/core/nocturnal-executability.ts +428 -0
- package/src/core/nocturnal-export.ts +390 -0
- package/{dist/core/nocturnal-paths.js → src/core/nocturnal-paths.ts} +49 -23
- package/src/core/nocturnal-trajectory-extractor.ts +484 -0
- package/src/core/nocturnal-trinity.ts +1384 -0
- package/src/core/pain.ts +122 -0
- package/{dist/core/path-resolver.js → src/core/path-resolver.ts} +157 -36
- package/{dist/core/paths.js → src/core/paths.ts} +13 -4
- package/src/core/principle-training-state.ts +450 -0
- package/src/core/profile.ts +226 -0
- package/src/core/promotion-gate.ts +822 -0
- package/{dist/core/risk-calculator.js → src/core/risk-calculator.ts} +42 -16
- package/{dist/core/session-tracker.js → src/core/session-tracker.ts} +185 -63
- package/src/core/shadow-observation-registry.ts +534 -0
- package/{dist/core/system-logger.js → src/core/system-logger.ts} +9 -5
- package/src/core/thinking-models.ts +217 -0
- package/src/core/training-program.ts +630 -0
- package/src/core/trajectory-types.ts +243 -0
- package/src/core/trajectory.ts +1673 -0
- package/{dist/core/workspace-context.js → src/core/workspace-context.ts} +57 -32
- package/src/hooks/bash-risk.ts +171 -0
- package/src/hooks/edit-verification.ts +295 -0
- package/src/hooks/gate-block-helper.ts +160 -0
- package/src/hooks/gate.ts +210 -0
- package/src/hooks/gfi-gate.ts +177 -0
- package/src/hooks/lifecycle.ts +326 -0
- package/{dist/hooks/llm.js → src/hooks/llm.ts} +166 -139
- package/src/hooks/message-sanitize.ts +45 -0
- package/src/hooks/pain.ts +384 -0
- package/src/hooks/progressive-trust-gate.ts +174 -0
- package/src/hooks/prompt.ts +920 -0
- package/src/hooks/subagent.ts +207 -0
- package/src/hooks/thinking-checkpoint.ts +73 -0
- package/src/hooks/trajectory-collector.ts +290 -0
- package/src/http/principles-console-route.ts +716 -0
- package/src/i18n/commands.ts +117 -0
- package/src/index.ts +694 -0
- package/src/service/central-database.ts +831 -0
- package/src/service/control-ui-query-service.ts +888 -0
- package/src/service/evolution-query-service.ts +405 -0
- package/src/service/evolution-worker.ts +1646 -0
- package/src/service/health-query-service.ts +836 -0
- package/{dist/service/nocturnal-runtime.js → src/service/nocturnal-runtime.ts} +263 -36
- package/src/service/nocturnal-service.ts +1015 -0
- package/src/service/nocturnal-target-selector.ts +532 -0
- package/src/service/phase3-input-filter.ts +237 -0
- package/src/service/runtime-summary-service.ts +757 -0
- package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +513 -0
- package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +603 -0
- package/src/service/subagent-workflow/index.ts +51 -0
- package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +856 -0
- package/src/service/subagent-workflow/runtime-direct-driver.ts +166 -0
- package/src/service/subagent-workflow/types.ts +378 -0
- package/src/service/subagent-workflow/workflow-store.ts +328 -0
- package/src/service/trajectory-service.ts +15 -0
- package/{dist/tools/critique-prompt.js → src/tools/critique-prompt.ts} +25 -8
- package/src/tools/deep-reflect.ts +349 -0
- package/{dist/tools/model-index.js → src/tools/model-index.ts} +33 -17
- package/src/types/event-types.ts +453 -0
- package/src/types/hygiene-types.ts +31 -0
- package/src/types/principle-tree-schema.ts +244 -0
- package/src/types/runtime-summary.ts +49 -0
- package/src/types.ts +74 -0
- package/src/utils/file-lock.ts +391 -0
- package/{dist/utils/glob-match.js → src/utils/glob-match.ts} +21 -20
- package/{dist/utils/hashing.js → src/utils/hashing.ts} +6 -4
- package/src/utils/io.ts +110 -0
- package/{dist/utils/nlp.js → src/utils/nlp.ts} +19 -12
- package/{dist/utils/plugin-logger.js → src/utils/plugin-logger.ts} +33 -8
- package/src/utils/subagent-probe.ts +94 -0
- package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +70 -1
- package/templates/pain_settings.json +2 -1
- package/tests/README.md +120 -0
- package/tests/build-artifacts.test.ts +111 -0
- package/tests/commands/evolution-status.test.ts +222 -0
- package/tests/commands/evolver.test.ts +22 -0
- package/tests/commands/export.test.ts +78 -0
- package/tests/commands/nocturnal-review.test.ts +448 -0
- package/tests/commands/nocturnal-train.test.ts +97 -0
- package/tests/commands/pain.test.ts +108 -0
- package/tests/commands/samples.test.ts +65 -0
- package/tests/commands/strategy.test.ts +34 -0
- package/tests/commands/thinking-os.test.ts +88 -0
- package/tests/core/adaptive-thresholds.test.ts +261 -0
- package/tests/core/config-service.test.ts +89 -0
- package/tests/core/config.test.ts +90 -0
- package/tests/core/control-ui-db.test.ts +75 -0
- package/tests/core/core-template-guidance.test.ts +21 -0
- package/tests/core/detection-funnel.test.ts +63 -0
- package/tests/core/detection-service.test.ts +50 -0
- package/tests/core/dictionary-service.test.ts +116 -0
- package/tests/core/dictionary.test.ts +168 -0
- package/tests/core/empathy-keyword-matcher.test.ts +209 -0
- package/tests/core/event-log.test.ts +181 -0
- package/tests/core/evolution-e2e.test.ts +58 -0
- package/tests/core/evolution-engine-gate-integration.test.ts +543 -0
- package/tests/core/evolution-engine.test.ts +562 -0
- package/tests/core/evolution-logger.test.ts +148 -0
- package/tests/core/evolution-migration.test.ts +50 -0
- package/tests/core/evolution-paths.test.ts +21 -0
- package/tests/core/evolution-reducer.detector-metadata.test.ts +602 -0
- package/tests/core/evolution-reducer.test.ts +180 -0
- package/tests/core/evolution-types-loop.test.ts +48 -0
- package/tests/core/evolution-user-stories.e2e.test.ts +249 -0
- package/tests/core/external-training-contract.test.ts +463 -0
- package/tests/core/focus-history.test.ts +682 -0
- package/tests/core/init-flatten.test.ts +69 -0
- package/tests/core/init-refactor.test.ts +87 -0
- package/tests/core/init-v1.3.test.ts +46 -0
- package/tests/core/init.test.ts +190 -0
- package/tests/core/local-worker-routing.test.ts +757 -0
- package/tests/core/migration.test.ts +84 -0
- package/tests/core/model-deployment-registry.test.ts +845 -0
- package/tests/core/model-training-registry.test.ts +889 -0
- package/tests/core/nocturnal-arbiter.test.ts +494 -0
- package/tests/core/nocturnal-candidate-scoring.test.ts +400 -0
- package/tests/core/nocturnal-compliance.test.ts +646 -0
- package/tests/core/nocturnal-dataset.test.ts +892 -0
- package/tests/core/nocturnal-executability.test.ts +357 -0
- package/tests/core/nocturnal-export.test.ts +462 -0
- package/tests/core/nocturnal-reviewed-subset-comparison.test.ts +428 -0
- package/tests/core/nocturnal-trajectory-extractor.test.ts +634 -0
- package/tests/core/nocturnal-trinity.test.ts +953 -0
- package/tests/core/pain.test.ts +33 -0
- package/tests/core/path-resolver.test.ts +57 -0
- package/tests/core/paths-refactor.test.ts +42 -0
- package/tests/core/phase7-rollout-integration.test.ts +477 -0
- package/tests/core/principle-training-state.test.ts +712 -0
- package/tests/core/profile.test.ts +56 -0
- package/tests/core/promotion-gate.test.ts +556 -0
- package/tests/core/risk-calculator.test.ts +168 -0
- package/tests/core/session-tracker.test.ts +191 -0
- package/tests/core/training-program.test.ts +472 -0
- package/tests/core/trajectory.test.ts +265 -0
- package/tests/core/workspace-context-factory.test.ts +18 -0
- package/tests/core/workspace-context.test.ts +134 -0
- package/tests/fixtures/nocturnal-reviewed-subset.json +183 -0
- package/tests/fixtures/production-compatibility.test.ts +147 -0
- package/tests/fixtures/production-mock-generator.ts +282 -0
- package/tests/hooks/bash-risk-integration.test.ts +137 -0
- package/tests/hooks/bash-risk.test.ts +81 -0
- package/tests/hooks/edit-verification.test.ts +678 -0
- package/tests/hooks/gate-edit-verification-p1.test.ts +632 -0
- package/tests/hooks/gate-edit-verification.test.ts +435 -0
- package/tests/hooks/gate-pipeline-integration.test.ts +404 -0
- package/tests/hooks/gate.test.ts +271 -0
- package/tests/hooks/gfi-gate-unit.test.ts +422 -0
- package/tests/hooks/gfi-gate.test.ts +669 -0
- package/tests/hooks/lifecycle.test.ts +248 -0
- package/tests/hooks/llm.test.ts +308 -0
- package/tests/hooks/message-sanitize.test.ts +36 -0
- package/tests/hooks/pain.test.ts +141 -0
- package/tests/hooks/progressive-trust-gate.test.ts +277 -0
- package/tests/hooks/prompt.test.ts +1411 -0
- package/tests/hooks/subagent.test.ts +467 -0
- package/tests/hooks/thinking-gate.test.ts +313 -0
- package/tests/http/principles-console-route.test.ts +140 -0
- package/tests/hygiene-tracker.test.ts +77 -0
- package/tests/index.integration.test.ts +179 -0
- package/tests/index.shadow-routing.integration.test.ts +140 -0
- package/tests/index.test.ts +9 -0
- package/tests/integration/empathy-workflow-integration.test.ts +627 -0
- package/tests/service/control-ui-query-service.test.ts +121 -0
- package/tests/service/empathy-observer-workflow-manager.test.ts +176 -0
- package/tests/service/evolution-worker.test.ts +585 -0
- package/tests/service/nocturnal-runtime.test.ts +470 -0
- package/tests/service/nocturnal-service.test.ts +577 -0
- package/tests/service/nocturnal-target-selector.test.ts +615 -0
- package/tests/service/nocturnal-workflow-manager.test.ts +439 -0
- package/tests/service/phase3-input-filter.test.ts +289 -0
- package/tests/service/runtime-summary-service.test.ts +919 -0
- package/tests/task-compliance.test.ts +166 -0
- package/tests/test-utils.ts +48 -0
- package/tests/tools/critique-prompt.test.ts +260 -0
- package/tests/tools/deep-reflect.test.ts +232 -0
- package/tests/tools/model-index.test.ts +246 -0
- package/tests/ui/app.test.tsx +114 -0
- package/tests/utils/file-lock.test.ts +407 -0
- package/tests/utils/hashing.test.ts +32 -0
- package/tests/utils/io.test.ts +39 -0
- package/tests/utils/nlp.test.ts +53 -0
- package/tests/utils/plugin-logger.test.ts +156 -0
- package/tsconfig.json +16 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/ui/src/App.tsx +45 -0
- package/ui/src/api.ts +216 -0
- package/ui/src/charts.tsx +586 -0
- package/ui/src/components/ErrorState.tsx +6 -0
- package/ui/src/components/Loading.tsx +13 -0
- package/ui/src/components/ProtectedRoute.tsx +12 -0
- package/ui/src/components/Shell.tsx +91 -0
- package/ui/src/components/WorkspaceConfig.tsx +146 -0
- package/ui/src/components/index.ts +5 -0
- package/ui/src/context/auth.tsx +80 -0
- package/ui/src/context/theme.tsx +66 -0
- package/ui/src/hooks/useAutoRefresh.ts +39 -0
- package/ui/src/i18n/ui.ts +363 -0
- package/ui/src/main.tsx +16 -0
- package/ui/src/pages/EvolutionPage.tsx +352 -0
- package/ui/src/pages/FeedbackPage.tsx +140 -0
- package/ui/src/pages/GateMonitorPage.tsx +136 -0
- package/ui/src/pages/LoginPage.tsx +88 -0
- package/ui/src/pages/OverviewPage.tsx +238 -0
- package/ui/src/pages/SamplesPage.tsx +174 -0
- package/ui/src/pages/ThinkingModelsPage.tsx +127 -0
- package/ui/src/styles.css +1661 -0
- package/ui/src/types.ts +368 -0
- package/ui/src/utils/format.ts +15 -0
- package/vitest.config.ts +23 -0
- package/dist/commands/capabilities.d.ts +0 -3
- package/dist/commands/capabilities.js +0 -73
- package/dist/commands/context.d.ts +0 -5
- package/dist/commands/evolution-status.d.ts +0 -4
- package/dist/commands/evolution-status.js +0 -117
- package/dist/commands/evolver.d.ts +0 -9
- package/dist/commands/evolver.js +0 -26
- package/dist/commands/export.d.ts +0 -2
- package/dist/commands/export.js +0 -98
- package/dist/commands/focus.d.ts +0 -14
- package/dist/commands/focus.js +0 -457
- package/dist/commands/nocturnal-review.d.ts +0 -24
- package/dist/commands/nocturnal-review.js +0 -265
- package/dist/commands/nocturnal-rollout.d.ts +0 -27
- package/dist/commands/nocturnal-rollout.js +0 -671
- package/dist/commands/nocturnal-train.d.ts +0 -25
- package/dist/commands/nocturnal-train.js +0 -919
- package/dist/commands/pain.d.ts +0 -5
- package/dist/commands/principle-rollback.d.ts +0 -4
- package/dist/commands/principle-rollback.js +0 -22
- package/dist/commands/rollback.d.ts +0 -19
- package/dist/commands/samples.d.ts +0 -2
- package/dist/commands/samples.js +0 -55
- package/dist/commands/strategy.d.ts +0 -3
- package/dist/commands/strategy.js +0 -29
- package/dist/commands/thinking-os.d.ts +0 -2
- package/dist/config/defaults/runtime.d.ts +0 -40
- package/dist/config/errors.d.ts +0 -84
- package/dist/config/errors.js +0 -94
- package/dist/config/index.js +0 -7
- package/dist/constants/diagnostician.d.ts +0 -12
- package/dist/constants/diagnostician.js +0 -56
- package/dist/constants/tools.d.ts +0 -17
- package/dist/constants/tools.js +0 -54
- package/dist/core/adaptive-thresholds.d.ts +0 -186
- package/dist/core/adaptive-thresholds.js +0 -300
- package/dist/core/config-service.d.ts +0 -15
- package/dist/core/config.d.ts +0 -127
- package/dist/core/control-ui-db.d.ts +0 -95
- package/dist/core/control-ui-db.js +0 -292
- package/dist/core/detection-funnel.d.ts +0 -33
- package/dist/core/detection-service.d.ts +0 -15
- package/dist/core/dictionary-service.d.ts +0 -15
- package/dist/core/dictionary.d.ts +0 -38
- package/dist/core/event-log.d.ts +0 -82
- package/dist/core/event-log.js +0 -463
- package/dist/core/evolution-engine.d.ts +0 -118
- package/dist/core/evolution-engine.js +0 -464
- package/dist/core/evolution-logger.d.ts +0 -137
- package/dist/core/evolution-logger.js +0 -256
- package/dist/core/evolution-migration.d.ts +0 -5
- package/dist/core/evolution-migration.js +0 -65
- package/dist/core/evolution-reducer.d.ts +0 -98
- package/dist/core/evolution-reducer.js +0 -465
- package/dist/core/evolution-types.d.ts +0 -287
- package/dist/core/evolution-types.js +0 -78
- package/dist/core/external-training-contract.d.ts +0 -276
- package/dist/core/external-training-contract.js +0 -269
- package/dist/core/focus-history.d.ts +0 -210
- package/dist/core/focus-history.js +0 -1185
- package/dist/core/hygiene/tracker.d.ts +0 -22
- package/dist/core/hygiene/tracker.js +0 -106
- package/dist/core/init.d.ts +0 -12
- package/dist/core/local-worker-routing.d.ts +0 -175
- package/dist/core/local-worker-routing.js +0 -525
- package/dist/core/migration.d.ts +0 -6
- package/dist/core/model-deployment-registry.d.ts +0 -218
- package/dist/core/model-deployment-registry.js +0 -503
- package/dist/core/model-training-registry.d.ts +0 -295
- package/dist/core/model-training-registry.js +0 -475
- package/dist/core/nocturnal-arbiter.d.ts +0 -159
- package/dist/core/nocturnal-arbiter.js +0 -534
- package/dist/core/nocturnal-candidate-scoring.d.ts +0 -137
- package/dist/core/nocturnal-candidate-scoring.js +0 -266
- package/dist/core/nocturnal-compliance.d.ts +0 -175
- package/dist/core/nocturnal-compliance.js +0 -824
- package/dist/core/nocturnal-dataset.d.ts +0 -224
- package/dist/core/nocturnal-dataset.js +0 -443
- package/dist/core/nocturnal-executability.d.ts +0 -85
- package/dist/core/nocturnal-executability.js +0 -331
- package/dist/core/nocturnal-export.d.ts +0 -124
- package/dist/core/nocturnal-export.js +0 -275
- package/dist/core/nocturnal-paths.d.ts +0 -124
- package/dist/core/nocturnal-trajectory-extractor.d.ts +0 -242
- package/dist/core/nocturnal-trajectory-extractor.js +0 -307
- package/dist/core/nocturnal-trinity.d.ts +0 -311
- package/dist/core/nocturnal-trinity.js +0 -880
- package/dist/core/pain.d.ts +0 -4
- package/dist/core/pain.js +0 -70
- package/dist/core/path-resolver.d.ts +0 -46
- package/dist/core/paths.d.ts +0 -65
- package/dist/core/principle-training-state.d.ts +0 -121
- package/dist/core/principle-training-state.js +0 -321
- package/dist/core/profile.d.ts +0 -62
- package/dist/core/profile.js +0 -210
- package/dist/core/promotion-gate.d.ts +0 -238
- package/dist/core/promotion-gate.js +0 -529
- package/dist/core/risk-calculator.d.ts +0 -22
- package/dist/core/session-tracker.d.ts +0 -99
- package/dist/core/shadow-observation-registry.d.ts +0 -217
- package/dist/core/shadow-observation-registry.js +0 -308
- package/dist/core/system-logger.d.ts +0 -8
- package/dist/core/thinking-models.d.ts +0 -38
- package/dist/core/thinking-models.js +0 -170
- package/dist/core/training-program.d.ts +0 -233
- package/dist/core/training-program.js +0 -433
- package/dist/core/trajectory.d.ts +0 -411
- package/dist/core/trajectory.js +0 -1307
- package/dist/core/workspace-context.d.ts +0 -71
- package/dist/hooks/bash-risk.d.ts +0 -57
- package/dist/hooks/bash-risk.js +0 -137
- package/dist/hooks/edit-verification.d.ts +0 -62
- package/dist/hooks/edit-verification.js +0 -256
- package/dist/hooks/gate-block-helper.d.ts +0 -44
- package/dist/hooks/gate-block-helper.js +0 -119
- package/dist/hooks/gate.d.ts +0 -24
- package/dist/hooks/gate.js +0 -173
- package/dist/hooks/gfi-gate.d.ts +0 -40
- package/dist/hooks/gfi-gate.js +0 -113
- package/dist/hooks/lifecycle.d.ts +0 -5
- package/dist/hooks/lifecycle.js +0 -284
- package/dist/hooks/llm.d.ts +0 -12
- package/dist/hooks/message-sanitize.d.ts +0 -3
- package/dist/hooks/message-sanitize.js +0 -37
- package/dist/hooks/pain.d.ts +0 -5
- package/dist/hooks/pain.js +0 -301
- package/dist/hooks/progressive-trust-gate.d.ts +0 -51
- package/dist/hooks/progressive-trust-gate.js +0 -89
- package/dist/hooks/prompt.d.ts +0 -47
- package/dist/hooks/prompt.js +0 -884
- package/dist/hooks/subagent.d.ts +0 -10
- package/dist/hooks/subagent.js +0 -387
- package/dist/hooks/thinking-checkpoint.d.ts +0 -37
- package/dist/hooks/thinking-checkpoint.js +0 -51
- package/dist/hooks/trajectory-collector.d.ts +0 -32
- package/dist/hooks/trajectory-collector.js +0 -256
- package/dist/http/principles-console-route.d.ts +0 -9
- package/dist/http/principles-console-route.js +0 -567
- package/dist/i18n/commands.d.ts +0 -26
- package/dist/i18n/commands.js +0 -116
- package/dist/index.d.ts +0 -7
- package/dist/index.js +0 -581
- package/dist/service/central-database.d.ts +0 -104
- package/dist/service/central-database.js +0 -649
- package/dist/service/control-ui-query-service.d.ts +0 -221
- package/dist/service/control-ui-query-service.js +0 -543
- package/dist/service/empathy-observer-manager.d.ts +0 -52
- package/dist/service/empathy-observer-manager.js +0 -229
- package/dist/service/evolution-query-service.d.ts +0 -155
- package/dist/service/evolution-query-service.js +0 -258
- package/dist/service/evolution-worker.d.ts +0 -101
- package/dist/service/evolution-worker.js +0 -974
- package/dist/service/nocturnal-runtime.d.ts +0 -183
- package/dist/service/nocturnal-service.d.ts +0 -163
- package/dist/service/nocturnal-service.js +0 -787
- package/dist/service/nocturnal-target-selector.d.ts +0 -145
- package/dist/service/nocturnal-target-selector.js +0 -315
- package/dist/service/phase3-input-filter.d.ts +0 -73
- package/dist/service/phase3-input-filter.js +0 -172
- package/dist/service/runtime-summary-service.d.ts +0 -122
- package/dist/service/runtime-summary-service.js +0 -485
- package/dist/service/trajectory-service.d.ts +0 -2
- package/dist/service/trajectory-service.js +0 -15
- package/dist/tools/critique-prompt.d.ts +0 -14
- package/dist/tools/deep-reflect.d.ts +0 -39
- package/dist/tools/deep-reflect.js +0 -350
- package/dist/tools/model-index.d.ts +0 -9
- package/dist/types/event-types.d.ts +0 -306
- package/dist/types/event-types.js +0 -106
- package/dist/types/hygiene-types.d.ts +0 -20
- package/dist/types/hygiene-types.js +0 -12
- package/dist/types/runtime-summary.d.ts +0 -47
- package/dist/types/runtime-summary.js +0 -1
- package/dist/types.d.ts +0 -50
- package/dist/types.js +0 -22
- package/dist/utils/file-lock.d.ts +0 -71
- package/dist/utils/file-lock.js +0 -309
- package/dist/utils/glob-match.d.ts +0 -28
- package/dist/utils/hashing.d.ts +0 -9
- package/dist/utils/io.d.ts +0 -6
- package/dist/utils/io.js +0 -106
- package/dist/utils/nlp.d.ts +0 -9
- package/dist/utils/plugin-logger.d.ts +0 -39
- package/dist/utils/subagent-probe.d.ts +0 -34
- package/dist/utils/subagent-probe.js +0 -81
|
@@ -0,0 +1,757 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { readPainFlagData } from '../core/pain.js';
|
|
4
|
+
import { listSessions } from '../core/session-tracker.js';
|
|
5
|
+
import { WorkspaceContext } from '../core/workspace-context.js';
|
|
6
|
+
import { evaluatePhase3Inputs } from './phase3-input-filter.js';
|
|
7
|
+
import { TrajectoryRegistry } from '../core/trajectory.js';
|
|
8
|
+
import type { RuntimeTruth, AnalyticsTruth, TrendMetrics } from '../types/runtime-summary.js';
|
|
9
|
+
|
|
10
|
+
export type RuntimeDataQuality = 'authoritative' | 'partial';
|
|
11
|
+
export type RuntimeRewardPolicy =
|
|
12
|
+
| 'frozen_all_positive'
|
|
13
|
+
| 'frozen_atomic_positive_keep_plan_ready';
|
|
14
|
+
|
|
15
|
+
interface RuntimeSummarySource {
|
|
16
|
+
source: string;
|
|
17
|
+
score?: number;
|
|
18
|
+
ts?: string;
|
|
19
|
+
confidence?: number;
|
|
20
|
+
origin?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface RuntimePainSignal {
|
|
24
|
+
source: string;
|
|
25
|
+
ts: string | null;
|
|
26
|
+
reason: string | null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface RuntimeSummary {
|
|
30
|
+
/**
|
|
31
|
+
* Runtime truth represents the current state of the system.
|
|
32
|
+
* Used for control decisions, Phase 3 eligibility, and real-time operations.
|
|
33
|
+
*/
|
|
34
|
+
runtime: RuntimeTruth;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Analytics truth represents historical data and aggregated metrics.
|
|
38
|
+
* Used for insights, trends, and supporting evidence (where explicitly allowed).
|
|
39
|
+
* NOT used for control decisions or Phase 3 eligibility.
|
|
40
|
+
*/
|
|
41
|
+
analytics: AnalyticsTruth;
|
|
42
|
+
|
|
43
|
+
gfi: {
|
|
44
|
+
current: number | null;
|
|
45
|
+
peak: number | null;
|
|
46
|
+
sources: RuntimeSummarySource[];
|
|
47
|
+
dataQuality: RuntimeDataQuality;
|
|
48
|
+
};
|
|
49
|
+
evolution: {
|
|
50
|
+
queue: {
|
|
51
|
+
pending: number;
|
|
52
|
+
inProgress: number;
|
|
53
|
+
completed: number;
|
|
54
|
+
};
|
|
55
|
+
directive: {
|
|
56
|
+
exists: boolean;
|
|
57
|
+
active: boolean | null;
|
|
58
|
+
ageSeconds: number | null;
|
|
59
|
+
taskPreview: string | null;
|
|
60
|
+
};
|
|
61
|
+
dataQuality: RuntimeDataQuality;
|
|
62
|
+
};
|
|
63
|
+
phase3: {
|
|
64
|
+
queueTruthReady: boolean;
|
|
65
|
+
phase3ShadowEligible: boolean;
|
|
66
|
+
evolutionEligible: number;
|
|
67
|
+
evolutionReferenceOnly: number;
|
|
68
|
+
evolutionReferenceOnlyReasons: string[];
|
|
69
|
+
evolutionRejected: number;
|
|
70
|
+
evolutionRejectedReasons: string[];
|
|
71
|
+
legacyDirectiveFilePresent: boolean;
|
|
72
|
+
directiveStatus: 'compatibility-only' | 'missing' | 'present';
|
|
73
|
+
directiveIgnoredReason: string;
|
|
74
|
+
/**
|
|
75
|
+
* Source of Phase 3 eligibility calculation.
|
|
76
|
+
* Should always be 'runtime_truth' - analytics not used for control decisions.
|
|
77
|
+
*/
|
|
78
|
+
eligibilitySource: 'runtime_truth';
|
|
79
|
+
};
|
|
80
|
+
pain: {
|
|
81
|
+
activeFlag: boolean;
|
|
82
|
+
activeFlagSource: string | null;
|
|
83
|
+
candidates: number | null;
|
|
84
|
+
lastSignal: RuntimePainSignal | null;
|
|
85
|
+
};
|
|
86
|
+
gate: {
|
|
87
|
+
recentBlocks: number | null;
|
|
88
|
+
recentBypasses: number | null;
|
|
89
|
+
dataQuality: RuntimeDataQuality;
|
|
90
|
+
};
|
|
91
|
+
metadata: {
|
|
92
|
+
generatedAt: string;
|
|
93
|
+
workspaceDir: string;
|
|
94
|
+
sessionId: string | null;
|
|
95
|
+
selectedSessionReason: 'explicit' | 'latest_active' | 'none';
|
|
96
|
+
warnings: string[];
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
interface PersistedSessionState {
|
|
101
|
+
sessionId: string;
|
|
102
|
+
currentGfi?: number;
|
|
103
|
+
dailyGfiPeak?: number;
|
|
104
|
+
lastActivityAt?: number;
|
|
105
|
+
lastControlActivityAt?: number;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
interface QueueItem {
|
|
109
|
+
id?: string;
|
|
110
|
+
status?: string;
|
|
111
|
+
task?: string;
|
|
112
|
+
trigger_text_preview?: string;
|
|
113
|
+
taskId?: string;
|
|
114
|
+
score?: number;
|
|
115
|
+
source?: string;
|
|
116
|
+
reason?: string;
|
|
117
|
+
timestamp?: string;
|
|
118
|
+
enqueued_at?: string;
|
|
119
|
+
started_at?: string;
|
|
120
|
+
assigned_session_key?: string;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
interface DirectiveFile {
|
|
124
|
+
active?: boolean;
|
|
125
|
+
task?: string;
|
|
126
|
+
taskId?: string;
|
|
127
|
+
timestamp?: string;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
interface EventLogEntry {
|
|
131
|
+
ts?: string;
|
|
132
|
+
type?: string;
|
|
133
|
+
category?: string;
|
|
134
|
+
sessionId?: string;
|
|
135
|
+
data?: Record<string, unknown>;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const MAX_SOURCE_EVENTS = 5;
|
|
139
|
+
const GFI_PARTIAL_WARNING =
|
|
140
|
+
'GFI source attribution remains partial in Phase 2b because only the empathy slice is source-attributed; most non-empathy friction still lacks full per-source attribution.';
|
|
141
|
+
const DAILY_GFI_WARNING =
|
|
142
|
+
'daily-stats.gfi is not authoritative in Phase 1 and is used only as a fallback reference.';
|
|
143
|
+
const EVENT_BUFFER_WARNING =
|
|
144
|
+
'Live event buffer is unavailable in this context, so status may lag until events.jsonl flushes.';
|
|
145
|
+
|
|
146
|
+
function pushWarning(warnings: string[], message: string): void {
|
|
147
|
+
if (!warnings.includes(message)) {
|
|
148
|
+
warnings.push(message);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export class RuntimeSummaryService {
|
|
153
|
+
static getSummary(
|
|
154
|
+
workspaceDir: string,
|
|
155
|
+
options?: { sessionId?: string | null }
|
|
156
|
+
): RuntimeSummary {
|
|
157
|
+
const generatedAt = new Date().toISOString();
|
|
158
|
+
const warnings: string[] = [];
|
|
159
|
+
const wctx = WorkspaceContext.fromHookContext({ workspaceDir });
|
|
160
|
+
|
|
161
|
+
const sessions = this.mergeSessionSnapshots(
|
|
162
|
+
this.readSessions(wctx.resolve('SESSION_DIR'), warnings),
|
|
163
|
+
workspaceDir
|
|
164
|
+
);
|
|
165
|
+
const selectedSession = this.selectSession(sessions, options?.sessionId ?? null);
|
|
166
|
+
const selectedSessionId = selectedSession.session?.sessionId ?? null;
|
|
167
|
+
|
|
168
|
+
const persistedEvents = this.readEvents(path.join(wctx.stateDir, 'logs', 'events.jsonl'), warnings);
|
|
169
|
+
const hasBufferedEventAccess =
|
|
170
|
+
typeof (wctx.eventLog as { getBufferedEvents?: () => EventLogEntry[] }).getBufferedEvents === 'function';
|
|
171
|
+
const bufferedEvents = hasBufferedEventAccess
|
|
172
|
+
? (wctx.eventLog as { getBufferedEvents: () => EventLogEntry[] }).getBufferedEvents()
|
|
173
|
+
: [];
|
|
174
|
+
const events = this.mergeEvents(persistedEvents, bufferedEvents);
|
|
175
|
+
const dailyStats = this.readJsonFile<Record<string, {
|
|
176
|
+
gfi?: { peak?: number };
|
|
177
|
+
toolCalls?: number;
|
|
178
|
+
painSignals?: number;
|
|
179
|
+
evolutionTasks?: number;
|
|
180
|
+
}>>(
|
|
181
|
+
path.join(wctx.stateDir, 'logs', 'daily-stats.json'),
|
|
182
|
+
warnings,
|
|
183
|
+
false
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
// Get most recent date from daily stats, fallback to today
|
|
187
|
+
const today = generatedAt.slice(0, 10);
|
|
188
|
+
const availableDates = Object.keys(dailyStats || {}).sort().reverse();
|
|
189
|
+
const statsDate = availableDates.length > 0 ? availableDates[0] : today;
|
|
190
|
+
const dailyGfiPeak = dailyStats?.[statsDate]?.gfi?.peak;
|
|
191
|
+
|
|
192
|
+
const gfiCurrent =
|
|
193
|
+
selectedSession.session && Number.isFinite(selectedSession.session.currentGfi)
|
|
194
|
+
? Number(selectedSession.session.currentGfi)
|
|
195
|
+
: null;
|
|
196
|
+
|
|
197
|
+
const sessionPeak =
|
|
198
|
+
selectedSession.session && Number.isFinite(selectedSession.session.dailyGfiPeak)
|
|
199
|
+
? Number(selectedSession.session.dailyGfiPeak)
|
|
200
|
+
: null;
|
|
201
|
+
const gfiPeak =
|
|
202
|
+
sessionPeak ?? (Number.isFinite(dailyGfiPeak) ? Number(dailyGfiPeak) : null);
|
|
203
|
+
|
|
204
|
+
pushWarning(warnings, GFI_PARTIAL_WARNING);
|
|
205
|
+
if (sessionPeak === null && Number.isFinite(dailyGfiPeak)) {
|
|
206
|
+
pushWarning(warnings, DAILY_GFI_WARNING);
|
|
207
|
+
}
|
|
208
|
+
if (!hasBufferedEventAccess) {
|
|
209
|
+
pushWarning(warnings, EVENT_BUFFER_WARNING);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (!selectedSession.session) {
|
|
213
|
+
pushWarning(warnings, 'No persisted session state was found; current session GFI is unavailable.');
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const queue = this.readJsonFile<QueueItem[]>(wctx.resolve('EVOLUTION_QUEUE'), warnings, false);
|
|
217
|
+
// compatibility-only display artifact - not a truth source for Phase 3 eligibility
|
|
218
|
+
// queue is the only authoritative execution truth source for Phase 3
|
|
219
|
+
const directive = this.readJsonFile<DirectiveFile>(wctx.resolve('EVOLUTION_DIRECTIVE'), warnings, false);
|
|
220
|
+
const queueStats = this.buildQueueStats(queue);
|
|
221
|
+
const directiveSummary = this.buildDirectiveSummary(queue, directive, generatedAt, warnings);
|
|
222
|
+
|
|
223
|
+
const painFlag = readPainFlagData(workspaceDir);
|
|
224
|
+
const painCandidates = this.readJsonFile<{ candidates?: Record<string, unknown> }>(
|
|
225
|
+
wctx.resolve('PAIN_CANDIDATES'),
|
|
226
|
+
warnings,
|
|
227
|
+
false
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
const phase3Inputs = evaluatePhase3Inputs(queue ?? []);
|
|
231
|
+
|
|
232
|
+
const lastPainSignal = this.findLastPainSignal(events, selectedSessionId);
|
|
233
|
+
const gfiSources = this.buildGfiSources(events, selectedSessionId);
|
|
234
|
+
const gateStats = this.buildGateStats(events, selectedSessionId, warnings);
|
|
235
|
+
|
|
236
|
+
// Read trajectory analytics data (historical data, NOT runtime truth)
|
|
237
|
+
const trajectoryStats = this.readTrajectoryStats(workspaceDir, warnings);
|
|
238
|
+
|
|
239
|
+
// Build runtime truth section (current state for control decisions)
|
|
240
|
+
const activeSessionIds = sessions.map(s => s.sessionId);
|
|
241
|
+
const runtimeTruth: RuntimeTruth = {
|
|
242
|
+
queueState: {
|
|
243
|
+
total: queueStats.pending + queueStats.inProgress + queueStats.completed,
|
|
244
|
+
pending: queueStats.pending,
|
|
245
|
+
inProgress: queueStats.inProgress,
|
|
246
|
+
completed: queueStats.completed,
|
|
247
|
+
lastUpdated: generatedAt,
|
|
248
|
+
},
|
|
249
|
+
activeSessions: activeSessionIds,
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// Build analytics truth section (historical data for insights)
|
|
253
|
+
const analyticsTruth: AnalyticsTruth = {
|
|
254
|
+
trajectoryData: {
|
|
255
|
+
totalTasks: trajectoryStats.assistantTurns + trajectoryStats.userTurns,
|
|
256
|
+
successRate: trajectoryStats.toolCalls > 0
|
|
257
|
+
? (trajectoryStats.toolCalls - trajectoryStats.failures) / trajectoryStats.toolCalls
|
|
258
|
+
: 0,
|
|
259
|
+
timeoutRate: trajectoryStats.failures > 0
|
|
260
|
+
? trajectoryStats.failures / (trajectoryStats.assistantTurns + trajectoryStats.userTurns || 1)
|
|
261
|
+
: 0,
|
|
262
|
+
lastUpdated: trajectoryStats.lastIngestAt ?? generatedAt,
|
|
263
|
+
},
|
|
264
|
+
dailyStats: {
|
|
265
|
+
toolCalls: dailyStats?.[statsDate]?.toolCalls ?? 0,
|
|
266
|
+
painSignals: dailyStats?.[statsDate]?.painSignals ?? 0,
|
|
267
|
+
evolutionTasks: dailyStats?.[statsDate]?.evolutionTasks ?? 0,
|
|
268
|
+
lastUpdated: statsDate,
|
|
269
|
+
},
|
|
270
|
+
trends: {
|
|
271
|
+
sevenDay: { successRateChange: 0, toolCallVolumeChange: 0, painSignalRateChange: 0 },
|
|
272
|
+
thirtyDay: { successRateChange: 0, toolCallVolumeChange: 0, painSignalRateChange: 0 },
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
return {
|
|
277
|
+
runtime: runtimeTruth,
|
|
278
|
+
analytics: analyticsTruth,
|
|
279
|
+
gfi: {
|
|
280
|
+
current: gfiCurrent,
|
|
281
|
+
peak: gfiPeak,
|
|
282
|
+
sources: gfiSources,
|
|
283
|
+
dataQuality: 'partial',
|
|
284
|
+
},
|
|
285
|
+
evolution: {
|
|
286
|
+
queue: queueStats,
|
|
287
|
+
directive: directiveSummary,
|
|
288
|
+
dataQuality: this.resolveEvolutionDataQuality(queue),
|
|
289
|
+
},
|
|
290
|
+
phase3: {
|
|
291
|
+
queueTruthReady: phase3Inputs.queueTruthReady,
|
|
292
|
+
phase3ShadowEligible: phase3Inputs.phase3ShadowEligible,
|
|
293
|
+
evolutionEligible: phase3Inputs.evolution.eligible.length,
|
|
294
|
+
evolutionReferenceOnly: phase3Inputs.evolution.referenceOnly.length,
|
|
295
|
+
evolutionReferenceOnlyReasons: [...new Set(phase3Inputs.evolution.referenceOnly.map((entry) => entry.classification))],
|
|
296
|
+
evolutionRejected: phase3Inputs.evolution.rejected.length,
|
|
297
|
+
evolutionRejectedReasons: phase3Inputs.evolution.rejected.flatMap((entry) => entry.reasons),
|
|
298
|
+
legacyDirectiveFilePresent: directive !== null,
|
|
299
|
+
directiveStatus: directive ? 'compatibility-only' : 'missing',
|
|
300
|
+
directiveIgnoredReason: 'queue is only truth source',
|
|
301
|
+
eligibilitySource: 'runtime_truth',
|
|
302
|
+
},
|
|
303
|
+
pain: {
|
|
304
|
+
activeFlag: Object.keys(painFlag).length > 0,
|
|
305
|
+
activeFlagSource: painFlag.source || null,
|
|
306
|
+
candidates:
|
|
307
|
+
painCandidates?.candidates && typeof painCandidates.candidates === 'object'
|
|
308
|
+
? Object.keys(painCandidates.candidates).length
|
|
309
|
+
: null,
|
|
310
|
+
lastSignal: lastPainSignal,
|
|
311
|
+
},
|
|
312
|
+
gate: gateStats,
|
|
313
|
+
metadata: {
|
|
314
|
+
generatedAt,
|
|
315
|
+
workspaceDir,
|
|
316
|
+
sessionId: selectedSessionId,
|
|
317
|
+
selectedSessionReason: selectedSession.reason,
|
|
318
|
+
warnings,
|
|
319
|
+
},
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
private static readSessions(sessionDir: string, warnings: string[]): PersistedSessionState[] {
|
|
324
|
+
if (!fs.existsSync(sessionDir)) {
|
|
325
|
+
pushWarning(warnings, 'No persisted session directory exists yet; session-scoped runtime state is unavailable.');
|
|
326
|
+
return [];
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const sessions: PersistedSessionState[] = [];
|
|
330
|
+
for (const file of fs.readdirSync(sessionDir)) {
|
|
331
|
+
if (!file.endsWith('.json')) continue;
|
|
332
|
+
try {
|
|
333
|
+
const raw = fs.readFileSync(path.join(sessionDir, file), 'utf8');
|
|
334
|
+
const parsed = JSON.parse(raw) as PersistedSessionState;
|
|
335
|
+
if (parsed?.sessionId) {
|
|
336
|
+
sessions.push(parsed);
|
|
337
|
+
}
|
|
338
|
+
} catch {
|
|
339
|
+
pushWarning(warnings, `Failed to parse session snapshot: ${file}`);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return sessions.sort((a, b) => this.resolveSessionSortTime(b) - this.resolveSessionSortTime(a));
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
private static selectSession(
|
|
347
|
+
sessions: PersistedSessionState[],
|
|
348
|
+
explicitSessionId: string | null
|
|
349
|
+
): {
|
|
350
|
+
session: PersistedSessionState | null;
|
|
351
|
+
reason: 'explicit' | 'latest_active' | 'none';
|
|
352
|
+
} {
|
|
353
|
+
if (explicitSessionId) {
|
|
354
|
+
const explicit = sessions.find((session) => session.sessionId === explicitSessionId) ?? null;
|
|
355
|
+
return { session: explicit, reason: explicit ? 'explicit' : 'none' };
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (sessions.length === 0) {
|
|
359
|
+
return { session: null, reason: 'none' };
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return { session: sessions[0], reason: 'latest_active' };
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
private static mergeSessionSnapshots(
|
|
366
|
+
persistedSessions: PersistedSessionState[],
|
|
367
|
+
workspaceDir: string
|
|
368
|
+
): PersistedSessionState[] {
|
|
369
|
+
const merged = new Map<string, PersistedSessionState>();
|
|
370
|
+
|
|
371
|
+
for (const session of persistedSessions) {
|
|
372
|
+
merged.set(session.sessionId, { ...session });
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
for (const live of listSessions(workspaceDir)) {
|
|
376
|
+
const persisted = merged.get(live.sessionId);
|
|
377
|
+
merged.set(live.sessionId, {
|
|
378
|
+
sessionId: live.sessionId,
|
|
379
|
+
currentGfi:
|
|
380
|
+
Number.isFinite(live.currentGfi) ? Number(live.currentGfi) : persisted?.currentGfi,
|
|
381
|
+
dailyGfiPeak:
|
|
382
|
+
Number.isFinite(live.dailyGfiPeak) ? Number(live.dailyGfiPeak) : persisted?.dailyGfiPeak,
|
|
383
|
+
lastActivityAt:
|
|
384
|
+
Number.isFinite(live.lastActivityAt) ? Number(live.lastActivityAt) : persisted?.lastActivityAt,
|
|
385
|
+
lastControlActivityAt:
|
|
386
|
+
Number.isFinite(live.lastControlActivityAt)
|
|
387
|
+
? Number(live.lastControlActivityAt)
|
|
388
|
+
: persisted?.lastControlActivityAt,
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
return [...merged.values()].sort((a, b) => this.resolveSessionSortTime(b) - this.resolveSessionSortTime(a));
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
private static buildQueueStats(queue: QueueItem[] | null): {
|
|
396
|
+
pending: number;
|
|
397
|
+
inProgress: number;
|
|
398
|
+
completed: number;
|
|
399
|
+
} {
|
|
400
|
+
const stats = { pending: 0, inProgress: 0, completed: 0 };
|
|
401
|
+
if (!queue) return stats;
|
|
402
|
+
|
|
403
|
+
for (const item of queue) {
|
|
404
|
+
if (item?.status === 'completed') {
|
|
405
|
+
stats.completed++;
|
|
406
|
+
} else if (item?.status === 'in_progress') {
|
|
407
|
+
stats.inProgress++;
|
|
408
|
+
} else {
|
|
409
|
+
stats.pending++;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return stats;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Builds directive summary for compatibility display only.
|
|
418
|
+
* NOT a truth source for Phase 3 eligibility or decisions.
|
|
419
|
+
* Queue is the only authoritative execution truth source.
|
|
420
|
+
*/
|
|
421
|
+
private static buildDirectiveSummary(
|
|
422
|
+
queue: QueueItem[] | null,
|
|
423
|
+
directive: DirectiveFile | null,
|
|
424
|
+
generatedAt: string,
|
|
425
|
+
warnings: string[]
|
|
426
|
+
): {
|
|
427
|
+
exists: boolean;
|
|
428
|
+
active: boolean | null;
|
|
429
|
+
ageSeconds: number | null;
|
|
430
|
+
taskPreview: string | null;
|
|
431
|
+
} {
|
|
432
|
+
const inProgressTask = this.selectInProgressTask(queue);
|
|
433
|
+
if (!inProgressTask) {
|
|
434
|
+
if (directive) {
|
|
435
|
+
this.warnOnLegacyDirectiveMismatch(directive, null, warnings);
|
|
436
|
+
}
|
|
437
|
+
return {
|
|
438
|
+
exists: false,
|
|
439
|
+
active: null,
|
|
440
|
+
ageSeconds: null,
|
|
441
|
+
taskPreview: null,
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const derivedTaskPreview = this.buildDirectiveTaskPreview(inProgressTask);
|
|
446
|
+
const timestampMs = this.resolveDirectiveTimestamp(inProgressTask);
|
|
447
|
+
const ageSeconds = Number.isFinite(timestampMs)
|
|
448
|
+
? Math.max(0, Math.floor((new Date(generatedAt).getTime() - timestampMs) / 1000))
|
|
449
|
+
: null;
|
|
450
|
+
|
|
451
|
+
if (directive) {
|
|
452
|
+
this.warnOnLegacyDirectiveMismatch(directive, {
|
|
453
|
+
active: true,
|
|
454
|
+
taskPreview: derivedTaskPreview,
|
|
455
|
+
taskId: inProgressTask.taskId ?? inProgressTask.id ?? null,
|
|
456
|
+
}, warnings);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
return {
|
|
460
|
+
exists: true,
|
|
461
|
+
active: true,
|
|
462
|
+
ageSeconds,
|
|
463
|
+
taskPreview: derivedTaskPreview,
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
private static readEvents(eventsPath: string, warnings: string[]): EventLogEntry[] {
|
|
468
|
+
if (!fs.existsSync(eventsPath)) {
|
|
469
|
+
warnings.push('No events.jsonl file exists yet; recent pain and gate summaries are partial.');
|
|
470
|
+
return [];
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
try {
|
|
474
|
+
const raw = fs.readFileSync(eventsPath, 'utf8').trim();
|
|
475
|
+
if (!raw) return [];
|
|
476
|
+
let parseFailures = 0;
|
|
477
|
+
const entries = raw
|
|
478
|
+
.split('\n')
|
|
479
|
+
.map((line) => {
|
|
480
|
+
try {
|
|
481
|
+
return JSON.parse(line) as EventLogEntry;
|
|
482
|
+
} catch {
|
|
483
|
+
parseFailures += 1;
|
|
484
|
+
return null;
|
|
485
|
+
}
|
|
486
|
+
})
|
|
487
|
+
.filter((entry): entry is EventLogEntry => entry !== null);
|
|
488
|
+
if (parseFailures > 0) {
|
|
489
|
+
pushWarning(
|
|
490
|
+
warnings,
|
|
491
|
+
`Skipped ${parseFailures} malformed event line${parseFailures === 1 ? '' : 's'} while reading events.jsonl.`
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
return entries;
|
|
495
|
+
} catch {
|
|
496
|
+
pushWarning(warnings, 'Failed to read events.jsonl; recent pain and gate summaries are partial.');
|
|
497
|
+
return [];
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
private static buildGfiSources(events: EventLogEntry[], sessionId: string | null): RuntimeSummarySource[] {
|
|
502
|
+
const filtered = events
|
|
503
|
+
.filter((entry) => {
|
|
504
|
+
if (sessionId && entry.sessionId !== sessionId) return false;
|
|
505
|
+
return (
|
|
506
|
+
entry.type === 'pain_signal' ||
|
|
507
|
+
(entry.type === 'tool_call' && entry.category === 'failure')
|
|
508
|
+
);
|
|
509
|
+
})
|
|
510
|
+
.slice(-MAX_SOURCE_EVENTS)
|
|
511
|
+
.reverse();
|
|
512
|
+
|
|
513
|
+
return filtered.map((entry) => {
|
|
514
|
+
if (entry.type === 'pain_signal') {
|
|
515
|
+
return {
|
|
516
|
+
source: String(entry.data?.source ?? 'pain_signal'),
|
|
517
|
+
score: this.asFiniteNumber(entry.data?.score),
|
|
518
|
+
ts: entry.ts,
|
|
519
|
+
confidence: this.asFiniteNumber(entry.data?.confidence),
|
|
520
|
+
origin: typeof entry.data?.origin === 'string' ? entry.data.origin : undefined,
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
return {
|
|
525
|
+
source: `tool_failure:${String(entry.data?.toolName ?? 'unknown')}`,
|
|
526
|
+
score: this.asFiniteNumber(entry.data?.gfi),
|
|
527
|
+
ts: entry.ts,
|
|
528
|
+
};
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
private static findLastPainSignal(
|
|
533
|
+
events: EventLogEntry[],
|
|
534
|
+
sessionId: string | null
|
|
535
|
+
): RuntimePainSignal | null {
|
|
536
|
+
for (let i = events.length - 1; i >= 0; i--) {
|
|
537
|
+
const entry = events[i];
|
|
538
|
+
if (entry.type !== 'pain_signal') continue;
|
|
539
|
+
if (sessionId && entry.sessionId !== sessionId) continue;
|
|
540
|
+
return {
|
|
541
|
+
source: String(entry.data?.source ?? 'pain_signal'),
|
|
542
|
+
ts: entry.ts ?? null,
|
|
543
|
+
reason: typeof entry.data?.reason === 'string' ? entry.data.reason : null,
|
|
544
|
+
};
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
return null;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
private static buildGateStats(
|
|
551
|
+
events: EventLogEntry[],
|
|
552
|
+
sessionId: string | null,
|
|
553
|
+
warnings: string[]
|
|
554
|
+
): RuntimeSummary['gate'] {
|
|
555
|
+
const scoped = events.filter((entry) => {
|
|
556
|
+
if (sessionId && entry.sessionId !== sessionId) return false;
|
|
557
|
+
return entry.type === 'gate_block' || entry.type === 'gate_bypass';
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
if (scoped.length === 0) {
|
|
561
|
+
pushWarning(warnings, 'Gate block counts before Phase 1 may be incomplete because older block events were not recorded to event-log.');
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
return {
|
|
565
|
+
recentBlocks: scoped.filter((entry) => entry.type === 'gate_block').length,
|
|
566
|
+
recentBypasses: scoped.filter((entry) => entry.type === 'gate_bypass').length,
|
|
567
|
+
dataQuality: scoped.length > 0 ? 'authoritative' : 'partial',
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
private static resolveSessionSortTime(session: PersistedSessionState): number {
|
|
572
|
+
return session.lastControlActivityAt ?? session.lastActivityAt ?? 0;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
private static mergeEvents(persistedEvents: EventLogEntry[], bufferedEvents: EventLogEntry[]): EventLogEntry[] {
|
|
576
|
+
const merged = new Map<string, EventLogEntry>();
|
|
577
|
+
for (const entry of [...persistedEvents, ...bufferedEvents]) {
|
|
578
|
+
merged.set(this.getEventDedupKey(entry), entry);
|
|
579
|
+
}
|
|
580
|
+
return [...merged.values()].sort((a, b) => (a.ts || '').localeCompare(b.ts || ''));
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
private static getEventDedupKey(entry: EventLogEntry): string {
|
|
584
|
+
const eventId = typeof entry.data?.eventId === 'string' ? entry.data.eventId : null;
|
|
585
|
+
if (eventId) {
|
|
586
|
+
return `${entry.type}:${entry.sessionId ?? 'none'}:${eventId}`;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
return [
|
|
590
|
+
entry.ts ?? 'no-ts',
|
|
591
|
+
entry.type ?? 'no-type',
|
|
592
|
+
entry.category ?? 'no-category',
|
|
593
|
+
entry.sessionId ?? 'no-session',
|
|
594
|
+
typeof entry.data?.source === 'string' ? entry.data.source : 'no-source',
|
|
595
|
+
typeof entry.data?.toolName === 'string' ? entry.data.toolName : 'no-tool',
|
|
596
|
+
typeof entry.data?.reason === 'string' ? entry.data.reason : 'no-reason',
|
|
597
|
+
].join('::');
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
private static resolveEvolutionDataQuality(
|
|
601
|
+
queue: QueueItem[] | null
|
|
602
|
+
): RuntimeDataQuality {
|
|
603
|
+
return queue ? 'authoritative' : 'partial';
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
private static selectInProgressTask(queue: QueueItem[] | null): QueueItem | null {
|
|
607
|
+
if (!queue || queue.length === 0) return null;
|
|
608
|
+
|
|
609
|
+
const inProgress = queue.filter((item) => item?.status === 'in_progress');
|
|
610
|
+
if (inProgress.length === 0) return null;
|
|
611
|
+
|
|
612
|
+
for (const item of [...inProgress].sort((a, b) => this.getQueuePriority(b) - this.getQueuePriority(a))) {
|
|
613
|
+
if (this.isResolvableEvolutionTask(item)) {
|
|
614
|
+
return item;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
return null;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
private static getQueuePriority(item: QueueItem): number {
|
|
622
|
+
return Number.isFinite(item.score) ? Number(item.score) : 0;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
private static isResolvableEvolutionTask(item: QueueItem): boolean {
|
|
626
|
+
const rawTask = typeof item.task === 'string' ? item.task.trim() : '';
|
|
627
|
+
if (rawTask && rawTask.toLowerCase() !== 'undefined') {
|
|
628
|
+
return true;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
return typeof item.id === 'string' && item.id.trim().length > 0;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
private static resolveDirectiveTimestamp(item: QueueItem): number {
|
|
635
|
+
const candidate = item.started_at || item.enqueued_at || item.timestamp || null;
|
|
636
|
+
return candidate ? new Date(candidate).getTime() : NaN;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
private static buildDirectiveTaskPreview(item: QueueItem): string {
|
|
640
|
+
const task = typeof item.task === 'string' ? item.task.trim() : '';
|
|
641
|
+
if (task && task.toLowerCase() !== 'undefined') {
|
|
642
|
+
return task.slice(0, 160);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
const triggerTextPreview = typeof item.trigger_text_preview === 'string' ? item.trigger_text_preview.trim() : '';
|
|
646
|
+
|
|
647
|
+
const taskId = typeof item.taskId === 'string' && item.taskId.trim()
|
|
648
|
+
? item.taskId.trim()
|
|
649
|
+
: typeof item.id === 'string' && item.id.trim()
|
|
650
|
+
? item.id.trim()
|
|
651
|
+
: 'unknown';
|
|
652
|
+
const source = typeof item.source === 'string' && item.source.trim() ? item.source.trim() : 'unknown';
|
|
653
|
+
const reason = typeof item.reason === 'string' && item.reason.trim() ? item.reason.trim() : 'Systemic pain detected';
|
|
654
|
+
const preview = triggerTextPreview || 'N/A';
|
|
655
|
+
return `Diagnose systemic pain [ID: ${taskId}]. Source: ${source}. Reason: ${reason}. Trigger text: "${preview}"`.slice(0, 160);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
private static warnOnLegacyDirectiveMismatch(
|
|
659
|
+
directive: DirectiveFile,
|
|
660
|
+
derived: { active: boolean; taskPreview: string | null; taskId: string | null } | null,
|
|
661
|
+
warnings: string[]
|
|
662
|
+
): void {
|
|
663
|
+
const legacyActive = typeof directive.active === 'boolean' ? directive.active : null;
|
|
664
|
+
const legacyTask = typeof directive.task === 'string' && directive.task.trim() ? directive.task.trim().slice(0, 160) : null;
|
|
665
|
+
const legacyTaskId = typeof directive.taskId === 'string' && directive.taskId.trim() ? directive.taskId.trim() : null;
|
|
666
|
+
|
|
667
|
+
const mismatchDetails: string[] = [];
|
|
668
|
+
if (derived === null) {
|
|
669
|
+
if (legacyActive === true || legacyTask || legacyTaskId) {
|
|
670
|
+
mismatchDetails.push('legacy directive exists but queue has no in_progress task');
|
|
671
|
+
}
|
|
672
|
+
} else {
|
|
673
|
+
if (legacyActive !== null && legacyActive !== derived.active) {
|
|
674
|
+
mismatchDetails.push(`active=${String(legacyActive)} vs queue=${String(derived.active)}`);
|
|
675
|
+
}
|
|
676
|
+
if (legacyTask && derived.taskPreview && legacyTask !== derived.taskPreview) {
|
|
677
|
+
mismatchDetails.push('task text differs');
|
|
678
|
+
}
|
|
679
|
+
if (legacyTaskId && derived.taskId && legacyTaskId !== derived.taskId) {
|
|
680
|
+
mismatchDetails.push('task id differs');
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
if (mismatchDetails.length > 0) {
|
|
685
|
+
pushWarning(
|
|
686
|
+
warnings,
|
|
687
|
+
`Legacy directive file disagrees with queue-derived evolution state; queue is authoritative (${mismatchDetails.join(', ')}).`
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
private static readJsonFile<T>(
|
|
693
|
+
filePath: string,
|
|
694
|
+
warnings: string[],
|
|
695
|
+
warnOnMissing: boolean
|
|
696
|
+
): T | null {
|
|
697
|
+
if (!fs.existsSync(filePath)) {
|
|
698
|
+
if (warnOnMissing) {
|
|
699
|
+
pushWarning(warnings, `Missing expected file: ${path.basename(filePath)}`);
|
|
700
|
+
}
|
|
701
|
+
return null;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
try {
|
|
705
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8')) as T;
|
|
706
|
+
} catch {
|
|
707
|
+
pushWarning(warnings, `Failed to parse ${path.basename(filePath)}.`);
|
|
708
|
+
return null;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
private static asFiniteNumber(value: unknown): number | undefined {
|
|
713
|
+
return Number.isFinite(value) ? Number(value) : undefined;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* Read trajectory analytics data from trajectory database.
|
|
718
|
+
*
|
|
719
|
+
* Returns: Analytics data (historical metrics) aggregated from trajectory database.
|
|
720
|
+
* Not: Runtime truth or real-time queue state.
|
|
721
|
+
*/
|
|
722
|
+
private static readTrajectoryStats(
|
|
723
|
+
workspaceDir: string,
|
|
724
|
+
warnings: string[]
|
|
725
|
+
): {
|
|
726
|
+
assistantTurns: number;
|
|
727
|
+
userTurns: number;
|
|
728
|
+
toolCalls: number;
|
|
729
|
+
failures: number;
|
|
730
|
+
lastIngestAt: string | null;
|
|
731
|
+
} {
|
|
732
|
+
try {
|
|
733
|
+
// Use transient database instance to avoid locking issues
|
|
734
|
+
const stats = TrajectoryRegistry.use(workspaceDir, (db) => db.getDataStats());
|
|
735
|
+
|
|
736
|
+
return {
|
|
737
|
+
assistantTurns: stats.assistantTurns,
|
|
738
|
+
userTurns: stats.userTurns,
|
|
739
|
+
toolCalls: stats.toolCalls,
|
|
740
|
+
failures: stats.painEvents, // Approximate failures from pain events
|
|
741
|
+
lastIngestAt: stats.lastIngestAt,
|
|
742
|
+
};
|
|
743
|
+
} catch (error) {
|
|
744
|
+
pushWarning(
|
|
745
|
+
warnings,
|
|
746
|
+
`Failed to read trajectory analytics: ${error instanceof Error ? error.message : String(error)}`
|
|
747
|
+
);
|
|
748
|
+
return {
|
|
749
|
+
assistantTurns: 0,
|
|
750
|
+
userTurns: 0,
|
|
751
|
+
toolCalls: 0,
|
|
752
|
+
failures: 0,
|
|
753
|
+
lastIngestAt: null,
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
}
|