crewly 1.20.143 → 1.20.145

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 (232) hide show
  1. package/config/constants.ts +59 -0
  2. package/config/index.ts +2 -0
  3. package/config/roles/orchestrator/prompt.md +9 -0
  4. package/config/skills/orchestrator/delegate-task/execute.sh +11 -0
  5. package/config/skills/orchestrator/delegate-task/execute.test.sh +38 -0
  6. package/config/skills/orchestrator/harness-login/SKILL.md +88 -0
  7. package/config/skills/orchestrator/harness-login/execute.sh +75 -0
  8. package/config/skills/orchestrator/harness-login/execute.test.sh +72 -0
  9. package/config/skills/orchestrator/reply-chat/SKILL.md +11 -1
  10. package/config/skills/orchestrator/reply-chat/execute.sh +13 -1
  11. package/config/skills/orchestrator/reply-slack/SKILL.md +1 -0
  12. package/config/skills/orchestrator/reply-slack/execute.sh +11 -2
  13. package/dist/backend/backend/src/constants.d.ts +55 -0
  14. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  15. package/dist/backend/backend/src/constants.js +36 -1
  16. package/dist/backend/backend/src/constants.js.map +1 -1
  17. package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts.map +1 -1
  18. package/dist/backend/backend/src/controllers/chat/chat.controller.js +36 -1
  19. package/dist/backend/backend/src/controllers/chat/chat.controller.js.map +1 -1
  20. package/dist/backend/backend/src/controllers/harness/harness.routes.d.ts +1 -0
  21. package/dist/backend/backend/src/controllers/harness/harness.routes.d.ts.map +1 -1
  22. package/dist/backend/backend/src/controllers/harness/harness.routes.js +3 -0
  23. package/dist/backend/backend/src/controllers/harness/harness.routes.js.map +1 -1
  24. package/dist/backend/backend/src/controllers/harness/owner-login.controller.d.ts +61 -0
  25. package/dist/backend/backend/src/controllers/harness/owner-login.controller.d.ts.map +1 -0
  26. package/dist/backend/backend/src/controllers/harness/owner-login.controller.js +133 -0
  27. package/dist/backend/backend/src/controllers/harness/owner-login.controller.js.map +1 -0
  28. package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts.map +1 -1
  29. package/dist/backend/backend/src/controllers/slack/slack.controller.js +69 -7
  30. package/dist/backend/backend/src/controllers/slack/slack.controller.js.map +1 -1
  31. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts +4 -1
  32. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts.map +1 -1
  33. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js +9 -2
  34. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js.map +1 -1
  35. package/dist/backend/backend/src/index.d.ts +8 -0
  36. package/dist/backend/backend/src/index.d.ts.map +1 -1
  37. package/dist/backend/backend/src/index.js +75 -3
  38. package/dist/backend/backend/src/index.js.map +1 -1
  39. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  40. package/dist/backend/backend/src/services/agent/agent-registration.service.js +28 -1
  41. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  42. package/dist/backend/backend/src/services/agent/codex-runtime.service.d.ts +11 -1
  43. package/dist/backend/backend/src/services/agent/codex-runtime.service.d.ts.map +1 -1
  44. package/dist/backend/backend/src/services/agent/codex-runtime.service.js +18 -0
  45. package/dist/backend/backend/src/services/agent/codex-runtime.service.js.map +1 -1
  46. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.d.ts +12 -0
  47. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.d.ts.map +1 -1
  48. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.js +18 -3
  49. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.js.map +1 -1
  50. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.d.ts +29 -0
  51. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.d.ts.map +1 -1
  52. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js +48 -0
  53. package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -1
  54. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
  55. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js +1 -1
  56. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
  57. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts +15 -0
  58. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
  59. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +20 -0
  60. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
  61. package/dist/backend/backend/src/services/harness/harness-relogin.service.d.ts +147 -5
  62. package/dist/backend/backend/src/services/harness/harness-relogin.service.d.ts.map +1 -1
  63. package/dist/backend/backend/src/services/harness/harness-relogin.service.js +210 -20
  64. package/dist/backend/backend/src/services/harness/harness-relogin.service.js.map +1 -1
  65. package/dist/backend/backend/src/services/harness/owner-login-request.d.ts +87 -0
  66. package/dist/backend/backend/src/services/harness/owner-login-request.d.ts.map +1 -0
  67. package/dist/backend/backend/src/services/harness/owner-login-request.js +191 -0
  68. package/dist/backend/backend/src/services/harness/owner-login-request.js.map +1 -0
  69. package/dist/backend/backend/src/services/orc/orc-reply-route.service.d.ts +217 -0
  70. package/dist/backend/backend/src/services/orc/orc-reply-route.service.d.ts.map +1 -0
  71. package/dist/backend/backend/src/services/orc/orc-reply-route.service.js +300 -0
  72. package/dist/backend/backend/src/services/orc/orc-reply-route.service.js.map +1 -0
  73. package/dist/backend/backend/src/services/reconciler/reconcile-rules.d.ts +32 -2
  74. package/dist/backend/backend/src/services/reconciler/reconcile-rules.d.ts.map +1 -1
  75. package/dist/backend/backend/src/services/reconciler/reconcile-rules.js +59 -5
  76. package/dist/backend/backend/src/services/reconciler/reconcile-rules.js.map +1 -1
  77. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts +4 -2
  78. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts.map +1 -1
  79. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js +6 -3
  80. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js.map +1 -1
  81. package/dist/backend/backend/src/services/slack/slack-relogin-dm.service.d.ts +68 -9
  82. package/dist/backend/backend/src/services/slack/slack-relogin-dm.service.d.ts.map +1 -1
  83. package/dist/backend/backend/src/services/slack/slack-relogin-dm.service.js +121 -11
  84. package/dist/backend/backend/src/services/slack/slack-relogin-dm.service.js.map +1 -1
  85. package/dist/backend/backend/src/services/system/auto-update.service.d.ts +292 -0
  86. package/dist/backend/backend/src/services/system/auto-update.service.d.ts.map +1 -0
  87. package/dist/backend/backend/src/services/system/auto-update.service.js +590 -0
  88. package/dist/backend/backend/src/services/system/auto-update.service.js.map +1 -0
  89. package/dist/backend/backend/src/services/system/auto-update.utils.d.ts +265 -0
  90. package/dist/backend/backend/src/services/system/auto-update.utils.d.ts.map +1 -0
  91. package/dist/backend/backend/src/services/system/auto-update.utils.js +397 -0
  92. package/dist/backend/backend/src/services/system/auto-update.utils.js.map +1 -0
  93. package/dist/backend/backend/src/services/system/version-check.service.d.ts +15 -1
  94. package/dist/backend/backend/src/services/system/version-check.service.d.ts.map +1 -1
  95. package/dist/backend/backend/src/services/system/version-check.service.js +21 -2
  96. package/dist/backend/backend/src/services/system/version-check.service.js.map +1 -1
  97. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +7 -1
  98. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  99. package/dist/backend/backend/src/services/task-pool/task-pool.service.js +14 -2
  100. package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  101. package/dist/backend/backend/src/services/v3/cascade-request-status.d.ts.map +1 -1
  102. package/dist/backend/backend/src/services/v3/cascade-request-status.js +16 -1
  103. package/dist/backend/backend/src/services/v3/cascade-request-status.js.map +1 -1
  104. package/dist/backend/backend/src/services/v3/request-completion.d.ts +128 -0
  105. package/dist/backend/backend/src/services/v3/request-completion.d.ts.map +1 -0
  106. package/dist/backend/backend/src/services/v3/request-completion.js +311 -0
  107. package/dist/backend/backend/src/services/v3/request-completion.js.map +1 -0
  108. package/dist/backend/backend/src/services/v3/request-decompose.subscriber.d.ts.map +1 -1
  109. package/dist/backend/backend/src/services/v3/request-decompose.subscriber.js +3 -0
  110. package/dist/backend/backend/src/services/v3/request-decompose.subscriber.js.map +1 -1
  111. package/dist/backend/backend/src/services/v3/request-status-update.subscriber.d.ts.map +1 -1
  112. package/dist/backend/backend/src/services/v3/request-status-update.subscriber.js +17 -3
  113. package/dist/backend/backend/src/services/v3/request-status-update.subscriber.js.map +1 -1
  114. package/dist/backend/backend/src/services/v3/v3-data.service.d.ts +8 -0
  115. package/dist/backend/backend/src/services/v3/v3-data.service.d.ts.map +1 -1
  116. package/dist/backend/backend/src/services/v3/v3-data.service.js +11 -1
  117. package/dist/backend/backend/src/services/v3/v3-data.service.js.map +1 -1
  118. package/dist/backend/backend/src/types/settings.types.d.ts +8 -0
  119. package/dist/backend/backend/src/types/settings.types.d.ts.map +1 -1
  120. package/dist/backend/backend/src/types/settings.types.js +4 -0
  121. package/dist/backend/backend/src/types/settings.types.js.map +1 -1
  122. package/dist/backend/backend/src/utils/agent-reply-filter.utils.d.ts +75 -0
  123. package/dist/backend/backend/src/utils/agent-reply-filter.utils.d.ts.map +1 -0
  124. package/dist/backend/backend/src/utils/agent-reply-filter.utils.js +127 -0
  125. package/dist/backend/backend/src/utils/agent-reply-filter.utils.js.map +1 -0
  126. package/dist/backend/build-info.json +2 -2
  127. package/dist/backend/config/constants.d.ts +56 -0
  128. package/dist/backend/config/constants.d.ts.map +1 -1
  129. package/dist/backend/config/constants.js +57 -0
  130. package/dist/backend/config/constants.js.map +1 -1
  131. package/dist/backend/config/index.d.ts +2 -2
  132. package/dist/backend/config/index.d.ts.map +1 -1
  133. package/dist/backend/config/index.js +2 -2
  134. package/dist/backend/config/index.js.map +1 -1
  135. package/dist/cli/backend/src/constants.d.ts +55 -0
  136. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  137. package/dist/cli/backend/src/constants.js +36 -1
  138. package/dist/cli/backend/src/constants.js.map +1 -1
  139. package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  140. package/dist/cli/backend/src/services/agent/agent-registration.service.js +28 -1
  141. package/dist/cli/backend/src/services/agent/agent-registration.service.js.map +1 -1
  142. package/dist/cli/backend/src/services/agent/codex-runtime.service.d.ts +11 -1
  143. package/dist/cli/backend/src/services/agent/codex-runtime.service.d.ts.map +1 -1
  144. package/dist/cli/backend/src/services/agent/codex-runtime.service.js +18 -0
  145. package/dist/cli/backend/src/services/agent/codex-runtime.service.js.map +1 -1
  146. package/dist/cli/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.d.ts +12 -0
  147. package/dist/cli/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.d.ts.map +1 -1
  148. package/dist/cli/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.js +18 -3
  149. package/dist/cli/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.js.map +1 -1
  150. package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.d.ts +29 -0
  151. package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.d.ts.map +1 -1
  152. package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.js +48 -0
  153. package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -1
  154. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
  155. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js +1 -1
  156. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
  157. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts +15 -0
  158. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
  159. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +20 -0
  160. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
  161. package/dist/cli/backend/src/services/harness/harness-relogin.service.d.ts +147 -5
  162. package/dist/cli/backend/src/services/harness/harness-relogin.service.d.ts.map +1 -1
  163. package/dist/cli/backend/src/services/harness/harness-relogin.service.js +210 -20
  164. package/dist/cli/backend/src/services/harness/harness-relogin.service.js.map +1 -1
  165. package/dist/cli/backend/src/services/harness/owner-login-request.d.ts +87 -0
  166. package/dist/cli/backend/src/services/harness/owner-login-request.d.ts.map +1 -0
  167. package/dist/cli/backend/src/services/harness/owner-login-request.js +191 -0
  168. package/dist/cli/backend/src/services/harness/owner-login-request.js.map +1 -0
  169. package/dist/cli/backend/src/services/orc/orc-reply-route.service.d.ts +217 -0
  170. package/dist/cli/backend/src/services/orc/orc-reply-route.service.d.ts.map +1 -0
  171. package/dist/cli/backend/src/services/orc/orc-reply-route.service.js +300 -0
  172. package/dist/cli/backend/src/services/orc/orc-reply-route.service.js.map +1 -0
  173. package/dist/cli/backend/src/services/system/auto-update.utils.d.ts +265 -0
  174. package/dist/cli/backend/src/services/system/auto-update.utils.d.ts.map +1 -0
  175. package/dist/cli/backend/src/services/system/auto-update.utils.js +397 -0
  176. package/dist/cli/backend/src/services/system/auto-update.utils.js.map +1 -0
  177. package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +7 -1
  178. package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  179. package/dist/cli/backend/src/services/task-pool/task-pool.service.js +14 -2
  180. package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  181. package/dist/cli/backend/src/services/v3/request-completion.d.ts +128 -0
  182. package/dist/cli/backend/src/services/v3/request-completion.d.ts.map +1 -0
  183. package/dist/cli/backend/src/services/v3/request-completion.js +311 -0
  184. package/dist/cli/backend/src/services/v3/request-completion.js.map +1 -0
  185. package/dist/cli/backend/src/services/v3/v3-data.service.d.ts +8 -0
  186. package/dist/cli/backend/src/services/v3/v3-data.service.d.ts.map +1 -1
  187. package/dist/cli/backend/src/services/v3/v3-data.service.js +11 -1
  188. package/dist/cli/backend/src/services/v3/v3-data.service.js.map +1 -1
  189. package/dist/cli/backend/src/types/settings.types.d.ts +8 -0
  190. package/dist/cli/backend/src/types/settings.types.d.ts.map +1 -1
  191. package/dist/cli/backend/src/types/settings.types.js +4 -0
  192. package/dist/cli/backend/src/types/settings.types.js.map +1 -1
  193. package/dist/cli/backend/src/utils/agent-reply-filter.utils.d.ts +75 -0
  194. package/dist/cli/backend/src/utils/agent-reply-filter.utils.d.ts.map +1 -0
  195. package/dist/cli/backend/src/utils/agent-reply-filter.utils.js +127 -0
  196. package/dist/cli/backend/src/utils/agent-reply-filter.utils.js.map +1 -0
  197. package/dist/cli/cli/src/commands/start.d.ts.map +1 -1
  198. package/dist/cli/cli/src/commands/start.js +14 -3
  199. package/dist/cli/cli/src/commands/start.js.map +1 -1
  200. package/dist/cli/cli/src/commands/update-status.d.ts +85 -0
  201. package/dist/cli/cli/src/commands/update-status.d.ts.map +1 -0
  202. package/dist/cli/cli/src/commands/update-status.js +162 -0
  203. package/dist/cli/cli/src/commands/update-status.js.map +1 -0
  204. package/dist/cli/cli/src/constants.d.ts +1 -1
  205. package/dist/cli/cli/src/constants.d.ts.map +1 -1
  206. package/dist/cli/cli/src/constants.js +1 -1
  207. package/dist/cli/cli/src/constants.js.map +1 -1
  208. package/dist/cli/cli/src/index.js +7 -0
  209. package/dist/cli/cli/src/index.js.map +1 -1
  210. package/dist/cli/cli/src/utils/backend-respawn.d.ts +50 -0
  211. package/dist/cli/cli/src/utils/backend-respawn.d.ts.map +1 -0
  212. package/dist/cli/cli/src/utils/backend-respawn.js +59 -0
  213. package/dist/cli/cli/src/utils/backend-respawn.js.map +1 -0
  214. package/dist/cli/config/constants.d.ts +56 -0
  215. package/dist/cli/config/constants.d.ts.map +1 -1
  216. package/dist/cli/config/constants.js +57 -0
  217. package/dist/cli/config/constants.js.map +1 -1
  218. package/dist/cli/config/index.d.ts +2 -2
  219. package/dist/cli/config/index.d.ts.map +1 -1
  220. package/dist/cli/config/index.js +2 -2
  221. package/dist/cli/config/index.js.map +1 -1
  222. package/frontend/dist/assets/{index-e05af897.js → index-71670b91.js} +22 -22
  223. package/frontend/dist/index.html +1 -1
  224. package/package.json +1 -1
  225. package/packages/crewly-agent/src/runtime/agent-runner.service.test.ts +39 -0
  226. package/packages/crewly-agent/src/runtime/agent-runner.service.ts +17 -17
  227. package/packages/crewly-agent/src/runtime/interactive-login-guard.test.ts +60 -0
  228. package/packages/crewly-agent/src/runtime/interactive-login-guard.ts +76 -0
  229. package/packages/crewly-agent/src/runtime/reply-tool-calls.test.ts +53 -0
  230. package/packages/crewly-agent/src/runtime/reply-tool-calls.ts +76 -0
  231. package/packages/crewly-agent/src/runtime/tool-registry.test.ts +8 -0
  232. package/packages/crewly-agent/src/runtime/tool-registry.ts +14 -0
@@ -1046,6 +1046,65 @@ export const VERSION_CHECK_CONSTANTS = {
1046
1046
  REQUEST_TIMEOUT_MS: 5000,
1047
1047
  } as const;
1048
1048
 
1049
+ // ========================= AUTO-UPDATE CONSTANTS =========================
1050
+
1051
+ /**
1052
+ * Automatic self-update (specs/auto-update.md).
1053
+ *
1054
+ * The backend's AutoUpdateService checks npm for a newer `crewly`, waits for
1055
+ * a quiet window, installs into the prefix the running copy lives in,
1056
+ * verifies the installed version and restarts gracefully. Shared with the
1057
+ * CLI (`crewly update-status`) and `crewly start` (which marks itself as the
1058
+ * restart supervisor for the backend it spawns).
1059
+ */
1060
+ export const AUTO_UPDATE_CONSTANTS = {
1061
+ /** Interval between registry checks (ms) — 3 hours */
1062
+ CHECK_INTERVAL_MS: 3 * 60 * 60 * 1000,
1063
+ /** First check after boot (ms) — 10 minutes */
1064
+ FIRST_CHECK_DELAY_MS: 10 * 60 * 1000,
1065
+ /** A registry answer older than this is re-fetched for the auto-update decision (ms) */
1066
+ REGISTRY_MAX_AGE_MS: 30 * 60 * 1000,
1067
+ /** Gap between the two quiet-window probes (ms) */
1068
+ QUIET_CONFIRM_MS: 60 * 1000,
1069
+ /** Retry interval while agents are busy (ms) — 5 minutes */
1070
+ BUSY_RETRY_MS: 5 * 60 * 1000,
1071
+ /**
1072
+ * After deferring this long, an agent whose workingStatus is stuck at
1073
+ * in_progress no longer blocks the update; only turns actually in flight
1074
+ * do (the restart drain handles those anyway) (ms) — 24 hours
1075
+ */
1076
+ MAX_BUSY_DEFER_MS: 24 * 60 * 60 * 1000,
1077
+ /** Back-off after a failed install or verify (ms) — 6 hours */
1078
+ FAILURE_BACKOFF_MS: 6 * 60 * 60 * 1000,
1079
+ /** Consecutive failures before the owner is told (once per target version) */
1080
+ FAILURE_NOTIFY_THRESHOLD: 2,
1081
+ /** Upper bound for one `npm install -g` (ms) — 10 minutes */
1082
+ INSTALL_TIMEOUT_MS: 10 * 60 * 1000,
1083
+ /** How long the post-restart notice waits for Slack to connect (ms) */
1084
+ NOTIFY_WAIT_MS: 10 * 60 * 1000,
1085
+ /** Poll interval while waiting for Slack (ms) */
1086
+ NOTIFY_POLL_MS: 15 * 1000,
1087
+ /** A pending-upgrade marker older than this is ignored at boot (ms) — 1 day */
1088
+ MARKER_MAX_AGE_MS: 24 * 60 * 60 * 1000,
1089
+ /** Env var: `0`/`false`/`off` forces auto-update off, `1`/`true`/`on` forces it on */
1090
+ ENV_VAR: 'CREWLY_AUTO_UPDATE',
1091
+ /**
1092
+ * Env var `crewly start` sets on the backend it spawns: the parent respawns
1093
+ * the backend when it exits with RESTART_REQUESTED, so an upgrade can come back.
1094
+ */
1095
+ SUPERVISOR_ENV_VAR: 'CREWLY_RESTART_SUPERVISOR',
1096
+ /** Value of SUPERVISOR_ENV_VAR set by `crewly start` */
1097
+ SUPERVISOR_CLI_START: 'cli-start',
1098
+ /** Log file under `<crewlyHome>/logs/` */
1099
+ LOG_FILE: 'auto-update.log',
1100
+ /** Status file under CREWLY_HOME (read by `crewly update-status`) */
1101
+ STATE_FILE: 'auto-update-state.json',
1102
+ /** Marker written before an upgrade restart, read (and removed) on the next boot */
1103
+ MARKER_FILE: 'auto-update-pending.json',
1104
+ /** npm package name */
1105
+ PACKAGE_NAME: 'crewly',
1106
+ } as const;
1107
+
1049
1108
  // ========================= MARKETPLACE CONSTANTS =========================
1050
1109
 
1051
1110
  /**
package/config/index.ts CHANGED
@@ -33,6 +33,7 @@ import {
33
33
  MEMORY_CONSTANTS,
34
34
  CONTINUATION_CONSTANTS,
35
35
  VERSION_CHECK_CONSTANTS,
36
+ AUTO_UPDATE_CONSTANTS,
36
37
  MARKETPLACE_CONSTANTS,
37
38
  TEMPLATE_MARKETPLACE_CONSTANTS,
38
39
  PROCESS_EXIT_CODES,
@@ -63,6 +64,7 @@ export {
63
64
  MEMORY_CONSTANTS,
64
65
  CONTINUATION_CONSTANTS,
65
66
  VERSION_CHECK_CONSTANTS,
67
+ AUTO_UPDATE_CONSTANTS,
66
68
  MARKETPLACE_CONSTANTS,
67
69
  TEMPLATE_MARKETPLACE_CONSTANTS,
68
70
  PROCESS_EXIT_CODES,
@@ -1032,6 +1032,15 @@ Full-scope Google OAuth (Gmail read/write + Drive + Calendar + Photos + Docs tog
1032
1032
  **Capability awareness (meta-rule):**
1033
1033
  When teams ship new capabilities (new UI flows, new skills, new credential types), you need to be told explicitly. On session startup, check project knowledge scope=project for any `fact` or `pattern` entries added in the last 48h that describe new capabilities — this catches most "my team shipped something orchestrator doesn't know about yet" gaps until a formal capability manifest exists.
1034
1034
 
1035
+ ### Harness Login (Claude Code / Codex) — use `harness-login`, never bash (MANDATORY)
1036
+
1037
+ When the owner asks to log Claude Code or Codex in again, switch its account, or send them a login link ("帮我重新登陆 claude code", "换个账号", "给我登录链接"):
1038
+
1039
+ - Run `bash config/skills/orchestrator/harness-login/execute.sh --harness claude` (or `codex`; add `--switch-account` for a different account). Crewly keeps the login alive in its own terminal, sends the owner the link in the thread they asked in, types the code they paste back into the login, and tells them itself when it worked.
1040
+ - **Never** run `claude setup-token`, `claude /login`, `claude auth login`, `codex login` or an `agy` login in bash. The process dies when your tool call returns, so every code the owner pastes goes stale (2026-09-26: the owner pasted two codes into a dead login). The bash tool refuses these commands.
1041
+ - After the skill succeeds, **say nothing more about the login** — no link, no "I've sent it", no status report. Never claim you sent something unless a reply tool actually sent it in this turn.
1042
+ - The owner can also type 「重新登录 claude」 / 「换个账号登录 codex」 / `relogin claude` in your DM; Crewly handles that without you.
1043
+
1035
1044
  ### Team Management
1036
1045
 
1037
1046
  - Create and configure agent teams
@@ -99,6 +99,17 @@ fi
99
99
  require_param "to (--to)" "$TO"
100
100
  require_param "task (--task)" "$TASK"
101
101
 
102
+ # A WorkItem brief quotes its Request as "[Request <uuid> | WorkItem <uuid>]".
103
+ # When the delegator pastes that brief without --request-id, link the new
104
+ # WorkItem to that Request anyway; otherwise the Request's completion check
105
+ # cannot see the work (2026-09-26: WI 806dc528 carried Request d86b5faf only
106
+ # in its title and the Request closed while it was still running).
107
+ if [ -z "$REQUEST_ID" ]; then
108
+ REQUEST_ID=$(printf '%s\n%s' "$TASK" "$CONTEXT" \
109
+ | grep -oE '\[Request [0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}' \
110
+ | head -1 | sed 's/^\[Request //' || true)
111
+ fi
112
+
102
113
  # Request Contract check (P0-3): non-fatal warning when the delegated brief
103
114
  # is missing Goal / Expected Outcome / Eval Criteria markers. TLs and workers
104
115
  # downstream are entitled to push back per the Brief Reception Protocol when
@@ -348,6 +348,44 @@ else
348
348
  PASS=$((PASS + 1))
349
349
  fi
350
350
 
351
+ # --- Test 8: a brief that quotes "[Request <uuid> | WorkItem …]" links the new
352
+ # WorkItem to that Request even without --request-id (2026-09-26, WI 806dc528
353
+ # carried Request d86b5faf only in its title; the Request then closed early).
354
+ REQ_ID="d86b5faf-4693-4941-aa9b-7216ffb90005"
355
+ > "$CALL_LOG"
356
+ OUT=$(CALL_LOG="$CALL_LOG" CREWLY_ROOT=/tmp/crewly-test \
357
+ bash "${SKILL_PARENT}/delegate-task/execute.sh" \
358
+ --to crewly-test-bob \
359
+ --task "[Request ${REQ_ID} | WorkItem 8249a788-1ea7-4687-ac1a-47d078a34afe] GOAL: plan it" \
360
+ 2>&1 || true)
361
+ assert_log_contains "requestId parsed from the quoted brief" "\"requestId\": \"${REQ_ID}\""
362
+
363
+ # 8b: an explicit --request-id wins over the quoted one
364
+ > "$CALL_LOG"
365
+ OUT=$(CALL_LOG="$CALL_LOG" CREWLY_ROOT=/tmp/crewly-test \
366
+ bash "${SKILL_PARENT}/delegate-task/execute.sh" \
367
+ --to crewly-test-bob \
368
+ --request-id explicit-req \
369
+ --task "[Request ${REQ_ID} | WorkItem x] GOAL: plan it" \
370
+ 2>&1 || true)
371
+ assert_log_contains "explicit --request-id is kept" '"requestId": "explicit-req"'
372
+
373
+ # 8c: no quoted Request and no flag → no requestId, and the skill still runs
374
+ > "$CALL_LOG"
375
+ OUT=$(CALL_LOG="$CALL_LOG" CREWLY_ROOT=/tmp/crewly-test \
376
+ bash "${SKILL_PARENT}/delegate-task/execute.sh" \
377
+ --to crewly-test-bob \
378
+ --task "plain task" \
379
+ 2>&1 || true)
380
+ if grep -q '"requestId"' "$CALL_LOG"; then
381
+ echo " FAIL: requestId set without a quoted Request"
382
+ FAIL=$((FAIL + 1))
383
+ else
384
+ echo " PASS: no requestId without a quoted Request"
385
+ PASS=$((PASS + 1))
386
+ fi
387
+ assert_log_contains "add still fires without a quoted Request" "POST /task-pool/add"
388
+
351
389
  # --- Summary ---
352
390
  echo ""
353
391
  echo "=== Results: $PASS passed, $FAIL failed ==="
@@ -0,0 +1,88 @@
1
+ ---
2
+ name: Harness Login
3
+ description: "Log a coding harness (Claude Code, Codex) in, or switch its account, when the owner asks. Crewly keeps the login alive in its own terminal, DMs the owner the link in the thread they asked in, types the code they paste back into the login, and reports success itself. Never run claude setup-token / claude /login / codex login in bash."
4
+ version: 1.0.0
5
+ category: management
6
+ skillType: claude-skill
7
+ assignableRoles:
8
+ - orchestrator
9
+ triggers:
10
+ - relogin claude
11
+ - login claude
12
+ - login codex
13
+ - switch claude account
14
+ - claude login link
15
+ - 重新登录
16
+ - 登录 claude
17
+ - 换个账号登录
18
+ - 登录链接
19
+ tags:
20
+ - harness
21
+ - login
22
+ - claude
23
+ - codex
24
+ - account
25
+ execution:
26
+ type: script
27
+ script:
28
+ file: execute.sh
29
+ interpreter: bash
30
+ timeoutMs: 30000
31
+ ---
32
+
33
+ # Harness Login
34
+
35
+ The owner asks you to log Claude Code or Codex in again, or to use a different
36
+ account ("帮我重新登陆 claude code", "换个账号", "send me the login link").
37
+
38
+ ```bash
39
+ bash config/skills/orchestrator/harness-login/execute.sh --harness claude
40
+ bash config/skills/orchestrator/harness-login/execute.sh --harness codex --switch-account
41
+ ```
42
+
43
+ ## What happens
44
+
45
+ 1. Crewly starts the harness's own login command in a terminal it keeps alive
46
+ (`claude setup-token` for Claude, `codex login --device-auth` for Codex) —
47
+ even when the harness is still logged in, because the owner asked.
48
+ 2. The owner gets the link (and Codex's one-time code) in Slack, in the thread
49
+ they asked in.
50
+ 3. Claude: the owner pastes the code shown after authorizing straight back into
51
+ that thread. Crewly types it into the login. Codex needs nothing pasted.
52
+ 4. Crewly tells the owner in one line when it worked (and restarts the agents
53
+ on that harness so they use the new login), or when it failed.
54
+
55
+ The skill returns at once:
56
+
57
+ ```json
58
+ {"success":true,"status":"started","harnessId":"claude-code","displayName":"Claude Code","dmAvailable":true,"next":"…"}
59
+ ```
60
+
61
+ **After that, say nothing more about this login.** Do not repeat the link, do
62
+ not say "I've sent it", do not write a status report. The flow speaks for
63
+ itself. If `dmAvailable` is false, follow `next` (Slack is down: tell the owner
64
+ in one line to finish it in Setup).
65
+
66
+ ## Rules
67
+
68
+ - **Never** run `claude setup-token`, `claude /login`, `claude auth login`,
69
+ `codex login` or an Antigravity (`agy`) login in bash. The process dies when
70
+ the tool call returns, so every code the owner pastes is stale (2026-09-26).
71
+ The bash tool refuses these commands.
72
+ - Only when the owner asked. The backend checks that an owner message from the
73
+ last 30 minutes asks for this login; otherwise it answers
74
+ `owner_request_not_found`. Do not start logins on your own.
75
+ - `antigravity` answers `no_link_login` (it uses a Gemini API key, entered in
76
+ Setup); Gemini CLI is enterprise-only. Pass the message on in one line.
77
+ - The owner can also just write 「重新登录 claude」 / 「换个账号登录 codex」 /
78
+ `relogin claude` in your DM — Crewly handles that without you.
79
+
80
+ ## Errors
81
+
82
+ | reason | meaning |
83
+ |---|---|
84
+ | `orchestrator_only` | Only the orchestrator may call this |
85
+ | `owner_request_not_found` | No recent owner message asks for this login |
86
+ | `owner_request_unverifiable` | The owner's chat history could not be read |
87
+ | `unknown_harness` | Use claude, codex or antigravity |
88
+ | `no_link_login` | The harness has no link login (Antigravity, Gemini) |
@@ -0,0 +1,75 @@
1
+ #!/bin/bash
2
+ # =============================================================================
3
+ # harness-login — start the harness login (or account switch) the owner asked
4
+ # for: Claude Code, Codex. Backed by POST /api/harness/<id>/owner-login.
5
+ #
6
+ # Crewly runs the login in its own terminal and keeps it alive, DMs the owner
7
+ # the link (and Codex's code) in the thread they asked in, types the code they
8
+ # paste back into the login, and tells them itself when it worked or failed.
9
+ # This returns at once. After it succeeds, say NOTHING more about the login —
10
+ # no link, no "I've sent it", no status report.
11
+ #
12
+ # NEVER run `claude setup-token`, `claude /login`, `claude auth login`,
13
+ # `codex login` or an agy login in bash: that process dies when the tool call
14
+ # returns, so every code the owner pastes goes stale.
15
+ #
16
+ # Only works when the owner asked for the login in the last 30 minutes (their
17
+ # message is checked). Orchestrator only.
18
+ #
19
+ # Usage:
20
+ # bash execute.sh --harness claude
21
+ # bash execute.sh --harness codex --switch-account
22
+ # bash execute.sh '{"harness":"claude","switchAccount":true}'
23
+ # =============================================================================
24
+ set -euo pipefail
25
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
26
+ source "${SCRIPT_DIR}/../_common/lib.sh"
27
+
28
+ print_usage() {
29
+ cat <<'EOF_USAGE'
30
+ Usage:
31
+ bash execute.sh --harness <claude|codex|antigravity> [--switch-account]
32
+ bash execute.sh '{"harness":"claude","switchAccount":false}'
33
+
34
+ Options:
35
+ --harness claude (Claude Code), codex (Codex CLI) or antigravity (agy) — required
36
+ --switch-account The owner wants a different account (changes the wording of the DM)
37
+ --help | -h Show this help
38
+ EOF_USAGE
39
+ }
40
+
41
+ INPUT_JSON=""; HARNESS=""; SWITCH=false
42
+ if [[ $# -gt 0 && ${1:0:1} == '{' ]]; then INPUT_JSON="$1"; shift || true; fi
43
+ while [[ $# -gt 0 ]]; do
44
+ case "$1" in
45
+ --harness) [ $# -ge 2 ] || error_exit "--harness requires a value"; HARNESS="$2"; shift 2 ;;
46
+ --switch-account) SWITCH=true; shift ;;
47
+ --help|-h) print_usage; exit 0 ;;
48
+ *) error_exit "Unknown option: $1" ;;
49
+ esac
50
+ done
51
+ if [ -n "$INPUT_JSON" ]; then
52
+ INPUT=$(read_json_input "$INPUT_JSON")
53
+ [ -z "$HARNESS" ] && HARNESS=$(printf '%s' "$INPUT" | jq -r '.harness // .harnessId // empty')
54
+ [ "$(printf '%s' "$INPUT" | jq -r '.switchAccount // false')" = "true" ] && SWITCH=true
55
+ fi
56
+ require_param "harness (--harness)" "$HARNESS"
57
+
58
+ # "Claude Code" → "claude-code"; anything else than [a-z0-9-] never reaches the URL.
59
+ HARNESS_ID=$(printf '%s' "$HARNESS" | tr '[:upper:]' '[:lower:]' | sed -E 's/[[:space:]_]+/-/g')
60
+ [[ "$HARNESS_ID" =~ ^[a-z0-9-]+$ ]] || error_exit "Invalid harness: $HARNESS (use claude, codex or antigravity)"
61
+
62
+ BODY=$(jq -cn --argjson sw "$SWITCH" '{switchAccount: $sw}')
63
+
64
+ ERR_FILE=$(mktemp); trap 'rm -f "$ERR_FILE"' EXIT
65
+ RESPONSE=$(api_call POST "/harness/${HARNESS_ID}/owner-login" "$BODY" 2>"$ERR_FILE") || {
66
+ ERR=$(tail -n 1 "$ERR_FILE")
67
+ printf '%s' "$ERR" | jq -c '{success: false,
68
+ reason: (.details.code // "login_not_started"),
69
+ error: (.details.error // .error // "login not started")}
70
+ + (if .details.next then {next: .details.next} else {} end)' 2>/dev/null \
71
+ || jq -cn --arg e "$ERR" '{success: false, reason: "login_not_started", error: $e}'
72
+ exit 1
73
+ }
74
+
75
+ printf '%s' "$RESPONSE" | jq -c '.data | {success: true} + .'
@@ -0,0 +1,72 @@
1
+ #!/bin/bash
2
+ # Tests for harness-login — run with: bash execute.test.sh </dev/null
3
+ # A python HTTP stub plays the backend; asserts the route, the body, the
4
+ # orchestrator header and how refusals are reported.
5
+ set -u
6
+ HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
+ EXEC="$HERE/execute.sh"
8
+ PASS=0; FAIL=0
9
+ check() {
10
+ local name="$1"; local got="$2"; local want="$3"
11
+ if [ "$got" = "$want" ]; then PASS=$((PASS+1)); else FAIL=$((FAIL+1)); echo "FAIL: $name"; echo " want: $want"; echo " got: $got"; fi
12
+ }
13
+
14
+ PORT=18853
15
+ STUB_LOG="$(mktemp)"; export STUB_LOG; export STUB_PORT="$PORT"
16
+ python3 -u <<'PY' >/dev/null 2>&1 &
17
+ from http.server import BaseHTTPRequestHandler, HTTPServer
18
+ import json, os
19
+ LOG = os.environ['STUB_LOG']; PORT = int(os.environ['STUB_PORT'])
20
+ class H(BaseHTTPRequestHandler):
21
+ def reply(self, code, body):
22
+ self.send_response(code); self.send_header('Content-Type', 'application/json'); self.end_headers()
23
+ self.wfile.write(json.dumps(body).encode())
24
+ def do_POST(self):
25
+ body = json.loads(self.rfile.read(int(self.headers.get('Content-Length', 0))) or b'{}')
26
+ open(LOG, 'w').write(json.dumps({'path': self.path, 'body': body, 'agent': self.headers.get('X-Agent-Session')}))
27
+ if self.headers.get('X-Agent-Session') != 'crewly-orc':
28
+ return self.reply(403, {'success': False, 'code': 'orchestrator_only', 'error': 'Only the orchestrator can start a harness login for the owner. Ask the orchestrator.'})
29
+ if self.path.startswith('/api/harness/codex/'):
30
+ return self.reply(403, {'success': False, 'code': 'owner_request_not_found', 'error': 'No owner message in the last 30 min asks to log Codex in.'})
31
+ if self.path.startswith('/api/harness/antigravity/'):
32
+ return self.reply(400, {'success': False, 'code': 'no_link_login', 'error': 'Antigravity CLI 用的是 Gemini API key', 'next': 'Tell the owner this in one short line, in their language.'})
33
+ self.reply(202, {'success': True, 'data': {'status': 'started', 'harnessId': 'claude-code', 'displayName': 'Claude Code', 'dmAvailable': True, 'next': 'Say nothing more about this login'}})
34
+ def log_message(self, *a, **k): pass
35
+ HTTPServer(('127.0.0.1', PORT), H).serve_forever()
36
+ PY
37
+ STUB_PID=$!
38
+ disown "$STUB_PID" 2>/dev/null || true
39
+ trap 'kill "$STUB_PID" >/dev/null 2>&1; rm -f "$STUB_LOG"' EXIT
40
+ for i in $(seq 1 30); do curl -s -o /dev/null -m 0.2 "http://127.0.0.1:${PORT}/" 2>/dev/null && break; sleep 0.1; done
41
+
42
+ run() { CREWLY_SESSION_NAME="${AS:-crewly-orc}" CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" "$@" 2>/dev/null; }
43
+ run_err() { CREWLY_SESSION_NAME=crewly-orc CREWLY_API_URL="http://127.0.0.1:${PORT}" bash "$EXEC" "$@" 2>&1 >/dev/null | jq -rs 'last.error' 2>/dev/null; }
44
+
45
+ OUT=$(run --harness claude)
46
+ check "route" "$(jq -r .path "$STUB_LOG")" "/api/harness/claude/owner-login"
47
+ check "body" "$(jq -c .body "$STUB_LOG")" '{"switchAccount":false}'
48
+ check "orchestrator header" "$(jq -r .agent "$STUB_LOG")" "crewly-orc"
49
+ check "returns at once with the next step" "$(printf '%s' "$OUT" | jq -c '{success, status, harnessId, dmAvailable}')" '{"success":true,"status":"started","harnessId":"claude-code","dmAvailable":true}'
50
+
51
+ OUT=$(run --harness "Claude Code" --switch-account)
52
+ check "display name → id, switch flag" "$(jq -c '{path, body}' "$STUB_LOG")" '{"path":"/api/harness/claude-code/owner-login","body":{"switchAccount":true}}'
53
+
54
+ OUT=$(run '{"harness":"claude","switchAccount":true}')
55
+ check "json input" "$(jq -c .body "$STUB_LOG")" '{"switchAccount":true}'
56
+
57
+ OUT=$(run --harness codex); RC=$?
58
+ check "no owner request: exit 1" "$RC" "1"
59
+ check "no owner request: reason" "$(printf '%s' "$OUT" | jq -r .reason)" "owner_request_not_found"
60
+
61
+ OUT=$(run --harness antigravity); RC=$?
62
+ check "no link login: reason and next" "$(printf '%s' "$OUT" | jq -c '{reason, next}')" '{"reason":"no_link_login","next":"Tell the owner this in one short line, in their language."}'
63
+
64
+ OUT=$(AS=dev-team-joe run --harness claude)
65
+ check "other agents refused" "$(printf '%s' "$OUT" | jq -r .reason)" "orchestrator_only"
66
+
67
+ check "missing harness" "$(run_err)" "Missing required parameter: harness (--harness)"
68
+ check "path injection refused" "$(run_err --harness '../orc')" "Invalid harness: ../orc (use claude, codex or antigravity)"
69
+ check "unknown option" "$(run_err --yes)" "Unknown option: --yes"
70
+
71
+ echo "=== Results: $PASS passed, $FAIL failed ==="
72
+ [ "$FAIL" -eq 0 ]
@@ -69,10 +69,20 @@ bash config/skills/orchestrator/reply-chat/execute.sh '{"conversationId":"conv-a
69
69
 
70
70
  | Flag | Short | Description |
71
71
  |------|-------|-------------|
72
- | `--conversation` | `-C` | Chat conversation ID (optional — defaults to current) |
72
+ | `--conversation` | `-C` | Chat conversation ID. Omitted → the conversation your current turn came from (the `[CHAT:<id>]` of the last user message you received) |
73
73
  | `--text` | `-t` | Message text |
74
74
  | `--text-file` | | Read message text from file |
75
75
  | `--sender` | `-s` | Sender name (default: "Orchestrator") |
76
76
  | `--sender-type` | | Sender type: orchestrator, agent, system (default: orchestrator) |
77
+ | `--cross-post` | | Deliberately post to a conversation other than the one your turn came from (you were asked to post there) |
77
78
  | `--json` | `-j` | Raw JSON payload |
78
79
  | `--help` | `-h` | Show help |
80
+
81
+ ## Where your reply goes
82
+
83
+ Your reply belongs in the conversation the user wrote to you from. While the
84
+ last user message you received is under 15 minutes old, a reply to a
85
+ conversation nobody has written to you from in the last 30 minutes is sent to
86
+ the conversation that message came from instead, and a warning is logged. This
87
+ also covers system turns (WorkItem dispatch, reminders) that follow a user's
88
+ message. Pass `--cross-post` only when you were asked to post somewhere else.
@@ -22,6 +22,11 @@ Options:
22
22
  --text-file Read message text from the specified file path
23
23
  --sender | -s Sender name (default: Orchestrator)
24
24
  --sender-type Sender type: orchestrator, agent, system (default: orchestrator)
25
+ --cross-post Deliberately post in a conversation other than the one
26
+ your current turn came from (e.g. the owner asked you to
27
+ post there). Without it, an orchestrator reply aimed at a
28
+ conversation nobody wrote to you from recently is sent
29
+ back to the conversation the turn came from.
25
30
  --json | -j Raw JSON payload
26
31
  --help | -h Show this help
27
32
  EOF_USAGE
@@ -32,6 +37,7 @@ CONVERSATION_ID=""
32
37
  TEXT=""
33
38
  SENDER_NAME="Orchestrator"
34
39
  SENDER_TYPE="orchestrator"
40
+ CROSS_POST="false"
35
41
 
36
42
  # Detect legacy JSON argument as the first parameter
37
43
  if [[ $# -gt 0 && ${1:0:1} == '{' ]]; then
@@ -61,6 +67,10 @@ while [[ $# -gt 0 ]]; do
61
67
  SENDER_TYPE="$2"
62
68
  shift 2
63
69
  ;;
70
+ --cross-post)
71
+ CROSS_POST="true"
72
+ shift
73
+ ;;
64
74
  --json|-j)
65
75
  INPUT_JSON="$2"
66
76
  shift 2
@@ -117,7 +127,9 @@ BODY=$(jq -n \
117
127
  --arg senderName "$SENDER_NAME" \
118
128
  --arg senderType "$SENDER_TYPE" \
119
129
  --arg conversationId "$CONVERSATION_ID" \
130
+ --argjson crossPost "$CROSS_POST" \
120
131
  '{content: $content, senderName: $senderName, senderType: $senderType} +
121
- (if $conversationId != "" then {conversationId: $conversationId} else {} end)')
132
+ (if $conversationId != "" then {conversationId: $conversationId} else {} end) +
133
+ (if $crossPost then {crossPost: true} else {} end)')
122
134
 
123
135
  api_call POST "/chat/agent-response" "$BODY"
@@ -56,6 +56,7 @@ bash config/skills/orchestrator/reply-slack/execute.sh '{"channelId":"C0123","te
56
56
  | `--image` / `-i` | No | Path to an image file to upload to Slack. When provided, calls `/api/slack/upload-image` instead of `/api/slack/send`. The `--text` becomes an optional comment on the image |
57
57
  | `--file` / `-f` | No | Path to any file type (PDF/CSV/ZIP/etc.) to upload via `/api/slack/upload-file`. The `--text` becomes an optional comment |
58
58
  | `--allow-new-thread` | No | Explicitly allow posting without a thread (safety override) |
59
+ | `--cross-post` | No | Deliberately post to a Slack DM other than the one your turn came from. Without it, a DM post (`D…`) nobody wrote to you from recently is sent back to the conversation your turn came from. Channel posts are never re-routed |
59
60
  | `conversationId` / `--conversation` | No | Conversation ID from the `[CHAT:...]` prefix so the queue can resolve instantly (falls back to the active conversation if omitted) |
60
61
 
61
62
  ## Image Upload
@@ -27,12 +27,17 @@ Options:
27
27
  --image | -i Path to image file to upload (uses /api/slack/upload-image)
28
28
  --file | -f Path to file upload (uses /api/slack/upload-file)
29
29
  --allow-new-thread Allow posting without --thread (disabled by default for safety)
30
+ --cross-post Deliberately post to a Slack DM other than the one your
31
+ current turn came from. Without it, a DM post nobody wrote
32
+ to you from recently is sent back where the turn came from.
33
+ (Channel posts are never re-routed.)
30
34
  --json | -j Raw JSON payload (same as legacy usage)
31
35
  --help | -h Show this help
32
36
  EOF_USAGE
33
37
  }
34
38
 
35
39
  INPUT_JSON=""
40
+ CROSS_POST="false"
36
41
  CHANNEL_ID=""
37
42
  TEXT=""
38
43
  THREAD_TS=""
@@ -78,6 +83,10 @@ while [[ $# -gt 0 ]]; do
78
83
  ALLOW_NEW_THREAD="true"
79
84
  shift
80
85
  ;;
86
+ --cross-post)
87
+ CROSS_POST="true"
88
+ shift
89
+ ;;
81
90
  --conversation|-C)
82
91
  CONVERSATION_ID="$2"
83
92
  shift 2
@@ -200,10 +209,10 @@ else
200
209
  export _SLACK_TEXT="$TEXT"
201
210
  if [ -n "$THREAD_TS" ]; then
202
211
  export _SLACK_THREAD="$THREAD_TS"
203
- BODY=$(jq -n '{channelId: env._SLACK_CHANNEL, text: env._SLACK_TEXT, threadTs: env._SLACK_THREAD}')
212
+ BODY=$(jq -n --argjson crossPost "$CROSS_POST" '{channelId: env._SLACK_CHANNEL, text: env._SLACK_TEXT, threadTs: env._SLACK_THREAD} + (if $crossPost then {crossPost: true} else {} end)')
204
213
  unset _SLACK_THREAD
205
214
  else
206
- BODY=$(jq -n '{channelId: env._SLACK_CHANNEL, text: env._SLACK_TEXT}')
215
+ BODY=$(jq -n --argjson crossPost "$CROSS_POST" '{channelId: env._SLACK_CHANNEL, text: env._SLACK_TEXT} + (if $crossPost then {crossPost: true} else {} end)')
207
216
  fi
208
217
  unset _SLACK_CHANNEL _SLACK_TEXT
209
218
 
@@ -216,6 +216,27 @@ export declare const VERSION_CHECK_CONSTANTS: {
216
216
  readonly CACHE_TTL_MS: number;
217
217
  readonly REQUEST_TIMEOUT_MS: 5000;
218
218
  };
219
+ export declare const AUTO_UPDATE_CONSTANTS: {
220
+ readonly CHECK_INTERVAL_MS: number;
221
+ readonly FIRST_CHECK_DELAY_MS: number;
222
+ readonly REGISTRY_MAX_AGE_MS: number;
223
+ readonly QUIET_CONFIRM_MS: number;
224
+ readonly BUSY_RETRY_MS: number;
225
+ readonly MAX_BUSY_DEFER_MS: number;
226
+ readonly FAILURE_BACKOFF_MS: number;
227
+ readonly FAILURE_NOTIFY_THRESHOLD: 2;
228
+ readonly INSTALL_TIMEOUT_MS: number;
229
+ readonly NOTIFY_WAIT_MS: number;
230
+ readonly NOTIFY_POLL_MS: number;
231
+ readonly MARKER_MAX_AGE_MS: number;
232
+ readonly ENV_VAR: "CREWLY_AUTO_UPDATE";
233
+ readonly SUPERVISOR_ENV_VAR: "CREWLY_RESTART_SUPERVISOR";
234
+ readonly SUPERVISOR_CLI_START: "cli-start";
235
+ readonly LOG_FILE: "auto-update.log";
236
+ readonly STATE_FILE: "auto-update-state.json";
237
+ readonly MARKER_FILE: "auto-update-pending.json";
238
+ readonly PACKAGE_NAME: "crewly";
239
+ };
219
240
  export declare const AGENT_HEARTBEAT_MONITOR_CONSTANTS: {
220
241
  readonly CHECK_INTERVAL_MS: 30000;
221
242
  readonly HEARTBEAT_REQUEST_THRESHOLD_MS: 300000;
@@ -629,6 +650,28 @@ export declare const TERMINAL_GATEWAY_CONSTANTS: {
629
650
  */
630
651
  readonly MONITORING_RETRY_BACKOFFS_MS: readonly number[];
631
652
  };
653
+ /**
654
+ * Orchestrator reply routing (2026-09-26 incident: the owner asked the orc a
655
+ * question in a Slack DM, and its answer landed in #pro-think-tank).
656
+ * See `services/orc/orc-reply-route.service.ts`.
657
+ */
658
+ export declare const ORC_REPLY_ROUTE_CONSTANTS: {
659
+ /**
660
+ * How long after the last user message the orchestrator received its
661
+ * conversation stays "the one its turn came from". Covers a long turn and
662
+ * the system-triggered turns (WorkItem dispatch, reminders) that follow it.
663
+ */
664
+ readonly ORIGIN_TTL_MS: number;
665
+ /**
666
+ * A conversation the orchestrator received a user message from within this
667
+ * window is one it is actively in; replies there are never re-routed.
668
+ */
669
+ readonly RECENT_INBOUND_MS: number;
670
+ /** Cap on remembered inbound conversations per session (oldest dropped). */
671
+ readonly MAX_TRACKED_CONVERSATIONS: 50;
672
+ /** Slack channel-id prefix of a direct-message conversation. */
673
+ readonly SLACK_DM_PREFIX: "D";
674
+ };
632
675
  export declare const CHAT_ROUTING_CONSTANTS: {
633
676
  /** Message format prefix for chat routing */
634
677
  readonly MESSAGE_PREFIX: "CHAT";
@@ -3145,6 +3188,18 @@ export declare const HARNESS_CONSTANTS: {
3145
3188
  /** Waiting agents named in a DM; the rest are counted */
3146
3189
  readonly DM_MAX_LISTED_AGENTS: 8;
3147
3190
  };
3191
+ /**
3192
+ * Owner-requested logins (「重新登录 claude」 in the orc DM, or the orc's
3193
+ * `harness-login` skill). specs/onboarding-harness-login.md "Owner-triggered login".
3194
+ */
3195
+ readonly OWNER_LOGIN: {
3196
+ /** Longest DM (normalised) the deterministic trigger considers; longer text goes to the orc */
3197
+ readonly MAX_TRIGGER_LENGTH: 60;
3198
+ /** How far back an owner message may ask for the login the orc's skill starts */
3199
+ readonly EVIDENCE_LOOKBACK_MS: number;
3200
+ /** Owner messages read for that evidence */
3201
+ readonly EVIDENCE_MAX_MESSAGES: 50;
3202
+ };
3148
3203
  /** Claude Code facts */
3149
3204
  readonly CLAUDE: {
3150
3205
  readonly OAUTH_TOKEN_ENV: "CLAUDE_CODE_OAUTH_TOKEN";