principles-disciple 1.8.0 → 1.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (460) hide show
  1. package/ADVANCED_CONFIG_ZH.md +97 -0
  2. package/AGENT_INSTALL.md +173 -0
  3. package/AGENT_INSTALL_EN.md +173 -0
  4. package/INSTALL.md +256 -0
  5. package/SKILL.md +63 -0
  6. package/docs/COMMAND_REFERENCE.md +76 -0
  7. package/docs/COMMAND_REFERENCE_EN.md +79 -0
  8. package/esbuild.config.js +75 -0
  9. package/openclaw.plugin.json +6 -1
  10. package/package.json +13 -15
  11. package/scripts/build-web.mjs +46 -0
  12. package/scripts/install-dependencies.cjs +47 -0
  13. package/scripts/sync-plugin.mjs +802 -0
  14. package/scripts/verify-build.mjs +109 -0
  15. package/src/agents/nocturnal-dreamer.md +152 -0
  16. package/src/agents/nocturnal-philosopher.md +138 -0
  17. package/src/agents/nocturnal-reflector.md +126 -0
  18. package/src/agents/nocturnal-scribe.md +164 -0
  19. package/src/commands/capabilities.ts +85 -0
  20. package/{dist/commands/context.js → src/commands/context.ts} +78 -38
  21. package/src/commands/evolution-status.ts +146 -0
  22. package/src/commands/export.ts +111 -0
  23. package/src/commands/focus.ts +533 -0
  24. package/src/commands/nocturnal-review.ts +311 -0
  25. package/src/commands/nocturnal-rollout.ts +763 -0
  26. package/src/commands/nocturnal-train.ts +1002 -0
  27. package/{dist/commands/pain.js → src/commands/pain.ts} +68 -49
  28. package/src/commands/principle-rollback.ts +27 -0
  29. package/{dist/commands/rollback.js → src/commands/rollback.ts} +44 -12
  30. package/src/commands/samples.ts +60 -0
  31. package/src/commands/strategy.ts +38 -0
  32. package/{dist/commands/thinking-os.js → src/commands/thinking-os.ts} +59 -36
  33. package/src/commands/workflow-debug.ts +128 -0
  34. package/{dist/config/defaults/runtime.js → src/config/defaults/runtime.ts} +12 -5
  35. package/src/config/errors.ts +163 -0
  36. package/{dist/config/index.d.ts → src/config/index.ts} +2 -1
  37. package/src/constants/diagnostician.ts +66 -0
  38. package/src/constants/tools.ts +62 -0
  39. package/src/core/adaptive-thresholds.ts +476 -0
  40. package/{dist/core/config-service.js → src/core/config-service.ts} +7 -4
  41. package/{dist/core/config.js → src/core/config.ts} +158 -46
  42. package/src/core/control-ui-db.ts +435 -0
  43. package/{dist/core/detection-funnel.js → src/core/detection-funnel.ts} +36 -21
  44. package/{dist/core/detection-service.js → src/core/detection-service.ts} +7 -4
  45. package/{dist/core/dictionary-service.js → src/core/dictionary-service.ts} +7 -4
  46. package/{dist/core/dictionary.js → src/core/dictionary.ts} +57 -34
  47. package/src/core/empathy-keyword-matcher.ts +327 -0
  48. package/src/core/empathy-types.ts +218 -0
  49. package/src/core/event-log.ts +544 -0
  50. package/src/core/evolution-engine.ts +612 -0
  51. package/src/core/evolution-logger.ts +353 -0
  52. package/src/core/evolution-migration.ts +77 -0
  53. package/src/core/evolution-reducer.ts +731 -0
  54. package/src/core/evolution-types.ts +456 -0
  55. package/src/core/external-training-contract.ts +527 -0
  56. package/src/core/focus-history.ts +1458 -0
  57. package/src/core/hygiene/tracker.ts +117 -0
  58. package/{dist/core/init.js → src/core/init.ts} +39 -26
  59. package/src/core/local-worker-routing.ts +617 -0
  60. package/{dist/core/migration.js → src/core/migration.ts} +18 -11
  61. package/src/core/model-deployment-registry.ts +722 -0
  62. package/src/core/model-training-registry.ts +813 -0
  63. package/src/core/nocturnal-arbiter.ts +706 -0
  64. package/src/core/nocturnal-candidate-scoring.ts +392 -0
  65. package/src/core/nocturnal-compliance.ts +1075 -0
  66. package/src/core/nocturnal-dataset.ts +668 -0
  67. package/src/core/nocturnal-executability.ts +428 -0
  68. package/src/core/nocturnal-export.ts +390 -0
  69. package/{dist/core/nocturnal-paths.js → src/core/nocturnal-paths.ts} +49 -23
  70. package/src/core/nocturnal-trajectory-extractor.ts +484 -0
  71. package/src/core/nocturnal-trinity.ts +1384 -0
  72. package/src/core/pain.ts +122 -0
  73. package/{dist/core/path-resolver.js → src/core/path-resolver.ts} +157 -36
  74. package/{dist/core/paths.js → src/core/paths.ts} +13 -4
  75. package/src/core/principle-training-state.ts +450 -0
  76. package/src/core/profile.ts +226 -0
  77. package/src/core/promotion-gate.ts +822 -0
  78. package/{dist/core/risk-calculator.js → src/core/risk-calculator.ts} +42 -16
  79. package/{dist/core/session-tracker.js → src/core/session-tracker.ts} +185 -63
  80. package/src/core/shadow-observation-registry.ts +534 -0
  81. package/{dist/core/system-logger.js → src/core/system-logger.ts} +9 -5
  82. package/src/core/thinking-models.ts +217 -0
  83. package/src/core/training-program.ts +630 -0
  84. package/src/core/trajectory-types.ts +243 -0
  85. package/src/core/trajectory.ts +1673 -0
  86. package/{dist/core/workspace-context.js → src/core/workspace-context.ts} +57 -32
  87. package/src/hooks/bash-risk.ts +171 -0
  88. package/src/hooks/edit-verification.ts +295 -0
  89. package/src/hooks/gate-block-helper.ts +160 -0
  90. package/src/hooks/gate.ts +210 -0
  91. package/src/hooks/gfi-gate.ts +177 -0
  92. package/src/hooks/lifecycle.ts +326 -0
  93. package/{dist/hooks/llm.js → src/hooks/llm.ts} +166 -139
  94. package/src/hooks/message-sanitize.ts +45 -0
  95. package/src/hooks/pain.ts +384 -0
  96. package/src/hooks/progressive-trust-gate.ts +174 -0
  97. package/src/hooks/prompt.ts +920 -0
  98. package/src/hooks/subagent.ts +207 -0
  99. package/src/hooks/thinking-checkpoint.ts +73 -0
  100. package/src/hooks/trajectory-collector.ts +290 -0
  101. package/src/http/principles-console-route.ts +716 -0
  102. package/src/i18n/commands.ts +117 -0
  103. package/src/index.ts +694 -0
  104. package/src/service/central-database.ts +831 -0
  105. package/src/service/control-ui-query-service.ts +888 -0
  106. package/src/service/evolution-query-service.ts +405 -0
  107. package/src/service/evolution-worker.ts +1646 -0
  108. package/src/service/health-query-service.ts +836 -0
  109. package/{dist/service/nocturnal-runtime.js → src/service/nocturnal-runtime.ts} +263 -36
  110. package/src/service/nocturnal-service.ts +1015 -0
  111. package/src/service/nocturnal-target-selector.ts +532 -0
  112. package/src/service/phase3-input-filter.ts +237 -0
  113. package/src/service/runtime-summary-service.ts +757 -0
  114. package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +513 -0
  115. package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +603 -0
  116. package/src/service/subagent-workflow/index.ts +51 -0
  117. package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +856 -0
  118. package/src/service/subagent-workflow/runtime-direct-driver.ts +166 -0
  119. package/src/service/subagent-workflow/types.ts +378 -0
  120. package/src/service/subagent-workflow/workflow-store.ts +328 -0
  121. package/src/service/trajectory-service.ts +15 -0
  122. package/{dist/tools/critique-prompt.js → src/tools/critique-prompt.ts} +25 -8
  123. package/src/tools/deep-reflect.ts +349 -0
  124. package/{dist/tools/model-index.js → src/tools/model-index.ts} +33 -17
  125. package/src/types/event-types.ts +453 -0
  126. package/src/types/hygiene-types.ts +31 -0
  127. package/src/types/principle-tree-schema.ts +244 -0
  128. package/src/types/runtime-summary.ts +49 -0
  129. package/src/types.ts +74 -0
  130. package/src/utils/file-lock.ts +391 -0
  131. package/{dist/utils/glob-match.js → src/utils/glob-match.ts} +21 -20
  132. package/{dist/utils/hashing.js → src/utils/hashing.ts} +6 -4
  133. package/src/utils/io.ts +110 -0
  134. package/{dist/utils/nlp.js → src/utils/nlp.ts} +19 -12
  135. package/{dist/utils/plugin-logger.js → src/utils/plugin-logger.ts} +33 -8
  136. package/src/utils/subagent-probe.ts +94 -0
  137. package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +70 -1
  138. package/templates/pain_settings.json +2 -1
  139. package/tests/README.md +120 -0
  140. package/tests/build-artifacts.test.ts +111 -0
  141. package/tests/commands/evolution-status.test.ts +222 -0
  142. package/tests/commands/evolver.test.ts +22 -0
  143. package/tests/commands/export.test.ts +78 -0
  144. package/tests/commands/nocturnal-review.test.ts +448 -0
  145. package/tests/commands/nocturnal-train.test.ts +97 -0
  146. package/tests/commands/pain.test.ts +108 -0
  147. package/tests/commands/samples.test.ts +65 -0
  148. package/tests/commands/strategy.test.ts +34 -0
  149. package/tests/commands/thinking-os.test.ts +88 -0
  150. package/tests/core/adaptive-thresholds.test.ts +261 -0
  151. package/tests/core/config-service.test.ts +89 -0
  152. package/tests/core/config.test.ts +90 -0
  153. package/tests/core/control-ui-db.test.ts +75 -0
  154. package/tests/core/core-template-guidance.test.ts +21 -0
  155. package/tests/core/detection-funnel.test.ts +63 -0
  156. package/tests/core/detection-service.test.ts +50 -0
  157. package/tests/core/dictionary-service.test.ts +116 -0
  158. package/tests/core/dictionary.test.ts +168 -0
  159. package/tests/core/empathy-keyword-matcher.test.ts +209 -0
  160. package/tests/core/event-log.test.ts +181 -0
  161. package/tests/core/evolution-e2e.test.ts +58 -0
  162. package/tests/core/evolution-engine-gate-integration.test.ts +543 -0
  163. package/tests/core/evolution-engine.test.ts +562 -0
  164. package/tests/core/evolution-logger.test.ts +148 -0
  165. package/tests/core/evolution-migration.test.ts +50 -0
  166. package/tests/core/evolution-paths.test.ts +21 -0
  167. package/tests/core/evolution-reducer.detector-metadata.test.ts +602 -0
  168. package/tests/core/evolution-reducer.test.ts +180 -0
  169. package/tests/core/evolution-types-loop.test.ts +48 -0
  170. package/tests/core/evolution-user-stories.e2e.test.ts +249 -0
  171. package/tests/core/external-training-contract.test.ts +463 -0
  172. package/tests/core/focus-history.test.ts +682 -0
  173. package/tests/core/init-flatten.test.ts +69 -0
  174. package/tests/core/init-refactor.test.ts +87 -0
  175. package/tests/core/init-v1.3.test.ts +46 -0
  176. package/tests/core/init.test.ts +190 -0
  177. package/tests/core/local-worker-routing.test.ts +757 -0
  178. package/tests/core/migration.test.ts +84 -0
  179. package/tests/core/model-deployment-registry.test.ts +845 -0
  180. package/tests/core/model-training-registry.test.ts +889 -0
  181. package/tests/core/nocturnal-arbiter.test.ts +494 -0
  182. package/tests/core/nocturnal-candidate-scoring.test.ts +400 -0
  183. package/tests/core/nocturnal-compliance.test.ts +646 -0
  184. package/tests/core/nocturnal-dataset.test.ts +892 -0
  185. package/tests/core/nocturnal-executability.test.ts +357 -0
  186. package/tests/core/nocturnal-export.test.ts +462 -0
  187. package/tests/core/nocturnal-reviewed-subset-comparison.test.ts +428 -0
  188. package/tests/core/nocturnal-trajectory-extractor.test.ts +634 -0
  189. package/tests/core/nocturnal-trinity.test.ts +953 -0
  190. package/tests/core/pain.test.ts +33 -0
  191. package/tests/core/path-resolver.test.ts +57 -0
  192. package/tests/core/paths-refactor.test.ts +42 -0
  193. package/tests/core/phase7-rollout-integration.test.ts +477 -0
  194. package/tests/core/principle-training-state.test.ts +712 -0
  195. package/tests/core/profile.test.ts +56 -0
  196. package/tests/core/promotion-gate.test.ts +556 -0
  197. package/tests/core/risk-calculator.test.ts +168 -0
  198. package/tests/core/session-tracker.test.ts +191 -0
  199. package/tests/core/training-program.test.ts +472 -0
  200. package/tests/core/trajectory.test.ts +265 -0
  201. package/tests/core/workspace-context-factory.test.ts +18 -0
  202. package/tests/core/workspace-context.test.ts +134 -0
  203. package/tests/fixtures/nocturnal-reviewed-subset.json +183 -0
  204. package/tests/fixtures/production-compatibility.test.ts +147 -0
  205. package/tests/fixtures/production-mock-generator.ts +282 -0
  206. package/tests/hooks/bash-risk-integration.test.ts +137 -0
  207. package/tests/hooks/bash-risk.test.ts +81 -0
  208. package/tests/hooks/edit-verification.test.ts +678 -0
  209. package/tests/hooks/gate-edit-verification-p1.test.ts +632 -0
  210. package/tests/hooks/gate-edit-verification.test.ts +435 -0
  211. package/tests/hooks/gate-pipeline-integration.test.ts +404 -0
  212. package/tests/hooks/gate.test.ts +271 -0
  213. package/tests/hooks/gfi-gate-unit.test.ts +422 -0
  214. package/tests/hooks/gfi-gate.test.ts +669 -0
  215. package/tests/hooks/lifecycle.test.ts +248 -0
  216. package/tests/hooks/llm.test.ts +308 -0
  217. package/tests/hooks/message-sanitize.test.ts +36 -0
  218. package/tests/hooks/pain.test.ts +141 -0
  219. package/tests/hooks/progressive-trust-gate.test.ts +277 -0
  220. package/tests/hooks/prompt.test.ts +1411 -0
  221. package/tests/hooks/subagent.test.ts +467 -0
  222. package/tests/hooks/thinking-gate.test.ts +313 -0
  223. package/tests/http/principles-console-route.test.ts +140 -0
  224. package/tests/hygiene-tracker.test.ts +77 -0
  225. package/tests/index.integration.test.ts +179 -0
  226. package/tests/index.shadow-routing.integration.test.ts +140 -0
  227. package/tests/index.test.ts +9 -0
  228. package/tests/integration/empathy-workflow-integration.test.ts +627 -0
  229. package/tests/service/control-ui-query-service.test.ts +121 -0
  230. package/tests/service/empathy-observer-workflow-manager.test.ts +176 -0
  231. package/tests/service/evolution-worker.test.ts +585 -0
  232. package/tests/service/nocturnal-runtime.test.ts +470 -0
  233. package/tests/service/nocturnal-service.test.ts +577 -0
  234. package/tests/service/nocturnal-target-selector.test.ts +615 -0
  235. package/tests/service/nocturnal-workflow-manager.test.ts +439 -0
  236. package/tests/service/phase3-input-filter.test.ts +289 -0
  237. package/tests/service/runtime-summary-service.test.ts +919 -0
  238. package/tests/task-compliance.test.ts +166 -0
  239. package/tests/test-utils.ts +48 -0
  240. package/tests/tools/critique-prompt.test.ts +260 -0
  241. package/tests/tools/deep-reflect.test.ts +232 -0
  242. package/tests/tools/model-index.test.ts +246 -0
  243. package/tests/ui/app.test.tsx +114 -0
  244. package/tests/utils/file-lock.test.ts +407 -0
  245. package/tests/utils/hashing.test.ts +32 -0
  246. package/tests/utils/io.test.ts +39 -0
  247. package/tests/utils/nlp.test.ts +53 -0
  248. package/tests/utils/plugin-logger.test.ts +156 -0
  249. package/tsconfig.json +16 -0
  250. package/tsconfig.tsbuildinfo +1 -0
  251. package/ui/src/App.tsx +45 -0
  252. package/ui/src/api.ts +216 -0
  253. package/ui/src/charts.tsx +586 -0
  254. package/ui/src/components/ErrorState.tsx +6 -0
  255. package/ui/src/components/Loading.tsx +13 -0
  256. package/ui/src/components/ProtectedRoute.tsx +12 -0
  257. package/ui/src/components/Shell.tsx +91 -0
  258. package/ui/src/components/WorkspaceConfig.tsx +146 -0
  259. package/ui/src/components/index.ts +5 -0
  260. package/ui/src/context/auth.tsx +80 -0
  261. package/ui/src/context/theme.tsx +66 -0
  262. package/ui/src/hooks/useAutoRefresh.ts +39 -0
  263. package/ui/src/i18n/ui.ts +363 -0
  264. package/ui/src/main.tsx +16 -0
  265. package/ui/src/pages/EvolutionPage.tsx +352 -0
  266. package/ui/src/pages/FeedbackPage.tsx +140 -0
  267. package/ui/src/pages/GateMonitorPage.tsx +136 -0
  268. package/ui/src/pages/LoginPage.tsx +88 -0
  269. package/ui/src/pages/OverviewPage.tsx +238 -0
  270. package/ui/src/pages/SamplesPage.tsx +174 -0
  271. package/ui/src/pages/ThinkingModelsPage.tsx +127 -0
  272. package/ui/src/styles.css +1661 -0
  273. package/ui/src/types.ts +368 -0
  274. package/ui/src/utils/format.ts +15 -0
  275. package/vitest.config.ts +23 -0
  276. package/dist/commands/capabilities.d.ts +0 -3
  277. package/dist/commands/capabilities.js +0 -73
  278. package/dist/commands/context.d.ts +0 -5
  279. package/dist/commands/evolution-status.d.ts +0 -4
  280. package/dist/commands/evolution-status.js +0 -117
  281. package/dist/commands/evolver.d.ts +0 -9
  282. package/dist/commands/evolver.js +0 -26
  283. package/dist/commands/export.d.ts +0 -2
  284. package/dist/commands/export.js +0 -98
  285. package/dist/commands/focus.d.ts +0 -14
  286. package/dist/commands/focus.js +0 -457
  287. package/dist/commands/nocturnal-review.d.ts +0 -24
  288. package/dist/commands/nocturnal-review.js +0 -265
  289. package/dist/commands/nocturnal-rollout.d.ts +0 -27
  290. package/dist/commands/nocturnal-rollout.js +0 -671
  291. package/dist/commands/nocturnal-train.d.ts +0 -25
  292. package/dist/commands/nocturnal-train.js +0 -919
  293. package/dist/commands/pain.d.ts +0 -5
  294. package/dist/commands/principle-rollback.d.ts +0 -4
  295. package/dist/commands/principle-rollback.js +0 -22
  296. package/dist/commands/rollback.d.ts +0 -19
  297. package/dist/commands/samples.d.ts +0 -2
  298. package/dist/commands/samples.js +0 -55
  299. package/dist/commands/strategy.d.ts +0 -3
  300. package/dist/commands/strategy.js +0 -29
  301. package/dist/commands/thinking-os.d.ts +0 -2
  302. package/dist/config/defaults/runtime.d.ts +0 -40
  303. package/dist/config/errors.d.ts +0 -84
  304. package/dist/config/errors.js +0 -94
  305. package/dist/config/index.js +0 -7
  306. package/dist/constants/diagnostician.d.ts +0 -12
  307. package/dist/constants/diagnostician.js +0 -56
  308. package/dist/constants/tools.d.ts +0 -17
  309. package/dist/constants/tools.js +0 -54
  310. package/dist/core/adaptive-thresholds.d.ts +0 -186
  311. package/dist/core/adaptive-thresholds.js +0 -300
  312. package/dist/core/config-service.d.ts +0 -15
  313. package/dist/core/config.d.ts +0 -127
  314. package/dist/core/control-ui-db.d.ts +0 -95
  315. package/dist/core/control-ui-db.js +0 -292
  316. package/dist/core/detection-funnel.d.ts +0 -33
  317. package/dist/core/detection-service.d.ts +0 -15
  318. package/dist/core/dictionary-service.d.ts +0 -15
  319. package/dist/core/dictionary.d.ts +0 -38
  320. package/dist/core/event-log.d.ts +0 -82
  321. package/dist/core/event-log.js +0 -463
  322. package/dist/core/evolution-engine.d.ts +0 -118
  323. package/dist/core/evolution-engine.js +0 -464
  324. package/dist/core/evolution-logger.d.ts +0 -137
  325. package/dist/core/evolution-logger.js +0 -256
  326. package/dist/core/evolution-migration.d.ts +0 -5
  327. package/dist/core/evolution-migration.js +0 -65
  328. package/dist/core/evolution-reducer.d.ts +0 -98
  329. package/dist/core/evolution-reducer.js +0 -465
  330. package/dist/core/evolution-types.d.ts +0 -287
  331. package/dist/core/evolution-types.js +0 -78
  332. package/dist/core/external-training-contract.d.ts +0 -276
  333. package/dist/core/external-training-contract.js +0 -269
  334. package/dist/core/focus-history.d.ts +0 -210
  335. package/dist/core/focus-history.js +0 -1185
  336. package/dist/core/hygiene/tracker.d.ts +0 -22
  337. package/dist/core/hygiene/tracker.js +0 -106
  338. package/dist/core/init.d.ts +0 -12
  339. package/dist/core/local-worker-routing.d.ts +0 -175
  340. package/dist/core/local-worker-routing.js +0 -525
  341. package/dist/core/migration.d.ts +0 -6
  342. package/dist/core/model-deployment-registry.d.ts +0 -218
  343. package/dist/core/model-deployment-registry.js +0 -503
  344. package/dist/core/model-training-registry.d.ts +0 -295
  345. package/dist/core/model-training-registry.js +0 -475
  346. package/dist/core/nocturnal-arbiter.d.ts +0 -159
  347. package/dist/core/nocturnal-arbiter.js +0 -534
  348. package/dist/core/nocturnal-candidate-scoring.d.ts +0 -137
  349. package/dist/core/nocturnal-candidate-scoring.js +0 -266
  350. package/dist/core/nocturnal-compliance.d.ts +0 -175
  351. package/dist/core/nocturnal-compliance.js +0 -824
  352. package/dist/core/nocturnal-dataset.d.ts +0 -224
  353. package/dist/core/nocturnal-dataset.js +0 -443
  354. package/dist/core/nocturnal-executability.d.ts +0 -85
  355. package/dist/core/nocturnal-executability.js +0 -331
  356. package/dist/core/nocturnal-export.d.ts +0 -124
  357. package/dist/core/nocturnal-export.js +0 -275
  358. package/dist/core/nocturnal-paths.d.ts +0 -124
  359. package/dist/core/nocturnal-trajectory-extractor.d.ts +0 -242
  360. package/dist/core/nocturnal-trajectory-extractor.js +0 -307
  361. package/dist/core/nocturnal-trinity.d.ts +0 -311
  362. package/dist/core/nocturnal-trinity.js +0 -880
  363. package/dist/core/pain.d.ts +0 -4
  364. package/dist/core/pain.js +0 -70
  365. package/dist/core/path-resolver.d.ts +0 -46
  366. package/dist/core/paths.d.ts +0 -65
  367. package/dist/core/principle-training-state.d.ts +0 -121
  368. package/dist/core/principle-training-state.js +0 -321
  369. package/dist/core/profile.d.ts +0 -62
  370. package/dist/core/profile.js +0 -210
  371. package/dist/core/promotion-gate.d.ts +0 -238
  372. package/dist/core/promotion-gate.js +0 -529
  373. package/dist/core/risk-calculator.d.ts +0 -22
  374. package/dist/core/session-tracker.d.ts +0 -99
  375. package/dist/core/shadow-observation-registry.d.ts +0 -217
  376. package/dist/core/shadow-observation-registry.js +0 -308
  377. package/dist/core/system-logger.d.ts +0 -8
  378. package/dist/core/thinking-models.d.ts +0 -38
  379. package/dist/core/thinking-models.js +0 -170
  380. package/dist/core/training-program.d.ts +0 -233
  381. package/dist/core/training-program.js +0 -433
  382. package/dist/core/trajectory.d.ts +0 -411
  383. package/dist/core/trajectory.js +0 -1307
  384. package/dist/core/workspace-context.d.ts +0 -71
  385. package/dist/hooks/bash-risk.d.ts +0 -57
  386. package/dist/hooks/bash-risk.js +0 -137
  387. package/dist/hooks/edit-verification.d.ts +0 -62
  388. package/dist/hooks/edit-verification.js +0 -256
  389. package/dist/hooks/gate-block-helper.d.ts +0 -44
  390. package/dist/hooks/gate-block-helper.js +0 -119
  391. package/dist/hooks/gate.d.ts +0 -24
  392. package/dist/hooks/gate.js +0 -173
  393. package/dist/hooks/gfi-gate.d.ts +0 -40
  394. package/dist/hooks/gfi-gate.js +0 -113
  395. package/dist/hooks/lifecycle.d.ts +0 -5
  396. package/dist/hooks/lifecycle.js +0 -284
  397. package/dist/hooks/llm.d.ts +0 -12
  398. package/dist/hooks/message-sanitize.d.ts +0 -3
  399. package/dist/hooks/message-sanitize.js +0 -37
  400. package/dist/hooks/pain.d.ts +0 -5
  401. package/dist/hooks/pain.js +0 -301
  402. package/dist/hooks/progressive-trust-gate.d.ts +0 -51
  403. package/dist/hooks/progressive-trust-gate.js +0 -89
  404. package/dist/hooks/prompt.d.ts +0 -47
  405. package/dist/hooks/prompt.js +0 -884
  406. package/dist/hooks/subagent.d.ts +0 -10
  407. package/dist/hooks/subagent.js +0 -387
  408. package/dist/hooks/thinking-checkpoint.d.ts +0 -37
  409. package/dist/hooks/thinking-checkpoint.js +0 -51
  410. package/dist/hooks/trajectory-collector.d.ts +0 -32
  411. package/dist/hooks/trajectory-collector.js +0 -256
  412. package/dist/http/principles-console-route.d.ts +0 -9
  413. package/dist/http/principles-console-route.js +0 -567
  414. package/dist/i18n/commands.d.ts +0 -26
  415. package/dist/i18n/commands.js +0 -116
  416. package/dist/index.d.ts +0 -7
  417. package/dist/index.js +0 -581
  418. package/dist/service/central-database.d.ts +0 -104
  419. package/dist/service/central-database.js +0 -649
  420. package/dist/service/control-ui-query-service.d.ts +0 -221
  421. package/dist/service/control-ui-query-service.js +0 -543
  422. package/dist/service/empathy-observer-manager.d.ts +0 -52
  423. package/dist/service/empathy-observer-manager.js +0 -229
  424. package/dist/service/evolution-query-service.d.ts +0 -155
  425. package/dist/service/evolution-query-service.js +0 -258
  426. package/dist/service/evolution-worker.d.ts +0 -101
  427. package/dist/service/evolution-worker.js +0 -974
  428. package/dist/service/nocturnal-runtime.d.ts +0 -183
  429. package/dist/service/nocturnal-service.d.ts +0 -163
  430. package/dist/service/nocturnal-service.js +0 -787
  431. package/dist/service/nocturnal-target-selector.d.ts +0 -145
  432. package/dist/service/nocturnal-target-selector.js +0 -315
  433. package/dist/service/phase3-input-filter.d.ts +0 -73
  434. package/dist/service/phase3-input-filter.js +0 -172
  435. package/dist/service/runtime-summary-service.d.ts +0 -122
  436. package/dist/service/runtime-summary-service.js +0 -485
  437. package/dist/service/trajectory-service.d.ts +0 -2
  438. package/dist/service/trajectory-service.js +0 -15
  439. package/dist/tools/critique-prompt.d.ts +0 -14
  440. package/dist/tools/deep-reflect.d.ts +0 -39
  441. package/dist/tools/deep-reflect.js +0 -350
  442. package/dist/tools/model-index.d.ts +0 -9
  443. package/dist/types/event-types.d.ts +0 -306
  444. package/dist/types/event-types.js +0 -106
  445. package/dist/types/hygiene-types.d.ts +0 -20
  446. package/dist/types/hygiene-types.js +0 -12
  447. package/dist/types/runtime-summary.d.ts +0 -47
  448. package/dist/types/runtime-summary.js +0 -1
  449. package/dist/types.d.ts +0 -50
  450. package/dist/types.js +0 -22
  451. package/dist/utils/file-lock.d.ts +0 -71
  452. package/dist/utils/file-lock.js +0 -309
  453. package/dist/utils/glob-match.d.ts +0 -28
  454. package/dist/utils/hashing.d.ts +0 -9
  455. package/dist/utils/io.d.ts +0 -6
  456. package/dist/utils/io.js +0 -106
  457. package/dist/utils/nlp.d.ts +0 -9
  458. package/dist/utils/plugin-logger.d.ts +0 -39
  459. package/dist/utils/subagent-probe.d.ts +0 -34
  460. package/dist/utils/subagent-probe.js +0 -81
@@ -0,0 +1,856 @@
1
+ /**
2
+ * NocturnalWorkflowManager — WorkflowManager interface for Nocturnal Reflection
3
+ * =============================================================================
4
+ *
5
+ * PURPOSE: Wraps OpenClawTrinityRuntimeAdapter in the WorkflowManager interface.
6
+ * Single-reflector path only (useTrinity=false). Trinity multi-stage chain comes
7
+ * in Phase 7.
8
+ *
9
+ * DESIGN:
10
+ * - NocturnalWorkflowManager calls executeNocturnalReflectionAsync synchronously
11
+ * within startWorkflow. There is no wait polling path.
12
+ * - All 5 nocturnal event types are recorded: nocturnal_started, nocturnal_completed,
13
+ * nocturnal_failed, nocturnal_fallback, nocturnal_expired.
14
+ * - sweepExpiredWorkflows marks expired workflows and cleans partial artifact files.
15
+ * - notifyWaitResult and notifyLifecycleEvent are no-ops per D-10.
16
+ *
17
+ * PHASE: Phase 6 — Foundation and Single-Reflector Mode
18
+ */
19
+
20
+ import type { PluginLogger } from '../../openclaw-sdk.js';
21
+ import type {
22
+ WorkflowManager,
23
+ WorkflowHandle,
24
+ SubagentWorkflowSpec,
25
+ WorkflowMetadata,
26
+ WorkflowDebugSummary,
27
+ WorkflowResultContext,
28
+ WorkflowPersistContext,
29
+ WorkflowEventRow,
30
+ } from './types.js';
31
+ import { WorkflowStore } from './workflow-store.js';
32
+ import { resolveNocturnalDir } from '../../core/nocturnal-paths.js';
33
+ import {
34
+ executeNocturnalReflectionAsync,
35
+ type NocturnalRunResult,
36
+ } from '../nocturnal-service.js';
37
+ import { type TrinityStageFailure, type TrinityResult } from '../../core/nocturnal-trinity.js';
38
+ import type { TrinityRuntimeAdapter, TrinityConfig, DreamerOutput, PhilosopherOutput, TrinityTelemetry } from '../../core/nocturnal-trinity.js';
39
+ import type { NocturnalSessionSnapshot } from '../../core/nocturnal-trajectory-extractor.js';
40
+ import { createHash } from 'crypto';
41
+ import * as fs from 'fs';
42
+ import * as path from 'path';
43
+
44
+ // ─────────────────────────────────────────────────────────────────────────────
45
+ // NocturnalResult Type Alias
46
+ // ─────────────────────────────────────────────────────────────────────────────
47
+
48
+ /**
49
+ * Nocturnal workflow result type (mirrors NocturnalRunResult per D-02).
50
+ * This is the result type returned by executeNocturnalReflectionAsync.
51
+ */
52
+ export type NocturnalResult = NocturnalRunResult;
53
+
54
+ // ─────────────────────────────────────────────────────────────────────────────
55
+ // Idempotency Key Computation (D-18)
56
+ // ─────────────────────────────────────────────────────────────────────────────
57
+
58
+ /**
59
+ * Compute idempotency key for the Dreamer stage (D-18).
60
+ * Key = SHA-256(workflowId + stage + inputDigest)
61
+ * inputDigest = SHA-256(snapshot.sessionId + principleId + maxCandidates)
62
+ * Uses simple concatenation (no delimiters) per D-18 spec.
63
+ */
64
+ function computeDreamerIdempotencyKey(
65
+ workflowId: string,
66
+ snapshot: import('../../core/nocturnal-trajectory-extractor.js').NocturnalSessionSnapshot,
67
+ principleId: string,
68
+ maxCandidates: number
69
+ ): string {
70
+ // Use delimiters to prevent collision (e.g., "sess10"+"2"+"3" vs "sess1"+"02"+"3")
71
+ const inputDigest = createHash('sha256')
72
+ .update(`${snapshot.sessionId}::${principleId}::${maxCandidates}`)
73
+ .digest('hex');
74
+ return createHash('sha256')
75
+ .update(`${workflowId}::dreamer::${inputDigest}`)
76
+ .digest('hex');
77
+ }
78
+
79
+ /**
80
+ * Compute idempotency key for the Philosopher stage (D-18).
81
+ * Key = SHA-256(workflowId + stage + inputDigest)
82
+ * inputDigest = SHA-256(workflowId + dreamerOutputJson)
83
+ * Uses simple concatenation (no delimiters) per D-18 spec.
84
+ */
85
+ function computePhilosopherIdempotencyKey(
86
+ workflowId: string,
87
+ dreamerOutput: import('../../core/nocturnal-trinity.js').DreamerOutput
88
+ ): string {
89
+ const dreamerOutputJson = JSON.stringify(dreamerOutput);
90
+ const inputDigest = createHash('sha256')
91
+ .update(workflowId + dreamerOutputJson)
92
+ .digest('hex');
93
+ return createHash('sha256')
94
+ .update(workflowId + 'philosopher' + inputDigest)
95
+ .digest('hex');
96
+ }
97
+
98
+ // ─────────────────────────────────────────────────────────────────────────────
99
+ // NocturnalWorkflowOptions
100
+ // ─────────────────────────────────────────────────────────────────────────────
101
+
102
+ export interface NocturnalWorkflowOptions {
103
+ /** Workspace directory for artifact storage */
104
+ workspaceDir: string;
105
+ /** State directory for nocturnal runtime bookkeeping */
106
+ stateDir: string;
107
+ /** Plugin logger */
108
+ logger: PluginLogger;
109
+ /** Trinity runtime adapter for subagent execution */
110
+ runtimeAdapter: TrinityRuntimeAdapter;
111
+ }
112
+
113
+ // ─────────────────────────────────────────────────────────────────────────────
114
+ // NocturnalWorkflowSpec
115
+ // ─────────────────────────────────────────────────────────────────────────────
116
+
117
+ /**
118
+ * Nocturnal workflow specification.
119
+ * Drives NocturnalWorkflowManager for the nocturnal reflection workflow.
120
+ *
121
+ * Per D-07, D-08, D-09, D-03, D-04:
122
+ * - workflowType: 'nocturnal'
123
+ * - transport: 'runtime_direct'
124
+ * - shouldDeleteSessionAfterFinalize: false (no external session to delete)
125
+ * - timeoutMs: 15 minutes (900000ms)
126
+ * - ttlMs: 30 minutes (1800000ms)
127
+ */
128
+ export const nocturnalWorkflowSpec: SubagentWorkflowSpec<NocturnalResult> = {
129
+ workflowType: 'nocturnal',
130
+ transport: 'runtime_direct',
131
+ timeoutMs: 15 * 60 * 1000, // D-03: 15 minutes
132
+ ttlMs: 30 * 60 * 1000, // D-04: 30 minutes
133
+ shouldDeleteSessionAfterFinalize: false, // D-09: no external session to delete
134
+
135
+ buildPrompt(_taskInput: unknown, _metadata: WorkflowMetadata): string {
136
+ // NocturnalWorkflowManager does not use prompt injection.
137
+ // Execution is driven by executeNocturnalReflectionAsync.
138
+ return '';
139
+ },
140
+
141
+ async parseResult(ctx: WorkflowResultContext): Promise<NocturnalResult | null> {
142
+ // NocturnalWorkflowManager handles execution directly in startWorkflow.
143
+ // This is not called via the standard subagent message path.
144
+ return (ctx.metadata['nocturnalResult'] as NocturnalResult) ?? null;
145
+ },
146
+
147
+ async persistResult(_ctx: WorkflowPersistContext<NocturnalResult>): Promise<void> {
148
+ // Artifact persistence is handled in startWorkflow after
149
+ // executeNocturnalReflectionAsync returns. The artifact is already
150
+ // persisted by the service; nothing more needed here.
151
+ },
152
+
153
+ shouldFinalizeOnWaitStatus(status: 'ok' | 'error' | 'timeout'): boolean {
154
+ return status === 'ok';
155
+ },
156
+ };
157
+
158
+ // ─────────────────────────────────────────────────────────────────────────────
159
+ // Stub Fallback Runtime Adapter (NOC-15)
160
+ // ─────────────────────────────────────────────────────────────────────────────
161
+
162
+ /**
163
+ * Stub fallback runtime adapter for Trinity.
164
+ * Wraps a real adapter and provides stub implementations for fallback when stages fail.
165
+ * Per NOC-15: Fallback degrades to stub, NOT to EmpathyObserver/DeepReflect.
166
+ */
167
+ class StubFallbackRuntimeAdapter implements TrinityRuntimeAdapter {
168
+ constructor(
169
+ private snapshot: NocturnalSessionSnapshot,
170
+ private principleId: string,
171
+ private maxCandidates: number
172
+ ) {}
173
+
174
+ async invokeDreamer(
175
+ snapshot: NocturnalSessionSnapshot,
176
+ principleId: string,
177
+ maxCandidates: number
178
+ ): Promise<DreamerOutput> {
179
+ const { invokeStubDreamer } = await import('../../core/nocturnal-trinity.js');
180
+ return invokeStubDreamer(snapshot, principleId, maxCandidates);
181
+ }
182
+
183
+ async invokePhilosopher(
184
+ dreamerOutput: DreamerOutput,
185
+ principleId: string
186
+ ): Promise<PhilosopherOutput> {
187
+ const { invokeStubPhilosopher } = await import('../../core/nocturnal-trinity.js');
188
+ return invokeStubPhilosopher(dreamerOutput, principleId);
189
+ }
190
+
191
+ async invokeScribe(
192
+ dreamerOutput: DreamerOutput,
193
+ philosopherOutput: PhilosopherOutput,
194
+ snapshot: NocturnalSessionSnapshot,
195
+ principleId: string,
196
+ telemetry: TrinityTelemetry,
197
+ config: TrinityConfig
198
+ ): Promise<import('../../core/nocturnal-trinity.js').TrinityDraftArtifact | null> {
199
+ // Use stub Scribe
200
+ const { invokeStubScribe } = await import('../../core/nocturnal-trinity.js');
201
+ return invokeStubScribe(dreamerOutput, philosopherOutput, snapshot, principleId, telemetry, config);
202
+ }
203
+
204
+ async close(): Promise<void> {
205
+ // No-op for stubs
206
+ }
207
+ }
208
+
209
+ // ─────────────────────────────────────────────────────────────────────────────
210
+ // NocturnalWorkflowManager
211
+ // ─────────────────────────────────────────────────────────────────────────────
212
+
213
+ /**
214
+ * NocturnalWorkflowManager — implements WorkflowManager for nocturnal reflection.
215
+ *
216
+ * Single-reflector path (useTrinity=false) only in Phase 6.
217
+ * Trinity multi-stage chain (Dreamer→Philosopher→Scribe) comes in Phase 7.
218
+ *
219
+ * Key behaviors:
220
+ * - startWorkflow calls executeNocturnalReflectionAsync with useTrinity=false
221
+ * - Records all 5 nocturnal event types to WorkflowStore
222
+ * - notifyWaitResult and notifyLifecycleEvent are no-ops
223
+ * - sweepExpiredWorkflows marks expired workflows and cleans partial artifacts
224
+ */
225
+ export class NocturnalWorkflowManager implements WorkflowManager {
226
+ private readonly workspaceDir: string;
227
+ private readonly stateDir: string;
228
+ private readonly logger: PluginLogger;
229
+ private readonly runtimeAdapter: TrinityRuntimeAdapter;
230
+ private readonly store: WorkflowStore;
231
+
232
+ /** Tracks completion timestamps for idempotency */
233
+ private completedWorkflows = new Map<string, number>();
234
+ /** Maps workflowId → spec (needed for finalizeOnce) */
235
+ private workflowSpecs = new Map<string, SubagentWorkflowSpec<unknown>>();
236
+ /** Maps workflowId → result (needed for finalizeOnce) */
237
+ private executionResults = new Map<string, NocturnalResult>();
238
+ /** Maps workflowId → TrinityStageFailure[] (stored before async launch, used in notifyWaitResult) */
239
+ private pendingTrinityFailures = new Map<string, TrinityStageFailure[]>();
240
+ /** Maps workflowId → TrinityResult (needed by notifyWaitResult for artifact persistence) */
241
+ private pendingTrinityResults = new Map<string, TrinityResult>();
242
+
243
+ constructor(opts: NocturnalWorkflowOptions) {
244
+ this.workspaceDir = opts.workspaceDir;
245
+ this.stateDir = opts.stateDir;
246
+ this.logger = opts.logger;
247
+ this.runtimeAdapter = opts.runtimeAdapter;
248
+ this.store = new WorkflowStore({ workspaceDir: opts.workspaceDir });
249
+ }
250
+
251
+ // ─────────────────────────────────────────────────────────────────────────
252
+ // WorkflowManager Interface: startWorkflow (NOC-01, NOC-02, NOC-03)
253
+ // ─────────────────────────────────────────────────────────────────────────
254
+
255
+ async startWorkflow<TResult>(
256
+ spec: SubagentWorkflowSpec<TResult>,
257
+ options: {
258
+ parentSessionId: string;
259
+ workspaceDir?: string;
260
+ taskInput: unknown;
261
+ metadata?: Record<string, unknown>;
262
+ }
263
+ ): Promise<WorkflowHandle> {
264
+ const workflowId = this.generateWorkflowId();
265
+ const now = Date.now();
266
+
267
+ const metadata: WorkflowMetadata = {
268
+ parentSessionId: options.parentSessionId,
269
+ workspaceDir: options.workspaceDir,
270
+ taskInput: options.taskInput,
271
+ startedAt: now,
272
+ workflowType: spec.workflowType,
273
+ ...options.metadata,
274
+ };
275
+
276
+ this.logger.info(`[PD:NocturnalWorkflow] Starting workflow: workflowId=${workflowId}, type=${spec.workflowType}`);
277
+
278
+ // Record nocturnal_started event (NOC-03)
279
+ this.store.createWorkflow({
280
+ workflow_id: workflowId,
281
+ workflow_type: spec.workflowType,
282
+ transport: spec.transport,
283
+ parent_session_id: options.parentSessionId,
284
+ child_session_key: `nocturnal:internal:${workflowId}`, // D-10: placeholder since adapter manages sessions internally
285
+ run_id: null,
286
+ state: 'active',
287
+ created_at: now,
288
+ updated_at: now,
289
+ metadata_json: JSON.stringify(metadata),
290
+ });
291
+ this.store.recordEvent(workflowId, 'nocturnal_started', null, 'active', 'TrinityRuntimeAdapter invoked', { workflowType: 'nocturnal' });
292
+
293
+ // Extract snapshot and principleId from taskInput.metadata (NOC-07: Trinity async path)
294
+ const snapshot = options.metadata?.snapshot as import('../../core/nocturnal-trajectory-extractor.js').NocturnalSessionSnapshot | undefined;
295
+ const principleId = options.metadata?.principleId as string | undefined;
296
+
297
+ // Validate required metadata (prevent runtime crashes from undefined snapshot)
298
+ if (!snapshot?.sessionId) {
299
+ this.logger.warn(`[PD:NocturnalWorkflow] Missing snapshot.sessionId in metadata for workflow=${workflowId}, terminating`);
300
+ this.store.recordEvent(workflowId, 'nocturnal_failed', null, 'terminal_error', 'Missing required metadata: snapshot.sessionId', { workflowId });
301
+ return {
302
+ workflowId,
303
+ childSessionKey: `nocturnal:internal:${workflowId}`,
304
+ state: 'terminal_error' as const,
305
+ };
306
+ }
307
+ if (!principleId) {
308
+ this.logger.warn(`[PD:NocturnalWorkflow] Missing principleId in metadata for workflow=${workflowId}, terminating`);
309
+ this.store.recordEvent(workflowId, 'nocturnal_failed', null, 'terminal_error', 'Missing required metadata: principleId', { workflowId });
310
+ return {
311
+ workflowId,
312
+ childSessionKey: `nocturnal:internal:${workflowId}`,
313
+ state: 'terminal_error' as const,
314
+ };
315
+ }
316
+
317
+ // Configure Trinity for async execution (NOC-06, NOC-07)
318
+ const trinityConfig: TrinityConfig = {
319
+ useTrinity: true, // NOC-07: Trinity chain, not single-reflector
320
+ maxCandidates: 3,
321
+ useStubs: false,
322
+ runtimeAdapter: this.runtimeAdapter,
323
+ stateDir: this.stateDir,
324
+ };
325
+
326
+ // Create mutable telemetry object (passed to invokeScribe and mutated)
327
+ const telemetry: TrinityTelemetry = {
328
+ chainMode: 'trinity',
329
+ usedStubs: false,
330
+ dreamerPassed: false,
331
+ philosopherPassed: false,
332
+ scribePassed: false,
333
+ candidateCount: 0,
334
+ selectedCandidateIndex: -1,
335
+ stageFailures: [],
336
+ };
337
+
338
+ // NOC-07: Launch Trinity async via Promise.resolve().then() WITHOUT awaiting
339
+ // This offloads the async chain so startWorkflow returns immediately with state='active'
340
+ Promise.resolve().then(async () => {
341
+ try {
342
+ // NOC-15: Track if stub fallback was used
343
+ let fallbackUsed = false;
344
+
345
+ // Step 1: Crash recovery — check for existing stage outputs (NOC-13)
346
+ // Query WorkflowStore for any existing outputs for this workflowId
347
+ const existingOutputs = this.store.getStageOutputs(workflowId);
348
+ const recoveredDreamerOutput = existingOutputs.find(o => o.stage === 'dreamer')?.output as DreamerOutput | undefined;
349
+ const recoveredPhilosopherOutput = existingOutputs.find(o => o.stage === 'philosopher')?.output as PhilosopherOutput | undefined;
350
+
351
+ let dreamerOutput: DreamerOutput;
352
+ let philosopherOutput: PhilosopherOutput;
353
+
354
+ // Step 2: Dreamer — skip if recovered (NOC-12 idempotency)
355
+ if (recoveredDreamerOutput) {
356
+ this.logger.info(`[PD:NocturnalWorkflow] Recovered Dreamer output for workflow=${workflowId}, skipping Dreamer stage`);
357
+ dreamerOutput = recoveredDreamerOutput;
358
+ } else {
359
+ // Compute idempotency key BEFORE calling invokeDreamer
360
+ const dreamerIdemKey = computeDreamerIdempotencyKey(workflowId, snapshot, principleId, trinityConfig.maxCandidates);
361
+
362
+ // Check idempotency — another concurrent run may have completed this stage
363
+ const existingDreamerByKey = this.store.getStageOutputByKey(dreamerIdemKey);
364
+ if (existingDreamerByKey) {
365
+ this.logger.info(`[PD:NocturnalWorkflow] Found existing Dreamer output by idempotency key for workflow=${workflowId}`);
366
+ dreamerOutput = existingDreamerByKey.output as DreamerOutput;
367
+ } else {
368
+ dreamerOutput = await this.runtimeAdapter.invokeDreamer(snapshot, principleId, trinityConfig.maxCandidates);
369
+ // NOC-15: Fallback to stub Dreamer if real Dreamer failed
370
+ if (!dreamerOutput.valid || dreamerOutput.candidates.length === 0) {
371
+ this.logger.info(`[PD:NocturnalWorkflow] Dreamer failed (${dreamerOutput.reason}), falling back to stub`);
372
+ fallbackUsed = true;
373
+ const stubAdapter = new StubFallbackRuntimeAdapter(
374
+ snapshot,
375
+ principleId,
376
+ trinityConfig.maxCandidates
377
+ );
378
+ dreamerOutput = await stubAdapter.invokeDreamer(snapshot, principleId, trinityConfig.maxCandidates);
379
+ }
380
+ // Persist Dreamer output (NOC-11)
381
+ if (dreamerOutput.valid) {
382
+ this.store.recordStageOutput(workflowId, 'dreamer', dreamerOutput, dreamerIdemKey);
383
+ }
384
+ }
385
+ }
386
+
387
+ // Step 3: Philosopher — skip if recovered (NOC-12 idempotency)
388
+ if (recoveredPhilosopherOutput) {
389
+ this.logger.info(`[PD:NocturnalWorkflow] Recovered Philosopher output for workflow=${workflowId}, skipping Philosopher stage`);
390
+ philosopherOutput = recoveredPhilosopherOutput;
391
+ } else {
392
+ // Compute idempotency key BEFORE calling invokePhilosopher
393
+ const philosopherIdemKey = computePhilosopherIdempotencyKey(workflowId, dreamerOutput);
394
+
395
+ // Check idempotency
396
+ const existingPhilosopherByKey = this.store.getStageOutputByKey(philosopherIdemKey);
397
+ if (existingPhilosopherByKey) {
398
+ this.logger.info(`[PD:NocturnalWorkflow] Found existing Philosopher output by idempotency key for workflow=${workflowId}`);
399
+ philosopherOutput = existingPhilosopherByKey.output as PhilosopherOutput;
400
+ } else {
401
+ philosopherOutput = await this.runtimeAdapter.invokePhilosopher(dreamerOutput, principleId);
402
+ // NOC-15: Fallback to stub Philosopher if real Philosopher failed
403
+ if (!philosopherOutput.valid || philosopherOutput.judgments.length === 0) {
404
+ this.logger.info(`[PD:NocturnalWorkflow] Philosopher failed (${philosopherOutput.reason}), falling back to stub`);
405
+ fallbackUsed = true;
406
+ const stubAdapter = new StubFallbackRuntimeAdapter(
407
+ snapshot,
408
+ principleId,
409
+ trinityConfig.maxCandidates
410
+ );
411
+ philosopherOutput = await stubAdapter.invokePhilosopher(dreamerOutput, principleId);
412
+ }
413
+ // Persist Philosopher output (NOC-11)
414
+ if (philosopherOutput.valid) {
415
+ this.store.recordStageOutput(workflowId, 'philosopher', philosopherOutput, philosopherIdemKey);
416
+ }
417
+ }
418
+ }
419
+
420
+ // Step 4: Scribe — always runs (no intermediate Scribe output to persist)
421
+ const draftArtifact = await this.runtimeAdapter.invokeScribe(
422
+ dreamerOutput,
423
+ philosopherOutput,
424
+ snapshot,
425
+ principleId,
426
+ telemetry,
427
+ trinityConfig
428
+ );
429
+
430
+ // Step 5: Build TrinityResult from stage outcomes
431
+ const failures: TrinityStageFailure[] = [];
432
+ if (!dreamerOutput.valid || dreamerOutput.candidates.length === 0) {
433
+ failures.push({ stage: 'dreamer', reason: dreamerOutput.reason ?? 'no valid candidates' });
434
+ }
435
+ if (!philosopherOutput.valid || philosopherOutput.judgments.length === 0) {
436
+ failures.push({ stage: 'philosopher', reason: philosopherOutput.reason ?? 'no judgments produced' });
437
+ }
438
+ if (!draftArtifact) {
439
+ failures.push({ stage: 'scribe', reason: 'Failed to synthesize artifact' });
440
+ }
441
+
442
+ const trinityResult: TrinityResult = {
443
+ success: failures.length === 0 && !!draftArtifact,
444
+ artifact: draftArtifact ?? undefined,
445
+ telemetry: {
446
+ chainMode: 'trinity',
447
+ usedStubs: fallbackUsed, // NOC-15: reflect actual stub usage
448
+ dreamerPassed: dreamerOutput.valid && dreamerOutput.candidates.length > 0,
449
+ philosopherPassed: philosopherOutput.valid && philosopherOutput.judgments.length > 0,
450
+ scribePassed: !!draftArtifact,
451
+ candidateCount: dreamerOutput.candidates.length,
452
+ selectedCandidateIndex: draftArtifact?.selectedCandidateIndex ?? -1,
453
+ stageFailures: failures.map(f => `${f.stage}: ${f.reason}`),
454
+ },
455
+ failures,
456
+ fallbackOccurred: fallbackUsed, // NOC-15: mark when fallback was triggered
457
+ };
458
+
459
+ // Store for notifyWaitResult and proceed with existing flow
460
+ this.pendingTrinityResults.set(workflowId, trinityResult);
461
+ this.pendingTrinityFailures.set(workflowId, failures);
462
+
463
+ // Record stage events (NOC-08, already implemented in Phase 07)
464
+ this.recordStageEvents(workflowId, trinityResult);
465
+
466
+ // Drive state transitions (NOC-10)
467
+ if (trinityResult.success) {
468
+ await this.notifyWaitResult(workflowId, 'ok');
469
+ } else {
470
+ const errorMsg = failures.map(f => `${f.stage}: ${f.reason}`).join('; ');
471
+ await this.notifyWaitResult(workflowId, 'error', errorMsg);
472
+ }
473
+ } catch (err) {
474
+ // Unexpected error - treat as Trinity failure
475
+ const errorMsg = err instanceof Error ? err.message : String(err);
476
+ this.pendingTrinityFailures.set(workflowId, [{ stage: 'dreamer' as const, reason: errorMsg }]);
477
+ await this.notifyWaitResult(workflowId, 'error', errorMsg);
478
+ }
479
+ });
480
+
481
+ // Return immediately with state='active' (NOC-07)
482
+ return {
483
+ workflowId,
484
+ childSessionKey: `nocturnal:internal:${workflowId}`,
485
+ runId: undefined,
486
+ state: 'active',
487
+ };
488
+ }
489
+
490
+ // ─────────────────────────────────────────────────────────────────────────
491
+ // WorkflowManager Interface: notifyWaitResult (NOC-01, D-10: no-op)
492
+ // ─────────────────────────────────────────────────────────────────────────
493
+
494
+ async notifyWaitResult(
495
+ workflowId: string,
496
+ status: 'ok' | 'error' | 'timeout',
497
+ error?: string
498
+ ): Promise<void> {
499
+ const workflow = this.store.getWorkflow(workflowId);
500
+ if (!workflow) {
501
+ this.logger.warn(`[PD:NocturnalWorkflow] notifyWaitResult: workflow not found: ${workflowId}`);
502
+ return;
503
+ }
504
+
505
+ // Only handle workflows in 'active' state (Trinity async path)
506
+ if (workflow.state !== 'active') {
507
+ this.logger.info(`[PD:NocturnalWorkflow] notifyWaitResult: workflow ${workflowId} not in active state: ${workflow.state}`);
508
+ return;
509
+ }
510
+
511
+ const trinityFailures = this.pendingTrinityFailures.get(workflowId) ?? [];
512
+ const trinityResult = this.pendingTrinityResults.get(workflowId);
513
+
514
+ if (status === 'ok') {
515
+ // Trinity succeeded: active -> finalizing -> completed (NOC-10)
516
+ this.store.updateWorkflowState(workflowId, 'finalizing');
517
+ this.store.recordEvent(workflowId, 'trinity_completed', 'active', 'finalizing', 'Trinity chain completed successfully', {
518
+ trinityTelemetry: trinityResult?.telemetry,
519
+ });
520
+
521
+ this.store.updateWorkflowState(workflowId, 'completed');
522
+ this.store.recordEvent(workflowId, 'nocturnal_completed', 'finalizing', 'completed', 'artifact persisted', {
523
+ persistedPath: trinityResult?.artifact ? 'trinity-draft' : undefined,
524
+ });
525
+ } else {
526
+ // Any stage failure: -> terminal_error immediately (NOC-09, NOC-10)
527
+ this.store.updateWorkflowState(workflowId, 'terminal_error');
528
+ this.store.recordEvent(workflowId, 'nocturnal_failed', 'active', 'terminal_error', error ?? 'Trinity stage failed', {
529
+ failures: trinityFailures, // NOC-09: TrinityStageFailure[] in payload
530
+ trinityTelemetry: trinityResult?.telemetry,
531
+ });
532
+ }
533
+
534
+ // Clean up pending state (idempotent - also cleaned in markCompleted)
535
+ this.pendingTrinityFailures.delete(workflowId);
536
+ this.pendingTrinityResults.delete(workflowId);
537
+ this.markCompleted(workflowId);
538
+ }
539
+
540
+ // ─────────────────────────────────────────────────────────────────────────
541
+ // WorkflowManager Interface: notifyLifecycleEvent (NOC-01, D-10: no-op)
542
+ // ─────────────────────────────────────────────────────────────────────────
543
+
544
+ async notifyLifecycleEvent(
545
+ _workflowId: string,
546
+ _event: 'subagent_spawned' | 'subagent_ended',
547
+ _data?: Record<string, unknown>
548
+ ): Promise<void> {
549
+ // D-10: No-op. NocturnalWorkflowManager does not use the wait-on-run pattern.
550
+ // TrinityRuntimeAdapter manages its own internal subagent lifecycle.
551
+ // No external subagent_spawned/subagent_ended events need to be tracked.
552
+ }
553
+
554
+ // ─────────────────────────────────────────────────────────────────────────
555
+ // WorkflowManager Interface: finalizeOnce (NOC-01)
556
+ // ─────────────────────────────────────────────────────────────────────────
557
+
558
+ async finalizeOnce(workflowId: string): Promise<void> {
559
+ const workflow = this.store.getWorkflow(workflowId);
560
+ if (!workflow) {
561
+ this.logger.warn(`[PD:NocturnalWorkflow] finalizeOnce: workflow not found: ${workflowId}`);
562
+ return;
563
+ }
564
+
565
+ if (this.isCompleted(workflowId)) {
566
+ this.logger.info(`[PD:NocturnalWorkflow] finalizeOnce: already completed: ${workflowId}`);
567
+ return;
568
+ }
569
+
570
+ // NocturnalWorkflowManager completes execution synchronously in startWorkflow.
571
+ // If we reach here, the workflow was already marked as completed/failed.
572
+ // Nothing more to do - result already persisted by executeNocturnalReflectionAsync.
573
+ this.logger.info(`[PD:NocturnalWorkflow] finalizeOnce: workflow already in terminal state: ${workflowId}, state=${workflow.state}`);
574
+ this.markCompleted(workflowId);
575
+ }
576
+
577
+ // ─────────────────────────────────────────────────────────────────────────
578
+ // WorkflowManager Interface: sweepExpiredWorkflows (NOC-05)
579
+ // ─────────────────────────────────────────────────────────────────────────
580
+
581
+ async sweepExpiredWorkflows(maxAgeMs = 30 * 60 * 1000): Promise<number> {
582
+ const expired = this.store.getExpiredWorkflows(maxAgeMs);
583
+
584
+ this.logger.info(`[PD:NocturnalWorkflow] sweepExpiredWorkflows: found ${expired.length} expired`);
585
+
586
+ for (const workflow of expired) {
587
+ try {
588
+ this.logger.info(`[PD:NocturnalWorkflow] Sweeping expired workflow: ${workflow.workflow_id}`);
589
+
590
+ // D-06: Mark as expired in WorkflowStore
591
+ this.store.updateWorkflowState(workflow.workflow_id, 'expired');
592
+ this.store.recordEvent(workflow.workflow_id, 'nocturnal_expired', workflow.state, 'expired', 'TTL expired', { workflowId: workflow.workflow_id });
593
+
594
+ // D-06: Clean partial artifact files by workflowId prefix
595
+ const samplesDir = resolveNocturnalDir(this.workspaceDir, 'SAMPLES');
596
+ if (fs.existsSync(samplesDir)) {
597
+ const files = fs.readdirSync(samplesDir).filter(f => f.includes(workflow.workflow_id));
598
+ for (const file of files) {
599
+ const filePath = path.join(samplesDir, file);
600
+ try {
601
+ fs.unlinkSync(filePath);
602
+ this.logger.info(`[PD:NocturnalWorkflow] Removed partial artifact: ${filePath}`);
603
+ } catch (unlinkErr) {
604
+ this.logger.warn(`[PD:NocturnalWorkflow] Failed to remove partial artifact ${filePath}: ${String(unlinkErr)}`);
605
+ }
606
+ }
607
+ }
608
+
609
+ } catch (error) {
610
+ this.logger.error(`[PD:NocturnalWorkflow] Sweep failed for ${workflow.workflow_id}: ${String(error)}`);
611
+ }
612
+ }
613
+
614
+ // Clean up memory Maps to prevent leaks
615
+ const cutoff = Date.now() - 60_000; // 1 minute dedup window
616
+ for (const [id, timestamp] of this.completedWorkflows) {
617
+ if (timestamp < cutoff) {
618
+ this.completedWorkflows.delete(id);
619
+ }
620
+ }
621
+
622
+ return expired.length;
623
+ }
624
+
625
+ // ─────────────────────────────────────────────────────────────────────────
626
+ // WorkflowManager Interface: getWorkflowDebugSummary (NOC-01)
627
+ // ─────────────────────────────────────────────────────────────────────────
628
+
629
+ async getWorkflowDebugSummary(workflowId: string, eventLimit = 10): Promise<WorkflowDebugSummary | null> {
630
+ const workflow = this.store.getWorkflow(workflowId);
631
+ if (!workflow) return null;
632
+
633
+ const metadata = JSON.parse(workflow.metadata_json) as WorkflowMetadata;
634
+ const allEvents = this.store.getEvents(workflowId);
635
+ const recentEvents = allEvents
636
+ .slice(-eventLimit)
637
+ .map((event) => ({
638
+ eventType: event.event_type,
639
+ fromState: event.from_state,
640
+ toState: event.to_state,
641
+ reason: event.reason,
642
+ createdAt: event.created_at,
643
+ payload: JSON.parse(event.payload_json || '{}') as Record<string, unknown>,
644
+ }));
645
+
646
+ // NOC-16: Compute Trinity stage states from events
647
+ const trinityStageStates = this.computeTrinityStageStates(allEvents);
648
+
649
+ return {
650
+ workflowId: workflow.workflow_id,
651
+ workflowType: workflow.workflow_type,
652
+ transport: workflow.transport,
653
+ parentSessionId: workflow.parent_session_id,
654
+ childSessionKey: workflow.child_session_key,
655
+ runId: workflow.run_id,
656
+ state: workflow.state,
657
+ cleanupState: workflow.cleanup_state,
658
+ lastObservedAt: workflow.last_observed_at ?? null,
659
+ metadata,
660
+ recentEvents,
661
+ trinityStageStates, // NOC-16
662
+ };
663
+ }
664
+
665
+ // ─────────────────────────────────────────────────────────────────────────
666
+ // WorkflowManager Interface: dispose (NOC-01)
667
+ // ─────────────────────────────────────────────────────────────────────────
668
+
669
+ dispose(): void {
670
+ this.store.dispose();
671
+ }
672
+
673
+ // ─────────────────────────────────────────────────────────────────────────
674
+ // Helper Methods
675
+ // ─────────────────────────────────────────────────────────────────────────
676
+
677
+ private generateWorkflowId(): string {
678
+ return `wf_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`;
679
+ }
680
+
681
+ private isCompleted(workflowId: string): boolean {
682
+ const timestamp = this.completedWorkflows.get(workflowId);
683
+ if (!timestamp) return false;
684
+ if (Date.now() - timestamp > 5 * 60 * 1000) {
685
+ this.completedWorkflows.delete(workflowId);
686
+ return false;
687
+ }
688
+ return true;
689
+ }
690
+
691
+ private markCompleted(workflowId: string): void {
692
+ this.completedWorkflows.set(workflowId, Date.now());
693
+ this.workflowSpecs.delete(workflowId);
694
+ this.executionResults.delete(workflowId);
695
+ this.pendingTrinityFailures.delete(workflowId);
696
+ this.pendingTrinityResults.delete(workflowId);
697
+ }
698
+
699
+ /**
700
+ * Compute Trinity stage states from workflow events (NOC-16).
701
+ * Derives current/completed/failed state for each Trinity stage.
702
+ */
703
+ private computeTrinityStageStates(events: WorkflowEventRow[]): Array<{
704
+ stage: 'dreamer' | 'philosopher' | 'scribe';
705
+ status: 'pending' | 'running' | 'completed' | 'failed';
706
+ reason?: string;
707
+ completedAt?: number;
708
+ }> {
709
+ const stages: Array<'dreamer' | 'philosopher' | 'scribe'> = ['dreamer', 'philosopher', 'scribe'];
710
+ const result: Array<{
711
+ stage: 'dreamer' | 'philosopher' | 'scribe';
712
+ status: 'pending' | 'running' | 'completed' | 'failed';
713
+ reason?: string;
714
+ completedAt?: number;
715
+ }> = [];
716
+
717
+ for (const stage of stages) {
718
+ const startEvent = events.find(e => e.event_type === `trinity_${stage}_start`);
719
+ const completeEvent = events.find(e => e.event_type === `trinity_${stage}_complete`);
720
+ const failedEvent = events.find(e => e.event_type === `trinity_${stage}_failed`);
721
+
722
+ if (!startEvent) {
723
+ // Stage never ran
724
+ result.push({ stage, status: 'pending' });
725
+ } else if (failedEvent) {
726
+ // Stage ran and failed
727
+ const payload = JSON.parse(failedEvent.payload_json || '{}') as Record<string, unknown>;
728
+ const failures = payload.failures as Array<{ reason?: string }> | undefined;
729
+ result.push({
730
+ stage,
731
+ status: 'failed',
732
+ reason: failures?.[0]?.reason ?? failedEvent.reason,
733
+ completedAt: failedEvent.created_at,
734
+ });
735
+ } else if (completeEvent) {
736
+ // Stage ran and completed
737
+ result.push({
738
+ stage,
739
+ status: 'completed',
740
+ completedAt: completeEvent.created_at,
741
+ });
742
+ } else {
743
+ // Stage started but not completed or failed — currently running
744
+ result.push({ stage, status: 'running' });
745
+ }
746
+ }
747
+
748
+ return result;
749
+ }
750
+
751
+ /**
752
+ * Record Trinity stage events in batch after the chain completes (per NOC-08).
753
+ * Derives stage events from TrinityResult.telemetry and TrinityResult.failures.
754
+ * Always records _start event for each stage that ran, plus _complete or _failed based on outcome.
755
+ */
756
+ private recordStageEvents(workflowId: string, result: TrinityResult): void {
757
+ const { telemetry, failures } = result;
758
+
759
+ // Dreamer events (always runs if we reach here)
760
+ this.store.recordEvent(
761
+ workflowId,
762
+ 'trinity_dreamer_start',
763
+ null, // fromState: null for first event
764
+ 'active',
765
+ 'Trinity Dreamer stage began',
766
+ {}
767
+ );
768
+
769
+ if (telemetry.dreamerPassed) {
770
+ this.store.recordEvent(
771
+ workflowId,
772
+ 'trinity_dreamer_complete',
773
+ 'active',
774
+ 'active',
775
+ 'Dreamer completed successfully',
776
+ { candidateCount: telemetry.candidateCount }
777
+ );
778
+ } else {
779
+ const dreamerFailure = failures.find(f => f.stage === 'dreamer');
780
+ this.store.recordEvent(
781
+ workflowId,
782
+ 'trinity_dreamer_failed',
783
+ 'active',
784
+ 'active',
785
+ dreamerFailure?.reason ?? 'Dreamer stage failed',
786
+ { failures: failures.filter(f => f.stage === 'dreamer') }
787
+ );
788
+ }
789
+
790
+ // Philosopher events (only if Dreamer passed)
791
+ if (telemetry.dreamerPassed) {
792
+ this.store.recordEvent(
793
+ workflowId,
794
+ 'trinity_philosopher_start',
795
+ 'active',
796
+ 'active',
797
+ 'Trinity Philosopher stage began',
798
+ {}
799
+ );
800
+
801
+ if (telemetry.philosopherPassed) {
802
+ this.store.recordEvent(
803
+ workflowId,
804
+ 'trinity_philosopher_complete',
805
+ 'active',
806
+ 'active',
807
+ 'Philosopher completed successfully',
808
+ {}
809
+ );
810
+ } else {
811
+ const philosopherFailure = failures.find(f => f.stage === 'philosopher');
812
+ this.store.recordEvent(
813
+ workflowId,
814
+ 'trinity_philosopher_failed',
815
+ 'active',
816
+ 'active',
817
+ philosopherFailure?.reason ?? 'Philosopher stage failed',
818
+ { failures: failures.filter(f => f.stage === 'philosopher') }
819
+ );
820
+ }
821
+ }
822
+
823
+ // Scribe events (only if Philosopher passed)
824
+ if (telemetry.philosopherPassed) {
825
+ this.store.recordEvent(
826
+ workflowId,
827
+ 'trinity_scribe_start',
828
+ 'active',
829
+ 'active',
830
+ 'Trinity Scribe stage began',
831
+ {}
832
+ );
833
+
834
+ if (telemetry.scribePassed) {
835
+ this.store.recordEvent(
836
+ workflowId,
837
+ 'trinity_scribe_complete',
838
+ 'active',
839
+ 'finalizing', // NOC-10: scribe complete -> finalizing state
840
+ 'Scribe completed successfully',
841
+ { selectedCandidateIndex: telemetry.selectedCandidateIndex }
842
+ );
843
+ } else {
844
+ const scribeFailure = failures.find(f => f.stage === 'scribe');
845
+ this.store.recordEvent(
846
+ workflowId,
847
+ 'trinity_scribe_failed',
848
+ 'active',
849
+ 'terminal_error', // NOC-10: scribe failure -> terminal_error immediately
850
+ scribeFailure?.reason ?? 'Scribe stage failed',
851
+ { failures: failures.filter(f => f.stage === 'scribe') }
852
+ );
853
+ }
854
+ }
855
+ }
856
+ }