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
@@ -17,47 +17,176 @@
17
17
  * - cooldown/quota state is persisted in nocturnal-runtime.json
18
18
  * - abandoned sessions (>2h inactive) must not block nocturnal flow
19
19
  */
20
+
20
21
  import * as fs from 'fs';
21
22
  import * as path from 'path';
22
- import { listSessions } from '../core/session-tracker.js';
23
+ import { listSessions, SessionState } from '../core/session-tracker.js';
23
24
  import { withLockAsync } from '../utils/file-lock.js';
25
+
26
+ // ---------------------------------------------------------------------------
27
+ // System Session Detection
28
+ // ---------------------------------------------------------------------------
29
+
30
+ /**
31
+ * Returns true if the session was created by a system process (cron, boot, probe, subagent, acp).
32
+ * Uses OpenClaw's native session key patterns to avoid false positives.
33
+ *
34
+ * Detection priority (most reliable first):
35
+ * 1. trigger field: Most reliable — explicitly set by OpenClaw ("cron", "heartbeat", "subagent")
36
+ * 2. sessionKey patterns: Secondary confirmation via structured key (agent:main:cron:...)
37
+ * 3. sessionId prefix: Fallback for boot-, probe- prefixed IDs
38
+ *
39
+ * Excluded (NOT system sessions):
40
+ * - User sessions like agent:main:feishu:user:xxx — third component is channel type
41
+ */
42
+ function isSystemSession(state: SessionState): boolean {
43
+ const { sessionId, sessionKey, trigger } = state;
44
+
45
+ // Primary: trigger field is explicitly set by OpenClaw - most reliable
46
+ if (trigger === 'cron' || trigger === 'heartbeat' || trigger === 'subagent') {
47
+ return true;
48
+ }
49
+
50
+ // Secondary: sessionKey pattern matching
51
+ if (sessionKey) {
52
+ const raw = sessionKey.toLowerCase();
53
+ if (raw.includes('cron:')) return true;
54
+ if (raw.includes('subagent:')) return true;
55
+ if (raw.includes('acp:')) return true;
56
+ }
57
+
58
+ // Fallback: sessionId prefix patterns (boot-, probe-)
59
+ if (sessionId?.startsWith('boot-')) return true;
60
+ if (sessionId?.startsWith('probe-')) return true;
61
+
62
+ return false;
63
+ }
64
+
24
65
  // ---------------------------------------------------------------------------
25
66
  // Constants
26
67
  // ---------------------------------------------------------------------------
68
+
27
69
  /** File name for nocturnal runtime bookkeeping */
28
70
  export const NOCTURNAL_RUNTIME_FILE = 'nocturnal-runtime.json';
71
+
29
72
  /** Default idle threshold: workspace is considered idle if no activity for this duration (ms) */
30
73
  export const DEFAULT_IDLE_THRESHOLD_MS = 30 * 60 * 1000; // 30 minutes
74
+
31
75
  /** Default cooldown between nocturnal runs (ms) */
32
76
  export const DEFAULT_GLOBAL_COOLDOWN_MS = 60 * 60 * 1000; // 1 hour
77
+
33
78
  /** Default per-principle cooldown (ms) */
34
79
  export const DEFAULT_PRINCIPLE_COOLDOWN_MS = 6 * 60 * 60 * 1000; // 6 hours
80
+
35
81
  /** Default maximum nocturnal runs per quota window */
36
82
  export const DEFAULT_MAX_RUNS_PER_WINDOW = 3;
83
+
37
84
  /** Default quota window size (ms) */
38
85
  export const DEFAULT_QUOTA_WINDOW_MS = 24 * 60 * 60 * 1000; // 24 hours
86
+
39
87
  /** Abandoned session threshold: sessions inactive for longer than this are ignored (ms) */
40
88
  export const DEFAULT_ABANDONED_THRESHOLD_MS = 2 * 60 * 60 * 1000; // 2 hours
89
+
90
+ // ---------------------------------------------------------------------------
91
+ // Types
92
+ // ---------------------------------------------------------------------------
93
+
94
+ /**
95
+ * Persisted state for nocturnal runtime bookkeeping.
96
+ * Stored in {stateDir}/nocturnal-runtime.json
97
+ */
98
+ export interface NocturnalRuntimeState {
99
+ /** Last time a nocturnal run was started (ISO string) */
100
+ lastRunAt?: string;
101
+
102
+ /** Last time a nocturnal run completed successfully */
103
+ lastSuccessfulRunAt?: string;
104
+
105
+ /** Cooldown end time for global cooldown (ISO string) */
106
+ globalCooldownUntil?: string;
107
+
108
+ /**
109
+ * Per-principle cooldown map.
110
+ * Key: principleId, Value: ISO string of cooldown end time
111
+ */
112
+ principleCooldowns: Record<string, string>;
113
+
114
+ /**
115
+ * Sliding window of recent run timestamps.
116
+ * Used for quota enforcement.
117
+ */
118
+ recentRunTimestamps: string[];
119
+
120
+ /** Metadata about last run (for debugging) */
121
+ lastRunMeta?: {
122
+ targetPrincipleId?: string;
123
+ sampleCount?: number;
124
+ status: 'success' | 'failed' | 'skipped';
125
+ reason?: string;
126
+ };
127
+ }
128
+
129
+ /** Result of an idle check */
130
+ export interface IdleCheckResult {
131
+ /** Whether the workspace is currently idle */
132
+ isIdle: boolean;
133
+ /** Most recent activity timestamp across all sessions (epoch ms) */
134
+ mostRecentActivityAt: number;
135
+ /** How long since the last activity (ms) */
136
+ idleForMs: number;
137
+ /** Number of active (non-abandoned) user sessions found */
138
+ userActiveSessions: number;
139
+ /** List of abandoned session IDs (inactive > abandoned threshold) */
140
+ abandonedSessionIds: string[];
141
+ /** Whether trajectory guardrail also confirms idle */
142
+ trajectoryGuardrailConfirmsIdle: boolean;
143
+ /** Reason for the idle determination */
144
+ reason: string;
145
+ }
146
+
147
+ /** Result of a cooldown check */
148
+ export interface CooldownCheckResult {
149
+ /** Whether the global cooldown is currently active */
150
+ globalCooldownActive: boolean;
151
+ /** When the global cooldown ends (ISO string), null if not in cooldown */
152
+ globalCooldownUntil: string | null;
153
+ /** Remaining ms until global cooldown expires */
154
+ globalCooldownRemainingMs: number;
155
+ /** Whether the principle-specific cooldown is active */
156
+ principleCooldownActive: boolean;
157
+ /** When the principle cooldown ends (ISO string), null if not in cooldown */
158
+ principleCooldownUntil: string | null;
159
+ /** Remaining ms until principle cooldown expires */
160
+ principleCooldownRemainingMs: number;
161
+ /** Whether the quota has been exhausted */
162
+ quotaExhausted: boolean;
163
+ /** Number of runs remaining in current window */
164
+ runsRemaining: number;
165
+ }
166
+
41
167
  // ---------------------------------------------------------------------------
42
168
  // Default State
43
169
  // ---------------------------------------------------------------------------
44
- function createDefaultState() {
170
+
171
+ function createDefaultState(): NocturnalRuntimeState {
45
172
  return {
46
173
  principleCooldowns: {},
47
174
  recentRunTimestamps: [],
48
175
  };
49
176
  }
177
+
50
178
  // ---------------------------------------------------------------------------
51
179
  // File Operations (with locking)
52
180
  // ---------------------------------------------------------------------------
53
- async function readState(stateDir) {
181
+
182
+ async function readState(stateDir: string): Promise<NocturnalRuntimeState> {
54
183
  const filePath = path.join(stateDir, NOCTURNAL_RUNTIME_FILE);
55
184
  if (!fs.existsSync(filePath)) {
56
185
  return createDefaultState();
57
186
  }
58
187
  try {
59
188
  const raw = fs.readFileSync(filePath, 'utf-8');
60
- const parsed = JSON.parse(raw);
189
+ const parsed = JSON.parse(raw) as NocturnalRuntimeState;
61
190
  // Ensure required fields exist (migration-safe)
62
191
  return {
63
192
  principleCooldowns: parsed.principleCooldowns ?? {},
@@ -67,20 +196,20 @@ async function readState(stateDir) {
67
196
  globalCooldownUntil: parsed.globalCooldownUntil,
68
197
  lastRunMeta: parsed.lastRunMeta,
69
198
  };
70
- }
71
- catch {
199
+ } catch {
72
200
  // Corrupted file — start fresh
73
201
  return createDefaultState();
74
202
  }
75
203
  }
76
- function readStateSync(stateDir) {
204
+
205
+ function readStateSync(stateDir: string): NocturnalRuntimeState {
77
206
  const filePath = path.join(stateDir, NOCTURNAL_RUNTIME_FILE);
78
207
  if (!fs.existsSync(filePath)) {
79
208
  return createDefaultState();
80
209
  }
81
210
  try {
82
211
  const raw = fs.readFileSync(filePath, 'utf-8');
83
- const parsed = JSON.parse(raw);
212
+ const parsed = JSON.parse(raw) as NocturnalRuntimeState;
84
213
  return {
85
214
  principleCooldowns: parsed.principleCooldowns ?? {},
86
215
  recentRunTimestamps: parsed.recentRunTimestamps ?? [],
@@ -89,13 +218,13 @@ function readStateSync(stateDir) {
89
218
  globalCooldownUntil: parsed.globalCooldownUntil,
90
219
  lastRunMeta: parsed.lastRunMeta,
91
220
  };
92
- }
93
- catch (err) {
221
+ } catch (err) {
94
222
  console.warn(`[nocturnal-runtime] State file corrupted, resetting: ${err instanceof Error ? err.message : String(err)}`);
95
223
  return createDefaultState();
96
224
  }
97
225
  }
98
- async function writeState(stateDir, state) {
226
+
227
+ async function writeState(stateDir: string, state: NocturnalRuntimeState): Promise<void> {
99
228
  const filePath = path.join(stateDir, NOCTURNAL_RUNTIME_FILE);
100
229
  const stateDirPath = path.dirname(filePath);
101
230
  if (!fs.existsSync(stateDirPath)) {
@@ -105,9 +234,11 @@ async function writeState(stateDir, state) {
105
234
  fs.writeFileSync(filePath, JSON.stringify(state, null, 2), 'utf-8');
106
235
  });
107
236
  }
237
+
108
238
  // ---------------------------------------------------------------------------
109
239
  // Idle Detection
110
240
  // ---------------------------------------------------------------------------
241
+
111
242
  /**
112
243
  * Check if the workspace is currently idle based on session activity.
113
244
  *
@@ -123,28 +254,45 @@ async function writeState(stateDir, state) {
123
254
  * @param trajectoryLastActivityAt - Optional trajectory timestamp as secondary guardrail
124
255
  * @returns IdleCheckResult with full diagnostic information
125
256
  */
126
- export function checkWorkspaceIdle(workspaceDir, options = {}, trajectoryLastActivityAt) {
127
- const { idleThresholdMs = DEFAULT_IDLE_THRESHOLD_MS, abandonedThresholdMs = DEFAULT_ABANDONED_THRESHOLD_MS, } = options;
257
+ export function checkWorkspaceIdle(
258
+ workspaceDir: string,
259
+ options: {
260
+ idleThresholdMs?: number;
261
+ abandonedThresholdMs?: number;
262
+ } = {},
263
+ trajectoryLastActivityAt?: number
264
+ ): IdleCheckResult {
265
+ const {
266
+ idleThresholdMs = DEFAULT_IDLE_THRESHOLD_MS,
267
+ abandonedThresholdMs = DEFAULT_ABANDONED_THRESHOLD_MS,
268
+ } = options;
269
+
128
270
  const now = Date.now();
129
271
  const sessions = listSessions(workspaceDir);
272
+
130
273
  // Separate active vs abandoned sessions
131
- const abandonedSessions = [];
274
+ const abandonedSessions: string[] = [];
132
275
  let mostRecentActivityAt = 0;
133
- let activeSessionCount = 0;
276
+ let userActiveSessions = 0;
277
+
134
278
  for (const session of sessions) {
279
+ // Skip system sessions (cron, boot, probe, subagent, acp) from idle determination
280
+ if (isSystemSession(session)) continue;
281
+
135
282
  const inactiveFor = now - session.lastActivityAt;
136
283
  if (inactiveFor > abandonedThresholdMs) {
137
284
  abandonedSessions.push(session.sessionId);
138
- }
139
- else {
140
- activeSessionCount++;
285
+ } else {
286
+ userActiveSessions++;
141
287
  if (session.lastActivityAt > mostRecentActivityAt) {
142
288
  mostRecentActivityAt = session.lastActivityAt;
143
289
  }
144
290
  }
145
291
  }
292
+
146
293
  const idleForMs = mostRecentActivityAt > 0 ? now - mostRecentActivityAt : now;
147
294
  const isIdle = mostRecentActivityAt === 0 || idleForMs > idleThresholdMs;
295
+
148
296
  // Trajectory guardrail: only used as a secondary check
149
297
  // If trajectory says there's recent activity but session state says idle,
150
298
  // that's a discrepancy we should note but still trust session state as primary
@@ -154,32 +302,35 @@ export function checkWorkspaceIdle(workspaceDir, options = {}, trajectoryLastAct
154
302
  // Guardrail confirms if trajectory also shows idle or near-idle (>80% of threshold)
155
303
  trajectoryGuardrailConfirmsIdle = trajectoryIdleFor > idleThresholdMs * 0.8;
156
304
  }
157
- let reason;
305
+
306
+ let reason: string;
158
307
  if (mostRecentActivityAt === 0) {
159
308
  reason = 'No active sessions found — workspace is idle';
160
- }
161
- else if (isIdle) {
309
+ } else if (isIdle) {
162
310
  reason = `Most recent activity ${idleForMs}ms ago (>${idleThresholdMs}ms threshold)`;
163
- }
164
- else {
311
+ } else {
165
312
  reason = `Recent activity ${idleForMs}ms ago (<${idleThresholdMs}ms threshold)`;
166
313
  }
314
+
167
315
  if (abandonedSessions.length > 0) {
168
316
  reason += `; ${abandonedSessions.length} abandoned session(s) ignored`;
169
317
  }
318
+
170
319
  return {
171
320
  isIdle,
172
321
  mostRecentActivityAt,
173
322
  idleForMs,
174
- activeSessionCount,
323
+ userActiveSessions,
175
324
  abandonedSessionIds: abandonedSessions,
176
325
  trajectoryGuardrailConfirmsIdle,
177
326
  reason,
178
327
  };
179
328
  }
329
+
180
330
  // ---------------------------------------------------------------------------
181
331
  // Cooldown Management
182
332
  // ---------------------------------------------------------------------------
333
+
183
334
  /**
184
335
  * Check if the workspace is currently in a cooldown period.
185
336
  *
@@ -188,14 +339,31 @@ export function checkWorkspaceIdle(workspaceDir, options = {}, trajectoryLastAct
188
339
  * @param options - Cooldown configuration options
189
340
  * @returns CooldownCheckResult
190
341
  */
191
- export function checkCooldown(stateDir, principleId, options = {}) {
192
- const { globalCooldownMs = DEFAULT_GLOBAL_COOLDOWN_MS, principleCooldownMs = DEFAULT_PRINCIPLE_COOLDOWN_MS, maxRunsPerWindow = DEFAULT_MAX_RUNS_PER_WINDOW, quotaWindowMs = DEFAULT_QUOTA_WINDOW_MS, } = options;
342
+ export function checkCooldown(
343
+ stateDir: string,
344
+ principleId?: string,
345
+ options: {
346
+ globalCooldownMs?: number;
347
+ principleCooldownMs?: number;
348
+ maxRunsPerWindow?: number;
349
+ quotaWindowMs?: number;
350
+ } = {}
351
+ ): CooldownCheckResult {
352
+ const {
353
+ globalCooldownMs = DEFAULT_GLOBAL_COOLDOWN_MS,
354
+ principleCooldownMs = DEFAULT_PRINCIPLE_COOLDOWN_MS,
355
+ maxRunsPerWindow = DEFAULT_MAX_RUNS_PER_WINDOW,
356
+ quotaWindowMs = DEFAULT_QUOTA_WINDOW_MS,
357
+ } = options;
358
+
193
359
  const now = Date.now();
194
360
  const state = readStateSync(stateDir);
361
+
195
362
  // Global cooldown check
196
363
  let globalCooldownActive = false;
197
364
  let globalCooldownRemainingMs = 0;
198
- let globalCooldownUntil = null;
365
+ let globalCooldownUntil: string | null = null;
366
+
199
367
  if (state.globalCooldownUntil) {
200
368
  const cooldownEnd = new Date(state.globalCooldownUntil).getTime();
201
369
  if (cooldownEnd > now) {
@@ -204,10 +372,12 @@ export function checkCooldown(stateDir, principleId, options = {}) {
204
372
  globalCooldownUntil = state.globalCooldownUntil;
205
373
  }
206
374
  }
375
+
207
376
  // Principle-specific cooldown check
208
377
  let principleCooldownActive = false;
209
378
  let principleCooldownRemainingMs = 0;
210
- let principleCooldownUntil = null;
379
+ let principleCooldownUntil: string | null = null;
380
+
211
381
  if (principleId && state.principleCooldowns[principleId]) {
212
382
  const cooldownEnd = new Date(state.principleCooldowns[principleId]).getTime();
213
383
  if (cooldownEnd > now) {
@@ -216,13 +386,16 @@ export function checkCooldown(stateDir, principleId, options = {}) {
216
386
  principleCooldownUntil = state.principleCooldowns[principleId];
217
387
  }
218
388
  }
389
+
219
390
  // Quota check: count runs in sliding window
220
391
  const windowStart = now - quotaWindowMs;
221
392
  const recentRuns = state.recentRunTimestamps
222
393
  .map(ts => new Date(ts).getTime())
223
394
  .filter(ts => ts > windowStart);
395
+
224
396
  const quotaExhausted = recentRuns.length >= maxRunsPerWindow;
225
397
  const runsRemaining = Math.max(0, maxRunsPerWindow - recentRuns.length);
398
+
226
399
  return {
227
400
  globalCooldownActive,
228
401
  globalCooldownUntil,
@@ -234,6 +407,7 @@ export function checkCooldown(stateDir, principleId, options = {}) {
234
407
  runsRemaining,
235
408
  };
236
409
  }
410
+
237
411
  /**
238
412
  * Record that a nocturnal run has started.
239
413
  * Updates global cooldown and quota tracking.
@@ -241,27 +415,36 @@ export function checkCooldown(stateDir, principleId, options = {}) {
241
415
  * @param stateDir - State directory
242
416
  * @param principleId - Target principle ID for this run
243
417
  */
244
- export async function recordRunStart(stateDir, principleId) {
418
+ export async function recordRunStart(
419
+ stateDir: string,
420
+ principleId: string
421
+ ): Promise<void> {
245
422
  const state = await readState(stateDir);
246
423
  const now = new Date().toISOString();
424
+
247
425
  state.lastRunAt = now;
248
426
  state.lastRunMeta = {
249
427
  targetPrincipleId: principleId,
250
428
  status: 'skipped', // Will be updated on completion
251
429
  };
430
+
252
431
  // Set global cooldown
253
432
  const cooldownUntil = new Date(Date.now() + DEFAULT_GLOBAL_COOLDOWN_MS).toISOString();
254
433
  state.globalCooldownUntil = cooldownUntil;
434
+
255
435
  // Add to recent runs for quota tracking
256
436
  state.recentRunTimestamps.push(now);
437
+
257
438
  // Prune old timestamps outside the quota window
258
439
  const windowStart = Date.now() - DEFAULT_QUOTA_WINDOW_MS;
259
440
  state.recentRunTimestamps = state.recentRunTimestamps
260
441
  .map(ts => new Date(ts).getTime())
261
442
  .filter(ts => ts > windowStart)
262
443
  .map(ts => new Date(ts).toISOString());
444
+
263
445
  await writeState(stateDir, state);
264
446
  }
447
+
265
448
  /**
266
449
  * Record the outcome of a nocturnal run.
267
450
  *
@@ -269,17 +452,29 @@ export async function recordRunStart(stateDir, principleId) {
269
452
  * @param outcome - 'success', 'failed', or 'skipped'
270
453
  * @param details - Optional details about the run
271
454
  */
272
- export async function recordRunEnd(stateDir, outcome, details) {
455
+ export async function recordRunEnd(
456
+ stateDir: string,
457
+ outcome: 'success' | 'failed' | 'skipped',
458
+ details?: {
459
+ sampleCount?: number;
460
+ reason?: string;
461
+ }
462
+ ): Promise<void> {
273
463
  const state = await readState(stateDir);
274
464
  const now = new Date().toISOString();
465
+
275
466
  if (outcome === 'success') {
276
467
  state.lastSuccessfulRunAt = now;
468
+
277
469
  // Also set per-principle cooldown if we know which principle was targeted
278
470
  if (state.lastRunMeta?.targetPrincipleId) {
279
471
  const pid = state.lastRunMeta.targetPrincipleId;
280
- state.principleCooldowns[pid] = new Date(Date.now() + DEFAULT_PRINCIPLE_COOLDOWN_MS).toISOString();
472
+ state.principleCooldowns[pid] = new Date(
473
+ Date.now() + DEFAULT_PRINCIPLE_COOLDOWN_MS
474
+ ).toISOString();
281
475
  }
282
476
  }
477
+
283
478
  // Update run metadata
284
479
  state.lastRunMeta = {
285
480
  ...state.lastRunMeta,
@@ -287,16 +482,19 @@ export async function recordRunEnd(stateDir, outcome, details) {
287
482
  sampleCount: details?.sampleCount ?? state.lastRunMeta?.sampleCount,
288
483
  reason: details?.reason ?? state.lastRunMeta?.reason,
289
484
  };
485
+
290
486
  // Note: global cooldown remains active (set at run start) - we don't clear it on failure
291
487
  // This prevents rapid retry loops
488
+
292
489
  await writeState(stateDir, state);
293
490
  }
491
+
294
492
  /**
295
493
  * Clear all cooldowns (for testing or admin reset).
296
494
  *
297
495
  * @param stateDir - State directory
298
496
  */
299
- export async function clearAllCooldowns(stateDir) {
497
+ export async function clearAllCooldowns(stateDir: string): Promise<void> {
300
498
  const state = await readState(stateDir);
301
499
  state.globalCooldownUntil = undefined;
302
500
  state.principleCooldowns = {};
@@ -304,15 +502,31 @@ export async function clearAllCooldowns(stateDir) {
304
502
  state.lastRunMeta = undefined;
305
503
  await writeState(stateDir, state);
306
504
  }
505
+
307
506
  /**
308
507
  * Get the current runtime state (for debugging/inspection).
309
508
  *
310
509
  * @param stateDir - State directory
311
510
  * @returns The current NocturnalRuntimeState
312
511
  */
313
- export async function getRuntimeState(stateDir) {
512
+ export async function getRuntimeState(stateDir: string): Promise<NocturnalRuntimeState> {
314
513
  return readState(stateDir);
315
514
  }
515
+
516
+ // ---------------------------------------------------------------------------
517
+ // Convenience: Full Pre-Flight Check
518
+ // ---------------------------------------------------------------------------
519
+
520
+ export interface PreflightCheckResult {
521
+ canRun: boolean;
522
+ idle: IdleCheckResult;
523
+ cooldown: CooldownCheckResult;
524
+ /**
525
+ * Human-readable reasons why run is blocked (if canRun is false)
526
+ */
527
+ blockers: string[];
528
+ }
529
+
316
530
  /**
317
531
  * Combined pre-flight check for whether a nocturnal run should proceed.
318
532
  * Integrates idle + cooldown + quota checks.
@@ -323,26 +537,39 @@ export async function getRuntimeState(stateDir) {
323
537
  * @param trajectoryLastActivityAt - Optional trajectory timestamp as secondary guardrail
324
538
  * @param idleCheckOverride - Optional override for idle check result (for testing)
325
539
  */
326
- export function checkPreflight(workspaceDir, stateDir, principleId, trajectoryLastActivityAt, idleCheckOverride) {
540
+ export function checkPreflight(
541
+ workspaceDir: string,
542
+ stateDir: string,
543
+ principleId?: string,
544
+ trajectoryLastActivityAt?: number,
545
+ idleCheckOverride?: IdleCheckResult
546
+ ): PreflightCheckResult {
327
547
  const idle = idleCheckOverride ?? checkWorkspaceIdle(workspaceDir, {}, trajectoryLastActivityAt);
328
548
  const cooldown = checkCooldown(stateDir, principleId);
329
- const blockers = [];
549
+
550
+ const blockers: string[] = [];
551
+
330
552
  if (!idle.isIdle) {
331
553
  blockers.push(`Workspace not idle (active for ${idle.idleForMs}ms, threshold=${DEFAULT_IDLE_THRESHOLD_MS}ms)`);
332
554
  }
555
+
333
556
  if (cooldown.globalCooldownActive) {
334
557
  blockers.push(`Global cooldown active until ${cooldown.globalCooldownUntil}`);
335
558
  }
559
+
336
560
  if (cooldown.principleCooldownActive) {
337
561
  blockers.push(`Principle cooldown active until ${cooldown.principleCooldownUntil}`);
338
562
  }
563
+
339
564
  if (cooldown.quotaExhausted) {
340
565
  blockers.push(`Quota exhausted (${DEFAULT_MAX_RUNS_PER_WINDOW} runs per ${DEFAULT_QUOTA_WINDOW_MS / 3600000}h window)`);
341
566
  }
342
- if (idle.abandonedSessionIds.length > 0 && idle.activeSessionCount === 0) {
567
+
568
+ if (idle.abandonedSessionIds.length > 0 && idle.userActiveSessions === 0) {
343
569
  // Only block if ALL sessions are abandoned (meaning workspace truly has no activity)
344
570
  // If some sessions are active, we trust the session-based idle check
345
571
  }
572
+
346
573
  return {
347
574
  canRun: blockers.length === 0,
348
575
  idle,