botmux 3.2.1-canary.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/dist/adapters/cli/pi.d.ts.map +1 -1
  2. package/dist/adapters/cli/pi.js +4 -0
  3. package/dist/adapters/cli/pi.js.map +1 -1
  4. package/dist/adapters/cli/types.d.ts +8 -1
  5. package/dist/adapters/cli/types.d.ts.map +1 -1
  6. package/dist/cli/deferred-topic-send.d.ts +37 -0
  7. package/dist/cli/deferred-topic-send.d.ts.map +1 -0
  8. package/dist/cli/deferred-topic-send.js +69 -0
  9. package/dist/cli/deferred-topic-send.js.map +1 -0
  10. package/dist/cli.d.ts.map +1 -1
  11. package/dist/cli.js +160 -34
  12. package/dist/cli.js.map +1 -1
  13. package/dist/core/command-handler.d.ts.map +1 -1
  14. package/dist/core/command-handler.js +17 -12
  15. package/dist/core/command-handler.js.map +1 -1
  16. package/dist/core/dashboard-ipc-server.d.ts +4 -1
  17. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  18. package/dist/core/dashboard-ipc-server.js +78 -8
  19. package/dist/core/dashboard-ipc-server.js.map +1 -1
  20. package/dist/core/deferred-schedule-settlement.d.ts +20 -0
  21. package/dist/core/deferred-schedule-settlement.d.ts.map +1 -0
  22. package/dist/core/deferred-schedule-settlement.js +18 -0
  23. package/dist/core/deferred-schedule-settlement.js.map +1 -0
  24. package/dist/core/deferred-topic-binding.d.ts +19 -0
  25. package/dist/core/deferred-topic-binding.d.ts.map +1 -0
  26. package/dist/core/deferred-topic-binding.js +55 -0
  27. package/dist/core/deferred-topic-binding.js.map +1 -0
  28. package/dist/core/scheduler.d.ts +26 -20
  29. package/dist/core/scheduler.d.ts.map +1 -1
  30. package/dist/core/scheduler.js +114 -56
  31. package/dist/core/scheduler.js.map +1 -1
  32. package/dist/core/session-discovery.d.ts.map +1 -1
  33. package/dist/core/session-discovery.js +47 -15
  34. package/dist/core/session-discovery.js.map +1 -1
  35. package/dist/core/session-manager.d.ts +17 -1
  36. package/dist/core/session-manager.d.ts.map +1 -1
  37. package/dist/core/session-manager.js +178 -84
  38. package/dist/core/session-manager.js.map +1 -1
  39. package/dist/core/types.d.ts +4 -0
  40. package/dist/core/types.d.ts.map +1 -1
  41. package/dist/core/types.js +10 -0
  42. package/dist/core/types.js.map +1 -1
  43. package/dist/core/worker-pool.d.ts +7 -0
  44. package/dist/core/worker-pool.d.ts.map +1 -1
  45. package/dist/core/worker-pool.js +51 -1
  46. package/dist/core/worker-pool.js.map +1 -1
  47. package/dist/daemon.d.ts.map +1 -1
  48. package/dist/daemon.js +90 -5
  49. package/dist/daemon.js.map +1 -1
  50. package/dist/dashboard/schedule-card-model.d.ts +12 -3
  51. package/dist/dashboard/schedule-card-model.d.ts.map +1 -1
  52. package/dist/dashboard/schedule-card-model.js +32 -8
  53. package/dist/dashboard/schedule-card-model.js.map +1 -1
  54. package/dist/dashboard/web/dashboard-components.d.ts +7 -0
  55. package/dist/dashboard/web/dashboard-components.d.ts.map +1 -1
  56. package/dist/dashboard/web/dashboard-components.js +11 -2
  57. package/dist/dashboard/web/dashboard-components.js.map +1 -1
  58. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  59. package/dist/dashboard/web/i18n.js +30 -6
  60. package/dist/dashboard/web/i18n.js.map +1 -1
  61. package/dist/dashboard/web/schedules-page.d.ts +2 -0
  62. package/dist/dashboard/web/schedules-page.d.ts.map +1 -1
  63. package/dist/dashboard/web/schedules-page.js +74 -27
  64. package/dist/dashboard/web/schedules-page.js.map +1 -1
  65. package/dist/dashboard-web/app.js +1 -1
  66. package/dist/dashboard-web/chunks/{bot-defaults-page-O37SAQD5.js → bot-defaults-page-B5AY4B2J.js} +1 -1
  67. package/dist/dashboard-web/chunks/{chunk-6QHMLMIM.js → chunk-CUV65BIQ.js} +3 -3
  68. package/dist/dashboard-web/chunks/{chunk-O2DPQL7C.js → chunk-JNRSPKLS.js} +1 -1
  69. package/dist/dashboard-web/chunks/{chunk-FYALHCPG.js → chunk-P6GO5KT4.js} +1 -1
  70. package/dist/dashboard-web/chunks/chunk-QFMH6ITB.js +1 -0
  71. package/dist/dashboard-web/chunks/{chunk-B42PCL5P.js → chunk-UBOLHQCK.js} +1 -1
  72. package/dist/dashboard-web/chunks/{connectors-page-DZBQ42MH.js → connectors-page-KTC2QWNW.js} +1 -1
  73. package/dist/dashboard-web/chunks/{groups-page-3IEGRZKQ.js → groups-page-B3EKGOLY.js} +1 -1
  74. package/dist/dashboard-web/chunks/{insights-page-X3ADRON3.js → insights-page-X6RXNCWX.js} +1 -1
  75. package/dist/dashboard-web/chunks/{monitor-room-IV36RGQY.js → monitor-room-LLRA5LQW.js} +1 -1
  76. package/dist/dashboard-web/chunks/{monitoring-page-ADFKVON4.js → monitoring-page-7MT5FEOS.js} +1 -1
  77. package/dist/dashboard-web/chunks/{office-page-CALAOWNS.js → office-page-KD46D5TD.js} +1 -1
  78. package/dist/dashboard-web/chunks/{overview-page-SLMGLK3M.js → overview-page-JUWNH32O.js} +1 -1
  79. package/dist/dashboard-web/chunks/{roles-page-L7JJ4FFV.js → roles-page-P6F7NLOI.js} +1 -1
  80. package/dist/dashboard-web/chunks/schedules-page-XIHWZST4.js +1 -0
  81. package/dist/dashboard-web/chunks/{sessions-page-OKJ5YWUZ.js → sessions-page-2VECQ27T.js} +1 -1
  82. package/dist/dashboard-web/chunks/{settings-page-P6MI2ZUE.js → settings-page-HMIUE2JA.js} +1 -1
  83. package/dist/dashboard-web/chunks/{skills-page-FT7BVZ6X.js → skills-page-A46KVWBL.js} +1 -1
  84. package/dist/dashboard-web/chunks/{team-federation-page-DEYCPUFB.js → team-federation-page-SDUC56DF.js} +1 -1
  85. package/dist/dashboard-web/chunks/{v3-page-4IOWREZG.js → v3-page-J5JOTUSQ.js} +1 -1
  86. package/dist/dashboard-web/chunks/{whiteboards-page-2VMBETZH.js → whiteboards-page-U7LSOAWI.js} +1 -1
  87. package/dist/dashboard-web/style.css +34 -4
  88. package/dist/dashboard.js +16 -1
  89. package/dist/dashboard.js.map +1 -1
  90. package/dist/i18n/en.d.ts.map +1 -1
  91. package/dist/i18n/en.js +16 -7
  92. package/dist/i18n/en.js.map +1 -1
  93. package/dist/i18n/zh.d.ts.map +1 -1
  94. package/dist/i18n/zh.js +16 -7
  95. package/dist/i18n/zh.js.map +1 -1
  96. package/dist/im/lark/ask-card.d.ts.map +1 -1
  97. package/dist/im/lark/ask-card.js +52 -4
  98. package/dist/im/lark/ask-card.js.map +1 -1
  99. package/dist/im/lark/card-handler.d.ts.map +1 -1
  100. package/dist/im/lark/card-handler.js +3 -0
  101. package/dist/im/lark/card-handler.js.map +1 -1
  102. package/dist/im/lark/event-dispatcher.d.ts +1 -0
  103. package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
  104. package/dist/im/lark/event-dispatcher.js +1 -1
  105. package/dist/im/lark/event-dispatcher.js.map +1 -1
  106. package/dist/im/lark/schedules-card.d.ts +2 -2
  107. package/dist/im/lark/schedules-card.d.ts.map +1 -1
  108. package/dist/im/lark/schedules-card.js +50 -34
  109. package/dist/im/lark/schedules-card.js.map +1 -1
  110. package/dist/index-daemon.js +13 -1
  111. package/dist/index-daemon.js.map +1 -1
  112. package/dist/services/schedule-store.d.ts +6 -2
  113. package/dist/services/schedule-store.d.ts.map +1 -1
  114. package/dist/services/schedule-store.js +19 -4
  115. package/dist/services/schedule-store.js.map +1 -1
  116. package/dist/skills/definitions.d.ts.map +1 -1
  117. package/dist/skills/definitions.js +4 -5
  118. package/dist/skills/definitions.js.map +1 -1
  119. package/dist/types.d.ts +36 -8
  120. package/dist/types.d.ts.map +1 -1
  121. package/dist/utils/child-env.d.ts +40 -1
  122. package/dist/utils/child-env.d.ts.map +1 -1
  123. package/dist/utils/child-env.js +45 -0
  124. package/dist/utils/child-env.js.map +1 -1
  125. package/dist/utils/input-gate.d.ts +0 -41
  126. package/dist/utils/input-gate.d.ts.map +1 -1
  127. package/dist/utils/input-gate.js +0 -41
  128. package/dist/utils/input-gate.js.map +1 -1
  129. package/dist/utils/pending-input-queue.d.ts +10 -0
  130. package/dist/utils/pending-input-queue.d.ts.map +1 -1
  131. package/dist/utils/pending-input-queue.js +15 -0
  132. package/dist/utils/pending-input-queue.js.map +1 -1
  133. package/dist/worker.js +105 -48
  134. package/dist/worker.js.map +1 -1
  135. package/dist/workflows/hostExecutors/botmux-schedule.d.ts +3 -1
  136. package/dist/workflows/hostExecutors/botmux-schedule.d.ts.map +1 -1
  137. package/dist/workflows/hostExecutors/botmux-schedule.js +14 -3
  138. package/dist/workflows/hostExecutors/botmux-schedule.js.map +1 -1
  139. package/dist/workflows/v3/architect.js +1 -1
  140. package/dist/workflows/v3/architect.js.map +1 -1
  141. package/dist/workflows/v3/contract.d.ts +8 -0
  142. package/dist/workflows/v3/contract.d.ts.map +1 -1
  143. package/dist/workflows/v3/contract.js.map +1 -1
  144. package/dist/workflows/v3/daemon-run.d.ts.map +1 -1
  145. package/dist/workflows/v3/daemon-run.js +2 -0
  146. package/dist/workflows/v3/daemon-run.js.map +1 -1
  147. package/dist/workflows/v3/ephemeral-pool.d.ts.map +1 -1
  148. package/dist/workflows/v3/ephemeral-pool.js +10 -2
  149. package/dist/workflows/v3/ephemeral-pool.js.map +1 -1
  150. package/dist/workflows/v3/run-envelope.d.ts +24 -24
  151. package/dist/workflows/v3/runtime.d.ts +5 -0
  152. package/dist/workflows/v3/runtime.d.ts.map +1 -1
  153. package/dist/workflows/v3/runtime.js +1 -0
  154. package/dist/workflows/v3/runtime.js.map +1 -1
  155. package/package.json +1 -1
  156. package/dist/dashboard-web/chunks/chunk-I35DXGM4.js +0 -1
  157. package/dist/dashboard-web/chunks/schedules-page-Z3672POL.js +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"pi.d.ts","sourceRoot":"","sources":["../../../src/adapters/cli/pi.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,YAAY,CAAC;AAIxD,uDAAuD;AACvD,wBAAgB,eAAe,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,UAAU,CA0CjE;AAED,eAAO,MAAM,MAAM,wBAAkB,CAAC"}
1
+ {"version":3,"file":"pi.d.ts","sourceRoot":"","sources":["../../../src/adapters/cli/pi.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,YAAY,CAAC;AAIxD,uDAAuD;AACvD,wBAAgB,eAAe,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,UAAU,CA8CjE;AAED,eAAO,MAAM,MAAM,wBAAkB,CAAC"}
@@ -22,6 +22,10 @@ export function createPiAdapter(pathOverride) {
22
22
  return `pi --session-id ${sessionId}`;
23
23
  },
24
24
  passesInitialPromptViaArgs: true,
25
+ // tmux reports "command too long" around ~12KB total launch argv on some
26
+ // deployments, well below OS ARG_MAX. Keep short Pi prompts on argv (legacy
27
+ // behavior) but route long first messages/cards through writeInput instead.
28
+ maxInitialPromptArgBytes: 4096,
25
29
  async writeInput(pty, content) {
26
30
  if (pty.pasteText && pty.sendSpecialKeys) {
27
31
  pty.pasteText(content);
@@ -1 +1 @@
1
- {"version":3,"file":"pi.js","sourceRoot":"","sources":["../../../src/adapters/cli/pi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAGvD,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAE9C,uDAAuD;AACvD,MAAM,UAAU,eAAe,CAAC,YAAqB;IACnD,MAAM,GAAG,GAAG,cAAc,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC;IACjD,OAAO;QACL,EAAE,EAAE,IAAI;QACR,SAAS,EAAE,CAAC,uBAAuB,CAAC;QACpC,WAAW,EAAE,GAAG;QAEhB,SAAS,CAAC,EAAE,SAAS,EAAE,aAAa,EAAE;YACpC,MAAM,IAAI,GAAG;gBACX,cAAc,EAAE,SAAS;aAC1B,CAAC;YACF,wEAAwE;YACxE,sEAAsE;YACtE,IAAI,aAAa;gBAAE,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YAC5C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,kBAAkB,CAAC,EAAE,SAAS,EAAE;YAC9B,OAAO,mBAAmB,SAAS,EAAE,CAAC;QACxC,CAAC;QAED,0BAA0B,EAAE,IAAI;QAEhC,KAAK,CAAC,UAAU,CAAC,GAAc,EAAE,OAAe;YAC9C,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,eAAe,EAAE,CAAC;gBACzC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;gBACvB,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;gBACjB,GAAG,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YAC/B,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,KAAK,CAAC,YAAY,OAAO,WAAW,CAAC,CAAC;gBAC1C,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;gBAClB,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;QAED,iBAAiB,EAAE,SAAS;QAC5B,WAAW,EAAE,eAAe;QAC5B,YAAY,EAAE,SAAS;QACvB,WAAW,EAAE,kBAAkB;QAC/B,SAAS,EAAE,IAAI;QACf,SAAS,EAAE,oBAAoB;KAChC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,eAAe,CAAC"}
1
+ {"version":3,"file":"pi.js","sourceRoot":"","sources":["../../../src/adapters/cli/pi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAGvD,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAE9C,uDAAuD;AACvD,MAAM,UAAU,eAAe,CAAC,YAAqB;IACnD,MAAM,GAAG,GAAG,cAAc,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC;IACjD,OAAO;QACL,EAAE,EAAE,IAAI;QACR,SAAS,EAAE,CAAC,uBAAuB,CAAC;QACpC,WAAW,EAAE,GAAG;QAEhB,SAAS,CAAC,EAAE,SAAS,EAAE,aAAa,EAAE;YACpC,MAAM,IAAI,GAAG;gBACX,cAAc,EAAE,SAAS;aAC1B,CAAC;YACF,wEAAwE;YACxE,sEAAsE;YACtE,IAAI,aAAa;gBAAE,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YAC5C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,kBAAkB,CAAC,EAAE,SAAS,EAAE;YAC9B,OAAO,mBAAmB,SAAS,EAAE,CAAC;QACxC,CAAC;QAED,0BAA0B,EAAE,IAAI;QAChC,yEAAyE;QACzE,4EAA4E;QAC5E,4EAA4E;QAC5E,wBAAwB,EAAE,IAAI;QAE9B,KAAK,CAAC,UAAU,CAAC,GAAc,EAAE,OAAe;YAC9C,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,eAAe,EAAE,CAAC;gBACzC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;gBACvB,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;gBACjB,GAAG,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YAC/B,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,KAAK,CAAC,YAAY,OAAO,WAAW,CAAC,CAAC;gBAC1C,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;gBAClB,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;QAED,iBAAiB,EAAE,SAAS;QAC5B,WAAW,EAAE,eAAe;QAC5B,YAAY,EAAE,SAAS;QACvB,WAAW,EAAE,kBAAkB;QAC/B,SAAS,EAAE,IAAI;QACf,SAAS,EAAE,oBAAoB;KAChC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,eAAe,CAAC"}
@@ -103,8 +103,15 @@ export interface CliAdapter {
103
103
  remoteThreadId?: string;
104
104
  }): string[];
105
105
  /** When true, the adapter passes the initial prompt via CLI args (e.g. -i).
106
- * The worker skips queuing the prompt for stdin write. */
106
+ * The worker skips queuing the prompt for stdin write unless another
107
+ * defer condition routes it through the post-start input queue. */
107
108
  readonly passesInitialPromptViaArgs?: boolean;
109
+ /** Only meaningful with passesInitialPromptViaArgs. If set, prompts whose
110
+ * UTF-8 byte length is GREATER than this adapter-specific limit are not
111
+ * baked into launch args; the worker defers them to the normal post-start
112
+ * input queue. This guards backend launchers (notably tmux) whose command
113
+ * string limit can be much lower than OS ARG_MAX. */
114
+ readonly maxInitialPromptArgBytes?: number;
108
115
  /** Only meaningful with passesInitialPromptViaArgs. When true, the CLI
109
116
  * silently drops its initial-prompt launch flag on a RESUME spawn (e.g.
110
117
  * OpenCode applies `--prompt` to new sessions only and ignores it with
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/adapters/cli/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/adapters/cli/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ export interface DeferredScheduleRunData {
2
+ taskId: string;
3
+ turnId: string;
4
+ routingAnchor: string;
5
+ topicTitle?: string;
6
+ createdAt: string;
7
+ }
8
+ export interface DeferredTopicSendSession {
9
+ sessionId: string;
10
+ chatId: string;
11
+ larkAppId: string;
12
+ deferredScheduleRun?: DeferredScheduleRunData;
13
+ }
14
+ export interface DeferredTopicSendResult {
15
+ handled: boolean;
16
+ messageId?: string;
17
+ rootMessageId?: string;
18
+ materializedNow?: boolean;
19
+ }
20
+ /** Route one `botmux send` effect for a lazily-materialized schedule topic.
21
+ * The per-session file lock spans the provider request so two concurrent CLI
22
+ * processes cannot both create a root. A stable provider UUID (sessionId)
23
+ * makes retry-after-local-write-failure converge on the same Lark message. */
24
+ export declare function dispatchDeferredTopicSend(opts: {
25
+ dataDir: string;
26
+ session: DeferredTopicSendSession;
27
+ currentTurnId?: string;
28
+ explicitTopLevel: boolean;
29
+ reuseBoundRootWhenTopLevel?: boolean;
30
+ content: string;
31
+ msgType: string;
32
+ uuid?: string;
33
+ sendRoot: (content: string, msgType: string, uuid: string) => Promise<string>;
34
+ sendTitleSeed: (title: string, uuid: string) => Promise<string>;
35
+ replyRoot: (rootMessageId: string, content: string, msgType: string, uuid?: string) => Promise<string>;
36
+ }): Promise<DeferredTopicSendResult>;
37
+ //# sourceMappingURL=deferred-topic-send.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deferred-topic-send.d.ts","sourceRoot":"","sources":["../../src/cli/deferred-topic-send.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,uBAAuB,CAAC;CAC/C;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;8EAG8E;AAC9E,wBAAsB,yBAAyB,CAAC,IAAI,EAAE;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,wBAAwB,CAAC;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9E,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAChE,SAAS,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACxG,GAAG,OAAO,CAAC,uBAAuB,CAAC,CA+DnC"}
@@ -0,0 +1,69 @@
1
+ import { readDeferredTopicBinding, withDeferredTopicBindingLock, writeDeferredTopicBinding, } from '../core/deferred-topic-binding.js';
2
+ /** Route one `botmux send` effect for a lazily-materialized schedule topic.
3
+ * The per-session file lock spans the provider request so two concurrent CLI
4
+ * processes cannot both create a root. A stable provider UUID (sessionId)
5
+ * makes retry-after-local-write-failure converge on the same Lark message. */
6
+ export async function dispatchDeferredTopicSend(opts) {
7
+ const run = opts.session.deferredScheduleRun;
8
+ if (!run)
9
+ return { handled: false };
10
+ return withDeferredTopicBindingLock(opts.dataDir, opts.session.sessionId, async () => {
11
+ const existing = readDeferredTopicBinding(opts.dataDir, opts.session.sessionId);
12
+ if (existing) {
13
+ if (existing.turnId !== run.turnId
14
+ || existing.chatId !== opts.session.chatId
15
+ || existing.larkAppId !== opts.session.larkAppId
16
+ || existing.routingAnchor !== run.routingAnchor) {
17
+ throw new Error('deferred topic binding identity mismatch');
18
+ }
19
+ if (opts.explicitTopLevel && !opts.reuseBoundRootWhenTopLevel)
20
+ return { handled: false };
21
+ const messageId = await opts.replyRoot(existing.rootMessageId, opts.content, opts.msgType, opts.uuid);
22
+ return { handled: true, messageId, rootMessageId: existing.rootMessageId, materializedNow: false };
23
+ }
24
+ // Only the scheduled turn itself may materialize an as-yet invisible run.
25
+ // A stale/local process without the exact turn marker must not publish it.
26
+ if (!opts.currentTurnId || opts.currentTurnId !== run.turnId) {
27
+ // A missing binding after the scheduled turn must fail closed. Falling
28
+ // through to ordinary chat-scope routing would leak a resumed/stale
29
+ // hidden session's output to the group top level. Explicit --top-level
30
+ // remains the deliberate escape hatch for an operator.
31
+ if (opts.explicitTopLevel)
32
+ return { handled: false };
33
+ throw new Error('deferred topic is not materialized for this turn');
34
+ }
35
+ const title = run.topicTitle?.trim();
36
+ let rootMessageId;
37
+ let messageId;
38
+ if (title) {
39
+ rootMessageId = await opts.sendTitleSeed(title, opts.session.sessionId);
40
+ const binding = {
41
+ sessionId: opts.session.sessionId,
42
+ turnId: run.turnId,
43
+ chatId: opts.session.chatId,
44
+ larkAppId: opts.session.larkAppId,
45
+ routingAnchor: run.routingAnchor,
46
+ rootMessageId,
47
+ createdAt: new Date().toISOString(),
48
+ };
49
+ writeDeferredTopicBinding(opts.dataDir, binding);
50
+ messageId = await opts.replyRoot(rootMessageId, opts.content, opts.msgType, opts.uuid);
51
+ }
52
+ else {
53
+ rootMessageId = await opts.sendRoot(opts.content, opts.msgType, opts.session.sessionId);
54
+ const binding = {
55
+ sessionId: opts.session.sessionId,
56
+ turnId: run.turnId,
57
+ chatId: opts.session.chatId,
58
+ larkAppId: opts.session.larkAppId,
59
+ routingAnchor: run.routingAnchor,
60
+ rootMessageId,
61
+ createdAt: new Date().toISOString(),
62
+ };
63
+ writeDeferredTopicBinding(opts.dataDir, binding);
64
+ messageId = rootMessageId;
65
+ }
66
+ return { handled: true, messageId, rootMessageId, materializedNow: true };
67
+ });
68
+ }
69
+ //# sourceMappingURL=deferred-topic-send.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deferred-topic-send.js","sourceRoot":"","sources":["../../src/cli/deferred-topic-send.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAo9EA,MAAM,MAAM,kBAAkB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,SAAS,GAAG,gBAAgB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACtE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,WAAW,GAAG,YAAY,GAAG,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAw9JrF;;;;;;;;;;;GAWG;AACH,wBAAsB,OAAO,CAC3B,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EACvC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,qBAAqB,EAAE,SAAS,CAAC,EAC9F,KAAK,EAAE,MAAM,EACb,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,2BAA2B,EAAE,UAAU,GAAG,IAAI,CAAC,GACzF,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA8F7B"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAi+EA,MAAM,MAAM,kBAAkB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,SAAS,GAAG,gBAAgB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACtE;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,WAAW,GAAG,YAAY,GAAG,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAwlKrF;;;;;;;;;;;GAWG;AACH,wBAAsB,OAAO,CAC3B,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EACvC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,qBAAqB,EAAE,SAAS,CAAC,EAC9F,KAAK,EAAE,MAAM,EACb,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,2BAA2B,EAAE,UAAU,GAAG,IAAI,CAAC,GACzF,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CA8F7B"}
package/dist/cli.js CHANGED
@@ -46,11 +46,13 @@ import { buildBotFromAddFlags, editInputFromFlags, isScriptedSetupInvocation, ma
46
46
  import { interactiveSelect, pickChoice, pickCliSelection } from './setup/interactive-select.js';
47
47
  import { buildPreset, serializePreset, presetFilename } from './setup/agent-preset.js';
48
48
  import { logger } from './utils/logger.js';
49
+ import { scrubSessionCliHomeEnv } from './utils/child-env.js';
49
50
  import { scheduleTimeZone } from './utils/timezone.js';
50
51
  import { expandHomePath, invalidWorkingDirs } from './utils/working-dir.js';
51
52
  import { firstPositional } from './cli/arg-utils.js';
52
53
  import { isColdResumeDormant, sessionListDisposition } from './cli/session-list-liveness.js';
53
54
  import { dispatchPrimaryMessage, findStdinAliasAttachment, normalizeInteractiveCardInput, sendFileAttachments, sendVideoAttachments, shouldSendAsPureVideo, validateVideoAttachments } from './cli/send-dispatch.js';
55
+ import { dispatchDeferredTopicSend } from './cli/deferred-topic-send.js';
54
56
  import { resolveDaemonExternalHostEnv } from './cli/daemon-lifecycle-env.js';
55
57
  import { buildPm2SpawnCommand } from './cli/pm2-command.js';
56
58
  import { callDashboard } from './cli/dashboard-endpoint.js';
@@ -146,7 +148,18 @@ function pm2Bin() {
146
148
  }
147
149
  /** Env for pm2 invocations with an isolated PM2_HOME. */
148
150
  function pm2Env(home = PM2_HOME) {
149
- return { ...process.env, PM2_HOME: home };
151
+ const env = { ...process.env, PM2_HOME: home };
152
+ // pm2 persists the caller's env into every managed app (and into dump.pm2
153
+ // for resurrect), so a `botmux start/restart` invoked from ANY process that
154
+ // carries a session-level CLI home pointer — most commonly a bot's own
155
+ // session during self-upgrade, whose env holds its injected
156
+ // CLAUDE_CONFIG_DIR — would poison ALL workers, making every non-isolated
157
+ // bot read/write a sibling bot's home. Strip at this boundary so the daemon
158
+ // stays session-agnostic; daemon/worker boot scrub the same keys against
159
+ // stale dumps (see SESSION_CLI_HOME_ENV_KEYS for the full story, including
160
+ // why GROK_HOME is exempt and why deleting beats pinning a default).
161
+ scrubSessionCliHomeEnv(env);
162
+ return env;
150
163
  }
151
164
  function listPm2GodDaemonPids(home = PM2_HOME) {
152
165
  if (process.platform !== 'linux')
@@ -4057,6 +4070,9 @@ async function cmdResume() {
4057
4070
  else if (errCode === 'adopt_unsupported') {
4058
4071
  console.error('❌ adopt 接管会话不支持 resume。');
4059
4072
  }
4073
+ else if (errCode === 'deferred_unmaterialized') {
4074
+ console.error('❌ 该静默定时轮次未创建话题,隐藏会话只保留审计记录,不能 resume。');
4075
+ }
4060
4076
  else {
4061
4077
  console.error(`❌ 恢复失败: ${errCode}`);
4062
4078
  }
@@ -4231,8 +4247,10 @@ botmux v${getVersion()} — IM ↔ AI 编程 CLI 桥接
4231
4247
  定时任务(可在 CLI 会话内自动推断 chat):
4232
4248
  schedule list 列出所有任务
4233
4249
  schedule add <schedule> <prompt> 添加任务(ex: "30m" / "every 2h" / "每日9:00" / "0 9 * * *")
4234
- --new-topic 每次触发在同群开一个新话题、起独立会话(不续旧话题)
4235
- --silent 静默执行:不发「执行中」提示,模型判断是否 botmux send 报警(与 --new-topic 互斥)
4250
+ --top-level 在群消息顶层执行(后续会话形态跟随普通群会话模式)
4251
+ --topic --root-msg-id <om_...> 固定在指定话题下执行
4252
+ --new-topic [--topic-title ...] 每次创建新话题和独立会话
4253
+ --silent 静默执行:不发「执行中」提示,模型判断是否 botmux send 报警
4236
4254
  schedule remove <id> 删除任务
4237
4255
  schedule pause|resume <id> 暂停/恢复
4238
4256
  schedule run <id> 标记立即执行
@@ -4711,9 +4729,9 @@ async function cmdSchedule(sub, rest) {
4711
4729
  return;
4712
4730
  }
4713
4731
  if (sub === 'add') {
4714
- const [rawSchedule, ...promptParts] = positionals(rest, ['--new-topic', '--silent']);
4732
+ const [rawSchedule, ...promptParts] = positionals(rest, ['--new-topic', '--top-level', '--topic', '--silent']);
4715
4733
  if (!rawSchedule) {
4716
- console.error('用法: botmux schedule add <schedule> <prompt> [--name NAME] [--chat-id CHAT] [--root-msg-id ROOT] [--lark-app-id APP] [--workdir DIR] [--new-topic] [--silent]');
4734
+ console.error('用法: botmux schedule add <schedule> <prompt> [--name NAME] [--chat-id CHAT] [--top-level | --topic --root-msg-id ROOT | --new-topic [--topic-title TITLE]] [--lark-app-id APP] [--workdir DIR] [--silent]');
4717
4735
  process.exit(1);
4718
4736
  }
4719
4737
  // prompt may come from positional or --prompt flag
@@ -4724,25 +4742,50 @@ async function cmdSchedule(sub, rest) {
4724
4742
  }
4725
4743
  const cur = detectCurrentSession();
4726
4744
  const chatId = argValue(rest, '--chat-id') ?? cur?.chatId;
4727
- const rootMessageId = argValue(rest, '--root-msg-id') ?? cur?.rootMessageId;
4745
+ const explicitRootMessageId = argValue(rest, '--root-msg-id');
4746
+ const rootMessageId = explicitRootMessageId
4747
+ ?? (chatId && chatId === cur?.chatId ? cur.rootMessageId : undefined);
4728
4748
  const larkAppId = argValue(rest, '--lark-app-id') ?? cur?.larkAppId;
4729
4749
  const workingDir = argValue(rest, '--workdir') ?? cur?.workingDir ?? process.cwd();
4730
4750
  const name = argValue(rest, '--name') ?? (promptArg.length > 20 ? promptArg.slice(0, 20) + '…' : promptArg);
4731
- // --new-topic: every fire opens a brand-new topic in a fresh session.
4732
- const deliver = rest.includes('--new-topic')
4733
- ? 'new-topic'
4734
- : (argValue(rest, '--deliver') ?? 'origin');
4751
+ const legacyDeliver = argValue(rest, '--deliver');
4752
+ const wantsNewTopic = rest.includes('--new-topic') || legacyDeliver === 'new-topic';
4753
+ const wantsTopLevel = rest.includes('--top-level');
4754
+ const wantsTopic = rest.includes('--topic');
4755
+ if ([wantsNewTopic, wantsTopLevel, wantsTopic].filter(Boolean).length > 1) {
4756
+ console.error('--top-level、--topic 与 --new-topic 只能选择一个。');
4757
+ process.exit(1);
4758
+ }
4759
+ const requestedDeliver = legacyDeliver;
4760
+ const deliver = requestedDeliver === 'local' ? 'local' : 'origin';
4735
4761
  // --silent: fires post no "执行中" banner; the spawned turn stays quiet and
4736
4762
  // the model only `botmux send`s when the alert condition in the prompt is met.
4737
4763
  const silent = rest.includes('--silent');
4738
- if (silent && deliver === 'new-topic') {
4739
- console.error('--silent 与 --new-topic 不能同时使用:新话题必须由首条消息开启。要「有异常才开新话题」,请在 prompt 里指示模型报警时用 botmux send 顶层发送。');
4740
- process.exit(1);
4741
- }
4742
4764
  if (!chatId) {
4743
4765
  console.error('无法推断 chat-id。请加上 --chat-id <CHAT_ID>,或从 Lark 话题内的 CLI 会话中运行本命令。');
4744
4766
  process.exit(1);
4745
4767
  }
4768
+ const executionPosition = wantsNewTopic
4769
+ ? 'new-topic'
4770
+ : wantsTopLevel
4771
+ ? 'top-level'
4772
+ : wantsTopic
4773
+ ? 'topic'
4774
+ : cur?.scope === 'chat' ? 'top-level' : rootMessageId ? 'topic' : 'top-level';
4775
+ const scope = executionPosition === 'topic' ? 'thread' : 'chat';
4776
+ if (scope === 'thread' && !rootMessageId) {
4777
+ console.error('话题下执行需要 --root-msg-id <ROOT_MESSAGE_ID>,或从 Lark 话题会话中运行。');
4778
+ process.exit(1);
4779
+ }
4780
+ const topicTitle = argValue(rest, '--topic-title');
4781
+ if (topicTitle && executionPosition !== 'new-topic') {
4782
+ console.error('--topic-title 仅可与 --new-topic 一起使用。');
4783
+ process.exit(1);
4784
+ }
4785
+ if (topicTitle && Array.from(topicTitle.trim()).length > 200) {
4786
+ console.error('--topic-title 最多 200 个字符。');
4787
+ process.exit(1);
4788
+ }
4746
4789
  let parsed;
4747
4790
  try {
4748
4791
  parsed = scheduler.parseSchedule(rawSchedule);
@@ -4764,7 +4807,9 @@ async function cmdSchedule(sub, rest) {
4764
4807
  creatorRootMessageId: cur?.rootMessageId,
4765
4808
  creatorLarkAppId: cur?.larkAppId,
4766
4809
  chatType: cur?.chatType === 'p2p' ? 'p2p' : 'topic_group',
4767
- scope: cur?.scope,
4810
+ scope,
4811
+ executionPosition,
4812
+ topicTitle,
4768
4813
  deliver,
4769
4814
  silent,
4770
4815
  });
@@ -4773,7 +4818,9 @@ async function cmdSchedule(sub, rest) {
4773
4818
  console.log(` 规则: ${parsed.display}`);
4774
4819
  console.log(` 下次执行: ${next}`);
4775
4820
  console.log(` 工作目录: ${workingDir}`);
4776
- console.log(` 话题: ${deliver === 'new-topic' ? '(每次新开话题,独立会话)' : rootMessageId ?? '(将新开)'}`);
4821
+ console.log(` 执行位置: ${executionPosition === 'new-topic' ? '每次新话题' : executionPosition === 'top-level' ? '群消息顶层' : '话题下'}`);
4822
+ if (executionPosition === 'new-topic' && topicTitle?.trim())
4823
+ console.log(` 新话题标题: ${topicTitle.trim()}`);
4777
4824
  if (silent)
4778
4825
  console.log(' 静默: 触发时不发「执行中」提示,由模型判断是否需要 botmux send 报警');
4779
4826
  return;
@@ -5417,6 +5464,10 @@ function riffModeSession(opts = {}) {
5417
5464
  const scopeEnv = process.env.BOTMUX_SESSION_SCOPE;
5418
5465
  const scope = scopeEnv === 'chat' || scopeEnv === 'thread' ? scopeEnv : (rootMessageId ? 'thread' : 'chat');
5419
5466
  const ownerOpenId = process.env.BOTMUX_OWNER_OPEN_ID;
5467
+ const deferredTaskId = process.env.BOTMUX_DEFERRED_SCHEDULE_TASK_ID;
5468
+ const deferredTurnId = process.env.BOTMUX_DEFERRED_SCHEDULE_TURN_ID;
5469
+ const deferredRoutingAnchor = process.env.BOTMUX_DEFERRED_SCHEDULE_ROUTING_ANCHOR;
5470
+ const deferredCreatedAt = process.env.BOTMUX_DEFERRED_SCHEDULE_CREATED_AT;
5420
5471
  const botConfig = {
5421
5472
  larkAppId: appId,
5422
5473
  larkAppSecret: appSecret,
@@ -5434,6 +5485,19 @@ function riffModeSession(opts = {}) {
5434
5485
  larkAppId: appId,
5435
5486
  scope,
5436
5487
  ownerOpenId,
5488
+ ...(deferredTaskId && deferredTurnId && deferredRoutingAnchor && deferredCreatedAt
5489
+ ? {
5490
+ deferredScheduleRun: {
5491
+ taskId: deferredTaskId,
5492
+ turnId: deferredTurnId,
5493
+ routingAnchor: deferredRoutingAnchor,
5494
+ ...(process.env.BOTMUX_DEFERRED_SCHEDULE_TOPIC_TITLE
5495
+ ? { topicTitle: process.env.BOTMUX_DEFERRED_SCHEDULE_TOPIC_TITLE }
5496
+ : {}),
5497
+ createdAt: deferredCreatedAt,
5498
+ },
5499
+ }
5500
+ : {}),
5437
5501
  // 刻意不设 quoteTargetSenderOpenId:env 是任务创建时冻结的,follow-up 轮
5438
5502
  // 换了触发人后 --mention-back 会错误 @ 最初 owner。riff routing 明确禁用
5439
5503
  // mention-back(@ 硬门会拒绝并提示 agent 改用 --mention <本轮 sender>)。
@@ -5707,6 +5771,8 @@ async function cmdSend(rest) {
5707
5771
  console.error(`session ${sid} 缺少 larkAppId`);
5708
5772
  process.exit(1);
5709
5773
  }
5774
+ let deferredMaterializedByThisCommand = false;
5775
+ let deferredTopicRootMessageIdForOutput;
5710
5776
  // 本轮的回复锚点:优先按 turnId 精确取 per-turn 落点(排队/并发轮次不再被
5711
5777
  // 后到轮次覆盖 currentReplyTarget 而塌成群顶层 plain),无记录再退回单槽。
5712
5778
  const turnReplyTarget = pickTurnReplyTarget(s, currentTurnId);
@@ -5855,23 +5921,45 @@ async function cmdSend(rest) {
5855
5921
  }
5856
5922
  else {
5857
5923
  revalidateVcMeetingManagedSend();
5858
- const canonicalTarget = resolveSendTarget({
5859
- into: sendInto,
5860
- topLevel: sendTopLevel,
5861
- chatScope: s.scope === 'chat',
5862
- chatId: canonicalOutput.targetChatId,
5863
- rootMessageId: s.rootMessageId,
5864
- replyTargetRootId: turnReplyTarget?.rootMessageId,
5865
- replyTargetTurnId: turnReplyTarget?.turnId,
5866
- replyTargetQuoteOnly: turnReplyTarget?.quoteOnly,
5867
- currentTurnId,
5868
- });
5869
5924
  const managedProviderOptions = prepared
5870
5925
  ? { suppressHook: true }
5871
5926
  : undefined;
5872
- messageId = canonicalTarget.mode === 'plain'
5873
- ? await sendMessage(appId, canonicalTarget.chatId, canonicalOutput.content, canonicalOutput.msgType, prepared?.providerKey, undefined, managedProviderOptions)
5874
- : await replyMessage(appId, canonicalTarget.rootMessageId, canonicalOutput.content, canonicalOutput.msgType, canonicalTarget.mode === 'thread', prepared?.providerKey, undefined, managedProviderOptions);
5927
+ const deferred = !sendInto && (!overrideChatId || overrideChatId === s.chatId)
5928
+ ? await dispatchDeferredTopicSend({
5929
+ dataDir: resolveDataDir(),
5930
+ session: s,
5931
+ currentTurnId,
5932
+ explicitTopLevel: sendTopLevel,
5933
+ reuseBoundRootWhenTopLevel: deferredMaterializedByThisCommand,
5934
+ content: canonicalOutput.content,
5935
+ msgType: canonicalOutput.msgType,
5936
+ uuid: prepared?.providerKey,
5937
+ sendRoot: (body, type, uuid) => sendMessage(appId, targetChatId, body, type, uuid, undefined, managedProviderOptions),
5938
+ sendTitleSeed: (title, uuid) => sendMessage(appId, targetChatId, title, 'text', uuid),
5939
+ replyRoot: (root, body, type, uuid) => replyMessage(appId, root, body, type, true, uuid, undefined, managedProviderOptions),
5940
+ })
5941
+ : { handled: false };
5942
+ if (deferred.handled && deferred.messageId) {
5943
+ deferredMaterializedByThisCommand ||= deferred.materializedNow === true;
5944
+ deferredTopicRootMessageIdForOutput = deferred.rootMessageId;
5945
+ messageId = deferred.messageId;
5946
+ }
5947
+ else {
5948
+ const canonicalTarget = resolveSendTarget({
5949
+ into: sendInto,
5950
+ topLevel: sendTopLevel,
5951
+ chatScope: s.scope === 'chat',
5952
+ chatId: canonicalOutput.targetChatId,
5953
+ rootMessageId: s.rootMessageId,
5954
+ replyTargetRootId: turnReplyTarget?.rootMessageId,
5955
+ replyTargetTurnId: turnReplyTarget?.turnId,
5956
+ replyTargetQuoteOnly: turnReplyTarget?.quoteOnly,
5957
+ currentTurnId,
5958
+ });
5959
+ messageId = canonicalTarget.mode === 'plain'
5960
+ ? await sendMessage(appId, canonicalTarget.chatId, canonicalOutput.content, canonicalOutput.msgType, prepared?.providerKey, undefined, managedProviderOptions)
5961
+ : await replyMessage(appId, canonicalTarget.rootMessageId, canonicalOutput.content, canonicalOutput.msgType, canonicalTarget.mode === 'thread', prepared?.providerKey, undefined, managedProviderOptions);
5962
+ }
5875
5963
  if (prepared?.kind === 'send' || prepared?.kind === 'succeeded') {
5876
5964
  finishVcMeetingImReply(resolveDataDir(), prepared.ref, messageId);
5877
5965
  }
@@ -5879,7 +5967,9 @@ async function cmdSend(rest) {
5879
5967
  recordVcMeetingPrimaryOutput(messageId, canonicalOutput.targetChatId);
5880
5968
  // 语音也是一次回复:写 bridge fallback marker,否则本轮会被判为"没发 botmux send"
5881
5969
  // 而触发兜底,多补一张文本卡。与文本/卡片路径同口径:仅同话题回复才记。
5882
- if (!sendTopLevel && !overrideChatId && !sendInto) {
5970
+ if ((!sendTopLevel || !!deferredTopicRootMessageIdForOutput)
5971
+ && (!overrideChatId || overrideChatId === s.chatId)
5972
+ && !sendInto) {
5883
5973
  try {
5884
5974
  const markerDir = join(resolveDataDir(), 'turn-sends');
5885
5975
  if (!existsSync(markerDir))
@@ -5889,7 +5979,16 @@ async function cmdSend(rest) {
5889
5979
  catch { /* best-effort:漏记只多一条兜底,不致命 */ }
5890
5980
  }
5891
5981
  console.error(`✓ 已发送语音 ${messageId} | ${Math.round(out.durationMs / 1000)}s`);
5892
- console.log(JSON.stringify({ success: true, messageId, sessionId: sid, kind: 'voice', durationMs: out.durationMs }));
5982
+ console.log(JSON.stringify({
5983
+ success: true,
5984
+ messageId,
5985
+ sessionId: sid,
5986
+ kind: 'voice',
5987
+ durationMs: out.durationMs,
5988
+ ...(deferredTopicRootMessageIdForOutput
5989
+ ? { deferredTopicRootMessageId: deferredTopicRootMessageIdForOutput, turnId: currentTurnId }
5990
+ : {}),
5991
+ }));
5893
5992
  }
5894
5993
  catch (e) {
5895
5994
  console.error(`语音发送失败:${e?.message ?? e}`);
@@ -6108,10 +6207,33 @@ async function cmdSend(rest) {
6108
6207
  // Dispatch helper: top-level / chat-scope send vs reply-in-thread, single
6109
6208
  // decision point. Used for file attachments (always plain in chat scope).
6110
6209
  const sendTarget = resolveSendTarget({ into: sendInto, topLevel: sendTopLevel, chatScope: isChatScope, chatId: targetChatId, rootMessageId: s.rootMessageId, replyTargetRootId: turnReplyTarget?.rootMessageId, replyTargetTurnId: turnReplyTarget?.turnId, replyTargetQuoteOnly: turnReplyTarget?.quoteOnly, currentTurnId });
6111
- const dispatch = (content, msgType, uuid, suppressHook) => {
6210
+ const dispatch = async (content, msgType, uuid, suppressHook) => {
6112
6211
  // This closure also carries attachments, so every Lark call re-checks the
6113
6212
  // exact durable attempt/member instead of inheriting the early cmd gate.
6114
6213
  revalidateVcMeetingManagedSend();
6214
+ if (!sendInto && (!overrideChatId || overrideChatId === s.chatId)) {
6215
+ const deferred = await dispatchDeferredTopicSend({
6216
+ dataDir: resolveDataDir(),
6217
+ session: s,
6218
+ currentTurnId,
6219
+ explicitTopLevel: sendTopLevel,
6220
+ reuseBoundRootWhenTopLevel: deferredMaterializedByThisCommand,
6221
+ content,
6222
+ msgType,
6223
+ uuid,
6224
+ sendRoot: (body, type, rootUuid) => sendMessage(appId, targetChatId, body, type, rootUuid, hookContext, suppressHook ? { suppressHook: true } : undefined),
6225
+ // The optional title is the root seed and the actual alert follows as
6226
+ // its first reply. Do not emit a user outbound hook for presentation-
6227
+ // only seed text; the alert itself still goes through the hook path.
6228
+ sendTitleSeed: (title, rootUuid) => sendMessage(appId, targetChatId, title, 'text', rootUuid),
6229
+ replyRoot: (root, body, type, replyUuid) => replyMessage(appId, root, body, type, true, replyUuid, hookContext, suppressHook ? { suppressHook: true } : undefined),
6230
+ });
6231
+ if (deferred.handled && deferred.messageId) {
6232
+ deferredMaterializedByThisCommand ||= deferred.materializedNow === true;
6233
+ deferredTopicRootMessageIdForOutput = deferred.rootMessageId;
6234
+ return deferred.messageId;
6235
+ }
6236
+ }
6115
6237
  return sendTarget.mode === 'plain'
6116
6238
  ? sendMessage(appId, sendTarget.chatId, content, msgType, uuid, hookContext, suppressHook ? { suppressHook: true } : undefined)
6117
6239
  : replyMessage(appId, sendTarget.rootMessageId, content, msgType, sendTarget.mode === 'thread', uuid, hookContext, suppressHook ? { suppressHook: true } : undefined);
@@ -6538,8 +6660,9 @@ async function cmdSend(rest) {
6538
6660
  // sends can suppress transcript fallback when their content appears to
6539
6661
  // cover the same final answer; detoured sends suppress only when they
6540
6662
  // closed a pending response card for this turn.
6541
- if (shouldRecordBridgeMarker)
6663
+ if (shouldRecordBridgeMarker || deferredTopicRootMessageIdForOutput) {
6542
6664
  recordBridgeSendMarker(sentAtMs, messageId, text);
6665
+ }
6543
6666
  // Send attachments as separate messages — best-effort. The primary message
6544
6667
  // is already delivered above; a failing attachment must not throw out to the
6545
6668
  // catch below (which would report total failure / exit 1 for an already-sent
@@ -6619,6 +6742,9 @@ async function cmdSend(rest) {
6619
6742
  sessionId: sid,
6620
6743
  quotedMessageId: primaryQuotedId,
6621
6744
  mentioned: mentions.map(m => ({ open_id: m.open_id, name: m.name })),
6745
+ ...(deferredTopicRootMessageIdForOutput
6746
+ ? { deferredTopicRootMessageId: deferredTopicRootMessageIdForOutput, turnId: currentTurnId }
6747
+ : {}),
6622
6748
  ...(attention.requested ? { attentionRaised, attentionError } : {}),
6623
6749
  ...(failedAttachments.length > 0
6624
6750
  ? { failedAttachments: failedAttachments.map(f => f.path) }