botmux 3.0.0 → 3.1.1

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 (220) hide show
  1. package/dist/adapters/backend/herdr-backend.d.ts +9 -7
  2. package/dist/adapters/backend/herdr-backend.d.ts.map +1 -1
  3. package/dist/adapters/backend/herdr-backend.js +63 -53
  4. package/dist/adapters/backend/herdr-backend.js.map +1 -1
  5. package/dist/adapters/backend/riff-backend.d.ts +6 -1
  6. package/dist/adapters/backend/riff-backend.d.ts.map +1 -1
  7. package/dist/adapters/backend/riff-backend.js +7 -2
  8. package/dist/adapters/backend/riff-backend.js.map +1 -1
  9. package/dist/adapters/backend/sandbox.d.ts +20 -16
  10. package/dist/adapters/backend/sandbox.d.ts.map +1 -1
  11. package/dist/adapters/backend/sandbox.js +193 -68
  12. package/dist/adapters/backend/sandbox.js.map +1 -1
  13. package/dist/adapters/backend/tmux-backend.d.ts +39 -2
  14. package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
  15. package/dist/adapters/backend/tmux-backend.js +66 -6
  16. package/dist/adapters/backend/tmux-backend.js.map +1 -1
  17. package/dist/adapters/backend/tmux-pipe-backend.js +2 -2
  18. package/dist/adapters/backend/tmux-pipe-backend.js.map +1 -1
  19. package/dist/adapters/backend/zellij-backend.d.ts.map +1 -1
  20. package/dist/adapters/backend/zellij-backend.js +9 -3
  21. package/dist/adapters/backend/zellij-backend.js.map +1 -1
  22. package/dist/adapters/cli/claude-code.d.ts +25 -0
  23. package/dist/adapters/cli/claude-code.d.ts.map +1 -1
  24. package/dist/adapters/cli/claude-code.js +79 -9
  25. package/dist/adapters/cli/claude-code.js.map +1 -1
  26. package/dist/adapters/cli/read-isolation.d.ts +2 -1
  27. package/dist/adapters/cli/read-isolation.d.ts.map +1 -1
  28. package/dist/adapters/cli/read-isolation.js.map +1 -1
  29. package/dist/adapters/cli/types.d.ts +2 -2
  30. package/dist/adapters/hook-installer.d.ts +11 -0
  31. package/dist/adapters/hook-installer.d.ts.map +1 -1
  32. package/dist/adapters/hook-installer.js +72 -11
  33. package/dist/adapters/hook-installer.js.map +1 -1
  34. package/dist/cli.d.ts.map +1 -1
  35. package/dist/cli.js +15 -4
  36. package/dist/cli.js.map +1 -1
  37. package/dist/config.d.ts +6 -0
  38. package/dist/config.d.ts.map +1 -1
  39. package/dist/config.js +18 -0
  40. package/dist/config.js.map +1 -1
  41. package/dist/core/command-handler.d.ts.map +1 -1
  42. package/dist/core/command-handler.js +354 -143
  43. package/dist/core/command-handler.js.map +1 -1
  44. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  45. package/dist/core/dashboard-ipc-server.js +12 -5
  46. package/dist/core/dashboard-ipc-server.js.map +1 -1
  47. package/dist/core/dashboard-rows.d.ts +5 -0
  48. package/dist/core/dashboard-rows.d.ts.map +1 -1
  49. package/dist/core/dashboard-rows.js +2 -0
  50. package/dist/core/dashboard-rows.js.map +1 -1
  51. package/dist/core/doc-comment-prompt.d.ts +2 -0
  52. package/dist/core/doc-comment-prompt.d.ts.map +1 -1
  53. package/dist/core/doc-comment-prompt.js +30 -0
  54. package/dist/core/doc-comment-prompt.js.map +1 -1
  55. package/dist/core/github-auth.d.ts +8 -0
  56. package/dist/core/github-auth.d.ts.map +1 -0
  57. package/dist/core/github-auth.js +44 -0
  58. package/dist/core/github-auth.js.map +1 -0
  59. package/dist/core/managed-origin-capability.d.ts +7 -0
  60. package/dist/core/managed-origin-capability.d.ts.map +1 -1
  61. package/dist/core/managed-origin-capability.js +12 -0
  62. package/dist/core/managed-origin-capability.js.map +1 -1
  63. package/dist/core/passthrough-commands.d.ts.map +1 -1
  64. package/dist/core/passthrough-commands.js +1 -1
  65. package/dist/core/passthrough-commands.js.map +1 -1
  66. package/dist/core/restart-report.d.ts +7 -1
  67. package/dist/core/restart-report.d.ts.map +1 -1
  68. package/dist/core/restart-report.js +19 -5
  69. package/dist/core/restart-report.js.map +1 -1
  70. package/dist/core/session-activity.d.ts +8 -0
  71. package/dist/core/session-activity.d.ts.map +1 -1
  72. package/dist/core/session-activity.js +16 -0
  73. package/dist/core/session-activity.js.map +1 -1
  74. package/dist/core/session-discovery.d.ts.map +1 -1
  75. package/dist/core/session-discovery.js +4 -2
  76. package/dist/core/session-discovery.js.map +1 -1
  77. package/dist/core/session-marker.d.ts.map +1 -1
  78. package/dist/core/session-marker.js +5 -2
  79. package/dist/core/session-marker.js.map +1 -1
  80. package/dist/core/types.d.ts +48 -0
  81. package/dist/core/types.d.ts.map +1 -1
  82. package/dist/core/types.js +55 -0
  83. package/dist/core/types.js.map +1 -1
  84. package/dist/core/update-check.d.ts +11 -0
  85. package/dist/core/update-check.d.ts.map +1 -1
  86. package/dist/core/update-check.js +6 -1
  87. package/dist/core/update-check.js.map +1 -1
  88. package/dist/core/vc-meeting-prepare-command.d.ts +22 -0
  89. package/dist/core/vc-meeting-prepare-command.d.ts.map +1 -0
  90. package/dist/core/vc-meeting-prepare-command.js +50 -0
  91. package/dist/core/vc-meeting-prepare-command.js.map +1 -0
  92. package/dist/core/worker-pool.d.ts.map +1 -1
  93. package/dist/core/worker-pool.js +21 -10
  94. package/dist/core/worker-pool.js.map +1 -1
  95. package/dist/daemon.d.ts +15 -5
  96. package/dist/daemon.d.ts.map +1 -1
  97. package/dist/daemon.js +645 -50
  98. package/dist/daemon.js.map +1 -1
  99. package/dist/dashboard/web/bot-defaults-page.d.ts.map +1 -1
  100. package/dist/dashboard/web/bot-defaults-page.js +6 -1
  101. package/dist/dashboard/web/bot-defaults-page.js.map +1 -1
  102. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  103. package/dist/dashboard/web/i18n.js +34 -0
  104. package/dist/dashboard/web/i18n.js.map +1 -1
  105. package/dist/dashboard/web/preferences.d.ts +1 -1
  106. package/dist/dashboard/web/preferences.d.ts.map +1 -1
  107. package/dist/dashboard/web/preferences.js +1 -1
  108. package/dist/dashboard/web/preferences.js.map +1 -1
  109. package/dist/dashboard/web/sessions-page.d.ts +19 -0
  110. package/dist/dashboard/web/sessions-page.d.ts.map +1 -1
  111. package/dist/dashboard/web/sessions-page.js +66 -7
  112. package/dist/dashboard/web/sessions-page.js.map +1 -1
  113. package/dist/dashboard/web/sessions.d.ts +31 -0
  114. package/dist/dashboard/web/sessions.d.ts.map +1 -1
  115. package/dist/dashboard/web/sessions.js +82 -0
  116. package/dist/dashboard/web/sessions.js.map +1 -1
  117. package/dist/dashboard-web/app.js +1 -1
  118. package/dist/dashboard-web/chunks/{bot-defaults-page-MBORWWP7.js → bot-defaults-page-KLDCZNLP.js} +5 -5
  119. package/dist/dashboard-web/chunks/{chunk-G43RUPUN.js → chunk-EZAW2EPM.js} +1 -1
  120. package/dist/dashboard-web/chunks/{chunk-EIO5AWDA.js → chunk-FMJNOATE.js} +1 -1
  121. package/dist/dashboard-web/chunks/{chunk-4QTBR7UF.js → chunk-KEAOTUL3.js} +7 -7
  122. package/dist/dashboard-web/chunks/{chunk-7STGZ5BX.js → chunk-MLNI5BKE.js} +1 -1
  123. package/dist/dashboard-web/chunks/{connectors-page-LKDT4WBG.js → connectors-page-O32LFAL5.js} +1 -1
  124. package/dist/dashboard-web/chunks/{groups-page-XKIWJ2TP.js → groups-page-PSAFIZ6M.js} +1 -1
  125. package/dist/dashboard-web/chunks/{insights-page-CBEZCYKV.js → insights-page-V23LLATX.js} +1 -1
  126. package/dist/dashboard-web/chunks/{monitor-room-AQTHAWXA.js → monitor-room-7X5AKYOF.js} +1 -1
  127. package/dist/dashboard-web/chunks/{monitoring-page-2R4NCNBQ.js → monitoring-page-CBA3CQYL.js} +1 -1
  128. package/dist/dashboard-web/chunks/{office-page-5M6MQIIL.js → office-page-RL6QSEM7.js} +1 -1
  129. package/dist/dashboard-web/chunks/{overview-page-N22HDZ2V.js → overview-page-XQIPO6KH.js} +1 -1
  130. package/dist/dashboard-web/chunks/{roles-page-J6K2HWFX.js → roles-page-ACIWV7QS.js} +1 -1
  131. package/dist/dashboard-web/chunks/{schedules-page-CGAQCB4J.js → schedules-page-KJDUKOJV.js} +1 -1
  132. package/dist/dashboard-web/chunks/sessions-page-2WDWHSP4.js +3 -0
  133. package/dist/dashboard-web/chunks/{settings-page-GLRWV5KU.js → settings-page-6VX4OUGG.js} +1 -1
  134. package/dist/dashboard-web/chunks/{skills-page-KQVW42QU.js → skills-page-WXE3UYLT.js} +1 -1
  135. package/dist/dashboard-web/chunks/{team-federation-page-5PYUOV5M.js → team-federation-page-PYTF4FLM.js} +1 -1
  136. package/dist/dashboard-web/chunks/{v3-page-DXPFILRZ.js → v3-page-G6CD6O3I.js} +1 -1
  137. package/dist/dashboard-web/chunks/{whiteboards-page-NUH6VZ4I.js → whiteboards-page-6SG33GP4.js} +1 -1
  138. package/dist/dashboard-web/style.css +167 -2
  139. package/dist/i18n/en.d.ts.map +1 -1
  140. package/dist/i18n/en.js +19 -3
  141. package/dist/i18n/en.js.map +1 -1
  142. package/dist/i18n/zh.d.ts.map +1 -1
  143. package/dist/i18n/zh.js +19 -3
  144. package/dist/i18n/zh.js.map +1 -1
  145. package/dist/im/lark/card-builder.d.ts.map +1 -1
  146. package/dist/im/lark/card-builder.js +11 -2
  147. package/dist/im/lark/card-builder.js.map +1 -1
  148. package/dist/im/lark/card-handler.d.ts +2 -0
  149. package/dist/im/lark/card-handler.d.ts.map +1 -1
  150. package/dist/im/lark/card-handler.js +219 -139
  151. package/dist/im/lark/card-handler.js.map +1 -1
  152. package/dist/im/lark/event-dispatcher.d.ts +4 -0
  153. package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
  154. package/dist/im/lark/event-dispatcher.js +249 -5
  155. package/dist/im/lark/event-dispatcher.js.map +1 -1
  156. package/dist/im/lark/forward-followup-buffer.d.ts +26 -0
  157. package/dist/im/lark/forward-followup-buffer.d.ts.map +1 -0
  158. package/dist/im/lark/forward-followup-buffer.js +48 -0
  159. package/dist/im/lark/forward-followup-buffer.js.map +1 -0
  160. package/dist/im/lark/forward-followup-content.d.ts +6 -0
  161. package/dist/im/lark/forward-followup-content.d.ts.map +1 -0
  162. package/dist/im/lark/forward-followup-content.js +46 -0
  163. package/dist/im/lark/forward-followup-content.js.map +1 -0
  164. package/dist/im/lark/forward-followup-store.d.ts +9 -0
  165. package/dist/im/lark/forward-followup-store.d.ts.map +1 -0
  166. package/dist/im/lark/forward-followup-store.js +48 -0
  167. package/dist/im/lark/forward-followup-store.js.map +1 -0
  168. package/dist/im/lark/message-parser.d.ts +1 -1
  169. package/dist/im/lark/message-parser.d.ts.map +1 -1
  170. package/dist/im/lark/message-parser.js +1 -2
  171. package/dist/im/lark/message-parser.js.map +1 -1
  172. package/dist/platform/tunnel-client.js +3 -3
  173. package/dist/platform/tunnel-client.js.map +1 -1
  174. package/dist/services/local-cli-opener.d.ts +7 -0
  175. package/dist/services/local-cli-opener.d.ts.map +1 -1
  176. package/dist/services/local-cli-opener.js +111 -3
  177. package/dist/services/local-cli-opener.js.map +1 -1
  178. package/dist/services/skill-registry-store.d.ts.map +1 -1
  179. package/dist/services/skill-registry-store.js +15 -2
  180. package/dist/services/skill-registry-store.js.map +1 -1
  181. package/dist/services/vc-meeting-consumer-isolation.d.ts +7 -5
  182. package/dist/services/vc-meeting-consumer-isolation.d.ts.map +1 -1
  183. package/dist/services/vc-meeting-consumer-isolation.js +7 -5
  184. package/dist/services/vc-meeting-consumer-isolation.js.map +1 -1
  185. package/dist/services/vc-meeting-preparations-store.d.ts +22 -0
  186. package/dist/services/vc-meeting-preparations-store.d.ts.map +1 -0
  187. package/dist/services/vc-meeting-preparations-store.js +131 -0
  188. package/dist/services/vc-meeting-preparations-store.js.map +1 -0
  189. package/dist/services/vc-meeting-runtime-store.d.ts +9 -0
  190. package/dist/services/vc-meeting-runtime-store.d.ts.map +1 -1
  191. package/dist/services/vc-meeting-runtime-store.js +16 -0
  192. package/dist/services/vc-meeting-runtime-store.js.map +1 -1
  193. package/dist/setup/ensure-tmux.d.ts.map +1 -1
  194. package/dist/setup/ensure-tmux.js +9 -11
  195. package/dist/setup/ensure-tmux.js.map +1 -1
  196. package/dist/types.d.ts +2 -0
  197. package/dist/types.d.ts.map +1 -1
  198. package/dist/utils/child-env.d.ts +24 -8
  199. package/dist/utils/child-env.d.ts.map +1 -1
  200. package/dist/utils/child-env.js +49 -8
  201. package/dist/utils/child-env.js.map +1 -1
  202. package/dist/utils/daemon-discovery.d.ts +8 -0
  203. package/dist/utils/daemon-discovery.d.ts.map +1 -1
  204. package/dist/utils/daemon-discovery.js +19 -0
  205. package/dist/utils/daemon-discovery.js.map +1 -1
  206. package/dist/utils/ready-gate.d.ts +9 -3
  207. package/dist/utils/ready-gate.d.ts.map +1 -1
  208. package/dist/utils/ready-gate.js +12 -4
  209. package/dist/utils/ready-gate.js.map +1 -1
  210. package/dist/worker.js +141 -29
  211. package/dist/worker.js.map +1 -1
  212. package/dist/workflows/ops-projection.d.ts.map +1 -1
  213. package/dist/workflows/ops-projection.js +27 -5
  214. package/dist/workflows/ops-projection.js.map +1 -1
  215. package/dist/workflows/v3/distillation-runner.d.ts +4 -0
  216. package/dist/workflows/v3/distillation-runner.d.ts.map +1 -1
  217. package/dist/workflows/v3/distillation-runner.js +4 -2
  218. package/dist/workflows/v3/distillation-runner.js.map +1 -1
  219. package/package.json +1 -1
  220. package/dist/dashboard-web/chunks/sessions-page-WJ2QYTIE.js +0 -3
@@ -34,11 +34,16 @@
34
34
  /**
35
35
  * Decide whether the worker should ARM the ready-gate for a given spawn. The
36
36
  * gate is only valid when a SessionStart hook will actually fire — i.e. a FRESH
37
- * Claude-family spawn that re-runs the CLI binary with our `--settings`:
37
+ * ready-gated spawn whose hook/transport preflight succeeded:
38
38
  *
39
39
  * - `injectsReadyHook` — the adapter injects the hook (claude / seed).
40
+ * - `readySignalAvailable` — the effective config contains the hook (or the
41
+ * CLI has a direct ready-command integration),
42
+ * and an isolated child has a usable callback
43
+ * route to the daemon.
40
44
  * - NOT `adoptMode` — adopt panes are pre-existing, never spawned with
41
- * our `--settings`, so they can't get the hook.
45
+ * our ready integration, so they can't get a
46
+ * fresh SessionStart signal.
42
47
  * - NOT `willReattachPersistent` — on daemon restart / worker recovery the
43
48
  * worker re-attaches to an existing tmux/zellij/
44
49
  * herdr session and does NOT re-run the CLI's
@@ -51,13 +56,14 @@
51
56
  * exactly as before (readyPattern + quiescence).
52
57
  *
53
58
  * NB: `wrapperCli=aiden x claude` strips our process-level `--settings`, but the
54
- * SessionStart hook is ALSO installed globally (~/.claude/settings.json see
59
+ * SessionStart hook is installed in the effective settings.json (see
55
60
  * claude-code.ts hookInstall.sessionStartCommand), which aiden's Claude still
56
61
  * reads. So the real signal fires there too → we KEEP arming for that case
57
62
  * (no readyPattern fallback, which could misjudge).
58
63
  */
59
64
  export declare function shouldArmReadyGate(state: {
60
65
  injectsReadyHook: boolean;
66
+ readySignalAvailable: boolean;
61
67
  adoptMode: boolean;
62
68
  willReattachPersistent: boolean;
63
69
  }): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"ready-gate.d.ts","sourceRoot":"","sources":["../../src/utils/ready-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;IACnB,sBAAsB,EAAE,OAAO,CAAC;CACjC,GAAG,OAAO,CAEV;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAS;IAEzB,oFAAoF;IACpF,GAAG,IAAI,IAAI;IAIX,qFAAqF;IACrF,UAAU,IAAI,OAAO;IAIrB;;;;;;OAMG;IACH,OAAO,IAAI,OAAO;IAOlB,qEAAqE;IACrE,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,gEAAgE;IAChE,IAAI,UAAU,IAAI,OAAO,CAExB;CACF"}
1
+ {"version":3,"file":"ready-gate.d.ts","sourceRoot":"","sources":["../../src/utils/ready-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,sBAAsB,EAAE,OAAO,CAAC;CACjC,GAAG,OAAO,CAKV;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAS;IAEzB,oFAAoF;IACpF,GAAG,IAAI,IAAI;IAIX,qFAAqF;IACrF,UAAU,IAAI,OAAO;IAIrB;;;;;;OAMG;IACH,OAAO,IAAI,OAAO;IAOlB,qEAAqE;IACrE,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,gEAAgE;IAChE,IAAI,UAAU,IAAI,OAAO,CAExB;CACF"}
@@ -34,11 +34,16 @@
34
34
  /**
35
35
  * Decide whether the worker should ARM the ready-gate for a given spawn. The
36
36
  * gate is only valid when a SessionStart hook will actually fire — i.e. a FRESH
37
- * Claude-family spawn that re-runs the CLI binary with our `--settings`:
37
+ * ready-gated spawn whose hook/transport preflight succeeded:
38
38
  *
39
39
  * - `injectsReadyHook` — the adapter injects the hook (claude / seed).
40
+ * - `readySignalAvailable` — the effective config contains the hook (or the
41
+ * CLI has a direct ready-command integration),
42
+ * and an isolated child has a usable callback
43
+ * route to the daemon.
40
44
  * - NOT `adoptMode` — adopt panes are pre-existing, never spawned with
41
- * our `--settings`, so they can't get the hook.
45
+ * our ready integration, so they can't get a
46
+ * fresh SessionStart signal.
42
47
  * - NOT `willReattachPersistent` — on daemon restart / worker recovery the
43
48
  * worker re-attaches to an existing tmux/zellij/
44
49
  * herdr session and does NOT re-run the CLI's
@@ -51,13 +56,16 @@
51
56
  * exactly as before (readyPattern + quiescence).
52
57
  *
53
58
  * NB: `wrapperCli=aiden x claude` strips our process-level `--settings`, but the
54
- * SessionStart hook is ALSO installed globally (~/.claude/settings.json see
59
+ * SessionStart hook is installed in the effective settings.json (see
55
60
  * claude-code.ts hookInstall.sessionStartCommand), which aiden's Claude still
56
61
  * reads. So the real signal fires there too → we KEEP arming for that case
57
62
  * (no readyPattern fallback, which could misjudge).
58
63
  */
59
64
  export function shouldArmReadyGate(state) {
60
- return state.injectsReadyHook && !state.adoptMode && !state.willReattachPersistent;
65
+ return state.injectsReadyHook
66
+ && state.readySignalAvailable
67
+ && !state.adoptMode
68
+ && !state.willReattachPersistent;
61
69
  }
62
70
  export class ReadyGate {
63
71
  armed = false;
@@ -1 +1 @@
1
- {"version":3,"file":"ready-gate.js","sourceRoot":"","sources":["../../src/utils/ready-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAIlC;IACC,OAAO,KAAK,CAAC,gBAAgB,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC;AACrF,CAAC;AAED,MAAM,OAAO,SAAS;IACZ,KAAK,GAAG,KAAK,CAAC;IACd,QAAQ,GAAG,KAAK,CAAC;IAEzB,oFAAoF;IACpF,GAAG;QACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAED,qFAAqF;IACrF,UAAU;QACR,OAAO,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;IACtC,CAAC;IAED;;;;;;OAMG;IACH,OAAO;QACL,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,KAAK,CAAC;QAChC,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC;QAC9B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,qEAAqE;IACrE,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,gEAAgE;IAChE,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;CACF"}
1
+ {"version":3,"file":"ready-gate.js","sourceRoot":"","sources":["../../src/utils/ready-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAKlC;IACC,OAAO,KAAK,CAAC,gBAAgB;WACxB,KAAK,CAAC,oBAAoB;WAC1B,CAAC,KAAK,CAAC,SAAS;WAChB,CAAC,KAAK,CAAC,sBAAsB,CAAC;AACrC,CAAC;AAED,MAAM,OAAO,SAAS;IACZ,KAAK,GAAG,KAAK,CAAC;IACd,QAAQ,GAAG,KAAK,CAAC;IAEzB,oFAAoF;IACpF,GAAG;QACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAED,qFAAqF;IACrF,UAAU;QACR,OAAO,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;IACtC,CAAC;IAED;;;;;;OAMG;IACH,OAAO;QACL,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,KAAK,CAAC;QAChC,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC;QAC9B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,qEAAqE;IACrE,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,gEAAgE;IAChE,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;CACF"}
package/dist/worker.js CHANGED
@@ -72,7 +72,7 @@ import { createCliAdapterSync, locateOnPath } from './adapters/cli/registry.js';
72
72
  import { buildWrappedLaunch, parseWrapperCli, isTtadkWrapper } from './setup/cli-selection.js';
73
73
  import { cliUnavailableMessage } from './setup/cli-availability.js';
74
74
  import { findLaunchedCliPid, scheduleWrapperRealCliPid, readComm, isBareShellComm, bareShellLaunchKind } from './core/session-discovery.js';
75
- import { claudeJsonlPathForSession, resolveJsonlFromPid, findOpenClaudeSessionIds, DEFAULT_CLAUDE_DATA_DIR } from './adapters/cli/claude-code.js';
75
+ import { claudeJsonlPathForSession, resolveJsonlFromPid, findOpenClaudeSessionIds, syncClaudeResumeTargetToCwd, DEFAULT_CLAUDE_DATA_DIR } from './adapters/cli/claude-code.js';
76
76
  import { sessionReadyHookCommand } from './adapters/hook-command.js';
77
77
  import { mtrSessionIdForBotmuxSession } from './adapters/cli/mtr.js';
78
78
  import { HerdrBackend } from './adapters/backend/herdr-backend.js';
@@ -83,7 +83,7 @@ import { ZellijObserveBackend } from './adapters/backend/zellij-observe-backend.
83
83
  import { zellijEnv } from './setup/ensure-zellij.js';
84
84
  import { isObserveBackend } from './adapters/backend/types.js';
85
85
  import { selectSessionBackend, decideBackendGate, backendGateUserMessage } from './adapters/backend/session-backend-selector.js';
86
- import { deriveRiffReposFromDirs, deriveRiffRepoFromWorkingDir, isValidRiffBaseUrl } from './adapters/backend/riff-backend.js';
86
+ import { deriveRiffReposFromDirs, deriveRiffRepoFromWorkingDir, isValidRiffBaseUrl, isValidRiffSandboxCluster, } from './adapters/backend/riff-backend.js';
87
87
  import { prepareSandbox, attachSandboxOutbox, startOutboxWatcher, sandboxEnabled, sandboxedClaudeDataDir, localSandboxApplies } from './adapters/backend/sandbox.js';
88
88
  import { tmuxEnv, probeTmuxFunctionalWithRetry } from './setup/ensure-tmux.js';
89
89
  import { tmuxRestartJitterMs } from './core/tmux-recovery.js';
@@ -102,12 +102,13 @@ import { config, resolveChatBotDiscoveryConfig } from './config.js';
102
102
  import * as sessionStore from './services/session-store.js';
103
103
  import * as pty from 'node-pty';
104
104
  import { createHash } from 'node:crypto';
105
- import { installHook } from './adapters/hook-installer.js';
105
+ import { hasInstalledSessionReadyHook, installHook, } from './adapters/hook-installer.js';
106
106
  import { hookCommandFor } from './adapters/hook-command.js';
107
+ import { parseDaemonIpcPort } from './utils/daemon-discovery.js';
107
108
  import { withCodexAppContext } from './utils/codex-app-context.js';
108
109
  import { resolveCodexAppFinalTurnIdentity } from './adapters/cli/codex-app-turn.js';
109
110
  import { RunnerControlDecoder } from './adapters/cli/runner-control-channel.js';
110
- import { managedOriginCapabilityPath, RELAY_ORIGIN_CAPABILITY_BASENAME, replaceManagedOriginCapabilityFile, } from './core/managed-origin-capability.js';
111
+ import { hasMatchingManagedOriginCapability, managedOriginCapabilityPath, RELAY_ORIGIN_CAPABILITY_BASENAME, replaceManagedOriginCapabilityFile, } from './core/managed-origin-capability.js';
111
112
  // ─── State ───────────────────────────────────────────────────────────────────
112
113
  let cliAdapter = null;
113
114
  let backend = null;
@@ -186,6 +187,24 @@ function provisionIsolatedBotHome(botHome, workingDir, isClaude, cliId, hookInst
186
187
  if (isClaude) {
187
188
  const cdir = join(botHome, 'claude');
188
189
  mkdirSync(cdir, { recursive: true });
190
+ // Settings: read-isolated Claude uses a fresh CLAUDE_CONFIG_DIR, so it
191
+ // otherwise loses provider auth/model/proxy values held in the shared
192
+ // ~/.claude/settings.json `env` map. Merge that map on EVERY cold spawn,
193
+ // then install botmux hooks into the same per-bot file. Global hooks and
194
+ // unrelated top-level settings are not inherited.
195
+ const isolatedSettingsPath = join(cdir, 'settings.json');
196
+ if (hookInstall) {
197
+ try {
198
+ installHook(cliId, {
199
+ ...hookInstall,
200
+ configPath: isolatedSettingsPath,
201
+ inheritClaudeEnvFrom: join(homedir(), '.claude', 'settings.json'),
202
+ }, hookCommandFor(cliId));
203
+ }
204
+ catch (e) {
205
+ log(`[read-isolation] WARN per-bot settings/hook install failed: ${e.message}`);
206
+ }
207
+ }
189
208
  // Auth: a fresh CLAUDE_CONFIG_DIR does NOT inherit the shared account's OAuth
190
209
  // token → keep <cdir>/.credentials.json synced to the FRESHEST valid credential
191
210
  // on EVERY spawn (verified: Claude logs in from that file). Refreshing here (not
@@ -194,24 +213,14 @@ function provisionIsolatedBotHome(botHome, workingDir, isClaude, cliId, hookInst
194
213
  const fresh = freshestClaudeCred();
195
214
  if (fresh)
196
215
  writeCredIfChanged(join(cdir, '.credentials.json'), fresh);
197
- else if (!existsSync(join(cdir, '.credentials.json'))) {
198
- log(`[read-isolation] WARN no Claude credential found (keychain or ~/.claude/.credentials.json) — bot may hit login screen`);
216
+ else if (!existsSync(join(cdir, '.credentials.json'))
217
+ && !claudeSettingsHasProviderAuth(isolatedSettingsPath)) {
218
+ log(`[read-isolation] WARN no Claude provider auth found (global settings env, keychain, or ~/.claude/.credentials.json) — bot may hit login screen`);
199
219
  }
200
220
  // State: seed <cdir>/.claude.json from the GLOBAL one MINUS `projects` (keeps the
201
221
  // onboarding/promo "seen" flags + account so no dialogs appear, without leaking
202
222
  // other projects' data), then trust this bot's cwd. Merge-safe on resume.
203
223
  seedAndTrustClaudeState(join(cdir, '.claude.json'), workingDir, log);
204
- // Hooks: install the SessionStart-ready + askUserQuestion hooks into the PER-BOT
205
- // settings.json (global ~/.claude/settings.json is Seatbelt-denied), else the
206
- // worker's ready gate falls back to a slow timeout and AskUserQuestion won't relay.
207
- if (hookInstall) {
208
- try {
209
- installHook(cliId, { ...hookInstall, configPath: join(cdir, 'settings.json') }, hookCommandFor(cliId));
210
- }
211
- catch (e) {
212
- log(`[read-isolation] WARN per-bot hook install failed: ${e.message}`);
213
- }
214
- }
215
224
  }
216
225
  else {
217
226
  const cdir = join(botHome, 'codex');
@@ -232,6 +241,22 @@ function provisionIsolatedBotHome(botHome, workingDir, isClaude, cliId, hookInst
232
241
  log(`[read-isolation] WARN provisioning bot home failed: ${e.message}`);
233
242
  }
234
243
  }
244
+ function claudeSettingsHasProviderAuth(settingsPath) {
245
+ try {
246
+ const settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
247
+ const env = settings.env;
248
+ if (!env || typeof env !== 'object' || Array.isArray(env))
249
+ return false;
250
+ const record = env;
251
+ return ((typeof record.ANTHROPIC_AUTH_TOKEN === 'string' && record.ANTHROPIC_AUTH_TOKEN.length > 0)
252
+ || (typeof record.ANTHROPIC_API_KEY === 'string' && record.ANTHROPIC_API_KEY.length > 0)
253
+ || record.CLAUDE_CODE_USE_BEDROCK === '1'
254
+ || record.CLAUDE_CODE_USE_VERTEX === '1');
255
+ }
256
+ catch {
257
+ return false;
258
+ }
259
+ }
235
260
  /** Pick the FRESHEST valid Claude OAuth credential: macOS keychain vs the global
236
261
  * `~/.claude/.credentials.json`, by `claudeAiOauth.expiresAt` (longest runway
237
262
  * wins — a re-login updates one of the two, and this picks whichever is newer).
@@ -724,6 +749,15 @@ async function deliverRawInput(msg) {
724
749
  const targetBackend = backend;
725
750
  if (!targetBackend)
726
751
  return;
752
+ // A passthrough is still an accepted input boundary. Rotate (or revoke) the
753
+ // marker immediately before the literal command reaches the CLI so it can
754
+ // never inherit a previous human turn. System-generated raw commands omit
755
+ // turnId and therefore publish an explicitly unattributed marker.
756
+ currentBotmuxTurnId = msg.turnId;
757
+ currentBotmuxDispatchAttempt = undefined;
758
+ currentVcMeetingImTurnOrigin = undefined;
759
+ writeCliPidMarker();
760
+ publishSandboxRelayCapability();
727
761
  let sent = false;
728
762
  try {
729
763
  await sendRawCommandLineSerially(targetBackend, msg.content);
@@ -741,7 +775,7 @@ async function deliverRawInput(msg) {
741
775
  // Enter lands. sendToPty also observes commandLineWritesPending, so another
742
776
  // raw command's text -> Enter window cannot be interrupted by the follow-up.
743
777
  if (sent && msg.followUpContent) {
744
- sendToPty(msg.followUpContent, undefined, {
778
+ sendToPty(msg.followUpContent, msg.followUpTurnId, {
745
779
  codexAppInput: msg.followUpCodexAppInput,
746
780
  });
747
781
  log(`Enqueued follow-up after raw input (${msg.followUpContent.length} chars)`);
@@ -789,18 +823,28 @@ function publishSandboxRelayCapability(opts = {}) {
789
823
  }]
790
824
  : []),
791
825
  ];
826
+ let publishError;
792
827
  for (const file of files) {
793
828
  try {
794
829
  replaceManagedOriginCapabilityFile(file.path, file.body);
795
830
  }
796
831
  catch (err) {
797
832
  log(`Failed to publish managed origin capability: ${err?.message ?? err}`);
798
- if (opts.failClosed) {
799
- unlinkManagedOriginCapabilityFiles();
800
- throw err;
801
- }
833
+ publishError = err;
834
+ break;
802
835
  }
803
836
  }
837
+ if (publishError) {
838
+ // The disk/daemon/worker views must rotate as one authority generation. If
839
+ // the child-visible transport cannot publish the new token, revoke the old
840
+ // generation and leave no in-memory authority for ready/send preflights to
841
+ // mistake as usable. Any files written before a later failure are removed
842
+ // by the revocation helper as well.
843
+ completeManagedTurnOriginRevocation(sandboxRelayCapability, currentBotmuxTurnId, currentBotmuxDispatchAttempt);
844
+ if (opts.failClosed)
845
+ throw publishError;
846
+ return false;
847
+ }
804
848
  sandboxRelayCapability = capability;
805
849
  if (sessionId) {
806
850
  send({
@@ -813,6 +857,7 @@ function publishSandboxRelayCapability(opts = {}) {
813
857
  : {}),
814
858
  });
815
859
  }
860
+ return true;
816
861
  }
817
862
  function unlinkManagedOriginCapabilityFiles() {
818
863
  const files = [
@@ -4381,8 +4426,14 @@ function detectBareShellLaunch() {
4381
4426
  else {
4382
4427
  message =
4383
4428
  `⚠️ 会话没能启动:pane 里还停在 \`${comm}\`,${cli} 没真正跑起来——我没把消息打进去(否则会被当 shell 命令执行)。\n\n` +
4384
- `可能原因:rc 文件启动过慢/报错,或 \`${cli}\` 的可执行文件不在 PATH 上(CLI 没找到)。\n` +
4385
- `建议:在 web 终端里手动敲一下启动命令看报什么错;确认 CLI 二进制能在 PATH 上找到;或精简 rc 启动逻辑后重启 daemon 再试。`;
4429
+ `最常见原因:rc 文件里有交互式提示卡住了 shell 启动,例如:\n` +
4430
+ `① Oh My Zsh 升级提示("Would you like to update Oh My Zsh? [Y/n]")——${comm} source ~/.zshrc 时弹出,等你按 Y/n,CLI 的启动命令没机会跑\n` +
4431
+ `② git 凭据弹窗(GIT_TERMINAL_PROMPT)或其它需要交互输入的启动脚本\n` +
4432
+ `③ ${cli} 的可执行文件不在 PATH 上(CLI 没找到)\n\n` +
4433
+ `修法(任选其一,改完重启 daemon 再发一条消息):\n` +
4434
+ `• 最省事:升级 botmux 到含自动注入 DISABLE_AUTO_UPDATE=true 的版本(仅 botmux 托管 shell 启动时跳过 oh-my-zsh 升级检查,不影响你自己的终端)\n` +
4435
+ `• 手动修:在 ~/.zshrc 的 source $ZSH/oh-my-zsh.sh 之前加一行 DISABLE_UPDATE_PROMPT="true"(自动升级不弹提示);或加 DISABLE_AUTO_UPDATE="true"(完全跳过升级检查)\n` +
4436
+ `• 在 web 终端里手动敲一下启动命令看报什么错;确认 CLI 二进制能在 PATH 上找到;或精简 rc 启动逻辑后重启 daemon 再试`;
4386
4437
  }
4387
4438
  send({ type: 'user_notify', turnId: currentBotmuxTurnId, dispatchAttempt: currentBotmuxDispatchAttempt, message });
4388
4439
  return true;
@@ -5300,6 +5351,9 @@ function spawnCli(cfg) {
5300
5351
  if (!isValidRiffBaseUrl(cfg.backendConfig.baseUrl)) {
5301
5352
  throw new Error(`riff baseUrl 未配置或非法(需 http(s) URL,当前: ${JSON.stringify(cfg.backendConfig.baseUrl ?? null)})——请在 dashboard 的 Riff 配置中填写`);
5302
5353
  }
5354
+ if (cfg.backendConfig.sandboxCluster !== undefined && !isValidRiffSandboxCluster(cfg.backendConfig.sandboxCluster)) {
5355
+ throw new Error(`riff sandboxCluster 非法(仅支持 boe/cn,当前: ${JSON.stringify(cfg.backendConfig.sandboxCluster)})——请在 dashboard 的 Riff 配置中重新选择`);
5356
+ }
5303
5357
  const sessionEnv = {
5304
5358
  BOTMUX_SESSION_ID: cfg.sessionId,
5305
5359
  BOTMUX_CHAT_ID: cfg.chatId,
@@ -5372,6 +5426,7 @@ function spawnCli(cfg) {
5372
5426
  // JSONL/pid/bridge gate below keys off it instead of `cliId === 'claude-code'`,
5373
5427
  // so a fork inherits the whole submit-confirm + bridge-fallback machinery.
5374
5428
  let claudeDataDir = cliAdapter.claudeDataDir;
5429
+ let effectiveReadyHookInstall = cliAdapter.hookInstall;
5375
5430
  // When this session will be file-sandboxed, the CLI's session jsonl is written
5376
5431
  // into the overlay's EPHEMERAL home upper (CLAUDE_CONFIG_DIR lives under $HOME),
5377
5432
  // invisible at the real path the bridge normally watches → "Bridge mark expired"
@@ -5382,7 +5437,10 @@ function spawnCli(cfg) {
5382
5437
  (effectiveBackendType === 'pty' || effectiveBackendType === 'tmux') &&
5383
5438
  !!process.env.SESSION_DATA_DIR;
5384
5439
  if (claudeDataDir && willFileSandbox) {
5385
- const redirected = sandboxedClaudeDataDir(cfg.sessionId, claudeDataDir);
5440
+ const redirected = sandboxedClaudeDataDir(cfg.sessionId, claudeDataDir, {
5441
+ sourceWorkingDir: cfg.workingDir,
5442
+ dataDir: process.env.SESSION_DATA_DIR,
5443
+ });
5386
5444
  log(`[sandbox] redirecting Claude bridge dataDir → overlay upper: ${redirected}`);
5387
5445
  claudeDataDir = redirected;
5388
5446
  }
@@ -5465,6 +5523,12 @@ function spawnCli(cfg) {
5465
5523
  // Provision the per-bot config dir (auth + onboarding/trust seed + hooks for claude;
5466
5524
  // auth/config copy for codex) so the CLI starts fully set up under the Seatbelt wrapper.
5467
5525
  provisionIsolatedBotHome(isolationBotHome, cfg.workingDir, isClaudeFam, cfg.cliId, cliAdapter.hookInstall, log);
5526
+ if (isClaudeFam && effectiveReadyHookInstall) {
5527
+ effectiveReadyHookInstall = {
5528
+ ...effectiveReadyHookInstall,
5529
+ configPath: join(claudeDataDir, 'settings.json'),
5530
+ };
5531
+ }
5468
5532
  if (cliAdapter.mcpGateway) {
5469
5533
  const isolatedConfigPath = isClaudeFam
5470
5534
  ? join(claudeDataDir, '.claude.json')
@@ -5586,6 +5650,26 @@ function spawnCli(cfg) {
5586
5650
  let effectiveResume = cfg.resume ?? false;
5587
5651
  let effectiveCliSessionId = cfg.cliSessionId;
5588
5652
  let effectiveAdapterSessionId = adapterSessionId;
5653
+ // Claude-family transcripts are scoped by cwd. `/cd` keeps the same Botmux /
5654
+ // CLI session id, so mirror the newest native transcript into the new cwd's
5655
+ // project directory before the adapter probes or launches `--resume`.
5656
+ // `claudeDataDir` is already the effective root here (global, per-bot read
5657
+ // isolation root, or a preserved sandbox upper), so this never crosses bot
5658
+ // isolation boundaries.
5659
+ if (effectiveResume && !willReattachPersistent && claudeDataDir) {
5660
+ const resumeSessionId = effectiveCliSessionId ?? effectiveAdapterSessionId;
5661
+ try {
5662
+ const synced = syncClaudeResumeTargetToCwd(resumeSessionId, cfg.workingDir, claudeDataDir);
5663
+ if (synced.copied && synced.sourcePath) {
5664
+ log(`Claude resume transcript synced for cwd change: ${synced.sourcePath} → ${synced.targetPath}`);
5665
+ }
5666
+ }
5667
+ catch (err) {
5668
+ // Preserve the existing fail-safe: the adapter probe / two-tier fallback
5669
+ // below still decides whether resume is possible.
5670
+ log(`WARN Claude resume transcript sync failed: ${err.message}`);
5671
+ }
5672
+ }
5589
5673
  const tier2ForceFresh = effectiveResume && consecutiveInWorkerRestarts >= 2;
5590
5674
  let tier1ProbeFalse = false;
5591
5675
  if (effectiveResume && !tier2ForceFresh && !willReattachPersistent) {
@@ -6461,15 +6545,22 @@ function spawnCli(cfg) {
6461
6545
  codexBridgeStartTimer();
6462
6546
  }
6463
6547
  }
6464
- // Arm the ready-gate for FRESH Claude-family spawns (which inject the
6465
- // SessionStart hook via --settings; see claude-code.ts buildArgs). Until
6548
+ // Arm the ready-gate for FRESH ready-integrated spawns. Until
6466
6549
  // `botmux session-ready` fires (daemon → 'session_ready' IPC → releaseReadyGate)
6467
6550
  // we hold the first prompt so a cjadk-style startup selector's ❯ can't eat it.
6468
- // shouldArmReadyGate() excludes adopt (pre-existing pane, no --settings) AND
6551
+ // shouldArmReadyGate() excludes adopt (pre-existing pane, no fresh hook) AND
6469
6552
  // persistent-backend reattach (daemon restart re-attaches an already-running
6470
6553
  // tmux/zellij/herdr Claude WITHOUT re-running its bin/args → no new
6471
6554
  // SessionStart hook → arming would hold the first post-recovery message until
6472
- // the timeout). Fallback: release after READY_SIGNAL_TIMEOUT_MS → readyPattern.
6555
+ // the timeout).
6556
+ //
6557
+ // Installation is best-effort, so verify the hook in the EFFECTIVE config
6558
+ // (global for ordinary sessions, per-bot CLAUDE_CONFIG_DIR under read
6559
+ // isolation) before arming. Isolated children also need the injected loopback
6560
+ // port plus a published rotating capability; without either the hook could
6561
+ // run but never reach the daemon. A failed preflight leaves the gate open and
6562
+ // immediately falls back to the adapter's normal readyPattern/quiescence path
6563
+ // instead of blindly waiting READY_SIGNAL_TIMEOUT_MS.
6473
6564
  readyGate = new ReadyGate();
6474
6565
  if (readySignalTimer) {
6475
6566
  clearTimeout(readySignalTimer);
@@ -6483,8 +6574,29 @@ function spawnCli(cfg) {
6483
6574
  promptReadyDetectedDuringSettle = false;
6484
6575
  // Reset quiescence baseline so the settle measures silence from THIS spawn.
6485
6576
  lastPtyOutputAtMs = Date.now();
6577
+ const readyHookAvailable = effectiveReadyHookInstall
6578
+ ? hasInstalledSessionReadyHook(effectiveReadyHookInstall)
6579
+ : true; // Hermes emits BOTMUX_READY_COMMAND directly instead of a config hook.
6580
+ const isolatedReadyTransportRequired = sandboxOn || willReadIsolate;
6581
+ const readyPortAvailable = !isolatedReadyTransportRequired
6582
+ || parseDaemonIpcPort(childEnv.BOTMUX_DAEMON_IPC_PORT) !== undefined;
6583
+ const readyCapabilityAvailable = !isolatedReadyTransportRequired
6584
+ || hasMatchingManagedOriginCapability(process.env.SESSION_DATA_DIR ?? '', cfg.sessionId, sandboxRelayCapability?.token, sandboxRelayOutbox ?? undefined);
6585
+ const readySignalAvailable = readyHookAvailable && readyPortAvailable && readyCapabilityAvailable;
6586
+ const freshReadyGateCandidate = cliAdapter.injectsReadyHook === true
6587
+ && cfg.adoptMode !== true
6588
+ && !willReattachPersistent;
6589
+ if (freshReadyGateCandidate && !readySignalAvailable) {
6590
+ const reasons = [
6591
+ ...(!readyHookAvailable ? ['SessionStart hook missing from effective config'] : []),
6592
+ ...(!readyPortAvailable ? ['BOTMUX_DAEMON_IPC_PORT missing/invalid'] : []),
6593
+ ...(!readyCapabilityAvailable ? ['ready capability transport missing, unreadable, or stale'] : []),
6594
+ ];
6595
+ log(`Ready gate skipped — preflight failed: ${reasons.join('; ')}`);
6596
+ }
6486
6597
  if (shouldArmReadyGate({
6487
6598
  injectsReadyHook: cliAdapter.injectsReadyHook === true,
6599
+ readySignalAvailable,
6488
6600
  adoptMode: cfg.adoptMode === true,
6489
6601
  willReattachPersistent,
6490
6602
  })) {