@jesonliu/lark-claudecode-bridge 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +183 -0
  3. package/config.example.yaml +42 -0
  4. package/deploy/com.lark-claudecode-bridge.plist +9 -0
  5. package/deploy/lark-claudecode-bridge.service +11 -0
  6. package/deploy/windows-start.bat +2 -0
  7. package/dist/access/access-control.d.ts +43 -0
  8. package/dist/access/access-control.js +88 -0
  9. package/dist/access/access-control.js.map +1 -0
  10. package/dist/bin/lcb.d.ts +2 -0
  11. package/dist/bin/lcb.js +191 -0
  12. package/dist/bin/lcb.js.map +1 -0
  13. package/dist/cli/app-manager.d.ts +28 -0
  14. package/dist/cli/app-manager.js +99 -0
  15. package/dist/cli/app-manager.js.map +1 -0
  16. package/dist/cli/asker.d.ts +7 -0
  17. package/dist/cli/asker.js +41 -0
  18. package/dist/cli/asker.js.map +1 -0
  19. package/dist/cli/setup-wizard.d.ts +28 -0
  20. package/dist/cli/setup-wizard.js +114 -0
  21. package/dist/cli/setup-wizard.js.map +1 -0
  22. package/dist/cli/stdin-pairing.d.ts +7 -0
  23. package/dist/cli/stdin-pairing.js +19 -0
  24. package/dist/cli/stdin-pairing.js.map +1 -0
  25. package/dist/cli/ws-manager.d.ts +11 -0
  26. package/dist/cli/ws-manager.js +67 -0
  27. package/dist/cli/ws-manager.js.map +1 -0
  28. package/dist/config.d.ts +7 -0
  29. package/dist/config.js +169 -0
  30. package/dist/config.js.map +1 -0
  31. package/dist/executor/claude-executor.d.ts +28 -0
  32. package/dist/executor/claude-executor.js +84 -0
  33. package/dist/executor/claude-executor.js.map +1 -0
  34. package/dist/executor/notify-server.d.ts +34 -0
  35. package/dist/executor/notify-server.js +193 -0
  36. package/dist/executor/notify-server.js.map +1 -0
  37. package/dist/executor/output-collector.d.ts +5 -0
  38. package/dist/executor/output-collector.js +17 -0
  39. package/dist/executor/output-collector.js.map +1 -0
  40. package/dist/executor/permission-gate.d.ts +20 -0
  41. package/dist/executor/permission-gate.js +66 -0
  42. package/dist/executor/permission-gate.js.map +1 -0
  43. package/dist/gateway/card-builder.d.ts +15 -0
  44. package/dist/gateway/card-builder.js +60 -0
  45. package/dist/gateway/card-builder.js.map +1 -0
  46. package/dist/gateway/feishu-gateway.d.ts +164 -0
  47. package/dist/gateway/feishu-gateway.js +249 -0
  48. package/dist/gateway/feishu-gateway.js.map +1 -0
  49. package/dist/gateway/progress-card.d.ts +34 -0
  50. package/dist/gateway/progress-card.js +106 -0
  51. package/dist/gateway/progress-card.js.map +1 -0
  52. package/dist/index.d.ts +38 -0
  53. package/dist/index.js +433 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/session/channel.d.ts +18 -0
  56. package/dist/session/channel.js +44 -0
  57. package/dist/session/channel.js.map +1 -0
  58. package/dist/session/commands.d.ts +24 -0
  59. package/dist/session/commands.js +87 -0
  60. package/dist/session/commands.js.map +1 -0
  61. package/dist/session/session-store.d.ts +42 -0
  62. package/dist/session/session-store.js +85 -0
  63. package/dist/session/session-store.js.map +1 -0
  64. package/dist/session/triggers.d.ts +12 -0
  65. package/dist/session/triggers.js +34 -0
  66. package/dist/session/triggers.js.map +1 -0
  67. package/dist/transcript/transcript-writer.d.ts +85 -0
  68. package/dist/transcript/transcript-writer.js +64 -0
  69. package/dist/transcript/transcript-writer.js.map +1 -0
  70. package/dist/types.d.ts +105 -0
  71. package/dist/types.js +2 -0
  72. package/dist/types.js.map +1 -0
  73. package/dist/version.d.ts +1 -0
  74. package/dist/version.js +3 -0
  75. package/dist/version.js.map +1 -0
  76. package/package.json +41 -0
@@ -0,0 +1,106 @@
1
+ import { buildProgressCard } from './card-builder.js';
2
+ const FLUSH_CHARS = 200;
3
+ export class ProgressCard {
4
+ sender;
5
+ opts;
6
+ messageId;
7
+ buffer = '';
8
+ state;
9
+ flushTimer;
10
+ heartbeatTimer;
11
+ lastActivityAt = Date.now();
12
+ done = false;
13
+ // C1 修复:flush 单飞串行化——同一时刻最多一个 updateCard in-flight,
14
+ // 期间的新 flush 请求标记 dirty,落地后补刷一次;保证任何时刻后发起的
15
+ // 更新(尤其 finish 终态)永远晚于先前挂起的更新落地。
16
+ flushChain = Promise.resolve();
17
+ dirty = false;
18
+ flushing = false;
19
+ constructor(sender, title, opts = {}) {
20
+ this.sender = sender;
21
+ this.opts = opts;
22
+ this.state = { title, status: '🚀 已接收,启动中…', textTail: '', toolLine: '', startedAt: Date.now() };
23
+ }
24
+ async start() {
25
+ this.messageId = await this.sender.sendCard(buildProgressCard(this.state));
26
+ const interval = this.opts.flushIntervalMs ?? 1500;
27
+ this.flushTimer = setInterval(() => void this.flush(), interval).unref();
28
+ this.heartbeatTimer = setInterval(() => {
29
+ if (Date.now() - this.lastActivityAt >= (this.opts.idleHeartbeatMs ?? 30_000)) {
30
+ this.lastActivityAt = Date.now(); // I1 修复:心跳刷过即重置空闲计时,否则退化为每秒连刷
31
+ void this.flush(); // 心跳:刷新运行时长,证明没卡死
32
+ }
33
+ }, 1000).unref();
34
+ }
35
+ appendText(delta) {
36
+ if (this.done)
37
+ return;
38
+ this.buffer += delta;
39
+ this.lastActivityAt = Date.now();
40
+ if (this.buffer.length >= FLUSH_CHARS)
41
+ void this.flush();
42
+ }
43
+ toolStart(name, summary) {
44
+ if (this.done)
45
+ return;
46
+ this.state.toolLine = `${name}: ${summary.slice(0, 120)}`;
47
+ this.lastActivityAt = Date.now();
48
+ void this.flush();
49
+ }
50
+ toolResult(name, ok) {
51
+ if (this.done)
52
+ return;
53
+ this.state.toolLine = `${ok ? '✔' : '✘'} ${name}`;
54
+ this.lastActivityAt = Date.now();
55
+ }
56
+ setStatus(status) {
57
+ if (this.done)
58
+ return;
59
+ this.state.status = status;
60
+ this.lastActivityAt = Date.now();
61
+ void this.flush();
62
+ }
63
+ async finish(summary) {
64
+ this.done = true;
65
+ clearInterval(this.flushTimer);
66
+ clearInterval(this.heartbeatTimer);
67
+ this.state.status = summary;
68
+ this.state.toolLine = '';
69
+ await this.flush(); // 经由同一串行链落地,保证是最后一张(终态不被旧 flush 覆盖)
70
+ }
71
+ /**
72
+ * 串行化 flush:所有更新走同一条 promise 链按发起顺序落地。
73
+ * - in-flight 中再来请求 → 标记 dirty,本轮落地后自动补刷一次(带上最新 state);
74
+ * - finish 的终态 flush 也入链,天然排在先前挂起的更新之后。
75
+ */
76
+ flush() {
77
+ if (!this.messageId)
78
+ return Promise.resolve();
79
+ if (this.flushing) {
80
+ this.dirty = true; // 已有 in-flight,补刷标记,等它落地后再发
81
+ return this.flushChain;
82
+ }
83
+ this.flushing = true;
84
+ this.flushChain = (async () => {
85
+ for (;;) {
86
+ this.dirty = false;
87
+ if (this.buffer) {
88
+ this.state.textTail += this.buffer;
89
+ this.buffer = '';
90
+ }
91
+ try {
92
+ await this.sender.updateCard(this.messageId, buildProgressCard(this.state));
93
+ }
94
+ catch {
95
+ // 单次 PATCH 失败不致命(限流/网络抖动),下轮重试
96
+ }
97
+ if (!this.dirty)
98
+ break; // 落地期间无新请求,收工
99
+ }
100
+ })().finally(() => {
101
+ this.flushing = false;
102
+ });
103
+ return this.flushChain;
104
+ }
105
+ }
106
+ //# sourceMappingURL=progress-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress-card.js","sourceRoot":"","sources":["../../src/gateway/progress-card.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import type { BridgeConfig, FeishuAppConfig, GatewayHandlers } from './types.js';
2
+ import { AccessControl } from './access/access-control.js';
3
+ import { runTask } from './executor/claude-executor.js';
4
+ import { SessionStore } from './session/session-store.js';
5
+ import { type TranscriptRecorder } from './transcript/transcript-writer.js';
6
+ export { VERSION } from './version.js';
7
+ export interface BridgeDeps {
8
+ gateway: {
9
+ start(h: GatewayHandlers): Promise<void>;
10
+ sendCardTo(chatId: string, card: unknown): Promise<string>;
11
+ sendTextTo(chatId: string, markdown: string): Promise<string>;
12
+ updateCard(id: string, card: unknown): Promise<void>;
13
+ uploadAndSendFile(chatId: string, p: string): Promise<void>;
14
+ /** 上传图片并发带 caption 的卡片(lcb-notify 逐张发图用);可选——旧 gateway/测试 mock 缺省走降级 */
15
+ sendImageTo?(chatId: string, p: string, caption?: string): Promise<string>;
16
+ };
17
+ access: AccessControl;
18
+ store: SessionStore;
19
+ executor: typeof runTask;
20
+ /** 对话落盘记录器(可选依赖:缺失即不落盘,写失败自身消化不抛出) */
21
+ transcript?: TranscriptRecorder;
22
+ }
23
+ export declare function createBridge(config: BridgeConfig, app: FeishuAppConfig, // 本 bridge 绑定的飞书应用:并发/默认工作区/Claude Code 环境/人格均 per-app
24
+ deps: BridgeDeps, opts?: {
25
+ confirmTimeoutMs?: number;
26
+ reloadConfig?: () => void;
27
+ }): GatewayHandlers;
28
+ /**
29
+ * 配置热重载器:lcb ws add/remove 写盘后,运行实例下一条消息即见新工作区
30
+ * (与 access.reload 同款模式——长驻进程不重读会持旧配置直至重启)。
31
+ * 热应用 workspaces + defaults + 各 app 的 triggers/plugins:createBridge 闭包持有
32
+ * 同一 app 对象引用、executeTask 每任务现读,原地 mutate 下一条消息即生效。
33
+ * 不热应用(且不纳入 sameApps 比较):FeishuGateway 与 Semaphore 均为启动时构造,
34
+ * apps 凭证 / concurrency 变更无法热生效,打警告提示重启,避免「以为已生效」的坑。
35
+ * 读失败(文件被写坏的中间态等)沿用旧值不崩。
36
+ */
37
+ export declare function createConfigReloader(config: BridgeConfig, configPath: string): () => void;
38
+ export declare function startBridge(configPath?: string): Promise<void>;
package/dist/index.js ADDED
@@ -0,0 +1,433 @@
1
+ // 装配主流程:消息 → 访问控制 → 命令 → 通道队列 → 执行 → 确认卡片 → 回传
2
+ import { randomUUID } from 'node:crypto';
3
+ import { execFile } from 'node:child_process';
4
+ import { tmpdir } from 'node:os';
5
+ import { join, basename, resolve } from 'node:path';
6
+ import { promisify } from 'node:util';
7
+ import { CONFIG_DIR, CONFIG_PATH, loadConfig, sameApps } from './config.js';
8
+ import { AccessControl } from './access/access-control.js';
9
+ import { FeishuGateway } from './gateway/feishu-gateway.js';
10
+ import { ProgressCard } from './gateway/progress-card.js';
11
+ import { buildConfirmCard, buildConfirmResultCard, DECISION_TEXT } from './gateway/card-builder.js';
12
+ import { runTask } from './executor/claude-executor.js';
13
+ import { PermissionGate } from './executor/permission-gate.js';
14
+ import { createGatewaySender, createNotifyServer, NOTIFY_SERVER_NAME } from './executor/notify-server.js';
15
+ import { SessionStore, migrateLegacySessions } from './session/session-store.js';
16
+ import { handleCommand } from './session/commands.js';
17
+ import { rewriteByTrigger } from './session/triggers.js';
18
+ import { Semaphore, channelKey } from './session/channel.js';
19
+ import { TranscriptWriter, sweepTranscripts } from './transcript/transcript-writer.js';
20
+ // 版本号收敛到 version.ts 单一来源(bin/lcb.ts 与 smoke 测试均引用)
21
+ export { VERSION } from './version.js';
22
+ const execFileP = promisify(execFile);
23
+ const MAX_FILES_BEFORE_ZIP = 10;
24
+ // 任务总超时 4 小时(防挂死;确认等待、长编译均在正常范围)
25
+ const TASK_HARD_TIMEOUT_MS = 4 * 60 * 60 * 1000;
26
+ // 确认等待窗:无人确认则自动拒绝。超时判定由 wiring 侧自管(ask 闭包内的定时器),
27
+ // 从而到点即清理 confirmPending 条目并把卡片 PATCH 为过期态——条目有界不泄漏,
28
+ // 迟到点击因条目已删被 handleCardAction toast 提示后忽略,永不显示与实际不符的决策态
29
+ const CONFIRM_TIMEOUT_MS = 10 * 60 * 1000;
30
+ // PermissionGate 的兜底超时:仅当 wiring 侧超时机制失效时才触发(正常流程 ask 必在 CONFIRM_TIMEOUT_MS 内 settle)
31
+ const GATE_FALLBACK_TIMEOUT_MS = CONFIRM_TIMEOUT_MS + 60_000;
32
+ /** 确认超时后的过期态卡片(此后迟到点击不再改写此卡片) */
33
+ function expiredConfirmCard(req, timeoutMs) {
34
+ return {
35
+ schema: '2.0',
36
+ config: { update_multi: true },
37
+ body: {
38
+ elements: [{
39
+ tag: 'markdown',
40
+ content: `**🔐 Claude 请求执行操作**\n\n工具: \`${req.toolName}\` 工作区: \`${req.workspaceName}\`\n\`\`\`\n${req.summary.slice(0, 500)}\n\`\`\`\n\n⏰ 已超时自动拒绝(${Math.round(timeoutMs / 60000)} 分钟未确认)`,
41
+ }],
42
+ },
43
+ };
44
+ }
45
+ export function createBridge(config, app, // 本 bridge 绑定的飞书应用:并发/默认工作区/Claude Code 环境/人格均 per-app
46
+ deps, opts = {}) {
47
+ const sem = new Semaphore(app.concurrency ?? config.concurrency);
48
+ const tag = `[app:${app.name}]`;
49
+ // per-app Claude Code 环境:每个机器人的子进程用各自的 CLAUDE_CONFIG_DIR
50
+ //(会话存储/用户设置/插件物理隔离),app.env 可覆盖模型凭证等变量;
51
+ // process.env 先展开保证其余变量(ANTHROPIC_* 凭证、代理等)原样透传
52
+ const appEnv = {
53
+ ...process.env,
54
+ CLAUDE_CONFIG_DIR: app.claudeConfigDir,
55
+ ...app.env,
56
+ };
57
+ const runtimes = new Map();
58
+ // 通道级权限闸:「本次会话不再询问」的记忆跨任务生效(spec:直至 /new),
59
+ // 故 gate 归通道持有而非每任务新建——每任务新建会把授权缩成任务级,任务 B 又要重新确认
60
+ const gates = new Map();
61
+ const confirmPending = new Map();
62
+ function workspacePath(name) {
63
+ return config.workspaces.find((w) => w.name === name)?.path ?? config.workspaces[0].path;
64
+ }
65
+ /** 通道内串行入队(每 key 一条 Promise 链),全局并发由 Semaphore 限制 */
66
+ function enqueue(key, msg, prompt, wsName) {
67
+ const rt = runtimes.get(key) ?? { queue: Promise.resolve() };
68
+ runtimes.set(key, rt);
69
+ rt.queue = rt.queue.then(() => executeTask(key, msg, prompt, wsName)).catch((e) => {
70
+ console.error(tag, '[任务异常]', e);
71
+ });
72
+ }
73
+ async function handleIncoming(msg) {
74
+ try {
75
+ await processMessage(msg);
76
+ }
77
+ catch (e) {
78
+ // 长驻进程兜底:单条消息处理失败不允许成为 unhandled rejection 拖垮整个桥接器
79
+ console.error(tag, '[消息处理异常]', msg.messageId, e);
80
+ }
81
+ }
82
+ async function processMessage(msg) {
83
+ const key = channelKey(msg.chatId, msg.userId);
84
+ // 1. 访问控制:白名单外发配对码(首个配对成功者自动成为 admin,见 AccessControl)
85
+ // 每条消息先重读 access.json:lcb pair / 运行终端等独立进程批准写盘后,
86
+ // 长存的内存实例不 reload 会查到旧白名单 → 反复发配对码且整盘覆写抹掉新用户(死循环)
87
+ deps.access.reload();
88
+ // 配置热重载:lcb ws add/remove 独立进程写盘后,本实例下一条消息即读到新工作区
89
+ opts.reloadConfig?.();
90
+ if (!deps.access.isAllowed(msg.userId)) {
91
+ const code = deps.access.beginPairing(msg.userId, msg.userId);
92
+ console.log(`${tag}[配对] 未知用户 ${msg.userId} 请求接入,配对码:${code}(在终端输入 lcb pair ${code} 批准)`);
93
+ await deps.gateway.sendTextTo(msg.chatId, `🔐 首次使用需配对。\n\n请管理员在桥接器终端确认配对码:**${code}**(15 分钟内有效)`);
94
+ return;
95
+ }
96
+ // 2. 命令:/help /new /resume /stop /status /ws
97
+ const st = deps.store.getChannelState(key);
98
+ // currentWorkspace 语义:store 中已设置的工作区优先,否则 app 默认,最后全局默认——
99
+ // 保证 /new、/status 回复与实际一致
100
+ const currentWorkspace = st?.workspaceName ?? app.defaultWorkspace ?? config.defaults.workspace;
101
+ // 2.5 触发词映射:必须放在本地命令之前——斜杠触发词(如 /produce)会被 handleCommand
102
+ // 的未知命令分支吞掉;rewriteByTrigger 对本地命令(/stop 等)直接放行,不会被劫持
103
+ const triggered = rewriteByTrigger(msg.text, app.triggers);
104
+ if (triggered !== null) {
105
+ await deps.gateway.sendTextTo(msg.chatId, '⚡ 已按触发词转入对应技能流程');
106
+ enqueue(key, msg, triggered, currentWorkspace);
107
+ return;
108
+ }
109
+ const cmd = await handleCommand(msg.text, {
110
+ channelKey: key,
111
+ store: deps.store,
112
+ config,
113
+ appName: app.name,
114
+ isAdmin: deps.access.isAdmin(msg.userId),
115
+ currentWorkspace: () => currentWorkspace,
116
+ stopCurrentTask: () => {
117
+ const rt = runtimes.get(key);
118
+ if (rt?.abort) {
119
+ rt.abort.abort();
120
+ return true;
121
+ }
122
+ return false;
123
+ },
124
+ });
125
+ if (cmd.handled) {
126
+ if (cmd.reply)
127
+ await deps.gateway.sendTextTo(msg.chatId, cmd.reply);
128
+ // /new 开启新会话:「本次会话不再询问」的授权随之失效(handleCommand 无权访问 wiring
129
+ // 持有的 gate,故在命令处理分支后于 wiring 侧检测并 reset)
130
+ if (/^\/new(?:\s|$)/.test(msg.text.trim()))
131
+ gates.get(key)?.reset();
132
+ return;
133
+ }
134
+ // 3. 普通文本:通道内串行入队(每 key 一条 Promise 链),全局并发由 Semaphore 限制
135
+ enqueue(key, msg, cmd.taskText ?? msg.text, currentWorkspace);
136
+ }
137
+ async function executeTask(key, msg, prompt, wsName) {
138
+ const release = await sem.acquire();
139
+ const abort = new AbortController();
140
+ const rt = runtimes.get(key);
141
+ rt.abort = abort;
142
+ const progress = new ProgressCard({
143
+ sendCard: (c) => deps.gateway.sendCardTo(msg.chatId, c),
144
+ updateCard: (id, c) => deps.gateway.updateCard(id, c),
145
+ }, `任务 · ${wsName}`);
146
+ const confirmTimeoutMs = opts.confirmTimeoutMs ?? CONFIRM_TIMEOUT_MS;
147
+ // 通道级复用:已存在则沿用(allow-session 记忆跨任务),不存在才建
148
+ let gate = gates.get(key);
149
+ if (!gate) {
150
+ gate = new PermissionGate({
151
+ ask: async (req) => {
152
+ // 发确认卡片并挂起,等待 onCardAction 按 requestId 唤醒;
153
+ // 超时由本闭包自管:到点删除条目 + 卡片置为过期态 + 以 deny 继续——
154
+ // 条目有界(无人点击、/stop、4h abort 挂起中的 ask 均会被定时器清理),
155
+ // 此后的迟到点击因条目已删被 toast 提示后忽略,卡片不再被改写为与实际不符的决策态
156
+ const cardId = await deps.gateway.sendCardTo(msg.chatId, buildConfirmCard(req));
157
+ return new Promise((resolve) => {
158
+ const gc = setTimeout(() => {
159
+ confirmPending.delete(req.requestId);
160
+ void deps.gateway.updateCard(cardId, expiredConfirmCard(req, confirmTimeoutMs)).catch(() => { });
161
+ resolve('deny');
162
+ }, confirmTimeoutMs);
163
+ gc.unref();
164
+ confirmPending.set(req.requestId, {
165
+ resolve: (d) => {
166
+ clearTimeout(gc); // 用户已及时确认:撤销过期态 PATCH,防止已决策的卡片被改写为超时
167
+ resolve(d);
168
+ },
169
+ req,
170
+ ownerId: msg.userId,
171
+ cardId,
172
+ });
173
+ });
174
+ },
175
+ timeoutMs: GATE_FALLBACK_TIMEOUT_MS,
176
+ });
177
+ gates.set(key, gate);
178
+ }
179
+ const hardTimeout = setTimeout(() => abort.abort(), TASK_HARD_TIMEOUT_MS);
180
+ hardTimeout.unref();
181
+ // lcb-notify 发送能力:chatId 硬绑定当前任务(权限闸直通的安全前提);
182
+ // sentPaths 记录中途已推送的文件,任务收尾的产出回传据此去重(用户已收过的不重发)
183
+ const sentPaths = new Set();
184
+ const notifySender = createGatewaySender({
185
+ chatId: msg.chatId,
186
+ sentPaths,
187
+ sendText: (c, md) => deps.gateway.sendTextTo(c, md),
188
+ sendImageWithCaption: deps.gateway.sendImageTo,
189
+ sendFileTo: (c, p) => deps.gateway.uploadAndSendFile(c, p),
190
+ });
191
+ try {
192
+ await progress.start();
193
+ const state = deps.store.getChannelState(key);
194
+ const resumeId = state?.sessions?.[0]?.sessionId;
195
+ const now = () => new Date().toISOString();
196
+ // 落盘 · user:任务起点(prompt 全文 + resume 链上一轮 sessionId)
197
+ deps.transcript?.user({
198
+ v: 1, ts: now(), kind: 'user', app: app.appId,
199
+ chatId: msg.chatId, userId: msg.userId, workspace: wsName, sessionId: resumeId, text: prompt,
200
+ });
201
+ const outcome = await deps.executor(prompt, {
202
+ cwd: workspacePath(wsName),
203
+ resumeSessionId: resumeId,
204
+ signal: abort.signal,
205
+ env: appEnv,
206
+ appendSystemPrompt: app.appendSystemPrompt,
207
+ // 进程内通知工具(send_text/send_image/send_file):中间产物实时推给当前聊天。
208
+ // server 实例按任务构造,chatId 在 sender 闭包内硬绑定——模型无法选择接收者
209
+ mcpServers: { [NOTIFY_SERVER_NAME]: createNotifyServer(notifySender) },
210
+ // per-app 显式加载的本地插件(SDK 单次 query 不展开斜杠命令,技能经触发词改写后由此加载)
211
+ ...(app.plugins?.length ? { plugins: app.plugins.map((p) => ({ path: p.path })) } : {}),
212
+ canUseTool: (toolName, input) => gate.decide(toolName, input, wsName),
213
+ }, {
214
+ onProgress: (e) => {
215
+ if (e.kind === 'text') {
216
+ progress.appendText(e.content);
217
+ // 落盘 · assistant:流式文本块全文(每块一行,天然增量)
218
+ deps.transcript?.assistant({
219
+ v: 1, ts: now(), kind: 'assistant', app: app.appId,
220
+ chatId: msg.chatId, userId: msg.userId, text: e.content,
221
+ });
222
+ }
223
+ else if (e.kind === 'tool-start') {
224
+ const [n, ...rest] = e.content.split(': ');
225
+ progress.toolStart(n, rest.join(': '));
226
+ deps.transcript?.tool({
227
+ v: 1, ts: now(), kind: 'tool', app: app.appId,
228
+ chatId: msg.chatId, userId: msg.userId, phase: 'start', tool: n, summary: rest.join(': '), ok: true,
229
+ });
230
+ }
231
+ else if (e.kind === 'tool-result') {
232
+ progress.toolResult(e.content, e.ok ?? true);
233
+ deps.transcript?.tool({
234
+ v: 1, ts: now(), kind: 'tool', app: app.appId,
235
+ chatId: msg.chatId, userId: msg.userId, phase: 'result', tool: e.content, summary: '', ok: e.ok ?? true,
236
+ });
237
+ }
238
+ },
239
+ });
240
+ if (abort.signal.aborted) {
241
+ // /stop(或硬超时)中止后 SDK 流仍会正常收尾走成功分支——按停止处理,不误报「完成」。
242
+ // 会话归档保留(中断任务的会话上下文仍有价值),但跳过结果与产出文件回传
243
+ await progress.finish('🛑 已停止');
244
+ deps.store.archiveSession(key, outcome.sessionId, prompt);
245
+ deps.transcript?.result({
246
+ v: 1, ts: now(), kind: 'result', app: app.appId,
247
+ chatId: msg.chatId, userId: msg.userId, sessionId: outcome.sessionId, subtype: 'stopped', text: '',
248
+ });
249
+ return;
250
+ }
251
+ await progress.finish(`✅ 完成`);
252
+ deps.store.archiveSession(key, outcome.sessionId, prompt);
253
+ deps.transcript?.result({
254
+ v: 1, ts: now(), kind: 'result', app: app.appId,
255
+ chatId: msg.chatId, userId: msg.userId, workspace: wsName,
256
+ sessionId: outcome.sessionId, subtype: 'success',
257
+ text: outcome.finalText, producedFiles: outcome.producedFiles, turns: outcome.turns,
258
+ });
259
+ // 会话超长提醒(累计轮次粗略估计,防上下文爆炸)
260
+ if (outcome.turns > 40) {
261
+ await deps.gateway.sendTextTo(msg.chatId, '💡 本会话已较长,建议发送 /new 开启新会话(/resume 可随时切回)');
262
+ }
263
+ // 结果回传(超长截断,防飞书消息体超限)
264
+ if (outcome.finalText)
265
+ await deps.gateway.sendTextTo(msg.chatId, outcome.finalText.slice(0, 4000));
266
+ // 产出文件回传:>10 个打 zip(Windows 10+ / macOS / Linux 均自带 tar),失败退化为逐个上传;
267
+ // 中途经 lcb-notify 已推送过的文件跳过(用户已收到,防重复轰炸)
268
+ const files = outcome.producedFiles.filter((f) => !sentPaths.has(resolve(f)));
269
+ if (files.length > MAX_FILES_BEFORE_ZIP) {
270
+ const zipPath = join(tmpdir(), `lcb-${randomUUID()}.zip`);
271
+ try {
272
+ await execFileP('tar', ['-a', '-cf', zipPath, ...files.map((f) => basename(f))], { cwd: workspacePath(wsName) });
273
+ await deps.gateway.uploadAndSendFile(msg.chatId, zipPath);
274
+ }
275
+ catch {
276
+ for (const f of files)
277
+ await deps.gateway.uploadAndSendFile(msg.chatId, f);
278
+ }
279
+ }
280
+ else {
281
+ for (const f of files)
282
+ await deps.gateway.uploadAndSendFile(msg.chatId, f);
283
+ }
284
+ }
285
+ catch (e) {
286
+ await progress.finish(`❌ 出错:${String(e).slice(0, 300)}`);
287
+ deps.transcript?.result({
288
+ v: 1, ts: new Date().toISOString(), kind: 'result', app: app.appId,
289
+ chatId: msg.chatId, userId: msg.userId, sessionId: '',
290
+ subtype: 'error', text: String(e).slice(0, 300),
291
+ });
292
+ }
293
+ finally {
294
+ clearTimeout(hardTimeout);
295
+ rt.abort = undefined;
296
+ release();
297
+ }
298
+ }
299
+ /**
300
+ * 卡片回调:所有路径必须给用户可感知反馈(点击无响应会导致反复点击)。
301
+ * 发起人有效点击走回调响应内联结果卡(飞书收到响应瞬间同步换卡,按钮即刻消失),
302
+ * toast 仅作即时提示;!pending 等分支严禁携带 card(卡片可能已是结果态,带卡会把
303
+ * 结果卡换回带按钮状态,等同剥夺发起人操作权——参照 I2 教训)。
304
+ */
305
+ async function handleCardAction(action) {
306
+ try {
307
+ const pending = confirmPending.get(action.value.requestId);
308
+ if (!pending) {
309
+ // 已处理/超时清理/桥接器重启后的孤儿卡:toast 提示后忽略,不重复决策
310
+ return { toast: { type: 'info', content: '该确认已被处理或已过期,无需重复操作' } };
311
+ }
312
+ if (action.operatorId !== pending.ownerId) {
313
+ // 非发起人点击:卡片保持原样(按钮保留,发起人仍可确认)——PATCH 成无按钮的结果卡
314
+ // 会让发起人从此无法操作,群聊可被任意成员 DoS。仅回 toast 提示 + resolve 落空
315
+ console.log(tag, `[卡片回调] 非发起人 ${action.operatorId} 点击确认卡 ${action.value.requestId},已忽略`);
316
+ return { toast: { type: 'info', content: '仅任务发起人可确认' } };
317
+ }
318
+ confirmPending.delete(action.value.requestId);
319
+ pending.resolve(action.value.decision);
320
+ const resultCard = buildConfirmResultCard(pending.req, action.value.decision, '任务发起人');
321
+ // 兜底 PATCH 不再 await:回调须在 3 秒内响应(协议 200341),且响应体已内联结果卡同步换卡,
322
+ // PATCH 仅在 WS 回传响应丢失时保证最终一致(同时消掉 await PATCH 慢网络下拖垮响应窗口的隐患)
323
+ void deps.gateway.updateCard(pending.cardId, resultCard)
324
+ .catch((e) => console.error('[卡片兜底更新失败]', action.value.requestId, e));
325
+ return {
326
+ toast: { type: 'success', content: DECISION_TEXT[action.value.decision] },
327
+ card: { type: 'raw', data: resultCard },
328
+ };
329
+ }
330
+ catch (e) {
331
+ console.error(tag, '[卡片回调异常]', action.value.requestId, e);
332
+ // resolve 之后的代码理论不可抛;若未来插入可抛代码,按条目是否仍在区分决策是否已生效
333
+ const retryable = confirmPending.has(action.value.requestId);
334
+ return { toast: { type: 'error', content: retryable ? '处理失败,请重试' : '处理出现异常,决策可能已生效,请勿盲目重试' } };
335
+ }
336
+ }
337
+ return { onMessage: handleIncoming, onCardAction: handleCardAction };
338
+ }
339
+ /**
340
+ * 配置热重载器:lcb ws add/remove 写盘后,运行实例下一条消息即见新工作区
341
+ * (与 access.reload 同款模式——长驻进程不重读会持旧配置直至重启)。
342
+ * 热应用 workspaces + defaults + 各 app 的 triggers/plugins:createBridge 闭包持有
343
+ * 同一 app 对象引用、executeTask 每任务现读,原地 mutate 下一条消息即生效。
344
+ * 不热应用(且不纳入 sameApps 比较):FeishuGateway 与 Semaphore 均为启动时构造,
345
+ * apps 凭证 / concurrency 变更无法热生效,打警告提示重启,避免「以为已生效」的坑。
346
+ * 读失败(文件被写坏的中间态等)沿用旧值不崩。
347
+ */
348
+ export function createConfigReloader(config, configPath) {
349
+ return () => {
350
+ let fresh;
351
+ try {
352
+ fresh = loadConfig(configPath);
353
+ }
354
+ catch (e) {
355
+ console.warn('[配置热重载] 读取失败,沿用旧配置:', e instanceof Error ? e.message : e);
356
+ return;
357
+ }
358
+ if (!sameApps(fresh.apps, config.apps) || fresh.concurrency !== config.concurrency) {
359
+ console.warn('[配置热重载] 检测到应用列表/凭证或 concurrency 变更,需重启后生效');
360
+ }
361
+ config.workspaces = fresh.workspaces;
362
+ config.defaults = fresh.defaults;
363
+ // app 数量变化属需重启的变更(上面 sameApps 长度比较已警告),仅等长时逐位 mutate
364
+ if (fresh.apps.length === config.apps.length) {
365
+ fresh.apps.forEach((fa, i) => {
366
+ config.apps[i].triggers = fa.triggers;
367
+ config.apps[i].plugins = fa.plugins;
368
+ });
369
+ }
370
+ };
371
+ }
372
+ export async function startBridge(configPath = CONFIG_PATH) {
373
+ const config = loadConfig(configPath);
374
+ // access 全局共享:个人场景同一人对所有机器人,N 个 bridge 注入同一实例(单进程无竞态)
375
+ const access = AccessControl.load(join(CONFIG_DIR, 'access.json'));
376
+ // 旧单应用 sessions.json 一次性迁移到 apps[0] 的分片(键格式未变,纯改名)
377
+ migrateLegacySessions(CONFIG_DIR, config.apps[0].appId);
378
+ if (config.transcripts?.retentionDays) {
379
+ const removed = sweepTranscripts(join(CONFIG_DIR, 'transcripts'), config.transcripts.retentionDays);
380
+ if (removed > 0)
381
+ console.log(`[transcripts] 已清理 ${removed} 个过期落盘文件`);
382
+ }
383
+ // reloader 共享:所有 bridge 持有同一 config 对象引用,mutate 一处全员可见
384
+ const reloadConfig = createConfigReloader(config, configPath);
385
+ // 每 app 一对 gateway+bridge:长连接/会话池/并发闸/Claude Code 环境/落盘目录全部 per-app 隔离
386
+ const runners = config.apps.map((app) => {
387
+ const tag = `[app:${app.name}]`;
388
+ const gateway = new FeishuGateway(app, {
389
+ log: { warn: (...a) => console.warn(tag, ...a), error: (...a) => console.error(tag, ...a) },
390
+ // 多机器人部署:botOpenId 拉取失败时宁丢群消息不猜(防同群双触发)
391
+ strictGroupMention: config.apps.length > 1,
392
+ });
393
+ const deps = {
394
+ gateway: {
395
+ start: (h) => gateway.start(h),
396
+ sendCardTo: (chatId, card) => gateway.sendCard(chatId, card),
397
+ sendTextTo: (chatId, md) => gateway.sendText(chatId, md),
398
+ updateCard: (id, card) => gateway.updateCard(id, card),
399
+ uploadAndSendFile: (chatId, p) => gateway.uploadAndSendFile(chatId, p),
400
+ sendImageTo: (chatId, p, caption) => gateway.sendImage(chatId, p, caption),
401
+ },
402
+ access,
403
+ store: SessionStore.load(join(CONFIG_DIR, `sessions.${app.appId}.json`)),
404
+ executor: runTask,
405
+ transcript: new TranscriptWriter(join(CONFIG_DIR, 'transcripts', app.appId)),
406
+ };
407
+ return { app, gateway, bridge: createBridge(config, app, deps, { reloadConfig }) };
408
+ });
409
+ // 部分失败不拖垮其它 app:一个凭证写错时其余机器人照常服务。
410
+ // 注意:SDK 对非法 appId 的 start() 是静默 return 不抛错——Promise resolve 不等于连接成功,
411
+ // 逐 app 状态行是运维观测的主要手段
412
+ const results = await Promise.allSettled(runners.map((r) => r.gateway.start(r.bridge)));
413
+ runners.forEach((r, i) => {
414
+ if (results[i].status === 'fulfilled')
415
+ console.log(`✅ ${r.app.name}(${r.app.appId})长连接已启动`);
416
+ });
417
+ for (const f of results)
418
+ if (f.status === 'rejected')
419
+ console.error('❌ 应用启动失败:', f.reason);
420
+ if (results.every((r) => r.status === 'rejected'))
421
+ throw new Error('所有应用均启动失败,请检查 config.yaml 中的 apps 配置');
422
+ console.log(`🚀 lark-claudecode-bridge 已启动(${results.length - results.filter((r) => r.status === 'rejected').length}/${results.length} 个应用,长连接模式,无需公网 IP)`);
423
+ // 优雅关闭:SIGINT/SIGTERM 时逐个关闭全部长连接
424
+ const shutdown = (sig) => {
425
+ console.log(`\n收到 ${sig},正在关闭 ${runners.length} 条长连接…`);
426
+ for (const r of runners)
427
+ r.gateway.close();
428
+ process.exit(0);
429
+ };
430
+ process.on('SIGINT', () => shutdown('SIGINT'));
431
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
432
+ }
433
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /** 通道键:chatId 与 userId 拼接,同 chat + 同 user 视为同一会话通道 */
2
+ export declare function channelKey(chatId: string, userId: string): string;
3
+ /**
4
+ * 异步信号量:限制同时在跑的 Claude 任务数。
5
+ * acquire() 返回一个 release 函数,调用后唤醒最早排队者(FIFO)。
6
+ *
7
+ * - 许可转移式 release:有等待者时不减 active,直接把许可转移给队首等待者,
8
+ * 消除「release 先减、waiter 恢复后加」的 microtask 窗口内被新 acquire 插队超发。
9
+ * - 每个 release 带 once 保护:重复调用为 no-op,防止 active 递减为负。
10
+ */
11
+ export declare class Semaphore {
12
+ private n;
13
+ private active;
14
+ private waiters;
15
+ constructor(n: number);
16
+ acquire(): Promise<() => void>;
17
+ private makeRelease;
18
+ }