crewly 1.6.0 → 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (448) hide show
  1. package/config/roles/orchestrator/fragments/role-boundary.md +4 -1
  2. package/config/roles/orchestrator/prompt.md +53 -0
  3. package/config/roles/orchestrator/soul.md +47 -10
  4. package/config/skills/_common/lib.sh +28 -0
  5. package/config/skills/agent/core/cancel-followup/execute.sh +0 -19
  6. package/config/skills/agent/core/get-my-active-work/SKILL.md +101 -0
  7. package/config/skills/agent/core/get-my-active-work/execute.sh +122 -0
  8. package/config/skills/agent/core/list-my-followups/execute.sh +0 -19
  9. package/config/skills/agent/core/record-learning/SKILL.md +29 -0
  10. package/config/skills/agent/core/reply-channel/SKILL.md +41 -0
  11. package/config/skills/agent/core/reply-channel/execute.sh +165 -0
  12. package/config/skills/agent/core/reply-channel/execute.test.sh +148 -0
  13. package/config/skills/agent/core/schedule-followup/execute.sh +0 -19
  14. package/config/skills/agent/core/watch-for-event/execute.sh +0 -19
  15. package/config/skills/agent/remote-browser/execute.sh +296 -14
  16. package/config/skills/agent/remote-browser/execute.test.sh +482 -0
  17. package/config/skills/orchestrator/credential-manager/execute.test.sh +88 -0
  18. package/config/skills/orchestrator/send-message/SKILL.md +30 -7
  19. package/config/skills/orchestrator/team-health-scan/SKILL.md +98 -0
  20. package/config/skills/orchestrator/team-health-scan/execute.sh +44 -0
  21. package/config/skills/registry.json +62 -1
  22. package/config/sops/developer/git-workflow.md +38 -3
  23. package/dist/backend/backend/src/config/oauth.config.d.ts +33 -0
  24. package/dist/backend/backend/src/config/oauth.config.d.ts.map +1 -0
  25. package/dist/backend/backend/src/config/oauth.config.js +45 -0
  26. package/dist/backend/backend/src/config/oauth.config.js.map +1 -0
  27. package/dist/backend/backend/src/constants.d.ts +69 -1
  28. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  29. package/dist/backend/backend/src/constants.js +69 -2
  30. package/dist/backend/backend/src/constants.js.map +1 -1
  31. package/dist/backend/backend/src/controllers/active-work/active-work.controller.d.ts +53 -0
  32. package/dist/backend/backend/src/controllers/active-work/active-work.controller.d.ts.map +1 -0
  33. package/dist/backend/backend/src/controllers/active-work/active-work.controller.js +92 -0
  34. package/dist/backend/backend/src/controllers/active-work/active-work.controller.js.map +1 -0
  35. package/dist/backend/backend/src/controllers/agent-stream/agent-stream.controller.d.ts.map +1 -1
  36. package/dist/backend/backend/src/controllers/agent-stream/agent-stream.controller.js +18 -1
  37. package/dist/backend/backend/src/controllers/agent-stream/agent-stream.controller.js.map +1 -1
  38. package/dist/backend/backend/src/controllers/browser/browser.controller.d.ts +68 -0
  39. package/dist/backend/backend/src/controllers/browser/browser.controller.d.ts.map +1 -1
  40. package/dist/backend/backend/src/controllers/browser/browser.controller.js +233 -5
  41. package/dist/backend/backend/src/controllers/browser/browser.controller.js.map +1 -1
  42. package/dist/backend/backend/src/controllers/browser/browser.routes.d.ts.map +1 -1
  43. package/dist/backend/backend/src/controllers/browser/browser.routes.js +10 -1
  44. package/dist/backend/backend/src/controllers/browser/browser.routes.js.map +1 -1
  45. package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts.map +1 -1
  46. package/dist/backend/backend/src/controllers/chat/chat.controller.js +8 -3
  47. package/dist/backend/backend/src/controllers/chat/chat.controller.js.map +1 -1
  48. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.d.ts +132 -0
  49. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.d.ts.map +1 -0
  50. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.js +401 -0
  51. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.js.map +1 -0
  52. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.d.ts +29 -0
  53. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.d.ts.map +1 -0
  54. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.js +39 -0
  55. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.js.map +1 -0
  56. package/dist/backend/backend/src/controllers/chat-v2/index.d.ts +8 -0
  57. package/dist/backend/backend/src/controllers/chat-v2/index.d.ts.map +1 -0
  58. package/dist/backend/backend/src/controllers/chat-v2/index.js +8 -0
  59. package/dist/backend/backend/src/controllers/chat-v2/index.js.map +1 -0
  60. package/dist/backend/backend/src/controllers/credentials/credentials.controller.d.ts +0 -26
  61. package/dist/backend/backend/src/controllers/credentials/credentials.controller.d.ts.map +1 -1
  62. package/dist/backend/backend/src/controllers/credentials/credentials.controller.js +47 -184
  63. package/dist/backend/backend/src/controllers/credentials/credentials.controller.js.map +1 -1
  64. package/dist/backend/backend/src/controllers/credentials/credentials.routes.d.ts.map +1 -1
  65. package/dist/backend/backend/src/controllers/credentials/credentials.routes.js +2 -1
  66. package/dist/backend/backend/src/controllers/credentials/credentials.routes.js.map +1 -1
  67. package/dist/backend/backend/src/controllers/credentials/google-oauth.controller.d.ts +40 -0
  68. package/dist/backend/backend/src/controllers/credentials/google-oauth.controller.d.ts.map +1 -0
  69. package/dist/backend/backend/src/controllers/credentials/google-oauth.controller.js +162 -0
  70. package/dist/backend/backend/src/controllers/credentials/google-oauth.controller.js.map +1 -0
  71. package/dist/backend/backend/src/controllers/onboarding/onboarding.routes.d.ts +13 -13
  72. package/dist/backend/backend/src/controllers/onboarding/onboarding.routes.d.ts.map +1 -1
  73. package/dist/backend/backend/src/controllers/onboarding/onboarding.routes.js +74 -234
  74. package/dist/backend/backend/src/controllers/onboarding/onboarding.routes.js.map +1 -1
  75. package/dist/backend/backend/src/controllers/request/request.controller.d.ts.map +1 -1
  76. package/dist/backend/backend/src/controllers/request/request.controller.js +4 -6
  77. package/dist/backend/backend/src/controllers/request/request.controller.js.map +1 -1
  78. package/dist/backend/backend/src/controllers/skill/skill.controller.d.ts.map +1 -1
  79. package/dist/backend/backend/src/controllers/skill/skill.controller.js +1 -0
  80. package/dist/backend/backend/src/controllers/skill/skill.controller.js.map +1 -1
  81. package/dist/backend/backend/src/controllers/task-management/tasks.controller.d.ts +43 -0
  82. package/dist/backend/backend/src/controllers/task-management/tasks.controller.d.ts.map +1 -1
  83. package/dist/backend/backend/src/controllers/task-management/tasks.controller.js +200 -72
  84. package/dist/backend/backend/src/controllers/task-management/tasks.controller.js.map +1 -1
  85. package/dist/backend/backend/src/controllers/team/team.controller.d.ts.map +1 -1
  86. package/dist/backend/backend/src/controllers/team/team.controller.js +46 -0
  87. package/dist/backend/backend/src/controllers/team/team.controller.js.map +1 -1
  88. package/dist/backend/backend/src/controllers/team-health/team-health.controller.d.ts +59 -0
  89. package/dist/backend/backend/src/controllers/team-health/team-health.controller.d.ts.map +1 -0
  90. package/dist/backend/backend/src/controllers/team-health/team-health.controller.js +127 -0
  91. package/dist/backend/backend/src/controllers/team-health/team-health.controller.js.map +1 -0
  92. package/dist/backend/backend/src/controllers/team-health/team-health.routes.d.ts +13 -0
  93. package/dist/backend/backend/src/controllers/team-health/team-health.routes.d.ts.map +1 -0
  94. package/dist/backend/backend/src/controllers/team-health/team-health.routes.js +20 -0
  95. package/dist/backend/backend/src/controllers/team-health/team-health.routes.js.map +1 -0
  96. package/dist/backend/backend/src/index.d.ts +9 -0
  97. package/dist/backend/backend/src/index.d.ts.map +1 -1
  98. package/dist/backend/backend/src/index.js +256 -4
  99. package/dist/backend/backend/src/index.js.map +1 -1
  100. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  101. package/dist/backend/backend/src/routes/api.routes.js +43 -6
  102. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  103. package/dist/backend/backend/src/services/agent/active-work-briefing.service.d.ts +498 -0
  104. package/dist/backend/backend/src/services/agent/active-work-briefing.service.d.ts.map +1 -0
  105. package/dist/backend/backend/src/services/agent/active-work-briefing.service.js +759 -0
  106. package/dist/backend/backend/src/services/agent/active-work-briefing.service.js.map +1 -0
  107. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +25 -0
  108. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  109. package/dist/backend/backend/src/services/agent/agent-registration.service.js +193 -57
  110. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  111. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.d.ts +9 -2
  112. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.d.ts.map +1 -1
  113. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.js +35 -2
  114. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.js.map +1 -1
  115. package/dist/backend/backend/src/services/agent/crewly-agent/types.d.ts +8 -2
  116. package/dist/backend/backend/src/services/agent/crewly-agent/types.d.ts.map +1 -1
  117. package/dist/backend/backend/src/services/agent/crewly-agent/types.js +1 -0
  118. package/dist/backend/backend/src/services/agent/crewly-agent/types.js.map +1 -1
  119. package/dist/backend/backend/src/services/agent/tmux-command.service.d.ts.map +1 -1
  120. package/dist/backend/backend/src/services/agent/tmux-command.service.js +2 -1
  121. package/dist/backend/backend/src/services/agent/tmux-command.service.js.map +1 -1
  122. package/dist/backend/backend/src/services/agent/tmux.service.d.ts.map +1 -1
  123. package/dist/backend/backend/src/services/agent/tmux.service.js +2 -1
  124. package/dist/backend/backend/src/services/agent/tmux.service.js.map +1 -1
  125. package/dist/backend/backend/src/services/ai/prompt-builder.service.d.ts +148 -3
  126. package/dist/backend/backend/src/services/ai/prompt-builder.service.d.ts.map +1 -1
  127. package/dist/backend/backend/src/services/ai/prompt-builder.service.js +241 -2
  128. package/dist/backend/backend/src/services/ai/prompt-builder.service.js.map +1 -1
  129. package/dist/backend/backend/src/services/ai/prompt-modules/recovery.module.d.ts.map +1 -1
  130. package/dist/backend/backend/src/services/ai/prompt-modules/recovery.module.js +13 -0
  131. package/dist/backend/backend/src/services/ai/prompt-modules/recovery.module.js.map +1 -1
  132. package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.d.ts.map +1 -1
  133. package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.js +30 -2
  134. package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.js.map +1 -1
  135. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
  136. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js +17 -0
  137. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
  138. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.d.ts +79 -0
  139. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.d.ts.map +1 -0
  140. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.js +118 -0
  141. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.js.map +1 -0
  142. package/dist/backend/backend/src/services/browser/browser-bridge.service.d.ts +161 -0
  143. package/dist/backend/backend/src/services/browser/browser-bridge.service.d.ts.map +1 -1
  144. package/dist/backend/backend/src/services/browser/browser-bridge.service.js +382 -2
  145. package/dist/backend/backend/src/services/browser/browser-bridge.service.js.map +1 -1
  146. package/dist/backend/backend/src/services/browser/browser-proxy.service.d.ts +105 -0
  147. package/dist/backend/backend/src/services/browser/browser-proxy.service.d.ts.map +1 -1
  148. package/dist/backend/backend/src/services/browser/browser-proxy.service.js +232 -13
  149. package/dist/backend/backend/src/services/browser/browser-proxy.service.js.map +1 -1
  150. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts +178 -0
  151. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -0
  152. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +254 -0
  153. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -0
  154. package/dist/backend/backend/src/services/chat-v2/chat-v2.mention-resolver.d.ts +134 -0
  155. package/dist/backend/backend/src/services/chat-v2/chat-v2.mention-resolver.d.ts.map +1 -0
  156. package/dist/backend/backend/src/services/chat-v2/chat-v2.mention-resolver.js +232 -0
  157. package/dist/backend/backend/src/services/chat-v2/chat-v2.mention-resolver.js.map +1 -0
  158. package/dist/backend/backend/src/services/chat-v2/chat-v2.realtime-holder.d.ts +25 -0
  159. package/dist/backend/backend/src/services/chat-v2/chat-v2.realtime-holder.d.ts.map +1 -0
  160. package/dist/backend/backend/src/services/chat-v2/chat-v2.realtime-holder.js +23 -0
  161. package/dist/backend/backend/src/services/chat-v2/chat-v2.realtime-holder.js.map +1 -0
  162. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts +254 -0
  163. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts.map +1 -0
  164. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js +467 -0
  165. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js.map +1 -0
  166. package/dist/backend/backend/src/services/chat-v2/chat-v2.singleton.d.ts +27 -0
  167. package/dist/backend/backend/src/services/chat-v2/chat-v2.singleton.d.ts.map +1 -0
  168. package/dist/backend/backend/src/services/chat-v2/chat-v2.singleton.js +57 -0
  169. package/dist/backend/backend/src/services/chat-v2/chat-v2.singleton.js.map +1 -0
  170. package/dist/backend/backend/src/services/chat-v2/chat-v2.team-membership.d.ts +43 -0
  171. package/dist/backend/backend/src/services/chat-v2/chat-v2.team-membership.d.ts.map +1 -0
  172. package/dist/backend/backend/src/services/chat-v2/chat-v2.team-membership.js +54 -0
  173. package/dist/backend/backend/src/services/chat-v2/chat-v2.team-membership.js.map +1 -0
  174. package/dist/backend/backend/src/services/chat-v2/config.d.ts +100 -0
  175. package/dist/backend/backend/src/services/chat-v2/config.d.ts.map +1 -0
  176. package/dist/backend/backend/src/services/chat-v2/config.js +174 -0
  177. package/dist/backend/backend/src/services/chat-v2/config.js.map +1 -0
  178. package/dist/backend/backend/src/services/chat-v2/index.d.ts +11 -0
  179. package/dist/backend/backend/src/services/chat-v2/index.d.ts.map +1 -0
  180. package/dist/backend/backend/src/services/chat-v2/index.js +12 -0
  181. package/dist/backend/backend/src/services/chat-v2/index.js.map +1 -0
  182. package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.d.ts +114 -0
  183. package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.d.ts.map +1 -0
  184. package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.js +194 -0
  185. package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.js.map +1 -0
  186. package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.d.ts +100 -0
  187. package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.d.ts.map +1 -0
  188. package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.js +351 -0
  189. package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.js.map +1 -0
  190. package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.d.ts +132 -0
  191. package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.d.ts.map +1 -0
  192. package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.js +281 -0
  193. package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.js.map +1 -0
  194. package/dist/backend/backend/src/services/chat-v2/types.d.ts +295 -0
  195. package/dist/backend/backend/src/services/chat-v2/types.d.ts.map +1 -0
  196. package/dist/backend/backend/src/services/chat-v2/types.js +61 -0
  197. package/dist/backend/backend/src/services/chat-v2/types.js.map +1 -0
  198. package/dist/backend/backend/src/services/cloud/cloud-event-bridge.service.d.ts +113 -0
  199. package/dist/backend/backend/src/services/cloud/cloud-event-bridge.service.d.ts.map +1 -0
  200. package/dist/backend/backend/src/services/cloud/cloud-event-bridge.service.js +179 -0
  201. package/dist/backend/backend/src/services/cloud/cloud-event-bridge.service.js.map +1 -0
  202. package/dist/backend/backend/src/services/cloud/cloud-event-forwarder.service.d.ts +131 -0
  203. package/dist/backend/backend/src/services/cloud/cloud-event-forwarder.service.d.ts.map +1 -0
  204. package/dist/backend/backend/src/services/cloud/cloud-event-forwarder.service.js +227 -0
  205. package/dist/backend/backend/src/services/cloud/cloud-event-forwarder.service.js.map +1 -0
  206. package/dist/backend/backend/src/services/core/config.service.js +3 -3
  207. package/dist/backend/backend/src/services/core/config.service.js.map +1 -1
  208. package/dist/backend/backend/src/services/core/storage.service.d.ts +7 -0
  209. package/dist/backend/backend/src/services/core/storage.service.d.ts.map +1 -1
  210. package/dist/backend/backend/src/services/core/storage.service.js +15 -0
  211. package/dist/backend/backend/src/services/core/storage.service.js.map +1 -1
  212. package/dist/backend/backend/src/services/credential/helpers/gemini-cli-workspace.helper.d.ts +4 -16
  213. package/dist/backend/backend/src/services/credential/helpers/gemini-cli-workspace.helper.d.ts.map +1 -1
  214. package/dist/backend/backend/src/services/credential/helpers/gemini-cli-workspace.helper.js +7 -28
  215. package/dist/backend/backend/src/services/credential/helpers/gemini-cli-workspace.helper.js.map +1 -1
  216. package/dist/backend/backend/src/services/event-bus/event-bus.service.d.ts +69 -1
  217. package/dist/backend/backend/src/services/event-bus/event-bus.service.d.ts.map +1 -1
  218. package/dist/backend/backend/src/services/event-bus/event-bus.service.js +118 -0
  219. package/dist/backend/backend/src/services/event-bus/event-bus.service.js.map +1 -1
  220. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.d.ts +275 -0
  221. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.d.ts.map +1 -0
  222. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js +736 -0
  223. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js.map +1 -0
  224. package/dist/backend/backend/src/services/knowledge/fts5-index.service.d.ts.map +1 -1
  225. package/dist/backend/backend/src/services/knowledge/fts5-index.service.js +18 -2
  226. package/dist/backend/backend/src/services/knowledge/fts5-index.service.js.map +1 -1
  227. package/dist/backend/backend/src/services/knowledge/knowledge-search.service.d.ts +49 -13
  228. package/dist/backend/backend/src/services/knowledge/knowledge-search.service.d.ts.map +1 -1
  229. package/dist/backend/backend/src/services/knowledge/knowledge-search.service.js +123 -29
  230. package/dist/backend/backend/src/services/knowledge/knowledge-search.service.js.map +1 -1
  231. package/dist/backend/backend/src/services/knowledge/learnings-index.service.d.ts +159 -0
  232. package/dist/backend/backend/src/services/knowledge/learnings-index.service.d.ts.map +1 -0
  233. package/dist/backend/backend/src/services/knowledge/learnings-index.service.js +304 -0
  234. package/dist/backend/backend/src/services/knowledge/learnings-index.service.js.map +1 -0
  235. package/dist/backend/backend/src/services/knowledge/vector-store.service.d.ts.map +1 -1
  236. package/dist/backend/backend/src/services/knowledge/vector-store.service.js +24 -4
  237. package/dist/backend/backend/src/services/knowledge/vector-store.service.js.map +1 -1
  238. package/dist/backend/backend/src/services/mcp-server.d.ts +46 -2
  239. package/dist/backend/backend/src/services/mcp-server.d.ts.map +1 -1
  240. package/dist/backend/backend/src/services/mcp-server.js +216 -211
  241. package/dist/backend/backend/src/services/mcp-server.js.map +1 -1
  242. package/dist/backend/backend/src/services/mcp-tool-definitions.d.ts +254 -0
  243. package/dist/backend/backend/src/services/mcp-tool-definitions.d.ts.map +1 -0
  244. package/dist/backend/backend/src/services/mcp-tool-definitions.js +285 -0
  245. package/dist/backend/backend/src/services/mcp-tool-definitions.js.map +1 -0
  246. package/dist/backend/backend/src/services/memory/auto-learning.subscriber.d.ts +174 -0
  247. package/dist/backend/backend/src/services/memory/auto-learning.subscriber.d.ts.map +1 -0
  248. package/dist/backend/backend/src/services/memory/auto-learning.subscriber.js +375 -0
  249. package/dist/backend/backend/src/services/memory/auto-learning.subscriber.js.map +1 -0
  250. package/dist/backend/backend/src/services/memory/learning-format.validator.d.ts +97 -0
  251. package/dist/backend/backend/src/services/memory/learning-format.validator.d.ts.map +1 -0
  252. package/dist/backend/backend/src/services/memory/learning-format.validator.js +209 -0
  253. package/dist/backend/backend/src/services/memory/learning-format.validator.js.map +1 -0
  254. package/dist/backend/backend/src/services/memory/vector-store.service.d.ts.map +1 -1
  255. package/dist/backend/backend/src/services/memory/vector-store.service.js +19 -4
  256. package/dist/backend/backend/src/services/memory/vector-store.service.js.map +1 -1
  257. package/dist/backend/backend/src/services/onboarding/onboarding-provision.service.d.ts +16 -5
  258. package/dist/backend/backend/src/services/onboarding/onboarding-provision.service.d.ts.map +1 -1
  259. package/dist/backend/backend/src/services/onboarding/onboarding-provision.service.js +32 -5
  260. package/dist/backend/backend/src/services/onboarding/onboarding-provision.service.js.map +1 -1
  261. package/dist/backend/backend/src/services/onboarding/onboarding.service.d.ts +157 -0
  262. package/dist/backend/backend/src/services/onboarding/onboarding.service.d.ts.map +1 -0
  263. package/dist/backend/backend/src/services/onboarding/onboarding.service.js +229 -0
  264. package/dist/backend/backend/src/services/onboarding/onboarding.service.js.map +1 -0
  265. package/dist/backend/backend/src/services/onboarding/onboarding.types.d.ts +141 -0
  266. package/dist/backend/backend/src/services/onboarding/onboarding.types.d.ts.map +1 -0
  267. package/dist/backend/backend/src/services/onboarding/onboarding.types.js +18 -0
  268. package/dist/backend/backend/src/services/onboarding/onboarding.types.js.map +1 -0
  269. package/dist/backend/backend/src/services/pr-review/pr-review.service.d.ts.map +1 -1
  270. package/dist/backend/backend/src/services/pr-review/pr-review.service.js +1 -1
  271. package/dist/backend/backend/src/services/pr-review/pr-review.service.js.map +1 -1
  272. package/dist/backend/backend/src/services/project/task.service.d.ts.map +1 -1
  273. package/dist/backend/backend/src/services/project/task.service.js +5 -0
  274. package/dist/backend/backend/src/services/project/task.service.js.map +1 -1
  275. package/dist/backend/backend/src/services/skill/skill-executor.service.d.ts +41 -0
  276. package/dist/backend/backend/src/services/skill/skill-executor.service.d.ts.map +1 -1
  277. package/dist/backend/backend/src/services/skill/skill-executor.service.js +136 -7
  278. package/dist/backend/backend/src/services/skill/skill-executor.service.js.map +1 -1
  279. package/dist/backend/backend/src/services/skill/skill.service.d.ts.map +1 -1
  280. package/dist/backend/backend/src/services/skill/skill.service.js +1 -0
  281. package/dist/backend/backend/src/services/skill/skill.service.js.map +1 -1
  282. package/dist/backend/backend/src/services/slack/cross-machine-message.service.d.ts.map +1 -1
  283. package/dist/backend/backend/src/services/slack/cross-machine-message.service.js +17 -1
  284. package/dist/backend/backend/src/services/slack/cross-machine-message.service.js.map +1 -1
  285. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts +39 -1
  286. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
  287. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js +158 -26
  288. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
  289. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +248 -6
  290. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  291. package/dist/backend/backend/src/services/task-pool/task-pool.service.js +531 -51
  292. package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  293. package/dist/backend/backend/src/services/team-health/index.d.ts +16 -0
  294. package/dist/backend/backend/src/services/team-health/index.d.ts.map +1 -0
  295. package/dist/backend/backend/src/services/team-health/index.js +16 -0
  296. package/dist/backend/backend/src/services/team-health/index.js.map +1 -0
  297. package/dist/backend/backend/src/services/team-health/live-team-health-data-provider.d.ts +52 -0
  298. package/dist/backend/backend/src/services/team-health/live-team-health-data-provider.d.ts.map +1 -0
  299. package/dist/backend/backend/src/services/team-health/live-team-health-data-provider.js +161 -0
  300. package/dist/backend/backend/src/services/team-health/live-team-health-data-provider.js.map +1 -0
  301. package/dist/backend/backend/src/services/team-health/lost-dispatch-detector.d.ts +53 -0
  302. package/dist/backend/backend/src/services/team-health/lost-dispatch-detector.d.ts.map +1 -0
  303. package/dist/backend/backend/src/services/team-health/lost-dispatch-detector.js +88 -0
  304. package/dist/backend/backend/src/services/team-health/lost-dispatch-detector.js.map +1 -0
  305. package/dist/backend/backend/src/services/team-health/stale-trigger-detector.d.ts +44 -0
  306. package/dist/backend/backend/src/services/team-health/stale-trigger-detector.d.ts.map +1 -0
  307. package/dist/backend/backend/src/services/team-health/stale-trigger-detector.js +83 -0
  308. package/dist/backend/backend/src/services/team-health/stale-trigger-detector.js.map +1 -0
  309. package/dist/backend/backend/src/services/team-health/team-health-alert-router.d.ts +92 -0
  310. package/dist/backend/backend/src/services/team-health/team-health-alert-router.d.ts.map +1 -0
  311. package/dist/backend/backend/src/services/team-health/team-health-alert-router.js +328 -0
  312. package/dist/backend/backend/src/services/team-health/team-health-alert-router.js.map +1 -0
  313. package/dist/backend/backend/src/services/team-health/team-health-config.d.ts +41 -0
  314. package/dist/backend/backend/src/services/team-health/team-health-config.d.ts.map +1 -0
  315. package/dist/backend/backend/src/services/team-health/team-health-config.js +213 -0
  316. package/dist/backend/backend/src/services/team-health/team-health-config.js.map +1 -0
  317. package/dist/backend/backend/src/services/team-health/team-health-detector.d.ts +46 -0
  318. package/dist/backend/backend/src/services/team-health/team-health-detector.d.ts.map +1 -0
  319. package/dist/backend/backend/src/services/team-health/team-health-detector.js +347 -0
  320. package/dist/backend/backend/src/services/team-health/team-health-detector.js.map +1 -0
  321. package/dist/backend/backend/src/services/team-health/team-health-types.d.ts +154 -0
  322. package/dist/backend/backend/src/services/team-health/team-health-types.d.ts.map +1 -0
  323. package/dist/backend/backend/src/services/team-health/team-health-types.js +94 -0
  324. package/dist/backend/backend/src/services/team-health/team-health-types.js.map +1 -0
  325. package/dist/backend/backend/src/services/team-health/team-health-watchdog.service.d.ts +111 -0
  326. package/dist/backend/backend/src/services/team-health/team-health-watchdog.service.d.ts.map +1 -0
  327. package/dist/backend/backend/src/services/team-health/team-health-watchdog.service.js +226 -0
  328. package/dist/backend/backend/src/services/team-health/team-health-watchdog.service.js.map +1 -0
  329. package/dist/backend/backend/src/services/v3/mission-reminder.service.d.ts +148 -0
  330. package/dist/backend/backend/src/services/v3/mission-reminder.service.d.ts.map +1 -0
  331. package/dist/backend/backend/src/services/v3/mission-reminder.service.js +545 -0
  332. package/dist/backend/backend/src/services/v3/mission-reminder.service.js.map +1 -0
  333. package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts +499 -0
  334. package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts.map +1 -0
  335. package/dist/backend/backend/src/services/v3/request-sla.subscriber.js +1105 -0
  336. package/dist/backend/backend/src/services/v3/request-sla.subscriber.js.map +1 -0
  337. package/dist/backend/backend/src/services/v3/request.service.d.ts +22 -0
  338. package/dist/backend/backend/src/services/v3/request.service.d.ts.map +1 -1
  339. package/dist/backend/backend/src/services/v3/request.service.js +71 -0
  340. package/dist/backend/backend/src/services/v3/request.service.js.map +1 -1
  341. package/dist/backend/backend/src/services/v3/v3-data.service.d.ts +1 -0
  342. package/dist/backend/backend/src/services/v3/v3-data.service.d.ts.map +1 -1
  343. package/dist/backend/backend/src/services/v3/v3-data.service.js +22 -6
  344. package/dist/backend/backend/src/services/v3/v3-data.service.js.map +1 -1
  345. package/dist/backend/backend/src/types/event-bus.types.d.ts +19 -1
  346. package/dist/backend/backend/src/types/event-bus.types.d.ts.map +1 -1
  347. package/dist/backend/backend/src/types/event-bus.types.js +43 -0
  348. package/dist/backend/backend/src/types/event-bus.types.js.map +1 -1
  349. package/dist/backend/backend/src/types/index.d.ts +22 -1
  350. package/dist/backend/backend/src/types/index.d.ts.map +1 -1
  351. package/dist/backend/backend/src/types/index.js.map +1 -1
  352. package/dist/backend/backend/src/types/review-reason.types.d.ts +63 -0
  353. package/dist/backend/backend/src/types/review-reason.types.d.ts.map +1 -0
  354. package/dist/backend/backend/src/types/review-reason.types.js +50 -0
  355. package/dist/backend/backend/src/types/review-reason.types.js.map +1 -0
  356. package/dist/backend/backend/src/types/skill.types.d.ts +9 -0
  357. package/dist/backend/backend/src/types/skill.types.d.ts.map +1 -1
  358. package/dist/backend/backend/src/types/skill.types.js.map +1 -1
  359. package/dist/backend/backend/src/types/slack.types.d.ts +4 -1
  360. package/dist/backend/backend/src/types/slack.types.d.ts.map +1 -1
  361. package/dist/backend/backend/src/types/slack.types.js.map +1 -1
  362. package/dist/backend/backend/src/types/v2/mission.types.d.ts +18 -0
  363. package/dist/backend/backend/src/types/v2/mission.types.d.ts.map +1 -1
  364. package/dist/backend/backend/src/types/v2/mission.types.js +1 -0
  365. package/dist/backend/backend/src/types/v2/mission.types.js.map +1 -1
  366. package/dist/backend/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  367. package/dist/backend/backend/src/types/v2/work-item.types.js +25 -1
  368. package/dist/backend/backend/src/types/v2/work-item.types.js.map +1 -1
  369. package/dist/backend/backend/src/utils/google-userinfo.utils.d.ts +41 -0
  370. package/dist/backend/backend/src/utils/google-userinfo.utils.d.ts.map +1 -0
  371. package/dist/backend/backend/src/utils/google-userinfo.utils.js +44 -0
  372. package/dist/backend/backend/src/utils/google-userinfo.utils.js.map +1 -0
  373. package/dist/backend/backend/src/utils/team.utils.d.ts +38 -0
  374. package/dist/backend/backend/src/utils/team.utils.d.ts.map +1 -0
  375. package/dist/backend/backend/src/utils/team.utils.js +45 -0
  376. package/dist/backend/backend/src/utils/team.utils.js.map +1 -0
  377. package/dist/backend/backend/src/websocket/chat-v2.gateway.d.ts +195 -0
  378. package/dist/backend/backend/src/websocket/chat-v2.gateway.d.ts.map +1 -0
  379. package/dist/backend/backend/src/websocket/chat-v2.gateway.js +401 -0
  380. package/dist/backend/backend/src/websocket/chat-v2.gateway.js.map +1 -0
  381. package/dist/backend/backend/src/websocket/terminal.gateway.d.ts +37 -2
  382. package/dist/backend/backend/src/websocket/terminal.gateway.d.ts.map +1 -1
  383. package/dist/backend/backend/src/websocket/terminal.gateway.js +106 -5
  384. package/dist/backend/backend/src/websocket/terminal.gateway.js.map +1 -1
  385. package/dist/cli/backend/src/config/oauth.config.d.ts +33 -0
  386. package/dist/cli/backend/src/config/oauth.config.d.ts.map +1 -0
  387. package/dist/cli/backend/src/config/oauth.config.js +45 -0
  388. package/dist/cli/backend/src/config/oauth.config.js.map +1 -0
  389. package/dist/cli/backend/src/constants.d.ts +69 -1
  390. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  391. package/dist/cli/backend/src/constants.js +69 -2
  392. package/dist/cli/backend/src/constants.js.map +1 -1
  393. package/dist/cli/backend/src/services/core/config.service.js +3 -3
  394. package/dist/cli/backend/src/services/core/config.service.js.map +1 -1
  395. package/dist/cli/backend/src/services/core/storage.service.d.ts +7 -0
  396. package/dist/cli/backend/src/services/core/storage.service.d.ts.map +1 -1
  397. package/dist/cli/backend/src/services/core/storage.service.js +15 -0
  398. package/dist/cli/backend/src/services/core/storage.service.js.map +1 -1
  399. package/dist/cli/backend/src/services/credential/helpers/gemini-cli-workspace.helper.d.ts +4 -16
  400. package/dist/cli/backend/src/services/credential/helpers/gemini-cli-workspace.helper.d.ts.map +1 -1
  401. package/dist/cli/backend/src/services/credential/helpers/gemini-cli-workspace.helper.js +7 -28
  402. package/dist/cli/backend/src/services/credential/helpers/gemini-cli-workspace.helper.js.map +1 -1
  403. package/dist/cli/backend/src/services/knowledge/fts5-index.service.d.ts.map +1 -1
  404. package/dist/cli/backend/src/services/knowledge/fts5-index.service.js +18 -2
  405. package/dist/cli/backend/src/services/knowledge/fts5-index.service.js.map +1 -1
  406. package/dist/cli/backend/src/services/knowledge/knowledge-search.service.d.ts +49 -13
  407. package/dist/cli/backend/src/services/knowledge/knowledge-search.service.d.ts.map +1 -1
  408. package/dist/cli/backend/src/services/knowledge/knowledge-search.service.js +123 -29
  409. package/dist/cli/backend/src/services/knowledge/knowledge-search.service.js.map +1 -1
  410. package/dist/cli/backend/src/services/knowledge/vector-store.service.d.ts.map +1 -1
  411. package/dist/cli/backend/src/services/knowledge/vector-store.service.js +24 -4
  412. package/dist/cli/backend/src/services/knowledge/vector-store.service.js.map +1 -1
  413. package/dist/cli/backend/src/services/mcp-server.d.ts +46 -2
  414. package/dist/cli/backend/src/services/mcp-server.d.ts.map +1 -1
  415. package/dist/cli/backend/src/services/mcp-server.js +216 -211
  416. package/dist/cli/backend/src/services/mcp-server.js.map +1 -1
  417. package/dist/cli/backend/src/services/mcp-tool-definitions.d.ts +254 -0
  418. package/dist/cli/backend/src/services/mcp-tool-definitions.d.ts.map +1 -0
  419. package/dist/cli/backend/src/services/mcp-tool-definitions.js +285 -0
  420. package/dist/cli/backend/src/services/mcp-tool-definitions.js.map +1 -0
  421. package/dist/cli/backend/src/services/skill/skill-executor.service.d.ts +18 -0
  422. package/dist/cli/backend/src/services/skill/skill-executor.service.d.ts.map +1 -1
  423. package/dist/cli/backend/src/services/skill/skill-executor.service.js +7 -9
  424. package/dist/cli/backend/src/services/skill/skill-executor.service.js.map +1 -1
  425. package/dist/cli/backend/src/types/index.d.ts +22 -1
  426. package/dist/cli/backend/src/types/index.d.ts.map +1 -1
  427. package/dist/cli/backend/src/types/index.js.map +1 -1
  428. package/dist/cli/backend/src/types/skill.types.d.ts +9 -0
  429. package/dist/cli/backend/src/types/skill.types.d.ts.map +1 -1
  430. package/dist/cli/backend/src/types/skill.types.js.map +1 -1
  431. package/dist/cli/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  432. package/dist/cli/backend/src/types/v2/work-item.types.js +25 -1
  433. package/dist/cli/backend/src/types/v2/work-item.types.js.map +1 -1
  434. package/dist/cli/backend/src/utils/google-userinfo.utils.d.ts +41 -0
  435. package/dist/cli/backend/src/utils/google-userinfo.utils.d.ts.map +1 -0
  436. package/dist/cli/backend/src/utils/google-userinfo.utils.js +44 -0
  437. package/dist/cli/backend/src/utils/google-userinfo.utils.js.map +1 -0
  438. package/frontend/dist/assets/{index-9e6d97d1.js → index-7a4e7df5.js} +328 -326
  439. package/frontend/dist/assets/index-b7e59b2b.css +33 -0
  440. package/frontend/dist/index.html +2 -2
  441. package/package.json +2 -1
  442. package/config/skills/orchestrator/recall/SKILL.md +0 -47
  443. package/config/skills/orchestrator/recall/execute.sh +0 -13
  444. package/config/skills/orchestrator/record-learning/SKILL.md +0 -47
  445. package/config/skills/orchestrator/record-learning/execute.sh +0 -13
  446. package/config/skills/orchestrator/remember/SKILL.md +0 -55
  447. package/config/skills/orchestrator/remember/execute.sh +0 -15
  448. package/frontend/dist/assets/index-6aaa0630.css +0 -33
@@ -0,0 +1,401 @@
1
+ /**
2
+ * ChatV2Gateway — native WebSocket gateway for the Phase 1 Chat MVP.
3
+ *
4
+ * Listens on `/ws/chat?channelId=X&token=Y&lastSeenSeq=N` and fans out
5
+ * wire-format frames to subscribers per Sam's tech spec §6 / the frontend
6
+ * contract implemented by Max in `packages/chat-ui/src/api/client.ts`.
7
+ *
8
+ * Wire contract this gateway must honor (enforced by co-located tests):
9
+ * - Client→server: `{type:"ping",ts}` every 25s
10
+ * - Server→client: `{type:"pong",ts}` echo within 10s
11
+ * - Server→client: `{type:"message",payload:{channelId,message:MessageDTO}}`
12
+ * - Server→client: `{type:"presence",payload:{agentSession,status,lastSeenAt?}}`
13
+ * - Server→client: `{type:"error",code,message}` followed by close() on fatal
14
+ *
15
+ * This module is intentionally thin: it does not persist, does not dispatch
16
+ * to agents, and does not manage presence state. The controller/dispatcher
17
+ * call `broadcast()` after the service layer writes to SQLite, so the
18
+ * gateway's only job is routing frames to the right sockets.
19
+ *
20
+ * Upgrade-handoff pattern copied from `BrowserBridgeService.attach()` —
21
+ * Socket.IO's Engine.IO upgrade handler would otherwise corrupt frames on
22
+ * non-`/socket.io/` paths, so we intercept the `upgrade` event on the
23
+ * HTTP server and handle `/ws/chat` exclusively.
24
+ *
25
+ * @module websocket/chat-v2.gateway
26
+ */
27
+ import { WebSocketServer, WebSocket } from 'ws';
28
+ import { ChatError, CHAT_ERROR_CODES } from '../services/chat-v2/types.js';
29
+ import { LoggerService } from '../services/core/logger.service.js';
30
+ /** Default WS mount path — matches the frontend `?${qs}` URL in client.ts. */
31
+ export const CHAT_V2_WS_PATH = '/ws/chat';
32
+ /**
33
+ * Always-accept token verifier used when `CREWLY_JWT_SECRET` is not
34
+ * configured. Returns the SAME `userId` that `requireAuth`'s dev
35
+ * fallback uses (`dev-user-001`) so that channels created via the
36
+ * REST API are owned by the same principal the WS client will verify
37
+ * as. Not for production — in production a JWT-verifying `verifyToken`
38
+ * function is passed to `ChatV2Gateway` instead.
39
+ */
40
+ export const devAnonymousTokenVerifier = async () => ({
41
+ userId: 'dev-user-001',
42
+ });
43
+ /**
44
+ * A WebSocket gateway that fans chat events out to subscribers.
45
+ *
46
+ * Lifecycle:
47
+ * 1. `attach(httpServer)` — hooks the upgrade interceptor
48
+ * 2. `broadcast(channelId, event)` — called by controller after persist
49
+ * 3. `close()` — shutdown hook (graceful close all sockets)
50
+ *
51
+ * The gateway owns the WebSocketServer and the subscribers map. It never
52
+ * reaches into the service layer on its own — all domain data arrives via
53
+ * `broadcast()` from callers who have already persisted.
54
+ */
55
+ export class ChatV2Gateway {
56
+ service;
57
+ verifyToken;
58
+ path;
59
+ webSocketServerImpl;
60
+ now;
61
+ logger;
62
+ wss = null;
63
+ attached = false;
64
+ /** channelId → set of subscribers listening on that channel. */
65
+ subscribers = new Map();
66
+ constructor(options) {
67
+ this.service = options.service;
68
+ this.verifyToken = options.verifyToken;
69
+ this.path = options.path ?? CHAT_V2_WS_PATH;
70
+ this.webSocketServerImpl = options.webSocketServerImpl ?? WebSocketServer;
71
+ this.now = options.now ?? Date.now;
72
+ this.logger = LoggerService.getInstance().createComponentLogger('ChatV2Gateway');
73
+ }
74
+ /**
75
+ * Mount the gateway on an HTTP server.
76
+ *
77
+ * Uses `noServer:true` + an `httpServer.emit` override identical to
78
+ * `BrowserBridgeService.attach()` — the override exclusively handles
79
+ * upgrades whose pathname matches `this.path`, so Engine.IO never sees
80
+ * them and cannot corrupt the frames.
81
+ *
82
+ * @param httpServer - Shared Node HTTP server instance
83
+ */
84
+ attach(httpServer) {
85
+ if (this.attached) {
86
+ this.logger.warn('chat-v2 WS gateway already attached');
87
+ return;
88
+ }
89
+ this.attached = true;
90
+ this.wss = new this.webSocketServerImpl({
91
+ noServer: true,
92
+ perMessageDeflate: false,
93
+ });
94
+ // Two-part installation:
95
+ // 1. Register an explicit `upgrade` listener. This guarantees the
96
+ // event is wired even when we're the ONLY listener (tests, dev
97
+ // standalone — no Socket.IO). In production Socket.IO ALSO
98
+ // listens; both fire, but step 2 keeps them from colliding.
99
+ // 2. Override `httpServer.emit` so that a `/ws/chat` upgrade event
100
+ // is handled exclusively, with no other listeners (Engine.IO's
101
+ // in particular) seeing it. Without this, Engine.IO's 1s
102
+ // socket.end() timer and compression bits would corrupt our
103
+ // frames. Same pattern as `BrowserBridgeService.attach()`.
104
+ const pathMatches = (req) => {
105
+ const url = req.url || '';
106
+ const host = req.headers.host || 'localhost';
107
+ try {
108
+ return new URL(url, `http://${host}`).pathname === this.path;
109
+ }
110
+ catch {
111
+ return false;
112
+ }
113
+ };
114
+ const performUpgrade = (request, socket, head) => {
115
+ if (!pathMatches(request))
116
+ return;
117
+ this.wss.handleUpgrade(request, socket, head, (ws, req) => {
118
+ this.wss.emit('connection', ws, req);
119
+ });
120
+ };
121
+ // Register the listener so the 'upgrade' event fires at all (Node's
122
+ // HTTP server routes upgrade requests to the regular request handler
123
+ // when no 'upgrade' listener is registered).
124
+ httpServer.on('upgrade', performUpgrade);
125
+ const originalEmit = httpServer.emit.bind(httpServer);
126
+ httpServer.emit = (event, ...args) => {
127
+ if (event === 'upgrade') {
128
+ const request = args[0];
129
+ if (pathMatches(request)) {
130
+ // Run our upgrade handler exclusively — skip every other
131
+ // listener (Engine.IO's especially) so their post-hooks cannot
132
+ // corrupt our socket.
133
+ performUpgrade(args[0], args[1], args[2]);
134
+ return true;
135
+ }
136
+ }
137
+ return originalEmit(event, ...args);
138
+ };
139
+ this.wss.on('connection', (ws, req) => {
140
+ // ts-jest in CI sometimes resolves req.url as undefined when the
141
+ // upgrade interceptor is exercised from a test — guard both.
142
+ void this.handleConnection(ws, req);
143
+ });
144
+ this.wss.on('error', (err) => {
145
+ this.logger.error('WS server error', { error: err.message });
146
+ });
147
+ this.logger.info('chat-v2 WS gateway attached', { path: this.path });
148
+ }
149
+ /**
150
+ * Broadcast a wire event to every subscriber on `channelId`.
151
+ *
152
+ * Safe to call synchronously from inside a DB transaction — sends are
153
+ * queued on the underlying socket and do not block.
154
+ *
155
+ * @param channelId - Target channel
156
+ * @param event - Wire frame to push
157
+ */
158
+ broadcast(channelId, event) {
159
+ const set = this.subscribers.get(channelId);
160
+ if (!set || set.size === 0)
161
+ return;
162
+ const frame = JSON.stringify(event);
163
+ for (const sub of set) {
164
+ if (sub.ws.readyState !== WebSocket.OPEN)
165
+ continue;
166
+ try {
167
+ sub.ws.send(frame);
168
+ }
169
+ catch (err) {
170
+ this.logger.warn('chat-v2 ws send failed', {
171
+ channelId,
172
+ err: err instanceof Error ? err.message : String(err),
173
+ });
174
+ }
175
+ }
176
+ }
177
+ /**
178
+ * Count of currently-open subscribers for a channel. Exposed for tests
179
+ * and future observability dashboards.
180
+ */
181
+ subscriberCount(channelId) {
182
+ return this.subscribers.get(channelId)?.size ?? 0;
183
+ }
184
+ /** Total open sockets across all channels. Observability helper. */
185
+ totalSubscribers() {
186
+ let n = 0;
187
+ for (const set of this.subscribers.values())
188
+ n += set.size;
189
+ return n;
190
+ }
191
+ /**
192
+ * Gracefully close all sockets. Called during shutdown.
193
+ */
194
+ async close() {
195
+ if (!this.wss)
196
+ return;
197
+ for (const set of this.subscribers.values()) {
198
+ for (const sub of set) {
199
+ try {
200
+ sub.ws.close(1001, 'server shutdown');
201
+ }
202
+ catch {
203
+ // ignore
204
+ }
205
+ }
206
+ }
207
+ this.subscribers.clear();
208
+ await new Promise((resolve) => {
209
+ this.wss.close(() => resolve());
210
+ });
211
+ this.wss = null;
212
+ }
213
+ // -------------------------------------------------------------------------
214
+ // Connection lifecycle
215
+ // -------------------------------------------------------------------------
216
+ /**
217
+ * Handle a freshly-upgraded socket: parse query string, verify token,
218
+ * authorize against the channel, and register the subscriber.
219
+ *
220
+ * On any failure we send a single `{type:"error",...}` frame and close
221
+ * with a 1008 (policy violation) code — matching the frontend's
222
+ * "fatal, stop reconnecting" contract.
223
+ */
224
+ async handleConnection(ws, req) {
225
+ const host = req.headers.host || 'localhost';
226
+ let parsed;
227
+ try {
228
+ parsed = new URL(req.url ?? '', `http://${host}`);
229
+ }
230
+ catch {
231
+ this.sendErrorAndClose(ws, 'bad_request', 'malformed URL');
232
+ return;
233
+ }
234
+ const channelId = parsed.searchParams.get('channelId');
235
+ const token = parsed.searchParams.get('token');
236
+ // lastSeenSeq is accepted but not yet acted on (Phase 1.5 replay).
237
+ // Parsing validates that callers send a number if they send it at all.
238
+ const lastSeenSeqRaw = parsed.searchParams.get('lastSeenSeq');
239
+ if (lastSeenSeqRaw !== null && !/^\d+$/.test(lastSeenSeqRaw)) {
240
+ this.sendErrorAndClose(ws, 'bad_request', 'lastSeenSeq must be a non-negative integer');
241
+ return;
242
+ }
243
+ if (!channelId) {
244
+ this.sendErrorAndClose(ws, 'bad_request', 'channelId is required');
245
+ return;
246
+ }
247
+ let identity;
248
+ try {
249
+ identity = await this.verifyToken(token);
250
+ }
251
+ catch (err) {
252
+ this.logger.warn('chat-v2 ws token verify threw', {
253
+ err: err instanceof Error ? err.message : String(err),
254
+ });
255
+ this.sendErrorAndClose(ws, 'unauthorized', 'token verification failed');
256
+ return;
257
+ }
258
+ if (!identity) {
259
+ this.sendErrorAndClose(ws, 'unauthorized', 'invalid token');
260
+ return;
261
+ }
262
+ // Authorize: the channel must exist AND be owned by this user (or —
263
+ // in a later iteration — be readable by the agent identified here).
264
+ try {
265
+ this.service.getChannel(channelId, { userId: identity.userId, source: 'oss' });
266
+ }
267
+ catch (err) {
268
+ if (err instanceof ChatError && err.code === CHAT_ERROR_CODES.CHANNEL_NOT_FOUND) {
269
+ // 404 leaks less than 403 for ownership checks (consistent with §7.2)
270
+ this.sendErrorAndClose(ws, 'channel_not_found', 'channel not found');
271
+ return;
272
+ }
273
+ this.sendErrorAndClose(ws, 'internal_error', 'authorization failed');
274
+ return;
275
+ }
276
+ const subscriber = {
277
+ ws,
278
+ channelId,
279
+ userId: identity.userId,
280
+ connectedAt: this.now(),
281
+ };
282
+ this.registerSubscriber(subscriber);
283
+ ws.on('message', (data) => this.handleMessage(subscriber, data));
284
+ ws.on('close', () => this.unregisterSubscriber(subscriber));
285
+ ws.on('error', (err) => {
286
+ this.logger.warn('chat-v2 ws socket error', {
287
+ channelId: subscriber.channelId,
288
+ err: err.message,
289
+ });
290
+ });
291
+ this.logger.debug('chat-v2 ws connection established', {
292
+ channelId,
293
+ userId: identity.userId,
294
+ total: this.totalSubscribers(),
295
+ });
296
+ }
297
+ // -------------------------------------------------------------------------
298
+ // Message routing
299
+ // -------------------------------------------------------------------------
300
+ /**
301
+ * Handle a frame from the client.
302
+ *
303
+ * Phase 1 only understands `{type:"ping",ts}`; any other shape is
304
+ * silently dropped (forward-compat with future client-origin frames).
305
+ */
306
+ handleMessage(sub, raw) {
307
+ let parsed = null;
308
+ try {
309
+ const text = typeof raw === 'string' ? raw : Buffer.isBuffer(raw) ? raw.toString('utf-8') : String(raw);
310
+ const obj = JSON.parse(text);
311
+ if (obj && obj.type === 'ping') {
312
+ const ts = typeof obj.ts === 'number' ? obj.ts : this.now();
313
+ parsed = { type: 'ping', ts };
314
+ }
315
+ }
316
+ catch {
317
+ // malformed frame — drop
318
+ return;
319
+ }
320
+ if (!parsed)
321
+ return;
322
+ // Echo pong with the client's own ts — the client uses the round-trip
323
+ // for its 10s timeout, not strict clock agreement.
324
+ const pong = { type: 'pong', ts: parsed.ts };
325
+ if (sub.ws.readyState === WebSocket.OPEN) {
326
+ try {
327
+ sub.ws.send(JSON.stringify(pong));
328
+ }
329
+ catch {
330
+ // ignore — the socket will close and the close handler cleans up
331
+ }
332
+ }
333
+ }
334
+ // -------------------------------------------------------------------------
335
+ // Subscriber bookkeeping
336
+ // -------------------------------------------------------------------------
337
+ registerSubscriber(sub) {
338
+ let set = this.subscribers.get(sub.channelId);
339
+ if (!set) {
340
+ set = new Set();
341
+ this.subscribers.set(sub.channelId, set);
342
+ }
343
+ set.add(sub);
344
+ }
345
+ unregisterSubscriber(sub) {
346
+ const set = this.subscribers.get(sub.channelId);
347
+ if (!set)
348
+ return;
349
+ set.delete(sub);
350
+ if (set.size === 0)
351
+ this.subscribers.delete(sub.channelId);
352
+ }
353
+ /**
354
+ * Send an error frame then close with 1008. Used for all pre-subscribe
355
+ * rejections (auth, malformed URL, missing channelId, not-found).
356
+ */
357
+ sendErrorAndClose(ws, code, message) {
358
+ try {
359
+ if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {
360
+ ws.send(JSON.stringify({ type: 'error', code, message }));
361
+ }
362
+ }
363
+ catch {
364
+ // ignore
365
+ }
366
+ try {
367
+ ws.close(1008, code);
368
+ }
369
+ catch {
370
+ // ignore
371
+ }
372
+ }
373
+ }
374
+ // ---------------------------------------------------------------------------
375
+ // Channel presence broadcast helper (future — not wired in Phase 1)
376
+ // ---------------------------------------------------------------------------
377
+ /**
378
+ * Build a presence wire frame. Placed here so both the gateway's tests and
379
+ * future presence emitters use the same shape.
380
+ *
381
+ * @param agentSession - The agent whose presence changed
382
+ * @param status - New status
383
+ * @param lastSeenAt - Optional last-seen timestamp (ms)
384
+ */
385
+ export function buildPresenceEvent(agentSession, status, lastSeenAt) {
386
+ return {
387
+ type: 'presence',
388
+ payload: { agentSession, status, lastSeenAt: lastSeenAt ?? null },
389
+ };
390
+ }
391
+ /**
392
+ * Build a message wire frame from a DTO. Used by both the controller (on
393
+ * HTTP persist) and the dispatcher (on agent reply).
394
+ */
395
+ export function buildMessageEvent(channelId, message) {
396
+ return {
397
+ type: 'message',
398
+ payload: { channelId, message },
399
+ };
400
+ }
401
+ //# sourceMappingURL=chat-v2.gateway.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-v2.gateway.js","sourceRoot":"","sources":["../../../../../backend/src/websocket/chat-v2.gateway.ts"],"names":[],"mappings":"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"}
@@ -28,6 +28,14 @@ export declare class TerminalGateway {
28
28
  private sessionSubscriptions;
29
29
  /** Set of sessions with persistent monitoring (not stopped on client disconnect) */
30
30
  private persistentMonitoringSessions;
31
+ /**
32
+ * Pending retry timers for eager monitoring attempts that fired before the
33
+ * PTY session was registered in the SessionBackend.
34
+ *
35
+ * Keyed by session name. Cleared on first successful attach, on stop, and
36
+ * on destroy so a backoff schedule never leaks a timer past the gateway.
37
+ */
38
+ private pendingMonitoringRetries;
31
39
  /** Current active chat conversation ID for orchestrator responses */
32
40
  private activeConversationId;
33
41
  /**
@@ -106,15 +114,42 @@ export declare class TerminalGateway {
106
114
  private stopPtyStreaming;
107
115
  /**
108
116
  * Start persistent monitoring for the orchestrator session.
109
- * This ensures chat responses are captured even when no WebSocket clients are viewing the terminal.
117
+ *
118
+ * Ensures chat responses are captured even when no WebSocket clients are
119
+ * viewing the terminal. If the PTY session is not yet registered in the
120
+ * SessionBackend (e.g. eager call from boot fires before
121
+ * createAgentSession's backend registration completes), schedules bounded
122
+ * retries on the {@link TERMINAL_GATEWAY_CONSTANTS.MONITORING_RETRY_BACKOFFS_MS}
123
+ * backoff schedule. Persistent flag stays set across retries so a parallel
124
+ * subscriber path doesn't bypass eventual attachment.
110
125
  *
111
126
  * @param sessionName - The orchestrator session name to monitor
112
- * @returns True if monitoring started successfully
127
+ * @returns True if monitoring started synchronously on first attempt; false
128
+ * if a retry was scheduled (caller-visible failure is reserved for
129
+ * terminal failure after all retries, surfaced via ERROR log only).
113
130
  */
114
131
  startOrchestratorChatMonitoring(sessionName: string): boolean;
132
+ /**
133
+ * Schedule the next bounded retry attempt to attach orchestrator monitoring.
134
+ *
135
+ * @param sessionName - Session name being monitored
136
+ * @param attemptIndex - 0-based index into MONITORING_RETRY_BACKOFFS_MS
137
+ */
138
+ private scheduleMonitoringRetry;
139
+ /**
140
+ * Clear any pending monitoring retry timer for a session.
141
+ *
142
+ * Idempotent — safe to call when no retry is queued.
143
+ *
144
+ * @param sessionName - Session name whose retry should be cleared
145
+ */
146
+ private clearPendingMonitoringRetry;
115
147
  /**
116
148
  * Stop persistent monitoring for the orchestrator session.
117
149
  *
150
+ * Cancels any in-flight retry schedule so a stop mid-backoff doesn't leak
151
+ * a timer that later attaches to a session the caller already gave up on.
152
+ *
118
153
  * @param sessionName - The orchestrator session name
119
154
  */
120
155
  stopOrchestratorChatMonitoring(sessionName: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"terminal.gateway.d.ts","sourceRoot":"","sources":["../../../../../backend/src/websocket/terminal.gateway.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"terminal.gateway.d.ts","sourceRoot":"","sources":["../../../../../backend/src/websocket/terminal.gateway.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,7 @@
11
11
  */
12
12
  import { LoggerService } from '../services/core/logger.service.js';
13
13
  import { getSessionBackendSync, } from '../services/session/index.js';
14
+ import { TERMINAL_GATEWAY_CONSTANTS } from '../constants.js';
14
15
  import { InProcessLogBuffer } from '../services/agent/crewly-agent/in-process-log-buffer.js';
15
16
  /**
16
17
  * Terminal Gateway class for WebSocket-based terminal streaming.
@@ -30,6 +31,14 @@ export class TerminalGateway {
30
31
  sessionSubscriptions = new Map();
31
32
  /** Set of sessions with persistent monitoring (not stopped on client disconnect) */
32
33
  persistentMonitoringSessions = new Set();
34
+ /**
35
+ * Pending retry timers for eager monitoring attempts that fired before the
36
+ * PTY session was registered in the SessionBackend.
37
+ *
38
+ * Keyed by session name. Cleared on first successful attach, on stop, and
39
+ * on destroy so a backoff schedule never leaks a timer past the gateway.
40
+ */
41
+ pendingMonitoringRetries = new Map();
33
42
  /** Current active chat conversation ID for orchestrator responses */
34
43
  activeConversationId = null;
35
44
  /**
@@ -297,13 +306,25 @@ export class TerminalGateway {
297
306
  }
298
307
  /**
299
308
  * Start persistent monitoring for the orchestrator session.
300
- * This ensures chat responses are captured even when no WebSocket clients are viewing the terminal.
309
+ *
310
+ * Ensures chat responses are captured even when no WebSocket clients are
311
+ * viewing the terminal. If the PTY session is not yet registered in the
312
+ * SessionBackend (e.g. eager call from boot fires before
313
+ * createAgentSession's backend registration completes), schedules bounded
314
+ * retries on the {@link TERMINAL_GATEWAY_CONSTANTS.MONITORING_RETRY_BACKOFFS_MS}
315
+ * backoff schedule. Persistent flag stays set across retries so a parallel
316
+ * subscriber path doesn't bypass eventual attachment.
301
317
  *
302
318
  * @param sessionName - The orchestrator session name to monitor
303
- * @returns True if monitoring started successfully
319
+ * @returns True if monitoring started synchronously on first attempt; false
320
+ * if a retry was scheduled (caller-visible failure is reserved for
321
+ * terminal failure after all retries, surfaced via ERROR log only).
304
322
  */
305
323
  startOrchestratorChatMonitoring(sessionName) {
306
324
  this.logger.info('Starting persistent orchestrator chat monitoring', { sessionName });
325
+ // Cancel any in-flight retry from a previous start call so we don't
326
+ // stack two backoff schedules on the same session.
327
+ this.clearPendingMonitoringRetry(sessionName);
307
328
  // Force cleanup any stale subscription from a previous session.
308
329
  // When the orchestrator is restarted, the old PTY session is destroyed but
309
330
  // the subscription entry may still exist pointing to the dead session.
@@ -317,19 +338,92 @@ export class TerminalGateway {
317
338
  // Mark session as persistent so it won't be stopped when clients disconnect
318
339
  this.persistentMonitoringSessions.add(sessionName);
319
340
  const started = this.startPtyStreaming(sessionName);
320
- if (!started) {
321
- this.logger.warn('Failed to start orchestrator chat monitoring', { sessionName });
341
+ if (started) {
342
+ return true;
343
+ }
344
+ // Backend hasn't registered the session yet (race with createAgentSession).
345
+ // Keep persistentMonitoringSessions flagged and schedule bounded retries.
346
+ this.logger.warn('PTY not ready for orchestrator chat monitoring, scheduling retries', { sessionName, schedule: TERMINAL_GATEWAY_CONSTANTS.MONITORING_RETRY_BACKOFFS_MS });
347
+ this.scheduleMonitoringRetry(sessionName, 0);
348
+ return false;
349
+ }
350
+ /**
351
+ * Schedule the next bounded retry attempt to attach orchestrator monitoring.
352
+ *
353
+ * @param sessionName - Session name being monitored
354
+ * @param attemptIndex - 0-based index into MONITORING_RETRY_BACKOFFS_MS
355
+ */
356
+ scheduleMonitoringRetry(sessionName, attemptIndex) {
357
+ const schedule = TERMINAL_GATEWAY_CONSTANTS.MONITORING_RETRY_BACKOFFS_MS;
358
+ if (attemptIndex >= schedule.length) {
359
+ // Exhausted retries — log diagnostics and give up. Drop the
360
+ // persistent flag so a subsequent subscriber-driven attach can
361
+ // still proceed via the normal subscribeToSession path.
362
+ const backend = getSessionBackendSync();
363
+ this.logger.error('Orchestrator chat monitoring failed after all retries — orc output will not stream until a client subscribes', {
364
+ sessionName,
365
+ attempts: schedule.length,
366
+ availableSessions: backend?.listSessions() ?? [],
367
+ });
322
368
  this.persistentMonitoringSessions.delete(sessionName);
369
+ this.pendingMonitoringRetries.delete(sessionName);
370
+ return;
371
+ }
372
+ const delayMs = schedule[attemptIndex];
373
+ const timer = setTimeout(() => {
374
+ this.pendingMonitoringRetries.delete(sessionName);
375
+ // Stop guard: the persistent flag is cleared by
376
+ // stopOrchestratorChatMonitoring. If it's gone, abandon retry.
377
+ if (!this.persistentMonitoringSessions.has(sessionName)) {
378
+ this.logger.debug('Monitoring retry abandoned — persistent flag cleared', {
379
+ sessionName,
380
+ attemptIndex,
381
+ });
382
+ return;
383
+ }
384
+ const started = this.startPtyStreaming(sessionName);
385
+ if (started) {
386
+ this.logger.info('Orchestrator chat monitoring attached on retry', {
387
+ sessionName,
388
+ attemptIndex: attemptIndex + 1,
389
+ delayMs,
390
+ });
391
+ return;
392
+ }
393
+ this.scheduleMonitoringRetry(sessionName, attemptIndex + 1);
394
+ }, delayMs);
395
+ // Allow the process to exit even if a retry is still pending.
396
+ // Without unref, lingering timers keep node alive past graceful shutdown.
397
+ if (typeof timer.unref === 'function') {
398
+ timer.unref();
399
+ }
400
+ this.pendingMonitoringRetries.set(sessionName, timer);
401
+ }
402
+ /**
403
+ * Clear any pending monitoring retry timer for a session.
404
+ *
405
+ * Idempotent — safe to call when no retry is queued.
406
+ *
407
+ * @param sessionName - Session name whose retry should be cleared
408
+ */
409
+ clearPendingMonitoringRetry(sessionName) {
410
+ const timer = this.pendingMonitoringRetries.get(sessionName);
411
+ if (timer) {
412
+ clearTimeout(timer);
413
+ this.pendingMonitoringRetries.delete(sessionName);
323
414
  }
324
- return started;
325
415
  }
326
416
  /**
327
417
  * Stop persistent monitoring for the orchestrator session.
328
418
  *
419
+ * Cancels any in-flight retry schedule so a stop mid-backoff doesn't leak
420
+ * a timer that later attaches to a session the caller already gave up on.
421
+ *
329
422
  * @param sessionName - The orchestrator session name
330
423
  */
331
424
  stopOrchestratorChatMonitoring(sessionName) {
332
425
  this.logger.info('Stopping persistent orchestrator chat monitoring', { sessionName });
426
+ this.clearPendingMonitoringRetry(sessionName);
333
427
  this.stopPtyStreaming(sessionName, true);
334
428
  }
335
429
  /**
@@ -778,6 +872,13 @@ export class TerminalGateway {
778
872
  * Destroy the gateway and clean up all subscriptions.
779
873
  */
780
874
  destroy() {
875
+ // Cancel any pending monitoring retries before tearing down.
876
+ // Otherwise a queued retry could fire after destroy and attach
877
+ // a listener to a session whose owner has gone away.
878
+ for (const timer of this.pendingMonitoringRetries.values()) {
879
+ clearTimeout(timer);
880
+ }
881
+ this.pendingMonitoringRetries.clear();
781
882
  // Unsubscribe from all PTY sessions
782
883
  for (const unsubscribe of this.sessionSubscriptions.values()) {
783
884
  unsubscribe();