principles-disciple 1.8.1 → 1.8.3

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.
Files changed (508) hide show
  1. package/ADVANCED_CONFIG_ZH.md +97 -0
  2. package/AGENT_INSTALL.md +173 -0
  3. package/AGENT_INSTALL_EN.md +173 -0
  4. package/INSTALL.md +256 -0
  5. package/SKILL.md +63 -0
  6. package/docs/COMMAND_REFERENCE.md +76 -0
  7. package/docs/COMMAND_REFERENCE_EN.md +79 -0
  8. package/esbuild.config.js +75 -0
  9. package/openclaw.plugin.json +4 -4
  10. package/package.json +11 -13
  11. package/scripts/build-web.mjs +46 -0
  12. package/scripts/install-dependencies.cjs +47 -0
  13. package/scripts/sync-plugin.mjs +802 -0
  14. package/scripts/verify-build.mjs +109 -0
  15. package/src/agents/nocturnal-dreamer.md +152 -0
  16. package/src/agents/nocturnal-philosopher.md +138 -0
  17. package/src/agents/nocturnal-reflector.md +126 -0
  18. package/src/agents/nocturnal-scribe.md +164 -0
  19. package/src/commands/capabilities.ts +85 -0
  20. package/{dist/commands/context.js → src/commands/context.ts} +78 -38
  21. package/src/commands/evolution-status.ts +146 -0
  22. package/src/commands/export.ts +111 -0
  23. package/src/commands/focus.ts +533 -0
  24. package/src/commands/nocturnal-review.ts +311 -0
  25. package/src/commands/nocturnal-rollout.ts +763 -0
  26. package/src/commands/nocturnal-train.ts +1002 -0
  27. package/{dist/commands/pain.js → src/commands/pain.ts} +68 -49
  28. package/src/commands/principle-rollback.ts +27 -0
  29. package/{dist/commands/rollback.js → src/commands/rollback.ts} +44 -12
  30. package/src/commands/samples.ts +60 -0
  31. package/src/commands/strategy.ts +38 -0
  32. package/{dist/commands/thinking-os.js → src/commands/thinking-os.ts} +59 -36
  33. package/src/commands/workflow-debug.ts +128 -0
  34. package/{dist/config/defaults/runtime.js → src/config/defaults/runtime.ts} +12 -5
  35. package/src/config/errors.ts +163 -0
  36. package/{dist/config/index.d.ts → src/config/index.ts} +2 -1
  37. package/src/constants/diagnostician.ts +66 -0
  38. package/src/constants/tools.ts +62 -0
  39. package/src/core/adaptive-thresholds.ts +476 -0
  40. package/{dist/core/config-service.js → src/core/config-service.ts} +7 -4
  41. package/{dist/core/config.js → src/core/config.ts} +158 -46
  42. package/src/core/control-ui-db.ts +435 -0
  43. package/{dist/core/detection-funnel.js → src/core/detection-funnel.ts} +36 -21
  44. package/{dist/core/detection-service.js → src/core/detection-service.ts} +7 -4
  45. package/{dist/core/dictionary-service.js → src/core/dictionary-service.ts} +7 -4
  46. package/{dist/core/dictionary.js → src/core/dictionary.ts} +57 -34
  47. package/src/core/empathy-keyword-matcher.ts +327 -0
  48. package/src/core/empathy-types.ts +218 -0
  49. package/src/core/event-log.ts +544 -0
  50. package/src/core/evolution-engine.ts +612 -0
  51. package/src/core/evolution-logger.ts +353 -0
  52. package/src/core/evolution-migration.ts +77 -0
  53. package/src/core/evolution-reducer.ts +731 -0
  54. package/src/core/evolution-types.ts +456 -0
  55. package/src/core/external-training-contract.ts +527 -0
  56. package/src/core/focus-history.ts +1458 -0
  57. package/src/core/hygiene/tracker.ts +117 -0
  58. package/{dist/core/init.js → src/core/init.ts} +39 -26
  59. package/src/core/local-worker-routing.ts +617 -0
  60. package/{dist/core/migration.js → src/core/migration.ts} +18 -11
  61. package/src/core/model-deployment-registry.ts +722 -0
  62. package/src/core/model-training-registry.ts +813 -0
  63. package/src/core/nocturnal-arbiter.ts +706 -0
  64. package/src/core/nocturnal-candidate-scoring.ts +392 -0
  65. package/src/core/nocturnal-compliance.ts +1075 -0
  66. package/src/core/nocturnal-dataset.ts +668 -0
  67. package/src/core/nocturnal-executability.ts +428 -0
  68. package/src/core/nocturnal-export.ts +390 -0
  69. package/{dist/core/nocturnal-paths.js → src/core/nocturnal-paths.ts} +49 -23
  70. package/src/core/nocturnal-trajectory-extractor.ts +484 -0
  71. package/src/core/nocturnal-trinity.ts +1384 -0
  72. package/src/core/pain.ts +122 -0
  73. package/{dist/core/path-resolver.js → src/core/path-resolver.ts} +157 -36
  74. package/{dist/core/paths.js → src/core/paths.ts} +13 -4
  75. package/src/core/principle-training-state.ts +450 -0
  76. package/src/core/profile.ts +226 -0
  77. package/src/core/promotion-gate.ts +822 -0
  78. package/{dist/core/risk-calculator.js → src/core/risk-calculator.ts} +42 -16
  79. package/{dist/core/session-tracker.js → src/core/session-tracker.ts} +175 -62
  80. package/src/core/shadow-observation-registry.ts +534 -0
  81. package/{dist/core/system-logger.js → src/core/system-logger.ts} +9 -5
  82. package/src/core/thinking-models.ts +217 -0
  83. package/src/core/training-program.ts +630 -0
  84. package/src/core/trajectory-types.ts +243 -0
  85. package/src/core/trajectory.ts +1673 -0
  86. package/{dist/core/workspace-context.js → src/core/workspace-context.ts} +57 -32
  87. package/src/hooks/bash-risk.ts +171 -0
  88. package/src/hooks/edit-verification.ts +295 -0
  89. package/src/hooks/gate-block-helper.ts +160 -0
  90. package/src/hooks/gate.ts +210 -0
  91. package/src/hooks/gfi-gate.ts +177 -0
  92. package/src/hooks/lifecycle.ts +326 -0
  93. package/{dist/hooks/llm.js → src/hooks/llm.ts} +160 -80
  94. package/src/hooks/message-sanitize.ts +45 -0
  95. package/src/hooks/pain.ts +384 -0
  96. package/src/hooks/progressive-trust-gate.ts +174 -0
  97. package/src/hooks/prompt.ts +920 -0
  98. package/src/hooks/subagent.ts +207 -0
  99. package/src/hooks/thinking-checkpoint.ts +73 -0
  100. package/src/hooks/trajectory-collector.ts +290 -0
  101. package/src/http/principles-console-route.ts +716 -0
  102. package/src/i18n/commands.ts +117 -0
  103. package/src/index.ts +694 -0
  104. package/src/service/central-database.ts +831 -0
  105. package/src/service/control-ui-query-service.ts +888 -0
  106. package/src/service/evolution-query-service.ts +405 -0
  107. package/src/service/evolution-worker.ts +1646 -0
  108. package/src/service/health-query-service.ts +836 -0
  109. package/{dist/service/nocturnal-runtime.js → src/service/nocturnal-runtime.ts} +235 -79
  110. package/src/service/nocturnal-service.ts +1015 -0
  111. package/src/service/nocturnal-target-selector.ts +532 -0
  112. package/src/service/phase3-input-filter.ts +237 -0
  113. package/src/service/runtime-summary-service.ts +757 -0
  114. package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +513 -0
  115. package/{dist/service/subagent-workflow/empathy-observer-workflow-manager.js → src/service/subagent-workflow/empathy-observer-workflow-manager.ts} +240 -117
  116. package/src/service/subagent-workflow/index.ts +51 -0
  117. package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +856 -0
  118. package/src/service/subagent-workflow/runtime-direct-driver.ts +166 -0
  119. package/{dist/service/subagent-workflow/types.d.ts → src/service/subagent-workflow/types.ts} +137 -18
  120. package/src/service/subagent-workflow/workflow-store.ts +328 -0
  121. package/src/service/trajectory-service.ts +15 -0
  122. package/{dist/tools/critique-prompt.js → src/tools/critique-prompt.ts} +25 -8
  123. package/src/tools/deep-reflect.ts +349 -0
  124. package/{dist/tools/model-index.js → src/tools/model-index.ts} +33 -17
  125. package/src/types/event-types.ts +453 -0
  126. package/src/types/hygiene-types.ts +31 -0
  127. package/src/types/principle-tree-schema.ts +244 -0
  128. package/src/types/runtime-summary.ts +49 -0
  129. package/src/types.ts +74 -0
  130. package/src/utils/file-lock.ts +391 -0
  131. package/{dist/utils/glob-match.js → src/utils/glob-match.ts} +21 -20
  132. package/{dist/utils/hashing.js → src/utils/hashing.ts} +6 -4
  133. package/src/utils/io.ts +110 -0
  134. package/{dist/utils/nlp.js → src/utils/nlp.ts} +19 -12
  135. package/{dist/utils/plugin-logger.js → src/utils/plugin-logger.ts} +33 -8
  136. package/src/utils/subagent-probe.ts +94 -0
  137. package/templates/langs/en/skills/ai-sprint-orchestration/EXAMPLES.md +63 -0
  138. package/templates/langs/en/skills/ai-sprint-orchestration/REFERENCE.md +136 -0
  139. package/templates/langs/en/skills/ai-sprint-orchestration/SKILL.md +67 -0
  140. package/templates/langs/en/skills/ai-sprint-orchestration/references/agent-registry.json +214 -0
  141. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +107 -0
  142. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +107 -0
  143. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +105 -0
  144. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +108 -0
  145. package/templates/langs/en/skills/ai-sprint-orchestration/references/workflow-v1-acceptance-checklist.md +58 -0
  146. package/templates/langs/en/skills/ai-sprint-orchestration/references/workflow-v1.4-work-unit-handoff.md +190 -0
  147. package/templates/langs/en/skills/ai-sprint-orchestration/runtime/.gitignore +2 -0
  148. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/archive.mjs +310 -0
  149. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/contract-enforcement.mjs +683 -0
  150. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/decision.mjs +604 -0
  151. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/state-store.mjs +32 -0
  152. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/task-specs.mjs +707 -0
  153. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/run.mjs +3419 -0
  154. package/templates/langs/zh/skills/ai-sprint-orchestration/EXAMPLES.md +63 -0
  155. package/templates/langs/zh/skills/ai-sprint-orchestration/REFERENCE.md +136 -0
  156. package/templates/langs/zh/skills/ai-sprint-orchestration/SKILL.md +67 -0
  157. package/templates/langs/zh/skills/ai-sprint-orchestration/references/agent-registry.json +214 -0
  158. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +107 -0
  159. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +107 -0
  160. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +105 -0
  161. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +108 -0
  162. package/templates/langs/zh/skills/ai-sprint-orchestration/references/workflow-v1-acceptance-checklist.md +58 -0
  163. package/templates/langs/zh/skills/ai-sprint-orchestration/references/workflow-v1.4-work-unit-handoff.md +190 -0
  164. package/templates/langs/zh/skills/ai-sprint-orchestration/runtime/.gitignore +2 -0
  165. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/archive.mjs +310 -0
  166. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/contract-enforcement.mjs +683 -0
  167. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/decision.mjs +604 -0
  168. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/state-store.mjs +32 -0
  169. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/task-specs.mjs +707 -0
  170. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/run.mjs +3419 -0
  171. package/templates/langs/zh/skills/ai-sprint-orchestration/test/archive.test.mjs +230 -0
  172. package/templates/langs/zh/skills/ai-sprint-orchestration/test/contract-enforcement.test.mjs +672 -0
  173. package/templates/langs/zh/skills/ai-sprint-orchestration/test/decision.test.mjs +1321 -0
  174. package/templates/langs/zh/skills/ai-sprint-orchestration/test/run.test.mjs +1419 -0
  175. package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +70 -1
  176. package/templates/pain_settings.json +2 -1
  177. package/tests/README.md +120 -0
  178. package/tests/build-artifacts.test.ts +111 -0
  179. package/tests/commands/evolution-status.test.ts +222 -0
  180. package/tests/commands/evolver.test.ts +22 -0
  181. package/tests/commands/export.test.ts +78 -0
  182. package/tests/commands/nocturnal-review.test.ts +448 -0
  183. package/tests/commands/nocturnal-train.test.ts +97 -0
  184. package/tests/commands/pain.test.ts +108 -0
  185. package/tests/commands/samples.test.ts +65 -0
  186. package/tests/commands/strategy.test.ts +34 -0
  187. package/tests/commands/thinking-os.test.ts +88 -0
  188. package/tests/core/adaptive-thresholds.test.ts +261 -0
  189. package/tests/core/config-service.test.ts +89 -0
  190. package/tests/core/config.test.ts +90 -0
  191. package/tests/core/control-ui-db.test.ts +75 -0
  192. package/tests/core/core-template-guidance.test.ts +21 -0
  193. package/tests/core/detection-funnel.test.ts +63 -0
  194. package/tests/core/detection-service.test.ts +50 -0
  195. package/tests/core/dictionary-service.test.ts +116 -0
  196. package/tests/core/dictionary.test.ts +168 -0
  197. package/tests/core/empathy-keyword-matcher.test.ts +209 -0
  198. package/tests/core/event-log.test.ts +181 -0
  199. package/tests/core/evolution-e2e.test.ts +58 -0
  200. package/tests/core/evolution-engine-gate-integration.test.ts +543 -0
  201. package/tests/core/evolution-engine.test.ts +562 -0
  202. package/tests/core/evolution-logger.test.ts +148 -0
  203. package/tests/core/evolution-migration.test.ts +50 -0
  204. package/tests/core/evolution-paths.test.ts +21 -0
  205. package/tests/core/evolution-reducer.detector-metadata.test.ts +602 -0
  206. package/tests/core/evolution-reducer.test.ts +180 -0
  207. package/tests/core/evolution-types-loop.test.ts +48 -0
  208. package/tests/core/evolution-user-stories.e2e.test.ts +249 -0
  209. package/tests/core/external-training-contract.test.ts +463 -0
  210. package/tests/core/focus-history.test.ts +682 -0
  211. package/tests/core/init-flatten.test.ts +69 -0
  212. package/tests/core/init-refactor.test.ts +87 -0
  213. package/tests/core/init-v1.3.test.ts +46 -0
  214. package/tests/core/init.test.ts +190 -0
  215. package/tests/core/local-worker-routing.test.ts +757 -0
  216. package/tests/core/migration.test.ts +84 -0
  217. package/tests/core/model-deployment-registry.test.ts +845 -0
  218. package/tests/core/model-training-registry.test.ts +889 -0
  219. package/tests/core/nocturnal-arbiter.test.ts +494 -0
  220. package/tests/core/nocturnal-candidate-scoring.test.ts +400 -0
  221. package/tests/core/nocturnal-compliance.test.ts +646 -0
  222. package/tests/core/nocturnal-dataset.test.ts +892 -0
  223. package/tests/core/nocturnal-executability.test.ts +357 -0
  224. package/tests/core/nocturnal-export.test.ts +462 -0
  225. package/tests/core/nocturnal-reviewed-subset-comparison.test.ts +428 -0
  226. package/tests/core/nocturnal-trajectory-extractor.test.ts +634 -0
  227. package/tests/core/nocturnal-trinity.test.ts +953 -0
  228. package/tests/core/pain.test.ts +33 -0
  229. package/tests/core/path-resolver.test.ts +57 -0
  230. package/tests/core/paths-refactor.test.ts +42 -0
  231. package/tests/core/phase7-rollout-integration.test.ts +477 -0
  232. package/tests/core/principle-training-state.test.ts +712 -0
  233. package/tests/core/profile.test.ts +56 -0
  234. package/tests/core/promotion-gate.test.ts +556 -0
  235. package/tests/core/risk-calculator.test.ts +168 -0
  236. package/tests/core/session-tracker.test.ts +191 -0
  237. package/tests/core/training-program.test.ts +472 -0
  238. package/tests/core/trajectory.test.ts +265 -0
  239. package/tests/core/workspace-context-factory.test.ts +18 -0
  240. package/tests/core/workspace-context.test.ts +134 -0
  241. package/tests/fixtures/nocturnal-reviewed-subset.json +183 -0
  242. package/tests/fixtures/production-compatibility.test.ts +147 -0
  243. package/tests/fixtures/production-mock-generator.ts +282 -0
  244. package/tests/hooks/bash-risk-integration.test.ts +137 -0
  245. package/tests/hooks/bash-risk.test.ts +81 -0
  246. package/tests/hooks/edit-verification.test.ts +678 -0
  247. package/tests/hooks/gate-edit-verification-p1.test.ts +632 -0
  248. package/tests/hooks/gate-edit-verification.test.ts +435 -0
  249. package/tests/hooks/gate-pipeline-integration.test.ts +404 -0
  250. package/tests/hooks/gate.test.ts +271 -0
  251. package/tests/hooks/gfi-gate-unit.test.ts +422 -0
  252. package/tests/hooks/gfi-gate.test.ts +669 -0
  253. package/tests/hooks/lifecycle.test.ts +248 -0
  254. package/tests/hooks/llm.test.ts +308 -0
  255. package/tests/hooks/message-sanitize.test.ts +36 -0
  256. package/tests/hooks/pain.test.ts +141 -0
  257. package/tests/hooks/progressive-trust-gate.test.ts +277 -0
  258. package/tests/hooks/prompt.test.ts +1411 -0
  259. package/tests/hooks/subagent.test.ts +467 -0
  260. package/tests/hooks/thinking-gate.test.ts +313 -0
  261. package/tests/http/principles-console-route.test.ts +140 -0
  262. package/tests/hygiene-tracker.test.ts +77 -0
  263. package/tests/index.integration.test.ts +179 -0
  264. package/tests/index.shadow-routing.integration.test.ts +140 -0
  265. package/tests/index.test.ts +9 -0
  266. package/tests/integration/empathy-workflow-integration.test.ts +627 -0
  267. package/tests/service/control-ui-query-service.test.ts +121 -0
  268. package/tests/service/empathy-observer-workflow-manager.test.ts +176 -0
  269. package/tests/service/evolution-worker.test.ts +585 -0
  270. package/tests/service/nocturnal-runtime.test.ts +470 -0
  271. package/tests/service/nocturnal-service.test.ts +577 -0
  272. package/tests/service/nocturnal-target-selector.test.ts +615 -0
  273. package/tests/service/nocturnal-workflow-manager.test.ts +439 -0
  274. package/tests/service/phase3-input-filter.test.ts +289 -0
  275. package/tests/service/runtime-summary-service.test.ts +919 -0
  276. package/tests/task-compliance.test.ts +166 -0
  277. package/tests/test-utils.ts +48 -0
  278. package/tests/tools/critique-prompt.test.ts +260 -0
  279. package/tests/tools/deep-reflect.test.ts +232 -0
  280. package/tests/tools/model-index.test.ts +246 -0
  281. package/tests/ui/app.test.tsx +114 -0
  282. package/tests/utils/file-lock.test.ts +407 -0
  283. package/tests/utils/hashing.test.ts +32 -0
  284. package/tests/utils/io.test.ts +39 -0
  285. package/tests/utils/nlp.test.ts +53 -0
  286. package/tests/utils/plugin-logger.test.ts +156 -0
  287. package/tsconfig.json +16 -0
  288. package/tsconfig.tsbuildinfo +1 -0
  289. package/ui/src/App.tsx +45 -0
  290. package/ui/src/api.ts +216 -0
  291. package/ui/src/charts.tsx +586 -0
  292. package/ui/src/components/ErrorState.tsx +6 -0
  293. package/ui/src/components/Loading.tsx +13 -0
  294. package/ui/src/components/ProtectedRoute.tsx +12 -0
  295. package/ui/src/components/Shell.tsx +91 -0
  296. package/ui/src/components/WorkspaceConfig.tsx +146 -0
  297. package/ui/src/components/index.ts +5 -0
  298. package/ui/src/context/auth.tsx +80 -0
  299. package/ui/src/context/theme.tsx +66 -0
  300. package/ui/src/hooks/useAutoRefresh.ts +39 -0
  301. package/ui/src/i18n/ui.ts +363 -0
  302. package/ui/src/main.tsx +16 -0
  303. package/ui/src/pages/EvolutionPage.tsx +352 -0
  304. package/ui/src/pages/FeedbackPage.tsx +140 -0
  305. package/ui/src/pages/GateMonitorPage.tsx +136 -0
  306. package/ui/src/pages/LoginPage.tsx +88 -0
  307. package/ui/src/pages/OverviewPage.tsx +238 -0
  308. package/ui/src/pages/SamplesPage.tsx +174 -0
  309. package/ui/src/pages/ThinkingModelsPage.tsx +127 -0
  310. package/ui/src/styles.css +1661 -0
  311. package/ui/src/types.ts +368 -0
  312. package/ui/src/utils/format.ts +15 -0
  313. package/vitest.config.ts +23 -0
  314. package/dist/commands/capabilities.d.ts +0 -3
  315. package/dist/commands/capabilities.js +0 -73
  316. package/dist/commands/context.d.ts +0 -5
  317. package/dist/commands/evolution-status.d.ts +0 -4
  318. package/dist/commands/evolution-status.js +0 -117
  319. package/dist/commands/evolver.d.ts +0 -9
  320. package/dist/commands/evolver.js +0 -26
  321. package/dist/commands/export.d.ts +0 -2
  322. package/dist/commands/export.js +0 -98
  323. package/dist/commands/focus.d.ts +0 -14
  324. package/dist/commands/focus.js +0 -457
  325. package/dist/commands/nocturnal-review.d.ts +0 -24
  326. package/dist/commands/nocturnal-review.js +0 -265
  327. package/dist/commands/nocturnal-rollout.d.ts +0 -27
  328. package/dist/commands/nocturnal-rollout.js +0 -671
  329. package/dist/commands/nocturnal-train.d.ts +0 -25
  330. package/dist/commands/nocturnal-train.js +0 -919
  331. package/dist/commands/pain.d.ts +0 -5
  332. package/dist/commands/principle-rollback.d.ts +0 -4
  333. package/dist/commands/principle-rollback.js +0 -22
  334. package/dist/commands/rollback.d.ts +0 -19
  335. package/dist/commands/samples.d.ts +0 -2
  336. package/dist/commands/samples.js +0 -55
  337. package/dist/commands/strategy.d.ts +0 -3
  338. package/dist/commands/strategy.js +0 -29
  339. package/dist/commands/thinking-os.d.ts +0 -2
  340. package/dist/config/defaults/runtime.d.ts +0 -40
  341. package/dist/config/errors.d.ts +0 -84
  342. package/dist/config/errors.js +0 -94
  343. package/dist/config/index.js +0 -7
  344. package/dist/constants/diagnostician.d.ts +0 -12
  345. package/dist/constants/diagnostician.js +0 -56
  346. package/dist/constants/tools.d.ts +0 -17
  347. package/dist/constants/tools.js +0 -54
  348. package/dist/core/adaptive-thresholds.d.ts +0 -186
  349. package/dist/core/adaptive-thresholds.js +0 -300
  350. package/dist/core/config-service.d.ts +0 -15
  351. package/dist/core/config.d.ts +0 -129
  352. package/dist/core/control-ui-db.d.ts +0 -95
  353. package/dist/core/control-ui-db.js +0 -292
  354. package/dist/core/detection-funnel.d.ts +0 -33
  355. package/dist/core/detection-service.d.ts +0 -15
  356. package/dist/core/dictionary-service.d.ts +0 -15
  357. package/dist/core/dictionary.d.ts +0 -38
  358. package/dist/core/event-log.d.ts +0 -82
  359. package/dist/core/event-log.js +0 -463
  360. package/dist/core/evolution-engine.d.ts +0 -118
  361. package/dist/core/evolution-engine.js +0 -464
  362. package/dist/core/evolution-logger.d.ts +0 -137
  363. package/dist/core/evolution-logger.js +0 -256
  364. package/dist/core/evolution-migration.d.ts +0 -5
  365. package/dist/core/evolution-migration.js +0 -65
  366. package/dist/core/evolution-reducer.d.ts +0 -98
  367. package/dist/core/evolution-reducer.js +0 -465
  368. package/dist/core/evolution-types.d.ts +0 -287
  369. package/dist/core/evolution-types.js +0 -78
  370. package/dist/core/external-training-contract.d.ts +0 -276
  371. package/dist/core/external-training-contract.js +0 -269
  372. package/dist/core/focus-history.d.ts +0 -210
  373. package/dist/core/focus-history.js +0 -1185
  374. package/dist/core/hygiene/tracker.d.ts +0 -22
  375. package/dist/core/hygiene/tracker.js +0 -106
  376. package/dist/core/init.d.ts +0 -12
  377. package/dist/core/local-worker-routing.d.ts +0 -175
  378. package/dist/core/local-worker-routing.js +0 -525
  379. package/dist/core/migration.d.ts +0 -6
  380. package/dist/core/model-deployment-registry.d.ts +0 -218
  381. package/dist/core/model-deployment-registry.js +0 -503
  382. package/dist/core/model-training-registry.d.ts +0 -295
  383. package/dist/core/model-training-registry.js +0 -475
  384. package/dist/core/nocturnal-arbiter.d.ts +0 -159
  385. package/dist/core/nocturnal-arbiter.js +0 -534
  386. package/dist/core/nocturnal-candidate-scoring.d.ts +0 -137
  387. package/dist/core/nocturnal-candidate-scoring.js +0 -266
  388. package/dist/core/nocturnal-compliance.d.ts +0 -175
  389. package/dist/core/nocturnal-compliance.js +0 -824
  390. package/dist/core/nocturnal-dataset.d.ts +0 -224
  391. package/dist/core/nocturnal-dataset.js +0 -443
  392. package/dist/core/nocturnal-executability.d.ts +0 -85
  393. package/dist/core/nocturnal-executability.js +0 -331
  394. package/dist/core/nocturnal-export.d.ts +0 -124
  395. package/dist/core/nocturnal-export.js +0 -275
  396. package/dist/core/nocturnal-paths.d.ts +0 -124
  397. package/dist/core/nocturnal-trajectory-extractor.d.ts +0 -242
  398. package/dist/core/nocturnal-trajectory-extractor.js +0 -307
  399. package/dist/core/nocturnal-trinity.d.ts +0 -311
  400. package/dist/core/nocturnal-trinity.js +0 -880
  401. package/dist/core/pain.d.ts +0 -4
  402. package/dist/core/pain.js +0 -70
  403. package/dist/core/path-resolver.d.ts +0 -46
  404. package/dist/core/paths.d.ts +0 -65
  405. package/dist/core/principle-training-state.d.ts +0 -121
  406. package/dist/core/principle-training-state.js +0 -321
  407. package/dist/core/profile.d.ts +0 -62
  408. package/dist/core/profile.js +0 -210
  409. package/dist/core/promotion-gate.d.ts +0 -238
  410. package/dist/core/promotion-gate.js +0 -529
  411. package/dist/core/risk-calculator.d.ts +0 -22
  412. package/dist/core/session-tracker.d.ts +0 -101
  413. package/dist/core/shadow-observation-registry.d.ts +0 -217
  414. package/dist/core/shadow-observation-registry.js +0 -308
  415. package/dist/core/system-logger.d.ts +0 -8
  416. package/dist/core/thinking-models.d.ts +0 -38
  417. package/dist/core/thinking-models.js +0 -170
  418. package/dist/core/training-program.d.ts +0 -233
  419. package/dist/core/training-program.js +0 -433
  420. package/dist/core/trajectory.d.ts +0 -411
  421. package/dist/core/trajectory.js +0 -1307
  422. package/dist/core/workspace-context.d.ts +0 -71
  423. package/dist/hooks/bash-risk.d.ts +0 -57
  424. package/dist/hooks/bash-risk.js +0 -137
  425. package/dist/hooks/edit-verification.d.ts +0 -62
  426. package/dist/hooks/edit-verification.js +0 -256
  427. package/dist/hooks/gate-block-helper.d.ts +0 -44
  428. package/dist/hooks/gate-block-helper.js +0 -119
  429. package/dist/hooks/gate.d.ts +0 -24
  430. package/dist/hooks/gate.js +0 -173
  431. package/dist/hooks/gfi-gate.d.ts +0 -40
  432. package/dist/hooks/gfi-gate.js +0 -113
  433. package/dist/hooks/lifecycle.d.ts +0 -5
  434. package/dist/hooks/lifecycle.js +0 -284
  435. package/dist/hooks/llm.d.ts +0 -13
  436. package/dist/hooks/message-sanitize.d.ts +0 -3
  437. package/dist/hooks/message-sanitize.js +0 -37
  438. package/dist/hooks/pain.d.ts +0 -5
  439. package/dist/hooks/pain.js +0 -301
  440. package/dist/hooks/progressive-trust-gate.d.ts +0 -52
  441. package/dist/hooks/progressive-trust-gate.js +0 -134
  442. package/dist/hooks/prompt.d.ts +0 -49
  443. package/dist/hooks/prompt.js +0 -905
  444. package/dist/hooks/subagent.d.ts +0 -10
  445. package/dist/hooks/subagent.js +0 -387
  446. package/dist/hooks/thinking-checkpoint.d.ts +0 -37
  447. package/dist/hooks/thinking-checkpoint.js +0 -51
  448. package/dist/hooks/trajectory-collector.d.ts +0 -32
  449. package/dist/hooks/trajectory-collector.js +0 -256
  450. package/dist/http/principles-console-route.d.ts +0 -9
  451. package/dist/http/principles-console-route.js +0 -681
  452. package/dist/i18n/commands.d.ts +0 -26
  453. package/dist/i18n/commands.js +0 -116
  454. package/dist/index.d.ts +0 -7
  455. package/dist/index.js +0 -581
  456. package/dist/service/central-database.d.ts +0 -104
  457. package/dist/service/central-database.js +0 -649
  458. package/dist/service/control-ui-query-service.d.ts +0 -221
  459. package/dist/service/control-ui-query-service.js +0 -543
  460. package/dist/service/empathy-observer-manager.d.ts +0 -88
  461. package/dist/service/empathy-observer-manager.js +0 -414
  462. package/dist/service/evolution-query-service.d.ts +0 -155
  463. package/dist/service/evolution-query-service.js +0 -258
  464. package/dist/service/evolution-worker.d.ts +0 -101
  465. package/dist/service/evolution-worker.js +0 -975
  466. package/dist/service/health-query-service.d.ts +0 -170
  467. package/dist/service/health-query-service.js +0 -662
  468. package/dist/service/nocturnal-runtime.d.ts +0 -183
  469. package/dist/service/nocturnal-service.d.ts +0 -163
  470. package/dist/service/nocturnal-service.js +0 -787
  471. package/dist/service/nocturnal-target-selector.d.ts +0 -145
  472. package/dist/service/nocturnal-target-selector.js +0 -315
  473. package/dist/service/phase3-input-filter.d.ts +0 -73
  474. package/dist/service/phase3-input-filter.js +0 -172
  475. package/dist/service/runtime-summary-service.d.ts +0 -122
  476. package/dist/service/runtime-summary-service.js +0 -485
  477. package/dist/service/subagent-workflow/empathy-observer-workflow-manager.d.ts +0 -48
  478. package/dist/service/subagent-workflow/index.d.ts +0 -4
  479. package/dist/service/subagent-workflow/index.js +0 -3
  480. package/dist/service/subagent-workflow/runtime-direct-driver.d.ts +0 -77
  481. package/dist/service/subagent-workflow/runtime-direct-driver.js +0 -75
  482. package/dist/service/subagent-workflow/types.js +0 -11
  483. package/dist/service/subagent-workflow/workflow-store.d.ts +0 -26
  484. package/dist/service/subagent-workflow/workflow-store.js +0 -165
  485. package/dist/service/trajectory-service.d.ts +0 -2
  486. package/dist/service/trajectory-service.js +0 -15
  487. package/dist/tools/critique-prompt.d.ts +0 -14
  488. package/dist/tools/deep-reflect.d.ts +0 -39
  489. package/dist/tools/deep-reflect.js +0 -350
  490. package/dist/tools/model-index.d.ts +0 -9
  491. package/dist/types/event-types.d.ts +0 -306
  492. package/dist/types/event-types.js +0 -106
  493. package/dist/types/hygiene-types.d.ts +0 -20
  494. package/dist/types/hygiene-types.js +0 -12
  495. package/dist/types/runtime-summary.d.ts +0 -47
  496. package/dist/types/runtime-summary.js +0 -1
  497. package/dist/types.d.ts +0 -50
  498. package/dist/types.js +0 -22
  499. package/dist/utils/file-lock.d.ts +0 -71
  500. package/dist/utils/file-lock.js +0 -309
  501. package/dist/utils/glob-match.d.ts +0 -28
  502. package/dist/utils/hashing.d.ts +0 -9
  503. package/dist/utils/io.d.ts +0 -6
  504. package/dist/utils/io.js +0 -106
  505. package/dist/utils/nlp.d.ts +0 -9
  506. package/dist/utils/plugin-logger.d.ts +0 -39
  507. package/dist/utils/subagent-probe.d.ts +0 -34
  508. package/dist/utils/subagent-probe.js +0 -81
@@ -1,17 +1,35 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
+
4
+ export type RuleType = 'regex' | 'exact_match';
5
+
6
+ export interface PainRule {
7
+ type: RuleType;
8
+ pattern?: string; // For regex
9
+ phrases?: string[]; // For exact_match
10
+ severity: number;
11
+ hits: number;
12
+ status: 'active' | 'dormant' | 'archived';
13
+ }
14
+
15
+ export interface PainDictionaryData {
16
+ rules: Record<string, PainRule>;
17
+ }
18
+
19
+
3
20
  export const PAIN_PROTOCOL_TOKENS = [
4
21
  '[EVOLUTION_ACK]',
5
22
  'HEARTBEAT_OK',
6
23
  'HEARTBEAT_CHECK',
7
- ];
8
- export function shouldIgnorePainProtocolText(text) {
24
+ ] as const;
25
+
26
+ export function shouldIgnorePainProtocolText(text: string): boolean {
9
27
  const normalized = text.trim();
10
- if (!normalized)
11
- return false;
28
+ if (!normalized) return false;
12
29
  return PAIN_PROTOCOL_TOKENS.some((token) => normalized === token || normalized.startsWith(`${token} `) || normalized.includes(token));
13
30
  }
14
- const DEFAULT_RULES = {
31
+
32
+ const DEFAULT_RULES: Record<string, PainRule> = {
15
33
  'P_CONFUSION_ZH': {
16
34
  type: 'regex',
17
35
  pattern: '我(似乎|好像)(不确定|不太确定|不清楚|困惑)',
@@ -41,33 +59,33 @@ const DEFAULT_RULES = {
41
59
  status: 'active'
42
60
  }
43
61
  };
62
+
44
63
  export class PainDictionary {
45
- stateDir;
46
- data = { rules: {} };
47
- filePath;
48
- compiledRegex = new Map();
49
- constructor(stateDir) {
50
- this.stateDir = stateDir;
64
+ private data: PainDictionaryData = { rules: {} };
65
+ private filePath: string;
66
+ private compiledRegex: Map<string, RegExp> = new Map();
67
+
68
+ constructor(private stateDir: string) {
51
69
  this.filePath = path.join(stateDir, 'pain_dictionary.json');
52
70
  }
53
- load() {
71
+
72
+ load(): void {
54
73
  if (fs.existsSync(this.filePath)) {
55
74
  try {
56
75
  this.data = JSON.parse(fs.readFileSync(this.filePath, 'utf8'));
57
- }
58
- catch (e) {
76
+ } catch (e) {
59
77
  console.error('[PD] Failed to parse pain_dictionary.json, using defaults.');
60
78
  this.data = { rules: { ...DEFAULT_RULES } };
61
79
  }
62
- }
63
- else {
80
+ } else {
64
81
  this.data = { rules: { ...DEFAULT_RULES } };
65
82
  console.log(`[PD:Dictionary] Dictionary not found at ${this.filePath}, creating with default rules`);
66
83
  this.flush();
67
84
  }
68
85
  this.compile();
69
86
  }
70
- compile() {
87
+
88
+ private compile(): void {
71
89
  this.compiledRegex.clear();
72
90
  for (const [id, rule] of Object.entries(this.data.rules)) {
73
91
  if (rule.type === 'regex' && rule.pattern) {
@@ -75,16 +93,19 @@ export class PainDictionary {
75
93
  }
76
94
  }
77
95
  }
78
- getRule(id) {
96
+
97
+ getRule(id: string): PainRule | undefined {
79
98
  return this.data.rules[id];
80
99
  }
81
- getAllRules() {
100
+
101
+ getAllRules(): Record<string, PainRule> {
82
102
  return this.data.rules;
83
103
  }
104
+
84
105
  /**
85
106
  * Adds a new rule or updates an existing one.
86
107
  */
87
- addRule(id, rule) {
108
+ addRule(id: string, rule: Omit<PainRule, 'hits'>): void {
88
109
  this.data.rules[id] = {
89
110
  ...rule,
90
111
  hits: this.data.rules[id]?.hits || 0
@@ -94,28 +115,29 @@ export class PainDictionary {
94
115
  this.compiledRegex.set(id, new RegExp(rule.pattern, 'i'));
95
116
  }
96
117
  }
97
- match(text) {
98
- if (shouldIgnorePainProtocolText(text))
99
- return undefined;
100
- let bestMatch = undefined;
118
+
119
+ match(text: string): { ruleId: string; severity: number } | undefined {
120
+ if (shouldIgnorePainProtocolText(text)) return undefined;
121
+
122
+ let bestMatch: { ruleId: string; severity: number } | undefined = undefined;
123
+
101
124
  for (const [id, rule] of Object.entries(this.data.rules)) {
102
- if (rule.status !== 'active')
103
- continue;
125
+ if (rule.status !== 'active') continue;
126
+
104
127
  let matched = false;
105
128
  if (rule.type === 'regex') {
106
129
  const re = this.compiledRegex.get(id);
107
130
  if (re) {
108
131
  re.lastIndex = 0;
109
- if (re.test(text))
110
- matched = true;
132
+ if (re.test(text)) matched = true;
111
133
  }
112
- }
113
- else if (rule.type === 'exact_match' && rule.phrases) {
134
+ } else if (rule.type === 'exact_match' && rule.phrases) {
114
135
  const lowerText = text.toLowerCase();
115
136
  if (rule.phrases.some(p => lowerText.includes(p.toLowerCase()))) {
116
137
  matched = true;
117
138
  }
118
139
  }
140
+
119
141
  if (matched) {
120
142
  rule.hits++;
121
143
  if (!bestMatch || rule.severity > bestMatch.severity) {
@@ -125,18 +147,19 @@ export class PainDictionary {
125
147
  }
126
148
  return bestMatch;
127
149
  }
128
- flush() {
150
+
151
+ flush(): void {
129
152
  try {
130
153
  if (!fs.existsSync(this.stateDir)) {
131
154
  fs.mkdirSync(this.stateDir, { recursive: true });
132
155
  }
133
156
  fs.writeFileSync(this.filePath, JSON.stringify(this.data, null, 2), 'utf8');
134
- }
135
- catch (e) {
157
+ } catch (e) {
136
158
  console.error('[PD] Failed to flush pain_dictionary.json:', e);
137
159
  }
138
160
  }
139
- getStats() {
161
+
162
+ getStats(): { totalRules: number; totalHits: number } {
140
163
  let totalHits = 0;
141
164
  for (const rule of Object.values(this.data.rules)) {
142
165
  totalHits += rule.hits || 0;
@@ -0,0 +1,327 @@
1
+ /**
2
+ * Empathy Keyword Matcher
3
+ *
4
+ * Fast keyword-based empathy detection that replaces the previous
5
+ * LLM subagent-per-turn approach.
6
+ *
7
+ * Flow:
8
+ * User message → keyword matching → weighted score → GFI penalty
9
+ *
10
+ * The keyword store is periodically optimized by a subagent that analyzes
11
+ * recent conversations and updates keyword weights, discovers new terms,
12
+ * and removes false positives.
13
+ */
14
+
15
+ import * as fs from 'fs';
16
+ import * as path from 'path';
17
+ import {
18
+ EmpathyKeywordStore,
19
+ EmpathyKeywordEntry,
20
+ EmpathyKeywordStats,
21
+ EmpathyMatchResult,
22
+ EmpathyKeywordConfig,
23
+ SeedKeywordEntry,
24
+ EMPATHY_SEED_KEYWORDS,
25
+ DEFAULT_EMPATHY_KEYWORD_CONFIG,
26
+ scoreToSeverity,
27
+ } from './empathy-types.js';
28
+
29
+ const KEYWORD_STORE_FILE = 'empathy_keywords.json';
30
+
31
+ // =========================================================================
32
+ // Store Management
33
+ // =========================================================================
34
+
35
+ /**
36
+ * Creates a default keyword store from seed keywords.
37
+ * Supports both Chinese and English keywords.
38
+ */
39
+ export function createDefaultKeywordStore(language: 'zh' | 'en' = 'zh'): EmpathyKeywordStore {
40
+ const now = new Date().toISOString();
41
+ const terms: Record<string, EmpathyKeywordEntry> = {};
42
+
43
+ // Include all seed keywords (both zh and en)
44
+ for (const seed of EMPATHY_SEED_KEYWORDS) {
45
+ // For Chinese language, include all keywords
46
+ // For English language, include only English keywords
47
+ const isChinese = /[\u4e00-\u9fa5]/.test(seed.term);
48
+ if (language === 'zh' || !isChinese) {
49
+ terms[seed.term] = {
50
+ weight: seed.weight,
51
+ source: 'seed',
52
+ hitCount: 0,
53
+ falsePositiveRate: seed.initialFalsePositiveRate ?? 0.15, // Differentiated FPR (Finding #6)
54
+ };
55
+ }
56
+ }
57
+
58
+ const stats: EmpathyKeywordStats = {
59
+ totalHits: 0,
60
+ totalFalsePositives: 0,
61
+ optimizationCount: 0,
62
+ };
63
+
64
+ return {
65
+ version: 1,
66
+ lastUpdated: now,
67
+ lastOptimizedAt: now,
68
+ terms,
69
+ stats,
70
+ };
71
+ }
72
+
73
+ /**
74
+ * Loads the keyword store from disk, or creates a default one if not found.
75
+ * Respects the configured language setting.
76
+ */
77
+ export function loadKeywordStore(stateDir: string, language?: 'zh' | 'en'): EmpathyKeywordStore {
78
+ const filePath = path.join(stateDir, KEYWORD_STORE_FILE);
79
+
80
+ try {
81
+ if (!fs.existsSync(filePath)) {
82
+ const store = createDefaultKeywordStore(language);
83
+ saveKeywordStore(stateDir, store);
84
+ return store;
85
+ }
86
+
87
+ const raw = fs.readFileSync(filePath, 'utf8');
88
+ const parsed = JSON.parse(raw);
89
+
90
+ // Validate structure
91
+ if (!parsed.terms || !parsed.stats || !parsed.version) {
92
+ console.warn('[PD:Empathy] Invalid keyword store format, creating default');
93
+ const store = createDefaultKeywordStore(language);
94
+ saveKeywordStore(stateDir, store);
95
+ return store;
96
+ }
97
+
98
+ return parsed as EmpathyKeywordStore;
99
+ } catch (e) {
100
+ console.warn(`[PD:Empathy] Failed to load keyword store: ${e}`);
101
+ const store = createDefaultKeywordStore(language);
102
+ saveKeywordStore(stateDir, store);
103
+ return store;
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Saves the keyword store to disk.
109
+ */
110
+ export function saveKeywordStore(stateDir: string, store: EmpathyKeywordStore): void {
111
+ const filePath = path.join(stateDir, KEYWORD_STORE_FILE);
112
+ const dir = path.dirname(filePath);
113
+
114
+ if (!fs.existsSync(dir)) {
115
+ fs.mkdirSync(dir, { recursive: true });
116
+ }
117
+
118
+ store.lastUpdated = new Date().toISOString();
119
+ fs.writeFileSync(filePath, JSON.stringify(store, null, 2), 'utf8');
120
+ }
121
+
122
+ // =========================================================================
123
+ // Keyword Matching
124
+ // =========================================================================
125
+
126
+ /**
127
+ * Matches text against the keyword store and returns a structured result.
128
+ *
129
+ * This is the core function that replaces the previous LLM-based empathy detection.
130
+ * It runs in < 1ms for typical keyword stores (50-200 terms).
131
+ */
132
+ export function matchEmpathyKeywords(
133
+ text: string,
134
+ store: EmpathyKeywordStore,
135
+ config: EmpathyKeywordConfig = DEFAULT_EMPATHY_KEYWORD_CONFIG,
136
+ ): EmpathyMatchResult {
137
+ if (!text || typeof text !== 'string' || text.trim().length === 0) {
138
+ return {
139
+ matched: false,
140
+ score: 0,
141
+ matchedTerms: [],
142
+ severity: 'mild',
143
+ confidence: 0,
144
+ };
145
+ }
146
+
147
+ const lowerText = text.toLowerCase();
148
+ let totalScore = 0;
149
+ const matchedTerms: string[] = [];
150
+
151
+ for (const [term, entry] of Object.entries(store.terms)) {
152
+ if (lowerText.includes(term.toLowerCase())) {
153
+ // Weight adjusted by false positive rate
154
+ const adjustedWeight = entry.weight * (1 - entry.falsePositiveRate);
155
+ totalScore += adjustedWeight;
156
+ matchedTerms.push(term);
157
+
158
+ // Update hit stats
159
+ entry.hitCount++;
160
+ entry.lastHitAt = new Date().toISOString();
161
+ }
162
+ }
163
+
164
+ // Cap score at 1.0
165
+ const cappedScore = Math.min(1, totalScore);
166
+
167
+ // Only consider matched if score exceeds threshold
168
+ const isMatched = cappedScore >= config.matchThreshold && matchedTerms.length > 0;
169
+
170
+ // Limit matched terms for performance
171
+ const limitedTerms = matchedTerms.slice(0, config.maxTermsPerMessage);
172
+
173
+ // Calculate confidence based on:
174
+ // - Number of matched terms (more terms = higher confidence)
175
+ // - Score relative to threshold (higher score = higher confidence)
176
+ const termConfidence = Math.min(1, limitedTerms.length / 3);
177
+ const scoreConfidence = Math.min(1, cappedScore / 0.8);
178
+ const confidence = Math.max(termConfidence, scoreConfidence);
179
+
180
+ const result: EmpathyMatchResult = {
181
+ matched: isMatched,
182
+ score: cappedScore,
183
+ matchedTerms: limitedTerms,
184
+ severity: scoreToSeverity(cappedScore),
185
+ confidence,
186
+ };
187
+
188
+ // Update store stats
189
+ if (isMatched) {
190
+ store.stats.totalHits += limitedTerms.length;
191
+ }
192
+
193
+ return result;
194
+ }
195
+
196
+ // =========================================================================
197
+ // Keyword Store Updates
198
+ // =========================================================================
199
+
200
+ /**
201
+ * Applies keyword updates from subagent optimization.
202
+ *
203
+ * This is called when the empathy optimizer subagent completes its analysis
204
+ * and returns suggested updates to the keyword store.
205
+ */
206
+ export function applyKeywordUpdates(
207
+ store: EmpathyKeywordStore,
208
+ updates: Record<string, {
209
+ action: 'add' | 'update' | 'remove';
210
+ weight?: number;
211
+ falsePositiveRate?: number;
212
+ examples?: string[];
213
+ reasoning?: string;
214
+ }>,
215
+ ): { added: number; updated: number; removed: number } {
216
+ let added = 0;
217
+ let updated = 0;
218
+ let removed = 0;
219
+ const now = new Date().toISOString();
220
+
221
+ for (const [term, update] of Object.entries(updates)) {
222
+ switch (update.action) {
223
+ case 'add':
224
+ if (!store.terms[term]) {
225
+ store.terms[term] = {
226
+ weight: update.weight ?? 0.5,
227
+ source: 'llm_discovered',
228
+ hitCount: 0,
229
+ falsePositiveRate: update.falsePositiveRate ?? 0.2,
230
+ examples: update.examples,
231
+ discoveredAt: now,
232
+ };
233
+ added++;
234
+ }
235
+ break;
236
+
237
+ case 'update':
238
+ if (store.terms[term]) {
239
+ if (update.weight !== undefined) {
240
+ store.terms[term].weight = update.weight;
241
+ }
242
+ if (update.falsePositiveRate !== undefined) {
243
+ store.terms[term].falsePositiveRate = update.falsePositiveRate;
244
+ }
245
+ if (update.examples) {
246
+ store.terms[term].examples = update.examples;
247
+ }
248
+ updated++;
249
+ }
250
+ break;
251
+
252
+ case 'remove':
253
+ if (store.terms[term]) {
254
+ delete store.terms[term];
255
+ removed++;
256
+ }
257
+ break;
258
+ }
259
+ }
260
+
261
+ store.lastOptimizedAt = now;
262
+ store.stats.optimizationCount++;
263
+
264
+ return { added, updated, removed };
265
+ }
266
+
267
+ // =========================================================================
268
+ // Optimization Trigger
269
+ // =========================================================================
270
+
271
+ /**
272
+ * Checks if it's time to trigger subagent optimization.
273
+ *
274
+ * Returns true if either:
275
+ * - The number of turns since last optimization exceeds the interval
276
+ * - The time since last optimization exceeds the interval
277
+ */
278
+ export function shouldTriggerOptimization(
279
+ store: EmpathyKeywordStore,
280
+ turnsSinceLastOptimization: number,
281
+ config: EmpathyKeywordConfig = DEFAULT_EMPATHY_KEYWORD_CONFIG,
282
+ ): boolean {
283
+ const turnsExceeded = turnsSinceLastOptimization >= config.optimizationIntervalTurns;
284
+
285
+ const lastOpt = new Date(store.lastOptimizedAt).getTime();
286
+ const now = Date.now();
287
+ const timeExceeded = (now - lastOpt) >= config.optimizationIntervalMs;
288
+
289
+ return turnsExceeded || timeExceeded;
290
+ }
291
+
292
+ // =========================================================================
293
+ // Store Inspection
294
+ // =========================================================================
295
+
296
+ /**
297
+ * Returns a summary of the keyword store for debugging/monitoring.
298
+ */
299
+ export function getKeywordStoreSummary(store: EmpathyKeywordStore): {
300
+ totalTerms: number;
301
+ seedTerms: number;
302
+ discoveredTerms: number;
303
+ topHitTerms: { term: string; hitCount: number; weight: number }[];
304
+ highFalsePositiveTerms: { term: string; falsePositiveRate: number }[];
305
+ } {
306
+ const terms = Object.entries(store.terms);
307
+ const seedTerms = terms.filter(([, e]) => e.source === 'seed');
308
+ const discoveredTerms = terms.filter(([, e]) => e.source === 'llm_discovered');
309
+
310
+ const topHitTerms = terms
311
+ .map(([term, entry]) => ({ term, hitCount: entry.hitCount, weight: entry.weight }))
312
+ .sort((a, b) => b.hitCount - a.hitCount)
313
+ .slice(0, 10);
314
+
315
+ const highFalsePositiveTerms = terms
316
+ .filter(([, e]) => e.falsePositiveRate > 0.3)
317
+ .map(([term, entry]) => ({ term, falsePositiveRate: entry.falsePositiveRate }))
318
+ .sort((a, b) => b.falsePositiveRate - a.falsePositiveRate);
319
+
320
+ return {
321
+ totalTerms: terms.length,
322
+ seedTerms: seedTerms.length,
323
+ discoveredTerms: discoveredTerms.length,
324
+ topHitTerms,
325
+ highFalsePositiveTerms,
326
+ };
327
+ }