crewly 1.6.5 → 1.7.0

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 (267) hide show
  1. package/config/roles/auditor/prompt.md +24 -0
  2. package/config/roles/developer/prompt.md +2 -1
  3. package/config/roles/orchestrator/prompt.md +74 -2
  4. package/config/roles/team-leader/prompt.md +6 -0
  5. package/config/skills/agent/core/create-request/SKILL.md +1 -1
  6. package/config/skills/agent/core/create-request/execute.sh +29 -2
  7. package/config/skills/agent/core/create-request/execute.test.sh +168 -0
  8. package/config/skills/agent/core/report-status/SKILL.md +8 -1
  9. package/config/skills/agent/core/report-status/execute.sh +23 -1
  10. package/config/skills/orchestrator/heartbeat/execute.sh +48 -6
  11. package/config/sops/common/mid-flight-milestone-surface.md +128 -0
  12. package/config/sops/common/owner-facing-communication.md +46 -2
  13. package/config/sops/developer/git-workflow.md +33 -0
  14. package/dist/backend/backend/src/constants.d.ts +12 -0
  15. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  16. package/dist/backend/backend/src/constants.js +12 -0
  17. package/dist/backend/backend/src/constants.js.map +1 -1
  18. package/dist/backend/backend/src/controllers/browser/browser.controller.js +2 -2
  19. package/dist/backend/backend/src/controllers/browser/browser.controller.js.map +1 -1
  20. package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts.map +1 -1
  21. package/dist/backend/backend/src/controllers/chat/chat.controller.js +6 -0
  22. package/dist/backend/backend/src/controllers/chat/chat.controller.js.map +1 -1
  23. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.d.ts +73 -0
  24. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.d.ts.map +1 -1
  25. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.js +128 -0
  26. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.js.map +1 -1
  27. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.d.ts +3 -0
  28. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.d.ts.map +1 -1
  29. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.js +8 -0
  30. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.routes.js.map +1 -1
  31. package/dist/backend/backend/src/controllers/session/session.controller.d.ts.map +1 -1
  32. package/dist/backend/backend/src/controllers/session/session.controller.js +50 -8
  33. package/dist/backend/backend/src/controllers/session/session.controller.js.map +1 -1
  34. package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts.map +1 -1
  35. package/dist/backend/backend/src/controllers/slack/slack.controller.js +215 -94
  36. package/dist/backend/backend/src/controllers/slack/slack.controller.js.map +1 -1
  37. package/dist/backend/backend/src/index.d.ts +1 -0
  38. package/dist/backend/backend/src/index.d.ts.map +1 -1
  39. package/dist/backend/backend/src/index.js +185 -36
  40. package/dist/backend/backend/src/index.js.map +1 -1
  41. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  42. package/dist/backend/backend/src/routes/api.routes.js +11 -1
  43. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  44. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +42 -0
  45. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  46. package/dist/backend/backend/src/services/agent/agent-registration.service.js +218 -6
  47. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  48. package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.d.ts +61 -1
  49. package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.d.ts.map +1 -1
  50. package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.js +117 -9
  51. package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.js.map +1 -1
  52. package/dist/backend/backend/src/services/agent/idle-detection.service.d.ts +33 -0
  53. package/dist/backend/backend/src/services/agent/idle-detection.service.d.ts.map +1 -1
  54. package/dist/backend/backend/src/services/agent/idle-detection.service.js +108 -4
  55. package/dist/backend/backend/src/services/agent/idle-detection.service.js.map +1 -1
  56. package/dist/backend/backend/src/services/browser/browser-proxy.service.d.ts +1 -1
  57. package/dist/backend/backend/src/services/browser/browser-proxy.service.d.ts.map +1 -1
  58. package/dist/backend/backend/src/services/browser/browser-proxy.service.js +40 -2
  59. package/dist/backend/backend/src/services/browser/browser-proxy.service.js.map +1 -1
  60. package/dist/backend/backend/src/services/chat/chat.service.d.ts +48 -331
  61. package/dist/backend/backend/src/services/chat/chat.service.d.ts.map +1 -1
  62. package/dist/backend/backend/src/services/chat/chat.service.js +261 -712
  63. package/dist/backend/backend/src/services/chat/chat.service.js.map +1 -1
  64. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts +82 -1
  65. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
  66. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +120 -2
  67. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
  68. package/dist/backend/backend/src/services/chat-v2/chat-v2.providers.d.ts +114 -0
  69. package/dist/backend/backend/src/services/chat-v2/chat-v2.providers.d.ts.map +1 -0
  70. package/dist/backend/backend/src/services/chat-v2/chat-v2.providers.js +182 -0
  71. package/dist/backend/backend/src/services/chat-v2/chat-v2.providers.js.map +1 -0
  72. package/dist/backend/backend/src/services/chat-v2/chat-v2.relay-adapter.service.d.ts +188 -0
  73. package/dist/backend/backend/src/services/chat-v2/chat-v2.relay-adapter.service.d.ts.map +1 -0
  74. package/dist/backend/backend/src/services/chat-v2/chat-v2.relay-adapter.service.js +434 -0
  75. package/dist/backend/backend/src/services/chat-v2/chat-v2.relay-adapter.service.js.map +1 -0
  76. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts +401 -5
  77. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts.map +1 -1
  78. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js +619 -3
  79. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js.map +1 -1
  80. package/dist/backend/backend/src/services/chat-v2/legacy-dto.utils.d.ts +93 -0
  81. package/dist/backend/backend/src/services/chat-v2/legacy-dto.utils.d.ts.map +1 -0
  82. package/dist/backend/backend/src/services/chat-v2/legacy-dto.utils.js +138 -0
  83. package/dist/backend/backend/src/services/chat-v2/legacy-dto.utils.js.map +1 -0
  84. package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.d.ts +46 -0
  85. package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.d.ts.map +1 -1
  86. package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.js +75 -0
  87. package/dist/backend/backend/src/services/chat-v2/sqlite/channel.store.js.map +1 -1
  88. package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.d.ts +10 -2
  89. package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.d.ts.map +1 -1
  90. package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.js +178 -10
  91. package/dist/backend/backend/src/services/chat-v2/sqlite/chat-db.js.map +1 -1
  92. package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.d.ts +37 -0
  93. package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.d.ts.map +1 -1
  94. package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.js +71 -0
  95. package/dist/backend/backend/src/services/chat-v2/sqlite/message.store.js.map +1 -1
  96. package/dist/backend/backend/src/services/chat-v2/types.d.ts +33 -1
  97. package/dist/backend/backend/src/services/chat-v2/types.d.ts.map +1 -1
  98. package/dist/backend/backend/src/services/chat-v2/types.js +1 -1
  99. package/dist/backend/backend/src/services/chat-v2/types.js.map +1 -1
  100. package/dist/backend/backend/src/services/cloud/cloud-sync.service.d.ts +22 -0
  101. package/dist/backend/backend/src/services/cloud/cloud-sync.service.d.ts.map +1 -1
  102. package/dist/backend/backend/src/services/cloud/cloud-sync.service.js +71 -1
  103. package/dist/backend/backend/src/services/cloud/cloud-sync.service.js.map +1 -1
  104. package/dist/backend/backend/src/services/cloud/cloud-sync.types.d.ts +102 -1
  105. package/dist/backend/backend/src/services/cloud/cloud-sync.types.d.ts.map +1 -1
  106. package/dist/backend/backend/src/services/cloud/cloud-sync.types.js +61 -0
  107. package/dist/backend/backend/src/services/cloud/cloud-sync.types.js.map +1 -1
  108. package/dist/backend/backend/src/services/cloud/device-auto-discovery.service.d.ts +21 -3
  109. package/dist/backend/backend/src/services/cloud/device-auto-discovery.service.d.ts.map +1 -1
  110. package/dist/backend/backend/src/services/cloud/device-auto-discovery.service.js +47 -13
  111. package/dist/backend/backend/src/services/cloud/device-auto-discovery.service.js.map +1 -1
  112. package/dist/backend/backend/src/services/core/system-health.util.d.ts +25 -4
  113. package/dist/backend/backend/src/services/core/system-health.util.d.ts.map +1 -1
  114. package/dist/backend/backend/src/services/core/system-health.util.js +30 -5
  115. package/dist/backend/backend/src/services/core/system-health.util.js.map +1 -1
  116. package/dist/backend/backend/src/services/event-bus/event-bus.service.d.ts.map +1 -1
  117. package/dist/backend/backend/src/services/event-bus/event-bus.service.js +22 -11
  118. package/dist/backend/backend/src/services/event-bus/event-bus.service.js.map +1 -1
  119. package/dist/backend/backend/src/services/memory/memory.service.d.ts.map +1 -1
  120. package/dist/backend/backend/src/services/memory/memory.service.js +35 -3
  121. package/dist/backend/backend/src/services/memory/memory.service.js.map +1 -1
  122. package/dist/backend/backend/src/services/messaging/message-replay.service.d.ts +2 -4
  123. package/dist/backend/backend/src/services/messaging/message-replay.service.d.ts.map +1 -1
  124. package/dist/backend/backend/src/services/messaging/message-replay.service.js +22 -12
  125. package/dist/backend/backend/src/services/messaging/message-replay.service.js.map +1 -1
  126. package/dist/backend/backend/src/services/messaging/queue-processor.service.d.ts.map +1 -1
  127. package/dist/backend/backend/src/services/messaging/queue-processor.service.js +25 -5
  128. package/dist/backend/backend/src/services/messaging/queue-processor.service.js.map +1 -1
  129. package/dist/backend/backend/src/services/monitoring/system-resource-alert.service.d.ts.map +1 -1
  130. package/dist/backend/backend/src/services/monitoring/system-resource-alert.service.js +13 -3
  131. package/dist/backend/backend/src/services/monitoring/system-resource-alert.service.js.map +1 -1
  132. package/dist/backend/backend/src/services/notification/milestone-notification.subscriber.d.ts +99 -0
  133. package/dist/backend/backend/src/services/notification/milestone-notification.subscriber.d.ts.map +1 -0
  134. package/dist/backend/backend/src/services/notification/milestone-notification.subscriber.js +225 -0
  135. package/dist/backend/backend/src/services/notification/milestone-notification.subscriber.js.map +1 -0
  136. package/dist/backend/backend/src/services/reconciler/reconcile-rules.d.ts +39 -18
  137. package/dist/backend/backend/src/services/reconciler/reconcile-rules.d.ts.map +1 -1
  138. package/dist/backend/backend/src/services/reconciler/reconcile-rules.js +60 -32
  139. package/dist/backend/backend/src/services/reconciler/reconcile-rules.js.map +1 -1
  140. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts +134 -0
  141. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts.map +1 -1
  142. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js +416 -13
  143. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js.map +1 -1
  144. package/dist/backend/backend/src/services/reconciler/reconciler.service.d.ts.map +1 -1
  145. package/dist/backend/backend/src/services/reconciler/reconciler.service.js +73 -7
  146. package/dist/backend/backend/src/services/reconciler/reconciler.service.js.map +1 -1
  147. package/dist/backend/backend/src/services/session/session-handoff.service.d.ts.map +1 -1
  148. package/dist/backend/backend/src/services/session/session-handoff.service.js +30 -4
  149. package/dist/backend/backend/src/services/session/session-handoff.service.js.map +1 -1
  150. package/dist/backend/backend/src/services/skill/skill-executor.service.d.ts.map +1 -1
  151. package/dist/backend/backend/src/services/skill/skill-executor.service.js +13 -1
  152. package/dist/backend/backend/src/services/skill/skill-executor.service.js.map +1 -1
  153. package/dist/backend/backend/src/services/slack/notify-reconciliation.service.d.ts.map +1 -1
  154. package/dist/backend/backend/src/services/slack/notify-reconciliation.service.js +9 -6
  155. package/dist/backend/backend/src/services/slack/notify-reconciliation.service.js.map +1 -1
  156. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts +21 -2
  157. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
  158. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js +120 -46
  159. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
  160. package/dist/backend/backend/src/services/slack/slack.service.d.ts.map +1 -1
  161. package/dist/backend/backend/src/services/slack/slack.service.js +49 -0
  162. package/dist/backend/backend/src/services/slack/slack.service.js.map +1 -1
  163. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +33 -2
  164. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  165. package/dist/backend/backend/src/services/task-pool/task-pool.service.js +160 -8
  166. package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  167. package/dist/backend/backend/src/services/v3/cascade-request-status.d.ts.map +1 -1
  168. package/dist/backend/backend/src/services/v3/cascade-request-status.js +55 -2
  169. package/dist/backend/backend/src/services/v3/cascade-request-status.js.map +1 -1
  170. package/dist/backend/backend/src/services/v3/mission-executor.service.d.ts.map +1 -1
  171. package/dist/backend/backend/src/services/v3/mission-executor.service.js +9 -1
  172. package/dist/backend/backend/src/services/v3/mission-executor.service.js.map +1 -1
  173. package/dist/backend/backend/src/services/v3/request-decompose.subscriber.d.ts.map +1 -1
  174. package/dist/backend/backend/src/services/v3/request-decompose.subscriber.js +28 -3
  175. package/dist/backend/backend/src/services/v3/request-decompose.subscriber.js.map +1 -1
  176. package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts.map +1 -1
  177. package/dist/backend/backend/src/services/v3/request-sla.subscriber.js +5 -2
  178. package/dist/backend/backend/src/services/v3/request-sla.subscriber.js.map +1 -1
  179. package/dist/backend/backend/src/services/v3/request-status-update.subscriber.d.ts.map +1 -1
  180. package/dist/backend/backend/src/services/v3/request-status-update.subscriber.js +57 -15
  181. package/dist/backend/backend/src/services/v3/request-status-update.subscriber.js.map +1 -1
  182. package/dist/backend/backend/src/services/v3/trigger-engine.service.d.ts +39 -0
  183. package/dist/backend/backend/src/services/v3/trigger-engine.service.d.ts.map +1 -1
  184. package/dist/backend/backend/src/services/v3/trigger-engine.service.js +81 -0
  185. package/dist/backend/backend/src/services/v3/trigger-engine.service.js.map +1 -1
  186. package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.d.ts +17 -1
  187. package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.d.ts.map +1 -1
  188. package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.js +22 -3
  189. package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.js.map +1 -1
  190. package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.d.ts +1 -1
  191. package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.d.ts.map +1 -1
  192. package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.js +26 -10
  193. package/dist/backend/backend/src/services/whatsapp/whatsapp-orchestrator-bridge.js.map +1 -1
  194. package/dist/backend/backend/src/services/workflow/cron-task.service.d.ts.map +1 -1
  195. package/dist/backend/backend/src/services/workflow/cron-task.service.js +68 -5
  196. package/dist/backend/backend/src/services/workflow/cron-task.service.js.map +1 -1
  197. package/dist/backend/backend/src/services/workflow/team-identifier-resolver.d.ts +44 -0
  198. package/dist/backend/backend/src/services/workflow/team-identifier-resolver.d.ts.map +1 -0
  199. package/dist/backend/backend/src/services/workflow/team-identifier-resolver.js +57 -0
  200. package/dist/backend/backend/src/services/workflow/team-identifier-resolver.js.map +1 -0
  201. package/dist/backend/backend/src/types/credential.types.d.ts +17 -1
  202. package/dist/backend/backend/src/types/credential.types.d.ts.map +1 -1
  203. package/dist/backend/backend/src/types/credential.types.js +15 -5
  204. package/dist/backend/backend/src/types/credential.types.js.map +1 -1
  205. package/dist/backend/backend/src/types/cron-task.types.d.ts +17 -0
  206. package/dist/backend/backend/src/types/cron-task.types.d.ts.map +1 -1
  207. package/dist/backend/backend/src/types/event-bus.types.d.ts +1 -1
  208. package/dist/backend/backend/src/types/event-bus.types.d.ts.map +1 -1
  209. package/dist/backend/backend/src/types/event-bus.types.js +12 -0
  210. package/dist/backend/backend/src/types/event-bus.types.js.map +1 -1
  211. package/dist/backend/backend/src/types/intent-task.types.d.ts +10 -13
  212. package/dist/backend/backend/src/types/intent-task.types.d.ts.map +1 -1
  213. package/dist/backend/backend/src/types/intent-task.types.js +4 -1
  214. package/dist/backend/backend/src/types/intent-task.types.js.map +1 -1
  215. package/dist/backend/backend/src/types/v2/work-item.types.d.ts +23 -0
  216. package/dist/backend/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  217. package/dist/backend/backend/src/types/v2/work-item.types.js.map +1 -1
  218. package/dist/backend/backend/src/utils/team.utils.d.ts +3 -1
  219. package/dist/backend/backend/src/utils/team.utils.d.ts.map +1 -1
  220. package/dist/backend/backend/src/utils/team.utils.js +26 -5
  221. package/dist/backend/backend/src/utils/team.utils.js.map +1 -1
  222. package/dist/backend/backend/src/websocket/chat-v2.gateway.d.ts +23 -0
  223. package/dist/backend/backend/src/websocket/chat-v2.gateway.d.ts.map +1 -1
  224. package/dist/backend/backend/src/websocket/chat-v2.gateway.js +56 -7
  225. package/dist/backend/backend/src/websocket/chat-v2.gateway.js.map +1 -1
  226. package/dist/backend/backend/src/websocket/chat.gateway.d.ts +19 -4
  227. package/dist/backend/backend/src/websocket/chat.gateway.d.ts.map +1 -1
  228. package/dist/backend/backend/src/websocket/chat.gateway.js +78 -63
  229. package/dist/backend/backend/src/websocket/chat.gateway.js.map +1 -1
  230. package/dist/backend/backend/src/websocket/terminal.gateway.d.ts.map +1 -1
  231. package/dist/backend/backend/src/websocket/terminal.gateway.js +10 -2
  232. package/dist/backend/backend/src/websocket/terminal.gateway.js.map +1 -1
  233. package/dist/cli/backend/src/constants.d.ts +12 -0
  234. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  235. package/dist/cli/backend/src/constants.js +12 -0
  236. package/dist/cli/backend/src/constants.js.map +1 -1
  237. package/dist/cli/backend/src/services/event-bus/event-bus.service.d.ts.map +1 -1
  238. package/dist/cli/backend/src/services/event-bus/event-bus.service.js +22 -11
  239. package/dist/cli/backend/src/services/event-bus/event-bus.service.js.map +1 -1
  240. package/dist/cli/backend/src/services/memory/memory.service.d.ts.map +1 -1
  241. package/dist/cli/backend/src/services/memory/memory.service.js +35 -3
  242. package/dist/cli/backend/src/services/memory/memory.service.js.map +1 -1
  243. package/dist/cli/backend/src/services/skill/skill-executor.service.d.ts.map +1 -1
  244. package/dist/cli/backend/src/services/skill/skill-executor.service.js +13 -1
  245. package/dist/cli/backend/src/services/skill/skill-executor.service.js.map +1 -1
  246. package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +33 -2
  247. package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  248. package/dist/cli/backend/src/services/task-pool/task-pool.service.js +160 -8
  249. package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  250. package/dist/cli/backend/src/types/credential.types.d.ts +17 -1
  251. package/dist/cli/backend/src/types/credential.types.d.ts.map +1 -1
  252. package/dist/cli/backend/src/types/credential.types.js +15 -5
  253. package/dist/cli/backend/src/types/credential.types.js.map +1 -1
  254. package/dist/cli/backend/src/types/event-bus.types.d.ts +1 -1
  255. package/dist/cli/backend/src/types/event-bus.types.d.ts.map +1 -1
  256. package/dist/cli/backend/src/types/event-bus.types.js +12 -0
  257. package/dist/cli/backend/src/types/event-bus.types.js.map +1 -1
  258. package/dist/cli/backend/src/types/v2/work-item.types.d.ts +23 -0
  259. package/dist/cli/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  260. package/dist/cli/backend/src/types/v2/work-item.types.js.map +1 -1
  261. package/dist/cli/cli/src/commands/start.js +73 -12
  262. package/dist/cli/cli/src/commands/start.js.map +1 -1
  263. package/frontend/dist/assets/index-b279da34.js +4926 -0
  264. package/frontend/dist/assets/{index-b7e59b2b.css → index-c07e04c0.css} +2 -2
  265. package/frontend/dist/index.html +2 -2
  266. package/package.json +1 -1
  267. package/frontend/dist/assets/index-698305f3.js +0 -5228
@@ -43,6 +43,30 @@ Continuously monitor all active agents, detect problems early, and produce struc
43
43
  - Use `heartbeat` to check overall system status
44
44
  - Detect: API failures, queue backlogs, scheduling issues
45
45
 
46
+ ### 6. Silent Shipping Detection (#437)
47
+
48
+ The auditor's blind spot before issue #432: an agent ships a real
49
+ artifact (PR merged, spec finalized) but never emits a `[MILESTONE]`
50
+ surface upstream. The owner finds out via `git log` 12 hours later —
51
+ exact shape of the 2026-05-04 incident that opened EPIC #426.
52
+
53
+ **How to monitor:**
54
+
55
+ - Cross-reference `git log` (commits in the last 24h) and merged PRs
56
+ against `report-status` / `[MILESTONE]` events from the same window.
57
+ - Flag any agent who authored a merged PR but did NOT emit a
58
+ `[MILESTONE]` surface within 30 minutes of merge.
59
+ - Evidence to capture: PR URL, author session, merge timestamp, the
60
+ most recent `report-status` event for that author (so the gap is
61
+ visible — "last surface at 14:02; PR merged at 17:18; 3h16m gap").
62
+
63
+ **Severity:** **medium** by default — silent shipping indicates a
64
+ system gap, not an agent bug. If the same author silently ships 3+
65
+ times across an audit cycle, escalate to **high**: the structural
66
+ fix (the Mid-Flight Milestone Surface SOP at
67
+ `config/sops/common/mid-flight-milestone-surface.md`) is not landing
68
+ in practice and a prompt/role adjustment is overdue.
69
+
46
70
  ## How You Report
47
71
 
48
72
  When you find a problem, use the `write_audit_report` tool to append it to the audit log.
@@ -160,7 +160,8 @@ When I send you a task:
160
160
  2. **Codebase audit** — Before implementing any feature, search the codebase for existing implementations that overlap with the task. Use `grep`, `find`, and read relevant service files. If the feature (or parts of it) already exists, report back what's already there and propose incremental improvements instead of building from scratch.
161
161
  3. Write clean, tested code following project conventions
162
162
  4. Report blockers and issues promptly
163
- 5. Let me know when done
163
+ 5. **Surface milestones the moment they ship** — see "Mid-Flight Milestone Surface" SOP at `config/sops/common/mid-flight-milestone-surface.md`. When a PR merges / a spec is finalized / a build passes on a non-trivial change, immediately call `report-status` with `status: "milestone"` and a plain-language summary. Do NOT wait for the next outcome-check tick. Issue #427 / EPIC #426 — the system was structurally silent on this path until now.
164
+ 6. Let me know when fully done.
164
165
 
165
166
  **CRITICAL**: Never assume a feature doesn't exist. Always verify by reading the codebase first. Building duplicate code wastes time and creates maintenance burden.
166
167
 
@@ -55,6 +55,18 @@ The owner hired you to deliver results, not to narrate progress or ask permissio
55
55
 
56
56
  **Onboarding exception:** For the first 1-2 interactions with a brand-new owner who hasn't seen how you work, a single onboarding message explaining "I'll run silently unless a deliverable is ready or I'm blocked" is fine. After that, don't repeat.
57
57
 
58
+ **Wall-clock time is NOT a sleep signal (anti-pattern, observed 2026-04 dogfood — #337):**
59
+
60
+ Silent Mode is about *not bothering the owner unnecessarily*. It does NOT mean "go quiet because it's late." The model runs 24/7; agents run 24/7; the owner sets the cadence, not the wall clock. Specifically:
61
+
62
+ - DO NOT add to any dispatch / status message: "wind down for the night", "stand back down", "GN", "sleep mode", "go to bed", "until tomorrow AM", "until 08:00 ET wake", "今晚该睡了", or any variant — unless the owner has *explicitly* said something equivalent to "I'm done for today / pick this up tomorrow / 我去睡了".
63
+ - DO NOT defer real work items to AM by default just because it's 22:00 / 01:00 / etc. Surface the work and execute. If the owner wants to defer, they will say so.
64
+ - DO NOT close out, suspend, or "park" agent sessions based on the local time of day. Agents idle out via their own runtime mechanisms; that's not your call.
65
+ - DO match the owner's observed energy. If owner Slack messages are arriving at 01:00, the team is also working at 01:00. If you're unsure whether they want to defer, **ask** — "Want me to push this now or queue for tomorrow?" — rather than assume.
66
+ - The only valid sleep-mode signal is the owner saying it directly, OR genuine Slack silence ≥ 60 min AFTER an explicit goodnight. Not a clock check.
67
+
68
+ This anti-pattern came from over-stretching the legitimate "respect owner time" guidance into "the owner is probably asleep, so the team should also wind down." Wall-clock projection is not "respect"; it's an unverified assumption that costs the owner an override turn every time. Stop it at source.
69
+
58
70
  ## Periodic Progress Check-In (User Requests)
59
71
 
60
72
  Silent Mode is the default **outside** a user request. **Inside** a user request that is going to take more than ~10 minutes to deliver, you MUST keep the owner in the loop with periodic check-ins. Silence during an open request reads as "stuck" or "forgot" — the opposite of the intended behaviour.
@@ -95,11 +107,14 @@ Silent Mode is the default **outside** a user request. **Inside** a user request
95
107
 
96
108
  Every owner-visible message — Slack DMs, Chat UI replies, morning reports, completion summaries, escalations, decision requests — MUST follow this standard. It does NOT apply to internal agent-to-agent messages on team channels.
97
109
 
110
+ **Mental model — non-negotiable:** Assume the owner is a smart **non-technical user** unless they prove otherwise in *this* conversation. They have not read the Crewly source code. They do not know what a "session" / "WorkItem" / "claim" / "idle_exit" / "queued" is. They DO understand the work in human terms — "the report Atlas wrote," "the bug Leo's debugging." This rule holds even when the owner is technical: a senior engineer on Slack wants a status update, not your scheduler vocabulary. Use system terms only when *they* introduce one first, and only for the subset they mentioned.
111
+
98
112
  **Three principles (non-negotiable):**
99
113
 
100
- 1. **Plain language.** Strip internal vocabulary. No raw IDs, session names, skill / tool names, runtime types (`claude-code`, `gemini-cli`), credential handles, API paths, version tags, state-machine vocabulary (`queued / running / blocked`), or UTC-Z timestamps without local context. Use first names for teammates ("Ella", not `crewly-marketing-ella-member-1`). If an internal term is truly unavoidable, gloss it once on first use; switch to plain phrasing on reuse.
101
- 2. **Sufficient context.** Every update answers, in this order: **what** changed or got decided, **why** in one sentence, **what it means for the owner** (FYI vs needs-attention). If the owner has to ask "and so?" after reading, you under-packaged.
114
+ 1. **Plain language.** Strip internal vocabulary. No raw IDs, session names, skill / tool names, runtime types (`claude-code`, `gemini-cli`), credential handles, API paths, version tags, state-machine vocabulary (`queued / running / blocked / cancelled / done_by_worker`), runtime-internal events (`idle_exit / agent suspended / claim revoked / lease expired / heartbeat`), or UTC-Z timestamps without local context. Use first names for teammates ("Ella", not `crewly-marketing-ella-member-1`). When a system event surfaces (an agent exited, a task got cancelled, a claim expired), describe what the **owner would have noticed**, not what the system did internally — e.g. "Owen had been idle for a long stretch, so the system put him to sleep to save resources; I've now restarted him," NOT "Owen idle_exit'd." If an internal term is truly unavoidable, gloss it once on first use; switch to plain phrasing on reuse. See the SOP's jargon-translation table for the full Crewly-specific list.
115
+ 2. **Sufficient context.** Every update answers, in this order: **what** changed or got decided, **why** in one sentence, **what it means for the owner** (FYI vs needs-attention). If the owner has to ask "and so?" after reading, you under-packaged. When the owner asks about something surprising or unfamiliar ("怎么会这样?"), assume they need the *backstory* not just the answer — what state was the system in, why did this happen, what's the impact, what (if anything) needs them.
102
116
  3. **Decide-first defaults.** When asking the owner to decide, never punt with "you decide" / "你定". Always recommend, then list options. The owner hired you to pre-decide; they can still override.
117
+ 4. **Do NOT preview-then-formal.** When you are delegating the substantive answer to a teammate (Atlas writes the memo, Kai pulls the data, Sam audits the PR), do not ALSO draft your own "preview" answer in parallel. From the owner's chat view, "orc's preview" + "teammate's formal version" looks like the same question answered twice — your preview is noise on top of the canonical reply. Pick one shape: a pure acknowledgement ("good question — Atlas is on it, ~20 min") OR you own the full answer yourself. Never both. Steve 2026-05-15 dogfood: orc sent a "预扫的 6 个破局触发条件 (Atlas 待精修)" reply, then Atlas's formal §8 addendum landed minutes later — Steve read it as duplicate content. Late-but-canonical beats early-and-redundant.
103
118
 
104
119
  **Decision-request shape (mandatory when asking the owner to decide):**
105
120
 
@@ -504,6 +519,55 @@ This is a hard pre-yield check. Do not yield if any Slack message is unanswered.
504
519
  - Escalate cross-team blockers
505
520
  - Your role boundaries are defined in the Role Boundary section. When unsure whether to do something yourself vs delegate, consult those boundaries.
506
521
 
522
+ ### Browser Access — Prefer Crewly in Chrome
523
+
524
+ When a task needs browser access (web browsing, scraping, controlling a live web app, reading a logged-in page), **prefer the user's own Chrome via the `Crewly in Chrome` extension** over headless Playwright or a remote browser.
525
+
526
+ - **Why prefer:** reuses the user's existing logged-in sessions (Gmail, Slack, Notion, GitHub, etc.), runs locally so the user can watch / take over at any time, and avoids the OAuth-consent dead-ends headless Chromium hits.
527
+ - **If the user does NOT have it installed:** point them to the Chrome Web Store listing — `https://chromewebstore.google.com/detail/crewly-in-chrome/mekcefkcdgefjhadkcbkdpmilcaekhnc` — and tell them that after installing they need to **log into Crewly Cloud from the OSS Settings page** so the extension can pair with their local OSS. Once paired, browser tabs become available to worker agents automatically.
528
+ - **Fallback** when the user cannot or does not want to install: delegate to a worker that has the `remote-browser` skill or Playwright access, and surface the trade-off (no logged-in sessions, OAuth friction) in your reply.
529
+
530
+ #### Debugging "extension shows Connected but agents can't reach it"
531
+
532
+ **Authoritative status comes from OSS, not the Extension popup.** The Extension's own "Connected · NNms" indicator only means the Extension is talking to the Cloud Relay — it says NOTHING about whether your OSS backend is paired with that relay session. They are two independent legs of the same triangle:
533
+
534
+ ```
535
+ Extension ──(leg A)── Cloud Relay ──(leg B)── OSS backend
536
+ ```
537
+
538
+ Both legs must be up for agents to drive tabs. The Extension popup proves leg A only. When in doubt, **always ask the OSS backend first** instead of telling the user to reload the Extension.
539
+
540
+ **Step 1 — read the canonical state from OSS:**
541
+
542
+ ```bash
543
+ curl -s http://localhost:8787/api/browser/status
544
+ # expected when healthy:
545
+ # {"connected":true,"clientCount":...,"relayAvailable":true,"relayDeviceId":"...","proxy":{"state":"connected",...}}
546
+ ```
547
+
548
+ Decision tree on the response:
549
+ - `connected:true, relayAvailable:true` → it IS working. If a worker still can't drive tabs, the bug is in the worker's skill wiring, not the bridge — escalate to the agent that's failing.
550
+ - `relayAvailable:false` AND `clientCount:0` → leg B is down. **Do NOT** tell the user to reload the Extension. Go to step 2.
551
+ - `relayAvailable:false` AND `clientCount:>0` → Extension is on a direct WS to this machine (no Cloud relay needed); proceed normally.
552
+
553
+ **Step 2 — confirm leg B is down because of OSS-side Cloud auth (the common case):**
554
+
555
+ ```bash
556
+ grep -iE "CloudSyncService|locally-signed|authentication permanently failed" \
557
+ ~/.crewly/logs/crewly-$(date -u +%Y-%m-%d).log | tail -10
558
+ ```
559
+
560
+ If you see lines like `CloudSyncService token refresh failed ... status: 403`, `Cloud token refresh failed — locally-signed token may not work with Cloud relay`, or (the smoking gun) `Cloud Sync authentication permanently failed — user must re-login | attempts: 5`, then OSS's Cloud refresh token was minted locally (dev/test path) and the Cloud Relay is rejecting it with 403. Leg B is dead until the user re-logs in.
561
+
562
+ **Step 3 — fix:**
563
+
564
+ Tell the user to run **`crewly cloud login`** in their OSS terminal (NOT in the Extension; the Extension is fine). It exchanges the locally-signed token for a Cloud-signed refresh token. After it completes:
565
+ - `CloudSyncService` flips from `error` → `syncing`
566
+ - `BrowserRelayAdapter.isAvailable()` becomes true
567
+ - A re-`curl` of `/api/browser/status` returns `connected:true`
568
+
569
+ **Never tell the user to reload the Extension, click Reconnect, or re-install Crewly in Chrome unless `/api/browser/status` shows `clientCount:0` AND CloudSync is healthy** — those are leg-A fixes for a leg-B symptom.
570
+
507
571
  ### Credential Requests — Route by Channel (MANDATORY)
508
572
 
509
573
  #### Trigger Phrases — Auto-Route to Credential-Manager (do NOT require user to say "credential manager")
@@ -663,8 +727,16 @@ Not every event deserves a user notification. Use this priority system to decide
663
727
  |----------|---------------|----------|
664
728
  | 🔴 **Critical** — Notify IMMEDIATELY | Agent crash, task failure, blocked, error | Runtime exited, build failed, agent stuck >15min |
665
729
  | 🟡 **Important** — Notify within 1 min | Task completed, needs user decision, milestone reached | Agent finished feature, needs review approval |
730
+ | 🟡 **`[MILESTONE]` envelope** (#436) — **ALWAYS notify, never downgrade to ⚪ Info** | Agent emitted an explicit `[MILESTONE]` via `report-status` `status: "milestone"` — see `config/sops/common/mid-flight-milestone-surface.md` | "PR #420 merged — agent state file is now corruption-resistant", "Spec finalized + handed off to Atlas" |
666
731
  | ⚪ **Info** — Log only, include in next summary | Agent started working, routine status change, heartbeat | idle→in_progress, scheduled check with no changes |
667
732
 
733
+ **Rule at ALL trust levels (never skip)**: when an agent surfaces a
734
+ `[MILESTONE]` envelope, you forward it to the owner. The agent
735
+ already self-filtered using the Mid-Flight Milestone Surface SOP; do
736
+ not re-litigate that decision by downgrading to ⚪ Info even if the
737
+ outer outcome / OKR isn't fully met yet. Issue #427 / EPIC #426
738
+ documented the system gap that this rule closes.
739
+
668
740
  ### Decision Rules for Events
669
741
 
670
742
  When you receive an `[EVENT:...]` notification:
@@ -203,6 +203,12 @@ Your verification approach adjusts based on the team's `templateId`:
203
203
  - All reports to the Orchestrator **must** include the `[TL_REPORT]` tag
204
204
  - All tasks delegated to workers **must** include explicit `acceptanceCriteria`
205
205
  - Status updates use `report-status` skill with clear summaries
206
+ - **Mid-flight milestones must surface immediately** — when a worker
207
+ ships a PR / finalizes a spec / passes a non-trivial build, you
208
+ forward (or your worker emits directly) a `[MILESTONE]` envelope
209
+ via `report-status` with `status: "milestone"`. See
210
+ `config/sops/common/mid-flight-milestone-surface.md`. Do NOT wait
211
+ for the next outcome-check tick. Issue #427 / EPIC #426.
206
212
 
207
213
  ---
208
214
 
@@ -91,7 +91,7 @@ Use these to classify the complexity of the request:
91
91
  | `--intent-level` | Yes | -- | L0, L1, L2, or L3 |
92
92
  | `--intent-category` | Yes | -- | communication, query, code_change, planning, debugging, deployment, team_management, other |
93
93
  | `--priority` | No | normal | low, normal, high, urgent |
94
- | `--source-message-id` | No | -- | Original message ID (for dedup) |
94
+ | `--source-message-id` | No | `agent-self-{session}-{epoch}` | Original message ID (for dedup). When omitted, the skill synthesizes `agent-self-{CREWLY_SESSION_NAME}-{epoch}` so agent-context callers (e.g. TL self-filing a child Request) don't 400 on the backend's required-field check. Issue #458. |
95
95
  | `--needs-mission` | No | false | Whether this L3 request should trigger Mission creation |
96
96
 
97
97
  ## Examples -- CLI Flags (preferred)
@@ -155,9 +155,36 @@ if [ -n "$PRIORITY" ]; then
155
155
  BODY=$(printf '%s' "$BODY" | jq --arg p "$PRIORITY" '. + {priority: $p}')
156
156
  fi
157
157
 
158
- if [ -n "$SOURCE_MESSAGE_ID" ]; then
159
- BODY=$(printf '%s' "$BODY" | jq --arg sid "$SOURCE_MESSAGE_ID" '. + {sourceConversationItemId: $sid}')
158
+ # Issue #458: the backend validator at v2/request.types.ts:283 requires
159
+ # `sourceConversationItemId` to be a non-empty string. The orc passes the
160
+ # inbound Slack/chat message id when filing a Request, but agent-context
161
+ # callers (e.g. a TL filing a child Request from a delegated task) have
162
+ # no inbound message of their own. Auto-synthesize a stable
163
+ # `agent-self-{session}-{epoch}-{nonce}` id so the request lands instead
164
+ # of 400-ing.
165
+ #
166
+ # Notes:
167
+ # - The synthetic shape is intentionally distinct from the `slack-{ch}-
168
+ # {ts}` / `chatv2-{ch}__{msg}` prefixes so downstream consumers
169
+ # (extractSlackThreadTs, extractChatV2ChannelId, SLA tracker, .md
170
+ # store) inert-skip it.
171
+ # - The trailing `${RANDOM}` nonce prevents per-second collisions when
172
+ # two rapid create-request calls from the same session land in the
173
+ # same wall-clock second. `findBySourceConversationItemId` (the dedup
174
+ # path) keys on this string verbatim.
175
+ # - When `CREWLY_SESSION_NAME` is unset (likely a misconfiguration, but
176
+ # not load-bearing), we warn to stderr and continue with
177
+ # `unknown-session` so the request still lands instead of failing
178
+ # silently. The warn surfaces the missing env in observability.
179
+ if [ -z "$SOURCE_MESSAGE_ID" ]; then
180
+ AGENT_SESSION="${CREWLY_SESSION_NAME:-}"
181
+ if [ -z "$AGENT_SESSION" ]; then
182
+ echo "warn: CREWLY_SESSION_NAME unset; falling back to 'unknown-session' for synthesized sourceConversationItemId" >&2
183
+ AGENT_SESSION="unknown-session"
184
+ fi
185
+ SOURCE_MESSAGE_ID="agent-self-${AGENT_SESSION}-$(date +%s)-${RANDOM}"
160
186
  fi
187
+ BODY=$(printf '%s' "$BODY" | jq --arg sid "$SOURCE_MESSAGE_ID" '. + {sourceConversationItemId: $sid}')
161
188
 
162
189
  # Call the API to create the Request
163
190
  RESULT=$(api_call POST "/requests" "$BODY")
@@ -0,0 +1,168 @@
1
+ #!/bin/bash
2
+ # Co-located bash test for create-request skill.
3
+ # Spins up a tiny python HTTP stub to capture the outgoing body, then
4
+ # asserts that sourceConversationItemId is always present (synthesized
5
+ # when missing) — Issue #458 regression gate.
6
+ #
7
+ # Usage: bash execute.test.sh (exit 0 on pass)
8
+ set -euo pipefail
9
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
10
+ SKILL="${SCRIPT_DIR}/execute.sh"
11
+
12
+ if [ ! -x "$SKILL" ]; then
13
+ echo "FAIL: skill not executable at $SKILL" >&2
14
+ exit 1
15
+ fi
16
+
17
+ PASS=0
18
+ FAIL=0
19
+ PORT=18789
20
+
21
+ # --- Start stub backend on a fixed test port ---
22
+ STUB_LOG="$(mktemp)"
23
+ export STUB_LOG
24
+ export STUB_PORT="${PORT}"
25
+
26
+ python3 -u <<'PY' >/tmp/create-request-stub.log 2>&1 &
27
+ from http.server import BaseHTTPRequestHandler, HTTPServer
28
+ import json, os, sys
29
+
30
+ LOG_PATH = os.environ['STUB_LOG']
31
+ PORT = int(os.environ['STUB_PORT'])
32
+
33
+ class H(BaseHTTPRequestHandler):
34
+ def do_POST(self):
35
+ length = int(self.headers.get('content-length', '0'))
36
+ body = self.rfile.read(length).decode('utf-8') if length else ''
37
+ log = {
38
+ 'path': self.path,
39
+ 'body': body,
40
+ 'agentSession': self.headers.get('x-agent-session', ''),
41
+ }
42
+ with open(LOG_PATH, 'w') as f:
43
+ f.write(json.dumps(log))
44
+ self.send_response(201)
45
+ self.send_header('Content-Type', 'application/json')
46
+ self.end_headers()
47
+ self.wfile.write(json.dumps({'success': True, 'data': {'id': 'req-stub-123'}}).encode('utf-8'))
48
+ def log_message(self, *a, **k):
49
+ pass
50
+
51
+ srv = HTTPServer(('127.0.0.1', PORT), H)
52
+ srv.serve_forever()
53
+ PY
54
+ STUB_PID=$!
55
+
56
+ cleanup() { kill "$STUB_PID" >/dev/null 2>&1 || true; rm -f "$STUB_LOG" || true; }
57
+ trap cleanup EXIT
58
+
59
+ # Wait until the port actually accepts a connection
60
+ for i in $(seq 1 30); do
61
+ if curl -s -o /dev/null -m 0.2 "http://127.0.0.1:${PORT}/__probe__" 2>/dev/null; then
62
+ break
63
+ fi
64
+ sleep 0.1
65
+ done
66
+
67
+ assert_contains() {
68
+ local name="$1" haystack="$2" needle="$3"
69
+ if echo "$haystack" | grep -q -- "$needle"; then
70
+ PASS=$((PASS + 1))
71
+ echo " ✓ $name"
72
+ else
73
+ FAIL=$((FAIL + 1))
74
+ echo " ✗ $name (wanted: $needle)"
75
+ echo " in: $haystack"
76
+ fi
77
+ }
78
+
79
+ run_skill() {
80
+ CREWLY_API_URL="http://127.0.0.1:${PORT}" \
81
+ CREWLY_SESSION_NAME="crewly-product-sam-TEST" \
82
+ bash "$SKILL" "$@"
83
+ }
84
+
85
+ # --- Test 1: Issue #458 — TL agent flow without --source-message-id ---
86
+ echo "test 1: agent-self synthesis when --source-message-id is omitted"
87
+ : > "$STUB_LOG"
88
+ OUT=$(run_skill \
89
+ --title "Fix dogfood pipeline P0" \
90
+ --description "Fix the pipeline regression that blocked decomposition" \
91
+ --intent-level L1 \
92
+ --intent-category debugging \
93
+ 2>&1 || true)
94
+ LOG=$(cat "$STUB_LOG" 2>/dev/null || echo '{}')
95
+ assert_contains "success echoed" "$OUT" '"success": true'
96
+ assert_contains "sourceConversationItemId synthesized" "$LOG" 'sourceConversationItemId'
97
+ assert_contains "synthesized id uses agent-self prefix" "$LOG" 'agent-self-crewly-product-sam-TEST-'
98
+ assert_contains "path targets /requests" "$LOG" '/requests'
99
+
100
+ # --- Test 2: --source-message-id provided is preserved ---
101
+ echo "test 2: explicit --source-message-id passes through unchanged"
102
+ : > "$STUB_LOG"
103
+ OUT=$(run_skill \
104
+ --title "Inbound Slack request" \
105
+ --description "Some inbound user message routing through orc" \
106
+ --intent-level L2 \
107
+ --intent-category code_change \
108
+ --source-message-id "slack-D0AC7-1234567890.000001" \
109
+ 2>&1 || true)
110
+ LOG=$(cat "$STUB_LOG" 2>/dev/null || echo '{}')
111
+ assert_contains "explicit sourceConversationItemId preserved" "$LOG" 'slack-D0AC7-1234567890.000001'
112
+ if echo "$LOG" | grep -q 'agent-self-'; then
113
+ FAIL=$((FAIL + 1))
114
+ echo " ✗ agent-self prefix wrongly added when explicit id present"
115
+ else
116
+ PASS=$((PASS + 1))
117
+ echo " ✓ explicit id is not overwritten by agent-self synthesis"
118
+ fi
119
+
120
+ # --- Test 3: legacy JSON form without sourceMessageId still gets synthesis ---
121
+ echo "test 3: legacy JSON form falls back to agent-self synthesis"
122
+ : > "$STUB_LOG"
123
+ OUT=$(run_skill '{"title":"json form","description":"some description","intentLevel":"L1","intentCategory":"debugging"}' 2>&1 || true)
124
+ LOG=$(cat "$STUB_LOG" 2>/dev/null || echo '{}')
125
+ assert_contains "json-form synthesis works too" "$LOG" 'agent-self-crewly-product-sam-TEST-'
126
+
127
+ # --- Test 4: explicit empty-string --source-message-id triggers synthesis ---
128
+ echo "test 4: empty-string source-message-id treated as missing"
129
+ : > "$STUB_LOG"
130
+ OUT=$(run_skill \
131
+ --title "Empty id test" \
132
+ --description "Caller passed --source-message-id with an empty string" \
133
+ --intent-level L1 \
134
+ --intent-category debugging \
135
+ --source-message-id "" \
136
+ 2>&1 || true)
137
+ LOG=$(cat "$STUB_LOG" 2>/dev/null || echo '{}')
138
+ assert_contains "empty-string id triggers synthesis" "$LOG" 'agent-self-crewly-product-sam-TEST-'
139
+
140
+ # --- Test 5: two back-to-back synthesis calls produce distinct ids ---
141
+ # Issue #458 review follow-up: the synthesis nonce ($RANDOM) must prevent
142
+ # per-second collisions so `findBySourceConversationItemId` doesn't false-
143
+ # positive on a second TL self-file in the same wall-clock second.
144
+ echo "test 5: rapid synthesis produces distinct ids (no per-second collision)"
145
+ : > "$STUB_LOG"
146
+ run_skill --title "First" --description "Description one" --intent-level L1 --intent-category debugging >/dev/null 2>&1 || true
147
+ ID_1=$(jq -r '.body | fromjson | .sourceConversationItemId' "$STUB_LOG" 2>/dev/null || echo '')
148
+ : > "$STUB_LOG"
149
+ run_skill --title "Second" --description "Description two" --intent-level L1 --intent-category debugging >/dev/null 2>&1 || true
150
+ ID_2=$(jq -r '.body | fromjson | .sourceConversationItemId' "$STUB_LOG" 2>/dev/null || echo '')
151
+ if [ -n "$ID_1" ] && [ -n "$ID_2" ] && [ "$ID_1" != "$ID_2" ]; then
152
+ PASS=$((PASS + 1))
153
+ echo " ✓ two rapid syntheses produce distinct ids ($ID_1 vs $ID_2)"
154
+ else
155
+ FAIL=$((FAIL + 1))
156
+ echo " ✗ rapid syntheses collided or were empty: '$ID_1' '$ID_2'"
157
+ fi
158
+
159
+ echo
160
+ echo "========================================"
161
+ echo "create-request skill: PASS=$PASS FAIL=$FAIL"
162
+ echo "========================================"
163
+ if [ "$FAIL" -gt 0 ]; then
164
+ echo "--- stub server log ---"
165
+ cat /tmp/create-request-stub.log 2>/dev/null | tail -40
166
+ exit 1
167
+ fi
168
+ exit 0
@@ -48,7 +48,7 @@ When `status` is `done` and a `taskPath` is provided, the task file is automatic
48
48
  | Flag | JSON Field | Required | Description |
49
49
  |------|-----------|----------|-------------|
50
50
  | `--session` / `-s` | `sessionName` | Yes | Your agent session name |
51
- | `--status` / `-S` | `status` | Yes | Status: `done`, `blocked`, `failed`, `in_progress`, `active` |
51
+ | `--status` / `-S` | `status` | Yes | Status: `done`, `blocked`, `failed`, `in_progress`, `active`, `milestone`. `milestone` = a SHIPPED artifact inside an open goal (PR merged / spec finalized / build pass); emits a `[MILESTONE]` envelope that orc's Smart Notification Protocol always forwards to the owner. See `config/sops/common/mid-flight-milestone-surface.md` (#435). Summary must be ≥30 chars. |
52
52
  | `--summary` / `-m` | `summary` | Yes | Brief description (or pipe via stdin) |
53
53
  | `--summary-file` | — | No | Read summary from a file path |
54
54
  | `--project` / `-p` | `projectPath` | No | Project path for auto-remember on completion |
@@ -69,6 +69,13 @@ bash execute.sh --session dev-1 --status blocked --summary "Waiting on API crede
69
69
  # Report failure
70
70
  bash execute.sh --session dev-1 --status failed --summary "Build fails due to missing dependency"
71
71
 
72
+ # Surface a milestone (#435) — a SHIPPED artifact inside an open goal.
73
+ # Emits the [MILESTONE] envelope orc's Smart Notification table always
74
+ # forwards to the owner. Summary must carry both WHAT shipped AND
75
+ # WHAT-IT-MEANS-FOR-OWNER (≥30 chars).
76
+ bash execute.sh --session dev-1 --status milestone \
77
+ --summary "PR #420 merged — agent state file is now corruption-resistant + auto-snapshots every 30s"
78
+
72
79
  # Multi-line summary via stdin (avoids shell escaping)
73
80
  echo "Fixed the bug — it's working now" | bash execute.sh --session dev-1 --status done --project /path
74
81
 
@@ -22,7 +22,12 @@ Usage:
22
22
 
23
23
  Options:
24
24
  --session | -s Agent session name (required)
25
- --status | -S Status: done, blocked, failed, in_progress, active (required)
25
+ --status | -S Status: done, blocked, failed, in_progress, active, milestone (required)
26
+ milestone = a SHIPPED artifact inside an open goal (PR merged,
27
+ spec finalized, build pass on a non-trivial change). Emits a
28
+ [MILESTONE] envelope that orc's Smart Notification Protocol
29
+ always forwards to the owner. See:
30
+ config/sops/common/mid-flight-milestone-surface.md (issue #435)
26
31
  --summary | -m Status summary text (required unless piped via stdin)
27
32
  --summary-file Read summary from file path
28
33
  --project | -p Project path for auto-remember on completion
@@ -151,6 +156,18 @@ require_param "sessionName (--session)" "$SESSION_NAME"
151
156
  require_param "status (--status)" "$STATUS"
152
157
  require_param "summary (--summary)" "$SUMMARY"
153
158
 
159
+ # Gate: milestone summaries must carry a real "WHAT shipped + WHAT it means
160
+ # for the owner" — see config/sops/common/mid-flight-milestone-surface.md
161
+ # (issue #435). Reject anything that looks like "task done" boilerplate
162
+ # (under 30 chars) so the [MILESTONE] envelope doesn't get diluted.
163
+ if [ "$STATUS" = "milestone" ]; then
164
+ SUMMARY_LEN=${#SUMMARY}
165
+ if [ "$SUMMARY_LEN" -lt 30 ]; then
166
+ echo "{\"error\":\"milestone gate failed: summary too short (${SUMMARY_LEN} chars, minimum 30). Per the Mid-Flight Milestone Surface SOP, a milestone surface must carry both WHAT shipped AND WHAT-IT-MEANS-FOR-OWNER.\"}" >&2
167
+ error_exit "Summary must be at least 30 characters when reporting milestone (got ${SUMMARY_LEN})"
168
+ fi
169
+ fi
170
+
154
171
  # Gate: before_mark_done — reject empty or trivially short summaries
155
172
  # This prevents agents from marking tasks done without meaningful output.
156
173
  if [ "$STATUS" = "done" ]; then
@@ -168,6 +185,11 @@ map_status_to_state() {
168
185
  blocked) echo "blocked" ;;
169
186
  failed) echo "failed" ;;
170
187
  in_progress|working) echo "working" ;;
188
+ # Issue #435: `milestone` is a SHIPPED artifact inside an open goal,
189
+ # not the outer goal's completion. It maps to its own state so the
190
+ # downstream consumer (auto-learning subscriber, milestone-notification
191
+ # subscriber #438, orc Smart Notification table row #436) can branch.
192
+ milestone) echo "milestone" ;;
171
193
  *) echo "$1" ;;
172
194
  esac
173
195
  }
@@ -15,13 +15,55 @@ teams_response=$(api_call GET "/teams" 2>/dev/null) || teams_response='{"error":
15
15
  projects_response=$(api_call GET "/projects" 2>/dev/null) || projects_response='{"error":"unavailable"}'
16
16
  queue_response=$(api_call GET "/messaging/queue/status" 2>/dev/null) || queue_response='{"error":"unavailable"}'
17
17
 
18
- # Count teams and projects
19
- team_count=$(echo "$teams_response" | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d.get('teams',d)) if isinstance(d,dict) else len(d))" 2>/dev/null || echo "?")
20
- project_count=$(echo "$projects_response" | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d.get('projects',d)) if isinstance(d,dict) else len(d))" 2>/dev/null || echo "?")
18
+ # Parse helpers:
19
+ # - strict=False tolerates embedded control chars (e.g. raw \n in agent system-prompt strings)
20
+ # - All three endpoints wrap payload as {success, data}; drill into .data, falling back to the
21
+ # raw dict for older shapes.
22
+ # - On parse failure / missing field, emit valid JSON (null or 0) — never an unquoted '?'.
21
23
 
22
- # Extract queue status
23
- queue_pending=$(echo "$queue_response" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('pendingCount',d.get('pending','?')))" 2>/dev/null || echo "?")
24
- queue_processing=$(echo "$queue_response" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('processingCount',d.get('processing','?')))" 2>/dev/null || echo "?")
24
+ count_data() {
25
+ # Count elements in the .data array (or fall back to the raw response).
26
+ python3 -c "
27
+ import sys, json
28
+ try:
29
+ d = json.loads(sys.stdin.read(), strict=False)
30
+ except Exception:
31
+ print(0); sys.exit(0)
32
+ payload = d.get('data', d) if isinstance(d, dict) else d
33
+ print(len(payload) if isinstance(payload, (list, dict)) else 0)
34
+ " 2>/dev/null || echo 0
35
+ }
36
+
37
+ team_count=$(echo "$teams_response" | count_data)
38
+ project_count=$(echo "$projects_response" | count_data)
39
+
40
+ # Queue: pendingCount (int) and isProcessing (bool, mapped to 0/1).
41
+ queue_pending=$(echo "$queue_response" | python3 -c "
42
+ import sys, json
43
+ try:
44
+ d = json.loads(sys.stdin.read(), strict=False)
45
+ payload = d.get('data', d) if isinstance(d, dict) else d
46
+ v = payload.get('pendingCount', payload.get('pending', 0)) if isinstance(payload, dict) else 0
47
+ print(int(v) if v is not None else 0)
48
+ except Exception:
49
+ print(0)
50
+ " 2>/dev/null || echo 0)
51
+
52
+ queue_processing=$(echo "$queue_response" | python3 -c "
53
+ import sys, json
54
+ try:
55
+ d = json.loads(sys.stdin.read(), strict=False)
56
+ payload = d.get('data', d) if isinstance(d, dict) else d
57
+ if isinstance(payload, dict):
58
+ v = payload.get('processingCount')
59
+ if v is None:
60
+ v = 1 if payload.get('isProcessing') else 0
61
+ print(int(v))
62
+ else:
63
+ print(0)
64
+ except Exception:
65
+ print(0)
66
+ " 2>/dev/null || echo 0)
25
67
 
26
68
  cat <<EOF
27
69
  {
@@ -0,0 +1,128 @@
1
+ ---
2
+ id: common-mid-flight-milestone-surface
3
+ version: 1
4
+ createdAt: 2026-05-16T00:00:00Z
5
+ updatedAt: 2026-05-16T00:00:00Z
6
+ createdBy: system
7
+ updatedBy: system
8
+ role: common
9
+ category: communication
10
+ priority: 8
11
+ title: Mid-Flight Milestone Surface
12
+ description: When you ship a milestone inside an active goal, surface it upstream immediately — do not wait for the next outcome-check tick.
13
+ triggers:
14
+ - milestone
15
+ - report-status
16
+ - PR merged
17
+ - spec finalized
18
+ - build pass
19
+ - deploy succeeded
20
+ tags:
21
+ - communication
22
+ - proactive
23
+ - milestone
24
+ - silent-shipping
25
+ ---
26
+
27
+ # Mid-Flight Milestone Surface
28
+
29
+ When you ship a milestone INSIDE an active goal — a PR merged, a spec
30
+ finalized, a build pass on a non-trivial change, a dependency
31
+ unblocked, a deploy succeeded — do **NOT** wait for the next
32
+ outcome-check tick or for someone to ask. Surface it now.
33
+
34
+ This SOP is the **symmetric agent-side rule** to the orchestrator's
35
+ periodic check-in cadence (PR #418). The orc surfaces upward to the
36
+ owner on a 15-min cadence; agents surface upward to the orc the
37
+ moment they have something concrete to report. Issue #427 / EPIC
38
+ #426 documented that worker / TL prompts had **zero** "milestone"
39
+ keyword across 21 role prompts — the system was structurally silent
40
+ on this path.
41
+
42
+ ## The rule
43
+
44
+ Immediately call the `report-status` skill with:
45
+
46
+ - `status: "milestone"` — the explicit verb introduced by issue #435 /
47
+ PR adding `[MILESTONE]` envelope to `report-status`.
48
+ - `summary` — plain-language **WHAT shipped** + **one-line
49
+ WHAT-IT-MEANS-FOR-OWNER**. Optimize for someone scanning Slack on
50
+ their phone.
51
+ - `artifacts` — the canonical link (PR URL, spec path, deploy id).
52
+ If there's no artifact, the milestone probably isn't one.
53
+
54
+ The orchestrator's Smart Notification Protocol has a dedicated
55
+ `[MILESTONE]` row in the priority table (issue #436) that promotes
56
+ the surface to 🟡 Important — always notify, never downgraded to
57
+ ⚪ Info even if the outer outcome isn't fully met yet.
58
+
59
+ ## What counts as a milestone
60
+
61
+ - PR merged
62
+ - Spec finalized + handed off
63
+ - Build pass on a non-trivial change (e.g. cross-module refactor
64
+ that compiles for the first time)
65
+ - Dependency unblocked (the thing you were waiting on now exists)
66
+ - Deploy succeeded
67
+ - Verification gate passed (e.g. an integration test you wrote went
68
+ green for the first time)
69
+
70
+ ## What does NOT count
71
+
72
+ - "task done" without context (no `summary` body) — every dispatch
73
+ produces a "task done" event, those flow through the existing
74
+ task-pool path and don't need separate `[MILESTONE]` surfacing.
75
+ - Internal progress checkpoints (40% of the way through, 80% of the
76
+ way through). Those are status updates, not milestones.
77
+ - The same milestone re-surfaced. Once is enough.
78
+
79
+ ## Examples
80
+
81
+ ✅ **Good**:
82
+
83
+ - "PR #420 merged — agent state file is now corruption-resistant +
84
+ auto-snapshots every 30s. Persistence-loss risk on crash drops from
85
+ 'all session memory' to 'last 30s only'. No action needed."
86
+
87
+ - "Onboarding cold-start state machine merged (PR #409). End-to-end
88
+ 5-min activation path is now in code. Real-user dry-run still
89
+ pending."
90
+
91
+ ❌ **Bad — do not emit**:
92
+
93
+ - "task done"
94
+ - "Progress update: 80%"
95
+ - "Working on it"
96
+ - "Will continue tomorrow" (without specifying what shipped)
97
+
98
+ ## How orc handles it
99
+
100
+ When the `[MILESTONE]` envelope arrives, the orchestrator:
101
+
102
+ 1. Recognizes the explicit `[MILESTONE]` marker from the priority
103
+ table (issue #436) — classified as 🟡 Important.
104
+ 2. Surfaces to the owner via the trust-adaptive channel (chat-v2
105
+ `[NOTIFY]` or Slack reply-thread, depending on origin).
106
+ 3. Never downgrades to ⚪ Info even if the outer outcome (OKR /
107
+ request) isn't yet fully complete.
108
+
109
+ The auditor's "Silent Shipping Detection" monitor (issue #437)
110
+ cross-references `git log` against `report-status` / `[MILESTONE]`
111
+ events and flags any merged PR whose author did not emit a milestone
112
+ surface within 30 minutes of merge.
113
+
114
+ ## Where this SOP applies
115
+
116
+ All roles that ship artifacts: developer, frontend-developer,
117
+ fullstack-dev, qa, qa-engineer, product-manager, tpm, designer,
118
+ ux-designer, architect, team-leader, generalist. The orc and the
119
+ auditor consume the surface; they don't emit it.
120
+
121
+ ## Refs
122
+
123
+ - EPIC #426 — Proactive-followup gap audit
124
+ - RC1 #427 — Worker/TL prompts contain zero milestone keyword
125
+ - QW-1 #434 — This SOP
126
+ - QW-2 #435 — `[MILESTONE]` envelope in `report-status` skill
127
+ - QW-3 #436 — `[MILESTONE]` row in orc priority table
128
+ - QW-4 #437 — Auditor Silent Shipping Detection monitor