lark-remote 0.2.2 → 0.4.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 (39) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.en.md +8 -5
  3. package/README.md +10 -6
  4. package/dist/binder.d.ts +9 -16
  5. package/dist/binder.js +14 -40
  6. package/dist/bridge/final-usage.js +2 -2
  7. package/dist/bridge/inbound-media.js +7 -5
  8. package/dist/bridge/index.js +75 -75
  9. package/dist/clone.d.ts +139 -0
  10. package/dist/clone.js +415 -0
  11. package/dist/common/fs.js +1 -1
  12. package/dist/config/codex-config.js +79 -24
  13. package/dist/config/index.js +1 -1
  14. package/dist/config/kimi-config.js +16 -5
  15. package/dist/connector/index.d.ts +25 -0
  16. package/dist/connector/index.js +133 -50
  17. package/dist/error-classification.d.ts +7 -0
  18. package/dist/error-classification.js +37 -1
  19. package/dist/index.js +48 -15
  20. package/dist/platform/command.js +1 -1
  21. package/dist/platform/sleep-blocker.d.ts +17 -0
  22. package/dist/platform/sleep-blocker.js +73 -0
  23. package/dist/platform/terminator-win32.js +1 -1
  24. package/dist/restart.d.ts +20 -3
  25. package/dist/restart.js +42 -23
  26. package/dist/router/config/kimi.js +4 -3
  27. package/dist/router/index.d.ts +10 -0
  28. package/dist/router/index.js +44 -6
  29. package/dist/runner/common/acp/base-acp-runner.js +7 -2
  30. package/dist/runner/common/acp/base-translator.d.ts +19 -0
  31. package/dist/runner/common/acp/base-translator.js +82 -0
  32. package/dist/runner/common/acp/protocol-types.d.ts +16 -2
  33. package/dist/runner/common/acp/protocol-types.js +3 -0
  34. package/dist/runner/kimi/acp/translator.js +60 -4
  35. package/dist/session/session-store.d.ts +1 -1
  36. package/dist/session/session-store.js +1 -1
  37. package/dist/workspace/index.d.ts +1 -1
  38. package/dist/workspace/index.js +1 -1
  39. package/package.json +2 -2
@@ -209,7 +209,7 @@ export class Bridge {
209
209
  if (!settings)
210
210
  continue;
211
211
  void runner.updateApprovalMode(settings).catch((err) => {
212
- getLogger().warn(`[bridge] sync approval mode failed cwd=${cwd}: ${err.message}`);
212
+ getLogger().warn(`[lark-remote] sync approval mode failed cwd=${cwd}: ${err.message}`);
213
213
  });
214
214
  }
215
215
  }
@@ -521,7 +521,7 @@ export class Bridge {
521
521
  if (active.userId === input.userId && active.chatId === input.chatId) {
522
522
  if (input.runId && active.runId !== input.runId)
523
523
  continue;
524
- getLogger().info(`[bridge] interrupt hit runId=${active.runId} cwd=${cwd} userId=${input.userId}`);
524
+ getLogger().info(`[lark-remote] interrupt hit runId=${active.runId} cwd=${cwd} userId=${input.userId}`);
525
525
  // Stop the EXACT runner instance that is running (carried by activeRun),
526
526
  // not whatever getRunner(cwd) would return now. clearRunners() may have
527
527
  // emptied the cache mid-run, in which case getRunner creates a fresh empty
@@ -564,7 +564,7 @@ export class Bridge {
564
564
  if (stoppedSlot !== undefined) {
565
565
  this.queueManager.resetExecutingCount(cwd, stoppedSlot);
566
566
  }
567
- getLogger().info(`[bridge] interrupt stop done runId=${active.runId}`);
567
+ getLogger().info(`[lark-remote] interrupt stop done runId=${active.runId}`);
568
568
  return true;
569
569
  }
570
570
  }
@@ -576,16 +576,16 @@ export class Bridge {
576
576
  if (b.userId === input.userId && b.chatId === input.chatId) {
577
577
  if (input.runId && runId !== input.runId)
578
578
  continue;
579
- getLogger().info(`[bridge] interrupt hit bash runId=${runId} cwd=${b.cwd} userId=${input.userId}`);
579
+ getLogger().info(`[lark-remote] interrupt hit bash runId=${runId} cwd=${b.cwd} userId=${input.userId}`);
580
580
  await b.bashRunner.stop({ immediate: true });
581
581
  // Update card to show interrupted state
582
582
  await b.cardSession.finish('interrupted', { exitCode: -1 });
583
583
  this.activeBashRuns.delete(runId);
584
- getLogger().info(`[bridge] interrupt bash stop done runId=${runId}`);
584
+ getLogger().info(`[lark-remote] interrupt bash stop done runId=${runId}`);
585
585
  return true;
586
586
  }
587
587
  }
588
- getLogger().debug(`[bridge] interrupt miss userId=${input.userId}`);
588
+ getLogger().debug(`[lark-remote] interrupt miss userId=${input.userId}`);
589
589
  return false;
590
590
  }
591
591
  /** Send a result message to the user (§7). Returns true on success, false on failure. */
@@ -595,26 +595,26 @@ export class Bridge {
595
595
  // 静态卡片体积保护:确保卡片不超过飞书大小限制
596
596
  const { card: safeCard, wasTruncated, reason, bytesBefore, bytesAfter, } = enforceCardBudget(result.card);
597
597
  if (wasTruncated) {
598
- getLogger().info(`[bridge] card size exceeded limit, applied budget enforcement: reason=${reason} bytesBefore=${bytesBefore} bytesAfter=${bytesAfter}`);
598
+ getLogger().info(`[lark-remote] card size exceeded limit, applied budget enforcement: reason=${reason} bytesBefore=${bytesBefore} bytesAfter=${bytesAfter}`);
599
599
  }
600
- getLogger().debug(`[bridge] sendResult kind=card chatId=${ctx.chatId}`);
600
+ getLogger().debug(`[lark-remote] sendResult kind=card chatId=${ctx.chatId}`);
601
601
  await this.connector.sendWithRetry(ctx.chatId, { card: safeCard }, { replyTo: ctx.messageId });
602
602
  return true;
603
603
  }
604
604
  else if (result.markdown) {
605
- getLogger().debug(`[bridge] sendResult kind=markdown chatId=${ctx.chatId}`);
605
+ getLogger().debug(`[lark-remote] sendResult kind=markdown chatId=${ctx.chatId}`);
606
606
  await this.connector.sendWithRetry(ctx.chatId, { markdown: result.markdown }, { replyTo: ctx.messageId });
607
607
  return true;
608
608
  }
609
609
  else if (result.text) {
610
- getLogger().debug(`[bridge] sendResult kind=text chatId=${ctx.chatId}`);
610
+ getLogger().debug(`[lark-remote] sendResult kind=text chatId=${ctx.chatId}`);
611
611
  await this.connector.sendWithRetry(ctx.chatId, { text: result.text }, { replyTo: ctx.messageId });
612
612
  return true;
613
613
  }
614
614
  return false;
615
615
  }
616
616
  catch (err) {
617
- getLogger().error('[bridge] failed to send result:', err);
617
+ getLogger().error('[lark-remote] failed to send result:', err);
618
618
  // 不静默:向用户发送一条纯文本消息,告知具体错误(如飞书 11310 element exceeds
619
619
  // the limit)。如果用户看到空白无反馈,无法判断是命令无效还是卡片发送失败。
620
620
  try {
@@ -622,7 +622,7 @@ export class Bridge {
622
622
  await this.connector.sendWithRetry(ctx.chatId, { text: `⚠️ 卡片发送失败:${errMsg}` }, { replyTo: ctx.messageId });
623
623
  }
624
624
  catch (fallbackErr) {
625
- getLogger().error('[bridge] fallback text send also failed:', fallbackErr);
625
+ getLogger().error('[lark-remote] fallback text send also failed:', fallbackErr);
626
626
  }
627
627
  return false;
628
628
  }
@@ -642,18 +642,18 @@ export class Bridge {
642
642
  */
643
643
  async updateCardInPlace(card, ctx) {
644
644
  if (!ctx.messageId) {
645
- getLogger().warn('[bridge] updateCardInPlace missing messageId, falling back to sendResult');
645
+ getLogger().warn('[lark-remote] updateCardInPlace missing messageId, falling back to sendResult');
646
646
  await this.sendResult({ card }, ctx);
647
647
  return false;
648
648
  }
649
649
  try {
650
- getLogger().debug(`[bridge] updateCardInPlace messageId=${ctx.messageId}`);
650
+ getLogger().debug(`[lark-remote] updateCardInPlace messageId=${ctx.messageId}`);
651
651
  await this.connector.updateCard(ctx.messageId, card);
652
652
  return true;
653
653
  }
654
654
  catch (err) {
655
655
  const errMsg = err.message ?? String(err);
656
- getLogger().warn(`[bridge] updateCardInPlace failed, falling back to sendResult: ${errMsg}`);
656
+ getLogger().warn(`[lark-remote] updateCardInPlace failed, falling back to sendResult: ${errMsg}`);
657
657
  // 先尝试 fallback 发卡片;若卡片本身有问题(如 11310),
658
658
  // sendResult 内部 catch 会发纯文本通知用户。
659
659
  await this.sendResult({ card }, ctx);
@@ -663,11 +663,11 @@ export class Bridge {
663
663
  /** Send a file to the user via Feishu. */
664
664
  async sendFile(filePath, ctx) {
665
665
  try {
666
- getLogger().debug(`[bridge] sendFile path=${filePath} chatId=${ctx.chatId}`);
666
+ getLogger().debug(`[lark-remote] sendFile path=${filePath} chatId=${ctx.chatId}`);
667
667
  await this.connector.sendFile(ctx.chatId, filePath);
668
668
  }
669
669
  catch (err) {
670
- getLogger().error('[bridge] failed to send file:', err);
670
+ getLogger().error('[lark-remote] failed to send file:', err);
671
671
  await this.sendResult({ text: `发送文件失败: ${err.message}` }, ctx);
672
672
  }
673
673
  }
@@ -697,7 +697,7 @@ export class Bridge {
697
697
  // NOTE: fallback uses insertion order, not sort preference — by design
698
698
  // (cwd fallback stays insertion-order for now)
699
699
  cwd = workspaces[0].path;
700
- getLogger().info(`[bridge] resolveCwd fallback cwd=${cwd} (first saved workspace)`);
700
+ getLogger().info(`[lark-remote] resolveCwd fallback cwd=${cwd} (first saved workspace)`);
701
701
  }
702
702
  }
703
703
  return cwd;
@@ -724,11 +724,11 @@ export class Bridge {
724
724
  return;
725
725
  }
726
726
  const entry = this.sessionStore.get(ctx.userId);
727
- getLogger().debug(`[bridge] forward entry userId=${ctx.userId} chatId=${ctx.chatId} cwd=${cwd} ` +
727
+ getLogger().debug(`[lark-remote] forward entry userId=${ctx.userId} chatId=${ctx.chatId} cwd=${cwd} ` +
728
728
  `agent=${agentKind} sessionId=${opts?.binding?.sessionId ?? entry?.sessions?.get(agentKind) ?? '(none)'} message=${message.slice(0, 100)}`);
729
729
  // Check if current workspace already has a run in progress
730
730
  if (this.activeRuns.has(cwd)) {
731
- getLogger().warn(`[bridge] workspace busy, dropping message userId=${ctx.userId} cwd=${cwd}`);
731
+ getLogger().warn(`[lark-remote] workspace busy, dropping message userId=${ctx.userId} cwd=${cwd}`);
732
732
  await this.sendResult({ text: '此 workspace 正在处理中,请 /stop 后重试' }, ctx);
733
733
  return;
734
734
  }
@@ -759,7 +759,7 @@ export class Bridge {
759
759
  */
760
760
  createRunSession(ctx, cwd, runner, agentKind = this.config.defaultAgent) {
761
761
  const runId = randomUUID();
762
- getLogger().debug(`[bridge] creating runCard runId=${runId}`);
762
+ getLogger().debug(`[lark-remote] creating runCard runId=${runId}`);
763
763
  // D5: agentKind 来自入队绑定(forwardToClaude 解析),不再读 live config。
764
764
  // 缓存键 (cwd, agentKind) 和 eviction 都用这个值(review P2-3)。
765
765
  const cardSession = new RunCardSession({
@@ -785,7 +785,7 @@ export class Bridge {
785
785
  agentKind,
786
786
  };
787
787
  this.activeRuns.set(cwd, activeRun);
788
- getLogger().info(`[bridge] activeRuns.set cwd=${cwd} runId=${runId}`);
788
+ getLogger().info(`[lark-remote] activeRuns.set cwd=${cwd} runId=${runId}`);
789
789
  return { runId, cardSession, activeRun };
790
790
  }
791
791
  /**
@@ -860,18 +860,18 @@ export class Bridge {
860
860
  });
861
861
  try {
862
862
  try {
863
- getLogger().debug(`[bridge] cardSession.start() begin runId=${runId}`);
863
+ getLogger().debug(`[lark-remote] cardSession.start() begin runId=${runId}`);
864
864
  await cardSession.start();
865
- getLogger().info(`[bridge] cardSession.start() ok runId=${runId}`);
865
+ getLogger().info(`[lark-remote] cardSession.start() ok runId=${runId}`);
866
866
  }
867
867
  catch (err) {
868
- getLogger().warn('[bridge] card stream unavailable, will use static fallback:', err);
868
+ getLogger().warn('[lark-remote] card stream unavailable, will use static fallback:', err);
869
869
  // Card stream failed - continue with static fallback below, but ensure
870
870
  // we don't silently fail if the fallback also fails (covered in catch below).
871
871
  }
872
872
  if (cardSession.currentState.terminal !== 'running') {
873
873
  // Card session did not enter running state - still try to send static fallback
874
- getLogger().info(`[bridge] cardSession not running, using static fallback`);
874
+ getLogger().info(`[lark-remote] cardSession not running, using static fallback`);
875
875
  }
876
876
  // P2-1: 单 interval 看门狗。事件到来时只刷新 lastEventTs(无 timer 操作);
877
877
  // interval 周期检查 `now - lastEventTs > idleTimeoutMs`,超时才触发 stop。
@@ -891,7 +891,7 @@ export class Bridge {
891
891
  if (idleInterval)
892
892
  clearInterval(idleInterval);
893
893
  idleInterval = null;
894
- getLogger().warn(`[bridge] claude idle timeout, stopping process runId=${runId}`);
894
+ getLogger().warn(`[lark-remote] claude idle timeout, stopping process runId=${runId}`);
895
895
  void Promise.allSettled([
896
896
  cardSession.finish('idle_timeout', {
897
897
  idleTimeoutMinutes: Math.max(1, Math.round(this.idleTimeoutMs / 60_000)),
@@ -912,7 +912,7 @@ export class Bridge {
912
912
  }
913
913
  resetIdle();
914
914
  let contextLength;
915
- getLogger().info(`[bridge] runner.run() begin runId=${runId} message=${message.slice(0, 100)}`);
915
+ getLogger().info(`[lark-remote] runner.run() begin runId=${runId} message=${message.slice(0, 100)}`);
916
916
  // Extract agent-specific options from config
917
917
  const agentOpts = this.getAgentRunOptions(agentKind);
918
918
  const runOpts = { cwd, sessionId, ...agentOpts };
@@ -940,7 +940,7 @@ export class Bridge {
940
940
  // task-notification 注入触发 Claude 重发 init,已终止的 run 被复活)。
941
941
  const pointerMoved = this.sessionStore.getSessionEpoch(ctx.userId, agentKind) !== sessionEpochAtStart;
942
942
  if (pointerMoved) {
943
- getLogger().info(`[bridge] system.init write-back skipped: session pointer moved since run start runId=${runId} sessionId=${event.session_id}`);
943
+ getLogger().info(`[lark-remote] system.init write-back skipped: session pointer moved since run start runId=${runId} sessionId=${event.session_id}`);
944
944
  }
945
945
  else {
946
946
  // L5: Use session's real directory from event.cwd (not runner's cwd parameter)
@@ -952,7 +952,7 @@ export class Bridge {
952
952
  if (hasCwd && event.cwd && event.cwd !== cwd) {
953
953
  // Session has its own cwd (e.g. EnterWorktree relocate). Keep the
954
954
  // workspace cwd unchanged; record the session's actual cwd in sessionCwds.
955
- getLogger().info(`[bridge] system.init: workspace cwd=${cwd}, session cwd=${event.cwd}`);
955
+ getLogger().info(`[lark-remote] system.init: workspace cwd=${cwd}, session cwd=${event.cwd}`);
956
956
  this.sessionStore.setSessionIdAndSessionCwd(ctx.userId, agentKind, event.session_id, realCwd);
957
957
  }
958
958
  else {
@@ -962,7 +962,7 @@ export class Bridge {
962
962
  this.sessionStore.setSessionIdAndCwd(ctx.userId, agentKind, event.session_id, realCwd, bootstrapSessionCwd);
963
963
  }
964
964
  }
965
- getLogger().info(`[bridge] system.init received runId=${runId} sessionId=${event.session_id} cwd=${event.cwd}`);
965
+ getLogger().info(`[lark-remote] system.init received runId=${runId} sessionId=${event.session_id} cwd=${event.cwd}`);
966
966
  }
967
967
  if (event.type === 'turn_started') {
968
968
  // app-server runner 在 turn setup 成功后补发 synthetic system.init
@@ -972,10 +972,10 @@ export class Bridge {
972
972
  const pointerMoved = this.sessionStore.getSessionEpoch(ctx.userId, agentKind) !== sessionEpochAtStart;
973
973
  if (!pointerMoved) {
974
974
  this.sessionStore.setSessionIdAndCwd(ctx.userId, agentKind, event.threadId, cwd);
975
- getLogger().info(`[bridge] turn_started session write-back runId=${runId} sessionId=${event.threadId}`);
975
+ getLogger().info(`[lark-remote] turn_started session write-back runId=${runId} sessionId=${event.threadId}`);
976
976
  }
977
977
  else {
978
- getLogger().info(`[bridge] turn_started write-back skipped: session pointer moved since run start runId=${runId} sessionId=${event.threadId}`);
978
+ getLogger().info(`[lark-remote] turn_started write-back skipped: session pointer moved since run start runId=${runId} sessionId=${event.threadId}`);
979
979
  }
980
980
  }
981
981
  // Track context length from compaction events
@@ -999,7 +999,7 @@ export class Bridge {
999
999
  // 卡片不会把半初始化的 run 当作已收尾。
1000
1000
  const preInitResult = !sawInit;
1001
1001
  if (preInitResult && usageAuthority !== 'live') {
1002
- getLogger().info(`[bridge] pre-init result ignored (resume replay) runId=${runId}`);
1002
+ getLogger().info(`[lark-remote] pre-init result ignored (resume replay) runId=${runId}`);
1003
1003
  // Still reset idle timer — the CLI is alive and producing events.
1004
1004
  resetIdle();
1005
1005
  // Do NOT push to cardSession: the run-state reducer would also
@@ -1012,8 +1012,8 @@ export class Bridge {
1012
1012
  }
1013
1013
  resultNotSuccess = event.subtype !== 'success';
1014
1014
  getLogger().info(preInitResult
1015
- ? `[bridge] pre-init result from live runner (app-server setup failure) runId=${runId}`
1016
- : `[bridge] result event received runId=${runId}`);
1015
+ ? `[lark-remote] pre-init result from live runner (app-server setup failure) runId=${runId}`
1016
+ : `[lark-remote] result event received runId=${runId}`);
1017
1017
  // app-server 模式 setup 失败路径(thread/start 成功后 turn/start 失败)
1018
1018
  // 不会有 turn_started 事件,store 不会写回新线程 id;runner 已在 result
1019
1019
  // 里兜底上报(review P3-10)。此处仅当 runner 声明 live usage(app-server)
@@ -1023,7 +1023,7 @@ export class Bridge {
1023
1023
  event.session_id &&
1024
1024
  this.sessionStore.getSessionEpoch(ctx.userId, agentKind) === sessionEpochAtStart) {
1025
1025
  this.sessionStore.setSessionIdAndCwd(ctx.userId, agentKind, event.session_id, cwd);
1026
- getLogger().info(`[bridge] result session write-back runId=${runId} sessionId=${event.session_id}`);
1026
+ getLogger().info(`[lark-remote] result session write-back runId=${runId} sessionId=${event.session_id}`);
1027
1027
  }
1028
1028
  // result 后进入 finalizing 非终态(暂存 subtype/errorMsg),由 for-await
1029
1029
  // 自然结束后在 finally 转 done/error。提取 usage 信息。
@@ -1065,13 +1065,13 @@ export class Bridge {
1065
1065
  await this.connector.removeReactionByEmoji(ctx.messageId, 'Typing');
1066
1066
  }
1067
1067
  catch (err) {
1068
- getLogger().warn(`[bridge] remove Typing reaction failed runId=${runId}: ${errorMessage(err)}`);
1068
+ getLogger().warn(`[lark-remote] remove Typing reaction failed runId=${runId}: ${errorMessage(err)}`);
1069
1069
  }
1070
1070
  try {
1071
1071
  await this.connector.addReaction(ctx.messageId, 'Typing');
1072
1072
  }
1073
1073
  catch (err) {
1074
- getLogger().warn(`[bridge] re-add Typing reaction failed runId=${runId}: ${errorMessage(err)}`);
1074
+ getLogger().warn(`[lark-remote] re-add Typing reaction failed runId=${runId}: ${errorMessage(err)}`);
1075
1075
  }
1076
1076
  })();
1077
1077
  let coordinator = this.approvalCoordinators.get(runId);
@@ -1095,7 +1095,7 @@ export class Bridge {
1095
1095
  },
1096
1096
  });
1097
1097
  this.approvalCoordinators.set(runId, coordinator);
1098
- getLogger().info(`[bridge] approval coordinator created runId=${runId.slice(0, 8)} requestId=${event.requestId}`);
1098
+ getLogger().info(`[lark-remote] approval coordinator created runId=${runId.slice(0, 8)} requestId=${event.requestId}`);
1099
1099
  }
1100
1100
  coordinator.onRequested(event);
1101
1101
  }
@@ -1116,7 +1116,7 @@ export class Bridge {
1116
1116
  resetIdle();
1117
1117
  await cardSession.push(event);
1118
1118
  }
1119
- getLogger().info(`[bridge] runner stream end runId=${runId} sawResult=${sawResult}`);
1119
+ getLogger().info(`[lark-remote] runner stream end runId=${runId} sawResult=${sawResult}`);
1120
1120
  // §9.12 红线(§P1-2 方案 A 第 2 点):for-await 自然结束 = CLI 已退出,
1121
1121
  // 看门狗使命结束,立即摘除 interval(不再等 finally),堵掉「stream 已结束、
1122
1122
  // 收尾处理跨过死线被误标 idle_timeout」的同源小窗口(P2-4 随本修复一并关闭)。
@@ -1167,7 +1167,7 @@ export class Bridge {
1167
1167
  finalCacheCreationTokens = finalUsage?.cacheCreationTokens ?? finalCacheCreationTokens;
1168
1168
  finalTotalTokens = finalUsage?.totalTokens ?? finalTotalTokens;
1169
1169
  }
1170
- getLogger().info(`[bridge] final usage runId=${runId} contextLength=${finalContextLength} contextLimit=${finalContextLimit ?? 'undefined'} compactCount=${finalCompactCount ?? 'undefined'} cacheRead=${finalCacheReadTokens ?? 'undefined'} cacheCreate=${finalCacheCreationTokens ?? 'undefined'}`);
1170
+ getLogger().info(`[lark-remote] final usage runId=${runId} contextLength=${finalContextLength} contextLimit=${finalContextLimit ?? 'undefined'} compactCount=${finalCompactCount ?? 'undefined'} cacheRead=${finalCacheReadTokens ?? 'undefined'} cacheCreate=${finalCacheCreationTokens ?? 'undefined'}`);
1171
1171
  // for-await 自然结束 = stream 关闭 = CLI 进程退出。
1172
1172
  // 进程退出(for-await end)= 唯一终态触发源。
1173
1173
  // 1) finalizing(result 已收到)-> 转 done/error + usage meta
@@ -1200,14 +1200,14 @@ export class Bridge {
1200
1200
  // else: 已终态且未收到 result(如 spawn 失败后 interrupted)-> 无 usage 可补,跳过
1201
1201
  }
1202
1202
  catch (err) {
1203
- getLogger().error(`[bridge] claude run error runId=${runId}:`, err);
1203
+ getLogger().error(`[lark-remote] claude run error runId=${runId}:`, err);
1204
1204
  // P1-11 双保险:run() 的 finally 已负责杀子进程,但 catch 路径再补一次
1205
1205
  // runner.stop()(与 bash 路径对齐),覆盖任何 finally 之外的残留窗口。
1206
1206
  try {
1207
1207
  await runner.stop();
1208
1208
  }
1209
1209
  catch (stopErr) {
1210
- getLogger().warn(`[bridge] runner stop failed:`, stopErr);
1210
+ getLogger().warn(`[lark-remote] runner stop failed:`, stopErr);
1211
1211
  }
1212
1212
  // 终态守卫:running 或 finalizing(非终态)-> 转 error;
1213
1213
  // 已终态(interrupted/idle_timeout/done/error)-> 保留首终态,仅补充 usage。
@@ -1221,7 +1221,7 @@ export class Bridge {
1221
1221
  });
1222
1222
  }
1223
1223
  else {
1224
- getLogger().info(`[bridge] skip error finish: state already terminal (${catchTerminal}) runId=${runId}`);
1224
+ getLogger().info(`[lark-remote] skip error finish: state already terminal (${catchTerminal}) runId=${runId}`);
1225
1225
  if (sawResult) {
1226
1226
  await cardSession.finish(catchTerminal, usageMeta());
1227
1227
  }
@@ -1244,7 +1244,7 @@ export class Bridge {
1244
1244
  async finalizeRun(cardSession, activeRun, ctx, cwd) {
1245
1245
  const runId = activeRun.runId;
1246
1246
  try {
1247
- getLogger().debug(`[bridge] finally settle runId=${runId} state.terminal=${cardSession.currentState.terminal}`);
1247
+ getLogger().debug(`[lark-remote] finally settle runId=${runId} state.terminal=${cardSession.currentState.terminal}`);
1248
1248
  const settleResult = await cardSession.settle();
1249
1249
  let runCardSent = false;
1250
1250
  if (settleResult === 'unsent') {
@@ -1316,7 +1316,7 @@ export class Bridge {
1316
1316
  });
1317
1317
  }
1318
1318
  }
1319
- getLogger().info(`[bridge] activeRuns.delete cwd=${cwd} runId=${runId}`);
1319
+ getLogger().info(`[lark-remote] activeRuns.delete cwd=${cwd} runId=${runId}`);
1320
1320
  }
1321
1321
  }
1322
1322
  }
@@ -1353,14 +1353,14 @@ export class Bridge {
1353
1353
  // sessions produced >28KB cards that Feishu silently rejected).
1354
1354
  const sent = await this.sendResult({ card }, ctx);
1355
1355
  if (sent) {
1356
- getLogger().debug(`[bridge] completion notification sent sessionId=${sessionId} chatId=${ctx.chatId}`);
1356
+ getLogger().debug(`[lark-remote] completion notification sent sessionId=${sessionId} chatId=${ctx.chatId}`);
1357
1357
  }
1358
1358
  else {
1359
- getLogger().warn(`[bridge] failed to send completion notification card sessionId=${sessionId}`);
1359
+ getLogger().warn(`[lark-remote] failed to send completion notification card sessionId=${sessionId}`);
1360
1360
  }
1361
1361
  }
1362
1362
  catch (err) {
1363
- getLogger().warn(`[bridge] failed to send completion notification card:`, err);
1363
+ getLogger().warn(`[lark-remote] failed to send completion notification card:`, err);
1364
1364
  }
1365
1365
  }
1366
1366
  // =============================================================================
@@ -1375,7 +1375,7 @@ export class Bridge {
1375
1375
  if (!coordinator) {
1376
1376
  // P2-7: run 已结束(coordinator 已释放)时点击审批按钮必须给用户明确反馈,
1377
1377
  // 不能静默。router 会把该异常转成 error toast。
1378
- getLogger().warn(`[bridge] no approval coordinator for runId=${runId.slice(0, 8)}`);
1378
+ getLogger().warn(`[lark-remote] no approval coordinator for runId=${runId.slice(0, 8)}`);
1379
1379
  throw new Error('任务已结束,审批无法响应');
1380
1380
  }
1381
1381
  return fn(coordinator);
@@ -1386,7 +1386,7 @@ export class Bridge {
1386
1386
  */
1387
1387
  async handleApprovalRespond(opts) {
1388
1388
  const log = getLogger();
1389
- log.info(`[bridge] handleApprovalRespond runId=${opts.runId.slice(0, 8)}... requestId=${opts.requestId} decision=${opts.decision}`);
1389
+ log.info(`[lark-remote] handleApprovalRespond runId=${opts.runId.slice(0, 8)}... requestId=${opts.requestId} decision=${opts.decision}`);
1390
1390
  return this.withCoordinator(opts.runId, async (coordinator) => {
1391
1391
  // Build ApprovalAction from the decision string
1392
1392
  const action = decisionToApprovalAction(opts.decision);
@@ -1408,7 +1408,7 @@ export class Bridge {
1408
1408
  */
1409
1409
  async handleApprovalToggle(opts) {
1410
1410
  const log = getLogger();
1411
- log.info(`[bridge] handleApprovalToggle runId=${opts.runId.slice(0, 8)}... requestId=${opts.requestId} permId=${opts.permId}`);
1411
+ log.info(`[lark-remote] handleApprovalToggle runId=${opts.runId.slice(0, 8)}... requestId=${opts.requestId} permId=${opts.permId}`);
1412
1412
  return this.withCoordinator(opts.runId, async (coordinator) => {
1413
1413
  // selected 由卡片根据当前渲染状态传回(取反),不再硬编码只授不撤。
1414
1414
  const toggleAction = {
@@ -1424,7 +1424,7 @@ export class Bridge {
1424
1424
  */
1425
1425
  async handleApprovalAnswer(opts) {
1426
1426
  const log = getLogger();
1427
- log.info(`[bridge] handleApprovalAnswer runId=${opts.runId.slice(0, 8)}... requestId=${opts.requestId} question=${opts.questionIndex}`);
1427
+ log.info(`[lark-remote] handleApprovalAnswer runId=${opts.runId.slice(0, 8)}... requestId=${opts.requestId} question=${opts.questionIndex}`);
1428
1428
  return this.withCoordinator(opts.runId, (coordinator) => coordinator.toggleAnswer({ questionIndex: opts.questionIndex, option: opts.option }, { requestId: opts.requestId, nonce: opts.nonce }));
1429
1429
  }
1430
1430
  /**
@@ -1433,7 +1433,7 @@ export class Bridge {
1433
1433
  */
1434
1434
  async handleApprovalAnswerSubmit(opts) {
1435
1435
  const log = getLogger();
1436
- log.info(`[bridge] handleApprovalAnswerSubmit runId=${opts.runId.slice(0, 8)}... requestId=${opts.requestId} question=${opts.questionIndex}`);
1436
+ log.info(`[lark-remote] handleApprovalAnswerSubmit runId=${opts.runId.slice(0, 8)}... requestId=${opts.requestId} question=${opts.questionIndex}`);
1437
1437
  return this.withCoordinator(opts.runId, (coordinator) => coordinator.submitAnswers({ questionIndex: opts.questionIndex }, { requestId: opts.requestId, nonce: opts.nonce }));
1438
1438
  }
1439
1439
  /**
@@ -1442,7 +1442,7 @@ export class Bridge {
1442
1442
  */
1443
1443
  async handleApprovalAnswerCustom(opts) {
1444
1444
  const log = getLogger();
1445
- log.info(`[bridge] handleApprovalAnswerCustom runId=${opts.runId.slice(0, 8)}... requestId=${opts.requestId} question=${opts.questionIndex}`);
1445
+ log.info(`[lark-remote] handleApprovalAnswerCustom runId=${opts.runId.slice(0, 8)}... requestId=${opts.requestId} question=${opts.questionIndex}`);
1446
1446
  return this.withCoordinator(opts.runId, (coordinator) => coordinator.answerCustom({ questionIndex: opts.questionIndex, text: opts.text }, { requestId: opts.requestId, nonce: opts.nonce }));
1447
1447
  }
1448
1448
  /**
@@ -1452,7 +1452,7 @@ export class Bridge {
1452
1452
  */
1453
1453
  async handleApprovalAnswerNote(opts) {
1454
1454
  const log = getLogger();
1455
- log.info(`[bridge] handleApprovalAnswerNote runId=${opts.runId.slice(0, 8)}... requestId=${opts.requestId} question=${opts.questionIndex}`);
1455
+ log.info(`[lark-remote] handleApprovalAnswerNote runId=${opts.runId.slice(0, 8)}... requestId=${opts.requestId} question=${opts.questionIndex}`);
1456
1456
  return this.withCoordinator(opts.runId, (coordinator) => coordinator.answerNote({ questionIndex: opts.questionIndex, text: opts.text }, { requestId: opts.requestId, nonce: opts.nonce }));
1457
1457
  }
1458
1458
  /**
@@ -1463,7 +1463,7 @@ export class Bridge {
1463
1463
  */
1464
1464
  async handleCodexCompact(value, ctx) {
1465
1465
  const log = getLogger();
1466
- log.info(`[bridge] handleCodexCompact userId=${ctx.userId} runId=${value.runId?.slice(0, 8)}...`);
1466
+ log.info(`[lark-remote] handleCodexCompact userId=${ctx.userId} runId=${value.runId?.slice(0, 8)}...`);
1467
1467
  const { runId } = value;
1468
1468
  if (!runId) {
1469
1469
  await this.sendResult({ text: '⚠️ 无效的 Compact 请求,缺少 runId' }, ctx);
@@ -1494,7 +1494,7 @@ export class Bridge {
1494
1494
  await this.sendResult({ text: '⚠️ 当前运行模式不支持 Compact' }, ctx);
1495
1495
  return;
1496
1496
  }
1497
- log.info(`[bridge] handleCodexCompact executing runCompact for runId=${runId} cwd=${cwd}`);
1497
+ log.info(`[lark-remote] handleCodexCompact executing runCompact for runId=${runId} cwd=${cwd}`);
1498
1498
  await this.streamCodexCompact({
1499
1499
  sessionId: last.sessionId,
1500
1500
  cwd,
@@ -1529,7 +1529,7 @@ export class Bridge {
1529
1529
  }
1530
1530
  }
1531
1531
  catch (err) {
1532
- getLogger().warn(`[bridge] readCompactionState failed sessionId=${sessionId}: ${errorMessage(err)}`);
1532
+ getLogger().warn(`[lark-remote] readCompactionState failed sessionId=${sessionId}: ${errorMessage(err)}`);
1533
1533
  }
1534
1534
  return false;
1535
1535
  }
@@ -1546,7 +1546,7 @@ export class Bridge {
1546
1546
  async streamCodexCompact(opts) {
1547
1547
  const log = getLogger();
1548
1548
  const { sessionId, cwd, agentKind, runner, ctx } = opts;
1549
- log.info(`[bridge] streamCodexCompact sessionId=${sessionId} cwd=${cwd}`);
1549
+ log.info(`[lark-remote] streamCodexCompact sessionId=${sessionId} cwd=${cwd}`);
1550
1550
  // 防御性能力检查:调用方已校验(runId / resume 两条路径),此处双保险并
1551
1551
  // 让 TS 收窄 runner 类型('runCompact' in runner 之后的 cast 才合法)。
1552
1552
  if (!('runCompact' in runner) ||
@@ -1618,10 +1618,10 @@ export class Bridge {
1618
1618
  cumulativeCacheReadTokens: finalUsage?.cumulativeCacheReadTokens,
1619
1619
  cumulativeCacheCreationTokens: finalUsage?.cumulativeCacheCreationTokens,
1620
1620
  });
1621
- log.info(`[bridge] streamCodexCompact finished sessionId=${sessionId} sawResult=${sawResult} subtype=${resultSubtype ?? 'none'}`);
1621
+ log.info(`[lark-remote] streamCodexCompact finished sessionId=${sessionId} sawResult=${sawResult} subtype=${resultSubtype ?? 'none'}`);
1622
1622
  }
1623
1623
  catch (err) {
1624
- log.error(`[bridge] streamCodexCompact failed: ${errorMessage(err)}`);
1624
+ log.error(`[lark-remote] streamCodexCompact failed: ${errorMessage(err)}`);
1625
1625
  await cardSession.finish('error', { errorMsg: errorMessage(err) });
1626
1626
  }
1627
1627
  }
@@ -1636,7 +1636,7 @@ export class Bridge {
1636
1636
  */
1637
1637
  async handleResumeCompact(value, ctx) {
1638
1638
  const log = getLogger();
1639
- log.info(`[bridge] handleResumeCompact userId=${ctx.userId} sessionId=${value.sessionId?.slice(0, 16)} agent=${value.agent ?? 'default'}`);
1639
+ log.info(`[lark-remote] handleResumeCompact userId=${ctx.userId} sessionId=${value.sessionId?.slice(0, 16)} agent=${value.agent ?? 'default'}`);
1640
1640
  const { sessionId } = value;
1641
1641
  if (!sessionId) {
1642
1642
  await this.sendResult({ text: '⚠️ 无效的 Compact 请求,缺少 sessionId' }, ctx);
@@ -1682,7 +1682,7 @@ export class Bridge {
1682
1682
  await this.sendResult({ text: '⚠️ 当前运行模式不支持 Compact' }, ctx);
1683
1683
  return;
1684
1684
  }
1685
- log.info(`[bridge] handleResumeCompact executing runCompact sessionId=${sessionId} cwd=${cwd}`);
1685
+ log.info(`[lark-remote] handleResumeCompact executing runCompact sessionId=${sessionId} cwd=${cwd}`);
1686
1686
  await this.streamCodexCompact({ sessionId, cwd, agentKind, runner, ctx });
1687
1687
  }
1688
1688
  /**
@@ -1693,13 +1693,13 @@ export class Bridge {
1693
1693
  */
1694
1694
  async executeBash(command, ctx) {
1695
1695
  const cwd = this.resolveCwd(ctx.userId);
1696
- getLogger().info(`[bridge] executeBash start userId=${ctx.userId} sessionCwd=${this.sessionStore.get(ctx.userId)?.cwd} command="${command.slice(0, 30)}..."`);
1696
+ getLogger().info(`[lark-remote] executeBash start userId=${ctx.userId} sessionCwd=${this.sessionStore.get(ctx.userId)?.cwd} command="${command.slice(0, 30)}..."`);
1697
1697
  if (!cwd) {
1698
- getLogger().info(`[bridge] executeBash no cwd, sending error`);
1698
+ getLogger().info(`[lark-remote] executeBash no cwd, sending error`);
1699
1699
  await this.sendResult({ text: '请先使用 /cd <path> 设置工作目录,或保存一个 workspace (/ws save <name>)' }, ctx);
1700
1700
  return;
1701
1701
  }
1702
- getLogger().info(`[bridge] executeBash proceeding cwd=${cwd}`);
1702
+ getLogger().info(`[lark-remote] executeBash proceeding cwd=${cwd}`);
1703
1703
  // `!` commands bypass the serial queue entirely (design.md §9.6):
1704
1704
  // index.ts dispatches `!` to router.handle → executeBash directly, NOT via
1705
1705
  // bridge.enqueue. bash runs in parallel with same-workspace claude runs.
@@ -1715,7 +1715,7 @@ export class Bridge {
1715
1715
  * bypassing the serial queue — see executeBash).
1716
1716
  */
1717
1717
  async executeBashInternal(command, ctx, cwd) {
1718
- getLogger().debug(`[bridge] executeBashInternal userId=${ctx.userId} chatId=${ctx.chatId} cwd=${cwd} command="${command.slice(0, 50)}..."`);
1718
+ getLogger().debug(`[lark-remote] executeBashInternal userId=${ctx.userId} chatId=${ctx.chatId} cwd=${cwd} command="${command.slice(0, 50)}..."`);
1719
1719
  // Note: We don't check activeRuns here because bash bypasses the serial
1720
1720
  // queue and runs in parallel with same-workspace agent runs (§9.6). The
1721
1721
  // activeRuns check in forwardToClaude is for a different purpose (detecting
@@ -1752,13 +1752,13 @@ export class Bridge {
1752
1752
  let stderr = '';
1753
1753
  let exitCode = null;
1754
1754
  try {
1755
- getLogger().info(`[bridge] executeBashInternal about to start stream chatId=${ctx.chatId} messageId=${ctx.messageId}`);
1755
+ getLogger().info(`[lark-remote] executeBashInternal about to start stream chatId=${ctx.chatId} messageId=${ctx.messageId}`);
1756
1756
  try {
1757
1757
  await cardSession.start();
1758
- getLogger().info(`[bridge] executeBash stream started runId=${runId}`);
1758
+ getLogger().info(`[lark-remote] executeBash stream started runId=${runId}`);
1759
1759
  }
1760
1760
  catch (err) {
1761
- getLogger().warn('[bridge] bash card stream unavailable:', err);
1761
+ getLogger().warn('[lark-remote] bash card stream unavailable:', err);
1762
1762
  }
1763
1763
  for await (const event of bashRunner.run(command, { cwd })) {
1764
1764
  if (event.type === 'stdout') {
@@ -1780,7 +1780,7 @@ export class Bridge {
1780
1780
  await cardSession.finish(exitCode === 0 ? 'done' : 'error', { exitCode, output, stderr });
1781
1781
  }
1782
1782
  catch (err) {
1783
- getLogger().error(`[bridge] bash run error runId=${runId}:`, err);
1783
+ getLogger().error(`[lark-remote] bash run error runId=${runId}:`, err);
1784
1784
  // If for-await threw mid-stream the bash child may still be running.
1785
1785
  // Stop it before finalizing the card — otherwise the finally block
1786
1786
  // removes the activeBashRuns entry and /stop can no longer reach it,
@@ -1789,7 +1789,7 @@ export class Bridge {
1789
1789
  await bashRunner.stop();
1790
1790
  }
1791
1791
  catch (stopErr) {
1792
- getLogger().warn(`[bridge] bash stop failed:`, stopErr);
1792
+ getLogger().warn(`[lark-remote] bash stop failed:`, stopErr);
1793
1793
  }
1794
1794
  await cardSession.finish('error', {
1795
1795
  exitCode: 1,
@@ -1811,7 +1811,7 @@ export class Bridge {
1811
1811
  }
1812
1812
  if (this.activeBashRuns.has(runId)) {
1813
1813
  this.activeBashRuns.delete(runId);
1814
- getLogger().info(`[bridge] executeBash done runId=${runId} exitCode=${exitCode}`);
1814
+ getLogger().info(`[lark-remote] executeBash done runId=${runId} exitCode=${exitCode}`);
1815
1815
  }
1816
1816
  // Add a Done emoji reaction to the user's original message to signal completion
1817
1817
  void this.connector.addReaction(ctx.messageId, 'Done');