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,759 @@
1
+ /**
2
+ * Active Work Briefing Service
3
+ *
4
+ * Generates an authoritative-state briefing for an agent at session startup
5
+ * (and on-demand mid-session via the `core/get-my-active-work` skill).
6
+ *
7
+ * Today the agent recovery prompt is memory-only — `SessionMemoryService`
8
+ * dumps the last session summary, agent/project knowledge, daily logs, and
9
+ * recent learning files. That is supplementary; it does NOT capture
10
+ * authoritative runtime state. Symptom: an agent restarts amnesiac about
11
+ * Requests it owes a reply on, queued WorkItems that survived the restart,
12
+ * and in-flight delegations.
13
+ *
14
+ * This service mirrors `SessionMemoryService` (`generate*` + `format*`
15
+ * methods, singleton, soft-fail wrapping at the call site) and produces a
16
+ * per-agent slice of the live Request + WorkItem state. The briefing is
17
+ * prepended ABOVE the memory briefing in the agent's startup prompt so the
18
+ * first thing the agent reads is "what am I on the hook for RIGHT NOW".
19
+ *
20
+ * Sources:
21
+ * - {@link RequestService.listAll} — all Requests on disk
22
+ * - {@link TaskPoolService.getAllItems} — all WorkItems in the pool
23
+ *
24
+ * Design doc: `/tmp/agent-state-recovery-design.md` (architect output)
25
+ * GitHub issue: stevehuang0115/crewly#395
26
+ *
27
+ * @module services/agent/active-work-briefing.service
28
+ */
29
+ import { LoggerService } from '../core/logger.service.js';
30
+ import { ORCHESTRATOR_ROLE, ORCHESTRATOR_SESSION_NAME } from '../../constants.js';
31
+ /**
32
+ * Default per-section item caps for non-orchestrator agents.
33
+ * Total cap = 45 items, ~6,300 chars (~1,500 tokens).
34
+ */
35
+ const DEFAULT_CAPS = {
36
+ openRequests: 10,
37
+ activeWorkItems: 15,
38
+ pendingReviews: 5,
39
+ outboundDelegations: 10,
40
+ recentlyAutoResolved: 5,
41
+ };
42
+ /** Orchestrator gets system-wide visibility — caps × 3. */
43
+ const ORCHESTRATOR_CAP_MULTIPLIER = 3;
44
+ /**
45
+ * Hard ceiling on the orchestrator's formatted briefing (chars). If the
46
+ * formatted markdown crosses this threshold, the formatter drops description
47
+ * fields to keep the prompt tractable. Bounded — does not truncate items.
48
+ */
49
+ const ORCHESTRATOR_OVERFLOW_CHARS = 25_000;
50
+ /** Default recently-resolved window: 30 minutes. */
51
+ const DEFAULT_RECENTLY_RESOLVED_WINDOW_MS = 30 * 60 * 1000;
52
+ /** Per-item title cap to prevent unbounded growth. */
53
+ const MAX_TITLE_CHARS = 80;
54
+ /** Per-item description cap. */
55
+ const MAX_DESCRIPTION_CHARS = 120;
56
+ /**
57
+ * Request statuses that count as "open / on the hook" for briefing
58
+ * inclusion. Terminal statuses (`done`, `cancelled`) are excluded —
59
+ * memory recall handles "what did I close last week".
60
+ */
61
+ const ACTIVE_REQUEST_STATUSES = new Set([
62
+ 'open',
63
+ 'ready',
64
+ 'running',
65
+ 'blocked',
66
+ 'waiting_confirmation',
67
+ ]);
68
+ /**
69
+ * WorkItem statuses that are still "in-flight" for the agent (target of a
70
+ * claim or work). Terminal statuses (`done`, `verified`, `cancelled`,
71
+ * `failed`, `rejected`) are excluded — they are recovered via memory.
72
+ */
73
+ const ACTIVE_WORK_ITEM_STATUSES = new Set([
74
+ 'queued',
75
+ 'scheduled',
76
+ 'proposed',
77
+ 'accepted',
78
+ 'running',
79
+ 'blocked',
80
+ 'escalated',
81
+ ]);
82
+ /** Status indicating a WorkItem is awaiting verifier review. */
83
+ const PENDING_REVIEW_STATUS = 'done_by_worker';
84
+ // ---------------------------------------------------------------------------
85
+ // Service
86
+ // ---------------------------------------------------------------------------
87
+ /**
88
+ * Singleton service producing per-agent active-work briefings.
89
+ *
90
+ * Mirrors the `SessionMemoryService.generate* + format*` shape so the
91
+ * `agent-registration.service.ts` glue can call them in parallel and
92
+ * concatenate the markdown.
93
+ *
94
+ * Stateless beyond singleton bookkeeping — every call hits the live
95
+ * `RequestService` + `TaskPoolService` instances.
96
+ */
97
+ export class ActiveWorkBriefingService {
98
+ requestServiceFactory;
99
+ taskPoolFactory;
100
+ static instance = null;
101
+ logger;
102
+ /**
103
+ * Private constructor — use {@link getInstance}. The `requestServiceFactory`
104
+ * and `taskPoolFactory` are dependency seams for tests; production code
105
+ * lets {@link getInstance} provide the live singletons.
106
+ */
107
+ constructor(requestServiceFactory, taskPoolFactory) {
108
+ this.requestServiceFactory = requestServiceFactory;
109
+ this.taskPoolFactory = taskPoolFactory;
110
+ this.logger = LoggerService.getInstance().createComponentLogger('ActiveWorkBriefingService');
111
+ }
112
+ /**
113
+ * Returns the singleton instance.
114
+ *
115
+ * The `RequestService` and `TaskPoolService` modules are loaded LAZILY here
116
+ * (CommonJS `require` rather than top-of-file `import`) so that consumers
117
+ * of this module do not pay the import cost — and more importantly, do not
118
+ * transitively load `chokidar` via `v3-data.service.ts` — until they
119
+ * actually call `getInstance()`. This keeps the agent-registration test
120
+ * suite mockable without forcing every caller to mock the v3 pipeline.
121
+ */
122
+ static getInstance() {
123
+ if (!ActiveWorkBriefingService.instance) {
124
+ // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
125
+ const { RequestService } = require('../v3/request.service.js');
126
+ // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
127
+ const { TaskPoolService } = require('../task-pool/task-pool.service.js');
128
+ ActiveWorkBriefingService.instance = new ActiveWorkBriefingService(() => RequestService.getInstance(), () => TaskPoolService.getInstance());
129
+ }
130
+ return ActiveWorkBriefingService.instance;
131
+ }
132
+ /**
133
+ * Resets the singleton — for tests only.
134
+ */
135
+ static resetInstance() {
136
+ ActiveWorkBriefingService.instance = null;
137
+ }
138
+ /**
139
+ * Test-only escape hatch to swap the underlying service factories.
140
+ * Production code never calls this; the public surface is the singleton.
141
+ *
142
+ * @param requestServiceFactory - Returns a `listAll` provider
143
+ * @param taskPoolFactory - Returns a `getAllItems` provider
144
+ */
145
+ static createForTest(requestServiceFactory, taskPoolFactory) {
146
+ return new ActiveWorkBriefingService(requestServiceFactory, taskPoolFactory);
147
+ }
148
+ // -------------------------------------------------------------------------
149
+ // Internal helpers
150
+ // -------------------------------------------------------------------------
151
+ /**
152
+ * Compute the effective per-section caps for the requested role. Orchestrator
153
+ * gets caps × 3 for system-wide visibility; everyone else uses the defaults
154
+ * (with optional overrides from {@link GenerateOptions.caps}).
155
+ *
156
+ * @param role - Agent role (orchestrator gets the multiplier)
157
+ * @param overrides - Optional explicit caps that win over both defaults and
158
+ * the role multiplier.
159
+ * @returns Effective caps for each section
160
+ */
161
+ resolveCaps(role, overrides) {
162
+ const isOrchestrator = role === ORCHESTRATOR_ROLE;
163
+ const multiplier = isOrchestrator ? ORCHESTRATOR_CAP_MULTIPLIER : 1;
164
+ return {
165
+ openRequests: overrides?.openRequests ?? DEFAULT_CAPS.openRequests * multiplier,
166
+ activeWorkItems: overrides?.activeWorkItems ?? DEFAULT_CAPS.activeWorkItems * multiplier,
167
+ pendingReviews: overrides?.pendingReviews ?? DEFAULT_CAPS.pendingReviews * multiplier,
168
+ outboundDelegations: overrides?.outboundDelegations ?? DEFAULT_CAPS.outboundDelegations * multiplier,
169
+ recentlyAutoResolved: overrides?.recentlyAutoResolved ?? DEFAULT_CAPS.recentlyAutoResolved * multiplier,
170
+ };
171
+ }
172
+ /**
173
+ * Convert a 'low' | 'normal' | 'high' priority to a sort key.
174
+ * Higher number = higher priority (sorted DESC).
175
+ *
176
+ * @param p - Priority value
177
+ * @returns Numeric sort key
178
+ */
179
+ priorityRank(p) {
180
+ switch (p) {
181
+ case 'high':
182
+ return 3;
183
+ case 'normal':
184
+ return 2;
185
+ case 'low':
186
+ return 1;
187
+ default:
188
+ return 0;
189
+ }
190
+ }
191
+ /**
192
+ * Compute age in hours since `createdAt`. Negative or NaN inputs are
193
+ * coerced to 0 — defensive against malformed timestamps.
194
+ *
195
+ * @param createdAt - ISO8601 timestamp
196
+ * @param nowMs - Current time in milliseconds
197
+ * @returns Age in hours (>= 0)
198
+ */
199
+ ageHours(createdAt, nowMs) {
200
+ const created = new Date(createdAt).getTime();
201
+ if (!Number.isFinite(created))
202
+ return 0;
203
+ const diff = nowMs - created;
204
+ return diff > 0 ? diff / (60 * 60 * 1000) : 0;
205
+ }
206
+ /**
207
+ * Read a string-typed field from a `metadata` blob, or null if missing /
208
+ * not a string. WorkItem.metadata is typed as `Record<string, unknown>` so
209
+ * every read needs this guard.
210
+ *
211
+ * @param metadata - WorkItem.metadata or undefined
212
+ * @param key - Field name to read
213
+ * @returns Trimmed string value or null
214
+ */
215
+ readMetadataString(metadata, key) {
216
+ if (!metadata)
217
+ return null;
218
+ const value = metadata[key];
219
+ if (typeof value !== 'string' || value.length === 0)
220
+ return null;
221
+ return value;
222
+ }
223
+ /**
224
+ * Apply the per-section cap. Returns the slice + a {@link SectionTruncation}
225
+ * object that the formatter renders as a "... and X more" marker.
226
+ *
227
+ * @param items - Sorted candidate rows
228
+ * @param cap - Per-section cap
229
+ * @returns Truncation metadata + the kept rows
230
+ */
231
+ applyCap(items, cap) {
232
+ const rows = items.slice(0, cap);
233
+ return {
234
+ rows,
235
+ truncation: {
236
+ totalCandidates: items.length,
237
+ cap,
238
+ truncated: items.length > cap,
239
+ },
240
+ };
241
+ }
242
+ // -------------------------------------------------------------------------
243
+ // Filter / project — Request rows
244
+ // -------------------------------------------------------------------------
245
+ /**
246
+ * Project Requests visible to this agent. Non-orchestrator agents only see
247
+ * Requests where they are the `ownerAgent`; the orchestrator sees all open
248
+ * Requests system-wide.
249
+ *
250
+ * @param requests - All Requests from {@link RequestService.listAll}
251
+ * @param sessionName - Agent session name
252
+ * @param role - Agent role
253
+ * @param nowMs - "Now" for age computation
254
+ * @returns Sorted candidate rows (priority DESC, then age DESC — older first)
255
+ */
256
+ projectRequests(requests, sessionName, role, nowMs) {
257
+ const isOrchestrator = role === ORCHESTRATOR_ROLE || sessionName === ORCHESTRATOR_SESSION_NAME;
258
+ const filtered = requests.filter((r) => {
259
+ if (!ACTIVE_REQUEST_STATUSES.has(r.status))
260
+ return false;
261
+ if (isOrchestrator)
262
+ return true;
263
+ // Non-orchestrator agents: must be on the hook (ownerAgent === sessionName).
264
+ return r.ownerAgent === sessionName;
265
+ });
266
+ const rows = filtered.map((r) => ({
267
+ id: r.id,
268
+ title: this.truncateTitle(r.title),
269
+ status: r.status,
270
+ priority: r.priority,
271
+ ageHours: this.ageHours(r.createdAt, nowMs),
272
+ source: r.sourceConversationItemId,
273
+ }));
274
+ rows.sort((a, b) => this.priorityRank(b.priority) - this.priorityRank(a.priority) ||
275
+ b.ageHours - a.ageHours);
276
+ return rows;
277
+ }
278
+ // -------------------------------------------------------------------------
279
+ // Filter / project — WorkItem rows
280
+ // -------------------------------------------------------------------------
281
+ /**
282
+ * Project active WorkItems for this agent: items the agent is on the hook
283
+ * to execute (target=me) OR items the agent has actively claimed
284
+ * (claimedBy=me, surfaced via `metadata.claimedBy`). Items targeted at this
285
+ * agent but already claimed by *another* agent are excluded — they are
286
+ * not actionable for the current session.
287
+ *
288
+ * Orchestrator override: include ALL active work items.
289
+ *
290
+ * @param items - All WorkItems from {@link TaskPoolService.getAllItems}
291
+ * @param sessionName - Agent session name
292
+ * @param role - Agent role
293
+ * @param nowMs - "Now" for age computation
294
+ * @returns Sorted candidate rows
295
+ */
296
+ projectActiveWorkItems(items, sessionName, role, nowMs) {
297
+ const isOrchestrator = role === ORCHESTRATOR_ROLE || sessionName === ORCHESTRATOR_SESSION_NAME;
298
+ const filtered = items.filter((wi) => {
299
+ if (!ACTIVE_WORK_ITEM_STATUSES.has(wi.status))
300
+ return false;
301
+ if (isOrchestrator)
302
+ return true;
303
+ const claimedBy = this.readMetadataString(wi.metadata, 'claimedBy');
304
+ const isTargetMe = wi.target === sessionName;
305
+ const isClaimedByMe = claimedBy === sessionName;
306
+ if (!isTargetMe && !isClaimedByMe)
307
+ return false;
308
+ // Excluded: target is me but another agent already claimed it.
309
+ if (isTargetMe && claimedBy && claimedBy !== sessionName)
310
+ return false;
311
+ return true;
312
+ });
313
+ const rows = filtered.map((wi) => ({
314
+ id: wi.id,
315
+ title: this.truncateTitle(wi.title),
316
+ status: wi.status,
317
+ ageHours: this.ageHours(wi.createdAt, nowMs),
318
+ priority: this.readPriorityFromMetadata(wi.metadata),
319
+ requestId: wi.requestId,
320
+ description: wi.description ? this.truncateDescription(wi.description) : undefined,
321
+ }));
322
+ rows.sort((a, b) => this.priorityRank(b.priority) - this.priorityRank(a.priority) ||
323
+ b.ageHours - a.ageHours);
324
+ return rows;
325
+ }
326
+ /**
327
+ * Pending review rows — WorkItems in `done_by_worker` where this agent
328
+ * is the verifier. Verifier signal = `metadata.verifier === sessionName`
329
+ * (TL/orchestrator pattern). For the orchestrator role we surface ALL
330
+ * `done_by_worker` items system-wide.
331
+ *
332
+ * @param items - All WorkItems from the pool
333
+ * @param sessionName - Agent session name
334
+ * @param role - Agent role
335
+ * @param nowMs - "Now" for age computation
336
+ * @returns Sorted candidate rows (oldest first — review backlog)
337
+ */
338
+ projectPendingReviews(items, sessionName, role, nowMs) {
339
+ const isOrchestrator = role === ORCHESTRATOR_ROLE || sessionName === ORCHESTRATOR_SESSION_NAME;
340
+ const filtered = items.filter((wi) => {
341
+ if (wi.status !== PENDING_REVIEW_STATUS)
342
+ return false;
343
+ if (isOrchestrator)
344
+ return true;
345
+ const verifier = this.readMetadataString(wi.metadata, 'verifier');
346
+ return verifier === sessionName;
347
+ });
348
+ const rows = filtered.map((wi) => ({
349
+ id: wi.id,
350
+ title: this.truncateTitle(wi.title),
351
+ ageHours: this.ageHours(wi.createdAt, nowMs),
352
+ claimedBy: this.readMetadataString(wi.metadata, 'claimedBy') ?? undefined,
353
+ }));
354
+ // Oldest first — review backlog should be drained FIFO.
355
+ rows.sort((a, b) => b.ageHours - a.ageHours);
356
+ return rows;
357
+ }
358
+ /**
359
+ * Outbound delegations — WorkItems this agent delegated and that haven't
360
+ * resolved yet. Identified by `metadata.delegatedBy === sessionName`.
361
+ * Forward-compatible: if upstream code does not yet populate
362
+ * `metadata.delegatedBy`, this section is empty.
363
+ *
364
+ * @param items - All WorkItems from the pool
365
+ * @param sessionName - Agent session name
366
+ * @param nowMs - "Now" for age computation
367
+ * @returns Sorted candidate rows
368
+ */
369
+ projectOutboundDelegations(items, sessionName, nowMs) {
370
+ const filtered = items.filter((wi) => {
371
+ if (!ACTIVE_WORK_ITEM_STATUSES.has(wi.status))
372
+ return false;
373
+ const delegatedBy = this.readMetadataString(wi.metadata, 'delegatedBy');
374
+ return delegatedBy === sessionName;
375
+ });
376
+ const rows = filtered.map((wi) => ({
377
+ id: wi.id,
378
+ title: this.truncateTitle(wi.title),
379
+ status: wi.status,
380
+ ageHours: this.ageHours(wi.createdAt, nowMs),
381
+ target: wi.target,
382
+ }));
383
+ rows.sort((a, b) => b.ageHours - a.ageHours);
384
+ return rows;
385
+ }
386
+ /**
387
+ * Recently auto-resolved WorkItems within the configured window
388
+ * (default 30 minutes). Surfaced so the agent knows what closed
389
+ * automatically while it was down. Identified by
390
+ * `metadata.slaResolvedAt` falling inside the window.
391
+ *
392
+ * @param items - All WorkItems from the pool
393
+ * @param sessionName - Agent session name (filters to items relevant to this agent)
394
+ * @param role - Agent role
395
+ * @param nowMs - "Now" for age computation
396
+ * @param windowMs - Window size in milliseconds
397
+ * @returns Sorted candidate rows (most recent first)
398
+ */
399
+ projectRecentlyResolved(items, sessionName, role, nowMs, windowMs) {
400
+ const isOrchestrator = role === ORCHESTRATOR_ROLE || sessionName === ORCHESTRATOR_SESSION_NAME;
401
+ const cutoff = nowMs - windowMs;
402
+ const filtered = items.filter((wi) => {
403
+ const resolvedAt = this.readMetadataString(wi.metadata, 'slaResolvedAt');
404
+ if (!resolvedAt)
405
+ return false;
406
+ const ts = new Date(resolvedAt).getTime();
407
+ if (!Number.isFinite(ts))
408
+ return false;
409
+ if (ts < cutoff)
410
+ return false;
411
+ if (isOrchestrator)
412
+ return true;
413
+ const claimedBy = this.readMetadataString(wi.metadata, 'claimedBy');
414
+ const delegatedBy = this.readMetadataString(wi.metadata, 'delegatedBy');
415
+ return (wi.target === sessionName ||
416
+ claimedBy === sessionName ||
417
+ delegatedBy === sessionName);
418
+ });
419
+ const rows = filtered.map((wi) => ({
420
+ id: wi.id,
421
+ title: this.truncateTitle(wi.title),
422
+ resolvedAt: this.readMetadataString(wi.metadata, 'slaResolvedAt') ?? '',
423
+ resolvedReason: this.readMetadataString(wi.metadata, 'slaResolvedReason') ?? undefined,
424
+ }));
425
+ rows.sort((a, b) => new Date(b.resolvedAt).getTime() - new Date(a.resolvedAt).getTime());
426
+ return rows;
427
+ }
428
+ /**
429
+ * Read a priority hint from WorkItem.metadata. Falls back to `'normal'`.
430
+ *
431
+ * @param metadata - WorkItem metadata blob
432
+ * @returns Briefing priority
433
+ */
434
+ readPriorityFromMetadata(metadata) {
435
+ const raw = this.readMetadataString(metadata, 'priority');
436
+ if (raw === 'high' || raw === 'normal' || raw === 'low')
437
+ return raw;
438
+ return 'normal';
439
+ }
440
+ /**
441
+ * Truncate a row title to {@link MAX_TITLE_CHARS}.
442
+ *
443
+ * @param title - Raw title
444
+ * @returns Truncated title (with ellipsis suffix if cut)
445
+ */
446
+ truncateTitle(title) {
447
+ if (title.length <= MAX_TITLE_CHARS)
448
+ return title;
449
+ return title.slice(0, MAX_TITLE_CHARS - 1) + '…';
450
+ }
451
+ /**
452
+ * Truncate a row description to {@link MAX_DESCRIPTION_CHARS}. Replaces
453
+ * newlines with spaces so a description never wraps the briefing layout.
454
+ *
455
+ * @param desc - Raw description
456
+ * @returns Truncated description
457
+ */
458
+ truncateDescription(desc) {
459
+ const oneLine = desc.replace(/\s+/g, ' ').trim();
460
+ if (oneLine.length <= MAX_DESCRIPTION_CHARS)
461
+ return oneLine;
462
+ return oneLine.slice(0, MAX_DESCRIPTION_CHARS - 1) + '…';
463
+ }
464
+ // -------------------------------------------------------------------------
465
+ // Public API — generate
466
+ // -------------------------------------------------------------------------
467
+ /**
468
+ * Generates an active-work briefing for the given agent.
469
+ *
470
+ * Pulls from {@link RequestService} + {@link TaskPoolService}, filters
471
+ * to the agent's slice (orchestrator gets system-wide), applies per-section
472
+ * caps, and returns the structured payload. The caller renders it via
473
+ * {@link formatBriefingAsMarkdown}.
474
+ *
475
+ * Soft-fail policy: any error from the underlying services bubbles up.
476
+ * The CALL SITE in `agent-registration.service.ts` wraps this in a try/catch
477
+ * with WARN-level logging — we deliberately do NOT swallow errors here so
478
+ * test scenarios can assert that the rejection occurs, and so the optional
479
+ * skill endpoint can return a structured 500 response.
480
+ *
481
+ * @param sessionName - Agent session name (e.g. `crewly-product-sam-dd2b46f7`)
482
+ * @param role - Agent role (`developer`, `orchestrator`, etc.)
483
+ * @param options - Optional caps + window overrides for testing
484
+ * @returns The structured briefing
485
+ *
486
+ * @throws Rethrows any error from {@link RequestService.listAll} or
487
+ * {@link TaskPoolService.getAllItems}.
488
+ *
489
+ * @example
490
+ * ```typescript
491
+ * const briefing = await ActiveWorkBriefingService.getInstance()
492
+ * .generateActiveWorkBriefing('dev-001', 'developer');
493
+ * const md = ActiveWorkBriefingService.getInstance()
494
+ * .formatBriefingAsMarkdown(briefing);
495
+ * ```
496
+ */
497
+ async generateActiveWorkBriefing(sessionName, role, options = {}) {
498
+ const nowMs = options.nowMs ?? Date.now();
499
+ const windowMs = options.recentlyResolvedWindowMs ?? DEFAULT_RECENTLY_RESOLVED_WINDOW_MS;
500
+ const caps = this.resolveCaps(role, options.caps);
501
+ // Fetch in parallel — both services are independent.
502
+ const [requests, workItems] = await Promise.all([
503
+ this.requestServiceFactory().listAll(),
504
+ this.taskPoolFactory().getAllItems(),
505
+ ]);
506
+ const openRequestsAll = this.projectRequests(requests, sessionName, role, nowMs);
507
+ const activeWorkItemsAll = this.projectActiveWorkItems(workItems, sessionName, role, nowMs);
508
+ const pendingReviewsAll = this.projectPendingReviews(workItems, sessionName, role, nowMs);
509
+ const outboundDelegationsAll = this.projectOutboundDelegations(workItems, sessionName, nowMs);
510
+ const recentlyAutoResolvedAll = this.projectRecentlyResolved(workItems, sessionName, role, nowMs, windowMs);
511
+ const openRequests = this.applyCap(openRequestsAll, caps.openRequests);
512
+ const activeWorkItems = this.applyCap(activeWorkItemsAll, caps.activeWorkItems);
513
+ const pendingReviews = this.applyCap(pendingReviewsAll, caps.pendingReviews);
514
+ const outboundDelegations = this.applyCap(outboundDelegationsAll, caps.outboundDelegations);
515
+ const recentlyAutoResolved = this.applyCap(recentlyAutoResolvedAll, caps.recentlyAutoResolved);
516
+ const truncated = openRequests.truncation.truncated ||
517
+ activeWorkItems.truncation.truncated ||
518
+ pendingReviews.truncation.truncated ||
519
+ outboundDelegations.truncation.truncated ||
520
+ recentlyAutoResolved.truncation.truncated;
521
+ return {
522
+ openRequests: openRequests.rows,
523
+ activeWorkItems: activeWorkItems.rows,
524
+ pendingReviews: pendingReviews.rows,
525
+ outboundDelegations: outboundDelegations.rows,
526
+ recentlyAutoResolved: recentlyAutoResolved.rows,
527
+ truncation: {
528
+ openRequests: openRequests.truncation,
529
+ activeWorkItems: activeWorkItems.truncation,
530
+ pendingReviews: pendingReviews.truncation,
531
+ outboundDelegations: outboundDelegations.truncation,
532
+ recentlyAutoResolved: recentlyAutoResolved.truncation,
533
+ },
534
+ truncated,
535
+ generatedAt: new Date(nowMs).toISOString(),
536
+ totalCounts: {
537
+ requests: requests.length,
538
+ workItems: workItems.length,
539
+ },
540
+ };
541
+ }
542
+ // -------------------------------------------------------------------------
543
+ // Public API — format
544
+ // -------------------------------------------------------------------------
545
+ /**
546
+ * Format a briefing as markdown suitable for prompt injection.
547
+ *
548
+ * Output structure:
549
+ *
550
+ * ```
551
+ * ## Your Active Work
552
+ *
553
+ * ### Open Requests
554
+ * - **request-abc** — Slack inbound — _open · 2h_ *(memory: marked done — verify)*
555
+ * ...
556
+ * ### Active WorkItems
557
+ * - **wi-123** — Implement feature X — _running · 1h_
558
+ * - desc here
559
+ * ...
560
+ * ```
561
+ *
562
+ * If a {@link MemoryHints} map is provided, contradicting memory notes are
563
+ * appended INLINE on each row, per design Q5/decision #2.
564
+ *
565
+ * Soft-formatting policy: empty briefing collapses to "(No active work —
566
+ * fresh start)". Sections with zero rows are omitted (no empty headings).
567
+ *
568
+ * @param briefing - Structured briefing payload
569
+ * @param memoryHints - Optional namespaced map of `req:<id>` / `wi:<id>` →
570
+ * short note string
571
+ * @returns Markdown string
572
+ */
573
+ formatBriefingAsMarkdown(briefing, memoryHints) {
574
+ const totalRows = briefing.openRequests.length +
575
+ briefing.activeWorkItems.length +
576
+ briefing.pendingReviews.length +
577
+ briefing.outboundDelegations.length +
578
+ briefing.recentlyAutoResolved.length;
579
+ if (totalRows === 0) {
580
+ return '## Your Active Work\n\n(No active work — fresh start)';
581
+ }
582
+ const sections = ['## Your Active Work'];
583
+ // First pass — full description rendering. We may re-render in compact
584
+ // mode below if the orchestrator's briefing crosses the overflow ceiling.
585
+ sections.push(...this.renderSections(briefing, memoryHints, /* compact */ false));
586
+ let md = sections.join('\n\n').trim();
587
+ if (md.length > ORCHESTRATOR_OVERFLOW_CHARS) {
588
+ this.logger.debug('Active-work briefing exceeded overflow ceiling — re-rendering compact', {
589
+ chars: md.length,
590
+ ceiling: ORCHESTRATOR_OVERFLOW_CHARS,
591
+ });
592
+ const compact = ['## Your Active Work'];
593
+ compact.push(...this.renderSections(briefing, memoryHints, /* compact */ true));
594
+ md = compact.join('\n\n').trim();
595
+ }
596
+ return md;
597
+ }
598
+ /**
599
+ * Render the five briefing sub-sections to markdown lines. Pulled out of
600
+ * {@link formatBriefingAsMarkdown} so the overflow-recover path can reuse
601
+ * the same renderer with `compact=true` (drops descriptions to bound
602
+ * the orchestrator briefing).
603
+ *
604
+ * @param briefing - Briefing payload
605
+ * @param memoryHints - Optional contradiction notes
606
+ * @param compact - If true, drop description lines under WorkItem rows
607
+ * @returns Array of markdown blocks (joined by blank lines by caller)
608
+ */
609
+ renderSections(briefing, memoryHints, compact) {
610
+ const out = [];
611
+ if (briefing.openRequests.length > 0) {
612
+ out.push(this.renderOpenRequests(briefing.openRequests, briefing.truncation.openRequests, memoryHints));
613
+ }
614
+ if (briefing.activeWorkItems.length > 0) {
615
+ out.push(this.renderActiveWorkItems(briefing.activeWorkItems, briefing.truncation.activeWorkItems, memoryHints, compact));
616
+ }
617
+ if (briefing.pendingReviews.length > 0) {
618
+ out.push(this.renderPendingReviews(briefing.pendingReviews, briefing.truncation.pendingReviews, memoryHints));
619
+ }
620
+ if (briefing.outboundDelegations.length > 0) {
621
+ out.push(this.renderOutboundDelegations(briefing.outboundDelegations, briefing.truncation.outboundDelegations, memoryHints));
622
+ }
623
+ if (briefing.recentlyAutoResolved.length > 0) {
624
+ out.push(this.renderRecentlyResolved(briefing.recentlyAutoResolved, briefing.truncation.recentlyAutoResolved, memoryHints));
625
+ }
626
+ return out;
627
+ }
628
+ /**
629
+ * Render the truncation marker line for a section. No-op when the section
630
+ * was not truncated.
631
+ *
632
+ * @param truncation - Section truncation metadata
633
+ * @returns Marker line (empty string if not truncated)
634
+ */
635
+ renderTruncationMarker(truncation) {
636
+ if (!truncation.truncated)
637
+ return '';
638
+ const more = truncation.totalCandidates - truncation.cap;
639
+ return `\n_… and ${more} more (call \`get-my-active-work\` for full list)_`;
640
+ }
641
+ /**
642
+ * Append a memory-hint annotation to a row line, if a hint exists for the
643
+ * given key. Renders the annotation italicized so it visually subordinates
644
+ * to the actionable state row.
645
+ *
646
+ * @param line - Row line so far
647
+ * @param key - Hint lookup key (e.g. `req:abc-123`)
648
+ * @param hints - Memory hints map (optional)
649
+ * @returns The line with annotation appended, or unchanged
650
+ */
651
+ appendMemoryHint(line, key, hints) {
652
+ if (!hints)
653
+ return line;
654
+ const note = hints.get(key);
655
+ if (!note)
656
+ return line;
657
+ return `${line} *(memory: ${note})*`;
658
+ }
659
+ /** Format hours into a compact "Nh" / "Nm" string for row metadata. */
660
+ formatAge(ageHours) {
661
+ if (ageHours < 1)
662
+ return `${Math.max(1, Math.round(ageHours * 60))}m`;
663
+ return `${Math.round(ageHours)}h`;
664
+ }
665
+ /**
666
+ * Render the Open Requests section.
667
+ *
668
+ * @param rows - Capped rows
669
+ * @param truncation - Section truncation metadata
670
+ * @param hints - Memory hints
671
+ * @returns Markdown block
672
+ */
673
+ renderOpenRequests(rows, truncation, hints) {
674
+ const lines = ['### Open Requests'];
675
+ for (const row of rows) {
676
+ const base = `- **${row.id}** — ${row.title} — _${row.status} · ${row.priority} · ${this.formatAge(row.ageHours)}_`;
677
+ lines.push(this.appendMemoryHint(base, `req:${row.id}`, hints));
678
+ }
679
+ const marker = this.renderTruncationMarker(truncation);
680
+ return lines.join('\n') + marker;
681
+ }
682
+ /**
683
+ * Render the Active WorkItems section.
684
+ *
685
+ * @param rows - Capped rows
686
+ * @param truncation - Section truncation metadata
687
+ * @param hints - Memory hints
688
+ * @param compact - If true, drop description lines (orchestrator overflow)
689
+ * @returns Markdown block
690
+ */
691
+ renderActiveWorkItems(rows, truncation, hints, compact) {
692
+ const lines = ['### Active WorkItems'];
693
+ for (const row of rows) {
694
+ const reqRef = row.requestId ? ` · req=${row.requestId}` : '';
695
+ const base = `- **${row.id}** — ${row.title} — _${row.status} · ${row.priority} · ${this.formatAge(row.ageHours)}${reqRef}_`;
696
+ lines.push(this.appendMemoryHint(base, `wi:${row.id}`, hints));
697
+ if (!compact && row.description) {
698
+ lines.push(` - ${row.description}`);
699
+ }
700
+ }
701
+ const marker = this.renderTruncationMarker(truncation);
702
+ return lines.join('\n') + marker;
703
+ }
704
+ /**
705
+ * Render the Pending Reviews section.
706
+ *
707
+ * @param rows - Capped rows
708
+ * @param truncation - Section truncation metadata
709
+ * @param hints - Memory hints
710
+ * @returns Markdown block
711
+ */
712
+ renderPendingReviews(rows, truncation, hints) {
713
+ const lines = ['### Pending Reviews'];
714
+ for (const row of rows) {
715
+ const claimedBy = row.claimedBy ? ` · by ${row.claimedBy}` : '';
716
+ const base = `- **${row.id}** — ${row.title} — _${this.formatAge(row.ageHours)}${claimedBy}_`;
717
+ lines.push(this.appendMemoryHint(base, `wi:${row.id}`, hints));
718
+ }
719
+ const marker = this.renderTruncationMarker(truncation);
720
+ return lines.join('\n') + marker;
721
+ }
722
+ /**
723
+ * Render the Outbound Delegations section.
724
+ *
725
+ * @param rows - Capped rows
726
+ * @param truncation - Section truncation metadata
727
+ * @param hints - Memory hints
728
+ * @returns Markdown block
729
+ */
730
+ renderOutboundDelegations(rows, truncation, hints) {
731
+ const lines = ['### Outbound Delegations'];
732
+ for (const row of rows) {
733
+ const target = row.target ? ` → ${row.target}` : '';
734
+ const base = `- **${row.id}** — ${row.title} — _${row.status} · ${this.formatAge(row.ageHours)}${target}_`;
735
+ lines.push(this.appendMemoryHint(base, `wi:${row.id}`, hints));
736
+ }
737
+ const marker = this.renderTruncationMarker(truncation);
738
+ return lines.join('\n') + marker;
739
+ }
740
+ /**
741
+ * Render the Recently Auto-Resolved section.
742
+ *
743
+ * @param rows - Capped rows
744
+ * @param truncation - Section truncation metadata
745
+ * @param hints - Memory hints
746
+ * @returns Markdown block
747
+ */
748
+ renderRecentlyResolved(rows, truncation, hints) {
749
+ const lines = ['### Recently Auto-Resolved (last 30min)'];
750
+ for (const row of rows) {
751
+ const reason = row.resolvedReason ? ` — ${row.resolvedReason}` : '';
752
+ const base = `- **${row.id}** — ${row.title}${reason}`;
753
+ lines.push(this.appendMemoryHint(base, `wi:${row.id}`, hints));
754
+ }
755
+ const marker = this.renderTruncationMarker(truncation);
756
+ return lines.join('\n') + marker;
757
+ }
758
+ }
759
+ //# sourceMappingURL=active-work-briefing.service.js.map