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
@@ -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
+ });