principles-disciple 1.8.1 → 1.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (508) hide show
  1. package/ADVANCED_CONFIG_ZH.md +97 -0
  2. package/AGENT_INSTALL.md +173 -0
  3. package/AGENT_INSTALL_EN.md +173 -0
  4. package/INSTALL.md +256 -0
  5. package/SKILL.md +63 -0
  6. package/docs/COMMAND_REFERENCE.md +76 -0
  7. package/docs/COMMAND_REFERENCE_EN.md +79 -0
  8. package/esbuild.config.js +75 -0
  9. package/openclaw.plugin.json +4 -4
  10. package/package.json +11 -13
  11. package/scripts/build-web.mjs +46 -0
  12. package/scripts/install-dependencies.cjs +47 -0
  13. package/scripts/sync-plugin.mjs +802 -0
  14. package/scripts/verify-build.mjs +109 -0
  15. package/src/agents/nocturnal-dreamer.md +152 -0
  16. package/src/agents/nocturnal-philosopher.md +138 -0
  17. package/src/agents/nocturnal-reflector.md +126 -0
  18. package/src/agents/nocturnal-scribe.md +164 -0
  19. package/src/commands/capabilities.ts +85 -0
  20. package/{dist/commands/context.js → src/commands/context.ts} +78 -38
  21. package/src/commands/evolution-status.ts +146 -0
  22. package/src/commands/export.ts +111 -0
  23. package/src/commands/focus.ts +533 -0
  24. package/src/commands/nocturnal-review.ts +311 -0
  25. package/src/commands/nocturnal-rollout.ts +763 -0
  26. package/src/commands/nocturnal-train.ts +1002 -0
  27. package/{dist/commands/pain.js → src/commands/pain.ts} +68 -49
  28. package/src/commands/principle-rollback.ts +27 -0
  29. package/{dist/commands/rollback.js → src/commands/rollback.ts} +44 -12
  30. package/src/commands/samples.ts +60 -0
  31. package/src/commands/strategy.ts +38 -0
  32. package/{dist/commands/thinking-os.js → src/commands/thinking-os.ts} +59 -36
  33. package/src/commands/workflow-debug.ts +128 -0
  34. package/{dist/config/defaults/runtime.js → src/config/defaults/runtime.ts} +12 -5
  35. package/src/config/errors.ts +163 -0
  36. package/{dist/config/index.d.ts → src/config/index.ts} +2 -1
  37. package/src/constants/diagnostician.ts +66 -0
  38. package/src/constants/tools.ts +62 -0
  39. package/src/core/adaptive-thresholds.ts +476 -0
  40. package/{dist/core/config-service.js → src/core/config-service.ts} +7 -4
  41. package/{dist/core/config.js → src/core/config.ts} +158 -46
  42. package/src/core/control-ui-db.ts +435 -0
  43. package/{dist/core/detection-funnel.js → src/core/detection-funnel.ts} +36 -21
  44. package/{dist/core/detection-service.js → src/core/detection-service.ts} +7 -4
  45. package/{dist/core/dictionary-service.js → src/core/dictionary-service.ts} +7 -4
  46. package/{dist/core/dictionary.js → src/core/dictionary.ts} +57 -34
  47. package/src/core/empathy-keyword-matcher.ts +327 -0
  48. package/src/core/empathy-types.ts +218 -0
  49. package/src/core/event-log.ts +544 -0
  50. package/src/core/evolution-engine.ts +612 -0
  51. package/src/core/evolution-logger.ts +353 -0
  52. package/src/core/evolution-migration.ts +77 -0
  53. package/src/core/evolution-reducer.ts +731 -0
  54. package/src/core/evolution-types.ts +456 -0
  55. package/src/core/external-training-contract.ts +527 -0
  56. package/src/core/focus-history.ts +1458 -0
  57. package/src/core/hygiene/tracker.ts +117 -0
  58. package/{dist/core/init.js → src/core/init.ts} +39 -26
  59. package/src/core/local-worker-routing.ts +617 -0
  60. package/{dist/core/migration.js → src/core/migration.ts} +18 -11
  61. package/src/core/model-deployment-registry.ts +722 -0
  62. package/src/core/model-training-registry.ts +813 -0
  63. package/src/core/nocturnal-arbiter.ts +706 -0
  64. package/src/core/nocturnal-candidate-scoring.ts +392 -0
  65. package/src/core/nocturnal-compliance.ts +1075 -0
  66. package/src/core/nocturnal-dataset.ts +668 -0
  67. package/src/core/nocturnal-executability.ts +428 -0
  68. package/src/core/nocturnal-export.ts +390 -0
  69. package/{dist/core/nocturnal-paths.js → src/core/nocturnal-paths.ts} +49 -23
  70. package/src/core/nocturnal-trajectory-extractor.ts +484 -0
  71. package/src/core/nocturnal-trinity.ts +1384 -0
  72. package/src/core/pain.ts +122 -0
  73. package/{dist/core/path-resolver.js → src/core/path-resolver.ts} +157 -36
  74. package/{dist/core/paths.js → src/core/paths.ts} +13 -4
  75. package/src/core/principle-training-state.ts +450 -0
  76. package/src/core/profile.ts +226 -0
  77. package/src/core/promotion-gate.ts +822 -0
  78. package/{dist/core/risk-calculator.js → src/core/risk-calculator.ts} +42 -16
  79. package/{dist/core/session-tracker.js → src/core/session-tracker.ts} +175 -62
  80. package/src/core/shadow-observation-registry.ts +534 -0
  81. package/{dist/core/system-logger.js → src/core/system-logger.ts} +9 -5
  82. package/src/core/thinking-models.ts +217 -0
  83. package/src/core/training-program.ts +630 -0
  84. package/src/core/trajectory-types.ts +243 -0
  85. package/src/core/trajectory.ts +1673 -0
  86. package/{dist/core/workspace-context.js → src/core/workspace-context.ts} +57 -32
  87. package/src/hooks/bash-risk.ts +171 -0
  88. package/src/hooks/edit-verification.ts +295 -0
  89. package/src/hooks/gate-block-helper.ts +160 -0
  90. package/src/hooks/gate.ts +210 -0
  91. package/src/hooks/gfi-gate.ts +177 -0
  92. package/src/hooks/lifecycle.ts +326 -0
  93. package/{dist/hooks/llm.js → src/hooks/llm.ts} +160 -80
  94. package/src/hooks/message-sanitize.ts +45 -0
  95. package/src/hooks/pain.ts +384 -0
  96. package/src/hooks/progressive-trust-gate.ts +174 -0
  97. package/src/hooks/prompt.ts +920 -0
  98. package/src/hooks/subagent.ts +207 -0
  99. package/src/hooks/thinking-checkpoint.ts +73 -0
  100. package/src/hooks/trajectory-collector.ts +290 -0
  101. package/src/http/principles-console-route.ts +716 -0
  102. package/src/i18n/commands.ts +117 -0
  103. package/src/index.ts +694 -0
  104. package/src/service/central-database.ts +831 -0
  105. package/src/service/control-ui-query-service.ts +888 -0
  106. package/src/service/evolution-query-service.ts +405 -0
  107. package/src/service/evolution-worker.ts +1646 -0
  108. package/src/service/health-query-service.ts +836 -0
  109. package/{dist/service/nocturnal-runtime.js → src/service/nocturnal-runtime.ts} +235 -79
  110. package/src/service/nocturnal-service.ts +1015 -0
  111. package/src/service/nocturnal-target-selector.ts +532 -0
  112. package/src/service/phase3-input-filter.ts +237 -0
  113. package/src/service/runtime-summary-service.ts +757 -0
  114. package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +513 -0
  115. package/{dist/service/subagent-workflow/empathy-observer-workflow-manager.js → src/service/subagent-workflow/empathy-observer-workflow-manager.ts} +240 -117
  116. package/src/service/subagent-workflow/index.ts +51 -0
  117. package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +856 -0
  118. package/src/service/subagent-workflow/runtime-direct-driver.ts +166 -0
  119. package/{dist/service/subagent-workflow/types.d.ts → src/service/subagent-workflow/types.ts} +137 -18
  120. package/src/service/subagent-workflow/workflow-store.ts +328 -0
  121. package/src/service/trajectory-service.ts +15 -0
  122. package/{dist/tools/critique-prompt.js → src/tools/critique-prompt.ts} +25 -8
  123. package/src/tools/deep-reflect.ts +349 -0
  124. package/{dist/tools/model-index.js → src/tools/model-index.ts} +33 -17
  125. package/src/types/event-types.ts +453 -0
  126. package/src/types/hygiene-types.ts +31 -0
  127. package/src/types/principle-tree-schema.ts +244 -0
  128. package/src/types/runtime-summary.ts +49 -0
  129. package/src/types.ts +74 -0
  130. package/src/utils/file-lock.ts +391 -0
  131. package/{dist/utils/glob-match.js → src/utils/glob-match.ts} +21 -20
  132. package/{dist/utils/hashing.js → src/utils/hashing.ts} +6 -4
  133. package/src/utils/io.ts +110 -0
  134. package/{dist/utils/nlp.js → src/utils/nlp.ts} +19 -12
  135. package/{dist/utils/plugin-logger.js → src/utils/plugin-logger.ts} +33 -8
  136. package/src/utils/subagent-probe.ts +94 -0
  137. package/templates/langs/en/skills/ai-sprint-orchestration/EXAMPLES.md +63 -0
  138. package/templates/langs/en/skills/ai-sprint-orchestration/REFERENCE.md +136 -0
  139. package/templates/langs/en/skills/ai-sprint-orchestration/SKILL.md +67 -0
  140. package/templates/langs/en/skills/ai-sprint-orchestration/references/agent-registry.json +214 -0
  141. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +107 -0
  142. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +107 -0
  143. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +105 -0
  144. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +108 -0
  145. package/templates/langs/en/skills/ai-sprint-orchestration/references/workflow-v1-acceptance-checklist.md +58 -0
  146. package/templates/langs/en/skills/ai-sprint-orchestration/references/workflow-v1.4-work-unit-handoff.md +190 -0
  147. package/templates/langs/en/skills/ai-sprint-orchestration/runtime/.gitignore +2 -0
  148. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/archive.mjs +310 -0
  149. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/contract-enforcement.mjs +683 -0
  150. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/decision.mjs +604 -0
  151. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/state-store.mjs +32 -0
  152. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/task-specs.mjs +707 -0
  153. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/run.mjs +3419 -0
  154. package/templates/langs/zh/skills/ai-sprint-orchestration/EXAMPLES.md +63 -0
  155. package/templates/langs/zh/skills/ai-sprint-orchestration/REFERENCE.md +136 -0
  156. package/templates/langs/zh/skills/ai-sprint-orchestration/SKILL.md +67 -0
  157. package/templates/langs/zh/skills/ai-sprint-orchestration/references/agent-registry.json +214 -0
  158. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +107 -0
  159. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +107 -0
  160. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +105 -0
  161. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +108 -0
  162. package/templates/langs/zh/skills/ai-sprint-orchestration/references/workflow-v1-acceptance-checklist.md +58 -0
  163. package/templates/langs/zh/skills/ai-sprint-orchestration/references/workflow-v1.4-work-unit-handoff.md +190 -0
  164. package/templates/langs/zh/skills/ai-sprint-orchestration/runtime/.gitignore +2 -0
  165. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/archive.mjs +310 -0
  166. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/contract-enforcement.mjs +683 -0
  167. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/decision.mjs +604 -0
  168. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/state-store.mjs +32 -0
  169. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/task-specs.mjs +707 -0
  170. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/run.mjs +3419 -0
  171. package/templates/langs/zh/skills/ai-sprint-orchestration/test/archive.test.mjs +230 -0
  172. package/templates/langs/zh/skills/ai-sprint-orchestration/test/contract-enforcement.test.mjs +672 -0
  173. package/templates/langs/zh/skills/ai-sprint-orchestration/test/decision.test.mjs +1321 -0
  174. package/templates/langs/zh/skills/ai-sprint-orchestration/test/run.test.mjs +1419 -0
  175. package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +70 -1
  176. package/templates/pain_settings.json +2 -1
  177. package/tests/README.md +120 -0
  178. package/tests/build-artifacts.test.ts +111 -0
  179. package/tests/commands/evolution-status.test.ts +222 -0
  180. package/tests/commands/evolver.test.ts +22 -0
  181. package/tests/commands/export.test.ts +78 -0
  182. package/tests/commands/nocturnal-review.test.ts +448 -0
  183. package/tests/commands/nocturnal-train.test.ts +97 -0
  184. package/tests/commands/pain.test.ts +108 -0
  185. package/tests/commands/samples.test.ts +65 -0
  186. package/tests/commands/strategy.test.ts +34 -0
  187. package/tests/commands/thinking-os.test.ts +88 -0
  188. package/tests/core/adaptive-thresholds.test.ts +261 -0
  189. package/tests/core/config-service.test.ts +89 -0
  190. package/tests/core/config.test.ts +90 -0
  191. package/tests/core/control-ui-db.test.ts +75 -0
  192. package/tests/core/core-template-guidance.test.ts +21 -0
  193. package/tests/core/detection-funnel.test.ts +63 -0
  194. package/tests/core/detection-service.test.ts +50 -0
  195. package/tests/core/dictionary-service.test.ts +116 -0
  196. package/tests/core/dictionary.test.ts +168 -0
  197. package/tests/core/empathy-keyword-matcher.test.ts +209 -0
  198. package/tests/core/event-log.test.ts +181 -0
  199. package/tests/core/evolution-e2e.test.ts +58 -0
  200. package/tests/core/evolution-engine-gate-integration.test.ts +543 -0
  201. package/tests/core/evolution-engine.test.ts +562 -0
  202. package/tests/core/evolution-logger.test.ts +148 -0
  203. package/tests/core/evolution-migration.test.ts +50 -0
  204. package/tests/core/evolution-paths.test.ts +21 -0
  205. package/tests/core/evolution-reducer.detector-metadata.test.ts +602 -0
  206. package/tests/core/evolution-reducer.test.ts +180 -0
  207. package/tests/core/evolution-types-loop.test.ts +48 -0
  208. package/tests/core/evolution-user-stories.e2e.test.ts +249 -0
  209. package/tests/core/external-training-contract.test.ts +463 -0
  210. package/tests/core/focus-history.test.ts +682 -0
  211. package/tests/core/init-flatten.test.ts +69 -0
  212. package/tests/core/init-refactor.test.ts +87 -0
  213. package/tests/core/init-v1.3.test.ts +46 -0
  214. package/tests/core/init.test.ts +190 -0
  215. package/tests/core/local-worker-routing.test.ts +757 -0
  216. package/tests/core/migration.test.ts +84 -0
  217. package/tests/core/model-deployment-registry.test.ts +845 -0
  218. package/tests/core/model-training-registry.test.ts +889 -0
  219. package/tests/core/nocturnal-arbiter.test.ts +494 -0
  220. package/tests/core/nocturnal-candidate-scoring.test.ts +400 -0
  221. package/tests/core/nocturnal-compliance.test.ts +646 -0
  222. package/tests/core/nocturnal-dataset.test.ts +892 -0
  223. package/tests/core/nocturnal-executability.test.ts +357 -0
  224. package/tests/core/nocturnal-export.test.ts +462 -0
  225. package/tests/core/nocturnal-reviewed-subset-comparison.test.ts +428 -0
  226. package/tests/core/nocturnal-trajectory-extractor.test.ts +634 -0
  227. package/tests/core/nocturnal-trinity.test.ts +953 -0
  228. package/tests/core/pain.test.ts +33 -0
  229. package/tests/core/path-resolver.test.ts +57 -0
  230. package/tests/core/paths-refactor.test.ts +42 -0
  231. package/tests/core/phase7-rollout-integration.test.ts +477 -0
  232. package/tests/core/principle-training-state.test.ts +712 -0
  233. package/tests/core/profile.test.ts +56 -0
  234. package/tests/core/promotion-gate.test.ts +556 -0
  235. package/tests/core/risk-calculator.test.ts +168 -0
  236. package/tests/core/session-tracker.test.ts +191 -0
  237. package/tests/core/training-program.test.ts +472 -0
  238. package/tests/core/trajectory.test.ts +265 -0
  239. package/tests/core/workspace-context-factory.test.ts +18 -0
  240. package/tests/core/workspace-context.test.ts +134 -0
  241. package/tests/fixtures/nocturnal-reviewed-subset.json +183 -0
  242. package/tests/fixtures/production-compatibility.test.ts +147 -0
  243. package/tests/fixtures/production-mock-generator.ts +282 -0
  244. package/tests/hooks/bash-risk-integration.test.ts +137 -0
  245. package/tests/hooks/bash-risk.test.ts +81 -0
  246. package/tests/hooks/edit-verification.test.ts +678 -0
  247. package/tests/hooks/gate-edit-verification-p1.test.ts +632 -0
  248. package/tests/hooks/gate-edit-verification.test.ts +435 -0
  249. package/tests/hooks/gate-pipeline-integration.test.ts +404 -0
  250. package/tests/hooks/gate.test.ts +271 -0
  251. package/tests/hooks/gfi-gate-unit.test.ts +422 -0
  252. package/tests/hooks/gfi-gate.test.ts +669 -0
  253. package/tests/hooks/lifecycle.test.ts +248 -0
  254. package/tests/hooks/llm.test.ts +308 -0
  255. package/tests/hooks/message-sanitize.test.ts +36 -0
  256. package/tests/hooks/pain.test.ts +141 -0
  257. package/tests/hooks/progressive-trust-gate.test.ts +277 -0
  258. package/tests/hooks/prompt.test.ts +1411 -0
  259. package/tests/hooks/subagent.test.ts +467 -0
  260. package/tests/hooks/thinking-gate.test.ts +313 -0
  261. package/tests/http/principles-console-route.test.ts +140 -0
  262. package/tests/hygiene-tracker.test.ts +77 -0
  263. package/tests/index.integration.test.ts +179 -0
  264. package/tests/index.shadow-routing.integration.test.ts +140 -0
  265. package/tests/index.test.ts +9 -0
  266. package/tests/integration/empathy-workflow-integration.test.ts +627 -0
  267. package/tests/service/control-ui-query-service.test.ts +121 -0
  268. package/tests/service/empathy-observer-workflow-manager.test.ts +176 -0
  269. package/tests/service/evolution-worker.test.ts +585 -0
  270. package/tests/service/nocturnal-runtime.test.ts +470 -0
  271. package/tests/service/nocturnal-service.test.ts +577 -0
  272. package/tests/service/nocturnal-target-selector.test.ts +615 -0
  273. package/tests/service/nocturnal-workflow-manager.test.ts +439 -0
  274. package/tests/service/phase3-input-filter.test.ts +289 -0
  275. package/tests/service/runtime-summary-service.test.ts +919 -0
  276. package/tests/task-compliance.test.ts +166 -0
  277. package/tests/test-utils.ts +48 -0
  278. package/tests/tools/critique-prompt.test.ts +260 -0
  279. package/tests/tools/deep-reflect.test.ts +232 -0
  280. package/tests/tools/model-index.test.ts +246 -0
  281. package/tests/ui/app.test.tsx +114 -0
  282. package/tests/utils/file-lock.test.ts +407 -0
  283. package/tests/utils/hashing.test.ts +32 -0
  284. package/tests/utils/io.test.ts +39 -0
  285. package/tests/utils/nlp.test.ts +53 -0
  286. package/tests/utils/plugin-logger.test.ts +156 -0
  287. package/tsconfig.json +16 -0
  288. package/tsconfig.tsbuildinfo +1 -0
  289. package/ui/src/App.tsx +45 -0
  290. package/ui/src/api.ts +216 -0
  291. package/ui/src/charts.tsx +586 -0
  292. package/ui/src/components/ErrorState.tsx +6 -0
  293. package/ui/src/components/Loading.tsx +13 -0
  294. package/ui/src/components/ProtectedRoute.tsx +12 -0
  295. package/ui/src/components/Shell.tsx +91 -0
  296. package/ui/src/components/WorkspaceConfig.tsx +146 -0
  297. package/ui/src/components/index.ts +5 -0
  298. package/ui/src/context/auth.tsx +80 -0
  299. package/ui/src/context/theme.tsx +66 -0
  300. package/ui/src/hooks/useAutoRefresh.ts +39 -0
  301. package/ui/src/i18n/ui.ts +363 -0
  302. package/ui/src/main.tsx +16 -0
  303. package/ui/src/pages/EvolutionPage.tsx +352 -0
  304. package/ui/src/pages/FeedbackPage.tsx +140 -0
  305. package/ui/src/pages/GateMonitorPage.tsx +136 -0
  306. package/ui/src/pages/LoginPage.tsx +88 -0
  307. package/ui/src/pages/OverviewPage.tsx +238 -0
  308. package/ui/src/pages/SamplesPage.tsx +174 -0
  309. package/ui/src/pages/ThinkingModelsPage.tsx +127 -0
  310. package/ui/src/styles.css +1661 -0
  311. package/ui/src/types.ts +368 -0
  312. package/ui/src/utils/format.ts +15 -0
  313. package/vitest.config.ts +23 -0
  314. package/dist/commands/capabilities.d.ts +0 -3
  315. package/dist/commands/capabilities.js +0 -73
  316. package/dist/commands/context.d.ts +0 -5
  317. package/dist/commands/evolution-status.d.ts +0 -4
  318. package/dist/commands/evolution-status.js +0 -117
  319. package/dist/commands/evolver.d.ts +0 -9
  320. package/dist/commands/evolver.js +0 -26
  321. package/dist/commands/export.d.ts +0 -2
  322. package/dist/commands/export.js +0 -98
  323. package/dist/commands/focus.d.ts +0 -14
  324. package/dist/commands/focus.js +0 -457
  325. package/dist/commands/nocturnal-review.d.ts +0 -24
  326. package/dist/commands/nocturnal-review.js +0 -265
  327. package/dist/commands/nocturnal-rollout.d.ts +0 -27
  328. package/dist/commands/nocturnal-rollout.js +0 -671
  329. package/dist/commands/nocturnal-train.d.ts +0 -25
  330. package/dist/commands/nocturnal-train.js +0 -919
  331. package/dist/commands/pain.d.ts +0 -5
  332. package/dist/commands/principle-rollback.d.ts +0 -4
  333. package/dist/commands/principle-rollback.js +0 -22
  334. package/dist/commands/rollback.d.ts +0 -19
  335. package/dist/commands/samples.d.ts +0 -2
  336. package/dist/commands/samples.js +0 -55
  337. package/dist/commands/strategy.d.ts +0 -3
  338. package/dist/commands/strategy.js +0 -29
  339. package/dist/commands/thinking-os.d.ts +0 -2
  340. package/dist/config/defaults/runtime.d.ts +0 -40
  341. package/dist/config/errors.d.ts +0 -84
  342. package/dist/config/errors.js +0 -94
  343. package/dist/config/index.js +0 -7
  344. package/dist/constants/diagnostician.d.ts +0 -12
  345. package/dist/constants/diagnostician.js +0 -56
  346. package/dist/constants/tools.d.ts +0 -17
  347. package/dist/constants/tools.js +0 -54
  348. package/dist/core/adaptive-thresholds.d.ts +0 -186
  349. package/dist/core/adaptive-thresholds.js +0 -300
  350. package/dist/core/config-service.d.ts +0 -15
  351. package/dist/core/config.d.ts +0 -129
  352. package/dist/core/control-ui-db.d.ts +0 -95
  353. package/dist/core/control-ui-db.js +0 -292
  354. package/dist/core/detection-funnel.d.ts +0 -33
  355. package/dist/core/detection-service.d.ts +0 -15
  356. package/dist/core/dictionary-service.d.ts +0 -15
  357. package/dist/core/dictionary.d.ts +0 -38
  358. package/dist/core/event-log.d.ts +0 -82
  359. package/dist/core/event-log.js +0 -463
  360. package/dist/core/evolution-engine.d.ts +0 -118
  361. package/dist/core/evolution-engine.js +0 -464
  362. package/dist/core/evolution-logger.d.ts +0 -137
  363. package/dist/core/evolution-logger.js +0 -256
  364. package/dist/core/evolution-migration.d.ts +0 -5
  365. package/dist/core/evolution-migration.js +0 -65
  366. package/dist/core/evolution-reducer.d.ts +0 -98
  367. package/dist/core/evolution-reducer.js +0 -465
  368. package/dist/core/evolution-types.d.ts +0 -287
  369. package/dist/core/evolution-types.js +0 -78
  370. package/dist/core/external-training-contract.d.ts +0 -276
  371. package/dist/core/external-training-contract.js +0 -269
  372. package/dist/core/focus-history.d.ts +0 -210
  373. package/dist/core/focus-history.js +0 -1185
  374. package/dist/core/hygiene/tracker.d.ts +0 -22
  375. package/dist/core/hygiene/tracker.js +0 -106
  376. package/dist/core/init.d.ts +0 -12
  377. package/dist/core/local-worker-routing.d.ts +0 -175
  378. package/dist/core/local-worker-routing.js +0 -525
  379. package/dist/core/migration.d.ts +0 -6
  380. package/dist/core/model-deployment-registry.d.ts +0 -218
  381. package/dist/core/model-deployment-registry.js +0 -503
  382. package/dist/core/model-training-registry.d.ts +0 -295
  383. package/dist/core/model-training-registry.js +0 -475
  384. package/dist/core/nocturnal-arbiter.d.ts +0 -159
  385. package/dist/core/nocturnal-arbiter.js +0 -534
  386. package/dist/core/nocturnal-candidate-scoring.d.ts +0 -137
  387. package/dist/core/nocturnal-candidate-scoring.js +0 -266
  388. package/dist/core/nocturnal-compliance.d.ts +0 -175
  389. package/dist/core/nocturnal-compliance.js +0 -824
  390. package/dist/core/nocturnal-dataset.d.ts +0 -224
  391. package/dist/core/nocturnal-dataset.js +0 -443
  392. package/dist/core/nocturnal-executability.d.ts +0 -85
  393. package/dist/core/nocturnal-executability.js +0 -331
  394. package/dist/core/nocturnal-export.d.ts +0 -124
  395. package/dist/core/nocturnal-export.js +0 -275
  396. package/dist/core/nocturnal-paths.d.ts +0 -124
  397. package/dist/core/nocturnal-trajectory-extractor.d.ts +0 -242
  398. package/dist/core/nocturnal-trajectory-extractor.js +0 -307
  399. package/dist/core/nocturnal-trinity.d.ts +0 -311
  400. package/dist/core/nocturnal-trinity.js +0 -880
  401. package/dist/core/pain.d.ts +0 -4
  402. package/dist/core/pain.js +0 -70
  403. package/dist/core/path-resolver.d.ts +0 -46
  404. package/dist/core/paths.d.ts +0 -65
  405. package/dist/core/principle-training-state.d.ts +0 -121
  406. package/dist/core/principle-training-state.js +0 -321
  407. package/dist/core/profile.d.ts +0 -62
  408. package/dist/core/profile.js +0 -210
  409. package/dist/core/promotion-gate.d.ts +0 -238
  410. package/dist/core/promotion-gate.js +0 -529
  411. package/dist/core/risk-calculator.d.ts +0 -22
  412. package/dist/core/session-tracker.d.ts +0 -101
  413. package/dist/core/shadow-observation-registry.d.ts +0 -217
  414. package/dist/core/shadow-observation-registry.js +0 -308
  415. package/dist/core/system-logger.d.ts +0 -8
  416. package/dist/core/thinking-models.d.ts +0 -38
  417. package/dist/core/thinking-models.js +0 -170
  418. package/dist/core/training-program.d.ts +0 -233
  419. package/dist/core/training-program.js +0 -433
  420. package/dist/core/trajectory.d.ts +0 -411
  421. package/dist/core/trajectory.js +0 -1307
  422. package/dist/core/workspace-context.d.ts +0 -71
  423. package/dist/hooks/bash-risk.d.ts +0 -57
  424. package/dist/hooks/bash-risk.js +0 -137
  425. package/dist/hooks/edit-verification.d.ts +0 -62
  426. package/dist/hooks/edit-verification.js +0 -256
  427. package/dist/hooks/gate-block-helper.d.ts +0 -44
  428. package/dist/hooks/gate-block-helper.js +0 -119
  429. package/dist/hooks/gate.d.ts +0 -24
  430. package/dist/hooks/gate.js +0 -173
  431. package/dist/hooks/gfi-gate.d.ts +0 -40
  432. package/dist/hooks/gfi-gate.js +0 -113
  433. package/dist/hooks/lifecycle.d.ts +0 -5
  434. package/dist/hooks/lifecycle.js +0 -284
  435. package/dist/hooks/llm.d.ts +0 -13
  436. package/dist/hooks/message-sanitize.d.ts +0 -3
  437. package/dist/hooks/message-sanitize.js +0 -37
  438. package/dist/hooks/pain.d.ts +0 -5
  439. package/dist/hooks/pain.js +0 -301
  440. package/dist/hooks/progressive-trust-gate.d.ts +0 -52
  441. package/dist/hooks/progressive-trust-gate.js +0 -134
  442. package/dist/hooks/prompt.d.ts +0 -49
  443. package/dist/hooks/prompt.js +0 -905
  444. package/dist/hooks/subagent.d.ts +0 -10
  445. package/dist/hooks/subagent.js +0 -387
  446. package/dist/hooks/thinking-checkpoint.d.ts +0 -37
  447. package/dist/hooks/thinking-checkpoint.js +0 -51
  448. package/dist/hooks/trajectory-collector.d.ts +0 -32
  449. package/dist/hooks/trajectory-collector.js +0 -256
  450. package/dist/http/principles-console-route.d.ts +0 -9
  451. package/dist/http/principles-console-route.js +0 -681
  452. package/dist/i18n/commands.d.ts +0 -26
  453. package/dist/i18n/commands.js +0 -116
  454. package/dist/index.d.ts +0 -7
  455. package/dist/index.js +0 -581
  456. package/dist/service/central-database.d.ts +0 -104
  457. package/dist/service/central-database.js +0 -649
  458. package/dist/service/control-ui-query-service.d.ts +0 -221
  459. package/dist/service/control-ui-query-service.js +0 -543
  460. package/dist/service/empathy-observer-manager.d.ts +0 -88
  461. package/dist/service/empathy-observer-manager.js +0 -414
  462. package/dist/service/evolution-query-service.d.ts +0 -155
  463. package/dist/service/evolution-query-service.js +0 -258
  464. package/dist/service/evolution-worker.d.ts +0 -101
  465. package/dist/service/evolution-worker.js +0 -975
  466. package/dist/service/health-query-service.d.ts +0 -170
  467. package/dist/service/health-query-service.js +0 -662
  468. package/dist/service/nocturnal-runtime.d.ts +0 -183
  469. package/dist/service/nocturnal-service.d.ts +0 -163
  470. package/dist/service/nocturnal-service.js +0 -787
  471. package/dist/service/nocturnal-target-selector.d.ts +0 -145
  472. package/dist/service/nocturnal-target-selector.js +0 -315
  473. package/dist/service/phase3-input-filter.d.ts +0 -73
  474. package/dist/service/phase3-input-filter.js +0 -172
  475. package/dist/service/runtime-summary-service.d.ts +0 -122
  476. package/dist/service/runtime-summary-service.js +0 -485
  477. package/dist/service/subagent-workflow/empathy-observer-workflow-manager.d.ts +0 -48
  478. package/dist/service/subagent-workflow/index.d.ts +0 -4
  479. package/dist/service/subagent-workflow/index.js +0 -3
  480. package/dist/service/subagent-workflow/runtime-direct-driver.d.ts +0 -77
  481. package/dist/service/subagent-workflow/runtime-direct-driver.js +0 -75
  482. package/dist/service/subagent-workflow/types.js +0 -11
  483. package/dist/service/subagent-workflow/workflow-store.d.ts +0 -26
  484. package/dist/service/subagent-workflow/workflow-store.js +0 -165
  485. package/dist/service/trajectory-service.d.ts +0 -2
  486. package/dist/service/trajectory-service.js +0 -15
  487. package/dist/tools/critique-prompt.d.ts +0 -14
  488. package/dist/tools/deep-reflect.d.ts +0 -39
  489. package/dist/tools/deep-reflect.js +0 -350
  490. package/dist/tools/model-index.d.ts +0 -9
  491. package/dist/types/event-types.d.ts +0 -306
  492. package/dist/types/event-types.js +0 -106
  493. package/dist/types/hygiene-types.d.ts +0 -20
  494. package/dist/types/hygiene-types.js +0 -12
  495. package/dist/types/runtime-summary.d.ts +0 -47
  496. package/dist/types/runtime-summary.js +0 -1
  497. package/dist/types.d.ts +0 -50
  498. package/dist/types.js +0 -22
  499. package/dist/utils/file-lock.d.ts +0 -71
  500. package/dist/utils/file-lock.js +0 -309
  501. package/dist/utils/glob-match.d.ts +0 -28
  502. package/dist/utils/hashing.d.ts +0 -9
  503. package/dist/utils/io.d.ts +0 -6
  504. package/dist/utils/io.js +0 -106
  505. package/dist/utils/nlp.d.ts +0 -9
  506. package/dist/utils/plugin-logger.d.ts +0 -39
  507. package/dist/utils/subagent-probe.d.ts +0 -34
  508. package/dist/utils/subagent-probe.js +0 -81
@@ -0,0 +1,627 @@
1
+ /**
2
+ * Integration tests for Empathy Observer Workflow
3
+ *
4
+ * These tests verify the complete chain from hook entry to workflow state/events.
5
+ * Unlike unit tests, these use real file system and SQLite for WorkflowStore.
6
+ *
7
+ * Coverage:
8
+ * 1. EmpathyObserverWorkflowManager startWorkflow triggers workflow helper
9
+ * 2. WorkflowStore records spawn/wait/finalize events
10
+ * 3. Lifecycle cleanup (sweepExpiredWorkflows) works when wired
11
+ */
12
+
13
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
14
+ import * as fs from 'node:fs';
15
+ import * as os from 'node:os';
16
+ import * as path from 'node:path';
17
+ import { EmpathyObserverWorkflowManager, empathyObserverWorkflowSpec } from '../../src/service/subagent-workflow/empathy-observer-workflow-manager.js';
18
+ import { WorkflowStore } from '../../src/service/subagent-workflow/workflow-store.js';
19
+ import { handleBeforePromptBuild } from '../../src/hooks/prompt.js';
20
+ import { WorkspaceContext } from '../../src/core/workspace-context.js';
21
+
22
+ /**
23
+ * Helper to create a mock function that properly reports as AsyncFunction.
24
+ * This is required because isSubagentRuntimeAvailable() checks constructor.name === 'AsyncFunction'.
25
+ */
26
+ function mockAsyncFn<T extends (...args: any[]) => Promise<any>>(impl: (...args: any[]) => any) {
27
+ const fn = vi.fn(impl) as unknown as T;
28
+ Object.defineProperty(fn, 'constructor', {
29
+ value: function AsyncFunction() {},
30
+ writable: true,
31
+ configurable: true,
32
+ });
33
+ return fn;
34
+ }
35
+
36
+ describe('Empathy Workflow Integration (PR2)', () => {
37
+ let tempDir: string;
38
+ let stateDir: string;
39
+ let store: WorkflowStore;
40
+
41
+ const logger = {
42
+ info: vi.fn(),
43
+ warn: vi.fn(),
44
+ error: vi.fn(),
45
+ debug: vi.fn(),
46
+ };
47
+
48
+ beforeEach(() => {
49
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pd-empathy-integration-'));
50
+ stateDir = path.join(tempDir, '.state');
51
+ fs.mkdirSync(stateDir, { recursive: true });
52
+ });
53
+
54
+ afterEach(() => {
55
+ store?.dispose();
56
+ fs.rmSync(tempDir, { recursive: true, force: true });
57
+ vi.clearAllMocks();
58
+ });
59
+
60
+ // ---------------------------------------------------------------------------
61
+ // Test 1: WorkflowStore records spawn/wait/finalize events
62
+ // ---------------------------------------------------------------------------
63
+ describe('WorkflowStore event chain', () => {
64
+ it('records spawned event when workflow starts', async () => {
65
+ store = new WorkflowStore({ workspaceDir: tempDir });
66
+
67
+ const subagent = {
68
+ run: mockAsyncFn(async () => ({ runId: 'run-001' })),
69
+ waitForRun: mockAsyncFn(async () => ({ status: 'ok' as const })),
70
+ getSessionMessages: mockAsyncFn(async () => ({ messages: [], assistantTexts: ['{"damageDetected":false}'] })),
71
+ deleteSession: mockAsyncFn(async () => {}),
72
+ };
73
+
74
+ const manager = new EmpathyObserverWorkflowManager({
75
+ workspaceDir: tempDir,
76
+ logger,
77
+ subagent,
78
+ });
79
+
80
+ const handle = await manager.startWorkflow(empathyObserverWorkflowSpec, {
81
+ parentSessionId: 'session-001',
82
+ taskInput: 'user message',
83
+ });
84
+
85
+ // Verify workflow was created in store
86
+ const workflow = store.getWorkflow(handle.workflowId);
87
+ expect(workflow).not.toBeNull();
88
+ expect(workflow?.state).toBe('active');
89
+ expect(workflow?.parent_session_id).toBe('session-001');
90
+
91
+ // Verify spawned event was recorded
92
+ const events = store.getEvents(handle.workflowId);
93
+ const spawnedEvent = events.find(e => e.event_type === 'spawned');
94
+ expect(spawnedEvent).toBeDefined();
95
+ expect(spawnedEvent?.to_state).toBe('active');
96
+
97
+ manager.dispose();
98
+ });
99
+
100
+ it('records wait_result and finalized events on successful completion', async () => {
101
+ store = new WorkflowStore({ workspaceDir: tempDir });
102
+
103
+ const subagent = {
104
+ run: mockAsyncFn(async () => ({ runId: 'run-002' })),
105
+ waitForRun: mockAsyncFn(async () => ({ status: 'ok' as const })),
106
+ getSessionMessages: mockAsyncFn(async () => ({ messages: [], assistantTexts: ['{"damageDetected":false}'] })),
107
+ deleteSession: mockAsyncFn(async () => {}),
108
+ };
109
+
110
+ const manager = new EmpathyObserverWorkflowManager({
111
+ workspaceDir: tempDir,
112
+ logger,
113
+ subagent,
114
+ });
115
+
116
+ const handle = await manager.startWorkflow(empathyObserverWorkflowSpec, {
117
+ parentSessionId: 'session-002',
118
+ taskInput: 'user message',
119
+ });
120
+
121
+ // Clear the scheduled poll timeout to manually trigger notifyWaitResult
122
+ const timeout = (manager as any).activeWorkflows.get(handle.workflowId);
123
+ if (timeout) {
124
+ clearTimeout(timeout);
125
+ (manager as any).activeWorkflows.delete(handle.workflowId);
126
+ }
127
+
128
+ await manager.notifyWaitResult(handle.workflowId, 'ok');
129
+
130
+ // Verify final state
131
+ const workflow = store.getWorkflow(handle.workflowId);
132
+ expect(workflow?.state).toBe('completed');
133
+
134
+ // Verify event chain: spawned -> wait_result -> finalized
135
+ const events = store.getEvents(handle.workflowId);
136
+ const eventTypes = events.map(e => e.event_type);
137
+
138
+ expect(eventTypes).toContain('spawned');
139
+ expect(eventTypes).toContain('wait_result');
140
+ expect(eventTypes).toContain('finalized');
141
+
142
+ manager.dispose();
143
+ });
144
+ });
145
+
146
+ // ---------------------------------------------------------------------------
147
+ // Test 2: sweepExpiredWorkflows works when wired
148
+ // ---------------------------------------------------------------------------
149
+ describe('Lifecycle cleanup (sweepExpiredWorkflows)', () => {
150
+ it('sweeps workflows older than TTL', async () => {
151
+ store = new WorkflowStore({ workspaceDir: tempDir });
152
+
153
+ const subagent = {
154
+ run: mockAsyncFn(async () => ({ runId: 'run-003' })),
155
+ waitForRun: mockAsyncFn(async () => ({ status: 'timeout' as const })),
156
+ getSessionMessages: mockAsyncFn(async () => ({ messages: [], assistantTexts: [] })),
157
+ deleteSession: mockAsyncFn(async () => {}),
158
+ };
159
+
160
+ const manager = new EmpathyObserverWorkflowManager({
161
+ workspaceDir: tempDir,
162
+ logger,
163
+ subagent,
164
+ });
165
+
166
+ // Create a workflow
167
+ const handle = await manager.startWorkflow(empathyObserverWorkflowSpec, {
168
+ parentSessionId: 'session-003',
169
+ taskInput: 'user message',
170
+ });
171
+
172
+ // Clear the scheduled poll timeout
173
+ const timeout = (manager as any).activeWorkflows.get(handle.workflowId);
174
+ if (timeout) {
175
+ clearTimeout(timeout);
176
+ (manager as any).activeWorkflows.delete(handle.workflowId);
177
+ }
178
+
179
+ // Manually set last_observed_at to simulate old workflow
180
+ const oldTime = Date.now() - 10 * 60 * 1000; // 10 minutes ago
181
+ const db = (store as any).db;
182
+ db.prepare('UPDATE subagent_workflows SET last_observed_at = ? WHERE workflow_id = ?').run(oldTime, handle.workflowId);
183
+
184
+ // Run sweep with 5 minute TTL
185
+ const sweptCount = await manager.sweepExpiredWorkflows(5 * 60 * 1000);
186
+
187
+ expect(sweptCount).toBe(1);
188
+
189
+ // Verify workflow is now expired
190
+ const workflow = store.getWorkflow(handle.workflowId);
191
+ expect(workflow?.state).toBe('expired');
192
+
193
+ // Verify swept event was recorded
194
+ const events = store.getEvents(handle.workflowId);
195
+ const sweptEvent = events.find(e => e.event_type === 'swept');
196
+ expect(sweptEvent).toBeDefined();
197
+
198
+ manager.dispose();
199
+ });
200
+ });
201
+
202
+ // ---------------------------------------------------------------------------
203
+ // Test 3: Debug summary is accessible
204
+ // ---------------------------------------------------------------------------
205
+ describe('Observability (getWorkflowDebugSummary)', () => {
206
+ it('provides debug summary with recent events', async () => {
207
+ store = new WorkflowStore({ workspaceDir: tempDir });
208
+
209
+ const subagent = {
210
+ run: mockAsyncFn(async () => ({ runId: 'run-004' })),
211
+ waitForRun: mockAsyncFn(async () => ({ status: 'ok' as const })),
212
+ getSessionMessages: mockAsyncFn(async () => ({ messages: [], assistantTexts: ['{"damageDetected":false}'] })),
213
+ deleteSession: mockAsyncFn(async () => {}),
214
+ };
215
+
216
+ const manager = new EmpathyObserverWorkflowManager({
217
+ workspaceDir: tempDir,
218
+ logger,
219
+ subagent,
220
+ });
221
+
222
+ const handle = await manager.startWorkflow(empathyObserverWorkflowSpec, {
223
+ parentSessionId: 'session-004',
224
+ taskInput: 'user message',
225
+ });
226
+
227
+ const summary = await manager.getWorkflowDebugSummary(handle.workflowId);
228
+
229
+ expect(summary).not.toBeNull();
230
+ expect(summary?.workflowId).toBe(handle.workflowId);
231
+ expect(summary?.workflowType).toBe('empathy-observer');
232
+ expect(summary?.transport).toBe('runtime_direct');
233
+ expect(summary?.state).toBe('active');
234
+ expect(summary?.parentSessionId).toBe('session-004');
235
+ expect(summary?.recentEvents.length).toBeGreaterThan(0);
236
+ expect(summary?.recentEvents[0].eventType).toBe('spawned');
237
+
238
+ manager.dispose();
239
+ });
240
+ });
241
+
242
+ // ---------------------------------------------------------------------------
243
+ // Test 4: Workflow isolation
244
+ // ---------------------------------------------------------------------------
245
+ describe('Workflow isolation', () => {
246
+ it('each workflow is recorded independently in WorkflowStore', async () => {
247
+ store = new WorkflowStore({ workspaceDir: tempDir });
248
+
249
+ const subagent = {
250
+ run: mockAsyncFn(async () => ({ runId: 'run-005' })),
251
+ waitForRun: mockAsyncFn(async () => ({ status: 'ok' as const })),
252
+ getSessionMessages: mockAsyncFn(async () => ({ messages: [], assistantTexts: ['{"damageDetected":false}'] })),
253
+ deleteSession: mockAsyncFn(async () => {}),
254
+ };
255
+
256
+ const manager = new EmpathyObserverWorkflowManager({
257
+ workspaceDir: tempDir,
258
+ logger,
259
+ subagent,
260
+ });
261
+
262
+ // Start workflow
263
+ const handle = await manager.startWorkflow(empathyObserverWorkflowSpec, {
264
+ parentSessionId: 'session-005',
265
+ taskInput: 'user message',
266
+ });
267
+
268
+ // Verify workflow is recorded independently
269
+ const workflow = store.getWorkflow(handle.workflowId);
270
+ expect(workflow).not.toBeNull();
271
+ expect(workflow?.workflow_type).toBe('empathy-observer');
272
+
273
+ manager.dispose();
274
+ });
275
+ });
276
+
277
+ // ---------------------------------------------------------------------------
278
+ // Test 5: State transition validation
279
+ // ---------------------------------------------------------------------------
280
+ describe('Workflow state transitions', () => {
281
+ it('transitions: active -> wait_result -> finalizing -> completed', async () => {
282
+ store = new WorkflowStore({ workspaceDir: tempDir });
283
+
284
+ const subagent = {
285
+ run: mockAsyncFn(async () => ({ runId: 'run-006' })),
286
+ waitForRun: mockAsyncFn(async () => ({ status: 'ok' as const })),
287
+ getSessionMessages: mockAsyncFn(async () => ({ messages: [], assistantTexts: ['{"damageDetected":false}'] })),
288
+ deleteSession: mockAsyncFn(async () => {}),
289
+ };
290
+
291
+ const manager = new EmpathyObserverWorkflowManager({
292
+ workspaceDir: tempDir,
293
+ logger,
294
+ subagent,
295
+ });
296
+
297
+ const handle = await manager.startWorkflow(empathyObserverWorkflowSpec, {
298
+ parentSessionId: 'session-006',
299
+ taskInput: 'user message',
300
+ });
301
+
302
+ // Verify initial state
303
+ expect(store.getWorkflow(handle.workflowId)?.state).toBe('active');
304
+
305
+ // Clear timeout and trigger wait result
306
+ const timeout = (manager as any).activeWorkflows.get(handle.workflowId);
307
+ if (timeout) {
308
+ clearTimeout(timeout);
309
+ (manager as any).activeWorkflows.delete(handle.workflowId);
310
+ }
311
+
312
+ await manager.notifyWaitResult(handle.workflowId, 'ok');
313
+
314
+ // Verify final state
315
+ expect(store.getWorkflow(handle.workflowId)?.state).toBe('completed');
316
+
317
+ // Verify state transition events
318
+ const events = store.getEvents(handle.workflowId);
319
+ const stateChanges = events.filter(e => e.event_type === 'state_change' || e.event_type === 'wait_result' || e.event_type === 'finalized');
320
+
321
+ // Should have spawn, wait_result, finalized at minimum
322
+ expect(stateChanges.length).toBeGreaterThanOrEqual(2);
323
+
324
+ manager.dispose();
325
+ });
326
+
327
+ it('transitions to terminal_error on timeout', async () => {
328
+ store = new WorkflowStore({ workspaceDir: tempDir });
329
+
330
+ const subagent = {
331
+ run: mockAsyncFn(async () => ({ runId: 'run-007' })),
332
+ waitForRun: mockAsyncFn(async () => ({ status: 'timeout' as const })),
333
+ getSessionMessages: mockAsyncFn(async () => ({ messages: [], assistantTexts: [] })),
334
+ deleteSession: mockAsyncFn(async () => {}),
335
+ };
336
+
337
+ const manager = new EmpathyObserverWorkflowManager({
338
+ workspaceDir: tempDir,
339
+ logger,
340
+ subagent,
341
+ });
342
+
343
+ const handle = await manager.startWorkflow(empathyObserverWorkflowSpec, {
344
+ parentSessionId: 'session-007',
345
+ taskInput: 'user message',
346
+ });
347
+
348
+ // Clear timeout and trigger error result
349
+ const timeout = (manager as any).activeWorkflows.get(handle.workflowId);
350
+ if (timeout) {
351
+ clearTimeout(timeout);
352
+ (manager as any).activeWorkflows.delete(handle.workflowId);
353
+ }
354
+
355
+ await manager.notifyWaitResult(handle.workflowId, 'timeout', 'wait timed out');
356
+
357
+ // Verify terminal state
358
+ expect(store.getWorkflow(handle.workflowId)?.state).toBe('terminal_error');
359
+
360
+ manager.dispose();
361
+ });
362
+ });
363
+
364
+ // ---------------------------------------------------------------------------
365
+ // Test 6: PR2.1 Task 1 - subagent_ended -> notifyLifecycleEvent wiring
366
+ // ---------------------------------------------------------------------------
367
+ describe('PR2.1: subagent_ended lifecycle event wiring', () => {
368
+ it('triggers notifyWaitResult when subagent_ended event received', async () => {
369
+ store = new WorkflowStore({ workspaceDir: tempDir });
370
+
371
+ const subagent = {
372
+ run: mockAsyncFn(async () => ({ runId: 'run-pr21-001' })),
373
+ waitForRun: mockAsyncFn(async () => ({ status: 'ok' as const })),
374
+ getSessionMessages: mockAsyncFn(async () => ({ messages: [], assistantTexts: ['{"damageDetected":false}'] })),
375
+ deleteSession: mockAsyncFn(async () => {}),
376
+ };
377
+
378
+ const manager = new EmpathyObserverWorkflowManager({
379
+ workspaceDir: tempDir,
380
+ logger,
381
+ subagent,
382
+ });
383
+
384
+ // Start a helper workflow
385
+ const handle = await manager.startWorkflow(empathyObserverWorkflowSpec, {
386
+ parentSessionId: 'session-pr21-001',
387
+ taskInput: 'user message',
388
+ });
389
+
390
+ // Get the child session key
391
+ const workflow = store.getWorkflow(handle.workflowId);
392
+ expect(workflow).not.toBeNull();
393
+ const childSessionKey = workflow!.child_session_key;
394
+
395
+ // Verify child session key has expected prefix
396
+ expect(childSessionKey).toMatch(/^agent:main:subagent:workflow-/);
397
+
398
+ // Clear the scheduled poll timeout to prevent auto-wait
399
+ const timeout = (manager as any).activeWorkflows.get(handle.workflowId);
400
+ if (timeout) {
401
+ clearTimeout(timeout);
402
+ (manager as any).activeWorkflows.delete(handle.workflowId);
403
+ }
404
+
405
+ // Verify initial state is active
406
+ expect(store.getWorkflow(handle.workflowId)?.state).toBe('active');
407
+
408
+ // Simulate subagent_ended event by calling notifyLifecycleEvent
409
+ // This triggers notifyWaitResult internally
410
+ await manager.notifyLifecycleEvent(handle.workflowId, 'subagent_ended', {
411
+ outcome: 'ok',
412
+ });
413
+
414
+ // Verify workflow completed through lifecycle event path
415
+ const finalWorkflow = store.getWorkflow(handle.workflowId);
416
+ expect(finalWorkflow?.state).toBe('completed');
417
+
418
+ // Verify event chain includes finalized
419
+ const events = store.getEvents(handle.workflowId);
420
+ const finalizedEvent = events.find(e => e.event_type === 'finalized');
421
+ expect(finalizedEvent).toBeDefined();
422
+
423
+ manager.dispose();
424
+ });
425
+
426
+ it('handles error outcome via lifecycle event', async () => {
427
+ store = new WorkflowStore({ workspaceDir: tempDir });
428
+
429
+ const subagent = {
430
+ run: mockAsyncFn(async () => ({ runId: 'run-pr21-002' })),
431
+ waitForRun: mockAsyncFn(async () => ({ status: 'error' as const, error: 'test error' })),
432
+ getSessionMessages: mockAsyncFn(async () => ({ messages: [], assistantTexts: [] })),
433
+ deleteSession: mockAsyncFn(async () => {}),
434
+ };
435
+
436
+ const manager = new EmpathyObserverWorkflowManager({
437
+ workspaceDir: tempDir,
438
+ logger,
439
+ subagent,
440
+ });
441
+
442
+ const handle = await manager.startWorkflow(empathyObserverWorkflowSpec, {
443
+ parentSessionId: 'session-pr21-002',
444
+ taskInput: 'test',
445
+ });
446
+
447
+ // Clear timeout
448
+ const timeout = (manager as any).activeWorkflows.get(handle.workflowId);
449
+ if (timeout) {
450
+ clearTimeout(timeout);
451
+ (manager as any).activeWorkflows.delete(handle.workflowId);
452
+ }
453
+
454
+ // Notify error outcome
455
+ await manager.notifyLifecycleEvent(handle.workflowId, 'subagent_ended', {
456
+ outcome: 'error',
457
+ error: 'subagent failed',
458
+ });
459
+
460
+ // Verify terminal state
461
+ const workflow = store.getWorkflow(handle.workflowId);
462
+ expect(workflow?.state).toBe('terminal_error');
463
+
464
+ manager.dispose();
465
+ });
466
+ });
467
+
468
+ // ---------------------------------------------------------------------------
469
+ // Test 7: PR2.1 Task 2 - sweepExpiredWorkflows integration
470
+ // ---------------------------------------------------------------------------
471
+ describe('PR2.1: sweepExpiredWorkflows integration', () => {
472
+ it('WorkflowStore.getExpiredWorkflows returns workflows past TTL', async () => {
473
+ store = new WorkflowStore({ workspaceDir: tempDir });
474
+
475
+ const subagent = {
476
+ run: mockAsyncFn(async () => ({ runId: 'run-sweep-001' })),
477
+ waitForRun: mockAsyncFn(async () => ({ status: 'ok' as const })),
478
+ getSessionMessages: mockAsyncFn(async () => ({ messages: [], assistantTexts: ['{}'] })),
479
+ deleteSession: mockAsyncFn(async () => {}),
480
+ };
481
+
482
+ const manager = new EmpathyObserverWorkflowManager({
483
+ workspaceDir: tempDir,
484
+ logger,
485
+ subagent,
486
+ });
487
+
488
+ const handle = await manager.startWorkflow(empathyObserverWorkflowSpec, {
489
+ parentSessionId: 'session-sweep-001',
490
+ taskInput: 'test',
491
+ });
492
+
493
+ // Clear timeout
494
+ const timeout = (manager as any).activeWorkflows.get(handle.workflowId);
495
+ if (timeout) {
496
+ clearTimeout(timeout);
497
+ (manager as any).activeWorkflows.delete(handle.workflowId);
498
+ }
499
+
500
+ // Manually set last_observed_at to simulate expired workflow
501
+ const db = (store as any).db;
502
+ const oldTime = Date.now() - 10 * 60 * 1000; // 10 minutes ago
503
+ db.prepare('UPDATE subagent_workflows SET last_observed_at = ? WHERE workflow_id = ?').run(oldTime, handle.workflowId);
504
+
505
+ // Verify getExpiredWorkflows finds it
506
+ const expired = store.getExpiredWorkflows(5 * 60 * 1000);
507
+ expect(expired.length).toBe(1);
508
+ expect(expired[0].workflow_id).toBe(handle.workflowId);
509
+
510
+ manager.dispose();
511
+ });
512
+
513
+ it('sweepExpiredWorkflows marks workflows as expired', async () => {
514
+ store = new WorkflowStore({ workspaceDir: tempDir });
515
+
516
+ const subagent = {
517
+ run: mockAsyncFn(async () => ({ runId: 'run-sweep-002' })),
518
+ waitForRun: mockAsyncFn(async () => ({ status: 'ok' as const })),
519
+ getSessionMessages: mockAsyncFn(async () => ({ messages: [], assistantTexts: ['{}'] })),
520
+ deleteSession: mockAsyncFn(async () => {}),
521
+ };
522
+
523
+ const manager = new EmpathyObserverWorkflowManager({
524
+ workspaceDir: tempDir,
525
+ logger,
526
+ subagent,
527
+ });
528
+
529
+ const handle = await manager.startWorkflow(empathyObserverWorkflowSpec, {
530
+ parentSessionId: 'session-sweep-002',
531
+ taskInput: 'test',
532
+ });
533
+
534
+ // Clear timeout
535
+ const timeout = (manager as any).activeWorkflows.get(handle.workflowId);
536
+ if (timeout) {
537
+ clearTimeout(timeout);
538
+ (manager as any).activeWorkflows.delete(handle.workflowId);
539
+ }
540
+
541
+ // Manually expire
542
+ const db = (store as any).db;
543
+ const oldTime = Date.now() - 10 * 60 * 1000;
544
+ db.prepare('UPDATE subagent_workflows SET last_observed_at = ? WHERE workflow_id = ?').run(oldTime, handle.workflowId);
545
+
546
+ // Sweep
547
+ const count = await manager.sweepExpiredWorkflows(5 * 60 * 1000);
548
+ expect(count).toBe(1);
549
+
550
+ // Verify state
551
+ const workflow = store.getWorkflow(handle.workflowId);
552
+ expect(workflow?.state).toBe('expired');
553
+
554
+ // Verify swept event
555
+ const events = store.getEvents(handle.workflowId);
556
+ const sweptEvent = events.find(e => e.event_type === 'swept');
557
+ expect(sweptEvent).toBeDefined();
558
+
559
+ manager.dispose();
560
+ });
561
+ });
562
+
563
+ // ---------------------------------------------------------------------------
564
+ // Test 8: PR2.1 Task 3 - getWorkflowDebugSummary slash command
565
+ // ---------------------------------------------------------------------------
566
+ describe('PR2.1: getWorkflowDebugSummary accessibility', () => {
567
+ it('provides complete debug summary with all fields', async () => {
568
+ store = new WorkflowStore({ workspaceDir: tempDir });
569
+
570
+ const subagent = {
571
+ run: mockAsyncFn(async () => ({ runId: 'run-debug-001' })),
572
+ waitForRun: mockAsyncFn(async () => ({ status: 'ok' as const })),
573
+ getSessionMessages: mockAsyncFn(async () => ({ messages: [], assistantTexts: ['{"damageDetected":true,"severity":"moderate"}'] })),
574
+ deleteSession: mockAsyncFn(async () => {}),
575
+ };
576
+
577
+ const manager = new EmpathyObserverWorkflowManager({
578
+ workspaceDir: tempDir,
579
+ logger,
580
+ subagent,
581
+ });
582
+
583
+ const handle = await manager.startWorkflow(empathyObserverWorkflowSpec, {
584
+ parentSessionId: 'session-debug-001',
585
+ workspaceDir: tempDir,
586
+ taskInput: 'This is a test user message for debugging',
587
+ metadata: { customField: 'customValue' },
588
+ });
589
+
590
+ const summary = await manager.getWorkflowDebugSummary(handle.workflowId);
591
+
592
+ expect(summary).not.toBeNull();
593
+ expect(summary?.workflowId).toBe(handle.workflowId);
594
+ expect(summary?.workflowType).toBe('empathy-observer');
595
+ expect(summary?.transport).toBe('runtime_direct');
596
+ expect(summary?.state).toBe('active');
597
+ expect(summary?.cleanupState).toBe('none');
598
+ expect(summary?.parentSessionId).toBe('session-debug-001');
599
+ expect(summary?.childSessionKey).toContain('workflow-');
600
+ expect(summary?.runId).toBe('run-debug-001');
601
+ expect(summary?.metadata.taskInput).toBe('This is a test user message for debugging');
602
+ expect(summary?.metadata.customField).toBe('customValue');
603
+ expect(summary?.recentEvents.length).toBeGreaterThan(0);
604
+
605
+ // Verify first event is spawned
606
+ expect(summary?.recentEvents[0].eventType).toBe('spawned');
607
+
608
+ manager.dispose();
609
+ });
610
+
611
+ it('returns null for non-existent workflow', async () => {
612
+ store = new WorkflowStore({ workspaceDir: tempDir });
613
+
614
+ const manager = new EmpathyObserverWorkflowManager({
615
+ workspaceDir: tempDir,
616
+ logger,
617
+ subagent: {} as any,
618
+ });
619
+
620
+ const summary = await manager.getWorkflowDebugSummary('non-existent-id');
621
+ expect(summary).toBeNull();
622
+
623
+ manager.dispose();
624
+ });
625
+ });
626
+
627
+ });