botmux 2.64.0 → 2.65.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 (208) hide show
  1. package/README.en.md +1 -1
  2. package/README.md +3 -3
  3. package/dist/adapters/backend/herdr-backend.d.ts +8 -1
  4. package/dist/adapters/backend/herdr-backend.d.ts.map +1 -1
  5. package/dist/adapters/backend/herdr-backend.js +15 -2
  6. package/dist/adapters/backend/herdr-backend.js.map +1 -1
  7. package/dist/adapters/backend/tmux-backend.d.ts +17 -1
  8. package/dist/adapters/backend/tmux-backend.d.ts.map +1 -1
  9. package/dist/adapters/backend/tmux-backend.js +25 -4
  10. package/dist/adapters/backend/tmux-backend.js.map +1 -1
  11. package/dist/adapters/backend/types.d.ts +14 -0
  12. package/dist/adapters/backend/types.d.ts.map +1 -1
  13. package/dist/adapters/backend/types.js.map +1 -1
  14. package/dist/adapters/backend/zellij-backend.d.ts +12 -1
  15. package/dist/adapters/backend/zellij-backend.d.ts.map +1 -1
  16. package/dist/adapters/backend/zellij-backend.js +25 -8
  17. package/dist/adapters/backend/zellij-backend.js.map +1 -1
  18. package/dist/bot-registry.d.ts +39 -0
  19. package/dist/bot-registry.d.ts.map +1 -1
  20. package/dist/bot-registry.js +30 -0
  21. package/dist/bot-registry.js.map +1 -1
  22. package/dist/cli/send-dispatch.d.ts +23 -0
  23. package/dist/cli/send-dispatch.d.ts.map +1 -0
  24. package/dist/cli/send-dispatch.js +23 -0
  25. package/dist/cli/send-dispatch.js.map +1 -0
  26. package/dist/cli.d.ts.map +1 -1
  27. package/dist/cli.js +141 -58
  28. package/dist/cli.js.map +1 -1
  29. package/dist/config.d.ts +8 -6
  30. package/dist/config.d.ts.map +1 -1
  31. package/dist/config.js +8 -6
  32. package/dist/config.js.map +1 -1
  33. package/dist/core/ask-broker.d.ts +33 -0
  34. package/dist/core/ask-broker.d.ts.map +1 -1
  35. package/dist/core/ask-broker.js +58 -0
  36. package/dist/core/ask-broker.js.map +1 -1
  37. package/dist/core/ask-hook/claude-code.d.ts.map +1 -1
  38. package/dist/core/ask-hook/claude-code.js +15 -9
  39. package/dist/core/ask-hook/claude-code.js.map +1 -1
  40. package/dist/core/ask-hook/codex.d.ts.map +1 -1
  41. package/dist/core/ask-hook/codex.js +2 -1
  42. package/dist/core/ask-hook/codex.js.map +1 -1
  43. package/dist/core/ask-hook/opencode.d.ts.map +1 -1
  44. package/dist/core/ask-hook/opencode.js +9 -6
  45. package/dist/core/ask-hook/opencode.js.map +1 -1
  46. package/dist/core/ask-hook/types.d.ts +3 -1
  47. package/dist/core/ask-hook/types.d.ts.map +1 -1
  48. package/dist/core/ask-types.d.ts +13 -6
  49. package/dist/core/ask-types.d.ts.map +1 -1
  50. package/dist/core/ask-types.js.map +1 -1
  51. package/dist/core/command-handler.d.ts.map +1 -1
  52. package/dist/core/command-handler.js +255 -4
  53. package/dist/core/command-handler.js.map +1 -1
  54. package/dist/core/daemon-heartbeat.d.ts +15 -0
  55. package/dist/core/daemon-heartbeat.d.ts.map +1 -0
  56. package/dist/core/daemon-heartbeat.js +83 -0
  57. package/dist/core/daemon-heartbeat.js.map +1 -0
  58. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  59. package/dist/core/dashboard-ipc-server.js +80 -33
  60. package/dist/core/dashboard-ipc-server.js.map +1 -1
  61. package/dist/core/dispatch.d.ts +1 -23
  62. package/dist/core/dispatch.d.ts.map +1 -1
  63. package/dist/core/dispatch.js +1 -17
  64. package/dist/core/dispatch.js.map +1 -1
  65. package/dist/core/idle-worker-sweeper.d.ts +13 -0
  66. package/dist/core/idle-worker-sweeper.d.ts.map +1 -0
  67. package/dist/core/idle-worker-sweeper.js +42 -0
  68. package/dist/core/idle-worker-sweeper.js.map +1 -0
  69. package/dist/core/maintenance-schedule.d.ts +34 -0
  70. package/dist/core/maintenance-schedule.d.ts.map +1 -0
  71. package/dist/core/maintenance-schedule.js +72 -0
  72. package/dist/core/maintenance-schedule.js.map +1 -0
  73. package/dist/core/maintenance.d.ts +43 -0
  74. package/dist/core/maintenance.d.ts.map +1 -0
  75. package/dist/core/maintenance.js +160 -0
  76. package/dist/core/maintenance.js.map +1 -0
  77. package/dist/core/reply-target.d.ts +23 -0
  78. package/dist/core/reply-target.d.ts.map +1 -0
  79. package/dist/core/reply-target.js +47 -0
  80. package/dist/core/reply-target.js.map +1 -0
  81. package/dist/core/restart-report.d.ts +49 -0
  82. package/dist/core/restart-report.d.ts.map +1 -0
  83. package/dist/core/restart-report.js +98 -0
  84. package/dist/core/restart-report.js.map +1 -0
  85. package/dist/core/scheduler.d.ts.map +1 -1
  86. package/dist/core/scheduler.js +20 -0
  87. package/dist/core/scheduler.js.map +1 -1
  88. package/dist/core/session-manager.d.ts +26 -10
  89. package/dist/core/session-manager.d.ts.map +1 -1
  90. package/dist/core/session-manager.js +104 -26
  91. package/dist/core/session-manager.js.map +1 -1
  92. package/dist/core/session-marker.d.ts +13 -0
  93. package/dist/core/session-marker.d.ts.map +1 -0
  94. package/dist/core/session-marker.js +55 -0
  95. package/dist/core/session-marker.js.map +1 -0
  96. package/dist/core/types.d.ts +20 -1
  97. package/dist/core/types.d.ts.map +1 -1
  98. package/dist/core/types.js.map +1 -1
  99. package/dist/core/worker-budget.d.ts +19 -0
  100. package/dist/core/worker-budget.d.ts.map +1 -0
  101. package/dist/core/worker-budget.js +50 -0
  102. package/dist/core/worker-budget.js.map +1 -0
  103. package/dist/core/worker-pool.d.ts +5 -2
  104. package/dist/core/worker-pool.d.ts.map +1 -1
  105. package/dist/core/worker-pool.js +105 -12
  106. package/dist/core/worker-pool.js.map +1 -1
  107. package/dist/daemon.d.ts.map +1 -1
  108. package/dist/daemon.js +243 -38
  109. package/dist/daemon.js.map +1 -1
  110. package/dist/dashboard/web/bot-defaults.d.ts.map +1 -1
  111. package/dist/dashboard/web/bot-defaults.js +118 -0
  112. package/dist/dashboard/web/bot-defaults.js.map +1 -1
  113. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  114. package/dist/dashboard/web/i18n.js +44 -0
  115. package/dist/dashboard/web/i18n.js.map +1 -1
  116. package/dist/dashboard/web/settings.d.ts.map +1 -1
  117. package/dist/dashboard/web/settings.js +84 -13
  118. package/dist/dashboard/web/settings.js.map +1 -1
  119. package/dist/dashboard-web/app.js +568 -503
  120. package/dist/dashboard.js +87 -7
  121. package/dist/dashboard.js.map +1 -1
  122. package/dist/global-config.d.ts +46 -0
  123. package/dist/global-config.d.ts.map +1 -1
  124. package/dist/global-config.js +115 -0
  125. package/dist/global-config.js.map +1 -1
  126. package/dist/i18n/en.d.ts.map +1 -1
  127. package/dist/i18n/en.js +72 -1
  128. package/dist/i18n/en.js.map +1 -1
  129. package/dist/i18n/zh.d.ts.map +1 -1
  130. package/dist/i18n/zh.js +72 -1
  131. package/dist/i18n/zh.js.map +1 -1
  132. package/dist/im/lark/ask-card.d.ts.map +1 -1
  133. package/dist/im/lark/ask-card.js +15 -1
  134. package/dist/im/lark/ask-card.js.map +1 -1
  135. package/dist/im/lark/card-builder.d.ts +17 -0
  136. package/dist/im/lark/card-builder.d.ts.map +1 -1
  137. package/dist/im/lark/card-builder.js +146 -0
  138. package/dist/im/lark/card-builder.js.map +1 -1
  139. package/dist/im/lark/card-handler.d.ts.map +1 -1
  140. package/dist/im/lark/card-handler.js +119 -4
  141. package/dist/im/lark/card-handler.js.map +1 -1
  142. package/dist/im/lark/client.d.ts +3 -2
  143. package/dist/im/lark/client.d.ts.map +1 -1
  144. package/dist/im/lark/client.js +28 -2
  145. package/dist/im/lark/client.js.map +1 -1
  146. package/dist/im/lark/event-dispatcher.d.ts +7 -17
  147. package/dist/im/lark/event-dispatcher.d.ts.map +1 -1
  148. package/dist/im/lark/event-dispatcher.js +170 -50
  149. package/dist/im/lark/event-dispatcher.js.map +1 -1
  150. package/dist/im/lark/message-parser.d.ts +1 -0
  151. package/dist/im/lark/message-parser.d.ts.map +1 -1
  152. package/dist/im/lark/message-parser.js +1 -0
  153. package/dist/im/lark/message-parser.js.map +1 -1
  154. package/dist/im/lark/reply-mode-command.d.ts +2 -0
  155. package/dist/im/lark/reply-mode-command.d.ts.map +1 -0
  156. package/dist/im/lark/reply-mode-command.js +102 -0
  157. package/dist/im/lark/reply-mode-command.js.map +1 -0
  158. package/dist/services/bot-config-store.d.ts +144 -0
  159. package/dist/services/bot-config-store.d.ts.map +1 -0
  160. package/dist/services/bot-config-store.js +241 -0
  161. package/dist/services/bot-config-store.js.map +1 -0
  162. package/dist/services/card-prefs-store.d.ts +5 -0
  163. package/dist/services/card-prefs-store.d.ts.map +1 -1
  164. package/dist/services/card-prefs-store.js +47 -0
  165. package/dist/services/card-prefs-store.js.map +1 -1
  166. package/dist/services/chat-reply-mode-store.d.ts +28 -0
  167. package/dist/services/chat-reply-mode-store.d.ts.map +1 -0
  168. package/dist/services/chat-reply-mode-store.js +115 -0
  169. package/dist/services/chat-reply-mode-store.js.map +1 -0
  170. package/dist/services/hook-runner.d.ts +43 -0
  171. package/dist/services/hook-runner.d.ts.map +1 -0
  172. package/dist/services/hook-runner.js +394 -0
  173. package/dist/services/hook-runner.js.map +1 -0
  174. package/dist/services/restart-intent-store.d.ts +26 -0
  175. package/dist/services/restart-intent-store.d.ts.map +1 -0
  176. package/dist/services/restart-intent-store.js +84 -0
  177. package/dist/services/restart-intent-store.js.map +1 -0
  178. package/dist/services/session-lifecycle-hooks.d.ts +10 -0
  179. package/dist/services/session-lifecycle-hooks.d.ts.map +1 -0
  180. package/dist/services/session-lifecycle-hooks.js +66 -0
  181. package/dist/services/session-lifecycle-hooks.js.map +1 -0
  182. package/dist/services/session-store.d.ts +6 -0
  183. package/dist/services/session-store.d.ts.map +1 -1
  184. package/dist/services/session-store.js +25 -0
  185. package/dist/services/session-store.js.map +1 -1
  186. package/dist/skills/definitions.d.ts.map +1 -1
  187. package/dist/skills/definitions.js +28 -3
  188. package/dist/skills/definitions.js.map +1 -1
  189. package/dist/types.d.ts +33 -0
  190. package/dist/types.d.ts.map +1 -1
  191. package/dist/utils/install-info.d.ts +13 -0
  192. package/dist/utils/install-info.d.ts.map +1 -0
  193. package/dist/utils/install-info.js +56 -0
  194. package/dist/utils/install-info.js.map +1 -0
  195. package/dist/utils/listen-with-probe.d.ts +26 -0
  196. package/dist/utils/listen-with-probe.d.ts.map +1 -0
  197. package/dist/utils/listen-with-probe.js +64 -0
  198. package/dist/utils/listen-with-probe.js.map +1 -0
  199. package/dist/utils/web-terminal-listen.d.ts +30 -0
  200. package/dist/utils/web-terminal-listen.d.ts.map +1 -0
  201. package/dist/utils/web-terminal-listen.js +81 -0
  202. package/dist/utils/web-terminal-listen.js.map +1 -0
  203. package/dist/worker.js +71 -44
  204. package/dist/worker.js.map +1 -1
  205. package/dist/workflows/definition.d.ts +30 -30
  206. package/dist/workflows/events/payloads.d.ts +4 -4
  207. package/dist/workflows/events/schema.d.ts +156 -156
  208. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAiBA;;6DAE6D;AAC7D,MAAM,UAAU,iBAAiB,CAAC,EAAc;IAC9C,IAAI,EAAE,CAAC,WAAW,KAAK,YAAY,IAAI,EAAE,CAAC,WAAW,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC,WAAW,CAAC;IAC1F,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC/C,CAAC;AAqGD;;;;;uDAKuD;AACvD,MAAM,UAAU,UAAU,CAAC,QAAgB,EAAE,SAAiB;IAC5D,OAAO,GAAG,QAAQ,KAAK,SAAS,EAAE,CAAC;AACrC,CAAC;AAED;;+BAE+B;AAC/B,MAAM,UAAU,eAAe,CAAC,EAAiB;IAC/C,OAAO,EAAE,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC;AACpE,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAiBA;;6DAE6D;AAC7D,MAAM,UAAU,iBAAiB,CAAC,EAAc;IAC9C,IAAI,EAAE,CAAC,WAAW,KAAK,YAAY,IAAI,EAAE,CAAC,WAAW,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC,WAAW,CAAC;IAC1F,OAAO,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC/C,CAAC;AA6GD;;;;;uDAKuD;AACvD,MAAM,UAAU,UAAU,CAAC,QAAgB,EAAE,SAAiB;IAC5D,OAAO,GAAG,QAAQ,KAAK,SAAS,EAAE,CAAC;AACrC,CAAC;AAED;;+BAE+B;AAC/B,MAAM,UAAU,eAAe,CAAC,EAAiB;IAC/C,OAAO,EAAE,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC;AACpE,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { WorkerConfig } from '../global-config.js';
2
+ export declare const MIN_AUTO_MAX_LIVE_WORKERS = 4;
3
+ export declare const MAX_AUTO_MAX_LIVE_WORKERS = 32;
4
+ export declare const DEFAULT_IDLE_SUSPEND_MS: number;
5
+ export interface WorkerResources {
6
+ cpuCount: number;
7
+ memoryBytes: number;
8
+ }
9
+ export interface ResolvedWorkerBudget {
10
+ maxLiveWorkers: number;
11
+ idleSuspendMs: number;
12
+ autoMaxLiveWorkers: number;
13
+ maxLiveWorkersSource: 'auto' | 'config';
14
+ idleSuspendMsSource: 'default' | 'config';
15
+ }
16
+ export declare function detectWorkerResources(): WorkerResources;
17
+ export declare function autoMaxLiveWorkers(resources?: WorkerResources): number;
18
+ export declare function resolveWorkerBudget(workerConfig?: WorkerConfig, resources?: WorkerResources): ResolvedWorkerBudget;
19
+ //# sourceMappingURL=worker-budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-budget.d.ts","sourceRoot":"","sources":["../../src/core/worker-budget.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAC3C,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAC5C,eAAO,MAAM,uBAAuB,QAAc,CAAC;AAEnD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,GAAG,QAAQ,CAAC;IACxC,mBAAmB,EAAE,SAAS,GAAG,QAAQ,CAAC;CAC3C;AAwBD,wBAAgB,qBAAqB,IAAI,eAAe,CAMvD;AAED,wBAAgB,kBAAkB,CAAC,SAAS,GAAE,eAAyC,GAAG,MAAM,CAI/F;AAED,wBAAgB,mBAAmB,CACjC,YAAY,CAAC,EAAE,YAAY,EAC3B,SAAS,GAAE,eAAyC,GACnD,oBAAoB,CAStB"}
@@ -0,0 +1,50 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { availableParallelism, totalmem } from 'node:os';
3
+ export const MIN_AUTO_MAX_LIVE_WORKERS = 4;
4
+ export const MAX_AUTO_MAX_LIVE_WORKERS = 32;
5
+ export const DEFAULT_IDLE_SUSPEND_MS = 30 * 60_000;
6
+ function clamp(n, min, max) {
7
+ return Math.max(min, Math.min(max, n));
8
+ }
9
+ function readMemoryLimitFile(path) {
10
+ if (!existsSync(path))
11
+ return undefined;
12
+ const raw = readFileSync(path, 'utf-8').trim();
13
+ if (!raw || raw === 'max')
14
+ return undefined;
15
+ const n = Number(raw);
16
+ return Number.isFinite(n) && n > 0 ? n : undefined;
17
+ }
18
+ function cgroupMemoryLimitBytes(hostMemoryBytes) {
19
+ const limits = [
20
+ readMemoryLimitFile('/sys/fs/cgroup/memory.max'),
21
+ readMemoryLimitFile('/sys/fs/cgroup/memory/memory.limit_in_bytes'),
22
+ ].filter((n) => n !== undefined);
23
+ if (limits.length === 0)
24
+ return undefined;
25
+ const limit = Math.min(...limits);
26
+ return limit < hostMemoryBytes ? limit : undefined;
27
+ }
28
+ export function detectWorkerResources() {
29
+ const hostMemoryBytes = totalmem();
30
+ return {
31
+ cpuCount: Math.max(1, availableParallelism?.() ?? 1),
32
+ memoryBytes: cgroupMemoryLimitBytes(hostMemoryBytes) ?? hostMemoryBytes,
33
+ };
34
+ }
35
+ export function autoMaxLiveWorkers(resources = detectWorkerResources()) {
36
+ const cpuBudget = Math.max(1, resources.cpuCount) * 2;
37
+ const memoryBudget = Math.max(1, Math.round(resources.memoryBytes / 1024 ** 3));
38
+ return clamp(Math.min(cpuBudget, memoryBudget), MIN_AUTO_MAX_LIVE_WORKERS, MAX_AUTO_MAX_LIVE_WORKERS);
39
+ }
40
+ export function resolveWorkerBudget(workerConfig, resources = detectWorkerResources()) {
41
+ const auto = autoMaxLiveWorkers(resources);
42
+ return {
43
+ maxLiveWorkers: workerConfig?.maxLiveWorkers ?? auto,
44
+ idleSuspendMs: workerConfig?.idleSuspendMs ?? DEFAULT_IDLE_SUSPEND_MS,
45
+ autoMaxLiveWorkers: auto,
46
+ maxLiveWorkersSource: workerConfig?.maxLiveWorkers === undefined ? 'auto' : 'config',
47
+ idleSuspendMsSource: workerConfig?.idleSuspendMs === undefined ? 'default' : 'config',
48
+ };
49
+ }
50
+ //# sourceMappingURL=worker-budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-budget.js","sourceRoot":"","sources":["../../src/core/worker-budget.ts"],"names":[],"mappings":"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"}
@@ -4,11 +4,12 @@
4
4
  */
5
5
  import { type ChildProcess } from 'node:child_process';
6
6
  import type { CliId } from '../adapters/cli/types.js';
7
+ import type { BackendType } from '../adapters/backend/types.js';
7
8
  import type { WorkerToDaemon, Session } from '../types.js';
8
9
  import { type DaemonSession } from './types.js';
9
10
  import { type CliUsageLimitState } from '../utils/cli-usage-limit.js';
10
11
  export interface WorkerPoolCallbacks {
11
- sessionReply: (rootId: string, content: string, msgType?: string, larkAppId?: string) => Promise<string>;
12
+ sessionReply: (rootId: string, content: string, msgType?: string, larkAppId?: string, turnId?: string) => Promise<string>;
12
13
  getSessionWorkingDir: (ds?: DaemonSession) => string;
13
14
  getActiveCount: () => number;
14
15
  /** Close a stale session (message withdrawn, etc.) */
@@ -107,7 +108,7 @@ export declare function recallFrozenCards(ds: DaemonSession): void;
107
108
  * Note: this does NOT itself flip `ds.streamingCardForced` — the caller sets
108
109
  * that so the card keeps live-patching afterwards even when the bot opted out.
109
110
  */
110
- export declare function postFreshStreamingCard(ds: DaemonSession, sessionReply: (rootId: string, content: string, msgType?: string, larkAppId?: string) => Promise<string>): Promise<boolean>;
111
+ export declare function postFreshStreamingCard(ds: DaemonSession, sessionReply: (rootId: string, content: string, msgType?: string, larkAppId?: string, turnId?: string) => Promise<string>): Promise<boolean>;
111
112
  /**
112
113
  * Audience for a private `/card`: the bot's `allowedUsers` (the canOperate set —
113
114
  * owner & co-owners), deduped, `ou_` only. Talk-only grants (`globalGrants` /
@@ -189,6 +190,8 @@ export declare function ensureCliEnv(cliId: CliId, cliPathOverride?: string): vo
189
190
  * clobbers other keys; any failure is swallowed so it can't block spawn. */
190
191
  export declare function ensureClaudeFolderTrust(workingDir: string, stateJsonPath?: string): void;
191
192
  export declare function killWorker(ds: DaemonSession): void;
193
+ export declare function isSuspendableBackendType(backendType: BackendType | undefined): boolean;
194
+ export declare function suspendWorker(ds: DaemonSession, reason?: string): boolean;
192
195
  /**
193
196
  * Idempotent close: kill worker if alive, mark Session status='closed' + closedAt,
194
197
  * publish session.exited (if a live worker was killed) and session.update
@@ -1 +1 @@
1
- {"version":3,"file":"worker-pool.d.ts","sourceRoot":"","sources":["../../src/core/worker-pool.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"worker-pool.d.ts","sourceRoot":"","sources":["../../src/core/worker-pool.ts"],"names":[],"mappings":"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"}
@@ -32,6 +32,7 @@ import { dashboardEventBus } from './dashboard-events.js';
32
32
  import { composeRowFromActive } from './dashboard-rows.js';
33
33
  import { publishAttentionPatch } from './session-activity.js';
34
34
  import { knownBotOpenIdsFromCrossRef } from '../utils/bot-routing.js';
35
+ import { emitSessionLifecycleHook, emitSessionStateTransitionHook } from '../services/session-lifecycle-hooks.js';
35
36
  import { sessionKey, sessionAnchorId } from './types.js';
36
37
  import { claimPendingResponseCard, COMPLETED_REACTION_EMOJI_TYPE, markPendingResponseCardPatchedIfCurrent, syncPendingResponseState } from './pending-response.js';
37
38
  import { buildTerminalUrl } from './terminal-url.js';
@@ -375,7 +376,7 @@ export async function postFreshStreamingCard(ds, sessionReply) {
375
376
  const cardJson = buildStreamingCard(ds.session.sessionId, sessionAnchorId(ds), readUrl, title, ds.lastScreenContent ?? '', status, effectiveCliId, ds.displayMode ?? 'hidden', ds.streamCardNonce, ds.currentImageKey, !!ds.adoptedFrom, false, localeForBot(ds.larkAppId), cardUsageLimit(ds), writableTerminalLinkFor(ds));
376
377
  ds.streamCardId = CARD_POSTING_SENTINEL;
377
378
  try {
378
- ds.streamCardId = await sessionReply(sessionAnchorId(ds), cardJson, 'interactive', ds.larkAppId);
379
+ ds.streamCardId = await sessionReply(sessionAnchorId(ds), cardJson, 'interactive', ds.larkAppId, ds.currentReplyTarget?.turnId);
379
380
  // This card is now the live one for the current turn. Clear the new-turn
380
381
  // pending flag so the next screen_update PATCHes it instead of POSTing a
381
382
  // duplicate (the gate above only suppresses cards when disabled+unforced;
@@ -804,6 +805,41 @@ export function killWorker(ds) {
804
805
  ds.workerPort = null;
805
806
  ds.workerToken = null;
806
807
  }
808
+ export function isSuspendableBackendType(backendType) {
809
+ return backendType === 'tmux' || backendType === 'herdr' || backendType === 'zellij';
810
+ }
811
+ export function suspendWorker(ds, reason = 'suspended_idle') {
812
+ if (!ds.worker || ds.worker.killed)
813
+ return false;
814
+ if (!isSuspendableBackendType(ds.initConfig?.backendType))
815
+ return false;
816
+ const w = ds.worker;
817
+ try {
818
+ w.send({ type: 'suspend' });
819
+ }
820
+ catch {
821
+ try {
822
+ w.kill('SIGTERM');
823
+ }
824
+ catch { /* already gone */ }
825
+ }
826
+ armWorkerKillBackstop(w, tag(ds));
827
+ ds.worker = null;
828
+ ds.workerPort = null;
829
+ ds.workerToken = null;
830
+ ds.session.webPort = undefined;
831
+ sessionStore.updateSessionPid(ds.session.sessionId, null);
832
+ sessionStore.updateSession(ds.session);
833
+ if (!ds.exitEventEmitted) {
834
+ ds.exitEventEmitted = true;
835
+ dashboardEventBus.publish({
836
+ type: 'session.exited',
837
+ body: { sessionId: ds.session.sessionId, reason },
838
+ });
839
+ }
840
+ logger.info(`[${tag(ds)}] Worker suspended (${reason}); session remains active`);
841
+ return true;
842
+ }
807
843
  function armWorkerKillBackstop(w, label) {
808
844
  const sigterm = setTimeout(() => {
809
845
  if (w.exitCode === null && w.signalCode === null) {
@@ -851,6 +887,7 @@ export async function closeSession(sessionId) {
851
887
  type: 'session.exited',
852
888
  body: { sessionId, reason: 'dashboard_close' },
853
889
  });
890
+ emitSessionLifecycleHook(ds, 'session.exit', { reason: 'dashboard_close' });
854
891
  }
855
892
  }
856
893
  // Persistence path — load → mark closed → save (delegated to sessionStore).
@@ -1204,6 +1241,7 @@ export function forkWorker(ds, prompt, resume = false) {
1204
1241
  botName: bot.botName,
1205
1242
  botOpenId: bot.botOpenId,
1206
1243
  locale: botLocale(botCfg),
1244
+ turnId: ds.currentReplyTarget?.turnId,
1207
1245
  };
1208
1246
  worker.send(initMsg);
1209
1247
  ds.initConfig = initMsg;
@@ -1230,11 +1268,16 @@ export function forkWorker(ds, prompt, resume = false) {
1230
1268
  type: 'session.spawned',
1231
1269
  body: { session: composeRowFromActive(ds) },
1232
1270
  });
1271
+ emitSessionLifecycleHook(ds, 'session.start', {
1272
+ reason: resume ? 'resume' : 'worker_spawn',
1273
+ pid: worker.pid ?? null,
1274
+ });
1233
1275
  }
1234
1276
  // ─── Shared worker IPC handler ──────────────────────────────────────────────
1235
1277
  function setupWorkerHandlers(ds, worker) {
1236
1278
  const cb = requireCallbacks();
1237
1279
  const t = tag(ds);
1280
+ const scopedReply = (content, msgType, turnId) => cb.sessionReply(sessionAnchorId(ds), content, msgType, ds.larkAppId, turnId);
1238
1281
  const bot = getBot(ds.larkAppId);
1239
1282
  const botCfg = bot.config;
1240
1283
  const loc = botLocale(botCfg);
@@ -1274,6 +1317,15 @@ function setupWorkerHandlers(ds, worker) {
1274
1317
  logger.info(`[${t}] Streaming card disabled for this bot — skipping card post`);
1275
1318
  break;
1276
1319
  }
1320
+ // Restart recovery: stay silent in the group. The session was restored
1321
+ // after a daemon restart; don't auto-post/patch a streaming card here.
1322
+ // The owner gets a private DM summary instead, and the surviving card
1323
+ // (if any) is left untouched. The next real user turn clears this flag
1324
+ // (rememberLastCliInput) and the normal card flow resumes.
1325
+ if (ds.suppressRecoveryCard) {
1326
+ logger.info(`[${t}] Restored session — suppressing recovery streaming card (silent restart)`);
1327
+ break;
1328
+ }
1277
1329
  // If a previous streaming card survived (e.g. daemon restart), try to
1278
1330
  // PATCH it with the new "starting" state instead of POSTing a fresh card.
1279
1331
  // ds.streamCardPending forces a new card (e.g. mid-session repo switch
@@ -1332,7 +1384,7 @@ function setupWorkerHandlers(ds, worker) {
1332
1384
  // before the first screen_update lands. Fresh worker spawn
1333
1385
  // has lastScreenContent undefined → '' (unchanged).
1334
1386
  ds.lastScreenContent ?? '', initStatus, effectiveCliId, ds.displayMode ?? 'hidden', ds.streamCardNonce, ds.currentImageKey, isAdopt, showTakeover, loc, initStatus === 'limited' ? ds.usageLimit : undefined, writableTerminalLinkFor(ds));
1335
- ds.streamCardId = await cb.sessionReply(sessionAnchorId(ds), streamCardJson, 'interactive', ds.larkAppId);
1387
+ ds.streamCardId = await scopedReply(streamCardJson, 'interactive', msg.turnId);
1336
1388
  // This card IS the current turn's live card — clear the new-turn flag
1337
1389
  // so subsequent screen_updates PATCH it (starting → working) instead of
1338
1390
  // POSTing a second card. Without this, a re-fork that happens while
@@ -1366,7 +1418,7 @@ function setupWorkerHandlers(ds, worker) {
1366
1418
  // Fallback: send static session card
1367
1419
  try {
1368
1420
  const cardJson = buildSessionCard(ds.session.sessionId, sessionAnchorId(ds), readOnlyUrl, ds.session.title || getCliDisplayName(effectiveCliId), effectiveCliId, undefined, !!ds.adoptedFrom, loc);
1369
- await cb.sessionReply(sessionAnchorId(ds), cardJson, 'interactive', ds.larkAppId);
1421
+ await scopedReply(cardJson, 'interactive', msg.turnId);
1370
1422
  }
1371
1423
  catch (fallbackErr) {
1372
1424
  if (fallbackErr instanceof MessageWithdrawnError) {
@@ -1412,11 +1464,20 @@ function setupWorkerHandlers(ds, worker) {
1412
1464
  },
1413
1465
  },
1414
1466
  });
1467
+ emitSessionStateTransitionHook(ds, prevStatus, ds.lastScreenStatus, {
1468
+ source: 'screen_update',
1469
+ content: msg.content,
1470
+ });
1415
1471
  }
1416
1472
  // Bot opted out of the streaming card — dashboard SSE above already got
1417
1473
  // the status patch; just don't touch any Lark card.
1418
1474
  if (streamingCardDisabled(ds))
1419
1475
  break;
1476
+ // Restart recovery: a restored worker may emit screen updates as the CLI
1477
+ // redraws on resume. Stay silent (no post/patch) until the first real
1478
+ // user turn clears the flag. Dashboard SSE above still reflects status.
1479
+ if (ds.suppressRecoveryCard)
1480
+ break;
1420
1481
  const readUrl = buildTerminalUrl(ds);
1421
1482
  const turnTitle = ds.currentTurnTitle || ds.session.title || getCliDisplayName(effectiveCliId);
1422
1483
  const mode = ds.displayMode ?? 'hidden';
@@ -1437,7 +1498,7 @@ function setupWorkerHandlers(ds, worker) {
1437
1498
  // not POSTed as duplicate cards.
1438
1499
  ds.streamCardPending = false;
1439
1500
  ds.streamCardId = CARD_POSTING_SENTINEL;
1440
- cb.sessionReply(sessionAnchorId(ds), cardJson, 'interactive', ds.larkAppId)
1501
+ scopedReply(cardJson, 'interactive', msg.turnId)
1441
1502
  .then(msgId => {
1442
1503
  ds.streamCardId = msgId;
1443
1504
  persistStreamCardState(ds);
@@ -1477,8 +1538,14 @@ function setupWorkerHandlers(ds, worker) {
1477
1538
  if (ds.streamCardPending)
1478
1539
  break;
1479
1540
  ds.currentImageKey = msg.imageKey;
1541
+ const prevStatus = ds.lastScreenStatus;
1480
1542
  updateUsageLimitState(ds, msg.usageLimit);
1481
1543
  ds.lastScreenStatus = (msg.usageLimit ?? ds.usageLimit) ? 'limited' : msg.status;
1544
+ emitSessionStateTransitionHook(ds, prevStatus, ds.lastScreenStatus, {
1545
+ source: 'screenshot_uploaded',
1546
+ imageKey: msg.imageKey,
1547
+ content: ds.lastScreenContent ?? '',
1548
+ });
1482
1549
  persistStreamCardState(ds);
1483
1550
  if ((ds.displayMode ?? 'hidden') !== 'screenshot')
1484
1551
  break;
@@ -1501,6 +1568,18 @@ function setupWorkerHandlers(ds, worker) {
1501
1568
  ds.tuiPromptOptions = msg.options;
1502
1569
  ds.tuiPromptMultiSelect = msg.multiSelect;
1503
1570
  ds.tuiToggledIndices = [];
1571
+ emitSessionLifecycleHook(ds, 'session.requires_attention', {
1572
+ reason: 'tui_prompt',
1573
+ description: msg.description,
1574
+ optionsCount: msg.options.length,
1575
+ optionsPreview: msg.options.slice(0, 5).map(option => ({
1576
+ text: option.text,
1577
+ label: option.label,
1578
+ type: option.type,
1579
+ selected: option.selected,
1580
+ })),
1581
+ multiSelect: msg.multiSelect,
1582
+ });
1504
1583
  const prevTuiTurnTitle = ds.currentTurnTitle;
1505
1584
  ds.currentTurnTitle = msg.description; // store for card PATCH on toggle
1506
1585
  if (prevTuiTurnTitle !== ds.currentTurnTitle) {
@@ -1514,7 +1593,7 @@ function setupWorkerHandlers(ds, worker) {
1514
1593
  }
1515
1594
  try {
1516
1595
  const cardJson = buildTuiPromptCard(sessionAnchorId(ds), ds.session.sessionId, msg.description, msg.options, msg.multiSelect, undefined, loc);
1517
- const cardMsgId = await cb.sessionReply(sessionAnchorId(ds), cardJson, 'interactive', ds.larkAppId);
1596
+ const cardMsgId = await scopedReply(cardJson, 'interactive', msg.turnId);
1518
1597
  ds.tuiPromptCardId = cardMsgId;
1519
1598
  publishAttentionPatch(ds);
1520
1599
  }
@@ -1556,7 +1635,7 @@ function setupWorkerHandlers(ds, worker) {
1556
1635
  // leave status='active' and still get the notice.
1557
1636
  if (ds.session.status !== 'closed') {
1558
1637
  try {
1559
- await cb.sessionReply(sessionAnchorId(ds), tr('worker.adopted_session_exited', undefined, loc), 'text', ds.larkAppId);
1638
+ await scopedReply(tr('worker.adopted_session_exited', undefined, loc), 'text', undefined);
1560
1639
  }
1561
1640
  catch { /* best effort */ }
1562
1641
  }
@@ -1584,7 +1663,7 @@ function setupWorkerHandlers(ds, worker) {
1584
1663
  killWorker(ds);
1585
1664
  const cliName = getCliDisplayName(effectiveCliId);
1586
1665
  try {
1587
- await cb.sessionReply(sessionAnchorId(ds), tr('worker.crash_loop_stopped', { cliName, count: rc.count }, loc), 'text', ds.larkAppId);
1666
+ await scopedReply(tr('worker.crash_loop_stopped', { cliName, count: rc.count }, loc), 'text', undefined);
1588
1667
  }
1589
1668
  catch (replyErr) {
1590
1669
  if (replyErr instanceof MessageWithdrawnError) {
@@ -1607,8 +1686,12 @@ function setupWorkerHandlers(ds, worker) {
1607
1686
  }
1608
1687
  case 'user_notify': {
1609
1688
  logger.warn(`[${t}] Worker user_notify: ${msg.message}`);
1689
+ emitSessionLifecycleHook(ds, 'session.requires_attention', {
1690
+ reason: 'user_notify',
1691
+ message: msg.message,
1692
+ });
1610
1693
  try {
1611
- await cb.sessionReply(sessionAnchorId(ds), msg.message, 'text', ds.larkAppId);
1694
+ await scopedReply(msg.message, 'text', msg.turnId);
1612
1695
  }
1613
1696
  catch (err) {
1614
1697
  logger.error(`[${t}] Failed to deliver user_notify to Lark: ${err.message}`);
@@ -1654,7 +1737,7 @@ function setupWorkerHandlers(ds, worker) {
1654
1737
  recipientOpenId,
1655
1738
  brand: resolveBrandLabel(ds.larkAppId),
1656
1739
  });
1657
- cb.sessionReply(sessionAnchorId(ds), cardJson, 'interactive', ds.larkAppId).catch((err) => {
1740
+ scopedReply(cardJson, 'interactive', msg.turnId).catch((err) => {
1658
1741
  logger.warn(`[${t}] Failed to deliver adopt_preamble to Lark: ${err.message}`);
1659
1742
  });
1660
1743
  break;
@@ -1681,6 +1764,10 @@ function setupWorkerHandlers(ds, worker) {
1681
1764
  reason: code === 0 ? 'graceful' : `exit_code_${code}`,
1682
1765
  },
1683
1766
  });
1767
+ emitSessionLifecycleHook(ds, 'session.exit', {
1768
+ reason: code === 0 ? 'graceful' : `exit_code_${code}`,
1769
+ code,
1770
+ });
1684
1771
  }
1685
1772
  });
1686
1773
  }
@@ -1694,6 +1781,7 @@ const FINAL_OUTPUT_RETRY_BACKOFF_MS = [0, 5000, 15000]; // immediate, +5s, +15s
1694
1781
  function deliverFinalOutput(ds, msg, t, attempt, lockedPendingCardId, lockedQuoteTargetId) {
1695
1782
  const cb = requireCallbacks();
1696
1783
  const effectiveCliId = ds.session.cliId ?? getBot(ds.larkAppId).config.cliId;
1784
+ const scopedReply = (content, msgType, turnId) => cb.sessionReply(sessionAnchorId(ds), content, msgType, ds.larkAppId, turnId);
1697
1785
  setTimeout(async () => {
1698
1786
  let pendingCardId;
1699
1787
  let pendingQuoteTargetId;
@@ -1734,7 +1822,7 @@ function deliverFinalOutput(ds, msg, t, attempt, lockedPendingCardId, lockedQuot
1734
1822
  if (pendingCardId) {
1735
1823
  try {
1736
1824
  if (ds.session.pendingResponseCardId !== pendingCardId) {
1737
- await cb.sessionReply(sessionAnchorId(ds), cardJson, 'interactive', ds.larkAppId);
1825
+ await scopedReply(cardJson, 'interactive', msg.turnId);
1738
1826
  }
1739
1827
  else {
1740
1828
  writePendingResponsePatchMarker(ds.session.sessionId, pendingCardId);
@@ -1755,14 +1843,14 @@ function deliverFinalOutput(ds, msg, t, attempt, lockedPendingCardId, lockedQuot
1755
1843
  if (!(err instanceof MessageWithdrawnError))
1756
1844
  throw err;
1757
1845
  logger.warn(`[${t}] Pending response card withdrawn while forwarding final_output; sending a new reply`);
1758
- await cb.sessionReply(sessionAnchorId(ds), cardJson, 'interactive', ds.larkAppId);
1846
+ await scopedReply(cardJson, 'interactive', msg.turnId);
1759
1847
  markPendingResponseCardPatchedIfCurrent(ds.session, pendingCardId);
1760
1848
  syncPendingResponseState(ds, ds.session);
1761
1849
  sessionStore.updateSession(ds.session);
1762
1850
  }
1763
1851
  }
1764
1852
  else {
1765
- await cb.sessionReply(sessionAnchorId(ds), cardJson, 'interactive', ds.larkAppId);
1853
+ await scopedReply(cardJson, 'interactive', msg.turnId);
1766
1854
  }
1767
1855
  ds.lastBridgeEmittedUuid = msg.lastUuid;
1768
1856
  logger.info(`[${t}] Bridge final_output forwarded (turn ${msg.turnId.substring(0, 8)}, ${msg.content.length} chars, kind=${msg.kind ?? 'bridge'}, attempt ${attempt + 1})`);
@@ -1977,6 +2065,11 @@ export function forkAdoptWorker(ds, opts) {
1977
2065
  type: 'session.spawned',
1978
2066
  body: { session: composeRowFromActive(ds) },
1979
2067
  });
2068
+ emitSessionLifecycleHook(ds, 'session.start', {
2069
+ reason: opts?.restoredFromMetadata ? 'adopt_restore' : 'adopt',
2070
+ pid: worker.pid ?? null,
2071
+ adoptedFrom: adopted.tmuxTarget,
2072
+ });
1980
2073
  }
1981
2074
  // ─── Kill stale PIDs ────────────────────────────────────────────────────────
1982
2075
  export function killStalePids(activeSessions_) {