crewly 1.6.1 → 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 (363) 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/sops/developer/git-workflow.md +38 -3
  15. package/dist/backend/backend/src/constants.d.ts +69 -1
  16. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  17. package/dist/backend/backend/src/constants.js +69 -2
  18. package/dist/backend/backend/src/constants.js.map +1 -1
  19. package/dist/backend/backend/src/controllers/active-work/active-work.controller.d.ts +53 -0
  20. package/dist/backend/backend/src/controllers/active-work/active-work.controller.d.ts.map +1 -0
  21. package/dist/backend/backend/src/controllers/active-work/active-work.controller.js +92 -0
  22. package/dist/backend/backend/src/controllers/active-work/active-work.controller.js.map +1 -0
  23. package/dist/backend/backend/src/controllers/agent-stream/agent-stream.controller.d.ts.map +1 -1
  24. package/dist/backend/backend/src/controllers/agent-stream/agent-stream.controller.js +18 -1
  25. package/dist/backend/backend/src/controllers/agent-stream/agent-stream.controller.js.map +1 -1
  26. package/dist/backend/backend/src/controllers/browser/browser.controller.d.ts +68 -0
  27. package/dist/backend/backend/src/controllers/browser/browser.controller.d.ts.map +1 -1
  28. package/dist/backend/backend/src/controllers/browser/browser.controller.js +233 -5
  29. package/dist/backend/backend/src/controllers/browser/browser.controller.js.map +1 -1
  30. package/dist/backend/backend/src/controllers/browser/browser.routes.d.ts.map +1 -1
  31. package/dist/backend/backend/src/controllers/browser/browser.routes.js +10 -1
  32. package/dist/backend/backend/src/controllers/browser/browser.routes.js.map +1 -1
  33. package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts.map +1 -1
  34. package/dist/backend/backend/src/controllers/chat/chat.controller.js +8 -3
  35. package/dist/backend/backend/src/controllers/chat/chat.controller.js.map +1 -1
  36. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.d.ts +132 -0
  37. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.d.ts.map +1 -0
  38. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.js +401 -0
  39. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.js.map +1 -0
  40. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.d.ts +29 -0
  41. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.d.ts.map +1 -0
  42. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.js +39 -0
  43. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.js.map +1 -0
  44. package/dist/backend/backend/src/controllers/chat-v2/index.d.ts +8 -0
  45. package/dist/backend/backend/src/controllers/chat-v2/index.d.ts.map +1 -0
  46. package/dist/backend/backend/src/controllers/chat-v2/index.js +8 -0
  47. package/dist/backend/backend/src/controllers/chat-v2/index.js.map +1 -0
  48. package/dist/backend/backend/src/controllers/onboarding/onboarding.routes.d.ts +13 -13
  49. package/dist/backend/backend/src/controllers/onboarding/onboarding.routes.d.ts.map +1 -1
  50. package/dist/backend/backend/src/controllers/onboarding/onboarding.routes.js +74 -234
  51. package/dist/backend/backend/src/controllers/onboarding/onboarding.routes.js.map +1 -1
  52. package/dist/backend/backend/src/controllers/request/request.controller.d.ts.map +1 -1
  53. package/dist/backend/backend/src/controllers/request/request.controller.js +4 -6
  54. package/dist/backend/backend/src/controllers/request/request.controller.js.map +1 -1
  55. package/dist/backend/backend/src/controllers/task-management/tasks.controller.d.ts +43 -0
  56. package/dist/backend/backend/src/controllers/task-management/tasks.controller.d.ts.map +1 -1
  57. package/dist/backend/backend/src/controllers/task-management/tasks.controller.js +200 -72
  58. package/dist/backend/backend/src/controllers/task-management/tasks.controller.js.map +1 -1
  59. package/dist/backend/backend/src/controllers/team/team.controller.d.ts.map +1 -1
  60. package/dist/backend/backend/src/controllers/team/team.controller.js +46 -0
  61. package/dist/backend/backend/src/controllers/team/team.controller.js.map +1 -1
  62. package/dist/backend/backend/src/controllers/team-health/team-health.controller.d.ts +59 -0
  63. package/dist/backend/backend/src/controllers/team-health/team-health.controller.d.ts.map +1 -0
  64. package/dist/backend/backend/src/controllers/team-health/team-health.controller.js +127 -0
  65. package/dist/backend/backend/src/controllers/team-health/team-health.controller.js.map +1 -0
  66. package/dist/backend/backend/src/controllers/team-health/team-health.routes.d.ts +13 -0
  67. package/dist/backend/backend/src/controllers/team-health/team-health.routes.d.ts.map +1 -0
  68. package/dist/backend/backend/src/controllers/team-health/team-health.routes.js +20 -0
  69. package/dist/backend/backend/src/controllers/team-health/team-health.routes.js.map +1 -0
  70. package/dist/backend/backend/src/index.d.ts +9 -0
  71. package/dist/backend/backend/src/index.d.ts.map +1 -1
  72. package/dist/backend/backend/src/index.js +233 -0
  73. package/dist/backend/backend/src/index.js.map +1 -1
  74. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  75. package/dist/backend/backend/src/routes/api.routes.js +40 -6
  76. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  77. package/dist/backend/backend/src/services/agent/active-work-briefing.service.d.ts +498 -0
  78. package/dist/backend/backend/src/services/agent/active-work-briefing.service.d.ts.map +1 -0
  79. package/dist/backend/backend/src/services/agent/active-work-briefing.service.js +759 -0
  80. package/dist/backend/backend/src/services/agent/active-work-briefing.service.js.map +1 -0
  81. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +25 -0
  82. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  83. package/dist/backend/backend/src/services/agent/agent-registration.service.js +193 -57
  84. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  85. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.d.ts +9 -2
  86. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.d.ts.map +1 -1
  87. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.js +35 -2
  88. package/dist/backend/backend/src/services/agent/crewly-agent/model-manager.js.map +1 -1
  89. package/dist/backend/backend/src/services/agent/crewly-agent/types.d.ts +8 -2
  90. package/dist/backend/backend/src/services/agent/crewly-agent/types.d.ts.map +1 -1
  91. package/dist/backend/backend/src/services/agent/crewly-agent/types.js +1 -0
  92. package/dist/backend/backend/src/services/agent/crewly-agent/types.js.map +1 -1
  93. package/dist/backend/backend/src/services/agent/tmux-command.service.d.ts.map +1 -1
  94. package/dist/backend/backend/src/services/agent/tmux-command.service.js +2 -1
  95. package/dist/backend/backend/src/services/agent/tmux-command.service.js.map +1 -1
  96. package/dist/backend/backend/src/services/agent/tmux.service.d.ts.map +1 -1
  97. package/dist/backend/backend/src/services/agent/tmux.service.js +2 -1
  98. package/dist/backend/backend/src/services/agent/tmux.service.js.map +1 -1
  99. package/dist/backend/backend/src/services/ai/prompt-builder.service.d.ts +148 -3
  100. package/dist/backend/backend/src/services/ai/prompt-builder.service.d.ts.map +1 -1
  101. package/dist/backend/backend/src/services/ai/prompt-builder.service.js +241 -2
  102. package/dist/backend/backend/src/services/ai/prompt-builder.service.js.map +1 -1
  103. package/dist/backend/backend/src/services/ai/prompt-modules/recovery.module.d.ts.map +1 -1
  104. package/dist/backend/backend/src/services/ai/prompt-modules/recovery.module.js +13 -0
  105. package/dist/backend/backend/src/services/ai/prompt-modules/recovery.module.js.map +1 -1
  106. package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.d.ts.map +1 -1
  107. package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.js +26 -1
  108. package/dist/backend/backend/src/services/ai/prompt-modules/role-boundary.module.js.map +1 -1
  109. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.d.ts +79 -0
  110. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.d.ts.map +1 -0
  111. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.js +118 -0
  112. package/dist/backend/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.js.map +1 -0
  113. package/dist/backend/backend/src/services/browser/browser-bridge.service.d.ts +161 -0
  114. package/dist/backend/backend/src/services/browser/browser-bridge.service.d.ts.map +1 -1
  115. package/dist/backend/backend/src/services/browser/browser-bridge.service.js +382 -2
  116. package/dist/backend/backend/src/services/browser/browser-bridge.service.js.map +1 -1
  117. package/dist/backend/backend/src/services/browser/browser-proxy.service.d.ts +105 -0
  118. package/dist/backend/backend/src/services/browser/browser-proxy.service.d.ts.map +1 -1
  119. package/dist/backend/backend/src/services/browser/browser-proxy.service.js +232 -13
  120. package/dist/backend/backend/src/services/browser/browser-proxy.service.js.map +1 -1
  121. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts +178 -0
  122. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -0
  123. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +254 -0
  124. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -0
  125. package/dist/backend/backend/src/services/chat-v2/chat-v2.mention-resolver.d.ts +134 -0
  126. package/dist/backend/backend/src/services/chat-v2/chat-v2.mention-resolver.d.ts.map +1 -0
  127. package/dist/backend/backend/src/services/chat-v2/chat-v2.mention-resolver.js +232 -0
  128. package/dist/backend/backend/src/services/chat-v2/chat-v2.mention-resolver.js.map +1 -0
  129. package/dist/backend/backend/src/services/chat-v2/chat-v2.realtime-holder.d.ts +25 -0
  130. package/dist/backend/backend/src/services/chat-v2/chat-v2.realtime-holder.d.ts.map +1 -0
  131. package/dist/backend/backend/src/services/chat-v2/chat-v2.realtime-holder.js +23 -0
  132. package/dist/backend/backend/src/services/chat-v2/chat-v2.realtime-holder.js.map +1 -0
  133. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts +254 -0
  134. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts.map +1 -0
  135. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js +467 -0
  136. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js.map +1 -0
  137. package/dist/backend/backend/src/services/chat-v2/chat-v2.singleton.d.ts +27 -0
  138. package/dist/backend/backend/src/services/chat-v2/chat-v2.singleton.d.ts.map +1 -0
  139. package/dist/backend/backend/src/services/chat-v2/chat-v2.singleton.js +57 -0
  140. package/dist/backend/backend/src/services/chat-v2/chat-v2.singleton.js.map +1 -0
  141. package/dist/backend/backend/src/services/chat-v2/chat-v2.team-membership.d.ts +43 -0
  142. package/dist/backend/backend/src/services/chat-v2/chat-v2.team-membership.d.ts.map +1 -0
  143. package/dist/backend/backend/src/services/chat-v2/chat-v2.team-membership.js +54 -0
  144. package/dist/backend/backend/src/services/chat-v2/chat-v2.team-membership.js.map +1 -0
  145. package/dist/backend/backend/src/services/chat-v2/config.d.ts +100 -0
  146. package/dist/backend/backend/src/services/chat-v2/config.d.ts.map +1 -0
  147. package/dist/backend/backend/src/services/chat-v2/config.js +174 -0
  148. package/dist/backend/backend/src/services/chat-v2/config.js.map +1 -0
  149. package/dist/backend/backend/src/services/chat-v2/index.d.ts +11 -0
  150. package/dist/backend/backend/src/services/chat-v2/index.d.ts.map +1 -0
  151. package/dist/backend/backend/src/services/chat-v2/index.js +12 -0
  152. package/dist/backend/backend/src/services/chat-v2/index.js.map +1 -0
  153. package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.d.ts +114 -0
  154. package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.d.ts.map +1 -0
  155. package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.js +194 -0
  156. package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.js.map +1 -0
  157. package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.d.ts +100 -0
  158. package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.d.ts.map +1 -0
  159. package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.js +351 -0
  160. package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.js.map +1 -0
  161. package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.d.ts +132 -0
  162. package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.d.ts.map +1 -0
  163. package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.js +281 -0
  164. package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.js.map +1 -0
  165. package/dist/backend/backend/src/services/chat-v2/types.d.ts +295 -0
  166. package/dist/backend/backend/src/services/chat-v2/types.d.ts.map +1 -0
  167. package/dist/backend/backend/src/services/chat-v2/types.js +61 -0
  168. package/dist/backend/backend/src/services/chat-v2/types.js.map +1 -0
  169. package/dist/backend/backend/src/services/cloud/cloud-event-bridge.service.d.ts +113 -0
  170. package/dist/backend/backend/src/services/cloud/cloud-event-bridge.service.d.ts.map +1 -0
  171. package/dist/backend/backend/src/services/cloud/cloud-event-bridge.service.js +179 -0
  172. package/dist/backend/backend/src/services/cloud/cloud-event-bridge.service.js.map +1 -0
  173. package/dist/backend/backend/src/services/cloud/cloud-event-forwarder.service.d.ts +131 -0
  174. package/dist/backend/backend/src/services/cloud/cloud-event-forwarder.service.d.ts.map +1 -0
  175. package/dist/backend/backend/src/services/cloud/cloud-event-forwarder.service.js +227 -0
  176. package/dist/backend/backend/src/services/cloud/cloud-event-forwarder.service.js.map +1 -0
  177. package/dist/backend/backend/src/services/core/config.service.js +3 -3
  178. package/dist/backend/backend/src/services/core/config.service.js.map +1 -1
  179. package/dist/backend/backend/src/services/core/storage.service.d.ts +7 -0
  180. package/dist/backend/backend/src/services/core/storage.service.d.ts.map +1 -1
  181. package/dist/backend/backend/src/services/core/storage.service.js +15 -0
  182. package/dist/backend/backend/src/services/core/storage.service.js.map +1 -1
  183. package/dist/backend/backend/src/services/event-bus/event-bus.service.d.ts +69 -1
  184. package/dist/backend/backend/src/services/event-bus/event-bus.service.d.ts.map +1 -1
  185. package/dist/backend/backend/src/services/event-bus/event-bus.service.js +118 -0
  186. package/dist/backend/backend/src/services/event-bus/event-bus.service.js.map +1 -1
  187. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.d.ts +275 -0
  188. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.d.ts.map +1 -0
  189. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js +736 -0
  190. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js.map +1 -0
  191. package/dist/backend/backend/src/services/knowledge/fts5-index.service.d.ts.map +1 -1
  192. package/dist/backend/backend/src/services/knowledge/fts5-index.service.js +18 -2
  193. package/dist/backend/backend/src/services/knowledge/fts5-index.service.js.map +1 -1
  194. package/dist/backend/backend/src/services/knowledge/knowledge-search.service.d.ts +49 -13
  195. package/dist/backend/backend/src/services/knowledge/knowledge-search.service.d.ts.map +1 -1
  196. package/dist/backend/backend/src/services/knowledge/knowledge-search.service.js +123 -29
  197. package/dist/backend/backend/src/services/knowledge/knowledge-search.service.js.map +1 -1
  198. package/dist/backend/backend/src/services/knowledge/learnings-index.service.d.ts +159 -0
  199. package/dist/backend/backend/src/services/knowledge/learnings-index.service.d.ts.map +1 -0
  200. package/dist/backend/backend/src/services/knowledge/learnings-index.service.js +304 -0
  201. package/dist/backend/backend/src/services/knowledge/learnings-index.service.js.map +1 -0
  202. package/dist/backend/backend/src/services/knowledge/vector-store.service.d.ts.map +1 -1
  203. package/dist/backend/backend/src/services/knowledge/vector-store.service.js +24 -4
  204. package/dist/backend/backend/src/services/knowledge/vector-store.service.js.map +1 -1
  205. package/dist/backend/backend/src/services/memory/auto-learning.subscriber.d.ts +174 -0
  206. package/dist/backend/backend/src/services/memory/auto-learning.subscriber.d.ts.map +1 -0
  207. package/dist/backend/backend/src/services/memory/auto-learning.subscriber.js +375 -0
  208. package/dist/backend/backend/src/services/memory/auto-learning.subscriber.js.map +1 -0
  209. package/dist/backend/backend/src/services/memory/learning-format.validator.d.ts +97 -0
  210. package/dist/backend/backend/src/services/memory/learning-format.validator.d.ts.map +1 -0
  211. package/dist/backend/backend/src/services/memory/learning-format.validator.js +209 -0
  212. package/dist/backend/backend/src/services/memory/learning-format.validator.js.map +1 -0
  213. package/dist/backend/backend/src/services/memory/vector-store.service.d.ts.map +1 -1
  214. package/dist/backend/backend/src/services/memory/vector-store.service.js +19 -4
  215. package/dist/backend/backend/src/services/memory/vector-store.service.js.map +1 -1
  216. package/dist/backend/backend/src/services/onboarding/onboarding-provision.service.d.ts +16 -5
  217. package/dist/backend/backend/src/services/onboarding/onboarding-provision.service.d.ts.map +1 -1
  218. package/dist/backend/backend/src/services/onboarding/onboarding-provision.service.js +32 -5
  219. package/dist/backend/backend/src/services/onboarding/onboarding-provision.service.js.map +1 -1
  220. package/dist/backend/backend/src/services/onboarding/onboarding.service.d.ts +157 -0
  221. package/dist/backend/backend/src/services/onboarding/onboarding.service.d.ts.map +1 -0
  222. package/dist/backend/backend/src/services/onboarding/onboarding.service.js +229 -0
  223. package/dist/backend/backend/src/services/onboarding/onboarding.service.js.map +1 -0
  224. package/dist/backend/backend/src/services/onboarding/onboarding.types.d.ts +141 -0
  225. package/dist/backend/backend/src/services/onboarding/onboarding.types.d.ts.map +1 -0
  226. package/dist/backend/backend/src/services/onboarding/onboarding.types.js +18 -0
  227. package/dist/backend/backend/src/services/onboarding/onboarding.types.js.map +1 -0
  228. package/dist/backend/backend/src/services/pr-review/pr-review.service.d.ts.map +1 -1
  229. package/dist/backend/backend/src/services/pr-review/pr-review.service.js +1 -1
  230. package/dist/backend/backend/src/services/pr-review/pr-review.service.js.map +1 -1
  231. package/dist/backend/backend/src/services/slack/cross-machine-message.service.d.ts.map +1 -1
  232. package/dist/backend/backend/src/services/slack/cross-machine-message.service.js +17 -1
  233. package/dist/backend/backend/src/services/slack/cross-machine-message.service.js.map +1 -1
  234. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts +39 -1
  235. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
  236. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js +158 -26
  237. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
  238. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +248 -6
  239. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  240. package/dist/backend/backend/src/services/task-pool/task-pool.service.js +531 -51
  241. package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  242. package/dist/backend/backend/src/services/team-health/index.d.ts +16 -0
  243. package/dist/backend/backend/src/services/team-health/index.d.ts.map +1 -0
  244. package/dist/backend/backend/src/services/team-health/index.js +16 -0
  245. package/dist/backend/backend/src/services/team-health/index.js.map +1 -0
  246. package/dist/backend/backend/src/services/team-health/live-team-health-data-provider.d.ts +52 -0
  247. package/dist/backend/backend/src/services/team-health/live-team-health-data-provider.d.ts.map +1 -0
  248. package/dist/backend/backend/src/services/team-health/live-team-health-data-provider.js +161 -0
  249. package/dist/backend/backend/src/services/team-health/live-team-health-data-provider.js.map +1 -0
  250. package/dist/backend/backend/src/services/team-health/lost-dispatch-detector.d.ts +53 -0
  251. package/dist/backend/backend/src/services/team-health/lost-dispatch-detector.d.ts.map +1 -0
  252. package/dist/backend/backend/src/services/team-health/lost-dispatch-detector.js +88 -0
  253. package/dist/backend/backend/src/services/team-health/lost-dispatch-detector.js.map +1 -0
  254. package/dist/backend/backend/src/services/team-health/stale-trigger-detector.d.ts +44 -0
  255. package/dist/backend/backend/src/services/team-health/stale-trigger-detector.d.ts.map +1 -0
  256. package/dist/backend/backend/src/services/team-health/stale-trigger-detector.js +83 -0
  257. package/dist/backend/backend/src/services/team-health/stale-trigger-detector.js.map +1 -0
  258. package/dist/backend/backend/src/services/team-health/team-health-alert-router.d.ts +92 -0
  259. package/dist/backend/backend/src/services/team-health/team-health-alert-router.d.ts.map +1 -0
  260. package/dist/backend/backend/src/services/team-health/team-health-alert-router.js +328 -0
  261. package/dist/backend/backend/src/services/team-health/team-health-alert-router.js.map +1 -0
  262. package/dist/backend/backend/src/services/team-health/team-health-config.d.ts +41 -0
  263. package/dist/backend/backend/src/services/team-health/team-health-config.d.ts.map +1 -0
  264. package/dist/backend/backend/src/services/team-health/team-health-config.js +213 -0
  265. package/dist/backend/backend/src/services/team-health/team-health-config.js.map +1 -0
  266. package/dist/backend/backend/src/services/team-health/team-health-detector.d.ts +46 -0
  267. package/dist/backend/backend/src/services/team-health/team-health-detector.d.ts.map +1 -0
  268. package/dist/backend/backend/src/services/team-health/team-health-detector.js +347 -0
  269. package/dist/backend/backend/src/services/team-health/team-health-detector.js.map +1 -0
  270. package/dist/backend/backend/src/services/team-health/team-health-types.d.ts +154 -0
  271. package/dist/backend/backend/src/services/team-health/team-health-types.d.ts.map +1 -0
  272. package/dist/backend/backend/src/services/team-health/team-health-types.js +94 -0
  273. package/dist/backend/backend/src/services/team-health/team-health-types.js.map +1 -0
  274. package/dist/backend/backend/src/services/team-health/team-health-watchdog.service.d.ts +111 -0
  275. package/dist/backend/backend/src/services/team-health/team-health-watchdog.service.d.ts.map +1 -0
  276. package/dist/backend/backend/src/services/team-health/team-health-watchdog.service.js +226 -0
  277. package/dist/backend/backend/src/services/team-health/team-health-watchdog.service.js.map +1 -0
  278. package/dist/backend/backend/src/services/v3/mission-reminder.service.d.ts +148 -0
  279. package/dist/backend/backend/src/services/v3/mission-reminder.service.d.ts.map +1 -0
  280. package/dist/backend/backend/src/services/v3/mission-reminder.service.js +545 -0
  281. package/dist/backend/backend/src/services/v3/mission-reminder.service.js.map +1 -0
  282. package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts +499 -0
  283. package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts.map +1 -0
  284. package/dist/backend/backend/src/services/v3/request-sla.subscriber.js +1105 -0
  285. package/dist/backend/backend/src/services/v3/request-sla.subscriber.js.map +1 -0
  286. package/dist/backend/backend/src/services/v3/request.service.d.ts +22 -0
  287. package/dist/backend/backend/src/services/v3/request.service.d.ts.map +1 -1
  288. package/dist/backend/backend/src/services/v3/request.service.js +71 -0
  289. package/dist/backend/backend/src/services/v3/request.service.js.map +1 -1
  290. package/dist/backend/backend/src/services/v3/v3-data.service.d.ts +1 -0
  291. package/dist/backend/backend/src/services/v3/v3-data.service.d.ts.map +1 -1
  292. package/dist/backend/backend/src/services/v3/v3-data.service.js +22 -6
  293. package/dist/backend/backend/src/services/v3/v3-data.service.js.map +1 -1
  294. package/dist/backend/backend/src/types/event-bus.types.d.ts +19 -1
  295. package/dist/backend/backend/src/types/event-bus.types.d.ts.map +1 -1
  296. package/dist/backend/backend/src/types/event-bus.types.js +43 -0
  297. package/dist/backend/backend/src/types/event-bus.types.js.map +1 -1
  298. package/dist/backend/backend/src/types/index.d.ts +22 -1
  299. package/dist/backend/backend/src/types/index.d.ts.map +1 -1
  300. package/dist/backend/backend/src/types/index.js.map +1 -1
  301. package/dist/backend/backend/src/types/review-reason.types.d.ts +63 -0
  302. package/dist/backend/backend/src/types/review-reason.types.d.ts.map +1 -0
  303. package/dist/backend/backend/src/types/review-reason.types.js +50 -0
  304. package/dist/backend/backend/src/types/review-reason.types.js.map +1 -0
  305. package/dist/backend/backend/src/types/slack.types.d.ts +4 -1
  306. package/dist/backend/backend/src/types/slack.types.d.ts.map +1 -1
  307. package/dist/backend/backend/src/types/slack.types.js.map +1 -1
  308. package/dist/backend/backend/src/types/v2/mission.types.d.ts +18 -0
  309. package/dist/backend/backend/src/types/v2/mission.types.d.ts.map +1 -1
  310. package/dist/backend/backend/src/types/v2/mission.types.js +1 -0
  311. package/dist/backend/backend/src/types/v2/mission.types.js.map +1 -1
  312. package/dist/backend/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  313. package/dist/backend/backend/src/types/v2/work-item.types.js +25 -1
  314. package/dist/backend/backend/src/types/v2/work-item.types.js.map +1 -1
  315. package/dist/backend/backend/src/utils/team.utils.d.ts +38 -0
  316. package/dist/backend/backend/src/utils/team.utils.d.ts.map +1 -0
  317. package/dist/backend/backend/src/utils/team.utils.js +45 -0
  318. package/dist/backend/backend/src/utils/team.utils.js.map +1 -0
  319. package/dist/backend/backend/src/websocket/chat-v2.gateway.d.ts +195 -0
  320. package/dist/backend/backend/src/websocket/chat-v2.gateway.d.ts.map +1 -0
  321. package/dist/backend/backend/src/websocket/chat-v2.gateway.js +401 -0
  322. package/dist/backend/backend/src/websocket/chat-v2.gateway.js.map +1 -0
  323. package/dist/backend/backend/src/websocket/terminal.gateway.d.ts +37 -2
  324. package/dist/backend/backend/src/websocket/terminal.gateway.d.ts.map +1 -1
  325. package/dist/backend/backend/src/websocket/terminal.gateway.js +106 -5
  326. package/dist/backend/backend/src/websocket/terminal.gateway.js.map +1 -1
  327. package/dist/cli/backend/src/constants.d.ts +69 -1
  328. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  329. package/dist/cli/backend/src/constants.js +69 -2
  330. package/dist/cli/backend/src/constants.js.map +1 -1
  331. package/dist/cli/backend/src/services/core/config.service.js +3 -3
  332. package/dist/cli/backend/src/services/core/config.service.js.map +1 -1
  333. package/dist/cli/backend/src/services/core/storage.service.d.ts +7 -0
  334. package/dist/cli/backend/src/services/core/storage.service.d.ts.map +1 -1
  335. package/dist/cli/backend/src/services/core/storage.service.js +15 -0
  336. package/dist/cli/backend/src/services/core/storage.service.js.map +1 -1
  337. package/dist/cli/backend/src/services/knowledge/fts5-index.service.d.ts.map +1 -1
  338. package/dist/cli/backend/src/services/knowledge/fts5-index.service.js +18 -2
  339. package/dist/cli/backend/src/services/knowledge/fts5-index.service.js.map +1 -1
  340. package/dist/cli/backend/src/services/knowledge/knowledge-search.service.d.ts +49 -13
  341. package/dist/cli/backend/src/services/knowledge/knowledge-search.service.d.ts.map +1 -1
  342. package/dist/cli/backend/src/services/knowledge/knowledge-search.service.js +123 -29
  343. package/dist/cli/backend/src/services/knowledge/knowledge-search.service.js.map +1 -1
  344. package/dist/cli/backend/src/services/knowledge/vector-store.service.d.ts.map +1 -1
  345. package/dist/cli/backend/src/services/knowledge/vector-store.service.js +24 -4
  346. package/dist/cli/backend/src/services/knowledge/vector-store.service.js.map +1 -1
  347. package/dist/cli/backend/src/types/index.d.ts +22 -1
  348. package/dist/cli/backend/src/types/index.d.ts.map +1 -1
  349. package/dist/cli/backend/src/types/index.js.map +1 -1
  350. package/dist/cli/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  351. package/dist/cli/backend/src/types/v2/work-item.types.js +25 -1
  352. package/dist/cli/backend/src/types/v2/work-item.types.js.map +1 -1
  353. package/frontend/dist/assets/{index-70356616.js → index-7a4e7df5.js} +328 -326
  354. package/frontend/dist/assets/index-b7e59b2b.css +33 -0
  355. package/frontend/dist/index.html +2 -2
  356. package/package.json +2 -1
  357. package/config/skills/orchestrator/recall/SKILL.md +0 -47
  358. package/config/skills/orchestrator/recall/execute.sh +0 -13
  359. package/config/skills/orchestrator/record-learning/SKILL.md +0 -47
  360. package/config/skills/orchestrator/record-learning/execute.sh +0 -13
  361. package/config/skills/orchestrator/remember/SKILL.md +0 -55
  362. package/config/skills/orchestrator/remember/execute.sh +0 -15
  363. package/frontend/dist/assets/index-6aaa0630.css +0 -33
@@ -0,0 +1,482 @@
1
+ #!/usr/bin/env bash
2
+ # Co-located test for remote-browser skill — covers the per-tab dispatch
3
+ # wiring added for the Crewly-in-Chrome concurrent-agent fix.
4
+ #
5
+ # Strategy: spin up a tiny Python HTTP stub on a free port, point the
6
+ # skill at it via CREWLY_API_URL, then drive scenarios. The stub records
7
+ # every request (method + path + body + headers) into a JSON log so we
8
+ # can assert exact wire shape — same pattern used by chat-v2 skill tests.
9
+ #
10
+ # Each scenario gets its own runtime dir under a per-run TMPDIR so cache
11
+ # state from one case never leaks into the next.
12
+
13
+ set -euo pipefail
14
+
15
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16
+ SKILL="${SCRIPT_DIR}/execute.sh"
17
+
18
+ # ---------------------------------------------------------------------------
19
+ # Stub HTTP server (Python). Logs every request to $LOG_FILE as JSONL,
20
+ # returns canned responses controlled by $RESPONSE_FILE (each line = one
21
+ # JSON response, consumed in order; empty line = use default).
22
+ # ---------------------------------------------------------------------------
23
+
24
+ start_stub_server() {
25
+ local port="$1" log_file="$2" responses_file="$3"
26
+ # CRITICAL: redirect python's stdio to /dev/null. Without this the surrounding
27
+ # `STUB_PID=$(start_stub_server ...)` $() subshell waits for python's stdout
28
+ # to close — and python never closes it — causing the test to hang on
29
+ # scenario startup. We don't need the python's chatter, only its pid.
30
+ PORT=$port LOG_FILE=$log_file RESPONSES=$responses_file \
31
+ python3 -c '
32
+ import http.server, json, os, threading, time, sys
33
+
34
+ LOG = os.environ["LOG_FILE"]
35
+ RESP = os.environ["RESPONSES"]
36
+ PORT = int(os.environ["PORT"])
37
+
38
+ # Load all canned responses up front.
39
+ with open(RESP) as f:
40
+ canned = [line.rstrip("\n") for line in f]
41
+ counter = {"i": 0}
42
+
43
+ class Handler(http.server.BaseHTTPRequestHandler):
44
+ def _read_body(self):
45
+ n = int(self.headers.get("Content-Length") or 0)
46
+ return self.rfile.read(n).decode("utf-8") if n else ""
47
+
48
+ def _log(self, body):
49
+ entry = {
50
+ "method": self.command,
51
+ "path": self.path,
52
+ "body": body,
53
+ "headers": {k: v for k, v in self.headers.items()},
54
+ }
55
+ with open(LOG, "a") as f:
56
+ f.write(json.dumps(entry) + "\n")
57
+
58
+ def _next_response(self):
59
+ # Skip ambient infra paths from the queued-response slot — `_common/lib.sh`
60
+ # auto-fires `/api/heartbeat` on every skill startup, which would burn the
61
+ # first canned response otherwise.
62
+ if self.path.startswith("/api/heartbeat"):
63
+ return json.dumps({"success": True})
64
+ i = counter["i"]
65
+ counter["i"] += 1
66
+ if i < len(canned) and canned[i]:
67
+ return canned[i]
68
+ return json.dumps({"success": True, "data": {}})
69
+
70
+ def _is_assertable(self):
71
+ """True if this request should be visible in the request_field log
72
+ (i.e. not an ambient heartbeat)."""
73
+ return not self.path.startswith("/api/heartbeat")
74
+
75
+ def _serve(self, body):
76
+ if self._is_assertable():
77
+ self._log(body)
78
+ raw = self._next_response()
79
+ # raw format: "<status>|<json-body>" (status is optional, default 200)
80
+ if "|" in raw:
81
+ status_str, payload = raw.split("|", 1)
82
+ status = int(status_str)
83
+ else:
84
+ status = 200
85
+ payload = raw
86
+ self.send_response(status)
87
+ self.send_header("Content-Type", "application/json")
88
+ self.send_header("Content-Length", str(len(payload)))
89
+ self.end_headers()
90
+ self.wfile.write(payload.encode("utf-8"))
91
+
92
+ def log_message(self, fmt, *args): # silence default access log
93
+ return
94
+
95
+ def do_GET(self):
96
+ self._serve("")
97
+
98
+ def do_POST(self):
99
+ self._serve(self._read_body())
100
+
101
+ server = http.server.ThreadingHTTPServer(("127.0.0.1", PORT), Handler)
102
+ # Daemonize so SIGTERM cleanly kills it.
103
+ threading.Thread(target=server.serve_forever, daemon=True).start()
104
+ print(f"stub listening on :{PORT}", flush=True)
105
+ # Block forever — parent will SIGKILL.
106
+ while True:
107
+ time.sleep(60)
108
+ ' >/dev/null 2>&1 &
109
+ echo $!
110
+ }
111
+
112
+ # Pick a free TCP port on 127.0.0.1
113
+ free_port() {
114
+ python3 -c 'import socket; s=socket.socket(); s.bind(("127.0.0.1",0)); print(s.getsockname()[1]); s.close()'
115
+ }
116
+
117
+ # ---------------------------------------------------------------------------
118
+ # Test harness — minimal pass/fail printer
119
+ # ---------------------------------------------------------------------------
120
+
121
+ PASS_COUNT=0
122
+ FAIL_COUNT=0
123
+
124
+ pass() {
125
+ PASS_COUNT=$((PASS_COUNT + 1))
126
+ printf ' \033[32m✓\033[0m %s\n' "$1"
127
+ }
128
+ fail() {
129
+ FAIL_COUNT=$((FAIL_COUNT + 1))
130
+ printf ' \033[31m✗\033[0m %s\n' "$1"
131
+ [ -n "${2:-}" ] && printf ' %s\n' "$2"
132
+ }
133
+
134
+ assert_eq() {
135
+ local label="$1" expected="$2" actual="$3"
136
+ if [ "$expected" = "$actual" ]; then
137
+ pass "$label"
138
+ else
139
+ fail "$label" "expected=$expected actual=$actual"
140
+ fi
141
+ }
142
+
143
+ assert_contains() {
144
+ local label="$1" haystack="$2" needle="$3"
145
+ if printf '%s' "$haystack" | grep -qF "$needle"; then
146
+ pass "$label"
147
+ else
148
+ fail "$label" "needle=$needle haystack=$haystack"
149
+ fi
150
+ }
151
+
152
+ # ---------------------------------------------------------------------------
153
+ # Per-scenario fixture: fresh stub + fresh runtime dir
154
+ # ---------------------------------------------------------------------------
155
+
156
+ scenario_init() {
157
+ local name="$1"
158
+ echo
159
+ echo "=== $name ==="
160
+ PORT=$(free_port)
161
+ WORK_DIR=$(mktemp -d -t remote-browser-test.XXXXXX)
162
+ LOG_FILE="${WORK_DIR}/requests.jsonl"
163
+ RESP_FILE="${WORK_DIR}/responses.txt"
164
+ RUNTIME_DIR="${WORK_DIR}/runtime"
165
+ : > "$LOG_FILE"
166
+ : > "$RESP_FILE"
167
+ mkdir -p "$RUNTIME_DIR"
168
+ export CREWLY_API_URL="http://127.0.0.1:${PORT}"
169
+ export CREWLY_RUNTIME_DIR="$RUNTIME_DIR"
170
+ }
171
+
172
+ # Push a canned response onto the stub queue.
173
+ queue_response() {
174
+ printf '%s\n' "$1" >> "$RESP_FILE"
175
+ }
176
+
177
+ start_stub() {
178
+ STUB_PID=$(start_stub_server "$PORT" "$LOG_FILE" "$RESP_FILE")
179
+ # Wait for the server to be ready (poll the port).
180
+ local tries=0
181
+ until python3 -c "import socket; s=socket.socket(); s.settimeout(0.2); s.connect(('127.0.0.1', $PORT))" 2>/dev/null; do
182
+ tries=$((tries + 1))
183
+ if [ $tries -gt 50 ]; then
184
+ fail "stub server failed to start within 5s"
185
+ return 1
186
+ fi
187
+ sleep 0.1
188
+ done
189
+ }
190
+
191
+ scenario_teardown() {
192
+ if [ -n "${STUB_PID:-}" ]; then
193
+ kill "$STUB_PID" 2>/dev/null || true
194
+ wait "$STUB_PID" 2>/dev/null || true
195
+ fi
196
+ if [ -n "${WORK_DIR:-}" ] && [ -d "$WORK_DIR" ]; then
197
+ rm -rf "$WORK_DIR"
198
+ fi
199
+ unset CREWLY_API_URL CREWLY_RUNTIME_DIR CREWLY_SESSION_NAME STUB_PID WORK_DIR PORT
200
+ unset LOG_FILE RESP_FILE RUNTIME_DIR
201
+ }
202
+
203
+ # Read a logged request — `nth` is 0-indexed.
204
+ request_field() {
205
+ local nth="$1" field="$2"
206
+ python3 -c "
207
+ import json, sys
208
+ with open('${LOG_FILE}') as f:
209
+ lines = [json.loads(l) for l in f if l.strip()]
210
+ idx = int('${nth}')
211
+ if idx >= len(lines):
212
+ sys.exit(0)
213
+ entry = lines[idx]
214
+ keys = '${field}'.split('.')
215
+ v = entry
216
+ for k in keys:
217
+ if isinstance(v, dict):
218
+ v = v.get(k)
219
+ else:
220
+ v = None
221
+ break
222
+ if v is None:
223
+ print('', end='')
224
+ else:
225
+ print(v if isinstance(v, str) else json.dumps(v), end='')
226
+ "
227
+ }
228
+
229
+ # ---------------------------------------------------------------------------
230
+ # Scenarios
231
+ # ---------------------------------------------------------------------------
232
+
233
+ # Scenario 1: bind-tab caches tabId locally
234
+ scenario_init "scenario 1: bind-tab caches tabId"
235
+ queue_response '{"success":true,"data":{"tabId":42,"windowId":9}}'
236
+ start_stub
237
+ export CREWLY_SESSION_NAME="agent-1"
238
+ out=$("$SKILL" --action bind-tab 2>&1) || true
239
+ assert_contains "bind-tab response carries tabId" "$out" '"tabId":42'
240
+ assert_eq "stub got POST /api/browser/bind" "POST /api/browser/bind" "$(request_field 0 method) $(request_field 0 path)"
241
+ assert_eq "X-Agent-Session forwarded" "agent-1" "$(request_field 0 headers.X-Agent-Session)"
242
+ [ -f "${RUNTIME_DIR}/agent-1/browser-tab-id" ] \
243
+ && pass "cache file written" \
244
+ || fail "cache file written" "missing ${RUNTIME_DIR}/agent-1/browser-tab-id"
245
+ assert_eq "cache content = tabId" "42" "$(cat ${RUNTIME_DIR}/agent-1/browser-tab-id 2>/dev/null)"
246
+ scenario_teardown
247
+
248
+ # Scenario 2: subsequent action injects cached tabId into body
249
+ scenario_init "scenario 2: cached tabId injected into body"
250
+ mkdir -p "${RUNTIME_DIR}/agent-2"
251
+ echo "77" > "${RUNTIME_DIR}/agent-2/browser-tab-id"
252
+ queue_response '{"success":true,"data":{"text":"hello"}}'
253
+ start_stub
254
+ export CREWLY_SESSION_NAME="agent-2"
255
+ "$SKILL" --action read-text > /dev/null 2>&1 || true
256
+ body=$(request_field 0 body)
257
+ assert_contains "read-text body contains tabId:77" "$body" '"tabId":77'
258
+ scenario_teardown
259
+
260
+ # Scenario 3: --tab-id flag overrides cache
261
+ scenario_init "scenario 3: --tab-id flag overrides cache"
262
+ mkdir -p "${RUNTIME_DIR}/agent-3"
263
+ echo "55" > "${RUNTIME_DIR}/agent-3/browser-tab-id"
264
+ queue_response '{"success":true,"data":{}}'
265
+ start_stub
266
+ export CREWLY_SESSION_NAME="agent-3"
267
+ "$SKILL" --action read-text --tab-id 999 > /dev/null 2>&1 || true
268
+ body=$(request_field 0 body)
269
+ assert_contains "body uses --tab-id override" "$body" '"tabId":999'
270
+ scenario_teardown
271
+
272
+ # Scenario 4: --no-bind drops X-Agent-Session header
273
+ scenario_init "scenario 4: --no-bind drops session header"
274
+ queue_response '{"success":true,"data":{}}'
275
+ start_stub
276
+ export CREWLY_SESSION_NAME="agent-4"
277
+ "$SKILL" --action read-text --no-bind > /dev/null 2>&1 || true
278
+ hdr=$(request_field 0 headers.X-Agent-Session)
279
+ assert_eq "no X-Agent-Session header on --no-bind" "" "$hdr"
280
+ scenario_teardown
281
+
282
+ # Scenario 5: unbind-tab purges cache
283
+ scenario_init "scenario 5: unbind-tab purges cache"
284
+ mkdir -p "${RUNTIME_DIR}/agent-5"
285
+ echo "33" > "${RUNTIME_DIR}/agent-5/browser-tab-id"
286
+ queue_response '{"success":true,"data":{"released":true,"tabClosed":true}}'
287
+ start_stub
288
+ export CREWLY_SESSION_NAME="agent-5"
289
+ "$SKILL" --action unbind-tab > /dev/null 2>&1 || true
290
+ [ -f "${RUNTIME_DIR}/agent-5/browser-tab-id" ] \
291
+ && fail "cache should be purged" "still present at ${RUNTIME_DIR}/agent-5/browser-tab-id" \
292
+ || pass "cache file purged"
293
+ scenario_teardown
294
+
295
+ # Scenario 6: 404 tab_not_found triggers cache purge + auto-retry
296
+ scenario_init "scenario 6: 404 tab_not_found triggers retry"
297
+ mkdir -p "${RUNTIME_DIR}/agent-6"
298
+ echo "100" > "${RUNTIME_DIR}/agent-6/browser-tab-id"
299
+ # First call: 404 with tab_not_found body
300
+ queue_response '404|{"success":false,"error":"tab_not_found","details":"Tab 100 closed"}'
301
+ # Second call (retry without tabId): success
302
+ queue_response '{"success":true,"data":{"text":"recovered"}}'
303
+ start_stub
304
+ export CREWLY_SESSION_NAME="agent-6"
305
+ out=$("$SKILL" --action read-text 2>&1) || true
306
+ # Two requests should have been made.
307
+ total_reqs=$(wc -l < "$LOG_FILE")
308
+ assert_eq "stub received 2 requests" "2" "$(printf '%s' "$total_reqs" | tr -d ' ')"
309
+ # First request had tabId:100, second omits tabId (auto-bind path)
310
+ first_body=$(request_field 0 body)
311
+ second_body=$(request_field 1 body)
312
+ assert_contains "first request had stale tabId:100" "$first_body" '"tabId":100'
313
+ [ -z "$(printf '%s' "$second_body" | grep -o '"tabId"' || true)" ] \
314
+ && pass "retry request omitted tabId (auto-bind path)" \
315
+ || fail "retry request omitted tabId" "second_body=$second_body"
316
+ [ -f "${RUNTIME_DIR}/agent-6/browser-tab-id" ] \
317
+ && fail "cache purged on 404" "still present" \
318
+ || pass "cache purged on 404"
319
+ scenario_teardown
320
+
321
+ # Scenario 7: bind-tab with --active sends active:true
322
+ scenario_init "scenario 7: bind-tab --active forwards foreground flag"
323
+ queue_response '{"success":true,"data":{"tabId":7}}'
324
+ start_stub
325
+ export CREWLY_SESSION_NAME="agent-7"
326
+ "$SKILL" --action bind-tab --active > /dev/null 2>&1 || true
327
+ body=$(request_field 0 body)
328
+ assert_contains "body contains active:true" "$body" '"active":true'
329
+ scenario_teardown
330
+
331
+ # Scenario 8: no CREWLY_SESSION_NAME — no cache, no tabId, legacy fallback
332
+ scenario_init "scenario 8: missing CREWLY_SESSION_NAME → legacy active-tab path"
333
+ queue_response '{"success":true,"data":{}}'
334
+ start_stub
335
+ unset CREWLY_SESSION_NAME
336
+ "$SKILL" --action read-text > /dev/null 2>&1 || true
337
+ hdr=$(request_field 0 headers.X-Agent-Session)
338
+ body=$(request_field 0 body)
339
+ assert_eq "no X-Agent-Session header" "" "$hdr"
340
+ [ -z "$(printf '%s' "$body" | grep -o '"tabId"' || true)" ] \
341
+ && pass "body has no tabId field" \
342
+ || fail "body has no tabId field" "body=$body"
343
+ scenario_teardown
344
+
345
+ # ---------------------------------------------------------------------------
346
+ # Scenarios 9–13: brace-injection bug regression coverage
347
+ #
348
+ # Repro: `BODY="${EXTRA_PARAMS:-{}}"` was mis-parsed by bash — the closing
349
+ # `}` of the parameter expansion was the FIRST `}`, so `${EXTRA_PARAMS:-{}}`
350
+ # was read as `${EXTRA_PARAMS:-{}` (default = literal `{`) followed by a
351
+ # stray literal `}`. With EXTRA_PARAMS set, body became `<value>}` —
352
+ # malformed JSON. With EXTRA_PARAMS empty, the bug coincidentally produced
353
+ # `{}` and masked itself. Fix replaces the pattern with `_body_or_empty`.
354
+ #
355
+ # These scenarios drive --params with a non-empty value through every
356
+ # affected action and assert the wire body is parseable JSON without a
357
+ # trailing stray `}`. Each action is a separate scenario so a regression
358
+ # in one branch does not mask another.
359
+ # ---------------------------------------------------------------------------
360
+
361
+ # Helper for the brace-bug regression scenarios — drives one action with
362
+ # a known payload and asserts the body is exactly that payload (no stray
363
+ # trailing `}`).
364
+ _assert_brace_clean() {
365
+ local action="$1" payload="$2"
366
+ scenario_init "scenario brace-clean: $action --params"
367
+ queue_response '{"success":true,"data":{}}'
368
+ start_stub
369
+ unset CREWLY_SESSION_NAME
370
+ "$SKILL" --action "$action" --params "$payload" > /dev/null 2>&1 || true
371
+ local body
372
+ body=$(request_field 0 body)
373
+ # Body must parse cleanly as JSON (the bug appended a literal `}`).
374
+ if printf '%s' "$body" | jq -e . >/dev/null 2>&1; then
375
+ pass "[$action] body parses as JSON"
376
+ else
377
+ fail "[$action] body parses as JSON" "body=$body"
378
+ fi
379
+ # Body must equal the payload byte-for-byte (no trailing extra char).
380
+ assert_eq "[$action] body == payload" "$payload" "$body"
381
+ scenario_teardown
382
+ }
383
+
384
+ # Scenario 9: scroll
385
+ _assert_brace_clean "scroll" '{"direction":"down","amount":500}'
386
+ # Scenario 10: scroll-in-element
387
+ _assert_brace_clean "scroll-in-element" '{"selector":".sb","amount":200}'
388
+ # Scenario 11: press-key
389
+ _assert_brace_clean "press-key" '{"key":"Enter","modifiers":["Shift"]}'
390
+ # Scenario 12: local-storage
391
+ _assert_brace_clean "local-storage" '{"keys":["uid","theme"]}'
392
+ # Scenario 13: get-interactive-elements
393
+ _assert_brace_clean "get-interactive-elements" '{"textContains":"Submit"}'
394
+ # Scenario 14: set-file-input (was missing from Olivias original list)
395
+ _assert_brace_clean "set-file-input" '{"selector":"input","filePaths":["/tmp/a"]}'
396
+
397
+ # Scenario 15: empty --params still produces a valid `{}` body
398
+ scenario_init "scenario 15: empty --params produces {} (back-compat)"
399
+ queue_response '{"success":true,"data":{}}'
400
+ start_stub
401
+ unset CREWLY_SESSION_NAME
402
+ "$SKILL" --action scroll > /dev/null 2>&1 || true
403
+ body=$(request_field 0 body)
404
+ assert_eq "empty params → body is canonical {}" "{}" "$body"
405
+ scenario_teardown
406
+
407
+ # ---------------------------------------------------------------------------
408
+ # Scenarios 16–18: select-option route + body shapes
409
+ # ---------------------------------------------------------------------------
410
+
411
+ # Scenario 16: select-option with --value projects {selector, value}
412
+ scenario_init "scenario 16: select-option --selector --value"
413
+ queue_response '{"success":true,"data":{"selectedValue":"opt2","selectedText":"Option 2"}}'
414
+ start_stub
415
+ unset CREWLY_SESSION_NAME
416
+ "$SKILL" --action select-option --selector "#level" --value "opt2" > /dev/null 2>&1 || true
417
+ assert_eq "POST /api/browser/select-option" \
418
+ "POST /api/browser/select-option" \
419
+ "$(request_field 0 method) $(request_field 0 path)"
420
+ body=$(request_field 0 body)
421
+ assert_eq "body has selector" "#level" "$(printf '%s' "$body" | jq -r '.selector')"
422
+ assert_eq "body has value" "opt2" "$(printf '%s' "$body" | jq -r '.value')"
423
+ scenario_teardown
424
+
425
+ # Scenario 17: select-option with --params (label-based)
426
+ scenario_init "scenario 17: select-option --params with label"
427
+ queue_response '{"success":true,"data":{}}'
428
+ start_stub
429
+ unset CREWLY_SESSION_NAME
430
+ "$SKILL" --action select-option --selector "#level" \
431
+ --params '{"label":"Beginner"}' > /dev/null 2>&1 || true
432
+ body=$(request_field 0 body)
433
+ assert_eq "body has selector merged from --selector" "#level" \
434
+ "$(printf '%s' "$body" | jq -r '.selector')"
435
+ assert_eq "body has label from --params" "Beginner" \
436
+ "$(printf '%s' "$body" | jq -r '.label')"
437
+ # Must be parseable JSON (regression guard against the brace bug since
438
+ # this path also uses EXTRA_PARAMS in a jq pipeline).
439
+ if printf '%s' "$body" | jq -e . >/dev/null 2>&1; then
440
+ pass "select-option --params body parses as JSON"
441
+ else
442
+ fail "select-option --params body parses as JSON" "body=$body"
443
+ fi
444
+ scenario_teardown
445
+
446
+ # Scenario 18: select-option with --params (index-based)
447
+ scenario_init "scenario 18: select-option --params with index"
448
+ queue_response '{"success":true,"data":{}}'
449
+ start_stub
450
+ unset CREWLY_SESSION_NAME
451
+ "$SKILL" --action select-option --selector "#level" \
452
+ --params '{"index":2}' > /dev/null 2>&1 || true
453
+ body=$(request_field 0 body)
454
+ assert_eq "body has index from --params" "2" \
455
+ "$(printf '%s' "$body" | jq -r '.index')"
456
+ scenario_teardown
457
+
458
+ # Scenario 19: select-option missing --value AND --params errors out
459
+ scenario_init "scenario 19: select-option without value or params errors"
460
+ queue_response '{"success":true,"data":{}}'
461
+ start_stub
462
+ unset CREWLY_SESSION_NAME
463
+ out=$("$SKILL" --action select-option --selector "#level" 2>&1) || true
464
+ assert_contains "error message mentions value/params requirement" "$out" \
465
+ "select-option requires"
466
+ # Stub should NOT have received any request (hard-fail before HTTP).
467
+ total_reqs=$(wc -l < "$LOG_FILE" | tr -d ' ')
468
+ assert_eq "stub received 0 requests" "0" "$total_reqs"
469
+ scenario_teardown
470
+
471
+ # ---------------------------------------------------------------------------
472
+ # Summary
473
+ # ---------------------------------------------------------------------------
474
+ echo
475
+ TOTAL=$((PASS_COUNT + FAIL_COUNT))
476
+ if [ "$FAIL_COUNT" -gt 0 ]; then
477
+ printf '\033[31mFAIL\033[0m %d/%d passed (%d failed)\n' "$PASS_COUNT" "$TOTAL" "$FAIL_COUNT"
478
+ exit 1
479
+ else
480
+ printf '\033[32mOK\033[0m %d/%d passed\n' "$PASS_COUNT" "$TOTAL"
481
+ exit 0
482
+ fi
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: Send Message
3
- description: "Send a text message to an agent's terminal session."
4
- version: 1.0.0
3
+ description: "Readiness-aware message delivery to an agent's terminal session via /terminal/{session}/deliver. Distinct from agent/core/send-message which uses /terminal/{session}/write."
4
+ version: 1.1.0
5
5
  category: communication
6
6
  skillType: claude-skill
7
7
  assignableRoles:
@@ -10,10 +10,12 @@ triggers:
10
10
  - send message
11
11
  - tell agent
12
12
  - message agent
13
+ - deliver message
13
14
  tags:
14
15
  - communication
15
16
  - agent
16
17
  - message
18
+ - readiness-aware
17
19
  execution:
18
20
  type: script
19
21
  script:
@@ -22,14 +24,34 @@ execution:
22
24
  timeoutMs: 30000
23
25
  ---
24
26
 
25
- # Send Message
27
+ # Send Message (orchestrator — readiness-aware delivery)
26
28
 
27
- Sends a text message to an agent's terminal session.
29
+ Delivers a text message to an agent's terminal session via the
30
+ **`POST /terminal/{session}/deliver`** endpoint.
31
+
32
+ ## When to use this vs `agent/core/send-message`
33
+
34
+ | | `orchestrator/send-message` | `agent/core/send-message` |
35
+ |---|---|---|
36
+ | Endpoint | `POST /terminal/{id}/deliver` | `POST /terminal/{id}/write` |
37
+ | Readiness gate | Yes — waits up to `waitTimeout` ms (default 120 s) for the agent prompt | No — direct PTY write, fires immediately |
38
+ | Force override | Yes — `force: true` skips the readiness wait | n/a |
39
+ | Typical caller | Orchestrator dispatching new work to an agent that may currently be busy | Any agent that just wants to drop a line into another session's PTY |
40
+
41
+ Prefer this skill when the orchestrator needs the message to land **at**
42
+ the agent's prompt rather than mid-token. Use `agent/core/send-message`
43
+ for fire-and-forget cross-agent comms.
28
44
 
29
45
  ## Usage
30
46
 
31
47
  ```bash
32
- bash config/skills/orchestrator/send-message/execute.sh '{"sessionName":"agent-joe","message":"Please review the PR"}'
48
+ # Default: wait up to 120 s for the agent to be ready, then deliver
49
+ bash config/skills/orchestrator/send-message/execute.sh \
50
+ '{"sessionName":"agent-joe","message":"Please review the PR"}'
51
+
52
+ # Force: write immediately even if the agent is busy mid-token
53
+ bash config/skills/orchestrator/send-message/execute.sh \
54
+ '{"sessionName":"agent-joe","message":"URGENT: stop","force":true}'
33
55
  ```
34
56
 
35
57
  ## Parameters
@@ -37,8 +59,9 @@ bash config/skills/orchestrator/send-message/execute.sh '{"sessionName":"agent-j
37
59
  | Parameter | Required | Description |
38
60
  |-----------|----------|-------------|
39
61
  | `sessionName` | Yes | The target agent's PTY session name |
40
- | `message` | Yes | The message text to send |
62
+ | `message` | Yes | The message text to deliver |
63
+ | `force` | No | When `true`, write directly to PTY without waiting for the agent prompt. Defaults to `false` (wait for ready). |
41
64
 
42
65
  ## Output
43
66
 
44
- JSON confirmation of delivery.
67
+ JSON confirmation of delivery from the deliver endpoint.
@@ -0,0 +1,98 @@
1
+ ---
2
+ name: Team Health Scan
3
+ description: On-demand snapshot of the Team-Health-Watchdog (THW) verdicts. Returns per-team health (🟢/🟡/🔴/🚨/🟪) plus the gates that fired, so an operator can investigate before the next 60s sweep.
4
+ version: 1.0.0
5
+ category: monitoring
6
+ skillType: claude-skill
7
+ assignableRoles:
8
+ - orchestrator
9
+ triggers:
10
+ - team health
11
+ - health scan
12
+ - is anything stuck
13
+ - team-health-scan
14
+ tags:
15
+ - team-health
16
+ - watchdog
17
+ - monitoring
18
+ - liveness
19
+ execution:
20
+ type: script
21
+ script:
22
+ file: execute.sh
23
+ interpreter: bash
24
+ timeoutMs: 30000
25
+ ---
26
+
27
+ # Team Health Scan
28
+
29
+ Returns the current per-team health verdicts from the Team-Health-Watchdog (THW), the system-level liveness aggregator (Layer 4 of the four-layer liveness stack).
30
+
31
+ ## When to use
32
+
33
+ - Before EOD: "is anything stuck I should know about?"
34
+ - After a Slack alert: "you flagged Marketing 🔴; show me the gates."
35
+ - During shadow-mode review: inspect candidate detections without waiting for the next sweep.
36
+
37
+ ## Verdict tiers
38
+
39
+ | Code | Display | Meaning |
40
+ |---|---|---|
41
+ | `healthy` | 🟢 | No concerning signals |
42
+ | `stalling` | 🟡 | Soft concern; observation-only |
43
+ | `stuck` | 🔴 | Sharp concern; action expected |
44
+ | `cascade` | 🚨 | Multi-team correlated failure |
45
+ | `stale` | 🟪 | Stale-trigger refire — assignee should confirm/cancel |
46
+
47
+ ## Usage
48
+
49
+ ```bash
50
+ # All teams:
51
+ bash execute.sh '{}'
52
+
53
+ # One team:
54
+ bash execute.sh '{"teamId":"marketing"}'
55
+
56
+ # Force a fresh sweep (bypass the 60s cache):
57
+ bash execute.sh '{"force":true}'
58
+ ```
59
+
60
+ ## Response shape
61
+
62
+ ```jsonc
63
+ {
64
+ "success": true,
65
+ "data": {
66
+ "verdicts": [
67
+ {
68
+ "teamId": "marketing",
69
+ "verdict": "stuck",
70
+ "gates": {
71
+ "team_idle": true,
72
+ "team_pending": true,
73
+ "team_silent": true,
74
+ "cascade_with_siblings": false
75
+ },
76
+ "pendingWorkItemIds": ["wi-1", "wi-2"],
77
+ "idleAgentSessions": ["ella", "grace"],
78
+ "lostDispatchWorkItemIds": [],
79
+ "rationale": "Team has 2 pending WorkItem(s); 2 member(s) idle and no trigger has fired recently.",
80
+ "detectedAt": "2026-04-25T19:30:00.000Z"
81
+ }
82
+ ],
83
+ "lastSweep": {
84
+ "sweptAt": "2026-04-25T19:30:00.000Z",
85
+ "durationMs": 7,
86
+ "shadowMode": true
87
+ },
88
+ "lastSweepAgeMs": 1234,
89
+ "degraded": false
90
+ }
91
+ }
92
+ ```
93
+
94
+ `degraded: true` indicates the watchdog itself has stopped sweeping (last sweep > 3× sweep interval). Investigate the backend `/api/health` endpoint.
95
+
96
+ ## Layer-4 invariant
97
+
98
+ This skill is **read-only**. THW does NOT change agent status, claims, or work items — it only emits alerts. To act on a verdict, use the relevant skill (`start-agent` to restart a member, `assign-task` to reassign, etc.).