@jesonliu/lark-claudecode-bridge 0.3.1 → 0.7.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.
- package/README.md +90 -12
- package/config.example.yaml +42 -17
- package/dist/auth-precheck.d.ts +3 -3
- package/dist/auth-precheck.js +6 -7
- package/dist/auth-precheck.js.map +1 -1
- package/dist/cli/app-manager.d.ts +2 -3
- package/dist/cli/app-manager.js +2 -7
- package/dist/cli/app-manager.js.map +1 -1
- package/dist/cli/setup-wizard.d.ts +1 -0
- package/dist/cli/setup-wizard.js +5 -6
- package/dist/cli/setup-wizard.js.map +1 -1
- package/dist/config.js +73 -10
- package/dist/config.js.map +1 -1
- package/dist/executor/claude-executor.d.ts +8 -2
- package/dist/executor/claude-executor.js +20 -2
- package/dist/executor/claude-executor.js.map +1 -1
- package/dist/executor/notify-server.d.ts +2 -5
- package/dist/executor/notify-server.js +3 -48
- package/dist/executor/notify-server.js.map +1 -1
- package/dist/executor/permission-gate.d.ts +30 -0
- package/dist/executor/permission-gate.js +56 -5
- package/dist/executor/permission-gate.js.map +1 -1
- package/dist/executor/plugin-discovery.d.ts +26 -0
- package/dist/executor/plugin-discovery.js +131 -0
- package/dist/executor/plugin-discovery.js.map +1 -0
- package/dist/gateway/card-builder.d.ts +16 -1
- package/dist/gateway/card-builder.js +58 -0
- package/dist/gateway/card-builder.js.map +1 -1
- package/dist/gateway/diff-card.d.ts +16 -0
- package/dist/gateway/diff-card.js +39 -0
- package/dist/gateway/diff-card.js.map +1 -0
- package/dist/gateway/feishu-gateway.js +9 -2
- package/dist/gateway/feishu-gateway.js.map +1 -1
- package/dist/index.js +163 -32
- package/dist/index.js.map +1 -1
- package/dist/session/commands.d.ts +13 -2
- package/dist/session/commands.js +97 -9
- package/dist/session/commands.js.map +1 -1
- package/dist/session/session-store.d.ts +3 -0
- package/dist/session/session-store.js.map +1 -1
- package/dist/session/triggers.d.ts +1 -1
- package/dist/session/triggers.js +3 -2
- package/dist/session/triggers.js.map +1 -1
- package/dist/types.d.ts +49 -9
- package/dist/util/beijing-time.d.ts +5 -0
- package/dist/util/beijing-time.js +33 -0
- package/dist/util/beijing-time.js.map +1 -0
- package/dist/util/chunk-text.d.ts +2 -0
- package/dist/util/chunk-text.js +48 -0
- package/dist/util/chunk-text.js.map +1 -0
- package/dist/util/diff.d.ts +2 -0
- package/dist/util/diff.js +70 -0
- package/dist/util/diff.js.map +1 -0
- package/dist/util/workspace-diff.d.ts +9 -0
- package/dist/util/workspace-diff.js +56 -0
- package/dist/util/workspace-diff.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { chunkText } from '../util/chunk-text.js';
|
|
1
2
|
function card(elements) {
|
|
2
3
|
return { schema: '2.0', config: { update_multi: true }, body: { elements } };
|
|
3
4
|
}
|
|
@@ -57,4 +58,61 @@ export function buildConfirmResultCard(req, decision, byName) {
|
|
|
57
58
|
// 摘要截断与确认卡一致(1500):点击瞬间回调响应内联换卡,摘要突然缩水会被用户看到
|
|
58
59
|
return card([md(`**🔐 Claude 请求执行操作**\n\n工具: \`${req.toolName}\` 工作区: \`${req.workspaceName}\`\n\`\`\`\n${req.summary.slice(0, 1500)}\n\`\`\`\n\n${DECISION_TEXT[decision]}(由 ${byName} 操作)`)]);
|
|
59
60
|
}
|
|
61
|
+
function planButton(decision, label, type, requestId) {
|
|
62
|
+
return {
|
|
63
|
+
tag: 'button',
|
|
64
|
+
text: { tag: 'plain_text', content: label },
|
|
65
|
+
type,
|
|
66
|
+
behaviors: [{ type: 'callback', value: { requestId, decision } }],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 计划确认卡片组:plan 超长时按 ~2800 字拆多张(首卡含输入框与按钮,其余为纯正文续篇)。
|
|
71
|
+
* 空白 plan 退化为单卡占位(模型未提交实质计划时用户只能放弃)。
|
|
72
|
+
*/
|
|
73
|
+
export function buildPlanCards(req) {
|
|
74
|
+
const chunks = chunkText(req.plan, 2800);
|
|
75
|
+
if (chunks.length === 0)
|
|
76
|
+
chunks.push('(模型未提交计划正文)');
|
|
77
|
+
return chunks.map((chunk, i) => {
|
|
78
|
+
const header = chunks.length > 1
|
|
79
|
+
? `**📋 Claude 提交执行计划(${i + 1}/${chunks.length})**\n\n工作区: \`${req.workspaceName}\`\n`
|
|
80
|
+
: `**📋 Claude 提交执行计划**\n\n工作区: \`${req.workspaceName}\`\n`;
|
|
81
|
+
if (i === 0) {
|
|
82
|
+
return card([
|
|
83
|
+
md(`${header}${chunk}`),
|
|
84
|
+
// 修改意见输入框:plan-revise 点击时随回调 form_value 传回(name=feedback)
|
|
85
|
+
{
|
|
86
|
+
tag: 'input',
|
|
87
|
+
name: 'feedback',
|
|
88
|
+
placeholder: { tag: 'plain_text', content: '修改意见(点「按意见修改」时随意见重新出计划)' },
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
// 卡片 V2 已废弃 tag:'action',与确认卡同款 column_set 分栏按钮
|
|
92
|
+
tag: 'column_set',
|
|
93
|
+
flex_mode: 'flow',
|
|
94
|
+
columns: [
|
|
95
|
+
{ tag: 'column', width: 'auto', weight: 1, vertical_align: 'top', elements: [planButton('plan-approve', '✅ 批准执行', 'primary', req.requestId)] },
|
|
96
|
+
{ tag: 'column', width: 'auto', weight: 1, vertical_align: 'top', elements: [planButton('plan-revise', '📝 按意见修改', 'default', req.requestId)] },
|
|
97
|
+
{ tag: 'column', width: 'auto', weight: 1, vertical_align: 'top', elements: [planButton('plan-reject', '❌ 放弃计划', 'danger', req.requestId)] },
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
]);
|
|
101
|
+
}
|
|
102
|
+
return card([md(`${header}${chunk}`)]);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/** 计划决策结果卡(决策后由回调响应内联 + 兜底 PATCH 首卡) */
|
|
106
|
+
export function buildPlanResultCard(req, decision, byName, feedback) {
|
|
107
|
+
const text = decision === 'plan-approve'
|
|
108
|
+
? `✅ 计划已批准,开始执行(由 ${byName} 操作)`
|
|
109
|
+
: decision === 'plan-revise'
|
|
110
|
+
? `📝 已提交修改意见,Claude 将修订计划后重新提交(由 ${byName} 操作):\n${(feedback ?? '').slice(0, 500)}`
|
|
111
|
+
: `❌ 计划已放弃(由 ${byName} 操作)`;
|
|
112
|
+
return card([md(`**📋 Claude 提交执行计划**\n\n工作区: \`${req.workspaceName}\`\n\n${text}`)]);
|
|
113
|
+
}
|
|
114
|
+
/** 计划确认超时卡(此后迟到点击不再改写此卡片) */
|
|
115
|
+
export function buildExpiredPlanCard(req, timeoutMs) {
|
|
116
|
+
return card([md(`**📋 Claude 提交执行计划**\n\n工作区: \`${req.workspaceName}\`\n\n⏰ 已超时自动放弃(${Math.round(timeoutMs / 60000)} 分钟未确认)`)]);
|
|
117
|
+
}
|
|
60
118
|
//# sourceMappingURL=card-builder.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"card-builder.js","sourceRoot":"","sources":["../../src/gateway/card-builder.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"card-builder.js","sourceRoot":"","sources":["../../src/gateway/card-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface DiffSummaryMeta {
|
|
2
|
+
workspaceName: string;
|
|
3
|
+
files: number;
|
|
4
|
+
}
|
|
5
|
+
/** 从 unified diff 文本统计改动规模:+/− 行数(排除 +++/--- 文件头) */
|
|
6
|
+
export declare function diffStats(diffText: string): {
|
|
7
|
+
additions: number;
|
|
8
|
+
deletions: number;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* 生成汇总 diff 卡片组:
|
|
12
|
+
* - 首卡标题含文件数与 +X/-Y 统计
|
|
13
|
+
* - diff 正文按 ~2800 字分块,每块包在 ```diff 围栏里(飞书 markdown 渲染红绿着色)
|
|
14
|
+
* - diff 为空(无改动)返回 [],调用方跳过发送
|
|
15
|
+
*/
|
|
16
|
+
export declare function buildDiffSummaryCards(diffText: string, meta: DiffSummaryMeta): unknown[];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// 汇总 diff 收尾卡片:code-dev 工作区任务完成后替代整文件上传——只发「改了什么」,
|
|
2
|
+
// 多文件 diff 合并展示,超长按块拆多张卡(复用 chunkText 贪心分块)
|
|
3
|
+
import { chunkText } from '../util/chunk-text.js';
|
|
4
|
+
/** 从 unified diff 文本统计改动规模:+/− 行数(排除 +++/--- 文件头) */
|
|
5
|
+
export function diffStats(diffText) {
|
|
6
|
+
let additions = 0;
|
|
7
|
+
let deletions = 0;
|
|
8
|
+
for (const line of diffText.split('\n')) {
|
|
9
|
+
if (line.startsWith('+++') || line.startsWith('---'))
|
|
10
|
+
continue;
|
|
11
|
+
if (line.startsWith('+'))
|
|
12
|
+
additions++;
|
|
13
|
+
else if (line.startsWith('-'))
|
|
14
|
+
deletions++;
|
|
15
|
+
}
|
|
16
|
+
return { additions, deletions };
|
|
17
|
+
}
|
|
18
|
+
/** 单张卡片正文上限:留出标题/```diff 围栏/卡片包壳的 JSON 余量 */
|
|
19
|
+
const DIFF_CHUNK_MAX_CHARS = 2800;
|
|
20
|
+
/**
|
|
21
|
+
* 生成汇总 diff 卡片组:
|
|
22
|
+
* - 首卡标题含文件数与 +X/-Y 统计
|
|
23
|
+
* - diff 正文按 ~2800 字分块,每块包在 ```diff 围栏里(飞书 markdown 渲染红绿着色)
|
|
24
|
+
* - diff 为空(无改动)返回 [],调用方跳过发送
|
|
25
|
+
*/
|
|
26
|
+
export function buildDiffSummaryCards(diffText, meta) {
|
|
27
|
+
const src = diffText.trim();
|
|
28
|
+
if (!src)
|
|
29
|
+
return [];
|
|
30
|
+
const { additions, deletions } = diffStats(src);
|
|
31
|
+
const title = `**📊 改动汇总** 工作区: \`${meta.workspaceName}\`\n\n${meta.files} 个文件 **+${additions} / -${deletions}** 行\n`;
|
|
32
|
+
const chunks = chunkText(src, DIFF_CHUNK_MAX_CHARS);
|
|
33
|
+
return chunks.map((chunk, i) => {
|
|
34
|
+
const counter = chunks.length > 1 ? `(${i + 1}/${chunks.length})` : '';
|
|
35
|
+
const content = i === 0 ? `${title}\`\`\`diff\n${chunk}\n\`\`\`` : `**📊 改动汇总${counter}**\n\n\`\`\`diff\n${chunk}\n\`\`\``;
|
|
36
|
+
return { schema: '2.0', config: { update_multi: true }, body: { elements: [{ tag: 'markdown', content }] } };
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=diff-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-card.js","sourceRoot":"","sources":["../../src/gateway/diff-card.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,4CAA4C;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAIlD,qDAAqD;AACrD,MAAM,UAAU,SAAS,CAAC,QAAgB;IACxC,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;YAAE,SAAS;QAC/D,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS,EAAE,CAAC;aACjC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS,EAAE,CAAC;IAC7C,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AAClC,CAAC;AAED,6CAA6C;AAC7C,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAElC;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAgB,EAAE,IAAqB;IAC3E,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,sBAAsB,IAAI,CAAC,aAAa,SAAS,IAAI,CAAC,KAAK,WAAW,SAAS,OAAO,SAAS,QAAQ,CAAC;IACtH,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC;IACpD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAC7B,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,eAAe,KAAK,UAAU,CAAC,CAAC,CAAC,YAAY,OAAO,qBAAqB,KAAK,UAAU,CAAC;QAC3H,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;IAC/G,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -70,7 +70,10 @@ export function parseIncomingMessage(event, botOpenId, opts = {}) {
|
|
|
70
70
|
return null;
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
-
const VALID_DECISIONS = new Set([
|
|
73
|
+
const VALID_DECISIONS = new Set([
|
|
74
|
+
'allow', 'deny', 'allow-session',
|
|
75
|
+
'plan-approve', 'plan-revise', 'plan-reject',
|
|
76
|
+
]);
|
|
74
77
|
/** 解析 card.action.trigger 回调;不完整或 decision 不在合法枚举内返回 null */
|
|
75
78
|
function parseCardAction(data) {
|
|
76
79
|
try {
|
|
@@ -81,8 +84,12 @@ function parseCardAction(data) {
|
|
|
81
84
|
// decision 必须严格匹配枚举:畸形字符串(如 'ALLOW')不能流入 CardActionValue.decision
|
|
82
85
|
if (!value?.requestId || typeof value.decision !== 'string' || !VALID_DECISIONS.has(value.decision) || !d.operator?.open_id)
|
|
83
86
|
return null;
|
|
87
|
+
// 修改意见:按钮自带 value.feedback 优先,其次卡片输入框 form_value.feedback
|
|
88
|
+
const fromValue = typeof value.feedback === 'string' && value.feedback ? value.feedback : undefined;
|
|
89
|
+
const fromForm = typeof d.action?.form_value?.feedback === 'string' ? d.action.form_value.feedback : undefined;
|
|
90
|
+
const feedback = fromValue ?? fromForm;
|
|
84
91
|
return {
|
|
85
|
-
value: { requestId: value.requestId, decision: value.decision },
|
|
92
|
+
value: { requestId: value.requestId, decision: value.decision, ...(feedback ? { feedback } : {}) },
|
|
86
93
|
operatorId: d.operator.open_id,
|
|
87
94
|
openMessageId: d.context?.open_message_id ?? d.open_message_id ?? '',
|
|
88
95
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feishu-gateway.js","sourceRoot":"","sources":["../../src/gateway/feishu-gateway.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"feishu-gateway.js","sourceRoot":"","sources":["../../src/gateway/feishu-gateway.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// 装配主流程:消息 → 访问控制 → 命令 → 通道队列 → 执行 → 确认卡片 → 回传
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
3
|
import { execFile } from 'node:child_process';
|
|
4
|
-
import {
|
|
4
|
+
import { existsSync } from 'node:fs';
|
|
5
|
+
import { homedir, tmpdir } from 'node:os';
|
|
5
6
|
import { join, basename, resolve } from 'node:path';
|
|
6
7
|
import { promisify } from 'node:util';
|
|
7
8
|
import { CONFIG_DIR, CONFIG_PATH, loadConfig, sameApps } from './config.js';
|
|
@@ -9,19 +10,26 @@ import { warnIfNoClaudeAuth } from './auth-precheck.js';
|
|
|
9
10
|
import { AccessControl } from './access/access-control.js';
|
|
10
11
|
import { FeishuGateway } from './gateway/feishu-gateway.js';
|
|
11
12
|
import { ProgressCard } from './gateway/progress-card.js';
|
|
12
|
-
import { buildConfirmCard, buildConfirmResultCard, DECISION_TEXT } from './gateway/card-builder.js';
|
|
13
|
+
import { buildConfirmCard, buildConfirmResultCard, DECISION_TEXT, buildPlanCards, buildPlanResultCard, buildExpiredPlanCard, } from './gateway/card-builder.js';
|
|
14
|
+
import { buildDiffSummaryCards } from './gateway/diff-card.js';
|
|
13
15
|
import { runTask } from './executor/claude-executor.js';
|
|
14
16
|
import { PermissionGate } from './executor/permission-gate.js';
|
|
17
|
+
import { discoverPlugins, resolvePluginPaths } from './executor/plugin-discovery.js';
|
|
15
18
|
import { createGatewaySender, createNotifyServer, NOTIFY_SERVER_NAME } from './executor/notify-server.js';
|
|
19
|
+
import { collectWorkspaceDiff } from './util/workspace-diff.js';
|
|
16
20
|
import { SessionStore, migrateLegacySessions } from './session/session-store.js';
|
|
17
21
|
import { handleCommand } from './session/commands.js';
|
|
18
22
|
import { rewriteByTrigger } from './session/triggers.js';
|
|
19
23
|
import { Semaphore, channelKey } from './session/channel.js';
|
|
20
24
|
import { TranscriptWriter, sweepTranscripts } from './transcript/transcript-writer.js';
|
|
25
|
+
import { nowBeijingISO } from './util/beijing-time.js';
|
|
21
26
|
// 版本号收敛到 version.ts 单一来源(bin/lcb.ts 与 smoke 测试均引用)
|
|
22
27
|
export { VERSION } from './version.js';
|
|
23
28
|
const execFileP = promisify(execFile);
|
|
24
29
|
const MAX_FILES_BEFORE_ZIP = 10;
|
|
30
|
+
// 全部机器人共享本机 ~/.claude(模型设置/登录态/user MCP/skills/插件;会话池仍 per-app 隔离)。
|
|
31
|
+
// 显式注入 CLAUDE_CONFIG_DIR 而非依赖 CLI 缺省,防外部环境变量把数据目录带偏
|
|
32
|
+
const SHARED_CLAUDE_DIR = join(homedir(), '.claude');
|
|
25
33
|
// 任务总超时 4 小时(防挂死;确认等待、长编译均在正常范围)
|
|
26
34
|
const TASK_HARD_TIMEOUT_MS = 4 * 60 * 60 * 1000;
|
|
27
35
|
// 确认等待窗:无人确认则自动拒绝。超时判定由 wiring 侧自管(ask 闭包内的定时器),
|
|
@@ -43,26 +51,37 @@ function expiredConfirmCard(req, timeoutMs) {
|
|
|
43
51
|
},
|
|
44
52
|
};
|
|
45
53
|
}
|
|
54
|
+
/** plan 卡片按钮文案(toast 用) */
|
|
55
|
+
const PLAN_DECISION_TEXT = {
|
|
56
|
+
'plan-approve': '✅ 计划已批准,开始执行',
|
|
57
|
+
'plan-revise': '📝 修改意见已提交',
|
|
58
|
+
'plan-reject': '❌ 计划已放弃',
|
|
59
|
+
};
|
|
46
60
|
export function createBridge(config, app, // 本 bridge 绑定的飞书应用:并发/默认工作区/Claude Code 环境/人格均 per-app
|
|
47
61
|
deps, opts = {}) {
|
|
48
62
|
const sem = new Semaphore(app.concurrency ?? config.concurrency);
|
|
49
63
|
const tag = `[app:${app.name}]`;
|
|
50
|
-
//
|
|
51
|
-
|
|
64
|
+
// Claude Code 子进程环境:CLAUDE_CONFIG_DIR 固定指向共享的 ~/.claude(settingSources 含 user,
|
|
65
|
+
// 模型设置/登录态/user MCP/skills 自动继承),app.env 追加 settings.json 里没有的键;
|
|
52
66
|
// process.env 先展开保证其余变量(ANTHROPIC_* 凭证、代理等)原样透传
|
|
53
67
|
const appEnv = {
|
|
54
68
|
...process.env,
|
|
55
|
-
CLAUDE_CONFIG_DIR:
|
|
69
|
+
CLAUDE_CONFIG_DIR: SHARED_CLAUDE_DIR,
|
|
56
70
|
...app.env,
|
|
57
71
|
};
|
|
58
|
-
// 启动预检:认证来源全落空(env 无 token
|
|
72
|
+
// 启动预检:认证来源全落空(env 无 token、~/.claude 无登录态)时提前 warn,
|
|
59
73
|
// 免得用户配好机器人才发现每条消息都报 Not logged in(真判定仍在 CLI 侧)
|
|
60
|
-
warnIfNoClaudeAuth(app.name, appEnv,
|
|
74
|
+
warnIfNoClaudeAuth(app.name, appEnv, SHARED_CLAUDE_DIR);
|
|
75
|
+
// 会话清单缓存(SDK init 消息):按工作区键存——project 级 .mcp.json/skills 随工作区不同,
|
|
76
|
+
// 任一通道跑过一次该工作区即可供 /skills /plugins /mcp /model 渲染。进程内存,重启后清空
|
|
77
|
+
const inventories = new Map();
|
|
61
78
|
const runtimes = new Map();
|
|
62
79
|
// 通道级权限闸:「本次会话不再询问」的记忆跨任务生效(spec:直至 /new),
|
|
63
80
|
// 故 gate 归通道持有而非每任务新建——每任务新建会把授权缩成任务级,任务 B 又要重新确认
|
|
64
81
|
const gates = new Map();
|
|
65
82
|
const confirmPending = new Map();
|
|
83
|
+
// plan 确认挂起项:requestId → 等待中的计划决策(plan-approve/revise/reject)
|
|
84
|
+
const planPending = new Map();
|
|
66
85
|
function workspacePath(name) {
|
|
67
86
|
return config.workspaces.find((w) => w.name === name)?.path ?? config.workspaces[0].path;
|
|
68
87
|
}
|
|
@@ -117,6 +136,7 @@ deps, opts = {}) {
|
|
|
117
136
|
appName: app.name,
|
|
118
137
|
isAdmin: deps.access.isAdmin(msg.userId),
|
|
119
138
|
currentWorkspace: () => currentWorkspace,
|
|
139
|
+
getInventory: () => inventories.get(currentWorkspace),
|
|
120
140
|
stopCurrentTask: () => {
|
|
121
141
|
const rt = runtimes.get(key);
|
|
122
142
|
if (rt?.abort) {
|
|
@@ -148,10 +168,15 @@ deps, opts = {}) {
|
|
|
148
168
|
updateCard: (id, c) => deps.gateway.updateCard(id, c),
|
|
149
169
|
}, `任务 · ${wsName}`);
|
|
150
170
|
const confirmTimeoutMs = opts.confirmTimeoutMs ?? CONFIRM_TIMEOUT_MS;
|
|
151
|
-
// 通道级复用:已存在则沿用(allow-session
|
|
171
|
+
// 通道级复用:已存在则沿用(allow-session 记忆跨任务),不存在才建。
|
|
172
|
+
// 白名单每任务现读 config.permissions(热重载改配置下一条消息即生效——但 gate 是
|
|
173
|
+
// 通道级复用实例,decide 时才查 allowTools,故以构造时引用为准;改 permissions 后
|
|
174
|
+
// 新通道或重启即全量生效,README 注明)
|
|
152
175
|
let gate = gates.get(key);
|
|
153
176
|
if (!gate) {
|
|
154
177
|
gate = new PermissionGate({
|
|
178
|
+
allowTools: config.permissions?.allowTools ? new Set(config.permissions.allowTools) : undefined,
|
|
179
|
+
dangerousCommands: config.permissions?.dangerousCommands,
|
|
155
180
|
ask: async (req) => {
|
|
156
181
|
// 发确认卡片并挂起,等待 onCardAction 按 requestId 唤醒;
|
|
157
182
|
// 超时由本闭包自管:到点删除条目 + 卡片置为过期态 + 以 deny 继续——
|
|
@@ -176,6 +201,32 @@ deps, opts = {}) {
|
|
|
176
201
|
});
|
|
177
202
|
});
|
|
178
203
|
},
|
|
204
|
+
// plan 确认:发计划卡片组(首卡带按钮+输入框)挂起等待;超时自动放弃。
|
|
205
|
+
// chatId/userId 绑定构造时任务——通道 key = chatId+userId,同通道内固定,闭包安全
|
|
206
|
+
planAsk: async (req) => {
|
|
207
|
+
const planReq = { requestId: randomUUID(), plan: req.plan, workspaceName: req.workspaceName };
|
|
208
|
+
const ids = [];
|
|
209
|
+
for (const c of buildPlanCards(planReq))
|
|
210
|
+
ids.push(await deps.gateway.sendCardTo(msg.chatId, c));
|
|
211
|
+
const cardId = ids[0];
|
|
212
|
+
return new Promise((resolve) => {
|
|
213
|
+
const gc = setTimeout(() => {
|
|
214
|
+
planPending.delete(planReq.requestId);
|
|
215
|
+
void deps.gateway.updateCard(cardId, buildExpiredPlanCard(planReq, confirmTimeoutMs)).catch(() => { });
|
|
216
|
+
resolve({ action: 'reject' });
|
|
217
|
+
}, confirmTimeoutMs);
|
|
218
|
+
gc.unref();
|
|
219
|
+
planPending.set(planReq.requestId, {
|
|
220
|
+
resolve: (r) => {
|
|
221
|
+
clearTimeout(gc);
|
|
222
|
+
resolve(r);
|
|
223
|
+
},
|
|
224
|
+
req: planReq,
|
|
225
|
+
ownerId: msg.userId,
|
|
226
|
+
cardId,
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
},
|
|
179
230
|
timeoutMs: GATE_FALLBACK_TIMEOUT_MS,
|
|
180
231
|
});
|
|
181
232
|
gates.set(key, gate);
|
|
@@ -196,7 +247,7 @@ deps, opts = {}) {
|
|
|
196
247
|
await progress.start();
|
|
197
248
|
const state = deps.store.getChannelState(key);
|
|
198
249
|
const resumeId = state?.sessions?.[0]?.sessionId;
|
|
199
|
-
const now = () =>
|
|
250
|
+
const now = () => nowBeijingISO();
|
|
200
251
|
// 落盘 · user:任务起点(prompt 全文 + resume 链上一轮 sessionId)
|
|
201
252
|
deps.transcript?.user({
|
|
202
253
|
v: 1, ts: now(), kind: 'user', app: app.appId,
|
|
@@ -208,13 +259,25 @@ deps, opts = {}) {
|
|
|
208
259
|
signal: abort.signal,
|
|
209
260
|
env: appEnv,
|
|
210
261
|
appendSystemPrompt: app.appendSystemPrompt,
|
|
262
|
+
// code-dev 工作区统一 plan mode:模型先出计划(ExitPlanMode → planAsk 飞书卡片),
|
|
263
|
+
// 用户批准后 SDK 自动切回可编辑模式继续执行
|
|
264
|
+
...(config.workspaces.find((w) => w.name === wsName)?.type === 'code-dev' ? { permissionMode: 'plan' } : {}),
|
|
265
|
+
// 通道级模型覆盖(/model 设置,每任务现读——改完下一条消息即生效);未设 = 跟随 ~/.claude 全局
|
|
266
|
+
...(state?.model ? { model: state.model } : {}),
|
|
211
267
|
// 进程内通知工具(send_text/send_image/send_file):中间产物实时推给当前聊天。
|
|
212
268
|
// server 实例按任务构造,chatId 在 sender 闭包内硬绑定——模型无法选择接收者
|
|
213
269
|
mcpServers: { [NOTIFY_SERVER_NAME]: createNotifyServer(notifySender) },
|
|
214
|
-
//
|
|
215
|
-
|
|
270
|
+
// 插件:config.yaml 显式配置(开发期指源码目录)+ ~/.claude 已启用 marketplace 插件自动发现,
|
|
271
|
+
// 同名显式优先;SDK 对无效路径静默跳过,实际加载以 init 清单(/plugins 命令)为准
|
|
272
|
+
...(() => {
|
|
273
|
+
const merged = resolvePluginPaths(app.plugins, discoverPlugins(SHARED_CLAUDE_DIR));
|
|
274
|
+
return merged.length ? { plugins: merged.map((p) => ({ path: p.path })) } : {};
|
|
275
|
+
})(),
|
|
216
276
|
canUseTool: (toolName, input) => gate.decide(toolName, input, wsName),
|
|
217
277
|
}, {
|
|
278
|
+
onInit: (inv) => {
|
|
279
|
+
inventories.set(wsName, { ...inv, workspace: wsName, loadedAt: new Date().toISOString() });
|
|
280
|
+
},
|
|
218
281
|
onProgress: (e) => {
|
|
219
282
|
if (e.kind === 'text') {
|
|
220
283
|
progress.appendText(e.content);
|
|
@@ -267,34 +330,59 @@ deps, opts = {}) {
|
|
|
267
330
|
// 结果回传(超长截断,防飞书消息体超限)
|
|
268
331
|
if (outcome.finalText)
|
|
269
332
|
await deps.gateway.sendTextTo(msg.chatId, outcome.finalText.slice(0, 4000));
|
|
270
|
-
//
|
|
333
|
+
// 旧产出回传路径(generic 工作区 / code-dev 非 git 仓库回退):
|
|
334
|
+
// >10 个打 zip(Windows 10+ / macOS / Linux 均自带 tar),失败退化为逐个上传;
|
|
271
335
|
// 中途经 lcb-notify 已推送过的文件跳过(用户已收到,防重复轰炸)
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
336
|
+
const uploadProducedFiles = async () => {
|
|
337
|
+
const files = outcome.producedFiles.filter((f) => !sentPaths.has(resolve(f)));
|
|
338
|
+
if (files.length > MAX_FILES_BEFORE_ZIP) {
|
|
339
|
+
const zipPath = join(tmpdir(), `lcb-${randomUUID()}.zip`);
|
|
340
|
+
try {
|
|
341
|
+
await execFileP('tar', ['-a', '-cf', zipPath, ...files.map((f) => basename(f))], { cwd: workspacePath(wsName) });
|
|
342
|
+
await deps.gateway.uploadAndSendFile(msg.chatId, zipPath);
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
for (const f of files)
|
|
346
|
+
await deps.gateway.uploadAndSendFile(msg.chatId, f);
|
|
347
|
+
}
|
|
278
348
|
}
|
|
279
|
-
|
|
349
|
+
else {
|
|
280
350
|
for (const f of files)
|
|
281
351
|
await deps.gateway.uploadAndSendFile(msg.chatId, f);
|
|
282
352
|
}
|
|
353
|
+
};
|
|
354
|
+
// 产出回传:code-dev 工作区发汇总 diff 卡片(只发「改了什么」,不再整文件轰炸);
|
|
355
|
+
// generic 工作区保留旧的文件上传行为
|
|
356
|
+
const isCodeDev = config.workspaces.find((w) => w.name === wsName)?.type === 'code-dev';
|
|
357
|
+
if (isCodeDev) {
|
|
358
|
+
const wsDiff = await collectWorkspaceDiff(workspacePath(wsName));
|
|
359
|
+
if (wsDiff === null) {
|
|
360
|
+
// 非 git 仓库无法生成 diff:回退上传 + 提示 git init 可切换为 diff 模式
|
|
361
|
+
console.warn(tag, `[任务收尾] 工作区 ${wsName} 不是 git 仓库,回退为文件上传(git init 后可改用汇总 diff 卡片)`);
|
|
362
|
+
await uploadProducedFiles();
|
|
363
|
+
}
|
|
364
|
+
else if (wsDiff.diff.trim()) {
|
|
365
|
+
for (const c of buildDiffSummaryCards(wsDiff.diff, { workspaceName: wsName, files: wsDiff.files })) {
|
|
366
|
+
await deps.gateway.sendCardTo(msg.chatId, c);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
283
369
|
}
|
|
284
370
|
else {
|
|
285
|
-
|
|
286
|
-
await deps.gateway.uploadAndSendFile(msg.chatId, f);
|
|
371
|
+
await uploadProducedFiles();
|
|
287
372
|
}
|
|
288
373
|
}
|
|
289
374
|
catch (e) {
|
|
290
|
-
//
|
|
291
|
-
//
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
375
|
+
// 常见错误附配置指引:Not logged in 多因 ~/.claude 无登录态(本机跑一次 claude login 即可);
|
|
376
|
+
// No conversation found 多因旧版独立目录里的会话(本版起统一 ~/.claude,旧会话无法跨目录 resume)
|
|
377
|
+
const errText = String(e);
|
|
378
|
+
const hint = errText.includes('Not logged in')
|
|
379
|
+
? '\n\n💡 没有可用的 Claude Code 认证:在本机终端跑一次 claude login 登录(登录态存于 ~/.claude,所有机器人共享);或在本机 ~/.claude/settings.json 的 env 配 ANTHROPIC_AUTH_TOKEN(第三方端点另配 ANTHROPIC_BASE_URL),改完重启 bridge。'
|
|
380
|
+
: /No conversation found|session not found/i.test(errText)
|
|
381
|
+
? '\n\n💡 该会话可能已失效(或属于旧版独立配置目录):发 /new 开启新会话即可。'
|
|
382
|
+
: '';
|
|
383
|
+
await progress.finish(`❌ 出错:${errText.slice(0, 300)}${hint}`);
|
|
296
384
|
deps.transcript?.result({
|
|
297
|
-
v: 1, ts:
|
|
385
|
+
v: 1, ts: nowBeijingISO(), kind: 'result', app: app.appId,
|
|
298
386
|
chatId: msg.chatId, userId: msg.userId, sessionId: '',
|
|
299
387
|
subtype: 'error', text: String(e).slice(0, 300),
|
|
300
388
|
});
|
|
@@ -313,6 +401,34 @@ deps, opts = {}) {
|
|
|
313
401
|
*/
|
|
314
402
|
async function handleCardAction(action) {
|
|
315
403
|
try {
|
|
404
|
+
// plan 确认回调分流(requestId 唯一,planPending 与 confirmPending 不会同时命中)
|
|
405
|
+
const plan = planPending.get(action.value.requestId);
|
|
406
|
+
if (plan) {
|
|
407
|
+
if (action.operatorId !== plan.ownerId) {
|
|
408
|
+
console.log(tag, `[卡片回调] 非发起人 ${action.operatorId} 点击计划卡 ${action.value.requestId},已忽略`);
|
|
409
|
+
return { toast: { type: 'info', content: '仅任务发起人可操作计划' } };
|
|
410
|
+
}
|
|
411
|
+
const decision = action.value.decision;
|
|
412
|
+
if (decision !== 'plan-approve' && decision !== 'plan-revise' && decision !== 'plan-reject') {
|
|
413
|
+
return { toast: { type: 'info', content: '该计划确认已被处理或已过期' } };
|
|
414
|
+
}
|
|
415
|
+
// revise 意见为空:不消耗本次决策(条目保留,卡片按钮仍可用),提示先填意见
|
|
416
|
+
const feedback = (action.value.feedback ?? '').trim();
|
|
417
|
+
if (decision === 'plan-revise' && !feedback) {
|
|
418
|
+
return { toast: { type: 'warning', content: '请先在输入框填写修改意见(或点「放弃计划」)' } };
|
|
419
|
+
}
|
|
420
|
+
planPending.delete(action.value.requestId);
|
|
421
|
+
plan.resolve(decision === 'plan-approve' ? { action: 'approve' }
|
|
422
|
+
: decision === 'plan-revise' ? { action: 'revise', feedback }
|
|
423
|
+
: { action: 'reject' });
|
|
424
|
+
const resultCard = buildPlanResultCard(plan.req, decision, '任务发起人', feedback);
|
|
425
|
+
void deps.gateway.updateCard(plan.cardId, resultCard)
|
|
426
|
+
.catch((e) => console.error('[计划卡兜底更新失败]', action.value.requestId, e));
|
|
427
|
+
return {
|
|
428
|
+
toast: { type: 'success', content: PLAN_DECISION_TEXT[decision] },
|
|
429
|
+
card: { type: 'raw', data: resultCard },
|
|
430
|
+
};
|
|
431
|
+
}
|
|
316
432
|
const pending = confirmPending.get(action.value.requestId);
|
|
317
433
|
if (!pending) {
|
|
318
434
|
// 已处理/超时清理/桥接器重启后的孤儿卡:toast 提示后忽略,不重复决策
|
|
@@ -324,22 +440,26 @@ deps, opts = {}) {
|
|
|
324
440
|
console.log(tag, `[卡片回调] 非发起人 ${action.operatorId} 点击确认卡 ${action.value.requestId},已忽略`);
|
|
325
441
|
return { toast: { type: 'info', content: '仅任务发起人可确认' } };
|
|
326
442
|
}
|
|
443
|
+
const decision = action.value.decision;
|
|
444
|
+
if (decision !== 'allow' && decision !== 'deny' && decision !== 'allow-session') {
|
|
445
|
+
return { toast: { type: 'info', content: '该确认已被处理或已过期,无需重复操作' } };
|
|
446
|
+
}
|
|
327
447
|
confirmPending.delete(action.value.requestId);
|
|
328
|
-
pending.resolve(
|
|
329
|
-
const resultCard = buildConfirmResultCard(pending.req,
|
|
448
|
+
pending.resolve(decision);
|
|
449
|
+
const resultCard = buildConfirmResultCard(pending.req, decision, '任务发起人');
|
|
330
450
|
// 兜底 PATCH 不再 await:回调须在 3 秒内响应(协议 200341),且响应体已内联结果卡同步换卡,
|
|
331
451
|
// PATCH 仅在 WS 回传响应丢失时保证最终一致(同时消掉 await PATCH 慢网络下拖垮响应窗口的隐患)
|
|
332
452
|
void deps.gateway.updateCard(pending.cardId, resultCard)
|
|
333
453
|
.catch((e) => console.error('[卡片兜底更新失败]', action.value.requestId, e));
|
|
334
454
|
return {
|
|
335
|
-
toast: { type: 'success', content: DECISION_TEXT[
|
|
455
|
+
toast: { type: 'success', content: DECISION_TEXT[decision] },
|
|
336
456
|
card: { type: 'raw', data: resultCard },
|
|
337
457
|
};
|
|
338
458
|
}
|
|
339
459
|
catch (e) {
|
|
340
460
|
console.error(tag, '[卡片回调异常]', action.value.requestId, e);
|
|
341
461
|
// resolve 之后的代码理论不可抛;若未来插入可抛代码,按条目是否仍在区分决策是否已生效
|
|
342
|
-
const retryable = confirmPending.has(action.value.requestId);
|
|
462
|
+
const retryable = confirmPending.has(action.value.requestId) || planPending.has(action.value.requestId);
|
|
343
463
|
return { toast: { type: 'error', content: retryable ? '处理失败,请重试' : '处理出现异常,决策可能已生效,请勿盲目重试' } };
|
|
344
464
|
}
|
|
345
465
|
}
|
|
@@ -369,6 +489,8 @@ export function createConfigReloader(config, configPath) {
|
|
|
369
489
|
}
|
|
370
490
|
config.workspaces = fresh.workspaces;
|
|
371
491
|
config.defaults = fresh.defaults;
|
|
492
|
+
// 权限白名单热应用:gate 每任务现读 config.permissions(通道级 gate 虽复用,白名单在 decide 时取用)
|
|
493
|
+
config.permissions = fresh.permissions;
|
|
372
494
|
// app 数量变化属需重启的变更(上面 sameApps 长度比较已警告),仅等长时逐位 mutate
|
|
373
495
|
if (fresh.apps.length === config.apps.length) {
|
|
374
496
|
fresh.apps.forEach((fa, i) => {
|
|
@@ -391,6 +513,15 @@ export async function startBridge(configPath = CONFIG_PATH) {
|
|
|
391
513
|
}
|
|
392
514
|
// reloader 共享:所有 bridge 持有同一 config 对象引用,mutate 一处全员可见
|
|
393
515
|
const reloadConfig = createConfigReloader(config, configPath);
|
|
516
|
+
// 旧版(≤0.3.x)缺省独立目录的一次性迁移提示:目录还在则其中历史会话不再可 /resume
|
|
517
|
+
//(本版起所有机器人统一 ~/.claude,会话无法跨数据目录 resume)。不做自动迁移(双目录合并无安全做法)
|
|
518
|
+
for (const app of config.apps) {
|
|
519
|
+
const legacyDir = join(CONFIG_DIR, 'claude', app.appId);
|
|
520
|
+
if (existsSync(legacyDir)) {
|
|
521
|
+
console.warn(`[app:${app.name}] 检测到旧版独立数据目录 ${legacyDir}:本版起统一使用 ~/.claude,`
|
|
522
|
+
+ `该目录中的历史会话不再出现在 /resume(本机配置/登录态/插件已自动继承)。目录保留未动,确认无用后可手动删除`);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
394
525
|
// 每 app 一对 gateway+bridge:长连接/会话池/并发闸/Claude Code 环境/落盘目录全部 per-app 隔离
|
|
395
526
|
const runners = config.apps.map((app) => {
|
|
396
527
|
const tag = `[app:${app.name}]`;
|