lark-coding-assistant 0.2.0 → 0.2.2

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.
@@ -2112,6 +2112,8 @@ var LarkGateway = class {
2112
2112
  signer;
2113
2113
  formActions = /* @__PURE__ */ new Map();
2114
2114
  formActionsInFlight = /* @__PURE__ */ new Set();
2115
+ processingReactions = /* @__PURE__ */ new Map();
2116
+ processingGenerations = /* @__PURE__ */ new Map();
2115
2117
  async handleDeferredCardAction(event, action) {
2116
2118
  let initialResumePicker;
2117
2119
  try {
@@ -2128,7 +2130,7 @@ var LarkGateway = class {
2128
2130
  this.formActions.delete(event.messageId);
2129
2131
  return;
2130
2132
  }
2131
- await this.channel.send(event.chatId, { text: `\u5361\u7247\u64CD\u4F5C\u672A\u5B8C\u6210\uFF1A${result2.content}` });
2133
+ await this.sendMessage(event.chatId, { text: `\u5361\u7247\u64CD\u4F5C\u672A\u5B8C\u6210\uFF1A${result2.content}` });
2132
2134
  return;
2133
2135
  }
2134
2136
  if (result2.type === "session-created") {
@@ -2158,7 +2160,7 @@ var LarkGateway = class {
2158
2160
  }
2159
2161
  if (result2.type === "session-picker") {
2160
2162
  if (action.kind === "session-start-error") {
2161
- await this.channel.send(event.chatId, { card: sessionPickerCard(
2163
+ await this.sendMessage(event.chatId, { card: sessionPickerCard(
2162
2164
  event.chatId,
2163
2165
  result2.sessions,
2164
2166
  result2.activeSessionId,
@@ -2177,13 +2179,13 @@ var LarkGateway = class {
2177
2179
  return;
2178
2180
  }
2179
2181
  if (result2.type === "session-create-form") {
2180
- const sent = await this.channel.send(event.chatId, { card: sessionCreateCard() });
2182
+ const sent = await this.sendMessage(event.chatId, { card: sessionCreateCard() });
2181
2183
  this.rememberSessionCreateFormAction(sent.messageId, event.chatId);
2182
2184
  const sourceCard = action.kind === "session-create" && result2.sessions ? sessionPickerCard(event.chatId, result2.sessions, result2.activeSessionId, this.signer, void 0, false) : sessionCreateOpenedCard();
2183
2185
  await this.updateCardAfterAction(event.messageId, sourceCard).catch(async (error) => {
2184
2186
  const detail = cardErrorDetail(error);
2185
2187
  console.error(`[lca] failed to retire session-create source card: message=${event.messageId} detail=${detail}`);
2186
- await this.channel.send(event.chatId, {
2188
+ await this.sendMessage(event.chatId, {
2187
2189
  text: "\u65B0\u5EFA\u8868\u5355\u5DF2\u53D1\u9001\uFF0C\u4F46\u539F\u5361\u7247\u72B6\u6001\u66F4\u65B0\u5931\u8D25\uFF1B\u8BF7\u4F7F\u7528\u6700\u65B0\u7684\u201C\u65B0\u5EFA Coding Session\u201D\u5361\u7247\u7EE7\u7EED\u64CD\u4F5C\u3002"
2188
2190
  }).catch(() => void 0);
2189
2191
  });
@@ -2216,7 +2218,7 @@ var LarkGateway = class {
2216
2218
  }
2217
2219
  if (action.kind === "session-create") this.formActions.delete(event.messageId);
2218
2220
  console.error(`[lca] deferred card action failed: kind=${action.kind} action=${action.action} message=${event.messageId} detail=${detail}`);
2219
- await this.channel.send(event.chatId, {
2221
+ await this.sendMessage(event.chatId, {
2220
2222
  text: action.kind === "session-create" ? `\u65B0\u5EFA Session \u8868\u5355\u6253\u5F00\u5931\u8D25\uFF1A${detail}\u3002\u8BF7\u91CD\u65B0\u53D1\u9001 /sessions\uFF0C\u6216\u76F4\u63A5\u4F7F\u7528 /start \u547D\u4EE4\u3002` : `\u5361\u7247\u64CD\u4F5C\u540C\u6B65\u5931\u8D25\uFF1A${detail}`
2221
2223
  }).catch(() => void 0);
2222
2224
  }
@@ -2242,7 +2244,7 @@ var LarkGateway = class {
2242
2244
  } catch (error) {
2243
2245
  const detail = cardErrorDetail(error);
2244
2246
  console.error(`[lca] failed to mark expired card: message=${event.messageId} detail=${detail}`);
2245
- await this.channel.send(event.chatId, {
2247
+ await this.sendMessage(event.chatId, {
2246
2248
  text: "\u5361\u7247\u6216\u6309\u94AE\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u53D1\u9001\u5BF9\u5E94\u547D\u4EE4\u83B7\u53D6\u6700\u65B0\u5361\u7247\uFF1BSession \u76F8\u5173\u64CD\u4F5C\u53EF\u53D1\u9001 /sessions\u3002"
2247
2249
  }).catch(() => void 0);
2248
2250
  }
@@ -2250,17 +2252,37 @@ var LarkGateway = class {
2250
2252
  connect() {
2251
2253
  return this.channel.connect();
2252
2254
  }
2253
- disconnect() {
2254
- return this.channel.disconnect();
2255
+ async disconnect() {
2256
+ const chats = /* @__PURE__ */ new Set([...this.processingGenerations.keys(), ...this.processingReactions.keys()]);
2257
+ await Promise.all([...chats].map((chatId) => this.clearProcessing(chatId)));
2258
+ await this.channel.disconnect();
2259
+ }
2260
+ async startProcessing(message) {
2261
+ await this.clearProcessing(message.chatId);
2262
+ const generation = this.processingGenerations.get(message.chatId) ?? 0;
2263
+ try {
2264
+ const reactionId = await this.channel.addReaction(message.messageId, "Typing");
2265
+ if (this.processingGenerations.get(message.chatId) !== generation) {
2266
+ await this.removeProcessingReaction(message.messageId, reactionId);
2267
+ return;
2268
+ }
2269
+ const timer = setTimeout(() => {
2270
+ void this.clearProcessing(message.chatId, generation);
2271
+ }, 10 * 6e4);
2272
+ timer.unref?.();
2273
+ this.processingReactions.set(message.chatId, { messageId: message.messageId, reactionId, timer, generation });
2274
+ } catch (error) {
2275
+ console.error(`[lca] failed to add processing reaction: chat=${message.chatId} message=${message.messageId} detail=${cardErrorDetail(error)}`);
2276
+ }
2255
2277
  }
2256
2278
  sendText(chatId, text) {
2257
- return this.channel.send(chatId, { text });
2279
+ return this.sendMessage(chatId, { text });
2258
2280
  }
2259
2281
  sendMarkdown(chatId, markdown) {
2260
- return this.channel.send(chatId, { markdown });
2282
+ return this.sendMessage(chatId, { markdown });
2261
2283
  }
2262
2284
  async sendChoice(chatId, paneId, screen, agent) {
2263
- const result2 = await this.channel.send(chatId, { card: choiceCard(chatId, paneId, screen, this.signer, agent) });
2285
+ const result2 = await this.sendMessage(chatId, { card: choiceCard(chatId, paneId, screen, this.signer, agent) });
2264
2286
  this.rememberFormActions(result2.messageId, chatId, paneId, screen, agent);
2265
2287
  return result2;
2266
2288
  }
@@ -2273,7 +2295,7 @@ var LarkGateway = class {
2273
2295
  this.formActions.delete(messageId);
2274
2296
  }
2275
2297
  async sendManual(chatId, view2) {
2276
- const result2 = await this.channel.send(chatId, { card: manualControlCard(chatId, view2, this.signer) });
2298
+ const result2 = await this.sendMessage(chatId, { card: manualControlCard(chatId, view2, this.signer) });
2277
2299
  this.rememberManualFormActions(result2.messageId, chatId, view2);
2278
2300
  return result2;
2279
2301
  }
@@ -2332,27 +2354,51 @@ var LarkGateway = class {
2332
2354
  }
2333
2355
  }
2334
2356
  sendStatus(chatId, status) {
2335
- return this.channel.send(chatId, { card: statusCard(status) });
2357
+ return this.sendMessage(chatId, { card: statusCard(status) });
2336
2358
  }
2337
2359
  sendSessionPicker(chatId, sessions, activeSessionId) {
2338
- return this.channel.send(chatId, { card: sessionPickerCard(chatId, sessions, activeSessionId, this.signer) });
2360
+ return this.sendMessage(chatId, { card: sessionPickerCard(chatId, sessions, activeSessionId, this.signer) });
2339
2361
  }
2340
2362
  sendResumePicker(chatId, session, picker) {
2341
- return this.channel.send(chatId, { card: resumePickerCard(chatId, session, picker, this.signer) });
2363
+ return this.sendMessage(chatId, { card: resumePickerCard(chatId, session, picker, this.signer) });
2342
2364
  }
2343
2365
  sendStartupConflict(chatId, request, owner) {
2344
- return this.channel.send(chatId, { card: startupConflictCard(chatId, requestSession(request), owner, this.signer) });
2366
+ return this.sendMessage(chatId, { card: startupConflictCard(chatId, requestSession(request), owner, this.signer) });
2345
2367
  }
2346
2368
  async sendSessionCreate(chatId) {
2347
- const result2 = await this.channel.send(chatId, { card: sessionCreateCard() });
2369
+ const result2 = await this.sendMessage(chatId, { card: sessionCreateCard() });
2348
2370
  this.rememberSessionCreateFormAction(result2.messageId, chatId);
2349
2371
  return result2;
2350
2372
  }
2351
2373
  sendSessionStartupFailure(chatId, failure) {
2352
- return this.channel.send(chatId, { card: sessionStartupFailureCard(chatId, failure, this.signer) });
2374
+ return this.sendMessage(chatId, { card: sessionStartupFailureCard(chatId, failure, this.signer) });
2353
2375
  }
2354
2376
  sendStopConfirmation(chatId, paneId, fingerprint, agent) {
2355
- return this.channel.send(chatId, { card: stopCard(chatId, paneId, fingerprint, this.signer, agent) });
2377
+ return this.sendMessage(chatId, { card: stopCard(chatId, paneId, fingerprint, this.signer, agent) });
2378
+ }
2379
+ async sendMessage(chatId, input) {
2380
+ await this.clearProcessing(chatId);
2381
+ return this.channel.send(chatId, input);
2382
+ }
2383
+ async clearProcessing(chatId, expectedGeneration) {
2384
+ const currentGeneration = this.processingGenerations.get(chatId) ?? 0;
2385
+ if (expectedGeneration !== void 0 && currentGeneration !== expectedGeneration) return;
2386
+ this.processingGenerations.set(chatId, currentGeneration + 1);
2387
+ const pending = this.processingReactions.get(chatId);
2388
+ if (!pending) return;
2389
+ this.processingReactions.delete(chatId);
2390
+ clearTimeout(pending.timer);
2391
+ await this.removeProcessingReaction(pending.messageId, pending.reactionId);
2392
+ }
2393
+ async removeProcessingReaction(messageId, reactionId) {
2394
+ try {
2395
+ await this.channel.removeReaction(messageId, reactionId);
2396
+ } catch (error) {
2397
+ console.error(`[lca] failed to remove processing reaction by id: message=${messageId} detail=${cardErrorDetail(error)}`);
2398
+ await this.channel.removeReactionByEmoji(messageId, "Typing").catch((fallbackError) => {
2399
+ console.error(`[lca] failed to remove processing reaction by emoji: message=${messageId} detail=${cardErrorDetail(fallbackError)}`);
2400
+ });
2401
+ }
2356
2402
  }
2357
2403
  };
2358
2404
  function requestSession(request) {
@@ -2917,10 +2963,41 @@ var AssistantDaemon = class {
2917
2963
  }
2918
2964
  return { mode: "code", bindCode: createBindCode(), expiresInSeconds: 600 };
2919
2965
  }
2920
- async runtimeStatus(sessionId = this.state.activeSessionId) {
2921
- const session = sessionId ? this.state.sessions?.[sessionId] : void 0;
2922
- const pane = session ? await this.tmux.inspect(session.paneId) : void 0;
2923
- return { state: this.state, session, screen: sessionId === this.state.activeSessionId ? this.screen : void 0, paneAlive: Boolean(pane && !pane.dead) };
2966
+ async runtimeStatus(sessionId) {
2967
+ const selectedSessionId = sessionId ?? this.state.activeSessionId;
2968
+ const selected = selectedSessionId ? this.state.sessions?.[selectedSessionId] : void 0;
2969
+ const requestedSessions = sessionId ? selected ? [selected] : [] : Object.values(this.state.sessions ?? {});
2970
+ const sessions = await Promise.all(requestedSessions.map((session) => this.sessionRuntimeStatus(session)));
2971
+ const selectedRuntime = selected ? sessions.find(({ session }) => session.id === selected.id) ?? await this.sessionRuntimeStatus(selected) : void 0;
2972
+ return {
2973
+ state: this.state,
2974
+ session: selected,
2975
+ screen: selectedRuntime?.screen,
2976
+ paneAlive: selectedRuntime?.paneAlive === true,
2977
+ sessions
2978
+ };
2979
+ }
2980
+ async sessionRuntimeStatus(session) {
2981
+ const active = session.id === this.state.activeSessionId;
2982
+ try {
2983
+ const pane = await this.tmux.inspect(session.paneId);
2984
+ if (!pane || pane.dead) {
2985
+ return {
2986
+ session,
2987
+ screen: getAgentAdapter(session.agent).detectScreen("", false),
2988
+ paneAlive: false,
2989
+ active
2990
+ };
2991
+ }
2992
+ const screen = active && this.screen ? this.screen : getAgentAdapter(session.agent).detectScreen(
2993
+ await this.tmux.capture(session.paneId, 160),
2994
+ true,
2995
+ { x: pane.cursorX, y: pane.cursorY }
2996
+ );
2997
+ return { session, screen, paneAlive: true, active };
2998
+ } catch {
2999
+ return { session, active };
3000
+ }
2924
3001
  }
2925
3002
  async tail(lines) {
2926
3003
  const session = this.activeSession();
@@ -3147,6 +3224,7 @@ ${escapeFence2(output).slice(-6800)}
3147
3224
  await this.gateway?.sendText(message.chatId, `\u5DF2\u5411 ${getAgentAdapter(session.agent).displayName} \u63D0\u4EA4\u8865\u5145\u5185\u5BB9\u3002`);
3148
3225
  return;
3149
3226
  }
3227
+ await this.gateway?.startProcessing(message);
3150
3228
  await this.poll();
3151
3229
  if (this.shouldQueueMessage()) {
3152
3230
  if (this.pendingMessages.length >= 100) {