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.
Files changed (460) 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 +6 -1
  10. package/package.json +13 -15
  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} +185 -63
  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} +166 -139
  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} +263 -36
  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/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +603 -0
  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/src/service/subagent-workflow/types.ts +378 -0
  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/zh/skills/pd-diagnostician/SKILL.md +70 -1
  138. package/templates/pain_settings.json +2 -1
  139. package/tests/README.md +120 -0
  140. package/tests/build-artifacts.test.ts +111 -0
  141. package/tests/commands/evolution-status.test.ts +222 -0
  142. package/tests/commands/evolver.test.ts +22 -0
  143. package/tests/commands/export.test.ts +78 -0
  144. package/tests/commands/nocturnal-review.test.ts +448 -0
  145. package/tests/commands/nocturnal-train.test.ts +97 -0
  146. package/tests/commands/pain.test.ts +108 -0
  147. package/tests/commands/samples.test.ts +65 -0
  148. package/tests/commands/strategy.test.ts +34 -0
  149. package/tests/commands/thinking-os.test.ts +88 -0
  150. package/tests/core/adaptive-thresholds.test.ts +261 -0
  151. package/tests/core/config-service.test.ts +89 -0
  152. package/tests/core/config.test.ts +90 -0
  153. package/tests/core/control-ui-db.test.ts +75 -0
  154. package/tests/core/core-template-guidance.test.ts +21 -0
  155. package/tests/core/detection-funnel.test.ts +63 -0
  156. package/tests/core/detection-service.test.ts +50 -0
  157. package/tests/core/dictionary-service.test.ts +116 -0
  158. package/tests/core/dictionary.test.ts +168 -0
  159. package/tests/core/empathy-keyword-matcher.test.ts +209 -0
  160. package/tests/core/event-log.test.ts +181 -0
  161. package/tests/core/evolution-e2e.test.ts +58 -0
  162. package/tests/core/evolution-engine-gate-integration.test.ts +543 -0
  163. package/tests/core/evolution-engine.test.ts +562 -0
  164. package/tests/core/evolution-logger.test.ts +148 -0
  165. package/tests/core/evolution-migration.test.ts +50 -0
  166. package/tests/core/evolution-paths.test.ts +21 -0
  167. package/tests/core/evolution-reducer.detector-metadata.test.ts +602 -0
  168. package/tests/core/evolution-reducer.test.ts +180 -0
  169. package/tests/core/evolution-types-loop.test.ts +48 -0
  170. package/tests/core/evolution-user-stories.e2e.test.ts +249 -0
  171. package/tests/core/external-training-contract.test.ts +463 -0
  172. package/tests/core/focus-history.test.ts +682 -0
  173. package/tests/core/init-flatten.test.ts +69 -0
  174. package/tests/core/init-refactor.test.ts +87 -0
  175. package/tests/core/init-v1.3.test.ts +46 -0
  176. package/tests/core/init.test.ts +190 -0
  177. package/tests/core/local-worker-routing.test.ts +757 -0
  178. package/tests/core/migration.test.ts +84 -0
  179. package/tests/core/model-deployment-registry.test.ts +845 -0
  180. package/tests/core/model-training-registry.test.ts +889 -0
  181. package/tests/core/nocturnal-arbiter.test.ts +494 -0
  182. package/tests/core/nocturnal-candidate-scoring.test.ts +400 -0
  183. package/tests/core/nocturnal-compliance.test.ts +646 -0
  184. package/tests/core/nocturnal-dataset.test.ts +892 -0
  185. package/tests/core/nocturnal-executability.test.ts +357 -0
  186. package/tests/core/nocturnal-export.test.ts +462 -0
  187. package/tests/core/nocturnal-reviewed-subset-comparison.test.ts +428 -0
  188. package/tests/core/nocturnal-trajectory-extractor.test.ts +634 -0
  189. package/tests/core/nocturnal-trinity.test.ts +953 -0
  190. package/tests/core/pain.test.ts +33 -0
  191. package/tests/core/path-resolver.test.ts +57 -0
  192. package/tests/core/paths-refactor.test.ts +42 -0
  193. package/tests/core/phase7-rollout-integration.test.ts +477 -0
  194. package/tests/core/principle-training-state.test.ts +712 -0
  195. package/tests/core/profile.test.ts +56 -0
  196. package/tests/core/promotion-gate.test.ts +556 -0
  197. package/tests/core/risk-calculator.test.ts +168 -0
  198. package/tests/core/session-tracker.test.ts +191 -0
  199. package/tests/core/training-program.test.ts +472 -0
  200. package/tests/core/trajectory.test.ts +265 -0
  201. package/tests/core/workspace-context-factory.test.ts +18 -0
  202. package/tests/core/workspace-context.test.ts +134 -0
  203. package/tests/fixtures/nocturnal-reviewed-subset.json +183 -0
  204. package/tests/fixtures/production-compatibility.test.ts +147 -0
  205. package/tests/fixtures/production-mock-generator.ts +282 -0
  206. package/tests/hooks/bash-risk-integration.test.ts +137 -0
  207. package/tests/hooks/bash-risk.test.ts +81 -0
  208. package/tests/hooks/edit-verification.test.ts +678 -0
  209. package/tests/hooks/gate-edit-verification-p1.test.ts +632 -0
  210. package/tests/hooks/gate-edit-verification.test.ts +435 -0
  211. package/tests/hooks/gate-pipeline-integration.test.ts +404 -0
  212. package/tests/hooks/gate.test.ts +271 -0
  213. package/tests/hooks/gfi-gate-unit.test.ts +422 -0
  214. package/tests/hooks/gfi-gate.test.ts +669 -0
  215. package/tests/hooks/lifecycle.test.ts +248 -0
  216. package/tests/hooks/llm.test.ts +308 -0
  217. package/tests/hooks/message-sanitize.test.ts +36 -0
  218. package/tests/hooks/pain.test.ts +141 -0
  219. package/tests/hooks/progressive-trust-gate.test.ts +277 -0
  220. package/tests/hooks/prompt.test.ts +1411 -0
  221. package/tests/hooks/subagent.test.ts +467 -0
  222. package/tests/hooks/thinking-gate.test.ts +313 -0
  223. package/tests/http/principles-console-route.test.ts +140 -0
  224. package/tests/hygiene-tracker.test.ts +77 -0
  225. package/tests/index.integration.test.ts +179 -0
  226. package/tests/index.shadow-routing.integration.test.ts +140 -0
  227. package/tests/index.test.ts +9 -0
  228. package/tests/integration/empathy-workflow-integration.test.ts +627 -0
  229. package/tests/service/control-ui-query-service.test.ts +121 -0
  230. package/tests/service/empathy-observer-workflow-manager.test.ts +176 -0
  231. package/tests/service/evolution-worker.test.ts +585 -0
  232. package/tests/service/nocturnal-runtime.test.ts +470 -0
  233. package/tests/service/nocturnal-service.test.ts +577 -0
  234. package/tests/service/nocturnal-target-selector.test.ts +615 -0
  235. package/tests/service/nocturnal-workflow-manager.test.ts +439 -0
  236. package/tests/service/phase3-input-filter.test.ts +289 -0
  237. package/tests/service/runtime-summary-service.test.ts +919 -0
  238. package/tests/task-compliance.test.ts +166 -0
  239. package/tests/test-utils.ts +48 -0
  240. package/tests/tools/critique-prompt.test.ts +260 -0
  241. package/tests/tools/deep-reflect.test.ts +232 -0
  242. package/tests/tools/model-index.test.ts +246 -0
  243. package/tests/ui/app.test.tsx +114 -0
  244. package/tests/utils/file-lock.test.ts +407 -0
  245. package/tests/utils/hashing.test.ts +32 -0
  246. package/tests/utils/io.test.ts +39 -0
  247. package/tests/utils/nlp.test.ts +53 -0
  248. package/tests/utils/plugin-logger.test.ts +156 -0
  249. package/tsconfig.json +16 -0
  250. package/tsconfig.tsbuildinfo +1 -0
  251. package/ui/src/App.tsx +45 -0
  252. package/ui/src/api.ts +216 -0
  253. package/ui/src/charts.tsx +586 -0
  254. package/ui/src/components/ErrorState.tsx +6 -0
  255. package/ui/src/components/Loading.tsx +13 -0
  256. package/ui/src/components/ProtectedRoute.tsx +12 -0
  257. package/ui/src/components/Shell.tsx +91 -0
  258. package/ui/src/components/WorkspaceConfig.tsx +146 -0
  259. package/ui/src/components/index.ts +5 -0
  260. package/ui/src/context/auth.tsx +80 -0
  261. package/ui/src/context/theme.tsx +66 -0
  262. package/ui/src/hooks/useAutoRefresh.ts +39 -0
  263. package/ui/src/i18n/ui.ts +363 -0
  264. package/ui/src/main.tsx +16 -0
  265. package/ui/src/pages/EvolutionPage.tsx +352 -0
  266. package/ui/src/pages/FeedbackPage.tsx +140 -0
  267. package/ui/src/pages/GateMonitorPage.tsx +136 -0
  268. package/ui/src/pages/LoginPage.tsx +88 -0
  269. package/ui/src/pages/OverviewPage.tsx +238 -0
  270. package/ui/src/pages/SamplesPage.tsx +174 -0
  271. package/ui/src/pages/ThinkingModelsPage.tsx +127 -0
  272. package/ui/src/styles.css +1661 -0
  273. package/ui/src/types.ts +368 -0
  274. package/ui/src/utils/format.ts +15 -0
  275. package/vitest.config.ts +23 -0
  276. package/dist/commands/capabilities.d.ts +0 -3
  277. package/dist/commands/capabilities.js +0 -73
  278. package/dist/commands/context.d.ts +0 -5
  279. package/dist/commands/evolution-status.d.ts +0 -4
  280. package/dist/commands/evolution-status.js +0 -117
  281. package/dist/commands/evolver.d.ts +0 -9
  282. package/dist/commands/evolver.js +0 -26
  283. package/dist/commands/export.d.ts +0 -2
  284. package/dist/commands/export.js +0 -98
  285. package/dist/commands/focus.d.ts +0 -14
  286. package/dist/commands/focus.js +0 -457
  287. package/dist/commands/nocturnal-review.d.ts +0 -24
  288. package/dist/commands/nocturnal-review.js +0 -265
  289. package/dist/commands/nocturnal-rollout.d.ts +0 -27
  290. package/dist/commands/nocturnal-rollout.js +0 -671
  291. package/dist/commands/nocturnal-train.d.ts +0 -25
  292. package/dist/commands/nocturnal-train.js +0 -919
  293. package/dist/commands/pain.d.ts +0 -5
  294. package/dist/commands/principle-rollback.d.ts +0 -4
  295. package/dist/commands/principle-rollback.js +0 -22
  296. package/dist/commands/rollback.d.ts +0 -19
  297. package/dist/commands/samples.d.ts +0 -2
  298. package/dist/commands/samples.js +0 -55
  299. package/dist/commands/strategy.d.ts +0 -3
  300. package/dist/commands/strategy.js +0 -29
  301. package/dist/commands/thinking-os.d.ts +0 -2
  302. package/dist/config/defaults/runtime.d.ts +0 -40
  303. package/dist/config/errors.d.ts +0 -84
  304. package/dist/config/errors.js +0 -94
  305. package/dist/config/index.js +0 -7
  306. package/dist/constants/diagnostician.d.ts +0 -12
  307. package/dist/constants/diagnostician.js +0 -56
  308. package/dist/constants/tools.d.ts +0 -17
  309. package/dist/constants/tools.js +0 -54
  310. package/dist/core/adaptive-thresholds.d.ts +0 -186
  311. package/dist/core/adaptive-thresholds.js +0 -300
  312. package/dist/core/config-service.d.ts +0 -15
  313. package/dist/core/config.d.ts +0 -127
  314. package/dist/core/control-ui-db.d.ts +0 -95
  315. package/dist/core/control-ui-db.js +0 -292
  316. package/dist/core/detection-funnel.d.ts +0 -33
  317. package/dist/core/detection-service.d.ts +0 -15
  318. package/dist/core/dictionary-service.d.ts +0 -15
  319. package/dist/core/dictionary.d.ts +0 -38
  320. package/dist/core/event-log.d.ts +0 -82
  321. package/dist/core/event-log.js +0 -463
  322. package/dist/core/evolution-engine.d.ts +0 -118
  323. package/dist/core/evolution-engine.js +0 -464
  324. package/dist/core/evolution-logger.d.ts +0 -137
  325. package/dist/core/evolution-logger.js +0 -256
  326. package/dist/core/evolution-migration.d.ts +0 -5
  327. package/dist/core/evolution-migration.js +0 -65
  328. package/dist/core/evolution-reducer.d.ts +0 -98
  329. package/dist/core/evolution-reducer.js +0 -465
  330. package/dist/core/evolution-types.d.ts +0 -287
  331. package/dist/core/evolution-types.js +0 -78
  332. package/dist/core/external-training-contract.d.ts +0 -276
  333. package/dist/core/external-training-contract.js +0 -269
  334. package/dist/core/focus-history.d.ts +0 -210
  335. package/dist/core/focus-history.js +0 -1185
  336. package/dist/core/hygiene/tracker.d.ts +0 -22
  337. package/dist/core/hygiene/tracker.js +0 -106
  338. package/dist/core/init.d.ts +0 -12
  339. package/dist/core/local-worker-routing.d.ts +0 -175
  340. package/dist/core/local-worker-routing.js +0 -525
  341. package/dist/core/migration.d.ts +0 -6
  342. package/dist/core/model-deployment-registry.d.ts +0 -218
  343. package/dist/core/model-deployment-registry.js +0 -503
  344. package/dist/core/model-training-registry.d.ts +0 -295
  345. package/dist/core/model-training-registry.js +0 -475
  346. package/dist/core/nocturnal-arbiter.d.ts +0 -159
  347. package/dist/core/nocturnal-arbiter.js +0 -534
  348. package/dist/core/nocturnal-candidate-scoring.d.ts +0 -137
  349. package/dist/core/nocturnal-candidate-scoring.js +0 -266
  350. package/dist/core/nocturnal-compliance.d.ts +0 -175
  351. package/dist/core/nocturnal-compliance.js +0 -824
  352. package/dist/core/nocturnal-dataset.d.ts +0 -224
  353. package/dist/core/nocturnal-dataset.js +0 -443
  354. package/dist/core/nocturnal-executability.d.ts +0 -85
  355. package/dist/core/nocturnal-executability.js +0 -331
  356. package/dist/core/nocturnal-export.d.ts +0 -124
  357. package/dist/core/nocturnal-export.js +0 -275
  358. package/dist/core/nocturnal-paths.d.ts +0 -124
  359. package/dist/core/nocturnal-trajectory-extractor.d.ts +0 -242
  360. package/dist/core/nocturnal-trajectory-extractor.js +0 -307
  361. package/dist/core/nocturnal-trinity.d.ts +0 -311
  362. package/dist/core/nocturnal-trinity.js +0 -880
  363. package/dist/core/pain.d.ts +0 -4
  364. package/dist/core/pain.js +0 -70
  365. package/dist/core/path-resolver.d.ts +0 -46
  366. package/dist/core/paths.d.ts +0 -65
  367. package/dist/core/principle-training-state.d.ts +0 -121
  368. package/dist/core/principle-training-state.js +0 -321
  369. package/dist/core/profile.d.ts +0 -62
  370. package/dist/core/profile.js +0 -210
  371. package/dist/core/promotion-gate.d.ts +0 -238
  372. package/dist/core/promotion-gate.js +0 -529
  373. package/dist/core/risk-calculator.d.ts +0 -22
  374. package/dist/core/session-tracker.d.ts +0 -99
  375. package/dist/core/shadow-observation-registry.d.ts +0 -217
  376. package/dist/core/shadow-observation-registry.js +0 -308
  377. package/dist/core/system-logger.d.ts +0 -8
  378. package/dist/core/thinking-models.d.ts +0 -38
  379. package/dist/core/thinking-models.js +0 -170
  380. package/dist/core/training-program.d.ts +0 -233
  381. package/dist/core/training-program.js +0 -433
  382. package/dist/core/trajectory.d.ts +0 -411
  383. package/dist/core/trajectory.js +0 -1307
  384. package/dist/core/workspace-context.d.ts +0 -71
  385. package/dist/hooks/bash-risk.d.ts +0 -57
  386. package/dist/hooks/bash-risk.js +0 -137
  387. package/dist/hooks/edit-verification.d.ts +0 -62
  388. package/dist/hooks/edit-verification.js +0 -256
  389. package/dist/hooks/gate-block-helper.d.ts +0 -44
  390. package/dist/hooks/gate-block-helper.js +0 -119
  391. package/dist/hooks/gate.d.ts +0 -24
  392. package/dist/hooks/gate.js +0 -173
  393. package/dist/hooks/gfi-gate.d.ts +0 -40
  394. package/dist/hooks/gfi-gate.js +0 -113
  395. package/dist/hooks/lifecycle.d.ts +0 -5
  396. package/dist/hooks/lifecycle.js +0 -284
  397. package/dist/hooks/llm.d.ts +0 -12
  398. package/dist/hooks/message-sanitize.d.ts +0 -3
  399. package/dist/hooks/message-sanitize.js +0 -37
  400. package/dist/hooks/pain.d.ts +0 -5
  401. package/dist/hooks/pain.js +0 -301
  402. package/dist/hooks/progressive-trust-gate.d.ts +0 -51
  403. package/dist/hooks/progressive-trust-gate.js +0 -89
  404. package/dist/hooks/prompt.d.ts +0 -47
  405. package/dist/hooks/prompt.js +0 -884
  406. package/dist/hooks/subagent.d.ts +0 -10
  407. package/dist/hooks/subagent.js +0 -387
  408. package/dist/hooks/thinking-checkpoint.d.ts +0 -37
  409. package/dist/hooks/thinking-checkpoint.js +0 -51
  410. package/dist/hooks/trajectory-collector.d.ts +0 -32
  411. package/dist/hooks/trajectory-collector.js +0 -256
  412. package/dist/http/principles-console-route.d.ts +0 -9
  413. package/dist/http/principles-console-route.js +0 -567
  414. package/dist/i18n/commands.d.ts +0 -26
  415. package/dist/i18n/commands.js +0 -116
  416. package/dist/index.d.ts +0 -7
  417. package/dist/index.js +0 -581
  418. package/dist/service/central-database.d.ts +0 -104
  419. package/dist/service/central-database.js +0 -649
  420. package/dist/service/control-ui-query-service.d.ts +0 -221
  421. package/dist/service/control-ui-query-service.js +0 -543
  422. package/dist/service/empathy-observer-manager.d.ts +0 -52
  423. package/dist/service/empathy-observer-manager.js +0 -229
  424. package/dist/service/evolution-query-service.d.ts +0 -155
  425. package/dist/service/evolution-query-service.js +0 -258
  426. package/dist/service/evolution-worker.d.ts +0 -101
  427. package/dist/service/evolution-worker.js +0 -974
  428. package/dist/service/nocturnal-runtime.d.ts +0 -183
  429. package/dist/service/nocturnal-service.d.ts +0 -163
  430. package/dist/service/nocturnal-service.js +0 -787
  431. package/dist/service/nocturnal-target-selector.d.ts +0 -145
  432. package/dist/service/nocturnal-target-selector.js +0 -315
  433. package/dist/service/phase3-input-filter.d.ts +0 -73
  434. package/dist/service/phase3-input-filter.js +0 -172
  435. package/dist/service/runtime-summary-service.d.ts +0 -122
  436. package/dist/service/runtime-summary-service.js +0 -485
  437. package/dist/service/trajectory-service.d.ts +0 -2
  438. package/dist/service/trajectory-service.js +0 -15
  439. package/dist/tools/critique-prompt.d.ts +0 -14
  440. package/dist/tools/deep-reflect.d.ts +0 -39
  441. package/dist/tools/deep-reflect.js +0 -350
  442. package/dist/tools/model-index.d.ts +0 -9
  443. package/dist/types/event-types.d.ts +0 -306
  444. package/dist/types/event-types.js +0 -106
  445. package/dist/types/hygiene-types.d.ts +0 -20
  446. package/dist/types/hygiene-types.js +0 -12
  447. package/dist/types/runtime-summary.d.ts +0 -47
  448. package/dist/types/runtime-summary.js +0 -1
  449. package/dist/types.d.ts +0 -50
  450. package/dist/types.js +0 -22
  451. package/dist/utils/file-lock.d.ts +0 -71
  452. package/dist/utils/file-lock.js +0 -309
  453. package/dist/utils/glob-match.d.ts +0 -28
  454. package/dist/utils/hashing.d.ts +0 -9
  455. package/dist/utils/io.d.ts +0 -6
  456. package/dist/utils/io.js +0 -106
  457. package/dist/utils/nlp.d.ts +0 -9
  458. package/dist/utils/plugin-logger.d.ts +0 -39
  459. package/dist/utils/subagent-probe.d.ts +0 -34
  460. package/dist/utils/subagent-probe.js +0 -81
@@ -0,0 +1,65 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
2
+ import { handleSamplesCommand } from '../../src/commands/samples.js';
3
+ import { WorkspaceContext } from '../../src/core/workspace-context.js';
4
+
5
+ vi.mock('../../src/core/workspace-context.js');
6
+
7
+ describe('Samples Command', () => {
8
+ const mockTrajectory = {
9
+ listCorrectionSamples: vi.fn().mockReturnValue([
10
+ { sampleId: 'sample-1', sessionId: 's1', reviewStatus: 'pending', qualityScore: 88 },
11
+ ]),
12
+ reviewCorrectionSample: vi.fn().mockReturnValue({ sampleId: 'sample-1', reviewStatus: 'approved' }),
13
+ };
14
+
15
+ beforeEach(() => {
16
+ vi.clearAllMocks();
17
+ vi.mocked(WorkspaceContext.fromHookContext).mockReturnValue({
18
+ trajectory: mockTrajectory,
19
+ } as any);
20
+ });
21
+
22
+ it('lists pending samples by default', () => {
23
+ const result = handleSamplesCommand({
24
+ args: '',
25
+ config: { workspaceDir: '/mock/workspace', language: 'en' },
26
+ } as any);
27
+
28
+ expect(mockTrajectory.listCorrectionSamples).toHaveBeenCalledWith('pending');
29
+ expect(result.text).toContain('sample-1');
30
+ });
31
+
32
+ it('approves a pending sample', () => {
33
+ const result = handleSamplesCommand({
34
+ args: 'review approve sample-1 useful-fix',
35
+ config: { workspaceDir: '/mock/workspace', language: 'en' },
36
+ } as any);
37
+
38
+ expect(mockTrajectory.reviewCorrectionSample).toHaveBeenCalledWith('sample-1', 'approved', 'useful-fix');
39
+ expect(result.text).toContain('sample-1');
40
+ expect(result.text).toContain('approved');
41
+ });
42
+
43
+ it('rejects invalid review decisions before writing', () => {
44
+ const result = handleSamplesCommand({
45
+ args: 'review maybe sample-1',
46
+ config: { workspaceDir: '/mock/workspace', language: 'en' },
47
+ } as any);
48
+
49
+ expect(mockTrajectory.reviewCorrectionSample).not.toHaveBeenCalled();
50
+ expect(result.text).toContain('Invalid review action');
51
+ });
52
+
53
+ it('returns a user-facing error when the sample is missing', () => {
54
+ mockTrajectory.reviewCorrectionSample.mockImplementation(() => {
55
+ throw new Error('not found');
56
+ });
57
+
58
+ const result = handleSamplesCommand({
59
+ args: 'review reject sample-404',
60
+ config: { workspaceDir: '/mock/workspace', language: 'en' },
61
+ } as any);
62
+
63
+ expect(result.text).toContain('Failed to review sample');
64
+ });
65
+ });
@@ -0,0 +1,34 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { handleInitStrategy, handleManageOkr } from '../../src/commands/strategy';
3
+
4
+ describe('Slash Commands Hook', () => {
5
+ it('should handle /init-strategy command', () => {
6
+ const mockCtx = {
7
+ workspaceDir: '/mock/workspace',
8
+ commandBody: '/init-strategy',
9
+ channel: 'cli',
10
+ isAuthorizedSender: true,
11
+ config: {} as any
12
+ };
13
+
14
+ const result = handleInitStrategy(mockCtx as any);
15
+
16
+ expect(result).toBeDefined();
17
+ expect(result.text).toContain('Strategy Initialization');
18
+ });
19
+
20
+ it('should handle /manage-okr command', () => {
21
+ const mockCtx = {
22
+ workspaceDir: '/mock/workspace',
23
+ commandBody: '/manage-okr',
24
+ channel: 'cli',
25
+ isAuthorizedSender: true,
26
+ config: {} as any
27
+ };
28
+
29
+ const result = handleManageOkr(mockCtx as any);
30
+
31
+ expect(result).toBeDefined();
32
+ expect(result.text).toContain('OKR Management');
33
+ });
34
+ });
@@ -0,0 +1,88 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { handleThinkingOs } from '../../src/commands/thinking-os';
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
5
+
6
+ vi.mock('fs');
7
+
8
+ describe('Thinking OS Command', () => {
9
+ // Use path.resolve for cross-platform compatibility
10
+ const workspaceDir = path.resolve('/mock/workspace');
11
+
12
+ beforeEach(() => {
13
+ vi.clearAllMocks();
14
+ });
15
+
16
+ it('should return default help text if no subcommand is provided', () => {
17
+ const result = handleThinkingOs({ config: { workspaceDir }, args: '' } as any);
18
+ expect(result.text).toContain('Governance Console');
19
+ expect(result.text).toContain('/thinking-os status');
20
+ });
21
+
22
+ it('should format usage report on status', () => {
23
+ const usageLogPath = path.join(workspaceDir, '.state', 'thinking_os_usage.json');
24
+ const thinkingOsPath = path.join(workspaceDir, '.principles', 'THINKING_OS.md');
25
+
26
+ vi.mocked(fs.existsSync).mockImplementation((p: fs.PathOrFileDescriptor) => {
27
+ const pStr = p.toString();
28
+ return pStr === usageLogPath || pStr === thinkingOsPath;
29
+ });
30
+ vi.mocked(fs.readFileSync).mockImplementation((p: fs.PathOrFileDescriptor) => {
31
+ const pStr = p.toString();
32
+ if (pStr === usageLogPath) {
33
+ return JSON.stringify({
34
+ '_total_turns': 100,
35
+ 'T-01': 10,
36
+ 'T-06': 3
37
+ });
38
+ }
39
+ if (pStr === thinkingOsPath) {
40
+ return '### T-01: Map Before Territory (地图先于领土)\n### T-06: Occam\'s Razor (奥卡姆剃刀)';
41
+ }
42
+ return '';
43
+ });
44
+
45
+ const result = handleThinkingOs({ config: { workspaceDir }, args: 'status' } as any);
46
+ expect(result.text).toContain('Total turns tracked: **100**');
47
+ expect(result.text).toContain('T-01 | Map Before Territory (地图先于领土) | 10 | ✅ 10.0%');
48
+ });
49
+
50
+ it('should handle propose subcommand', () => {
51
+ const result = handleThinkingOs({ config: { workspaceDir }, args: 'propose newly proposed test model with a signal section' } as any);
52
+
53
+ expect(fs.appendFileSync).toHaveBeenCalled();
54
+ // Check that the result mentions the file (cross-platform)
55
+ expect(result.text).toContain('THINKING_OS_CANDIDATES.md');
56
+ });
57
+
58
+ it('should return validation error if propose is empty', () => {
59
+ const result = handleThinkingOs({ config: { workspaceDir }, args: 'propose ' } as any);
60
+ expect(result.text).toContain('Usage: `/thinking-os propose');
61
+ expect(fs.appendFileSync).not.toHaveBeenCalled();
62
+ });
63
+
64
+ it('should run audit and warn about overused models', () => {
65
+ const usageLogPath = path.join(workspaceDir, '.state', 'thinking_os_usage.json');
66
+ const thinkingOsPath = path.join(workspaceDir, '.principles', 'THINKING_OS.md');
67
+
68
+ vi.mocked(fs.existsSync).mockImplementation(() => true);
69
+
70
+ vi.mocked(fs.readFileSync).mockImplementation((p: fs.PathOrFileDescriptor) => {
71
+ const pStr = p.toString();
72
+ if (pStr === usageLogPath) {
73
+ return JSON.stringify({
74
+ '_total_turns': 10,
75
+ 'T-01': 8 // 80% usage
76
+ });
77
+ }
78
+ if (pStr === thinkingOsPath) {
79
+ return '### T-01: Map\n### T-02: Constraints';
80
+ }
81
+ return '';
82
+ });
83
+
84
+ const result = handleThinkingOs({ config: { workspaceDir }, args: 'audit' } as any);
85
+ expect(result.text).toContain('Active models**: 2');
86
+ expect(result.text).toContain('possibly too broad a pattern');
87
+ });
88
+ });
@@ -0,0 +1,261 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ import {
5
+ loadThresholdState,
6
+ updateThresholdState,
7
+ resetThresholdState,
8
+ getEffectiveThresholds,
9
+ getDetailedThresholdState,
10
+ DEFAULT_THRESHOLDS,
11
+ MAX_ADJUSTMENT_PER_STEP,
12
+ THRESHOLD_STATE_FILE,
13
+ } from '../../src/core/adaptive-thresholds.js';
14
+
15
+ // ---------------------------------------------------------------------------
16
+ // Test Helpers
17
+ // ---------------------------------------------------------------------------
18
+
19
+ function createTempStateDir(): string {
20
+ const tmpDir = path.join(__dirname, '..', '..', '.tmp', `threshold-test-${Date.now()}`);
21
+ fs.mkdirSync(tmpDir, { recursive: true });
22
+ return tmpDir;
23
+ }
24
+
25
+ function cleanupStateDir(stateDir: string): void {
26
+ if (fs.existsSync(stateDir)) {
27
+ fs.rmSync(stateDir, { recursive: true, force: true });
28
+ }
29
+ }
30
+
31
+ // ---------------------------------------------------------------------------
32
+ // Tests: loadThresholdState
33
+ // ---------------------------------------------------------------------------
34
+
35
+ describe('loadThresholdState', () => {
36
+ let stateDir: string;
37
+
38
+ beforeEach(() => {
39
+ stateDir = createTempStateDir();
40
+ });
41
+
42
+ afterEach(() => {
43
+ cleanupStateDir(stateDir);
44
+ });
45
+
46
+ it('returns default thresholds when no state file exists', () => {
47
+ const result = loadThresholdState(stateDir);
48
+ expect(result.success).toBe(true);
49
+ expect(result.usedDefaults).toBe(true);
50
+ expect(result.thresholds).toEqual(DEFAULT_THRESHOLDS);
51
+ });
52
+
53
+ it('loads persisted thresholds', () => {
54
+ // Step constraint limits adjustment to MAX_ADJUSTMENT_PER_STEP per call
55
+ // schemaCompletenessMin: 0.6 + 0.05 = 0.65 (one step)
56
+ updateThresholdState(stateDir, 'schemaCompletenessMin', 0.65, 'test adjustment');
57
+
58
+ // Then load it back
59
+ const result = loadThresholdState(stateDir);
60
+ expect(result.success).toBe(true);
61
+ expect(result.usedDefaults).toBe(false);
62
+ expect(result.thresholds.schemaCompletenessMin).toBe(0.65);
63
+ });
64
+
65
+ it('clamps values to bounds', () => {
66
+ // Try to set above maximum
67
+ updateThresholdState(stateDir, 'principleAlignmentMin', 1.5, 'test');
68
+ const result = loadThresholdState(stateDir);
69
+ expect(result.thresholds.principleAlignmentMin).toBeLessThanOrEqual(1.0);
70
+ });
71
+
72
+ it('returns defaults on corrupted state', () => {
73
+ // Write corrupted JSON
74
+ const statePath = path.join(stateDir, THRESHOLD_STATE_FILE);
75
+ fs.writeFileSync(statePath, 'not valid json{', 'utf-8');
76
+
77
+ const result = loadThresholdState(stateDir);
78
+ expect(result.success).toBe(true);
79
+ expect(result.usedDefaults).toBe(true);
80
+ });
81
+ });
82
+
83
+ // ---------------------------------------------------------------------------
84
+ // Tests: updateThresholdState
85
+ // ---------------------------------------------------------------------------
86
+
87
+ describe('updateThresholdState', () => {
88
+ let stateDir: string;
89
+
90
+ beforeEach(() => {
91
+ stateDir = createTempStateDir();
92
+ });
93
+
94
+ afterEach(() => {
95
+ cleanupStateDir(stateDir);
96
+ });
97
+
98
+ it('updates a threshold value', () => {
99
+ // Step constraint limits adjustment per call
100
+ // schemaCompletenessMin: 0.6 + 0.05 (max step) = 0.65
101
+ const result = updateThresholdState(stateDir, 'schemaCompletenessMin', 0.65, 'test adjustment');
102
+ expect(result.success).toBe(true);
103
+ expect(result.changed).toBe(true);
104
+ expect(result.oldValue).toBe(DEFAULT_THRESHOLDS.schemaCompletenessMin);
105
+ expect(result.newValue).toBe(0.65);
106
+ expect(result.reason).toBe('test adjustment');
107
+ });
108
+
109
+ it('enforces max adjustment per step', () => {
110
+ const largeDelta = DEFAULT_THRESHOLDS.schemaCompletenessMin + MAX_ADJUSTMENT_PER_STEP + 0.1;
111
+ const result = updateThresholdState(stateDir, 'schemaCompletenessMin', largeDelta, 'large step');
112
+ expect(result.success).toBe(true);
113
+ expect(result.changed).toBe(true);
114
+ // Should only move by MAX_ADJUSTMENT_PER_STEP
115
+ expect(result.newValue).toBe(DEFAULT_THRESHOLDS.schemaCompletenessMin + MAX_ADJUSTMENT_PER_STEP);
116
+ });
117
+
118
+ it('ignores changes smaller than minimum', () => {
119
+ const smallChange = DEFAULT_THRESHOLDS.schemaCompletenessMin + 0.001;
120
+ const result = updateThresholdState(stateDir, 'schemaCompletenessMin', smallChange, 'tiny step');
121
+ expect(result.success).toBe(true);
122
+ expect(result.changed).toBe(false);
123
+ });
124
+
125
+ it('rejects unknown threshold names', () => {
126
+ const result = updateThresholdState(stateDir, 'unknownThreshold' as any, 0.5, 'test');
127
+ expect(result.success).toBe(false);
128
+ expect(result.error).toContain('Unknown threshold');
129
+ });
130
+
131
+ it('persists changes to disk', () => {
132
+ // Step constraint limits adjustment to MAX_ADJUSTMENT_PER_STEP per call
133
+ // executabilityMin: 0.65 + 0.05 (max step) = 0.70
134
+ updateThresholdState(stateDir, 'executabilityMin', 0.70, 'persistence test');
135
+ const loaded = loadThresholdState(stateDir);
136
+ expect(loaded.thresholds.executabilityMin).toBe(0.70);
137
+ });
138
+ });
139
+
140
+ // ---------------------------------------------------------------------------
141
+ // Tests: resetThresholdState
142
+ // ---------------------------------------------------------------------------
143
+
144
+ describe('resetThresholdState', () => {
145
+ let stateDir: string;
146
+
147
+ beforeEach(() => {
148
+ stateDir = createTempStateDir();
149
+ });
150
+
151
+ afterEach(() => {
152
+ cleanupStateDir(stateDir);
153
+ });
154
+
155
+ it('resets all thresholds to defaults', () => {
156
+ // Change some values
157
+ updateThresholdState(stateDir, 'schemaCompletenessMin', 0.9, 'change 1');
158
+ updateThresholdState(stateDir, 'principleAlignmentMin', 0.95, 'change 2');
159
+
160
+ // Reset
161
+ resetThresholdState(stateDir);
162
+
163
+ // Verify defaults
164
+ const result = loadThresholdState(stateDir);
165
+ expect(result.thresholds).toEqual(DEFAULT_THRESHOLDS);
166
+ });
167
+ });
168
+
169
+ // ---------------------------------------------------------------------------
170
+ // Tests: getEffectiveThresholds
171
+ // ---------------------------------------------------------------------------
172
+
173
+ describe('getEffectiveThresholds', () => {
174
+ let stateDir: string;
175
+
176
+ beforeEach(() => {
177
+ stateDir = createTempStateDir();
178
+ });
179
+
180
+ afterEach(() => {
181
+ cleanupStateDir(stateDir);
182
+ });
183
+
184
+ it('returns default thresholds when no state file exists', () => {
185
+ const thresholds = getEffectiveThresholds(stateDir);
186
+ expect(thresholds).toEqual(DEFAULT_THRESHOLDS);
187
+ });
188
+
189
+ it('returns persisted thresholds', () => {
190
+ // Note: step constraint limits adjustment per call
191
+ // Set to a value within one step: default (0.5) + MAX_ADJUSTMENT_PER_STEP (0.05) = 0.55
192
+ updateThresholdState(stateDir, 'boundednessMin', 0.55, 'test');
193
+ const thresholds = getEffectiveThresholds(stateDir);
194
+ expect(thresholds.boundednessMin).toBe(0.55);
195
+ });
196
+ });
197
+
198
+ // ---------------------------------------------------------------------------
199
+ // Tests: getDetailedThresholdState
200
+ // ---------------------------------------------------------------------------
201
+
202
+ describe('getDetailedThresholdState', () => {
203
+ let stateDir: string;
204
+
205
+ beforeEach(() => {
206
+ stateDir = createTempStateDir();
207
+ });
208
+
209
+ afterEach(() => {
210
+ cleanupStateDir(stateDir);
211
+ });
212
+
213
+ it('returns null when no state file exists', () => {
214
+ const state = getDetailedThresholdState(stateDir);
215
+ expect(state).toBeNull();
216
+ });
217
+
218
+ it('returns detailed state with metadata', () => {
219
+ updateThresholdState(stateDir, 'confidenceMin', 0.75, 'test adjustment');
220
+ const state = getDetailedThresholdState(stateDir);
221
+ expect(state).not.toBeNull();
222
+ expect(state!.thresholds.confidenceMin).toBeDefined();
223
+ expect(state!.thresholds.confidenceMin!.lastUpdatedAt).toBeDefined();
224
+ expect(state!.thresholds.confidenceMin!.adjustmentCount).toBe(1);
225
+ });
226
+ });
227
+
228
+ // ---------------------------------------------------------------------------
229
+ // Tests: Default values integrity
230
+ // ---------------------------------------------------------------------------
231
+
232
+ describe('DEFAULT_THRESHOLDS', () => {
233
+ it('has values in valid range (0-1)', () => {
234
+ for (const value of Object.values(DEFAULT_THRESHOLDS)) {
235
+ expect(value).toBeGreaterThanOrEqual(0);
236
+ expect(value).toBeLessThanOrEqual(1);
237
+ }
238
+ });
239
+
240
+ it('has aggregateMin higher than minimum possible weighted aggregate', () => {
241
+ // aggregateMin (0.65) should be higher than the minimum possible
242
+ // aggregate score given all thresholds at minimum values.
243
+ // This ensures aggregateMin provides an additional quality gate.
244
+ const weights = {
245
+ schemaCompletenessMin: 0.15,
246
+ principleAlignmentMin: 0.30,
247
+ executabilityMin: 0.20,
248
+ boundednessMin: 0.20,
249
+ confidenceMin: 0.15,
250
+ };
251
+ const minPossibleAggregate =
252
+ DEFAULT_THRESHOLDS.schemaCompletenessMin * weights.schemaCompletenessMin +
253
+ DEFAULT_THRESHOLDS.principleAlignmentMin * weights.principleAlignmentMin +
254
+ DEFAULT_THRESHOLDS.executabilityMin * weights.executabilityMin +
255
+ DEFAULT_THRESHOLDS.boundednessMin * weights.boundednessMin +
256
+ DEFAULT_THRESHOLDS.confidenceMin * weights.confidenceMin;
257
+
258
+ // aggregateMin should be at or above the minimum possible aggregate
259
+ expect(DEFAULT_THRESHOLDS.aggregateMin).toBeGreaterThanOrEqual(minPossibleAggregate);
260
+ });
261
+ });
@@ -0,0 +1,89 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { ConfigService } from '../../src/core/config-service.js';
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
5
+
6
+ vi.mock('fs');
7
+
8
+ describe('ConfigService', () => {
9
+ const stateDir = '/mock/state';
10
+ const configPath = path.join(stateDir, 'pain_settings.json');
11
+
12
+ beforeEach(() => {
13
+ vi.clearAllMocks();
14
+ ConfigService.reset();
15
+ });
16
+
17
+ it('should create and return a PainConfig instance', () => {
18
+ const mockConfig = {
19
+ thresholds: { pain_trigger: 50 }
20
+ };
21
+
22
+ vi.mocked(fs.existsSync).mockImplementation((p) => p.toString() === configPath);
23
+ vi.mocked(fs.readFileSync).mockImplementation((p) => {
24
+ if (p.toString() === configPath) return JSON.stringify(mockConfig);
25
+ return '';
26
+ });
27
+
28
+ const config = ConfigService.get(stateDir);
29
+ expect(config).toBeDefined();
30
+ expect(config.get('thresholds.pain_trigger')).toBe(50);
31
+ });
32
+
33
+ it('should return the same instance for the same stateDir', () => {
34
+ vi.mocked(fs.existsSync).mockReturnValue(false);
35
+
36
+ const config1 = ConfigService.get(stateDir);
37
+ const config2 = ConfigService.get(stateDir);
38
+
39
+ expect(config1).toBe(config2);
40
+ });
41
+
42
+ it('should create a new instance when stateDir changes', () => {
43
+ const stateDir1 = '/mock/state1';
44
+ const stateDir2 = '/mock/state2';
45
+ const configPath1 = path.join(stateDir1, 'pain_settings.json');
46
+ const configPath2 = path.join(stateDir2, 'pain_settings.json');
47
+
48
+ vi.mocked(fs.existsSync).mockImplementation((p) =>
49
+ p.toString() === configPath1 || p.toString() === configPath2
50
+ );
51
+ vi.mocked(fs.readFileSync).mockImplementation((p) => {
52
+ if (p.toString() === configPath1) return JSON.stringify({ thresholds: { pain_trigger: 10 } });
53
+ if (p.toString() === configPath2) return JSON.stringify({ thresholds: { pain_trigger: 20 } });
54
+ return '';
55
+ });
56
+
57
+ const config1 = ConfigService.get(stateDir1);
58
+ expect(config1.get('thresholds.pain_trigger')).toBe(10);
59
+
60
+ const config2 = ConfigService.get(stateDir2);
61
+ expect(config2.get('thresholds.pain_trigger')).toBe(20);
62
+
63
+ expect(config1).not.toBe(config2);
64
+ });
65
+
66
+ it('should reset the singleton instance', () => {
67
+ vi.mocked(fs.existsSync).mockReturnValue(false);
68
+
69
+ const config1 = ConfigService.get(stateDir);
70
+ ConfigService.reset();
71
+ const config2 = ConfigService.get(stateDir);
72
+
73
+ expect(config1).not.toBe(config2);
74
+ });
75
+
76
+ it('should reload config when instance is recreated after reset', () => {
77
+ vi.mocked(fs.existsSync).mockImplementation((p) => p.toString() === configPath);
78
+ vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify({ thresholds: { pain_trigger: 99 } }));
79
+
80
+ const config1 = ConfigService.get(stateDir);
81
+ expect(config1.get('thresholds.pain_trigger')).toBe(99);
82
+
83
+ ConfigService.reset();
84
+
85
+ vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify({ thresholds: { pain_trigger: 88 } }));
86
+ const config2 = ConfigService.get(stateDir);
87
+ expect(config2.get('thresholds.pain_trigger')).toBe(88);
88
+ });
89
+ });
@@ -0,0 +1,90 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { PainConfig } from '../../src/core/config.js';
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
5
+
6
+ vi.mock('fs');
7
+
8
+ describe('PainConfig', () => {
9
+ const stateDir = '/mock/state';
10
+ const configPath = path.join(stateDir, 'pain_settings.json');
11
+
12
+ beforeEach(() => {
13
+ vi.clearAllMocks();
14
+ });
15
+
16
+ it('should load config from file if it exists', () => {
17
+ const mockConfig = {
18
+ thresholds: {
19
+ pain_trigger: 40,
20
+ cognitive_paralysis_input: 5000
21
+ },
22
+ scores: {
23
+ paralysis: 50
24
+ }
25
+ };
26
+
27
+ vi.mocked(fs.existsSync).mockImplementation((p) => p.toString() === configPath);
28
+ vi.mocked(fs.readFileSync).mockImplementation((p) => {
29
+ if (p.toString() === configPath) return JSON.stringify(mockConfig);
30
+ return '';
31
+ });
32
+
33
+ const config = new PainConfig(stateDir);
34
+ config.load();
35
+
36
+ expect(config.get('thresholds.pain_trigger')).toBe(40);
37
+ expect(config.get('thresholds.cognitive_paralysis_input')).toBe(5000);
38
+ expect(config.get('scores.paralysis')).toBe(50);
39
+ });
40
+
41
+ it('should return default values if file does not exist', () => {
42
+ vi.mocked(fs.existsSync).mockReturnValue(false);
43
+
44
+ const config = new PainConfig(stateDir);
45
+ config.load();
46
+
47
+ // Check some defaults
48
+ expect(config.get('thresholds.pain_trigger')).toBe(40);
49
+ expect(config.get('scores.paralysis')).toBe(30);
50
+ });
51
+
52
+ it('should return nested values using dot notation', () => {
53
+ const config = new PainConfig(stateDir);
54
+ // Using defaults
55
+ config.load();
56
+ expect(config.get('intervals.worker_poll_ms')).toBe(15 * 60 * 1000);
57
+ });
58
+
59
+ it('should skip undefined values during merge', () => {
60
+ const mockConfig = {
61
+ thresholds: {
62
+ pain_trigger: undefined // Should NOT overwrite default
63
+ }
64
+ };
65
+
66
+ vi.mocked(fs.existsSync).mockReturnValue(true);
67
+ vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify(mockConfig));
68
+
69
+ const config = new PainConfig(stateDir);
70
+ config.load();
71
+
72
+ expect(config.get('thresholds.pain_trigger')).toBe(40); // Default remains
73
+ });
74
+
75
+ it('should validate and correct out-of-range values', () => {
76
+ const mockConfig = {
77
+ intervals: {
78
+ worker_poll_ms: 500 // Too fast, should be corrected
79
+ }
80
+ };
81
+
82
+ vi.mocked(fs.existsSync).mockReturnValue(true);
83
+ vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify(mockConfig));
84
+
85
+ const config = new PainConfig(stateDir);
86
+ config.load();
87
+
88
+ expect(config.get('intervals.worker_poll_ms')).toBe(15 * 60 * 1000); // Reset to default
89
+ });
90
+ });