lark-remote 0.1.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 (201) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/LICENSE +21 -0
  3. package/README.en.md +162 -0
  4. package/README.md +161 -0
  5. package/dist/binder.d.ts +57 -0
  6. package/dist/binder.js +105 -0
  7. package/dist/bridge/index.d.ts +338 -0
  8. package/dist/bridge/index.js +1281 -0
  9. package/dist/bridge/queue-manager.d.ts +277 -0
  10. package/dist/bridge/queue-manager.js +729 -0
  11. package/dist/card/bash-card-session.d.ts +78 -0
  12. package/dist/card/bash-card-session.js +174 -0
  13. package/dist/card/bash-renderer.d.ts +24 -0
  14. package/dist/card/bash-renderer.js +187 -0
  15. package/dist/card/card-budget.d.ts +31 -0
  16. package/dist/card/card-budget.js +280 -0
  17. package/dist/card/card-session.d.ts +83 -0
  18. package/dist/card/card-session.js +185 -0
  19. package/dist/card/card-shared.d.ts +28 -0
  20. package/dist/card/card-shared.js +99 -0
  21. package/dist/card/collapsible.d.ts +26 -0
  22. package/dist/card/collapsible.js +87 -0
  23. package/dist/card/run-card-session.d.ts +78 -0
  24. package/dist/card/run-card-session.js +165 -0
  25. package/dist/card/run-renderer.d.ts +66 -0
  26. package/dist/card/run-renderer.js +841 -0
  27. package/dist/card/run-state.d.ts +103 -0
  28. package/dist/card/run-state.js +313 -0
  29. package/dist/card/text-truncate.d.ts +56 -0
  30. package/dist/card/text-truncate.js +184 -0
  31. package/dist/card/time.d.ts +1 -0
  32. package/dist/card/time.js +14 -0
  33. package/dist/card/tool-render.d.ts +25 -0
  34. package/dist/card/tool-render.js +176 -0
  35. package/dist/cli.d.ts +28 -0
  36. package/dist/cli.js +89 -0
  37. package/dist/common/guards.d.ts +37 -0
  38. package/dist/common/guards.js +65 -0
  39. package/dist/config/codex-config.d.ts +113 -0
  40. package/dist/config/codex-config.js +428 -0
  41. package/dist/config/dir.d.ts +17 -0
  42. package/dist/config/dir.js +81 -0
  43. package/dist/config/index.d.ts +219 -0
  44. package/dist/config/index.js +388 -0
  45. package/dist/config/kimi-config.d.ts +33 -0
  46. package/dist/config/kimi-config.js +111 -0
  47. package/dist/config/opencode-config.d.ts +20 -0
  48. package/dist/config/opencode-config.js +124 -0
  49. package/dist/config/pi-config.d.ts +49 -0
  50. package/dist/config/pi-config.js +151 -0
  51. package/dist/config/wizard.d.ts +12 -0
  52. package/dist/config/wizard.js +84 -0
  53. package/dist/connector/file-limits.d.ts +7 -0
  54. package/dist/connector/file-limits.js +8 -0
  55. package/dist/connector/index.d.ts +86 -0
  56. package/dist/connector/index.js +340 -0
  57. package/dist/error-classification.d.ts +15 -0
  58. package/dist/error-classification.js +24 -0
  59. package/dist/index.d.ts +1 -0
  60. package/dist/index.js +580 -0
  61. package/dist/instance-lock.d.ts +30 -0
  62. package/dist/instance-lock.js +184 -0
  63. package/dist/logger/index.d.ts +57 -0
  64. package/dist/logger/index.js +178 -0
  65. package/dist/order/index.d.ts +27 -0
  66. package/dist/order/index.js +90 -0
  67. package/dist/persistence/atomic-write.d.ts +10 -0
  68. package/dist/persistence/atomic-write.js +65 -0
  69. package/dist/persistence/load-json-file.d.ts +9 -0
  70. package/dist/persistence/load-json-file.js +23 -0
  71. package/dist/restart.d.ts +24 -0
  72. package/dist/restart.js +73 -0
  73. package/dist/router/card-helpers.d.ts +28 -0
  74. package/dist/router/card-helpers.js +65 -0
  75. package/dist/router/config/claude.d.ts +14 -0
  76. package/dist/router/config/claude.js +72 -0
  77. package/dist/router/config/codex.d.ts +22 -0
  78. package/dist/router/config/codex.js +100 -0
  79. package/dist/router/config/common/render.d.ts +16 -0
  80. package/dist/router/config/common/render.js +158 -0
  81. package/dist/router/config/index.d.ts +18 -0
  82. package/dist/router/config/index.js +38 -0
  83. package/dist/router/config/kimi.d.ts +21 -0
  84. package/dist/router/config/kimi.js +63 -0
  85. package/dist/router/config/opencode.d.ts +12 -0
  86. package/dist/router/config/opencode.js +44 -0
  87. package/dist/router/config/pi.d.ts +12 -0
  88. package/dist/router/config/pi.js +50 -0
  89. package/dist/router/config/types.d.ts +43 -0
  90. package/dist/router/config/types.js +8 -0
  91. package/dist/router/index.d.ts +318 -0
  92. package/dist/router/index.js +2715 -0
  93. package/dist/router/order-exec-dispatch.d.ts +30 -0
  94. package/dist/router/order-exec-dispatch.js +48 -0
  95. package/dist/router/utils.d.ts +44 -0
  96. package/dist/router/utils.js +116 -0
  97. package/dist/runner/bash/index.d.ts +4 -0
  98. package/dist/runner/bash/index.js +5 -0
  99. package/dist/runner/bash/runner.d.ts +55 -0
  100. package/dist/runner/bash/runner.js +213 -0
  101. package/dist/runner/claude/index.d.ts +4 -0
  102. package/dist/runner/claude/index.js +5 -0
  103. package/dist/runner/claude/runner.d.ts +29 -0
  104. package/dist/runner/claude/runner.js +83 -0
  105. package/dist/runner/codex/argv.d.ts +33 -0
  106. package/dist/runner/codex/argv.js +40 -0
  107. package/dist/runner/codex/index.d.ts +1 -0
  108. package/dist/runner/codex/index.js +2 -0
  109. package/dist/runner/codex/jsonl.d.ts +37 -0
  110. package/dist/runner/codex/jsonl.js +221 -0
  111. package/dist/runner/codex/runner.d.ts +65 -0
  112. package/dist/runner/codex/runner.js +124 -0
  113. package/dist/runner/common/exec-translator.d.ts +73 -0
  114. package/dist/runner/common/exec-translator.js +105 -0
  115. package/dist/runner/common/jsonl-stream.d.ts +39 -0
  116. package/dist/runner/common/jsonl-stream.js +203 -0
  117. package/dist/runner/common/process-stopper.d.ts +28 -0
  118. package/dist/runner/common/process-stopper.js +79 -0
  119. package/dist/runner/common/runner-utils.d.ts +21 -0
  120. package/dist/runner/common/runner-utils.js +65 -0
  121. package/dist/runner/common/spawn-heartbeat.d.ts +33 -0
  122. package/dist/runner/common/spawn-heartbeat.js +51 -0
  123. package/dist/runner/common/spawning-runner.d.ts +321 -0
  124. package/dist/runner/common/spawning-runner.js +634 -0
  125. package/dist/runner/common/usage.d.ts +31 -0
  126. package/dist/runner/common/usage.js +29 -0
  127. package/dist/runner/index.d.ts +19 -0
  128. package/dist/runner/index.js +24 -0
  129. package/dist/runner/kimi/index.d.ts +1 -0
  130. package/dist/runner/kimi/index.js +2 -0
  131. package/dist/runner/kimi/jsonl.d.ts +28 -0
  132. package/dist/runner/kimi/jsonl.js +143 -0
  133. package/dist/runner/kimi/runner.d.ts +50 -0
  134. package/dist/runner/kimi/runner.js +105 -0
  135. package/dist/runner/opencode/argv.d.ts +32 -0
  136. package/dist/runner/opencode/argv.js +35 -0
  137. package/dist/runner/opencode/index.d.ts +1 -0
  138. package/dist/runner/opencode/index.js +2 -0
  139. package/dist/runner/opencode/jsonl.d.ts +68 -0
  140. package/dist/runner/opencode/jsonl.js +295 -0
  141. package/dist/runner/opencode/runner.d.ts +63 -0
  142. package/dist/runner/opencode/runner.js +93 -0
  143. package/dist/runner/pi/index.d.ts +1 -0
  144. package/dist/runner/pi/index.js +2 -0
  145. package/dist/runner/pi/jsonl.d.ts +128 -0
  146. package/dist/runner/pi/jsonl.js +249 -0
  147. package/dist/runner/pi/runner.d.ts +37 -0
  148. package/dist/runner/pi/runner.js +76 -0
  149. package/dist/runner/registry.d.ts +54 -0
  150. package/dist/runner/registry.js +75 -0
  151. package/dist/runner/resolve-agent-choices.d.ts +7 -0
  152. package/dist/runner/resolve-agent-choices.js +76 -0
  153. package/dist/runner/sync-agent-choices.d.ts +6 -0
  154. package/dist/runner/sync-agent-choices.js +73 -0
  155. package/dist/runner/types.d.ts +250 -0
  156. package/dist/runner/types.js +8 -0
  157. package/dist/session/claude/index.d.ts +1 -0
  158. package/dist/session/claude/index.js +2 -0
  159. package/dist/session/claude/session-reader.d.ts +34 -0
  160. package/dist/session/claude/session-reader.js +46 -0
  161. package/dist/session/claude/sessions.d.ts +53 -0
  162. package/dist/session/claude/sessions.js +528 -0
  163. package/dist/session/codex/index.d.ts +1 -0
  164. package/dist/session/codex/index.js +2 -0
  165. package/dist/session/codex/rollout-reader.d.ts +88 -0
  166. package/dist/session/codex/rollout-reader.js +473 -0
  167. package/dist/session/codex/sessions.d.ts +21 -0
  168. package/dist/session/codex/sessions.js +40 -0
  169. package/dist/session/common/catch-up.d.ts +12 -0
  170. package/dist/session/common/catch-up.js +31 -0
  171. package/dist/session/common/constants.d.ts +11 -0
  172. package/dist/session/common/constants.js +12 -0
  173. package/dist/session/common/content-blocks.d.ts +37 -0
  174. package/dist/session/common/content-blocks.js +68 -0
  175. package/dist/session/common/jsonl.d.ts +77 -0
  176. package/dist/session/common/jsonl.js +351 -0
  177. package/dist/session/common/usage-accumulator.d.ts +58 -0
  178. package/dist/session/common/usage-accumulator.js +72 -0
  179. package/dist/session/index.d.ts +7 -0
  180. package/dist/session/index.js +11 -0
  181. package/dist/session/kimi/index.d.ts +1 -0
  182. package/dist/session/kimi/index.js +2 -0
  183. package/dist/session/kimi/sessions.d.ts +81 -0
  184. package/dist/session/kimi/sessions.js +527 -0
  185. package/dist/session/opencode/index.d.ts +1 -0
  186. package/dist/session/opencode/index.js +2 -0
  187. package/dist/session/opencode/sessions.d.ts +81 -0
  188. package/dist/session/opencode/sessions.js +388 -0
  189. package/dist/session/pi/index.d.ts +1 -0
  190. package/dist/session/pi/index.js +2 -0
  191. package/dist/session/pi/sessions.d.ts +27 -0
  192. package/dist/session/pi/sessions.js +399 -0
  193. package/dist/session/registry.d.ts +12 -0
  194. package/dist/session/registry.js +20 -0
  195. package/dist/session/session-store.d.ts +86 -0
  196. package/dist/session/session-store.js +450 -0
  197. package/dist/startup-contact.d.ts +18 -0
  198. package/dist/startup-contact.js +51 -0
  199. package/dist/workspace/index.d.ts +19 -0
  200. package/dist/workspace/index.js +53 -0
  201. package/package.json +93 -0
@@ -0,0 +1,338 @@
1
+ import type { Runner, AgentRunner } from '../runner/index.js';
2
+ import type { AgentRegistry } from '../runner/registry.js';
3
+ import type { SessionReaderRegistry, SessionStore } from '../session/index.js';
4
+ import type { AppConfig } from '../config/index.js';
5
+ import { type RunCardChannel } from '../card/run-card-session.js';
6
+ import type { RunTerminal } from '../card/run-state.js';
7
+ import { type QueuedTask, type EnqueueOptions, type AgentBinding } from './queue-manager.js';
8
+ /**
9
+ * Seam (§7): the channel capabilities the bridge needs. `sendWithRetry` is
10
+ * the minimum a Feishu channel must offer for the bridge to push messages
11
+ * through it; `reconnect` lets `/reconnect` be served through the bridge
12
+ * without the router holding a separate connector reference. Declared here
13
+ * so tests can satisfy it structurally without `as unknown as` casts.
14
+ */
15
+ interface BridgeChannel extends RunCardChannel {
16
+ sendWithRetry(chatId: string, input: {
17
+ text: string;
18
+ } | {
19
+ markdown: string;
20
+ } | {
21
+ card: object;
22
+ }, opts?: {
23
+ replyTo?: string;
24
+ }): Promise<string>;
25
+ reconnect(): Promise<void>;
26
+ sendFile(chatId: string, filePath: string): Promise<string>;
27
+ addReaction(messageId: string, emoji: string): Promise<void>;
28
+ }
29
+ /** Caller context for a bridge operation. */
30
+ interface BridgeContext {
31
+ userId: string;
32
+ chatId: string;
33
+ messageId: string;
34
+ }
35
+ /** A sendable result payload (mirror of the router's CommandResult shape). */
36
+ interface BridgeResult {
37
+ text?: string;
38
+ markdown?: string;
39
+ card?: object;
40
+ }
41
+ export interface ActiveRunSnapshot {
42
+ runId: string;
43
+ userId: string;
44
+ chatId: string;
45
+ cwd: string;
46
+ sessionId?: string;
47
+ terminal: RunTerminal;
48
+ contextLength?: number;
49
+ compactCount?: number;
50
+ cacheReadTokens?: number;
51
+ cacheCreationTokens?: number;
52
+ }
53
+ interface BridgeDeps {
54
+ runner: Runner;
55
+ connector: BridgeChannel;
56
+ sessionStore: SessionStore;
57
+ config: AppConfig;
58
+ /** Workspace store for fallback when sessionStore has no cwd */
59
+ workspaceStore?: {
60
+ get(name: string): string | undefined;
61
+ list(): [string, string][];
62
+ };
63
+ /** Override the idle watchdog timeout (default 15 min). Tests use a small value. */
64
+ idleTimeoutMs?: number;
65
+ /**
66
+ * Multi-agent registry. `getRunner(workspace)` looks up
67
+ * `config.defaultAgent` here.
68
+ */
69
+ agentRegistry: AgentRegistry;
70
+ /**
71
+ * Session reader registry. Used by `resolveFinalUsage` and
72
+ * `sendCompletionNotificationCard` to read session content via
73
+ * `registry.get(config.defaultAgent)`.
74
+ */
75
+ sessionReaderRegistry: SessionReaderRegistry;
76
+ }
77
+ /**
78
+ * Bridge owns the per-workspace serial processing queue (§9.6) and the
79
+ * single-card streaming forwarding loop (§9.12 watchdog + session sync).
80
+ *
81
+ * The router delegates non-command messages here via `forwardToClaude` and
82
+ * sends command results via `sendResult`. Serial processing is enforced per
83
+ * workspace by `enqueue`: each workspace has its own Promise chain, so at
84
+ * most one agent process runs per workspace at a time, while different
85
+ * workspaces run in parallel (see `activeRuns`, §9.6). This is a load-bearing
86
+ * invariant — concurrent spawns within one workspace would corrupt session
87
+ * state. Most card actions go through `enqueueImmediate` (fire-and-forget,
88
+ * outside the serial chain); only run-forwarding is serialized.
89
+ *
90
+ * The idle watchdog (§9.12) is also load-bearing: without it a hung agent
91
+ * process would block its workspace's serial queue forever. Both invariants
92
+ * now have a single owner (this class) and a test surface via the
93
+ * Runner/BridgeChannel seams.
94
+ */
95
+ export declare class Bridge {
96
+ private runner;
97
+ private connector;
98
+ private sessionStore;
99
+ private config;
100
+ private workspaceStore?;
101
+ private idleTimeoutMs;
102
+ /** Multi-agent registry. */
103
+ private agentRegistry;
104
+ /** Session reader registry for usage and completion cards. */
105
+ private sessionReaderRegistry;
106
+ /**
107
+ * Per-workspace runner instances, keyed by (cwd, agentKind).
108
+ * Fix 4 (2026-07-18): Each agentKind has its own cache slot, so switching
109
+ * defaultAgent creates a NEW runner without evicting the old one. This
110
+ * eliminates the need for clearRunners() on agent switch, preventing the
111
+ * regression where clearRunners() orphaned a running subprocess and
112
+ * blocked the queue forever.
113
+ */
114
+ private runners;
115
+ /** Queue manager for per-workspace serial processing queue. */
116
+ private queueManager;
117
+ /** Active runs per workspace (cwd). Multiple workspaces can run in parallel. */
118
+ private activeRuns;
119
+ /**
120
+ * Active `!` bash runs, keyed by runId (NOT cwd). Bash runs bypass the serial
121
+ * queue and may run in parallel with claude runs / other bash runs in the same
122
+ * workspace, so they live outside `activeRuns`. Tracked so `/stop` can reach
123
+ * the per-run BashRunner instance via interruptCurrentRun.
124
+ */
125
+ private activeBashRuns;
126
+ constructor(deps: BridgeDeps);
127
+ /**
128
+ * Get or create a runner for the given workspace, keyed by current defaultAgent.
129
+ *
130
+ * Fix 4 (2026-07-18): Cache key includes agentKind, so switching defaultAgent
131
+ * creates a NEW runner under a different key without evicting the old one.
132
+ * This eliminates the need for clearRunners() on agent switch.
133
+ */
134
+ private getRunner;
135
+ /** Update the config reference (call after `/config set` reloads). */
136
+ setConfig(config: AppConfig): void;
137
+ /** Get the current runner for a workspace. Used by router for agent-specific commands (P3.2). */
138
+ getCurrentRunner(workspace: string): AgentRunner;
139
+ /** 入队时刻快照:当前 defaultAgent + 该 agent 的 sessionId(无 session 则 undefined)。
140
+ * 唯一捕获点:排队消息在 T0 把 agent+session 钉进 AgentBinding,随任务闭包带到 T1
141
+ * 执行时刻,避免 /new、/config 在排队期间改写 live 状态导致语义漂移(方案 D4)。 */
142
+ currentBinding(userId: string): AgentBinding;
143
+ /**
144
+ * Clear all cached runner instances. Call after config changes that affect runner config.
145
+ */
146
+ clearRunners(): void;
147
+ /**
148
+ * Evict a (cwd, agentKind) runner cache slot. Unregisters the runner from the
149
+ * process-level exit dispatcher first (P1-1: without removal the singleton
150
+ * Set<Runner> retains every historical runner instance, so memory still grows
151
+ * with run count), then deletes the slot. Every runner-discarding path
152
+ * (clearRunners / finalizeRun / interruptCurrentRun) must go through this.
153
+ */
154
+ private evictRunnerSlot;
155
+ /**
156
+ * Update the idle watchdog window at runtime.
157
+ * Called by router constructor and `config.save` (when `idle.watchdogMinutes` changes
158
+ * via `/config` card). The idle interval reads `this.idleTimeoutMs` live on every
159
+ * tick, so the new threshold takes effect immediately for any in-flight run —
160
+ * there is no per-event timer to reset.
161
+ */
162
+ setIdleTimeout(ms: number): void;
163
+ /**
164
+ * Extract agent-specific run options from config.
165
+ * Returns model/effort/etc. based on current defaultAgent.
166
+ */
167
+ private getAgentRunOptions;
168
+ /**
169
+ * Enqueue a task into the workspace-level serial bridge queue.
170
+ * Delegates to QueueManager for actual implementation.
171
+ */
172
+ enqueue(workspace: string, task: () => Promise<void>, opts?: EnqueueOptions): void;
173
+ /**
174
+ * Execute a task immediately without going through the queue.
175
+ * Used for / commands that should respond immediately.
176
+ */
177
+ enqueueImmediate(workspace: string, task: () => Promise<void>): void;
178
+ /** Get queue info for a workspace. */
179
+ getQueueInfo(workspace: string): {
180
+ position: number;
181
+ tasksAhead: number;
182
+ isRunning: boolean;
183
+ };
184
+ /** Remove a task from the queue by messageId. Returns true if found and removed. */
185
+ removeFromQueue(workspace: string, messageId: string): boolean;
186
+ /**
187
+ * One-shot: replace the execution closure of an existing queued task in
188
+ * place, preserving its queue position. Used by queue.immediate after the
189
+ * user edits a queued message (see router handleQueueImmediate).
190
+ */
191
+ setTaskReplacement(workspace: string, messageId: string, task: () => Promise<void>): void;
192
+ /** Update queue card to "cancelled" status when user clicks 撤销. */
193
+ updateQueueCardToCancelled(workspace: string, messageId: string): Promise<void>;
194
+ /** Mark a queued task's card as executing immediately (grey out buttons).
195
+ * Called by handleQueueImmediate so the user sees feedback right away
196
+ * instead of waiting for the queue callback. Idempotent: the queue
197
+ * callback's own updateQueueCardToExecuting call becomes a no-op because
198
+ * updateQueueCardToExecuting deletes the card-message mapping in finally. */
199
+ markQueueCardExecuting(workspace: string, messageId: string): Promise<void>;
200
+ /** Get task metadata from queue. */
201
+ getQueuedTask(workspace: string, messageId: string): QueuedTask | undefined;
202
+ /**
203
+ * Whether a task with the given messageId has begun executing and has not
204
+ * settled yet. Lets handleQueueImmediate's final feedback distinguish a
205
+ * target that was cancelled from one that began while the interrupt was in
206
+ * flight (the latter is already running, so the toast must not claim
207
+ * "未安排执行").
208
+ */
209
+ hasTaskBegan(messageId: string): boolean;
210
+ /** Get all queued tasks for a workspace. Returns a copy to prevent aliasing bugs. */
211
+ getQueuedTasks(workspace: string): QueuedTask[];
212
+ /**
213
+ * Update the messagePreview for a queued task and build the updated queue
214
+ * card. Returns the card object to send back as the cardAction callback
215
+ * response (Feishu renders it in place), or null if the task is no longer
216
+ * queued. Returning the card via the callback response avoids the
217
+ * PATCH-vs-callback-response race that left the card stuck in edit state.
218
+ */
219
+ updateMessagePreview(workspace: string, messageId: string, newMessage: string): Promise<object | null>;
220
+ /** Whether a claude run is currently in progress in the given workspace. */
221
+ isBusyFor(workspace: string): boolean;
222
+ getActiveRunFor(workspace: string): ActiveRunSnapshot | undefined;
223
+ /** Whether any claude run is currently in progress (any workspace). */
224
+ get isBusy(): boolean;
225
+ /** Get all active runs across all workspaces. */
226
+ getAllActiveRuns(): Map<string, {
227
+ runId: string;
228
+ userId: string;
229
+ chatId: string;
230
+ cwd: string;
231
+ }>;
232
+ /** Get all active runs with their state for /active command (memory-based). */
233
+ getActiveRuns(): Array<{
234
+ runId: string;
235
+ sessionId: string;
236
+ cwd: string;
237
+ userId: string;
238
+ chatId: string;
239
+ terminal: RunTerminal;
240
+ }>;
241
+ /** Get all active bash runs with their state for /active command. */
242
+ getActiveBashRuns(): Array<{
243
+ runId: string;
244
+ cwd: string;
245
+ userId: string;
246
+ chatId: string;
247
+ terminal: RunTerminal;
248
+ command: string;
249
+ }>;
250
+ interruptCurrentRun(input: {
251
+ userId: string;
252
+ chatId: string;
253
+ runId?: string;
254
+ /** Restrict the match to a single workspace (queue.immediate). When
255
+ * omitted, all workspaces are candidates (used by /stop, /t, and card stop button which don't know which workspace to target). */
256
+ workspace?: string;
257
+ }): Promise<boolean>;
258
+ /** Send a result message to the user (§7). Returns true on success, false on failure. */
259
+ sendResult(result: BridgeResult, ctx: BridgeContext): Promise<boolean>;
260
+ /**
261
+ * Update an existing card in place (原地更新) instead of sending a new one.
262
+ *
263
+ * Used by /config cardAction handlers (config.toggle/set/input/save) so the
264
+ * user sees the card refresh on the same message bubble rather than getting
265
+ * a new card per click — same-message-bubble update pattern.
266
+ *
267
+ * Falls back to `sendResult` (which sends a new card as reply) when:
268
+ * - `messageId` is missing (caller didn't pass ctx.messageId)
269
+ * - `connector.updateCard` throws (card was deleted, network error, etc.)
270
+ *
271
+ * Returns true if the in-place update succeeded, false if it fell back.
272
+ */
273
+ updateCardInPlace(card: object, ctx: BridgeContext): Promise<boolean>;
274
+ /** Send a file to the user via Feishu. */
275
+ sendFile(filePath: string, ctx: BridgeContext): Promise<void>;
276
+ /** Reconnect the underlying Feishu channel. */
277
+ reconnect(): Promise<void>;
278
+ /**
279
+ * Resolve the working directory for a user.
280
+ * First checks sessionStore (set by /cd), then falls back to first workspace.
281
+ * Returns undefined if no cwd is available.
282
+ */
283
+ private resolveCwd;
284
+ /**
285
+ * Forward a non-command message to claude.
286
+ *
287
+ * Watchdog (§9.12): if no AgentEvent arrives within IDLE_TIMEOUT_MS, the
288
+ * run is considered hung and `runner.stop()` is called to unblock the
289
+ * work queue. Session is synced from `system.init`; every renderable event
290
+ * updates the same run card, and terminal events finalize that card.
291
+ */
292
+ forwardToClaude(message: string, ctx: BridgeContext, opts?: {
293
+ cwdOverride?: string;
294
+ binding?: AgentBinding;
295
+ }): Promise<void>;
296
+ /**
297
+ * Step 1 of forwardToClaude: Create run session components.
298
+ * Returns runId, cardSession, and activeRun object for tracking.
299
+ */
300
+ private createRunSession;
301
+ /**
302
+ * Step 2 of forwardToClaude: Run the agent and consume its event stream.
303
+ * Handles idle watchdog, event processing, session sync, and state transitions.
304
+ */
305
+ private runAgentStreamToEnd;
306
+ /**
307
+ * Step 3 of forwardToClaude: Finalize the run.
308
+ * Handles fallback card sending, completion notification, and cleanup.
309
+ */
310
+ private finalizeRun;
311
+ /**
312
+ * Read final usage (contextLength + compactCount + cache tokens) from the session jsonl.
313
+ * Called after a run finishes: live stream-json does not emit compact_boundary,
314
+ * so the live contextLength (fallback to result.usage input+output) is
315
+ * unreliable. The jsonl is authoritative for postTokens + compact event count.
316
+ */
317
+ private resolveFinalUsage;
318
+ /**
319
+ * Send a notification card when a run completes.
320
+ * This card contains the session summary and a button to resume the session.
321
+ * It's sent as a new message (not updating the run card) so users can easily
322
+ * find and return to this session without scrolling up.
323
+ */
324
+ private sendCompletionNotificationCard;
325
+ /**
326
+ * Execute a bash command and stream output to a card.
327
+ * `!` commands bypass the serial queue entirely (see body comment + §9.6):
328
+ * bash runs in parallel with same-workspace agent runs, tracked in
329
+ * `activeBashRuns` separately from `activeRuns`.
330
+ */
331
+ executeBash(command: string, ctx: BridgeContext): Promise<void>;
332
+ /**
333
+ * Internal execution of bash command (called directly from executeBash,
334
+ * bypassing the serial queue — see executeBash).
335
+ */
336
+ private executeBashInternal;
337
+ }
338
+ export {};