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,467 @@
1
+ /**
2
+ * ChatV2Service — orchestrator for the Agent-First Chat MVP.
3
+ *
4
+ * Wires ChannelStore + MessageStore, enforces the authorization rules
5
+ * laid out in the tech spec §7.2, and maps DB rows to wire-format DTOs.
6
+ *
7
+ * WebSocket push, offline queuing, and attachment durability land in
8
+ * later passes of Phase 1 — see §18 rollout plan.
9
+ *
10
+ * @module services/chat-v2/chat-v2.service
11
+ */
12
+ import { ChannelStore } from './sqlite/channel.store.js';
13
+ import { MessageStore } from './sqlite/message.store.js';
14
+ import { openChatDatabase } from './sqlite/chat-db.js';
15
+ import { CHAT_CHANNEL_TYPES, CHAT_CONTENT_TYPES, CHAT_ERROR_CODES, ChatError, } from './types.js';
16
+ // ---------------------------------------------------------------------------
17
+ // Service
18
+ // ---------------------------------------------------------------------------
19
+ /** Default presence provider used until AgentRegistrationService is wired. */
20
+ const DEFAULT_PRESENCE = () => ({
21
+ status: 'offline',
22
+ lastSeenAt: null,
23
+ });
24
+ /**
25
+ * Orchestrator for chat domain operations.
26
+ *
27
+ * Responsibilities:
28
+ * - Owns the DB handle + stores.
29
+ * - Enforces authorization per §7.2.
30
+ * - Maps rows → DTOs.
31
+ * - Fans out to WebSocket / adapters in later phases.
32
+ */
33
+ export class ChatV2Service {
34
+ /** Phase A spec §3.2: max mention count per message. */
35
+ static MAX_MENTIONS_PER_MESSAGE = 50;
36
+ /** Phase A spec §3.2: max JSON-encoded byte size of the mentions array. */
37
+ static MAX_MENTIONS_JSON_BYTES = 1024;
38
+ config;
39
+ db;
40
+ channels;
41
+ messages;
42
+ presence;
43
+ validateTeamMembership;
44
+ now;
45
+ constructor(options) {
46
+ this.config = options.config;
47
+ this.db = options.db ?? openChatDatabase({ dbPath: options.config.storage.dbPath });
48
+ this.channels = new ChannelStore(this.db);
49
+ this.messages = new MessageStore(this.db);
50
+ this.presence = options.getPresence ?? DEFAULT_PRESENCE;
51
+ this.validateTeamMembership = options.validateTeamMembership;
52
+ this.now = options.now ?? Date.now;
53
+ }
54
+ /** Release the DB handle. Safe to call during graceful shutdown / in tests. */
55
+ close() {
56
+ try {
57
+ this.db.close();
58
+ }
59
+ catch {
60
+ // swallow — nothing to do if already closed
61
+ }
62
+ }
63
+ // -------------------------------------------------------------------------
64
+ // Channel operations
65
+ // -------------------------------------------------------------------------
66
+ /**
67
+ * Create a channel bound 1:1 to an agent session. Server always assigns
68
+ * `owner_user_id = principal.userId` — the body's owner fields are ignored.
69
+ *
70
+ * F2b (#333): when `type='channel'` and a `validateTeamMembership` provider
71
+ * is wired into the service, the principal must be authorized for the
72
+ * requested `teamId`. Failures throw `forbidden_team` (403) — distinct
73
+ * from generic `forbidden` so the FE can surface a tenant-specific
74
+ * message.
75
+ *
76
+ * @param args - Channel creation args
77
+ * @returns The created channel as a DTO
78
+ * @throws {ChatError} `validation_error` (400) / `forbidden_team` (403) /
79
+ * `agent_already_bound` (409)
80
+ */
81
+ createChannel(args) {
82
+ const name = (args.name ?? '').trim();
83
+ if (name.length === 0) {
84
+ throw new ChatError(CHAT_ERROR_CODES.VALIDATION, 400, 'name is required');
85
+ }
86
+ if (name.length > this.config.maxChannelNameChars) {
87
+ throw new ChatError(CHAT_ERROR_CODES.VALIDATION, 400, `name exceeds ${this.config.maxChannelNameChars} characters`);
88
+ }
89
+ // Phase A: validate channel type (defaults to 'dm' for backwards compat).
90
+ const channelType = args.type ?? 'dm';
91
+ if (!CHAT_CHANNEL_TYPES.includes(channelType)) {
92
+ throw new ChatError(CHAT_ERROR_CODES.VALIDATION, 400, `unknown channel type: ${channelType}`);
93
+ }
94
+ // agentSession requirement is type-dependent:
95
+ // - 'dm' → required (existing Phase 1 contract).
96
+ // - 'channel' → not 1:1-bound; server stores '' even if caller passed
97
+ // something. Keep this strict so the wire shape matches
98
+ // the design and we don't accidentally bind a team
99
+ // channel to a single agent.
100
+ const rawAgentSession = (args.agentSession ?? '').trim();
101
+ let agentSession;
102
+ if (channelType === 'dm') {
103
+ if (rawAgentSession.length === 0) {
104
+ throw new ChatError(CHAT_ERROR_CODES.VALIDATION, 400, "agentSession is required when type='dm'");
105
+ }
106
+ agentSession = rawAgentSession;
107
+ }
108
+ else {
109
+ // channel: discard any caller-supplied agentSession.
110
+ agentSession = '';
111
+ }
112
+ // Phase A: type='channel' must specify a teamId; type='dm' may
113
+ // optionally carry a targetMemberId. Reject the contradicting cases.
114
+ const teamId = args.teamId?.trim() || undefined;
115
+ const projectId = args.projectId?.trim() || undefined;
116
+ const targetMemberId = args.targetMemberId?.trim() || undefined;
117
+ if (channelType === 'channel' && !teamId) {
118
+ throw new ChatError(CHAT_ERROR_CODES.VALIDATION, 400, "teamId is required when type='channel'");
119
+ }
120
+ if (channelType === 'dm' && teamId) {
121
+ throw new ChatError(CHAT_ERROR_CODES.VALIDATION, 400, "teamId must be omitted when type='dm'");
122
+ }
123
+ if (channelType === 'channel' && targetMemberId) {
124
+ throw new ChatError(CHAT_ERROR_CODES.VALIDATION, 400, "targetMemberId must be omitted when type='channel'");
125
+ }
126
+ // F2b (#333) — outer-ring tenant defense. type='channel' bindings
127
+ // must pass the membership check when one is wired. Pre-checks
128
+ // already confirmed `teamId` is present and non-empty by here.
129
+ if (channelType === 'channel' && teamId && this.validateTeamMembership) {
130
+ const isMember = this.validateTeamMembership(args.principal, teamId);
131
+ if (!isMember) {
132
+ throw new ChatError(CHAT_ERROR_CODES.FORBIDDEN_TEAM, 403, 'caller is not a member of the requested team', { teamId, userId: args.principal.userId });
133
+ }
134
+ }
135
+ const purpose = args.purpose?.trim();
136
+ if (purpose && purpose.length > this.config.maxPurposeChars) {
137
+ throw new ChatError(CHAT_ERROR_CODES.VALIDATION, 400, `purpose exceeds ${this.config.maxPurposeChars} characters`);
138
+ }
139
+ const row = this.channels.create({
140
+ agentSession,
141
+ ownerUserId: args.principal.userId,
142
+ name,
143
+ purpose: purpose || null,
144
+ type: channelType,
145
+ teamId: teamId ?? null,
146
+ projectId: projectId ?? null,
147
+ targetMemberId: targetMemberId ?? null,
148
+ nowMs: this.now(),
149
+ });
150
+ return this.toChannelDTO(row);
151
+ }
152
+ /**
153
+ * List channels owned by the caller.
154
+ *
155
+ * Phase C: extended with optional `type` + `teamId` filters so the
156
+ * channel-rail can request a focused slice (e.g. "channels in this
157
+ * workspace only") without paging the full owner-scoped list. An
158
+ * unknown `type` value is rejected as `validation_error`. Blank
159
+ * `teamId` is normalized to "no filter" so callers don't need to
160
+ * sanitize empty query strings.
161
+ *
162
+ * @param args - List args (principal + optional filters)
163
+ * @returns DTO-mapped channels
164
+ * @throws {ChatError} `validation_error` (400) when `type` is set
165
+ * to a value outside {@link CHAT_CHANNEL_TYPES}.
166
+ */
167
+ listChannels(args) {
168
+ if (args.type !== undefined && !CHAT_CHANNEL_TYPES.includes(args.type)) {
169
+ throw new ChatError(CHAT_ERROR_CODES.VALIDATION, 400, `unknown channel type: ${args.type}`);
170
+ }
171
+ // Treat blank teamId the same as omitted — saves the channel-rail FE
172
+ // from having to strip empty query strings before issuing the GET.
173
+ const teamIdFilter = args.teamId !== undefined && args.teamId.trim().length > 0
174
+ ? args.teamId
175
+ : undefined;
176
+ const rows = this.channels.listByOwner(args.principal.userId, {
177
+ includeArchived: args.includeArchived,
178
+ limit: args.limit,
179
+ type: args.type,
180
+ teamId: teamIdFilter,
181
+ });
182
+ return rows.map((r) => this.toChannelDTO(r));
183
+ }
184
+ /**
185
+ * Look up a single channel the caller owns.
186
+ *
187
+ * @param channelId - Channel id
188
+ * @param principal - Auth principal
189
+ * @returns DTO shape
190
+ * @throws {ChatError} `channel_not_found` (404) if the caller doesn't own it
191
+ */
192
+ getChannel(channelId, principal) {
193
+ const row = this.requireOwnedChannel(channelId, principal);
194
+ return this.toChannelDTO(row);
195
+ }
196
+ /**
197
+ * Archive a channel. Returns true if a row was modified.
198
+ *
199
+ * @param channelId - Channel id
200
+ * @param principal - Auth principal
201
+ * @returns True if newly archived, false if already archived
202
+ * @throws {ChatError} `channel_not_found` (404)
203
+ */
204
+ archiveChannel(channelId, principal) {
205
+ this.requireOwnedChannel(channelId, principal);
206
+ return this.channels.archive(channelId, this.now());
207
+ }
208
+ // -------------------------------------------------------------------------
209
+ // Message operations
210
+ // -------------------------------------------------------------------------
211
+ /**
212
+ * Persist a message sent by the caller. The server decides `sender_type`
213
+ * and `sender_id` from the auth principal; client fields are ignored.
214
+ *
215
+ * @param args - Send args
216
+ * @returns The persisted message as a DTO (fresh or deduped)
217
+ * @throws {ChatError} on validation, authorization, or size limit
218
+ */
219
+ sendMessage(args) {
220
+ const row = this.requireReadableChannel(args.channelId, args.principal);
221
+ const content = args.content ?? '';
222
+ if (content.length === 0) {
223
+ throw new ChatError(CHAT_ERROR_CODES.VALIDATION, 400, 'content is required');
224
+ }
225
+ const byteLen = Buffer.byteLength(content, 'utf-8');
226
+ if (byteLen > this.config.maxMessageBytes) {
227
+ throw new ChatError(CHAT_ERROR_CODES.PAYLOAD_TOO_LARGE, 413, `content exceeds max bytes (${this.config.maxMessageBytes})`, { maxBytes: this.config.maxMessageBytes, yourBytes: byteLen });
228
+ }
229
+ const contentType = args.contentType ?? 'markdown';
230
+ if (!CHAT_CONTENT_TYPES.includes(contentType)) {
231
+ throw new ChatError(CHAT_ERROR_CODES.VALIDATION, 400, `unknown contentType: ${contentType}`);
232
+ }
233
+ // Agents/users cannot self-tag as system.
234
+ if (contentType === 'system_note' && this.resolveSender(row, args.principal).type !== 'system') {
235
+ throw new ChatError(CHAT_ERROR_CODES.VALIDATION, 400, 'system_note can only be emitted server-side');
236
+ }
237
+ const { type: senderType, id: senderId } = this.resolveSender(row, args.principal);
238
+ // Phase A: validate mentions array. Bounded count + JSON-byte cap so
239
+ // a misbehaving client cannot blow past the spec §3.2 1KB ceiling.
240
+ const mentions = this.validateMentions(args.mentions);
241
+ // Phase A: validate threadId — must reference an existing message in
242
+ // this channel; refusing dangling thread refs prevents orphan replies
243
+ // and contains UX confusion if the FE composes against a stale id.
244
+ const threadId = this.validateThreadId(args.threadId, args.channelId);
245
+ const { row: persisted } = this.messages.insert({
246
+ channelId: args.channelId,
247
+ senderType,
248
+ senderId,
249
+ content,
250
+ contentType,
251
+ clientMessageId: args.clientMessageId,
252
+ mentions,
253
+ threadId,
254
+ nowMs: this.now(),
255
+ });
256
+ return this.toMessageDTO(persisted, args.attachments ?? []);
257
+ }
258
+ /**
259
+ * Phase A — validate the mentions array passed to sendMessage.
260
+ * Returns the cleaned array (or undefined when input is empty/missing).
261
+ *
262
+ * @param raw - The raw `mentions` field from the request body
263
+ * @returns Validated mention IDs (caller passes to messageStore)
264
+ * @throws {ChatError} `validation_error` (400) on type / size / count violation
265
+ */
266
+ validateMentions(raw) {
267
+ if (raw === undefined || raw === null)
268
+ return undefined;
269
+ if (!Array.isArray(raw)) {
270
+ throw new ChatError(CHAT_ERROR_CODES.VALIDATION, 400, 'mentions must be an array');
271
+ }
272
+ if (raw.length === 0)
273
+ return undefined;
274
+ if (raw.length > ChatV2Service.MAX_MENTIONS_PER_MESSAGE) {
275
+ throw new ChatError(CHAT_ERROR_CODES.VALIDATION, 400, `mentions exceeds max count (${ChatV2Service.MAX_MENTIONS_PER_MESSAGE})`);
276
+ }
277
+ const cleaned = [];
278
+ for (const item of raw) {
279
+ if (typeof item !== 'string') {
280
+ throw new ChatError(CHAT_ERROR_CODES.VALIDATION, 400, 'mentions entries must be strings');
281
+ }
282
+ const trimmed = item.trim();
283
+ if (trimmed.length === 0) {
284
+ throw new ChatError(CHAT_ERROR_CODES.VALIDATION, 400, 'mentions entries must be non-empty');
285
+ }
286
+ cleaned.push(trimmed);
287
+ }
288
+ // Bound the JSON size — spec §3.2 caps mentions JSON at 1KB.
289
+ const jsonByteLen = Buffer.byteLength(JSON.stringify(cleaned), 'utf-8');
290
+ if (jsonByteLen > ChatV2Service.MAX_MENTIONS_JSON_BYTES) {
291
+ throw new ChatError(CHAT_ERROR_CODES.PAYLOAD_TOO_LARGE, 413, `mentions JSON exceeds max bytes (${ChatV2Service.MAX_MENTIONS_JSON_BYTES})`);
292
+ }
293
+ return cleaned;
294
+ }
295
+ /**
296
+ * Phase A — validate the threadId passed to sendMessage.
297
+ *
298
+ * Returns the original threadId if it's a valid reference to a message
299
+ * in the same channel, or undefined when input is empty/missing.
300
+ * Refuses dangling references and cross-channel thread roots.
301
+ *
302
+ * @param raw - The raw `threadId` field from the request body
303
+ * @param channelId - The channel this message will be inserted into
304
+ * @returns Validated thread root id (caller passes to messageStore)
305
+ * @throws {ChatError} `validation_error` (400) when invalid
306
+ */
307
+ validateThreadId(raw, channelId) {
308
+ if (raw === undefined || raw === null)
309
+ return undefined;
310
+ if (typeof raw !== 'string') {
311
+ throw new ChatError(CHAT_ERROR_CODES.VALIDATION, 400, 'threadId must be a string');
312
+ }
313
+ const trimmed = raw.trim();
314
+ if (trimmed.length === 0)
315
+ return undefined;
316
+ const root = this.messages.getById(trimmed);
317
+ if (!root) {
318
+ throw new ChatError(CHAT_ERROR_CODES.VALIDATION, 400, `threadId references a non-existent message`, { threadId: trimmed });
319
+ }
320
+ if (root.channel_id !== channelId) {
321
+ // Returning validation_error (not channel_not_found) because the
322
+ // caller's intent IS valid — they're just pointing at the wrong
323
+ // channel's thread root. Distinct error helps debugging.
324
+ throw new ChatError(CHAT_ERROR_CODES.VALIDATION, 400, `threadId belongs to a different channel`, { threadId: trimmed, expectedChannelId: channelId });
325
+ }
326
+ return trimmed;
327
+ }
328
+ /**
329
+ * Page messages for a channel the caller may read.
330
+ *
331
+ * @param args - List args
332
+ * @returns A pagination envelope
333
+ * @throws {ChatError} on auth or invalid cursor
334
+ */
335
+ listMessages(args) {
336
+ this.requireReadableChannel(args.channelId, args.principal);
337
+ const page = this.messages.listByChannel(args.channelId, {
338
+ cursor: args.cursor ?? null,
339
+ limit: args.limit,
340
+ direction: args.direction,
341
+ });
342
+ return {
343
+ channelId: args.channelId,
344
+ messages: page.rows.map((r) => this.toMessageDTO(r, [])),
345
+ nextCursor: page.nextCursor,
346
+ prevCursor: page.prevCursor,
347
+ };
348
+ }
349
+ // -------------------------------------------------------------------------
350
+ // Authorization helpers (§7.2)
351
+ // -------------------------------------------------------------------------
352
+ /** Fetch the channel and enforce caller = owner. */
353
+ requireOwnedChannel(channelId, principal) {
354
+ const row = this.channels.getById(channelId);
355
+ if (!row) {
356
+ throw new ChatError(CHAT_ERROR_CODES.CHANNEL_NOT_FOUND, 404, 'Channel not found');
357
+ }
358
+ if (row.owner_user_id !== principal.userId) {
359
+ throw new ChatError(CHAT_ERROR_CODES.CHANNEL_NOT_FOUND, 404, 'Channel not found');
360
+ }
361
+ return row;
362
+ }
363
+ /**
364
+ * Fetch the channel and allow if the caller is the owner OR the bound agent.
365
+ * Used for read + send; agents must always be acting from their own session.
366
+ */
367
+ requireReadableChannel(channelId, principal) {
368
+ const row = this.channels.getById(channelId);
369
+ if (!row) {
370
+ throw new ChatError(CHAT_ERROR_CODES.CHANNEL_NOT_FOUND, 404, 'Channel not found');
371
+ }
372
+ const isOwner = row.owner_user_id === principal.userId;
373
+ const isBoundAgent = !!principal.agentSession && principal.agentSession === row.agent_session;
374
+ if (!isOwner && !isBoundAgent) {
375
+ throw new ChatError(CHAT_ERROR_CODES.CHANNEL_NOT_FOUND, 404, 'Channel not found');
376
+ }
377
+ if (row.archived_at) {
378
+ throw new ChatError(CHAT_ERROR_CODES.CHANNEL_ARCHIVED, 404, 'Channel is archived');
379
+ }
380
+ return row;
381
+ }
382
+ /** Decide sender_type + sender_id for a message based on principal + channel. */
383
+ resolveSender(channel, principal) {
384
+ if (principal.agentSession && principal.agentSession === channel.agent_session) {
385
+ return { type: 'agent', id: principal.agentSession };
386
+ }
387
+ if (principal.userId === channel.owner_user_id) {
388
+ return { type: 'user', id: principal.userId };
389
+ }
390
+ // Server-minted system messages go through an internal path, not this one.
391
+ throw new ChatError(CHAT_ERROR_CODES.FORBIDDEN, 403, 'Principal cannot send in this channel');
392
+ }
393
+ // -------------------------------------------------------------------------
394
+ // DTO mappers
395
+ // -------------------------------------------------------------------------
396
+ /** Map a channel row + live presence into the wire DTO. */
397
+ toChannelDTO(row) {
398
+ // Phase B backwards-compat: legacy rows (pre-migration) lack `type` /
399
+ // team scope fields. The migration backfills `type='dm'` for existing
400
+ // rows; here we defend the in-memory path against rows that may not
401
+ // yet have the column populated (e.g. mid-migration test runs).
402
+ const channelType = row.type ?? 'dm';
403
+ const presenceSource = channelType === 'dm' ? row.agent_session : '';
404
+ const presence = (this.presence ?? DEFAULT_PRESENCE)(presenceSource);
405
+ return {
406
+ id: row.id,
407
+ agentSession: row.agent_session,
408
+ name: row.name,
409
+ purpose: row.purpose ?? undefined,
410
+ createdAt: row.created_at,
411
+ archivedAt: row.archived_at ?? null,
412
+ lastMessageAt: row.last_message_at ?? null,
413
+ agentPresence: {
414
+ status: presence.status,
415
+ lastSeenAt: presence.lastSeenAt,
416
+ },
417
+ type: channelType,
418
+ teamId: row.team_id ?? undefined,
419
+ projectId: row.project_id ?? undefined,
420
+ targetMemberId: row.target_member_id ?? undefined,
421
+ };
422
+ }
423
+ /** Map a message row to the wire DTO. Attachments passed in by the caller. */
424
+ toMessageDTO(row, attachments) {
425
+ let metadata;
426
+ if (row.metadata) {
427
+ try {
428
+ metadata = JSON.parse(row.metadata);
429
+ }
430
+ catch {
431
+ metadata = undefined;
432
+ }
433
+ }
434
+ // Phase B backwards-compat: parse mentions from JSON-encoded array
435
+ // column. Legacy rows (pre-migration) have null; we surface as
436
+ // empty array so the wire contract `mentions: string[]` is never
437
+ // violated. A malformed JSON column also falls back to `[]` rather
438
+ // than throwing — the wire contract is the priority.
439
+ let mentions = [];
440
+ if (row.mentions) {
441
+ try {
442
+ const parsed = JSON.parse(row.mentions);
443
+ if (Array.isArray(parsed) && parsed.every((x) => typeof x === 'string')) {
444
+ mentions = parsed;
445
+ }
446
+ }
447
+ catch {
448
+ mentions = [];
449
+ }
450
+ }
451
+ return {
452
+ id: row.id,
453
+ channelId: row.channel_id,
454
+ seq: row.seq,
455
+ senderType: row.sender_type,
456
+ senderId: row.sender_id,
457
+ content: row.content,
458
+ contentType: row.content_type,
459
+ createdAt: row.created_at,
460
+ attachments,
461
+ metadata,
462
+ mentions,
463
+ threadId: row.thread_id ?? undefined,
464
+ };
465
+ }
466
+ }
467
+ //# sourceMappingURL=chat-v2.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-v2.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/chat-v2/chat-v2.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Process-wide singleton accessor for `ChatV2Service`.
3
+ *
4
+ * The server wiring layer calls `getChatV2Service()` once and holds the
5
+ * reference; tests can `resetChatV2Service()` to start fresh.
6
+ *
7
+ * @module services/chat-v2/chat-v2.singleton
8
+ */
9
+ import { ChatV2Service, type ChatV2ServiceOptions } from './chat-v2.service.js';
10
+ /**
11
+ * Return the process-wide `ChatV2Service`, constructing it on first call.
12
+ *
13
+ * @param overrides - Optional overrides passed when first constructed.
14
+ * Ignored on subsequent calls.
15
+ * @returns The shared service instance
16
+ */
17
+ export declare function getChatV2Service(overrides?: Partial<ChatV2ServiceOptions>): ChatV2Service;
18
+ /**
19
+ * Replace the process-wide instance. Intended for tests and graceful
20
+ * shutdown paths; do not call from request handlers.
21
+ *
22
+ * @param next - Optional replacement; when omitted, the singleton is cleared
23
+ */
24
+ export declare function setChatV2ServiceForTesting(next: ChatV2Service | null): void;
25
+ /** Close the current instance (if any) and clear the singleton. */
26
+ export declare function resetChatV2Service(): void;
27
+ //# sourceMappingURL=chat-v2.singleton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-v2.singleton.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/chat-v2/chat-v2.singleton.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAKhF;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,aAAa,CAgBzF;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,GAAG,IAAI,CAS3E;AAED,mEAAmE;AACnE,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Process-wide singleton accessor for `ChatV2Service`.
3
+ *
4
+ * The server wiring layer calls `getChatV2Service()` once and holds the
5
+ * reference; tests can `resetChatV2Service()` to start fresh.
6
+ *
7
+ * @module services/chat-v2/chat-v2.singleton
8
+ */
9
+ import { ChatV2Service } from './chat-v2.service.js';
10
+ import { loadChatV2Config } from './config.js';
11
+ let _instance = null;
12
+ /**
13
+ * Return the process-wide `ChatV2Service`, constructing it on first call.
14
+ *
15
+ * @param overrides - Optional overrides passed when first constructed.
16
+ * Ignored on subsequent calls.
17
+ * @returns The shared service instance
18
+ */
19
+ export function getChatV2Service(overrides) {
20
+ if (!_instance) {
21
+ const config = overrides?.config ?? loadChatV2Config();
22
+ _instance = new ChatV2Service({
23
+ config,
24
+ db: overrides?.db,
25
+ getPresence: overrides?.getPresence,
26
+ // F2b (#333) — forward the validator so the production composition
27
+ // root in backend/src/index.ts can wire a teamId-existence /
28
+ // tenant-membership check on the singleton on first construction.
29
+ // Subsequent calls ignore overrides (existing contract).
30
+ validateTeamMembership: overrides?.validateTeamMembership,
31
+ now: overrides?.now,
32
+ });
33
+ }
34
+ return _instance;
35
+ }
36
+ /**
37
+ * Replace the process-wide instance. Intended for tests and graceful
38
+ * shutdown paths; do not call from request handlers.
39
+ *
40
+ * @param next - Optional replacement; when omitted, the singleton is cleared
41
+ */
42
+ export function setChatV2ServiceForTesting(next) {
43
+ if (_instance && _instance !== next) {
44
+ try {
45
+ _instance.close();
46
+ }
47
+ catch {
48
+ // ignore — already closed
49
+ }
50
+ }
51
+ _instance = next;
52
+ }
53
+ /** Close the current instance (if any) and clear the singleton. */
54
+ export function resetChatV2Service() {
55
+ setChatV2ServiceForTesting(null);
56
+ }
57
+ //# sourceMappingURL=chat-v2.singleton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-v2.singleton.js","sourceRoot":"","sources":["../../../../../../backend/src/services/chat-v2/chat-v2.singleton.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,aAAa,EAA6B,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,IAAI,SAAS,GAAyB,IAAI,CAAC;AAE3C;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAyC;IACxE,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,MAAM,GAAG,SAAS,EAAE,MAAM,IAAI,gBAAgB,EAAE,CAAC;QACvD,SAAS,GAAG,IAAI,aAAa,CAAC;YAC5B,MAAM;YACN,EAAE,EAAE,SAAS,EAAE,EAAE;YACjB,WAAW,EAAE,SAAS,EAAE,WAAW;YACnC,mEAAmE;YACnE,6DAA6D;YAC7D,kEAAkE;YAClE,yDAAyD;YACzD,sBAAsB,EAAE,SAAS,EAAE,sBAAsB;YACzD,GAAG,EAAE,SAAS,EAAE,GAAG;SACpB,CAAC,CAAC;IACL,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CAAC,IAA0B;IACnE,IAAI,SAAS,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;QACpC,IAAI,CAAC;YACH,SAAS,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,0BAA0B;QAC5B,CAAC;IACH,CAAC;IACD,SAAS,GAAG,IAAI,CAAC;AACnB,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,kBAAkB;IAChC,0BAA0B,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * OSS team-membership validator for `ChatV2Service.validateTeamMembership`.
3
+ *
4
+ * Phase C F2b (issue #333) — outer-ring tenant defense for type='channel'
5
+ * channel creation. The chat service's optional `validateTeamMembership`
6
+ * dependency is invoked when a caller binds a channel to a `teamId`; if
7
+ * the principal is not authorized for that team, the service throws
8
+ * `forbidden_team` (HTTP 403) before persisting the row.
9
+ *
10
+ * In OSS single-user mode there is no per-user tenant binding — the
11
+ * single user owns every team in their workspace. The right semantic is
12
+ * therefore "the team must exist" (you cannot bind a channel to a team
13
+ * id you fabricated). Cloud Portal Phase E swaps in a tenant-aware
14
+ * validator that checks the user's tenant membership against the team's
15
+ * tenant.
16
+ *
17
+ * Implementation: `existsSync` of `<teamsDir>/<teamId>/config.json`. Sync
18
+ * by design — `ChatV2Service.createChannel` runs inside the synchronous
19
+ * `runHandler` controller wrapper. Async refactors are a Phase E concern.
20
+ *
21
+ * @module services/chat-v2/chat-v2.team-membership
22
+ */
23
+ import type { ChatPrincipal } from './types.js';
24
+ /**
25
+ * Build the OSS validator. Captures the StorageService instance lazily so
26
+ * the singleton resolves correctly even when `getInstance()` lands later
27
+ * in module-init order (matches the existing `loadTeams` injection
28
+ * pattern in chat-v2 wiring).
29
+ *
30
+ * @param deps - Optional dependency overrides for tests.
31
+ * @returns A sync validator suitable for `ChatV2ServiceOptions.validateTeamMembership`.
32
+ *
33
+ * @example
34
+ * const validator = createOssTeamMembershipValidator();
35
+ * const service = getChatV2Service({ validateTeamMembership: validator });
36
+ */
37
+ export declare function createOssTeamMembershipValidator(deps?: {
38
+ /** Resolves the per-team config dir. Defaults to StorageService singleton. */
39
+ getTeamDir?: (teamId: string) => string;
40
+ /** Existence check. Override in tests to avoid touching the real FS. */
41
+ fileExists?: (filePath: string) => boolean;
42
+ }): (principal: ChatPrincipal, teamId: string) => boolean;
43
+ //# sourceMappingURL=chat-v2.team-membership.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-v2.team-membership.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/chat-v2/chat-v2.team-membership.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;;;;;;;;;GAYG;AACH,wBAAgB,gCAAgC,CAC9C,IAAI,GAAE;IACJ,8EAA8E;IAC9E,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,wEAAwE;IACxE,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;CACvC,GACL,CAAC,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAgBvD"}