crewly 1.6.1 → 1.6.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 (367) hide show
  1. package/config/roles/orchestrator/prompt.md +16 -0
  2. package/config/skills/agent/core/get-my-active-work/SKILL.md +101 -0
  3. package/config/skills/agent/core/get-my-active-work/execute.sh +122 -0
  4. package/config/skills/agent/core/record-learning/SKILL.md +29 -0
  5. package/config/skills/agent/core/reply-channel/SKILL.md +41 -0
  6. package/config/skills/agent/core/reply-channel/execute.sh +165 -0
  7. package/config/skills/agent/core/reply-channel/execute.test.sh +148 -0
  8. package/config/skills/agent/remote-browser/execute.sh +296 -14
  9. package/config/skills/agent/remote-browser/execute.test.sh +482 -0
  10. package/config/skills/orchestrator/send-message/SKILL.md +30 -7
  11. package/config/skills/orchestrator/team-health-scan/SKILL.md +98 -0
  12. package/config/skills/orchestrator/team-health-scan/execute.sh +44 -0
  13. package/config/skills/registry.json +62 -1
  14. package/config/slack-app-manifest.json +2 -1
  15. package/config/sops/developer/git-workflow.md +38 -3
  16. package/dist/backend/backend/src/constants.d.ts +69 -1
  17. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  18. package/dist/backend/backend/src/constants.js +69 -2
  19. package/dist/backend/backend/src/constants.js.map +1 -1
  20. package/dist/backend/backend/src/controllers/active-work/active-work.controller.d.ts +53 -0
  21. package/dist/backend/backend/src/controllers/active-work/active-work.controller.d.ts.map +1 -0
  22. package/dist/backend/backend/src/controllers/active-work/active-work.controller.js +92 -0
  23. package/dist/backend/backend/src/controllers/active-work/active-work.controller.js.map +1 -0
  24. package/dist/backend/backend/src/controllers/agent-stream/agent-stream.controller.d.ts.map +1 -1
  25. package/dist/backend/backend/src/controllers/agent-stream/agent-stream.controller.js +18 -1
  26. package/dist/backend/backend/src/controllers/agent-stream/agent-stream.controller.js.map +1 -1
  27. package/dist/backend/backend/src/controllers/browser/browser.controller.d.ts +68 -0
  28. package/dist/backend/backend/src/controllers/browser/browser.controller.d.ts.map +1 -1
  29. package/dist/backend/backend/src/controllers/browser/browser.controller.js +233 -5
  30. package/dist/backend/backend/src/controllers/browser/browser.controller.js.map +1 -1
  31. package/dist/backend/backend/src/controllers/browser/browser.routes.d.ts.map +1 -1
  32. package/dist/backend/backend/src/controllers/browser/browser.routes.js +10 -1
  33. package/dist/backend/backend/src/controllers/browser/browser.routes.js.map +1 -1
  34. package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts.map +1 -1
  35. package/dist/backend/backend/src/controllers/chat/chat.controller.js +8 -3
  36. package/dist/backend/backend/src/controllers/chat/chat.controller.js.map +1 -1
  37. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.d.ts +132 -0
  38. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.d.ts.map +1 -0
  39. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.js +401 -0
  40. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.js.map +1 -0
  41. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.d.ts +29 -0
  42. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.d.ts.map +1 -0
  43. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.js +39 -0
  44. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.js.map +1 -0
  45. package/dist/backend/backend/src/controllers/chat-v2/index.d.ts +8 -0
  46. package/dist/backend/backend/src/controllers/chat-v2/index.d.ts.map +1 -0
  47. package/dist/backend/backend/src/controllers/chat-v2/index.js +8 -0
  48. package/dist/backend/backend/src/controllers/chat-v2/index.js.map +1 -0
  49. package/dist/backend/backend/src/controllers/onboarding/onboarding.routes.d.ts +13 -13
  50. package/dist/backend/backend/src/controllers/onboarding/onboarding.routes.d.ts.map +1 -1
  51. package/dist/backend/backend/src/controllers/onboarding/onboarding.routes.js +74 -234
  52. package/dist/backend/backend/src/controllers/onboarding/onboarding.routes.js.map +1 -1
  53. package/dist/backend/backend/src/controllers/orchestrator/orchestrator.controller.d.ts.map +1 -1
  54. package/dist/backend/backend/src/controllers/orchestrator/orchestrator.controller.js +76 -15
  55. package/dist/backend/backend/src/controllers/orchestrator/orchestrator.controller.js.map +1 -1
  56. package/dist/backend/backend/src/controllers/request/request.controller.d.ts.map +1 -1
  57. package/dist/backend/backend/src/controllers/request/request.controller.js +4 -6
  58. package/dist/backend/backend/src/controllers/request/request.controller.js.map +1 -1
  59. package/dist/backend/backend/src/controllers/task-management/tasks.controller.d.ts +43 -0
  60. package/dist/backend/backend/src/controllers/task-management/tasks.controller.d.ts.map +1 -1
  61. package/dist/backend/backend/src/controllers/task-management/tasks.controller.js +200 -72
  62. package/dist/backend/backend/src/controllers/task-management/tasks.controller.js.map +1 -1
  63. package/dist/backend/backend/src/controllers/team/team.controller.d.ts.map +1 -1
  64. package/dist/backend/backend/src/controllers/team/team.controller.js +49 -0
  65. package/dist/backend/backend/src/controllers/team/team.controller.js.map +1 -1
  66. package/dist/backend/backend/src/controllers/team-health/team-health.controller.d.ts +59 -0
  67. package/dist/backend/backend/src/controllers/team-health/team-health.controller.d.ts.map +1 -0
  68. package/dist/backend/backend/src/controllers/team-health/team-health.controller.js +127 -0
  69. package/dist/backend/backend/src/controllers/team-health/team-health.controller.js.map +1 -0
  70. package/dist/backend/backend/src/controllers/team-health/team-health.routes.d.ts +13 -0
  71. package/dist/backend/backend/src/controllers/team-health/team-health.routes.d.ts.map +1 -0
  72. package/dist/backend/backend/src/controllers/team-health/team-health.routes.js +20 -0
  73. package/dist/backend/backend/src/controllers/team-health/team-health.routes.js.map +1 -0
  74. package/dist/backend/backend/src/index.d.ts +9 -0
  75. package/dist/backend/backend/src/index.d.ts.map +1 -1
  76. package/dist/backend/backend/src/index.js +233 -0
  77. package/dist/backend/backend/src/index.js.map +1 -1
  78. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  79. package/dist/backend/backend/src/routes/api.routes.js +40 -6
  80. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  81. package/dist/backend/backend/src/services/agent/active-work-briefing.service.d.ts +498 -0
  82. package/dist/backend/backend/src/services/agent/active-work-briefing.service.d.ts.map +1 -0
  83. package/dist/backend/backend/src/services/agent/active-work-briefing.service.js +759 -0
  84. package/dist/backend/backend/src/services/agent/active-work-briefing.service.js.map +1 -0
  85. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +25 -0
  86. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  87. package/dist/backend/backend/src/services/agent/agent-registration.service.js +221 -58
  88. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  89. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.d.ts +9 -2
  90. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.d.ts.map +1 -1
  91. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.js +35 -2
  92. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.js.map +1 -1
  93. package/dist/backend/backend/src/services/agent/crewly-agent/types.d.ts +8 -2
  94. package/dist/backend/backend/src/services/agent/crewly-agent/types.d.ts.map +1 -1
  95. package/dist/backend/backend/src/services/agent/crewly-agent/types.js +1 -0
  96. package/dist/backend/backend/src/services/agent/crewly-agent/types.js.map +1 -1
  97. package/dist/backend/backend/src/services/agent/tmux-command.service.d.ts.map +1 -1
  98. package/dist/backend/backend/src/services/agent/tmux-command.service.js +2 -1
  99. package/dist/backend/backend/src/services/agent/tmux-command.service.js.map +1 -1
  100. package/dist/backend/backend/src/services/agent/tmux.service.d.ts.map +1 -1
  101. package/dist/backend/backend/src/services/agent/tmux.service.js +2 -1
  102. package/dist/backend/backend/src/services/agent/tmux.service.js.map +1 -1
  103. package/dist/backend/backend/src/services/ai/prompt-builder.service.d.ts +148 -3
  104. package/dist/backend/backend/src/services/ai/prompt-builder.service.d.ts.map +1 -1
  105. package/dist/backend/backend/src/services/ai/prompt-builder.service.js +241 -2
  106. package/dist/backend/backend/src/services/ai/prompt-builder.service.js.map +1 -1
  107. package/dist/backend/backend/src/services/ai/prompt-modules/recovery.module.d.ts.map +1 -1
  108. package/dist/backend/backend/src/services/ai/prompt-modules/recovery.module.js +13 -0
  109. package/dist/backend/backend/src/services/ai/prompt-modules/recovery.module.js.map +1 -1
  110. package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.d.ts.map +1 -1
  111. package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.js +26 -1
  112. package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.js.map +1 -1
  113. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.d.ts +79 -0
  114. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.d.ts.map +1 -0
  115. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.js +118 -0
  116. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.js.map +1 -0
  117. package/dist/backend/backend/src/services/browser/browser-bridge.service.d.ts +161 -0
  118. package/dist/backend/backend/src/services/browser/browser-bridge.service.d.ts.map +1 -1
  119. package/dist/backend/backend/src/services/browser/browser-bridge.service.js +382 -2
  120. package/dist/backend/backend/src/services/browser/browser-bridge.service.js.map +1 -1
  121. package/dist/backend/backend/src/services/browser/browser-proxy.service.d.ts +105 -0
  122. package/dist/backend/backend/src/services/browser/browser-proxy.service.d.ts.map +1 -1
  123. package/dist/backend/backend/src/services/browser/browser-proxy.service.js +232 -13
  124. package/dist/backend/backend/src/services/browser/browser-proxy.service.js.map +1 -1
  125. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts +178 -0
  126. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -0
  127. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +254 -0
  128. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -0
  129. package/dist/backend/backend/src/services/chat-v2/chat-v2.mention-resolver.d.ts +134 -0
  130. package/dist/backend/backend/src/services/chat-v2/chat-v2.mention-resolver.d.ts.map +1 -0
  131. package/dist/backend/backend/src/services/chat-v2/chat-v2.mention-resolver.js +232 -0
  132. package/dist/backend/backend/src/services/chat-v2/chat-v2.mention-resolver.js.map +1 -0
  133. package/dist/backend/backend/src/services/chat-v2/chat-v2.realtime-holder.d.ts +25 -0
  134. package/dist/backend/backend/src/services/chat-v2/chat-v2.realtime-holder.d.ts.map +1 -0
  135. package/dist/backend/backend/src/services/chat-v2/chat-v2.realtime-holder.js +23 -0
  136. package/dist/backend/backend/src/services/chat-v2/chat-v2.realtime-holder.js.map +1 -0
  137. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts +254 -0
  138. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts.map +1 -0
  139. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js +467 -0
  140. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js.map +1 -0
  141. package/dist/backend/backend/src/services/chat-v2/chat-v2.singleton.d.ts +27 -0
  142. package/dist/backend/backend/src/services/chat-v2/chat-v2.singleton.d.ts.map +1 -0
  143. package/dist/backend/backend/src/services/chat-v2/chat-v2.singleton.js +57 -0
  144. package/dist/backend/backend/src/services/chat-v2/chat-v2.singleton.js.map +1 -0
  145. package/dist/backend/backend/src/services/chat-v2/chat-v2.team-membership.d.ts +43 -0
  146. package/dist/backend/backend/src/services/chat-v2/chat-v2.team-membership.d.ts.map +1 -0
  147. package/dist/backend/backend/src/services/chat-v2/chat-v2.team-membership.js +54 -0
  148. package/dist/backend/backend/src/services/chat-v2/chat-v2.team-membership.js.map +1 -0
  149. package/dist/backend/backend/src/services/chat-v2/config.d.ts +100 -0
  150. package/dist/backend/backend/src/services/chat-v2/config.d.ts.map +1 -0
  151. package/dist/backend/backend/src/services/chat-v2/config.js +174 -0
  152. package/dist/backend/backend/src/services/chat-v2/config.js.map +1 -0
  153. package/dist/backend/backend/src/services/chat-v2/index.d.ts +11 -0
  154. package/dist/backend/backend/src/services/chat-v2/index.d.ts.map +1 -0
  155. package/dist/backend/backend/src/services/chat-v2/index.js +12 -0
  156. package/dist/backend/backend/src/services/chat-v2/index.js.map +1 -0
  157. package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.d.ts +114 -0
  158. package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.d.ts.map +1 -0
  159. package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.js +194 -0
  160. package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.js.map +1 -0
  161. package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.d.ts +100 -0
  162. package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.d.ts.map +1 -0
  163. package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.js +351 -0
  164. package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.js.map +1 -0
  165. package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.d.ts +132 -0
  166. package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.d.ts.map +1 -0
  167. package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.js +281 -0
  168. package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.js.map +1 -0
  169. package/dist/backend/backend/src/services/chat-v2/types.d.ts +295 -0
  170. package/dist/backend/backend/src/services/chat-v2/types.d.ts.map +1 -0
  171. package/dist/backend/backend/src/services/chat-v2/types.js +61 -0
  172. package/dist/backend/backend/src/services/chat-v2/types.js.map +1 -0
  173. package/dist/backend/backend/src/services/cloud/cloud-event-bridge.service.d.ts +113 -0
  174. package/dist/backend/backend/src/services/cloud/cloud-event-bridge.service.d.ts.map +1 -0
  175. package/dist/backend/backend/src/services/cloud/cloud-event-bridge.service.js +179 -0
  176. package/dist/backend/backend/src/services/cloud/cloud-event-bridge.service.js.map +1 -0
  177. package/dist/backend/backend/src/services/cloud/cloud-event-forwarder.service.d.ts +131 -0
  178. package/dist/backend/backend/src/services/cloud/cloud-event-forwarder.service.d.ts.map +1 -0
  179. package/dist/backend/backend/src/services/cloud/cloud-event-forwarder.service.js +227 -0
  180. package/dist/backend/backend/src/services/cloud/cloud-event-forwarder.service.js.map +1 -0
  181. package/dist/backend/backend/src/services/core/config.service.js +3 -3
  182. package/dist/backend/backend/src/services/core/config.service.js.map +1 -1
  183. package/dist/backend/backend/src/services/core/storage.service.d.ts +22 -0
  184. package/dist/backend/backend/src/services/core/storage.service.d.ts.map +1 -1
  185. package/dist/backend/backend/src/services/core/storage.service.js +57 -0
  186. package/dist/backend/backend/src/services/core/storage.service.js.map +1 -1
  187. package/dist/backend/backend/src/services/event-bus/event-bus.service.d.ts +69 -1
  188. package/dist/backend/backend/src/services/event-bus/event-bus.service.d.ts.map +1 -1
  189. package/dist/backend/backend/src/services/event-bus/event-bus.service.js +118 -0
  190. package/dist/backend/backend/src/services/event-bus/event-bus.service.js.map +1 -1
  191. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.d.ts +275 -0
  192. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.d.ts.map +1 -0
  193. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js +736 -0
  194. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js.map +1 -0
  195. package/dist/backend/backend/src/services/knowledge/fts5-index.service.d.ts.map +1 -1
  196. package/dist/backend/backend/src/services/knowledge/fts5-index.service.js +18 -2
  197. package/dist/backend/backend/src/services/knowledge/fts5-index.service.js.map +1 -1
  198. package/dist/backend/backend/src/services/knowledge/knowledge-search.service.d.ts +49 -13
  199. package/dist/backend/backend/src/services/knowledge/knowledge-search.service.d.ts.map +1 -1
  200. package/dist/backend/backend/src/services/knowledge/knowledge-search.service.js +123 -29
  201. package/dist/backend/backend/src/services/knowledge/knowledge-search.service.js.map +1 -1
  202. package/dist/backend/backend/src/services/knowledge/learnings-index.service.d.ts +159 -0
  203. package/dist/backend/backend/src/services/knowledge/learnings-index.service.d.ts.map +1 -0
  204. package/dist/backend/backend/src/services/knowledge/learnings-index.service.js +304 -0
  205. package/dist/backend/backend/src/services/knowledge/learnings-index.service.js.map +1 -0
  206. package/dist/backend/backend/src/services/knowledge/vector-store.service.d.ts.map +1 -1
  207. package/dist/backend/backend/src/services/knowledge/vector-store.service.js +24 -4
  208. package/dist/backend/backend/src/services/knowledge/vector-store.service.js.map +1 -1
  209. package/dist/backend/backend/src/services/memory/auto-learning.subscriber.d.ts +174 -0
  210. package/dist/backend/backend/src/services/memory/auto-learning.subscriber.d.ts.map +1 -0
  211. package/dist/backend/backend/src/services/memory/auto-learning.subscriber.js +375 -0
  212. package/dist/backend/backend/src/services/memory/auto-learning.subscriber.js.map +1 -0
  213. package/dist/backend/backend/src/services/memory/learning-format.validator.d.ts +97 -0
  214. package/dist/backend/backend/src/services/memory/learning-format.validator.d.ts.map +1 -0
  215. package/dist/backend/backend/src/services/memory/learning-format.validator.js +209 -0
  216. package/dist/backend/backend/src/services/memory/learning-format.validator.js.map +1 -0
  217. package/dist/backend/backend/src/services/memory/vector-store.service.d.ts.map +1 -1
  218. package/dist/backend/backend/src/services/memory/vector-store.service.js +19 -4
  219. package/dist/backend/backend/src/services/memory/vector-store.service.js.map +1 -1
  220. package/dist/backend/backend/src/services/onboarding/onboarding-provision.service.d.ts +16 -5
  221. package/dist/backend/backend/src/services/onboarding/onboarding-provision.service.d.ts.map +1 -1
  222. package/dist/backend/backend/src/services/onboarding/onboarding-provision.service.js +32 -5
  223. package/dist/backend/backend/src/services/onboarding/onboarding-provision.service.js.map +1 -1
  224. package/dist/backend/backend/src/services/onboarding/onboarding.service.d.ts +157 -0
  225. package/dist/backend/backend/src/services/onboarding/onboarding.service.d.ts.map +1 -0
  226. package/dist/backend/backend/src/services/onboarding/onboarding.service.js +229 -0
  227. package/dist/backend/backend/src/services/onboarding/onboarding.service.js.map +1 -0
  228. package/dist/backend/backend/src/services/onboarding/onboarding.types.d.ts +141 -0
  229. package/dist/backend/backend/src/services/onboarding/onboarding.types.d.ts.map +1 -0
  230. package/dist/backend/backend/src/services/onboarding/onboarding.types.js +18 -0
  231. package/dist/backend/backend/src/services/onboarding/onboarding.types.js.map +1 -0
  232. package/dist/backend/backend/src/services/pr-review/pr-review.service.d.ts.map +1 -1
  233. package/dist/backend/backend/src/services/pr-review/pr-review.service.js +1 -1
  234. package/dist/backend/backend/src/services/pr-review/pr-review.service.js.map +1 -1
  235. package/dist/backend/backend/src/services/slack/cross-machine-message.service.d.ts.map +1 -1
  236. package/dist/backend/backend/src/services/slack/cross-machine-message.service.js +17 -1
  237. package/dist/backend/backend/src/services/slack/cross-machine-message.service.js.map +1 -1
  238. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts +39 -1
  239. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
  240. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js +158 -26
  241. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
  242. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +248 -6
  243. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  244. package/dist/backend/backend/src/services/task-pool/task-pool.service.js +531 -51
  245. package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  246. package/dist/backend/backend/src/services/team-health/index.d.ts +16 -0
  247. package/dist/backend/backend/src/services/team-health/index.d.ts.map +1 -0
  248. package/dist/backend/backend/src/services/team-health/index.js +16 -0
  249. package/dist/backend/backend/src/services/team-health/index.js.map +1 -0
  250. package/dist/backend/backend/src/services/team-health/live-team-health-data-provider.d.ts +52 -0
  251. package/dist/backend/backend/src/services/team-health/live-team-health-data-provider.d.ts.map +1 -0
  252. package/dist/backend/backend/src/services/team-health/live-team-health-data-provider.js +161 -0
  253. package/dist/backend/backend/src/services/team-health/live-team-health-data-provider.js.map +1 -0
  254. package/dist/backend/backend/src/services/team-health/lost-dispatch-detector.d.ts +53 -0
  255. package/dist/backend/backend/src/services/team-health/lost-dispatch-detector.d.ts.map +1 -0
  256. package/dist/backend/backend/src/services/team-health/lost-dispatch-detector.js +88 -0
  257. package/dist/backend/backend/src/services/team-health/lost-dispatch-detector.js.map +1 -0
  258. package/dist/backend/backend/src/services/team-health/stale-trigger-detector.d.ts +44 -0
  259. package/dist/backend/backend/src/services/team-health/stale-trigger-detector.d.ts.map +1 -0
  260. package/dist/backend/backend/src/services/team-health/stale-trigger-detector.js +83 -0
  261. package/dist/backend/backend/src/services/team-health/stale-trigger-detector.js.map +1 -0
  262. package/dist/backend/backend/src/services/team-health/team-health-alert-router.d.ts +92 -0
  263. package/dist/backend/backend/src/services/team-health/team-health-alert-router.d.ts.map +1 -0
  264. package/dist/backend/backend/src/services/team-health/team-health-alert-router.js +328 -0
  265. package/dist/backend/backend/src/services/team-health/team-health-alert-router.js.map +1 -0
  266. package/dist/backend/backend/src/services/team-health/team-health-config.d.ts +41 -0
  267. package/dist/backend/backend/src/services/team-health/team-health-config.d.ts.map +1 -0
  268. package/dist/backend/backend/src/services/team-health/team-health-config.js +213 -0
  269. package/dist/backend/backend/src/services/team-health/team-health-config.js.map +1 -0
  270. package/dist/backend/backend/src/services/team-health/team-health-detector.d.ts +46 -0
  271. package/dist/backend/backend/src/services/team-health/team-health-detector.d.ts.map +1 -0
  272. package/dist/backend/backend/src/services/team-health/team-health-detector.js +347 -0
  273. package/dist/backend/backend/src/services/team-health/team-health-detector.js.map +1 -0
  274. package/dist/backend/backend/src/services/team-health/team-health-types.d.ts +154 -0
  275. package/dist/backend/backend/src/services/team-health/team-health-types.d.ts.map +1 -0
  276. package/dist/backend/backend/src/services/team-health/team-health-types.js +94 -0
  277. package/dist/backend/backend/src/services/team-health/team-health-types.js.map +1 -0
  278. package/dist/backend/backend/src/services/team-health/team-health-watchdog.service.d.ts +111 -0
  279. package/dist/backend/backend/src/services/team-health/team-health-watchdog.service.d.ts.map +1 -0
  280. package/dist/backend/backend/src/services/team-health/team-health-watchdog.service.js +226 -0
  281. package/dist/backend/backend/src/services/team-health/team-health-watchdog.service.js.map +1 -0
  282. package/dist/backend/backend/src/services/v3/mission-reminder.service.d.ts +148 -0
  283. package/dist/backend/backend/src/services/v3/mission-reminder.service.d.ts.map +1 -0
  284. package/dist/backend/backend/src/services/v3/mission-reminder.service.js +545 -0
  285. package/dist/backend/backend/src/services/v3/mission-reminder.service.js.map +1 -0
  286. package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts +499 -0
  287. package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts.map +1 -0
  288. package/dist/backend/backend/src/services/v3/request-sla.subscriber.js +1105 -0
  289. package/dist/backend/backend/src/services/v3/request-sla.subscriber.js.map +1 -0
  290. package/dist/backend/backend/src/services/v3/request.service.d.ts +22 -0
  291. package/dist/backend/backend/src/services/v3/request.service.d.ts.map +1 -1
  292. package/dist/backend/backend/src/services/v3/request.service.js +71 -0
  293. package/dist/backend/backend/src/services/v3/request.service.js.map +1 -1
  294. package/dist/backend/backend/src/services/v3/v3-data.service.d.ts +1 -0
  295. package/dist/backend/backend/src/services/v3/v3-data.service.d.ts.map +1 -1
  296. package/dist/backend/backend/src/services/v3/v3-data.service.js +22 -6
  297. package/dist/backend/backend/src/services/v3/v3-data.service.js.map +1 -1
  298. package/dist/backend/backend/src/types/event-bus.types.d.ts +19 -1
  299. package/dist/backend/backend/src/types/event-bus.types.d.ts.map +1 -1
  300. package/dist/backend/backend/src/types/event-bus.types.js +43 -0
  301. package/dist/backend/backend/src/types/event-bus.types.js.map +1 -1
  302. package/dist/backend/backend/src/types/index.d.ts +22 -1
  303. package/dist/backend/backend/src/types/index.d.ts.map +1 -1
  304. package/dist/backend/backend/src/types/index.js.map +1 -1
  305. package/dist/backend/backend/src/types/review-reason.types.d.ts +63 -0
  306. package/dist/backend/backend/src/types/review-reason.types.d.ts.map +1 -0
  307. package/dist/backend/backend/src/types/review-reason.types.js +50 -0
  308. package/dist/backend/backend/src/types/review-reason.types.js.map +1 -0
  309. package/dist/backend/backend/src/types/slack.types.d.ts +4 -1
  310. package/dist/backend/backend/src/types/slack.types.d.ts.map +1 -1
  311. package/dist/backend/backend/src/types/slack.types.js.map +1 -1
  312. package/dist/backend/backend/src/types/v2/mission.types.d.ts +18 -0
  313. package/dist/backend/backend/src/types/v2/mission.types.d.ts.map +1 -1
  314. package/dist/backend/backend/src/types/v2/mission.types.js +1 -0
  315. package/dist/backend/backend/src/types/v2/mission.types.js.map +1 -1
  316. package/dist/backend/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  317. package/dist/backend/backend/src/types/v2/work-item.types.js +25 -1
  318. package/dist/backend/backend/src/types/v2/work-item.types.js.map +1 -1
  319. package/dist/backend/backend/src/utils/team.utils.d.ts +38 -0
  320. package/dist/backend/backend/src/utils/team.utils.d.ts.map +1 -0
  321. package/dist/backend/backend/src/utils/team.utils.js +45 -0
  322. package/dist/backend/backend/src/utils/team.utils.js.map +1 -0
  323. package/dist/backend/backend/src/websocket/chat-v2.gateway.d.ts +195 -0
  324. package/dist/backend/backend/src/websocket/chat-v2.gateway.d.ts.map +1 -0
  325. package/dist/backend/backend/src/websocket/chat-v2.gateway.js +401 -0
  326. package/dist/backend/backend/src/websocket/chat-v2.gateway.js.map +1 -0
  327. package/dist/backend/backend/src/websocket/terminal.gateway.d.ts +37 -2
  328. package/dist/backend/backend/src/websocket/terminal.gateway.d.ts.map +1 -1
  329. package/dist/backend/backend/src/websocket/terminal.gateway.js +106 -5
  330. package/dist/backend/backend/src/websocket/terminal.gateway.js.map +1 -1
  331. package/dist/cli/backend/src/constants.d.ts +69 -1
  332. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  333. package/dist/cli/backend/src/constants.js +69 -2
  334. package/dist/cli/backend/src/constants.js.map +1 -1
  335. package/dist/cli/backend/src/services/core/config.service.js +3 -3
  336. package/dist/cli/backend/src/services/core/config.service.js.map +1 -1
  337. package/dist/cli/backend/src/services/core/storage.service.d.ts +22 -0
  338. package/dist/cli/backend/src/services/core/storage.service.d.ts.map +1 -1
  339. package/dist/cli/backend/src/services/core/storage.service.js +57 -0
  340. package/dist/cli/backend/src/services/core/storage.service.js.map +1 -1
  341. package/dist/cli/backend/src/services/knowledge/fts5-index.service.d.ts.map +1 -1
  342. package/dist/cli/backend/src/services/knowledge/fts5-index.service.js +18 -2
  343. package/dist/cli/backend/src/services/knowledge/fts5-index.service.js.map +1 -1
  344. package/dist/cli/backend/src/services/knowledge/knowledge-search.service.d.ts +49 -13
  345. package/dist/cli/backend/src/services/knowledge/knowledge-search.service.d.ts.map +1 -1
  346. package/dist/cli/backend/src/services/knowledge/knowledge-search.service.js +123 -29
  347. package/dist/cli/backend/src/services/knowledge/knowledge-search.service.js.map +1 -1
  348. package/dist/cli/backend/src/services/knowledge/vector-store.service.d.ts.map +1 -1
  349. package/dist/cli/backend/src/services/knowledge/vector-store.service.js +24 -4
  350. package/dist/cli/backend/src/services/knowledge/vector-store.service.js.map +1 -1
  351. package/dist/cli/backend/src/types/index.d.ts +22 -1
  352. package/dist/cli/backend/src/types/index.d.ts.map +1 -1
  353. package/dist/cli/backend/src/types/index.js.map +1 -1
  354. package/dist/cli/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  355. package/dist/cli/backend/src/types/v2/work-item.types.js +25 -1
  356. package/dist/cli/backend/src/types/v2/work-item.types.js.map +1 -1
  357. package/frontend/dist/assets/{index-70356616.js → index-7a4e7df5.js} +328 -326
  358. package/frontend/dist/assets/index-b7e59b2b.css +33 -0
  359. package/frontend/dist/index.html +2 -2
  360. package/package.json +2 -1
  361. package/config/skills/orchestrator/recall/SKILL.md +0 -47
  362. package/config/skills/orchestrator/recall/execute.sh +0 -13
  363. package/config/skills/orchestrator/record-learning/SKILL.md +0 -47
  364. package/config/skills/orchestrator/record-learning/execute.sh +0 -13
  365. package/config/skills/orchestrator/remember/SKILL.md +0 -55
  366. package/config/skills/orchestrator/remember/execute.sh +0 -15
  367. package/frontend/dist/assets/index-6aaa0630.css +0 -33
@@ -0,0 +1,736 @@
1
+ /**
2
+ * EventToWorkItemBridge
3
+ *
4
+ * Subscribes to autonomy-relevant events on the EventBus and creates the
5
+ * appropriate WorkItem(s) so the autonomy chain advances without an explicit
6
+ * Trigger Engine (Arch Veto V5 — `.crewly/tmp/autonomy-doc-review-arch-2026-04-26.md`).
7
+ *
8
+ * Subscribed events (all `CRITICAL_EVENT_TYPES`):
9
+ * - `task:done_by_worker` → verification WI for TL
10
+ * - `task:rejected` → retry WI (or escalation review WI at retry cap)
11
+ * - `task:blocked` → review WI (`reviewReason: 'task_blocked'`)
12
+ * - `team:all_tasks_done` → emit `mission:review_due` (if mission active)
13
+ * - `mission:review_due` → review WI mirroring REVIEW-1's id pattern
14
+ * - `mission:stale` → review WI (`reviewReason: 'no_active_work'`)
15
+ * - `mission:replanned` → review WI (`reviewReason: 'scheduled_review'`)
16
+ *
17
+ * Idempotency contract (Arch Veto V1):
18
+ * Every auto-created WorkItem carries a deterministic `id` and a documentary
19
+ * `metadata.idempotencyKey === id`. The real dedup gate is
20
+ * `TaskPoolService.addToPool` which short-circuits on duplicate id. So a
21
+ * replayed event fires the bridge handler again, the bridge re-builds the
22
+ * same id, and addToPool's existing dedup is the safety net — no separate
23
+ * idempotency store needed.
24
+ *
25
+ * Retry cap (Arch Veto V2):
26
+ * `task:rejected` increments `retryCount` on the new retry WI. At
27
+ * `sourceWI.retryCount >= DEFAULT_MAX_RETRIES` (3) the bridge escalates to
28
+ * a review WI for the TL with `reviewReason: 'max_retries_exceeded'` and
29
+ * does NOT enqueue another retry. Retry WIs target the original worker;
30
+ * escalation WIs target the team lead resolved via `pickTeamLead()`.
31
+ *
32
+ * Status mutations (Arch Veto V3):
33
+ * The bridge does NOT mutate status directly — every state change goes
34
+ * through `TaskPoolService.transitionStatus()` (the canonical guarded
35
+ * entrypoint TRANS-1 shipped). Search guard (see PR body for full grep
36
+ * command — kept out of the doc comment so the grep doesn't false-positive
37
+ * on its own description).
38
+ *
39
+ * Team-lead resolution (Arch Veto V4):
40
+ * `pickTeamLead()` may return `null`. The bridge throws
41
+ * {@link BridgeTeamLeadResolutionError} on null — no silent fallback to
42
+ * the executor session.
43
+ *
44
+ * No parallel scheduler entity (Arch Veto V5):
45
+ * The bridge is a pure event listener. It does NOT subclass anything called
46
+ * "Trigger", does NOT create one, does NOT register with a TriggerEngine.
47
+ * See PR body for the grep guard command.
48
+ *
49
+ * Cron-recursion block (Arch Vetos V6 / V9):
50
+ * When the bridge derives a new WI from a source WI whose
51
+ * `metadata.triggerSource === 'cron'`, the new WI's triggerSource is
52
+ * demoted to `'event'` (cron sessions cannot beget more cron jobs). Any
53
+ * call to {@link assertNoCronFromCron} from a cron-source WI throws
54
+ * {@link CronRecursionError}. The retry path tags `triggerSource: 'event'`
55
+ * directly so demotion is the default rather than the exceptional path.
56
+ *
57
+ * @module services/event-bus/event-to-workitem-bridge
58
+ */
59
+ import { LoggerService } from '../core/logger.service.js';
60
+ import { StorageService } from '../core/storage.service.js';
61
+ import { TaskPoolService } from '../task-pool/task-pool.service.js';
62
+ import { pickTeamLead } from '../../utils/team.utils.js';
63
+ import { ORCHESTRATOR_SESSION_NAME } from '../../constants.js';
64
+ import { formatError } from '../../utils/format-error.js';
65
+ import { DEFAULT_MAX_RETRIES, } from '../../types/v2/work-item.types.js';
66
+ import { isReviewReason, } from '../../types/review-reason.types.js';
67
+ // ---------------------------------------------------------------------------
68
+ // Constants
69
+ // ---------------------------------------------------------------------------
70
+ /**
71
+ * Event types the bridge subscribes to. Listed in the same order as the
72
+ * dispatch table to make the start() registration easy to audit.
73
+ */
74
+ export const BRIDGE_SUBSCRIBED_EVENTS = [
75
+ 'task:done_by_worker',
76
+ 'task:rejected',
77
+ 'task:blocked',
78
+ 'team:all_tasks_done',
79
+ 'mission:review_due',
80
+ 'mission:stale',
81
+ 'mission:replanned',
82
+ ];
83
+ // ---------------------------------------------------------------------------
84
+ // Errors
85
+ // ---------------------------------------------------------------------------
86
+ /**
87
+ * Thrown when a cron-sourced WorkItem attempts to create another cron-recurring
88
+ * WorkItem. Encoded as a named error so tests + observability can distinguish
89
+ * the recursion guard from generic bridge errors.
90
+ */
91
+ export class CronRecursionError extends Error {
92
+ constructor(message) {
93
+ super(message);
94
+ this.name = 'CronRecursionError';
95
+ }
96
+ }
97
+ /**
98
+ * Thrown when the bridge cannot resolve a Team Lead session for a team that
99
+ * needs an escalation/verification WorkItem. Per Arch Veto V4 the bridge
100
+ * MUST NOT silently fall back to the executor session — losing visibility
101
+ * on a stalled escalation is worse than failing loudly.
102
+ */
103
+ export class BridgeTeamLeadResolutionError extends Error {
104
+ constructor(message) {
105
+ super(message);
106
+ this.name = 'BridgeTeamLeadResolutionError';
107
+ }
108
+ }
109
+ // ---------------------------------------------------------------------------
110
+ // Helpers
111
+ // ---------------------------------------------------------------------------
112
+ /** Day-bucket cycle key used by mission cadence handlers. */
113
+ function todayCycleKey(now = new Date()) {
114
+ return now.toISOString().slice(0, 10);
115
+ }
116
+ /**
117
+ * V6 / V9 guard: throw if a cron-sourced WI tries to create another cron job.
118
+ *
119
+ * @param sourceWI - WI being reacted to
120
+ * @param attemptedAction - Short label for the action that would create cron
121
+ * @throws CronRecursionError when sourceWI.metadata.triggerSource === 'cron'
122
+ */
123
+ export function assertNoCronFromCron(sourceWI, attemptedAction) {
124
+ const triggerSource = sourceWI.metadata?.['triggerSource'];
125
+ if (triggerSource === 'cron') {
126
+ throw new CronRecursionError(`Refusing ${attemptedAction}: source WorkItem ${sourceWI.id} has triggerSource='cron'. ` +
127
+ `Cron-fired sessions cannot create new cron / recurring schedules.`);
128
+ }
129
+ }
130
+ /**
131
+ * Derive the trigger source for a downstream WI. Defaults to `'event'`. If the
132
+ * source WI was cron-fired, the downstream WI is demoted to `'event'` (V6 / V9).
133
+ *
134
+ * @param sourceWI - Optional source WorkItem
135
+ * @returns The triggerSource value to tag on the new WorkItem
136
+ */
137
+ function inheritedTriggerSource(sourceWI) {
138
+ const tag = sourceWI?.metadata?.['triggerSource'];
139
+ if (tag === 'cron')
140
+ return 'event'; // demote
141
+ if (tag === 'manual')
142
+ return 'manual';
143
+ return 'event';
144
+ }
145
+ /**
146
+ * EventToWorkItemBridge — the BRIDGE-1 deliverable.
147
+ *
148
+ * Wired in `backend/src/index.ts` via {@link EventToWorkItemBridge.boot}; tests
149
+ * construct via the {@link EventToWorkItemBridge} constructor directly with
150
+ * fake dependencies.
151
+ *
152
+ * @example
153
+ * ```typescript
154
+ * const bridge = EventToWorkItemBridge.boot(eventBus);
155
+ * bridge.start();
156
+ * // … later, on shutdown:
157
+ * bridge.stop();
158
+ * ```
159
+ */
160
+ export class EventToWorkItemBridge {
161
+ eventBus;
162
+ taskPool;
163
+ loadMission;
164
+ loadTeam;
165
+ logger;
166
+ unsubscribers = [];
167
+ started = false;
168
+ /**
169
+ * In-flight async handler invocations. Test code calls
170
+ * {@link flushPending} to await every in-flight dispatch deterministically.
171
+ * Production code never reads this — handlers continue running off the
172
+ * event loop with their own try/catch.
173
+ */
174
+ pendingDispatches = new Set();
175
+ constructor(deps) {
176
+ this.eventBus = deps.eventBus;
177
+ this.taskPool = deps.taskPool;
178
+ this.loadMission = deps.loadMission;
179
+ this.loadTeam = deps.loadTeam;
180
+ this.logger =
181
+ deps.logger ?? LoggerService.getInstance().createComponentLogger('EventToWorkItemBridge');
182
+ }
183
+ /**
184
+ * Production wiring helper — constructs a bridge from singletons.
185
+ *
186
+ * Tests should use the constructor directly with fake `loadMission` /
187
+ * `loadTeam` rather than reaching for `boot`.
188
+ *
189
+ * @param eventBus - The live event bus
190
+ * @returns A bridge instance ready to `start()`
191
+ */
192
+ static boot(eventBus) {
193
+ const taskPool = TaskPoolService.getInstance();
194
+ const storage = StorageService.getInstance();
195
+ return new EventToWorkItemBridge({
196
+ eventBus,
197
+ taskPool,
198
+ loadMission: async (missionId) => {
199
+ // Storage exposes mission read by id; fall back to null on miss/error
200
+ try {
201
+ const mission = await storage.getMissionById?.(missionId);
202
+ return mission ?? null;
203
+ }
204
+ catch {
205
+ return null;
206
+ }
207
+ },
208
+ loadTeam: async (teamId) => {
209
+ const teams = await storage.getTeams();
210
+ return teams.find((t) => t.id === teamId) ?? null;
211
+ },
212
+ });
213
+ }
214
+ /**
215
+ * Subscribe to all bridge events. Idempotent — calling twice is a no-op.
216
+ *
217
+ * Each handler is wrapped so that a thrown error inside a single event
218
+ * dispatch is logged but does NOT propagate to `EventBus.publish()`. The
219
+ * EventBus itself also isolates handler errors (see
220
+ * `dispatchInProcess`); the inner try/catch belt-and-braces against the
221
+ * particular case where a handler returns a non-Promise that subsequently
222
+ * throws on access (rare but observed in jest fake-timer setups).
223
+ */
224
+ start() {
225
+ if (this.started)
226
+ return;
227
+ this.started = true;
228
+ this.unsubscribers.push(this.eventBus.onInProcess('task:done_by_worker', (e) => this.safeDispatch('task:done_by_worker', e, this.handleTaskDoneByWorker)), this.eventBus.onInProcess('task:rejected', (e) => this.safeDispatch('task:rejected', e, this.handleTaskRejected)), this.eventBus.onInProcess('task:blocked', (e) => this.safeDispatch('task:blocked', e, this.handleTaskBlocked)), this.eventBus.onInProcess('team:all_tasks_done', (e) => this.safeDispatch('team:all_tasks_done', e, this.handleTeamAllTasksDone)), this.eventBus.onInProcess('mission:review_due', (e) => this.safeDispatch('mission:review_due', e, this.handleMissionReviewDue)), this.eventBus.onInProcess('mission:stale', (e) => this.safeDispatch('mission:stale', e, this.handleMissionStale)), this.eventBus.onInProcess('mission:replanned', (e) => this.safeDispatch('mission:replanned', e, this.handleMissionReplanned)));
229
+ this.logger.info('EventToWorkItemBridge subscribed', {
230
+ eventTypes: BRIDGE_SUBSCRIBED_EVENTS,
231
+ });
232
+ }
233
+ /**
234
+ * Wait for every in-flight handler dispatch to settle. Test affordance —
235
+ * production code does not need this; the EventBus + safeDispatch already
236
+ * isolate handler errors. Tests use it to assert deterministically that
237
+ * `addToPool` has been called by the time the expectation runs, even
238
+ * though `EventBus.publish` is synchronous and bridge handlers are async.
239
+ *
240
+ * Calling more than once is safe — pending dispatches are removed as they
241
+ * settle, so a second call is effectively a no-op when nothing is in flight.
242
+ */
243
+ async flushPending() {
244
+ while (this.pendingDispatches.size > 0) {
245
+ // Snapshot the current pending set; new entries added by handlers (e.g.
246
+ // bridge re-emitting `mission:review_due` from `team:all_tasks_done`)
247
+ // will appear in the next loop iteration.
248
+ const inFlight = Array.from(this.pendingDispatches);
249
+ await Promise.allSettled(inFlight);
250
+ }
251
+ }
252
+ /**
253
+ * Detach every subscription. Safe to call multiple times.
254
+ */
255
+ stop() {
256
+ for (const unsubscribe of this.unsubscribers) {
257
+ try {
258
+ unsubscribe();
259
+ }
260
+ catch (err) {
261
+ this.logger.warn('Bridge unsubscribe threw', { error: formatError(err) });
262
+ }
263
+ }
264
+ this.unsubscribers = [];
265
+ this.started = false;
266
+ this.logger.info('EventToWorkItemBridge stopped');
267
+ }
268
+ // -------------------------------------------------------------------------
269
+ // Event handlers — each returns a Promise so onInProcess can attach .catch()
270
+ // -------------------------------------------------------------------------
271
+ /**
272
+ * `task:done_by_worker` → create a verification WI for the team lead.
273
+ *
274
+ * Idempotency: `${sourceWI.id}:verify:${sourceWI.id}` (one verify WI per task done).
275
+ * V4: throws if no TL resolvable.
276
+ */
277
+ handleTaskDoneByWorker = async (event) => {
278
+ const sourceWI = await this.resolveSourceWorkItem(event);
279
+ if (!sourceWI) {
280
+ this.logger.warn('task:done_by_worker missing source WorkItem', {
281
+ eventId: event.id,
282
+ workItemId: event.workItemId,
283
+ taskId: event.taskId,
284
+ });
285
+ return;
286
+ }
287
+ const target = await this.resolveTeamLeadSession(sourceWI);
288
+ const verifyId = `${sourceWI.id}:verify:${sourceWI.id}`;
289
+ const verifyWI = this.buildAutoWorkItem({
290
+ id: verifyId,
291
+ type: 'review',
292
+ owner: 'team_lead',
293
+ target,
294
+ title: `Verify: ${sourceWI.title}`,
295
+ description: `Worker reported done on ${sourceWI.id}. Verify the deliverable.`,
296
+ sourceWI,
297
+ missionId: sourceWI.missionId,
298
+ requestId: sourceWI.requestId,
299
+ retryCount: 0,
300
+ extraMetadata: {
301
+ idempotencyKey: verifyId, // V1 (per-handler)
302
+ sourceWorkItemId: sourceWI.id,
303
+ verifyOf: sourceWI.id,
304
+ },
305
+ });
306
+ await this.taskPool.addToPool(verifyWI);
307
+ this.logger.info('Verification WorkItem created', {
308
+ sourceWorkItemId: sourceWI.id,
309
+ verifyWorkItemId: verifyId,
310
+ target,
311
+ });
312
+ };
313
+ /**
314
+ * `task:rejected` → retry WI (cap at DEFAULT_MAX_RETRIES) or escalation review WI.
315
+ *
316
+ * - retryCount < cap → retry WI assigned to original worker, retryCount + 1
317
+ * - retryCount >= cap → review WI for TL with reviewReason='max_retries_exceeded'
318
+ *
319
+ * Idempotency:
320
+ * - retry path: `${sourceWI.id}:retry:${retryAttempt}`
321
+ * - escalation: `${sourceWI.id}:review:max_retries`
322
+ */
323
+ handleTaskRejected = async (event) => {
324
+ const sourceWI = await this.resolveSourceWorkItem(event);
325
+ if (!sourceWI) {
326
+ this.logger.warn('task:rejected missing source WorkItem', { eventId: event.id });
327
+ return;
328
+ }
329
+ const cap = sourceWI.maxRetries > 0 ? sourceWI.maxRetries : DEFAULT_MAX_RETRIES;
330
+ if (sourceWI.retryCount >= cap) {
331
+ // V2 escalation path
332
+ const escalationId = `${sourceWI.id}:review:max_retries`;
333
+ const target = await this.resolveTeamLeadSession(sourceWI);
334
+ const reason = 'max_retries_exceeded';
335
+ // 1-line cheap guard against silent typo drift (Sam's reminder)
336
+ if (!isReviewReason(reason)) {
337
+ throw new Error(`BRIDGE-1: invalid reviewReason ${String(reason)}`);
338
+ }
339
+ const escalationWI = this.buildAutoWorkItem({
340
+ id: escalationId,
341
+ type: 'review',
342
+ owner: 'team_lead',
343
+ target,
344
+ title: `Escalation: ${sourceWI.title} rejected ${sourceWI.retryCount}x`,
345
+ description: `Source WorkItem ${sourceWI.id} has been rejected ${sourceWI.retryCount} times ` +
346
+ `(cap = ${cap}). TL must re-scope, reassign, or cancel.`,
347
+ sourceWI,
348
+ missionId: sourceWI.missionId,
349
+ requestId: sourceWI.requestId,
350
+ retryCount: 0,
351
+ extraMetadata: {
352
+ idempotencyKey: escalationId, // V1 (per-handler)
353
+ sourceWorkItemId: sourceWI.id,
354
+ reviewReason: reason,
355
+ escalatedRetryCount: sourceWI.retryCount,
356
+ },
357
+ });
358
+ await this.taskPool.addToPool(escalationWI);
359
+ this.logger.info('Retry cap reached — escalation WorkItem created', {
360
+ sourceWorkItemId: sourceWI.id,
361
+ escalationWorkItemId: escalationId,
362
+ retryCount: sourceWI.retryCount,
363
+ cap,
364
+ });
365
+ return;
366
+ }
367
+ // Retry path
368
+ const retryAttempt = sourceWI.retryCount + 1;
369
+ const retryId = `${sourceWI.id}:retry:${retryAttempt}`;
370
+ const retryWI = this.buildAutoWorkItem({
371
+ id: retryId,
372
+ type: sourceWI.type,
373
+ owner: sourceWI.owner,
374
+ target: sourceWI.target,
375
+ title: `Retry ${retryAttempt}/${cap}: ${sourceWI.title}`,
376
+ description: sourceWI.description,
377
+ sourceWI,
378
+ missionId: sourceWI.missionId,
379
+ requestId: sourceWI.requestId,
380
+ retryCount: retryAttempt,
381
+ extraMetadata: {
382
+ idempotencyKey: retryId, // V1 (per-handler)
383
+ sourceWorkItemId: sourceWI.id,
384
+ retryAttempt,
385
+ },
386
+ });
387
+ await this.taskPool.addToPool(retryWI);
388
+ this.logger.info('Retry WorkItem created', {
389
+ sourceWorkItemId: sourceWI.id,
390
+ retryWorkItemId: retryId,
391
+ retryAttempt,
392
+ cap,
393
+ });
394
+ };
395
+ /**
396
+ * `task:blocked` → review WI for TL with `reviewReason='task_blocked'`.
397
+ *
398
+ * Idempotency: `${sourceWI.id}:review:blocked` (one review per blocked WI).
399
+ */
400
+ handleTaskBlocked = async (event) => {
401
+ const sourceWI = await this.resolveSourceWorkItem(event);
402
+ if (!sourceWI) {
403
+ this.logger.warn('task:blocked missing source WorkItem', { eventId: event.id });
404
+ return;
405
+ }
406
+ const blockedId = `${sourceWI.id}:review:blocked`;
407
+ const target = await this.resolveTeamLeadSession(sourceWI);
408
+ const reason = 'task_blocked';
409
+ if (!isReviewReason(reason)) {
410
+ throw new Error(`BRIDGE-1: invalid reviewReason ${String(reason)}`);
411
+ }
412
+ const reviewWI = this.buildAutoWorkItem({
413
+ id: blockedId,
414
+ type: 'review',
415
+ owner: 'team_lead',
416
+ target,
417
+ title: `Blocked: ${sourceWI.title}`,
418
+ description: `Source WorkItem ${sourceWI.id} entered 'blocked' status. TL must unblock or re-scope.`,
419
+ sourceWI,
420
+ missionId: sourceWI.missionId,
421
+ requestId: sourceWI.requestId,
422
+ retryCount: 0,
423
+ extraMetadata: {
424
+ idempotencyKey: blockedId, // V1 (per-handler)
425
+ sourceWorkItemId: sourceWI.id,
426
+ reviewReason: reason,
427
+ },
428
+ });
429
+ await this.taskPool.addToPool(reviewWI);
430
+ this.logger.info('Blocked-task review WorkItem created', {
431
+ sourceWorkItemId: sourceWI.id,
432
+ reviewWorkItemId: blockedId,
433
+ target,
434
+ });
435
+ };
436
+ /**
437
+ * `team:all_tasks_done` → emit `mission:review_due` if mission is active.
438
+ *
439
+ * The downstream `mission:review_due` handler then creates the actual
440
+ * review WorkItem. We split the emission from the WI-creation so the
441
+ * existing REVIEW-1 sweep path and BRIDGE-1's event-driven path converge
442
+ * on the same idempotency key (REVIEW-1 uses `${missionId}:review:${YYYY-MM-DD}`;
443
+ * BRIDGE-1's mission:review_due handler uses the same).
444
+ */
445
+ handleTeamAllTasksDone = async (event) => {
446
+ if (!event.missionId) {
447
+ this.logger.debug('team:all_tasks_done without missionId — ignoring', {
448
+ eventId: event.id,
449
+ });
450
+ return;
451
+ }
452
+ const mission = await this.loadMission(event.missionId);
453
+ if (!mission) {
454
+ this.logger.warn('team:all_tasks_done references unknown mission', {
455
+ missionId: event.missionId,
456
+ });
457
+ return;
458
+ }
459
+ if (mission.status !== 'active') {
460
+ this.logger.debug('team:all_tasks_done for non-active mission — skipping emit', {
461
+ missionId: mission.id,
462
+ status: mission.status,
463
+ });
464
+ return;
465
+ }
466
+ // Re-emit as mission:review_due so the downstream handler creates the WI.
467
+ // This preserves the deterministic-id contract — the downstream handler
468
+ // is the single point that creates review WIs for missions.
469
+ this.eventBus.publish({
470
+ id: `${mission.id}:emit:review_due:${todayCycleKey()}`,
471
+ type: 'mission:review_due',
472
+ timestamp: new Date().toISOString(),
473
+ teamId: mission.ownerTeamId,
474
+ teamName: '',
475
+ memberId: '',
476
+ memberName: '',
477
+ sessionName: '',
478
+ previousValue: '',
479
+ newValue: 'review_due',
480
+ changedField: 'taskStatus',
481
+ missionId: mission.id,
482
+ });
483
+ this.logger.info('Emitted mission:review_due for active mission', {
484
+ missionId: mission.id,
485
+ });
486
+ };
487
+ /**
488
+ * `mission:review_due` → review WI mirroring REVIEW-1's id pattern.
489
+ * Idempotency: `${missionId}:review:${YYYY-MM-DD}` — same as REVIEW-1.
490
+ */
491
+ handleMissionReviewDue = async (event) => {
492
+ if (!event.missionId)
493
+ return;
494
+ const mission = await this.loadMission(event.missionId);
495
+ if (!mission)
496
+ return;
497
+ const cycleId = todayCycleKey();
498
+ const id = `${mission.id}:review:${cycleId}`;
499
+ const target = await this.resolveTeamLeadSessionForMission(mission);
500
+ const reason = 'scheduled_review';
501
+ const reviewWI = this.buildAutoWorkItem({
502
+ id,
503
+ type: 'review',
504
+ owner: 'team_lead',
505
+ target,
506
+ title: `Mission review — ${mission.objective.slice(0, 60)}`,
507
+ description: `Event-driven mission review (cycle ${cycleId}). Reason: ${reason}.`,
508
+ sourceWI: null,
509
+ missionId: mission.id,
510
+ requestId: undefined,
511
+ retryCount: 0,
512
+ extraMetadata: {
513
+ idempotencyKey: id, // V1 (per-handler) — id matches REVIEW-1's pattern
514
+ reviewReason: reason,
515
+ reviewCycleId: cycleId,
516
+ triggerEventId: event.id,
517
+ },
518
+ });
519
+ await this.taskPool.addToPool(reviewWI);
520
+ this.logger.info('Mission review WorkItem created (event-driven)', {
521
+ missionId: mission.id,
522
+ workItemId: id,
523
+ });
524
+ };
525
+ /**
526
+ * `mission:stale` → review WI with `reviewReason='no_active_work'`.
527
+ * Idempotency: `${missionId}:review:stale:${YYYY-MM-DD}`.
528
+ */
529
+ handleMissionStale = async (event) => {
530
+ if (!event.missionId)
531
+ return;
532
+ const mission = await this.loadMission(event.missionId);
533
+ if (!mission)
534
+ return;
535
+ const cycleId = todayCycleKey();
536
+ const id = `${mission.id}:review:stale:${cycleId}`;
537
+ const target = await this.resolveTeamLeadSessionForMission(mission);
538
+ const reason = 'no_active_work';
539
+ const reviewWI = this.buildAutoWorkItem({
540
+ id,
541
+ type: 'review',
542
+ owner: 'team_lead',
543
+ target,
544
+ title: `Stale mission — ${mission.objective.slice(0, 60)}`,
545
+ description: `Mission ${mission.id} flagged stale on ${cycleId}.`,
546
+ sourceWI: null,
547
+ missionId: mission.id,
548
+ requestId: undefined,
549
+ retryCount: 0,
550
+ extraMetadata: {
551
+ idempotencyKey: id, // V1 (per-handler)
552
+ reviewReason: reason,
553
+ reviewCycleId: cycleId,
554
+ },
555
+ });
556
+ await this.taskPool.addToPool(reviewWI);
557
+ };
558
+ /**
559
+ * `mission:replanned` → review WI tied to the replan event id.
560
+ * Idempotency: `${missionId}:review:replan:${eventId}`.
561
+ */
562
+ handleMissionReplanned = async (event) => {
563
+ if (!event.missionId)
564
+ return;
565
+ const mission = await this.loadMission(event.missionId);
566
+ if (!mission)
567
+ return;
568
+ const id = `${mission.id}:review:replan:${event.id}`;
569
+ const target = await this.resolveTeamLeadSessionForMission(mission);
570
+ const reason = 'scheduled_review';
571
+ const reviewWI = this.buildAutoWorkItem({
572
+ id,
573
+ type: 'review',
574
+ owner: 'team_lead',
575
+ target,
576
+ title: `Mission replanned — ${mission.objective.slice(0, 60)}`,
577
+ description: `Mission ${mission.id} replanned (event ${event.id}). TL acknowledge.`,
578
+ sourceWI: null,
579
+ missionId: mission.id,
580
+ requestId: undefined,
581
+ retryCount: 0,
582
+ extraMetadata: {
583
+ idempotencyKey: id, // V1 (per-handler)
584
+ reviewReason: reason,
585
+ triggerEventId: event.id,
586
+ },
587
+ });
588
+ await this.taskPool.addToPool(reviewWI);
589
+ };
590
+ // -------------------------------------------------------------------------
591
+ // Internal helpers
592
+ // -------------------------------------------------------------------------
593
+ /**
594
+ * Build an auto-created WorkItem with all the BRIDGE-1 metadata invariants
595
+ * filled in (deterministic id, idempotencyKey === id, triggerSource derived
596
+ * from source WI, parent linkage). Pulls every shared field through one
597
+ * factory so each handler stays declarative and the V1 grep guard
598
+ * (`grep -c "idempotencyKey:" backend/src/services/event-bus/event-to-workitem-bridge.service.ts`
599
+ * ≥ 6) holds without litter.
600
+ */
601
+ buildAutoWorkItem(args) {
602
+ const triggerSource = inheritedTriggerSource(args.sourceWI);
603
+ const now = new Date().toISOString();
604
+ return {
605
+ id: args.id,
606
+ type: args.type,
607
+ owner: args.owner,
608
+ target: args.target,
609
+ title: args.title,
610
+ description: args.description,
611
+ status: 'queued',
612
+ createdAt: now,
613
+ retryCount: args.retryCount,
614
+ maxRetries: DEFAULT_MAX_RETRIES,
615
+ requestId: args.requestId,
616
+ missionId: args.missionId,
617
+ parentWorkItemId: args.sourceWI?.id,
618
+ inputTokens: 0,
619
+ outputTokens: 0,
620
+ cost: 0,
621
+ metadata: {
622
+ // V1 idempotency + V6 triggerSource invariants are enforced HERE in the
623
+ // factory and ALSO declared per-handler in `extraMetadata` so the
624
+ // audit grep (`grep -c "idempotencyKey:" event-to-workitem-bridge.service.ts`)
625
+ // shows one line per handler. Spread order keeps the per-handler
626
+ // declaration as the source of truth — factory only fills if the
627
+ // handler omitted (defensive default).
628
+ triggerSource, // V6 — never 'cron' for bridge-created WIs
629
+ ...args.extraMetadata,
630
+ },
631
+ };
632
+ }
633
+ /**
634
+ * Resolve the source WorkItem from an event. Prefers `event.workItemId`
635
+ * (BRIDGE-1.1 explicit field), falls back to `event.taskId` for events
636
+ * whose publishers haven't been migrated yet.
637
+ *
638
+ * @param event - The event being handled
639
+ * @returns The source WorkItem, or null when nothing matches
640
+ */
641
+ async resolveSourceWorkItem(event) {
642
+ const id = event.workItemId ?? event.taskId;
643
+ if (!id)
644
+ return null;
645
+ return this.taskPool.findWorkItem(id);
646
+ }
647
+ /**
648
+ * Resolve the team-lead session for a source WI's owning team.
649
+ * Throws {@link BridgeTeamLeadResolutionError} if no TL is resolvable —
650
+ * Arch Veto V4 forbids silently falling back to the executor.
651
+ */
652
+ async resolveTeamLeadSession(sourceWI) {
653
+ const teamId = sourceWI.metadata?.['teamId'] ?? null;
654
+ if (!teamId) {
655
+ // No team metadata on the WI — last-resort orchestrator routing keeps
656
+ // the escalation visible. We log a warn so this surface is auditable
657
+ // when a team-aware producer arrives.
658
+ this.logger.warn('Source WI missing metadata.teamId — routing escalation to orchestrator', {
659
+ sourceWorkItemId: sourceWI.id,
660
+ });
661
+ return ORCHESTRATOR_SESSION_NAME;
662
+ }
663
+ const team = await this.loadTeam(teamId);
664
+ if (!team) {
665
+ throw new BridgeTeamLeadResolutionError(`BRIDGE-1: cannot resolve team ${teamId} for source WorkItem ${sourceWI.id}`);
666
+ }
667
+ const lead = pickTeamLead(team);
668
+ if (!lead) {
669
+ throw new BridgeTeamLeadResolutionError(`BRIDGE-1: cannot resolve team lead for team ${teamId} on source WorkItem ${sourceWI.id}`);
670
+ }
671
+ if (!lead.sessionName) {
672
+ throw new BridgeTeamLeadResolutionError(`BRIDGE-1: team lead for team ${teamId} has no sessionName (member ${lead.id})`);
673
+ }
674
+ return lead.sessionName;
675
+ }
676
+ /**
677
+ * Resolve TL for a mission. Same V4 fail-fast contract as
678
+ * {@link resolveTeamLeadSession} but keyed on `mission.ownerTeamId`.
679
+ */
680
+ async resolveTeamLeadSessionForMission(mission) {
681
+ if (mission.ownerId) {
682
+ // Owner is a member id; we don't load members directly here. If the
683
+ // ownerId is set we trust it as a session name fallback would lose data
684
+ // — but `pickTeamLead` is the canonical resolver, so we still consult it.
685
+ }
686
+ const team = await this.loadTeam(mission.ownerTeamId);
687
+ if (!team) {
688
+ throw new BridgeTeamLeadResolutionError(`BRIDGE-1: cannot resolve owner team ${mission.ownerTeamId} for mission ${mission.id}`);
689
+ }
690
+ const lead = pickTeamLead(team);
691
+ if (!lead) {
692
+ throw new BridgeTeamLeadResolutionError(`BRIDGE-1: cannot resolve team lead for owner team ${mission.ownerTeamId} on mission ${mission.id}`);
693
+ }
694
+ if (!lead.sessionName) {
695
+ throw new BridgeTeamLeadResolutionError(`BRIDGE-1: team lead for owner team ${mission.ownerTeamId} has no sessionName (member ${lead.id})`);
696
+ }
697
+ return lead.sessionName;
698
+ }
699
+ /**
700
+ * Wrap a handler so a thrown error is caught at the bridge boundary instead
701
+ * of bubbling into EventBus.dispatchInProcess. Errors from handlers
702
+ * shouldn't crash the publisher — they should be observable via logs and
703
+ * — for tests — rethrowable from a deterministic spy point.
704
+ */
705
+ safeDispatch(eventType, event, handler) {
706
+ const dispatch = (async () => {
707
+ try {
708
+ await handler.call(this, event);
709
+ }
710
+ catch (err) {
711
+ this.logger.error('Bridge handler threw', {
712
+ eventType,
713
+ eventId: event.id,
714
+ error: formatError(err),
715
+ });
716
+ // Re-raise CronRecursionError + V4 errors so test spies + audit log
717
+ // surface them. EventBus.dispatchInProcess catches them harmlessly.
718
+ if (err instanceof CronRecursionError || err instanceof BridgeTeamLeadResolutionError) {
719
+ throw err;
720
+ }
721
+ }
722
+ })();
723
+ this.pendingDispatches.add(dispatch);
724
+ // Always remove from the in-flight set when the promise settles, regardless
725
+ // of fulfilled/rejected outcome, so flushPending() drains cleanly.
726
+ dispatch.finally(() => {
727
+ this.pendingDispatches.delete(dispatch);
728
+ }).catch(() => {
729
+ // Suppress unhandled-rejection warning — flushPending callers see the
730
+ // outcome via Promise.allSettled, and the handler's logger.error has
731
+ // already recorded the throw.
732
+ });
733
+ return dispatch;
734
+ }
735
+ }
736
+ //# sourceMappingURL=event-to-workitem-bridge.service.js.map