crewly 1.20.194 → 1.20.195

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 (320) hide show
  1. package/config/roles/auditor/prompt.md +2 -2
  2. package/config/roles/orchestrator/fragments/communication.md +1 -1
  3. package/config/roles/orchestrator/prompt.md +15 -505
  4. package/config/skills/agent/computer-use/SKILL.md +6 -0
  5. package/config/skills/agent/core/experiment-card/SKILL.md +10 -5
  6. package/config/skills/agent/core/experiment-card/execute.sh +5 -3
  7. package/config/skills/agent/core/experiment-card/execute.test.sh +6 -0
  8. package/config/skills/agent/desktop-app-control/execute.sh +5 -2
  9. package/config/skills/orchestrator/send-message/execute.sh +19 -2
  10. package/config/skills/orchestrator/send-message/execute.test.sh +80 -0
  11. package/config/skills/registry.json +6 -5
  12. package/config/skills/team-leader/signal-digest/SKILL.md +110 -0
  13. package/config/skills/team-leader/signal-digest/execute.sh +173 -0
  14. package/config/skills/team-leader/signal-digest/execute.test.sh +123 -0
  15. package/config/skills/team-leader/signal-digest/signal-digest.config.example.json +23 -0
  16. package/config/skills/team-leader/signal-digest/signal_digest.py +572 -0
  17. package/config/skills/team-leader/signal-digest/signal_digest.test.py +319 -0
  18. package/dist/backend/backend/src/constants.d.ts +133 -0
  19. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  20. package/dist/backend/backend/src/constants.js +135 -2
  21. package/dist/backend/backend/src/constants.js.map +1 -1
  22. package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts.map +1 -1
  23. package/dist/backend/backend/src/controllers/chat/chat.controller.js +6 -0
  24. package/dist/backend/backend/src/controllers/chat/chat.controller.js.map +1 -1
  25. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.d.ts.map +1 -1
  26. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.js +3 -1
  27. package/dist/backend/backend/src/controllers/chat-v2/chat-v2.controller.js.map +1 -1
  28. package/dist/backend/backend/src/controllers/marketplace/marketplace.routes.d.ts +1 -0
  29. package/dist/backend/backend/src/controllers/marketplace/marketplace.routes.d.ts.map +1 -1
  30. package/dist/backend/backend/src/controllers/marketplace/marketplace.routes.js +1 -0
  31. package/dist/backend/backend/src/controllers/marketplace/marketplace.routes.js.map +1 -1
  32. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.d.ts.map +1 -1
  33. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js +5 -2
  34. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js.map +1 -1
  35. package/dist/backend/backend/src/controllers/request/request.controller.d.ts.map +1 -1
  36. package/dist/backend/backend/src/controllers/request/request.controller.js +5 -1
  37. package/dist/backend/backend/src/controllers/request/request.controller.js.map +1 -1
  38. package/dist/backend/backend/src/controllers/settings/settings.controller.d.ts.map +1 -1
  39. package/dist/backend/backend/src/controllers/settings/settings.controller.js +18 -2
  40. package/dist/backend/backend/src/controllers/settings/settings.controller.js.map +1 -1
  41. package/dist/backend/backend/src/controllers/signal-digest/signal-digest.controller.d.ts +26 -0
  42. package/dist/backend/backend/src/controllers/signal-digest/signal-digest.controller.d.ts.map +1 -0
  43. package/dist/backend/backend/src/controllers/signal-digest/signal-digest.controller.js +100 -0
  44. package/dist/backend/backend/src/controllers/signal-digest/signal-digest.controller.js.map +1 -0
  45. package/dist/backend/backend/src/controllers/trace/trace.controller.d.ts +47 -0
  46. package/dist/backend/backend/src/controllers/trace/trace.controller.d.ts.map +1 -0
  47. package/dist/backend/backend/src/controllers/trace/trace.controller.js +169 -0
  48. package/dist/backend/backend/src/controllers/trace/trace.controller.js.map +1 -0
  49. package/dist/backend/backend/src/index.d.ts.map +1 -1
  50. package/dist/backend/backend/src/index.js +29 -19
  51. package/dist/backend/backend/src/index.js.map +1 -1
  52. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  53. package/dist/backend/backend/src/routes/api.routes.js +11 -0
  54. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  55. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  56. package/dist/backend/backend/src/services/agent/agent-registration.service.js +6 -1
  57. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  58. package/dist/backend/backend/src/services/agent/oauth-relogin-monitor.service.d.ts +1 -1
  59. package/dist/backend/backend/src/services/agent/oauth-relogin-monitor.service.d.ts.map +1 -1
  60. package/dist/backend/backend/src/services/agent/runtime-session-recovery.d.ts +4 -2
  61. package/dist/backend/backend/src/services/agent/runtime-session-recovery.d.ts.map +1 -1
  62. package/dist/backend/backend/src/services/agent/runtime-session-recovery.js +22 -6
  63. package/dist/backend/backend/src/services/agent/runtime-session-recovery.js.map +1 -1
  64. package/dist/backend/backend/src/services/ai/prompt-modules/communication.module.js +2 -2
  65. package/dist/backend/backend/src/services/ai/prompt-modules/communication.module.js.map +1 -1
  66. package/dist/backend/backend/src/services/backup/backup-archive.service.d.ts +6 -0
  67. package/dist/backend/backend/src/services/backup/backup-archive.service.d.ts.map +1 -1
  68. package/dist/backend/backend/src/services/backup/backup-archive.service.js +7 -1
  69. package/dist/backend/backend/src/services/backup/backup-archive.service.js.map +1 -1
  70. package/dist/backend/backend/src/services/boot/boot-announce.service.d.ts +1 -1
  71. package/dist/backend/backend/src/services/boot/boot-announce.service.d.ts.map +1 -1
  72. package/dist/backend/backend/src/services/chat/chat.service.d.ts +78 -2
  73. package/dist/backend/backend/src/services/chat/chat.service.d.ts.map +1 -1
  74. package/dist/backend/backend/src/services/chat/chat.service.js +210 -26
  75. package/dist/backend/backend/src/services/chat/chat.service.js.map +1 -1
  76. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.d.ts +4 -3
  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 +7 -4
  79. package/dist/backend/backend/src/services/chat-v2/chat-v2.service.js.map +1 -1
  80. package/dist/backend/backend/src/services/decisions/decision-store.d.ts.map +1 -1
  81. package/dist/backend/backend/src/services/decisions/decision-store.js +5 -1
  82. package/dist/backend/backend/src/services/decisions/decision-store.js.map +1 -1
  83. package/dist/backend/backend/src/services/decisions/decision.wiring.d.ts +10 -1
  84. package/dist/backend/backend/src/services/decisions/decision.wiring.d.ts.map +1 -1
  85. package/dist/backend/backend/src/services/decisions/decision.wiring.js +20 -9
  86. package/dist/backend/backend/src/services/decisions/decision.wiring.js.map +1 -1
  87. package/dist/backend/backend/src/services/experiments/experiment-verdict.d.ts +1 -1
  88. package/dist/backend/backend/src/services/experiments/experiment-verdict.js +2 -2
  89. package/dist/backend/backend/src/services/experiments/experiment-verdict.js.map +1 -1
  90. package/dist/backend/backend/src/services/experiments/experiment.service.d.ts +52 -3
  91. package/dist/backend/backend/src/services/experiments/experiment.service.d.ts.map +1 -1
  92. package/dist/backend/backend/src/services/experiments/experiment.service.js +178 -24
  93. package/dist/backend/backend/src/services/experiments/experiment.service.js.map +1 -1
  94. package/dist/backend/backend/src/services/experiments/experiment.wiring.d.ts +20 -5
  95. package/dist/backend/backend/src/services/experiments/experiment.wiring.d.ts.map +1 -1
  96. package/dist/backend/backend/src/services/experiments/experiment.wiring.js +27 -7
  97. package/dist/backend/backend/src/services/experiments/experiment.wiring.js.map +1 -1
  98. package/dist/backend/backend/src/services/experiments/seo-ops-metric.fetcher.d.ts +7 -0
  99. package/dist/backend/backend/src/services/experiments/seo-ops-metric.fetcher.d.ts.map +1 -1
  100. package/dist/backend/backend/src/services/experiments/seo-ops-metric.fetcher.js +21 -1
  101. package/dist/backend/backend/src/services/experiments/seo-ops-metric.fetcher.js.map +1 -1
  102. package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.d.ts.map +1 -1
  103. package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.js +7 -0
  104. package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.js.map +1 -1
  105. package/dist/backend/backend/src/services/monitoring/token-usage.service.d.ts +7 -0
  106. package/dist/backend/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -1
  107. package/dist/backend/backend/src/services/monitoring/token-usage.service.js +4 -0
  108. package/dist/backend/backend/src/services/monitoring/token-usage.service.js.map +1 -1
  109. package/dist/backend/backend/src/services/orc/orc-status-router.service.d.ts.map +1 -1
  110. package/dist/backend/backend/src/services/orc/orc-status-router.service.js +10 -2
  111. package/dist/backend/backend/src/services/orc/orc-status-router.service.js.map +1 -1
  112. package/dist/backend/backend/src/services/orc/reply-destination.wiring.d.ts.map +1 -1
  113. package/dist/backend/backend/src/services/orc/reply-destination.wiring.js +16 -0
  114. package/dist/backend/backend/src/services/orc/reply-destination.wiring.js.map +1 -1
  115. package/dist/backend/backend/src/services/project-tickets/project-ticket.service.d.ts.map +1 -1
  116. package/dist/backend/backend/src/services/project-tickets/project-ticket.service.js +2 -0
  117. package/dist/backend/backend/src/services/project-tickets/project-ticket.service.js.map +1 -1
  118. package/dist/backend/backend/src/services/reconciler/reconciler.service.d.ts.map +1 -1
  119. package/dist/backend/backend/src/services/reconciler/reconciler.service.js +15 -0
  120. package/dist/backend/backend/src/services/reconciler/reconciler.service.js.map +1 -1
  121. package/dist/backend/backend/src/services/session/session-handoff.service.d.ts.map +1 -1
  122. package/dist/backend/backend/src/services/session/session-handoff.service.js +8 -5
  123. package/dist/backend/backend/src/services/session/session-handoff.service.js.map +1 -1
  124. package/dist/backend/backend/src/services/signal-digest/signal-digest-card.d.ts +75 -0
  125. package/dist/backend/backend/src/services/signal-digest/signal-digest-card.d.ts.map +1 -0
  126. package/dist/backend/backend/src/services/signal-digest/signal-digest-card.js +187 -0
  127. package/dist/backend/backend/src/services/signal-digest/signal-digest-card.js.map +1 -0
  128. package/dist/backend/backend/src/services/signal-digest/signal-digest-contract.d.ts +86 -0
  129. package/dist/backend/backend/src/services/signal-digest/signal-digest-contract.d.ts.map +1 -0
  130. package/dist/backend/backend/src/services/signal-digest/signal-digest-contract.js +307 -0
  131. package/dist/backend/backend/src/services/signal-digest/signal-digest-contract.js.map +1 -0
  132. package/dist/backend/backend/src/services/signal-digest/signal-digest-store.d.ts +85 -0
  133. package/dist/backend/backend/src/services/signal-digest/signal-digest-store.d.ts.map +1 -0
  134. package/dist/backend/backend/src/services/signal-digest/signal-digest-store.js +185 -0
  135. package/dist/backend/backend/src/services/signal-digest/signal-digest-store.js.map +1 -0
  136. package/dist/backend/backend/src/services/signal-digest/signal-digest.service.d.ts +272 -0
  137. package/dist/backend/backend/src/services/signal-digest/signal-digest.service.d.ts.map +1 -0
  138. package/dist/backend/backend/src/services/signal-digest/signal-digest.service.js +570 -0
  139. package/dist/backend/backend/src/services/signal-digest/signal-digest.service.js.map +1 -0
  140. package/dist/backend/backend/src/services/signal-digest/signal-digest.wiring.d.ts +51 -0
  141. package/dist/backend/backend/src/services/signal-digest/signal-digest.wiring.d.ts.map +1 -0
  142. package/dist/backend/backend/src/services/signal-digest/signal-digest.wiring.js +116 -0
  143. package/dist/backend/backend/src/services/signal-digest/signal-digest.wiring.js.map +1 -0
  144. package/dist/backend/backend/src/services/slack/notify-reconciliation.service.d.ts +5 -1
  145. package/dist/backend/backend/src/services/slack/notify-reconciliation.service.d.ts.map +1 -1
  146. package/dist/backend/backend/src/services/slack/notify-reconciliation.service.js +6 -2
  147. package/dist/backend/backend/src/services/slack/notify-reconciliation.service.js.map +1 -1
  148. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts +2 -1
  149. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
  150. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js +3 -2
  151. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
  152. package/dist/backend/backend/src/services/slack/slack-relogin-dm.service.d.ts +1 -1
  153. package/dist/backend/backend/src/services/slack/slack-relogin-dm.service.d.ts.map +1 -1
  154. package/dist/backend/backend/src/services/slack/slack.service.d.ts +25 -1
  155. package/dist/backend/backend/src/services/slack/slack.service.d.ts.map +1 -1
  156. package/dist/backend/backend/src/services/slack/slack.service.js +44 -7
  157. package/dist/backend/backend/src/services/slack/slack.service.js.map +1 -1
  158. package/dist/backend/backend/src/services/system/auto-update.service.d.ts +2 -2
  159. package/dist/backend/backend/src/services/system/auto-update.service.d.ts.map +1 -1
  160. package/dist/backend/backend/src/services/task-pool/pool-storage.d.ts.map +1 -1
  161. package/dist/backend/backend/src/services/task-pool/pool-storage.js +4 -0
  162. package/dist/backend/backend/src/services/task-pool/pool-storage.js.map +1 -1
  163. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  164. package/dist/backend/backend/src/services/task-pool/task-pool.service.js +2 -0
  165. package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  166. package/dist/backend/backend/src/services/trace/trace-context.service.d.ts +195 -0
  167. package/dist/backend/backend/src/services/trace/trace-context.service.d.ts.map +1 -0
  168. package/dist/backend/backend/src/services/trace/trace-context.service.js +432 -0
  169. package/dist/backend/backend/src/services/trace/trace-context.service.js.map +1 -0
  170. package/dist/backend/backend/src/services/trace/trace-http.middleware.d.ts +42 -0
  171. package/dist/backend/backend/src/services/trace/trace-http.middleware.d.ts.map +1 -0
  172. package/dist/backend/backend/src/services/trace/trace-http.middleware.js +146 -0
  173. package/dist/backend/backend/src/services/trace/trace-http.middleware.js.map +1 -0
  174. package/dist/backend/backend/src/services/trace/trace-markers.d.ts +93 -0
  175. package/dist/backend/backend/src/services/trace/trace-markers.d.ts.map +1 -0
  176. package/dist/backend/backend/src/services/trace/trace-markers.js +162 -0
  177. package/dist/backend/backend/src/services/trace/trace-markers.js.map +1 -0
  178. package/dist/backend/backend/src/services/trace/trace-recorder.d.ts +290 -0
  179. package/dist/backend/backend/src/services/trace/trace-recorder.d.ts.map +1 -0
  180. package/dist/backend/backend/src/services/trace/trace-recorder.js +669 -0
  181. package/dist/backend/backend/src/services/trace/trace-recorder.js.map +1 -0
  182. package/dist/backend/backend/src/services/trace/trace-store.d.ts +269 -0
  183. package/dist/backend/backend/src/services/trace/trace-store.d.ts.map +1 -0
  184. package/dist/backend/backend/src/services/trace/trace-store.js +602 -0
  185. package/dist/backend/backend/src/services/trace/trace-store.js.map +1 -0
  186. package/dist/backend/backend/src/services/trace/trace.types.d.ts +118 -0
  187. package/dist/backend/backend/src/services/trace/trace.types.d.ts.map +1 -0
  188. package/dist/backend/backend/src/services/trace/trace.types.js +85 -0
  189. package/dist/backend/backend/src/services/trace/trace.types.js.map +1 -0
  190. package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt.boot.d.ts +1 -1
  191. package/dist/backend/backend/src/services/v3/owner-receipt/owner-receipt.boot.d.ts.map +1 -1
  192. package/dist/backend/backend/src/services/v3/request.service.d.ts.map +1 -1
  193. package/dist/backend/backend/src/services/v3/request.service.js +4 -0
  194. package/dist/backend/backend/src/services/v3/request.service.js.map +1 -1
  195. package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.d.ts.map +1 -1
  196. package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.js +22 -2
  197. package/dist/backend/backend/src/services/v3/workitem-dispatch.subscriber.js.map +1 -1
  198. package/dist/backend/backend/src/services/worktree/worktree-janitor.service.d.ts +3 -0
  199. package/dist/backend/backend/src/services/worktree/worktree-janitor.service.d.ts.map +1 -1
  200. package/dist/backend/backend/src/services/worktree/worktree-janitor.service.js +7 -0
  201. package/dist/backend/backend/src/services/worktree/worktree-janitor.service.js.map +1 -1
  202. package/dist/backend/backend/src/types/experiment.types.d.ts +8 -6
  203. package/dist/backend/backend/src/types/experiment.types.d.ts.map +1 -1
  204. package/dist/backend/backend/src/types/experiment.types.js.map +1 -1
  205. package/dist/backend/backend/src/types/signal-digest.types.d.ts +185 -0
  206. package/dist/backend/backend/src/types/signal-digest.types.d.ts.map +1 -0
  207. package/dist/backend/backend/src/types/signal-digest.types.js +21 -0
  208. package/dist/backend/backend/src/types/signal-digest.types.js.map +1 -0
  209. package/dist/backend/backend/src/types/v2/request.types.d.ts +4 -0
  210. package/dist/backend/backend/src/types/v2/request.types.d.ts.map +1 -1
  211. package/dist/backend/backend/src/types/v2/request.types.js.map +1 -1
  212. package/dist/backend/backend/src/types/v2/work-item.types.d.ts +4 -0
  213. package/dist/backend/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  214. package/dist/backend/backend/src/types/v2/work-item.types.js +1 -0
  215. package/dist/backend/backend/src/types/v2/work-item.types.js.map +1 -1
  216. package/dist/backend/backend/src/utils/security.d.ts +2 -0
  217. package/dist/backend/backend/src/utils/security.d.ts.map +1 -1
  218. package/dist/backend/backend/src/utils/security.js +3 -1
  219. package/dist/backend/backend/src/utils/security.js.map +1 -1
  220. package/dist/backend/backend/src/websocket/chat.gateway.d.ts +9 -0
  221. package/dist/backend/backend/src/websocket/chat.gateway.d.ts.map +1 -1
  222. package/dist/backend/backend/src/websocket/chat.gateway.js +26 -0
  223. package/dist/backend/backend/src/websocket/chat.gateway.js.map +1 -1
  224. package/dist/backend/build-info.json +2 -2
  225. package/dist/cli/backend/src/constants.d.ts +133 -0
  226. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  227. package/dist/cli/backend/src/constants.js +135 -2
  228. package/dist/cli/backend/src/constants.js.map +1 -1
  229. package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  230. package/dist/cli/backend/src/services/agent/agent-registration.service.js +6 -1
  231. package/dist/cli/backend/src/services/agent/agent-registration.service.js.map +1 -1
  232. package/dist/cli/backend/src/services/agent/oauth-relogin-monitor.service.d.ts +1 -1
  233. package/dist/cli/backend/src/services/agent/oauth-relogin-monitor.service.d.ts.map +1 -1
  234. package/dist/cli/backend/src/services/agent/runtime-session-recovery.d.ts +4 -2
  235. package/dist/cli/backend/src/services/agent/runtime-session-recovery.d.ts.map +1 -1
  236. package/dist/cli/backend/src/services/agent/runtime-session-recovery.js +22 -6
  237. package/dist/cli/backend/src/services/agent/runtime-session-recovery.js.map +1 -1
  238. package/dist/cli/backend/src/services/ai/prompt-modules/communication.module.js +2 -2
  239. package/dist/cli/backend/src/services/ai/prompt-modules/communication.module.js.map +1 -1
  240. package/dist/cli/backend/src/services/backup/backup-archive.service.d.ts +6 -0
  241. package/dist/cli/backend/src/services/backup/backup-archive.service.d.ts.map +1 -1
  242. package/dist/cli/backend/src/services/backup/backup-archive.service.js +7 -1
  243. package/dist/cli/backend/src/services/backup/backup-archive.service.js.map +1 -1
  244. package/dist/cli/backend/src/services/chat/chat.service.d.ts +185 -0
  245. package/dist/cli/backend/src/services/chat/chat.service.d.ts.map +1 -0
  246. package/dist/cli/backend/src/services/chat/chat.service.js +558 -0
  247. package/dist/cli/backend/src/services/chat/chat.service.js.map +1 -0
  248. package/dist/cli/backend/src/services/chat-v2/chat-v2.service.d.ts +4 -3
  249. package/dist/cli/backend/src/services/chat-v2/chat-v2.service.d.ts.map +1 -1
  250. package/dist/cli/backend/src/services/chat-v2/chat-v2.service.js +7 -4
  251. package/dist/cli/backend/src/services/chat-v2/chat-v2.service.js.map +1 -1
  252. package/dist/cli/backend/src/services/decisions/decision-store.d.ts.map +1 -1
  253. package/dist/cli/backend/src/services/decisions/decision-store.js +5 -1
  254. package/dist/cli/backend/src/services/decisions/decision-store.js.map +1 -1
  255. package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.d.ts.map +1 -1
  256. package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.js +7 -0
  257. package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.js.map +1 -1
  258. package/dist/cli/backend/src/services/monitoring/token-usage.service.d.ts +7 -0
  259. package/dist/cli/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -1
  260. package/dist/cli/backend/src/services/monitoring/token-usage.service.js +4 -0
  261. package/dist/cli/backend/src/services/monitoring/token-usage.service.js.map +1 -1
  262. package/dist/cli/backend/src/services/project-tickets/project-ticket.service.d.ts.map +1 -1
  263. package/dist/cli/backend/src/services/project-tickets/project-ticket.service.js +2 -0
  264. package/dist/cli/backend/src/services/project-tickets/project-ticket.service.js.map +1 -1
  265. package/dist/cli/backend/src/services/session/session-handoff.service.d.ts.map +1 -1
  266. package/dist/cli/backend/src/services/session/session-handoff.service.js +8 -5
  267. package/dist/cli/backend/src/services/session/session-handoff.service.js.map +1 -1
  268. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.d.ts +2 -1
  269. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
  270. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.js +3 -2
  271. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
  272. package/dist/cli/backend/src/services/slack/slack.service.d.ts +25 -1
  273. package/dist/cli/backend/src/services/slack/slack.service.d.ts.map +1 -1
  274. package/dist/cli/backend/src/services/slack/slack.service.js +44 -7
  275. package/dist/cli/backend/src/services/slack/slack.service.js.map +1 -1
  276. package/dist/cli/backend/src/services/task-pool/pool-storage.d.ts.map +1 -1
  277. package/dist/cli/backend/src/services/task-pool/pool-storage.js +4 -0
  278. package/dist/cli/backend/src/services/task-pool/pool-storage.js.map +1 -1
  279. package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  280. package/dist/cli/backend/src/services/task-pool/task-pool.service.js +2 -0
  281. package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  282. package/dist/cli/backend/src/services/trace/trace-context.service.d.ts +195 -0
  283. package/dist/cli/backend/src/services/trace/trace-context.service.d.ts.map +1 -0
  284. package/dist/cli/backend/src/services/trace/trace-context.service.js +432 -0
  285. package/dist/cli/backend/src/services/trace/trace-context.service.js.map +1 -0
  286. package/dist/cli/backend/src/services/trace/trace-markers.d.ts +93 -0
  287. package/dist/cli/backend/src/services/trace/trace-markers.d.ts.map +1 -0
  288. package/dist/cli/backend/src/services/trace/trace-markers.js +162 -0
  289. package/dist/cli/backend/src/services/trace/trace-markers.js.map +1 -0
  290. package/dist/cli/backend/src/services/trace/trace-recorder.d.ts +290 -0
  291. package/dist/cli/backend/src/services/trace/trace-recorder.d.ts.map +1 -0
  292. package/dist/cli/backend/src/services/trace/trace-recorder.js +669 -0
  293. package/dist/cli/backend/src/services/trace/trace-recorder.js.map +1 -0
  294. package/dist/cli/backend/src/services/trace/trace-store.d.ts +269 -0
  295. package/dist/cli/backend/src/services/trace/trace-store.d.ts.map +1 -0
  296. package/dist/cli/backend/src/services/trace/trace-store.js +602 -0
  297. package/dist/cli/backend/src/services/trace/trace-store.js.map +1 -0
  298. package/dist/cli/backend/src/services/trace/trace.types.d.ts +118 -0
  299. package/dist/cli/backend/src/services/trace/trace.types.d.ts.map +1 -0
  300. package/dist/cli/backend/src/services/trace/trace.types.js +85 -0
  301. package/dist/cli/backend/src/services/trace/trace.types.js.map +1 -0
  302. package/dist/cli/backend/src/services/v3/request.service.d.ts.map +1 -1
  303. package/dist/cli/backend/src/services/v3/request.service.js +4 -0
  304. package/dist/cli/backend/src/services/v3/request.service.js.map +1 -1
  305. package/dist/cli/backend/src/types/v2/request.types.d.ts +4 -0
  306. package/dist/cli/backend/src/types/v2/request.types.d.ts.map +1 -1
  307. package/dist/cli/backend/src/types/v2/request.types.js.map +1 -1
  308. package/dist/cli/backend/src/types/v2/work-item.types.d.ts +4 -0
  309. package/dist/cli/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  310. package/dist/cli/backend/src/types/v2/work-item.types.js +1 -0
  311. package/dist/cli/backend/src/types/v2/work-item.types.js.map +1 -1
  312. package/dist/cli/backend/src/utils/security.d.ts +196 -0
  313. package/dist/cli/backend/src/utils/security.d.ts.map +1 -0
  314. package/dist/cli/backend/src/utils/security.js +538 -0
  315. package/dist/cli/backend/src/utils/security.js.map +1 -0
  316. package/dist/cli/backend/src/websocket/chat.gateway.d.ts +9 -0
  317. package/dist/cli/backend/src/websocket/chat.gateway.d.ts.map +1 -1
  318. package/dist/cli/backend/src/websocket/chat.gateway.js +26 -0
  319. package/dist/cli/backend/src/websocket/chat.gateway.js.map +1 -1
  320. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: Experiment Card
3
3
  description: Attach an experiment to an optimisation ticket — hypothesis ("change X → metric Y from a to b"), a Search Console or GA4 metric (via seo-ops), an observation window (default 14 days). Crewly captures the baseline when the change ships, measures it when the window ends, labels it worked / didn't / inconclusive, resolves your prediction, writes the wiki experiment log and tells the owner.
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  category: analysis
6
6
  skillType: claude-skill
7
7
  assignableRoles:
@@ -41,7 +41,10 @@ Crewly does the rest:
41
41
 
42
42
  1. **Ship** — when the linked ticket reaches `done` (or you run `ship`), the
43
43
  windows are fixed and the **baseline** is fetched right away: the
44
- `windowDays` days that had settled before the ship day.
44
+ `windowDays` days that had settled before the ship day. The ship time is
45
+ the ticket's move to `done` in its log. If you link a ticket that is
46
+ already done and its log has no done time, `create` asks for
47
+ `--shipped-at` (when the change went live).
45
48
  2. **Wait** — the observation window is the `windowDays` days after the ship
46
49
  day. Nothing to do; don't re-check it by hand.
47
50
  3. **Measure** — once those days have settled (Search Console +3 days, GA4
@@ -76,8 +79,10 @@ bash execute.sh create --hypothesis "3-field inquiry form → submissions from 8
76
79
  - gsc measures: `clicks`, `impressions`, `ctr`, `position` (lower is better;
77
80
  direction defaults to `decrease`). Filters: `--page URL`, `--query Q`,
78
81
  `--page-match` / `--query-match exact|contains`.
79
- - ga4 measures: `sessions` (Organic Search unless `--channel all`) and
80
- `events` (`--event NAME`). Filter: `--page /landing-path`.
82
+ - ga4 measures: `sessions` (Organic Search unless `--channel all`),
83
+ `events` (`--event NAME`) and `conversions` (GA4 key events; `--event NAME`
84
+ for one of them). Filter: `--page /landing-path` (a full URL is reduced to
85
+ its path; the query string is dropped).
81
86
  - `--window-days` 7–90, whole weeks preferred (default 14).
82
87
  - One experiment per change: two changes on the same page in one window
83
88
  can't be told apart.
@@ -93,4 +98,4 @@ bash execute.sh cancel --id EXP-3 --reason "change reverted"
93
98
  ```
94
99
 
95
100
  If a fetch keeps failing (credentials, property access) the owner is told
96
- once with the error; it keeps retrying.
101
+ once with the error; after 6 failures in a row it retries once a day.
@@ -10,7 +10,7 @@
10
10
  # [--page P] [--page-match exact|contains] [--query Q] [--query-match exact|contains]
11
11
  # [--event NAME] [--channel all] [--label "…"] [--title "…"]
12
12
  # [--from A] [--to B] [--direction increase|decrease] [--window-days 14]
13
- # [--confidence 0.6] [--project P --ticket ID | --tkt TKT-12]
13
+ # [--confidence 0.6] [--project P --ticket ID | --tkt TKT-12] [--shipped-at ISO]
14
14
  # bash execute.sh ship --id EXP-3 [--shipped-at ISO]
15
15
  # bash execute.sh show --id EXP-3
16
16
  # bash execute.sh list [--status planned|running|done|cancelled] [--ticket ID]
@@ -28,8 +28,9 @@ Usage:
28
28
  bash execute.sh create --hypothesis "change X → metric Y from a to b" --source gsc|ga4 --measure M
29
29
  --config /abs/path/seo-ops.config.json [filters] [--from A] [--to B]
30
30
  [--window-days 14] [--confidence 0.6] [--project P --ticket ID | --tkt TKT-12]
31
+ [--shipped-at ISO] (required when the ticket is already done but has no recorded done time)
31
32
  gsc measures: clicks impressions ctr position (filters: --page URL --query Q, --page-match/--query-match exact|contains)
32
- ga4 measures: sessions events (filters: --page /path, --event NAME, --channel all)
33
+ ga4 measures: sessions events conversions (filters: --page /path, --event NAME, --channel all)
33
34
  bash execute.sh ship --id EXP-3 [--shipped-at ISO] The change is live (automatic when the ticket is done)
34
35
  bash execute.sh show --id EXP-3 Card, baseline, result and timeline
35
36
  bash execute.sh list [--status S] [--ticket ID]
@@ -51,7 +52,7 @@ if [[ $# -gt 0 && ${1:0:1} == '{' ]]; then
51
52
  STATUS=$(printf '%s' "$J" | jq -r '.status // empty')
52
53
  REASON=$(printf '%s' "$J" | jq -r '.reason // empty')
53
54
  TICKET=$(printf '%s' "$J" | jq -r 'if (.ticket|type) == "string" then .ticket else empty end')
54
- JSON_BODY=$(printf '%s' "$J" | jq -c 'del(.action, .id, .shippedAt, .status, .reason)')
55
+ JSON_BODY=$(printf '%s' "$J" | jq -c 'del(.action, .id, .status, .reason)')
55
56
  fi
56
57
  if [[ -z "$ACTION" && $# -gt 0 && ${1:0:1} != '-' ]]; then ACTION="$1"; shift; fi
57
58
 
@@ -116,6 +117,7 @@ case "$ACTION" in
116
117
  elif $tic != "" then {ticket: {kind: "project", project: $proj, id: $tic}}
117
118
  else {} end)')
118
119
  fi
120
+ if [ -n "$SHIPPED_AT" ]; then BODY=$(printf '%s' "$BODY" | jq -c --arg at "$SHIPPED_AT" '. + {shippedAt: $at}'); fi
119
121
  api_call POST "/experiments" "$BODY" | jq "{success, experiment: (.data | ${CARD})}"
120
122
  ;;
121
123
  ship)
@@ -64,6 +64,12 @@ check "create ga4: body" "$(last '.body | tostring')" '{"hypothesis":"Shorter fo
64
64
  run '{"action":"create","hypothesis":"J","metric":{"source":"gsc","measure":"ctr","config":"/c.json"}}' >/dev/null
65
65
  check "create json: body" "$(last '.body | tostring')" '{"hypothesis":"J","metric":{"source":"gsc","measure":"ctr","config":"/c.json"}}'
66
66
 
67
+ # --- create on an already-done ticket with an explicit ship time ---
68
+ run create --hypothesis "Late card" --source gsc --measure clicks --config /c.json --project ce --ticket T-9 --shipped-at 2026-10-01T10:00:00Z >/dev/null
69
+ check "create shipped-at: body" "$(last '.body.shippedAt')" "2026-10-01T10:00:00Z"
70
+ run '{"action":"create","hypothesis":"J","metric":{"source":"gsc","measure":"ctr","config":"/c.json"},"shippedAt":"2026-10-01T10:00:00Z"}' >/dev/null
71
+ check "create json shipped-at: body" "$(last '.body.shippedAt')" "2026-10-01T10:00:00Z"
72
+
67
73
  # --- missing params / a ticket without its project ---
68
74
  check "create: missing" "$(run_err create --hypothesis h --source gsc --measure clicks | grep -c 'config')" "1"
69
75
  check "create: ticket w/o project" "$(run_err create --hypothesis h --source gsc --measure clicks --config /c --ticket T-1 | grep -c 'needs --project')" "1"
@@ -32,6 +32,9 @@ set -euo pipefail
32
32
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
33
33
  LOG_DIR="${HOME}/.crewly/logs"
34
34
  LOG_FILE="${LOG_DIR}/desktop-app-control.log"
35
+ # Where `scan` looks for installed apps. Overridable so the scan can be
36
+ # exercised against a fixture directory on machines without /Applications.
37
+ APPLICATIONS_DIR="${CREWLY_APPLICATIONS_DIR:-/Applications}"
35
38
 
36
39
  # Ensure log directory exists
37
40
  mkdir -p "$LOG_DIR"
@@ -108,7 +111,7 @@ do_scan() {
108
111
  }
109
112
 
110
113
  # Scan for Electron apps by checking framework directory
111
- for app_dir in /Applications/*.app; do
114
+ for app_dir in "$APPLICATIONS_DIR"/*.app; do
112
115
  [ ! -d "$app_dir" ] && continue
113
116
  if [ -d "$app_dir/Contents/Frameworks/Electron Framework.framework" ]; then
114
117
  local app_name
@@ -138,7 +141,7 @@ do_scan() {
138
141
  local browser port
139
142
  while IFS='|' read -r browser port; do
140
143
  [ -z "$browser" ] && continue
141
- if [ -d "/Applications/$browser.app" ]; then
144
+ if [ -d "$APPLICATIONS_DIR/$browser.app" ]; then
142
145
  local running="false"
143
146
  if pgrep -f "$browser" > /dev/null 2>&1; then
144
147
  running="true"
@@ -5,10 +5,27 @@ set -euo pipefail
5
5
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
6
  source "${SCRIPT_DIR}/../_common/lib.sh"
7
7
 
8
- INPUT=$(read_json_input "${1:-}")
8
+ # CLI flags (--session/--to, --message, --force) are accepted too: the Gemini
9
+ # safe-call guide shows the flag form.
10
+ if [ "${1:-}" != "" ] && [ "${1#--}" != "${1}" ]; then
11
+ FLAG_SESSION=""; FLAG_MESSAGE=""; FLAG_FORCE=""
12
+ while [ $# -gt 0 ]; do
13
+ case "$1" in
14
+ --session|--sessionName|--to) FLAG_SESSION="${2:-}"; shift 2 ;;
15
+ --message) FLAG_MESSAGE="${2:-}"; shift 2 ;;
16
+ --force) FLAG_FORCE="true"; shift ;;
17
+ *) error_exit "Unknown option: $1" ;;
18
+ esac
19
+ done
20
+ INPUT=$(jq -n --arg s "$FLAG_SESSION" --arg m "$FLAG_MESSAGE" --arg f "$FLAG_FORCE" \
21
+ '{sessionName: $s, message: $m} + (if $f == "true" then {force: true} else {} end)')
22
+ else
23
+ INPUT=$(read_json_input "${1:-}")
24
+ fi
9
25
  [ -z "$INPUT" ] && error_exit "Usage: execute.sh '{\"sessionName\":\"agent-session\",\"message\":\"hello\"}' or echo '{...}' | execute.sh"
10
26
 
11
- SESSION_NAME=$(printf '%s' "$INPUT" | jq -r '.sessionName // empty')
27
+ # `to` is accepted as an alias for `sessionName` (older prompt examples used it).
28
+ SESSION_NAME=$(printf '%s' "$INPUT" | jq -r '.sessionName // .to // empty')
12
29
  MESSAGE=$(printf '%s' "$INPUT" | jq -r '.message // empty')
13
30
  FORCE=$(printf '%s' "$INPUT" | jq -r '.force // empty')
14
31
  require_param "sessionName" "$SESSION_NAME"
@@ -0,0 +1,80 @@
1
+ #!/bin/bash
2
+ # Tests for the orchestrator send-message skill.
3
+ #
4
+ # Guards the input forms the orchestrator prompt teaches: JSON with
5
+ # `sessionName` (canonical), JSON with `to` (older examples), and the CLI
6
+ # flag form from the Gemini safe-call guide. `curl` is stubbed on PATH, so
7
+ # every case runs offline and records the real request the skill issues.
8
+ set -uo pipefail
9
+
10
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
+ PASS=0
12
+ FAIL=0
13
+
14
+ check() {
15
+ local name="$1" needle="$2" haystack="$3"
16
+ if printf '%s' "$haystack" | grep -qF -- "$needle"; then
17
+ PASS=$((PASS + 1)); echo " ✓ ${name}"
18
+ else
19
+ FAIL=$((FAIL + 1)); echo " ✗ ${name}"; echo " expected to contain: ${needle}"; echo " actual: ${haystack}"
20
+ fi
21
+ }
22
+
23
+ STUB_DIR="$(mktemp -d)"
24
+ cat > "$STUB_DIR/curl" << 'STUB_EOF'
25
+ #!/bin/bash
26
+ URL=""; BODY=""
27
+ while [ $# -gt 0 ]; do
28
+ case "$1" in
29
+ -d) BODY="$2"; shift 2 ;;
30
+ -X|-H|-w) shift 2 ;;
31
+ -s) shift ;;
32
+ *) URL="$1"; shift ;;
33
+ esac
34
+ done
35
+ printf '%s %s\n' "$URL" "$(printf '%s' "$BODY" | tr -d '\n ')" >> "$CURL_LOG"
36
+ printf '{"success":true}\n200'
37
+ STUB_EOF
38
+ chmod +x "$STUB_DIR/curl"
39
+ export PATH="$STUB_DIR:$PATH" CREWLY_API_URL="http://stub.invalid" CREWLY_SESSION_NAME="crewly-orc"
40
+
41
+ # Runs the skill; sets OUT (stdout+stderr) and REQ (requests sent).
42
+ run() {
43
+ CURL_LOG="$(mktemp)"; export CURL_LOG
44
+ OUT="$(bash "$SCRIPT_DIR/execute.sh" "$@" </dev/null 2>&1)" || true
45
+ REQ="$(cat "$CURL_LOG")"; rm -f "$CURL_LOG"
46
+ }
47
+
48
+ echo "=== orchestrator send-message tests ==="
49
+
50
+ run '{"sessionName":"dev-1","message":"hi"}'
51
+ check "sessionName JSON reaches /deliver for that session" "http://stub.invalid/api/terminal/dev-1/deliver" "$REQ"
52
+ check "readiness-aware delivery by default" '"waitForReady":true' "$REQ"
53
+
54
+ run '{"to":"dev-2","message":"hi"}'
55
+ check "'to' is accepted as an alias for sessionName" "/api/terminal/dev-2/deliver" "$REQ"
56
+
57
+ run --to dev-3 --message "hello there"
58
+ check "--to/--message flags work" "/api/terminal/dev-3/deliver" "$REQ"
59
+ check "flag message is sent" '"message":"hellothere"' "$REQ"
60
+
61
+ run --session dev-4 --message hi --force
62
+ check "--session and --force flags work" "/api/terminal/dev-4/deliver" "$REQ"
63
+ check "--force sends force:true" '"force":true' "$REQ"
64
+
65
+ run '{"message":"no target"}'
66
+ check "missing session is reported" "sessionName" "$OUT"
67
+ # (lib.sh sends a skill-start heartbeat; what must not happen is a delivery.)
68
+ if printf '%s' "$REQ" | grep -q "/deliver"; then
69
+ FAIL=$((FAIL + 1)); echo " ✗ missing session must not deliver anything"
70
+ else
71
+ PASS=$((PASS + 1)); echo " ✓ missing session delivers nothing"
72
+ fi
73
+
74
+ run --bogus x
75
+ check "unknown flag is refused" "Unknown option: --bogus" "$OUT"
76
+
77
+ rm -rf "$STUB_DIR"
78
+ echo ""
79
+ echo "=== Results: ${PASS} passed, ${FAIL} failed ==="
80
+ [ "$FAIL" -eq 0 ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
- "lastUpdated": "2026-10-02T23:58:51.779Z",
3
+ "lastUpdated": "2026-10-03T01:12:43.309Z",
4
4
  "cdnBaseUrl": "https://raw.githubusercontent.com/stevehuang0115/crewly/main",
5
5
  "source": "github",
6
6
  "items": [
@@ -1412,7 +1412,7 @@
1412
1412
  "name": "SEO Ops",
1413
1413
  "description": "Search Console-driven SEO operations for any site: query patterns (low-CTR top-3, near-miss 4-20, rising queries, keyword cannibalization), per-URL report cards, pre-publish SEO/AEO checks, a gated programmatic-page queue, and a live-diff gate that stops agents from removing things from live pages. Use when auditing organic search, deciding what to rewrite, or before changing a live page. For writing posts use seo-blog-writer instead.",
1414
1414
  "author": "Crewly",
1415
- "version": "1.1.0",
1415
+ "version": "1.2.0",
1416
1416
  "category": "development",
1417
1417
  "tags": [
1418
1418
  "seo",
@@ -1425,12 +1425,12 @@
1425
1425
  "downloads": 0,
1426
1426
  "rating": 0,
1427
1427
  "createdAt": "2026-09-29T01:43:29.904Z",
1428
- "updatedAt": "2026-10-02T23:58:51.779Z",
1428
+ "updatedAt": "2026-10-03T01:12:43.309Z",
1429
1429
  "source": "config/skills/agent/marketplace/seo-ops",
1430
1430
  "assets": {
1431
1431
  "archive": "config/skills/agent/marketplace/seo-ops",
1432
1432
  "checksum": "",
1433
- "sizeBytes": 122232
1433
+ "sizeBytes": 149452
1434
1434
  },
1435
1435
  "metadata": {
1436
1436
  "skillType": "claude-skill",
@@ -1448,7 +1448,8 @@
1448
1448
  "pre-publish seo check",
1449
1449
  "programmatic seo pages",
1450
1450
  "live page diff",
1451
- "experiment metric"
1451
+ "experiment metric",
1452
+ "url inspection"
1452
1453
  ],
1453
1454
  "files": [
1454
1455
  "execute.sh",
@@ -0,0 +1,110 @@
1
+ ---
2
+ name: Signal Digest
3
+ description: "Daily signal digest for a site you own as team lead: GA4 traffic and key events, Search Console opportunities (low-CTR top-3, near-miss 4-20, rising, cannibalization), the site's inbound mail and broken pages / JS errors, minus what was already tried — turned into 3-5 ranked actions the owner answers Do / Skip on one Slack card. Do opens an experiment ticket."
4
+ version: 1.1.0
5
+ category: productivity
6
+ skillType: claude-skill
7
+ assignableRoles:
8
+ - team-leader
9
+ triggers:
10
+ - daily signal digest
11
+ - daily signals
12
+ - what should we try on the site
13
+ - site opportunities
14
+ tags:
15
+ - seo
16
+ - analytics
17
+ - experiments
18
+ - owner-decisions
19
+ execution:
20
+ type: script
21
+ script:
22
+ file: execute.sh
23
+ interpreter: bash
24
+ timeoutMs: 180000
25
+ ---
26
+
27
+ # Signal Digest (team lead)
28
+
29
+ One run per site per day (#987, `specs/2026-10-03-signal-digest.md`):
30
+
31
+ 1. **collect** — gathers the signals and drafts actions.
32
+ 2. **you decide** — keep the 3–5 actions most worth the owner's tap, rewrite them in plain words,
33
+ add your own (e.g. a question the inbox keeps asking → an FAQ section).
34
+ 3. **propose** — the owner gets **one card**: each action with **Do** / **Skip**.
35
+ - **Do** opens an experiment ticket in the site's project and, when the action names an
36
+ `experiment` metric, an **experiment card** (#986) linked to it: the baseline is captured when
37
+ the ticket is done and the result is measured after 14 days, automatically. You get a
38
+ `[SIGNAL DIGEST]` message with both ids. Ship it and close the ticket.
39
+ - **Skip** keeps that action off your list for 30 days. A Do keeps it off for 90.
40
+ - Unanswered actions are replaced by your next digest (you may propose them again).
41
+
42
+ ## Setup (once per site)
43
+
44
+ The config is the site's **seo-ops** config plus a `signalDigest` section — copy
45
+ `signal-digest.config.example.json`. Google access is seo-ops's service account
46
+ (`SEO_OPS_GOOGLE_CREDENTIALS`, read-only: Search Console user + GA4 Viewer).
47
+
48
+ | `signalDigest` key | Meaning |
49
+ |---|---|
50
+ | `site` | Site name on the card and in the history (default: host of `siteUrl`) |
51
+ | `project` | Project the Do tickets go into (name or id). Without it a Do opens no ticket |
52
+ | `days` | Window, compared with the window before it (default 7) |
53
+ | `ga4.conversionEvents` | Key events that count as conversions (default: all key events) |
54
+ | `inbox.query` / `.account` / `.max` | Gmail search for the site's inbound requests (Google connector) |
55
+ | `errors.checkSitemap` / `.maxUrls` | Fetch up to N sitemap pages and report the ones not answering 200 (default on, 60) |
56
+ | `errors.url` or `errors.command` | JS errors as JSON: `[{"message","count","url"}]` or `{"errors":[…]}` |
57
+ | `experimentLog` | Extra Markdown experiment log; a draft whose query/page it mentions is dropped (experiment cards are always checked) |
58
+ | `thresholds` | `ga4DropPct` (20), `ga4MinPrevSessions` (50), `ga4MinPrevKeyEvents` (5) |
59
+
60
+ Daily run: `bash execute.sh schedule --config <file> [--cron "0 8 * * *"] [--timezone America/New_York]`
61
+ prints the cron task; hand it to the orchestrator to create with `create-cron`.
62
+
63
+ ## Commands
64
+
65
+ ```bash
66
+ bash execute.sh collect --config ce.signal.json # JSON: signals, alreadyTried, candidates
67
+ bash execute.sh propose --config ce.signal.json --actions actions.json
68
+ ```
69
+
70
+ `collect` prints `sources` (ok / not configured / error: why), the signals (`ga4`, `gsc`,
71
+ `inbox`, `errors`), `alreadyTried` (dropped drafts and why: the owner's earlier Do / Skip, an
72
+ experiment card on the same query or page, or the experiment log), `pendingOnOwner` and up to 10
73
+ `candidates`, best first. GA4 respects seo-ops' `ga4HostName`. The sitemap check takes a different
74
+ slice of `errors.maxUrls` pages each day, so the whole sitemap is covered over a few days.
75
+
76
+ `collect` also reports the source statuses to Crewly (`sourceReport` in the output). The owner is
77
+ told **once** when a source starts failing and once when it works again; the digest card shows
78
+ each source's status. So never post about a failing source yourself. Exit `1` when no source
79
+ could be examined: stop there and do not propose from nothing.
80
+
81
+ `--actions` is a JSON array (file or inline) of 3–5 actions, best first:
82
+
83
+ ```json
84
+ [{"key":"gsc:low-ctr:h1b visa fee","source":"gsc",
85
+ "signal":"'h1b visa fee' ranks #2 with 4% CTR on 900 impressions (7 days)",
86
+ "proposal":"Rewrite the title and description of /h1b-fee to answer the fee question",
87
+ "expectedEffect":"CTR 4% → ~16%: about +100 clicks a week",
88
+ "effort":"S — 1 h","metric":"GSC CTR for 'h1b visa fee'",
89
+ "experiment":{"source":"gsc","measure":"ctr","query":"h1b visa fee","page":"https://visa.careerengine.us/h1b-fee"}}]
90
+ ```
91
+
92
+ - `key` is the action's identity across days. Keep the draft's key when you keep its action;
93
+ for your own, use `<source>:<kind>:<subject>`.
94
+ - `source`: `ga4` | `gsc` | `inbox` | `errors` | `other`.
95
+ - Lengths: signal ≤ 400, proposal ≤ 200, expectedEffect ≤ 240, effort ≤ 60 characters.
96
+ - `experiment` (optional, keep the draft's): the seo-ops metric that measures it —
97
+ `source` gsc (`clicks` / `impressions` / `ctr` / `position`, filters `query`, `page`) or
98
+ ga4 (`sessions` / `events`, `event`, `channel`). Leave it out for fixes that move no metric
99
+ (a broken page, a JS error).
100
+
101
+ `propose` answers `{"success":true,"digestId":"SD-4","card":"posted"}`. A `409` lists actions
102
+ the owner already decided — replace them and propose again. One card a day: while today's
103
+ digest (the last 20 hours) still has open actions, proposing the same actions returns it and
104
+ different ones get a `409` — do not post a second card.
105
+
106
+ ## Rules
107
+
108
+ - Never propose what `alreadyTried` lists, and never more than 5 actions.
109
+ - Each action states signal → proposal → expected effect → effort, with a number when there is one.
110
+ - This skill only reads Google and Gmail; it never changes the site.
@@ -0,0 +1,173 @@
1
+ #!/bin/bash
2
+ # =============================================================================
3
+ # signal-digest — a site's daily signals → 3–5 actions → one owner card (#987)
4
+ #
5
+ # collect GA4 + Search Console + the site inbox + broken pages / JS errors,
6
+ # minus what was already tried; prints JSON with draft actions.
7
+ # Reports each source's status to Crewly, which tells the owner
8
+ # once when a source starts or stops failing.
9
+ # propose send 3–5 actions; the owner gets one Slack card with Do / Skip
10
+ # per action (Do opens an experiment ticket in the site's project).
11
+ # schedule print the daily cron task for the orchestrator to create.
12
+ #
13
+ # Usage:
14
+ # bash execute.sh collect --config site.signal.json [--days 7]
15
+ # bash execute.sh propose --config site.signal.json --actions actions.json
16
+ # bash execute.sh schedule --config site.signal.json [--cron "0 8 * * *"] [--timezone America/New_York]
17
+ # bash execute.sh '{"command":"collect","config":"site.signal.json"}'
18
+ # =============================================================================
19
+ set -euo pipefail
20
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
21
+ source "${SCRIPT_DIR}/../_common/lib.sh"
22
+
23
+ DEFAULT_CRON="0 8 * * *"
24
+ DEFAULT_TIMEZONE="America/New_York"
25
+
26
+ print_usage() {
27
+ cat <<'EOF_USAGE'
28
+ Usage:
29
+ bash execute.sh collect --config site.signal.json [--days 7]
30
+ bash execute.sh propose --config site.signal.json --actions actions.json (file, or inline JSON)
31
+ bash execute.sh schedule --config site.signal.json [--cron "0 8 * * *"] [--timezone America/New_York]
32
+ bash execute.sh '{"command":"collect","config":"site.signal.json"}'
33
+
34
+ The config is the site's seo-ops config plus a "signalDigest" section
35
+ (see signal-digest.config.example.json).
36
+ EOF_USAGE
37
+ }
38
+
39
+ COMMAND=""; CONFIG=""; DAYS=""; ACTIONS=""; CRON=""; TIMEZONE=""
40
+ if [[ $# -gt 0 && ${1:0:1} == '{' ]]; then
41
+ INPUT=$(read_json_input "$1")
42
+ shift || true
43
+ COMMAND=$(printf '%s' "$INPUT" | jq -r '.command // empty')
44
+ CONFIG=$(printf '%s' "$INPUT" | jq -r '.config // empty')
45
+ DAYS=$(printf '%s' "$INPUT" | jq -r '.days // empty')
46
+ ACTIONS=$(printf '%s' "$INPUT" | jq -r 'if .actions == null then empty elif (.actions | type) == "string" then .actions else (.actions | tojson) end')
47
+ CRON=$(printf '%s' "$INPUT" | jq -r '.cron // empty')
48
+ TIMEZONE=$(printf '%s' "$INPUT" | jq -r '.timezone // empty')
49
+ elif [[ $# -gt 0 && ${1:0:1} != '-' ]]; then
50
+ COMMAND="$1"
51
+ shift
52
+ fi
53
+ while [[ $# -gt 0 ]]; do
54
+ case "$1" in
55
+ --config|-c) [ $# -ge 2 ] || error_exit "--config requires a value"; CONFIG="$2"; shift 2 ;;
56
+ --days) [ $# -ge 2 ] || error_exit "--days requires a value"; DAYS="$2"; shift 2 ;;
57
+ --actions) [ $# -ge 2 ] || error_exit "--actions requires a value"; ACTIONS="$2"; shift 2 ;;
58
+ --cron) [ $# -ge 2 ] || error_exit "--cron requires a value"; CRON="$2"; shift 2 ;;
59
+ --timezone) [ $# -ge 2 ] || error_exit "--timezone requires a value"; TIMEZONE="$2"; shift 2 ;;
60
+ --help|-h) print_usage; exit 0 ;;
61
+ *) error_exit "Unknown option: $1" ;;
62
+ esac
63
+ done
64
+ [ -n "$COMMAND" ] || { print_usage; exit 1; }
65
+ require_param "config (--config)" "$CONFIG"
66
+ [ -f "$CONFIG" ] || error_exit "Config file not found: $CONFIG"
67
+ jq -e 'type == "object"' "$CONFIG" >/dev/null 2>&1 || error_exit "Config file $CONFIG is not a JSON object"
68
+
69
+ # The site name: signalDigest.site, else the host of siteUrl.
70
+ SITE=$(jq -r '.signalDigest.site // ((.siteUrl // "") | sub("^[a-zA-Z]+://"; "") | sub("/.*$"; ""))' "$CONFIG")
71
+ [ -n "$SITE" ] || error_exit "Config needs signalDigest.site (or siteUrl) to name the site"
72
+ PROJECT=$(jq -r '.signalDigest.project // empty' "$CONFIG")
73
+ uri() { jq -rn --arg v "$1" '$v|@uri'; }
74
+
75
+ # api_call may print a one-line warning to stderr; the answer is the last line.
76
+ call() {
77
+ local out
78
+ out=$(api_call "$@" 2>&1) || { printf '%s\n' "$out" | tail -n 1; return 1; }
79
+ printf '%s\n' "$out" | tail -n 1
80
+ }
81
+
82
+ case "$COMMAND" in
83
+ collect)
84
+ command -v python3 >/dev/null 2>&1 || error_exit "python3 (>= 3.8) is required"
85
+ WORK=$(mktemp -d)
86
+ trap 'rm -rf "$WORK"' EXIT
87
+ ARGS=(collect --config "$CONFIG")
88
+ [ -n "$DAYS" ] && ARGS+=(--days "$DAYS")
89
+ # History: what the owner already chose Do / Skip on for this site.
90
+ if HISTORY=$(call GET "/signal-digests/history?site=$(uri "$SITE")"); then
91
+ printf '%s' "$HISTORY" > "$WORK/history.json"
92
+ ARGS+=(--history "$WORK/history.json")
93
+ else
94
+ echo "{\"warning\":\"could not read the site history from Crewly; already-decided actions are not filtered out\"}" >&2
95
+ fi
96
+ # Experiment cards (#986): drafts their query / page already covers are dropped.
97
+ if EXPERIMENTS=$(call GET "/experiments"); then
98
+ printf '%s' "$EXPERIMENTS" > "$WORK/experiments.json"
99
+ ARGS+=(--experiments "$WORK/experiments.json")
100
+ else
101
+ echo "{\"warning\":\"could not read the experiment cards from Crewly; drafts they cover are not filtered out\"}" >&2
102
+ fi
103
+ # Inbox: the site's inbound requests (signalDigest.inbox.query), via Gmail.
104
+ INBOX_QUERY=$(jq -r '.signalDigest.inbox.query // empty' "$CONFIG")
105
+ if [ -n "$INBOX_QUERY" ]; then
106
+ INBOX_ACCOUNT=$(jq -r '.signalDigest.inbox.account // empty' "$CONFIG")
107
+ INBOX_MAX=$(jq -r '.signalDigest.inbox.max // 20' "$CONFIG")
108
+ [ -n "$INBOX_ACCOUNT" ] && export CREWLY_GOOGLE_ACCOUNT="$INBOX_ACCOUNT"
109
+ if INBOX=$(call GET "/google/gmail/search?q=$(uri "$INBOX_QUERY")&max=$(uri "$INBOX_MAX")"); then
110
+ printf '%s' "$INBOX" | jq -c '{query: .data.query, count: .data.count, messages: [.data.messages[]? | {from, subject, date, snippet}]}' > "$WORK/inbox.json"
111
+ else
112
+ printf '%s' "$INBOX" | jq -c '{success: false, reason: (.details.error // .error // "unknown"), message: (.details.message // .message // "")}' > "$WORK/inbox.json" 2>/dev/null \
113
+ || jq -n '{success: false, reason: "unreadable answer"}' > "$WORK/inbox.json"
114
+ fi
115
+ ARGS+=(--inbox "$WORK/inbox.json")
116
+ fi
117
+ set +e
118
+ RESULT=$(python3 "$SCRIPT_DIR/signal_digest.py" "${ARGS[@]}")
119
+ CODE=$?
120
+ set -e
121
+ [ -n "$RESULT" ] || exit "$CODE"
122
+ # Source status → Crewly. The owner hears once when a source starts or
123
+ # stops failing; nothing is posted on the days nothing changes.
124
+ REPORT='{"sent":false}'
125
+ SOURCES=$(printf '%s' "$RESULT" | jq -c '.sources // empty' 2>/dev/null || true)
126
+ if [ -n "$SOURCES" ]; then
127
+ BODY=$(jq -cn --arg site "$SITE" --argjson sources "$SOURCES" '{site: $site, sources: $sources}')
128
+ if ANSWER=$(call POST "/signal-digests/sources" "$BODY"); then
129
+ REPORT=$(printf '%s' "$ANSWER" | jq -c '{sent: true, started: (.data.started // []), stopped: (.data.stopped // []), ownerTold: (.data.notified // false)}' 2>/dev/null || echo '{"sent":true}')
130
+ else
131
+ echo "{\"warning\":\"could not report the source status to Crewly; the owner is not told about source failures\"}" >&2
132
+ fi
133
+ fi
134
+ printf '%s' "$RESULT" | jq --argjson report "$REPORT" '. + {sourceReport: $report}' 2>/dev/null || printf '%s\n' "$RESULT"
135
+ exit "$CODE"
136
+ ;;
137
+
138
+ propose)
139
+ require_param "actions (--actions)" "$ACTIONS"
140
+ if [ -f "$ACTIONS" ]; then ACTIONS_JSON=$(cat "$ACTIONS"); else ACTIONS_JSON="$ACTIONS"; fi
141
+ ITEMS=$(printf '%s' "$ACTIONS_JSON" | jq -c 'if type == "array" then . elif type == "object" and (.items | type) == "array" then .items elif type == "object" and (.actions | type) == "array" then .actions else error("expected an array of actions") end' 2>/dev/null) \
142
+ || error_exit "--actions must be a JSON array of actions (or {\"items\": [...]}), as a file or inline"
143
+ # The absolute config lets a Do create the action's experiment card (#986).
144
+ CONFIG_ABS="$(cd "$(dirname "$CONFIG")" && pwd)/$(basename "$CONFIG")"
145
+ BODY=$(jq -cn --arg site "$SITE" --arg project "$PROJECT" --arg config "$CONFIG_ABS" --argjson items "$ITEMS" \
146
+ '{site: $site, config: $config, items: [$items[] | {key, source, signal, proposal, expectedEffect, effort}
147
+ + (if .metric then {metric} else {} end) + (if .experiment then {experiment} else {} end)]}
148
+ + (if $project != "" then {project: $project} else {} end)')
149
+ if ! RESPONSE=$(call POST "/signal-digests" "$BODY"); then
150
+ printf '%s' "$RESPONSE" | jq -c '{success: false, error: (.details.error // .error // .details // "unknown")}' 2>/dev/null || jq -n --arg r "$RESPONSE" '{success: false, error: $r}'
151
+ exit 1
152
+ fi
153
+ printf '%s' "$RESPONSE" | jq -c '{success: true, digestId: .data.id, site: .data.site, actions: (.data.items | length)}
154
+ + (if .data.card then {card: "posted"} else {card: "not posted", postError: .data.postError} end)'
155
+ ;;
156
+
157
+ schedule)
158
+ # Cron tasks are created by the orchestrator (or the owner), not by a lead:
159
+ # print the exact create-cron call to hand over.
160
+ [ -n "${CREWLY_SESSION_NAME:-}" ] || error_exit "CREWLY_SESSION_NAME is not set: run this from your agent session"
161
+ TEAM_ID=$(resolve_team_id) || error_exit "Could not find the team of ${CREWLY_SESSION_NAME}"
162
+ CONFIG_ABS="$(cd "$(dirname "$CONFIG")" && pwd)/$(basename "$CONFIG")"
163
+ TASK="Daily signal digest for ${SITE}: run \`bash ${SCRIPT_DIR}/execute.sh collect --config ${CONFIG_ABS}\`, pick the 3-5 actions most worth the owner's tap (rewrite the drafts as needed), then run \`bash ${SCRIPT_DIR}/execute.sh propose --config ${CONFIG_ABS} --actions <file>\`. If no source could be examined, stop there: the owner is told once when a source starts or stops failing, so post nothing about it."
164
+ CRON_JSON=$(jq -cn --arg cron "${CRON:-$DEFAULT_CRON}" --arg tz "${TIMEZONE:-$DEFAULT_TIMEZONE}" --arg agent "$CREWLY_SESSION_NAME" --arg team "$TEAM_ID" --arg task "$TASK" \
165
+ '{cronExpression: $cron, timezone: $tz, targetAgent: $agent, targetTeamId: $team, taskDescription: $task}')
166
+ jq -cn --argjson cron "$CRON_JSON" '{success: true, createCron: $cron,
167
+ next: "Cron tasks are created by the orchestrator: send it this createCron object and ask it to run create-cron with it (or the owner can add it under Schedules)."}'
168
+ ;;
169
+
170
+ *)
171
+ error_exit "Unknown command: ${COMMAND} (collect | propose | schedule)"
172
+ ;;
173
+ esac