@jesonliu/lark-claudecode-bridge 0.10.0 → 0.13.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 +84 -46
- package/assets/web/index.html +1416 -0
- package/config.example.yaml +22 -2
- package/dist/auth-precheck.d.ts +5 -2
- package/dist/auth-precheck.js +8 -2
- package/dist/auth-precheck.js.map +1 -1
- package/dist/bin/lcb.js +34 -3
- package/dist/bin/lcb.js.map +1 -1
- package/dist/claude-config.d.ts +19 -0
- package/dist/claude-config.js +76 -0
- package/dist/claude-config.js.map +1 -0
- package/dist/cli/setup-wizard.d.ts +1 -0
- package/dist/cli/setup-wizard.js +4 -0
- package/dist/cli/setup-wizard.js.map +1 -1
- package/dist/config-defaults.d.ts +4 -0
- package/dist/config-defaults.js +15 -0
- package/dist/config-defaults.js.map +1 -0
- package/dist/config.d.ts +7 -0
- package/dist/config.js +190 -6
- package/dist/config.js.map +1 -1
- package/dist/executor/permission-gate.d.ts +8 -1
- package/dist/executor/permission-gate.js +21 -14
- package/dist/executor/permission-gate.js.map +1 -1
- package/dist/executor/plugin-discovery.d.ts +11 -0
- package/dist/executor/plugin-discovery.js +28 -0
- package/dist/executor/plugin-discovery.js.map +1 -1
- package/dist/executor/plugin-manager.d.ts +19 -0
- package/dist/executor/plugin-manager.js +84 -0
- package/dist/executor/plugin-manager.js.map +1 -0
- package/dist/feishu/slash-commands.d.ts +77 -0
- package/dist/feishu/slash-commands.js +188 -0
- package/dist/feishu/slash-commands.js.map +1 -0
- package/dist/gateway/card-builder.d.ts +2 -0
- package/dist/gateway/card-builder.js +3 -1
- package/dist/gateway/card-builder.js.map +1 -1
- package/dist/gateway/feishu-gateway.d.ts +37 -2
- package/dist/gateway/feishu-gateway.js +153 -8
- package/dist/gateway/feishu-gateway.js.map +1 -1
- package/dist/index.js +87 -20
- package/dist/index.js.map +1 -1
- package/dist/session/commands.d.ts +16 -1
- package/dist/session/commands.js +33 -1
- package/dist/session/commands.js.map +1 -1
- package/dist/session/plugin-command.d.ts +14 -0
- package/dist/session/plugin-command.js +110 -0
- package/dist/session/plugin-command.js.map +1 -0
- package/dist/types.d.ts +69 -0
- package/dist/util/open-browser.d.ts +1 -0
- package/dist/util/open-browser.js +20 -0
- package/dist/util/open-browser.js.map +1 -0
- package/dist/util/server-url.d.ts +3 -0
- package/dist/util/server-url.js +10 -0
- package/dist/util/server-url.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +6 -2
- package/dist/version.js.map +1 -1
- package/dist/web/config-api.d.ts +50 -0
- package/dist/web/config-api.js +184 -0
- package/dist/web/config-api.js.map +1 -0
- package/dist/web/lifecycle.d.ts +52 -0
- package/dist/web/lifecycle.js +167 -0
- package/dist/web/lifecycle.js.map +1 -0
- package/dist/web/model-list.d.ts +36 -0
- package/dist/web/model-list.js +101 -0
- package/dist/web/model-list.js.map +1 -0
- package/dist/web/server.d.ts +22 -0
- package/dist/web/server.js +543 -0
- package/dist/web/server.js.map +1 -0
- package/dist/web/update.d.ts +26 -0
- package/dist/web/update.js +64 -0
- package/dist/web/update.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// /plugin 飞书端插件管理命令:spawn SDK bundled CLI(plugin-manager)执行安装/启停/市场操作。
|
|
2
|
+
// 权限分级:list 对所有成员开放;变更类(install/uninstall/enable/disable/marketplace)仅 admin。
|
|
3
|
+
// 长操作(安装含 git clone)立即 ack、完成后经 deps.send 异步推送结果——不阻塞 gateway 事件链。
|
|
4
|
+
// managed 模式双目录:list 合并自管目录 + 本机 ~/.claude;变更操作按插件所在目录定向执行,
|
|
5
|
+
// install 默认装 ~/.claude(与本机 claude CLI 共用一份),--dir=managed 装 bridge 自管目录
|
|
6
|
+
import { runPluginCli } from '../executor/plugin-manager.js';
|
|
7
|
+
import { invalidatePluginCache, listInstalledPlugins } from '../executor/plugin-discovery.js';
|
|
8
|
+
const USAGE = [
|
|
9
|
+
'**插件管理**(仅管理员可变更)',
|
|
10
|
+
'/plugin list — 已安装插件清单(managed 模式含本机 ~/.claude)',
|
|
11
|
+
'/plugin install <name[@marketplace]> [--dir=managed] — 安装插件(默认装本机 ~/.claude)',
|
|
12
|
+
'/plugin uninstall <name> — 卸载插件',
|
|
13
|
+
'/plugin enable|disable <name> — 启用/停用插件',
|
|
14
|
+
'/plugin marketplace add <git地址|路径> — 添加插件市场',
|
|
15
|
+
'/plugin marketplace list — 查看插件市场',
|
|
16
|
+
'/plugin marketplace update [name] — 更新插件市场',
|
|
17
|
+
'/plugin marketplace remove <name> — 移除插件市场',
|
|
18
|
+
'',
|
|
19
|
+
'💡 插件装好后下一条消息自动加载(无须重启,两处目录的插件都会加载);/plugins 查看当前会话实际加载的插件',
|
|
20
|
+
].join('\n');
|
|
21
|
+
/** 变更类子命令(admin only);list 与用法提示对全部成员开放 */
|
|
22
|
+
const ADMIN_SUBS = new Set(['install', 'uninstall', 'enable', 'disable', 'marketplace']);
|
|
23
|
+
/**
|
|
24
|
+
* 处理 /plugin 子命令,返回立即回复文本。install/uninstall/marketplace 为长操作:
|
|
25
|
+
* 先回 ack,后台执行完毕(成功/失败/超时)经 deps.send 推送结果。
|
|
26
|
+
*/
|
|
27
|
+
export async function handlePluginCommand(args, deps) {
|
|
28
|
+
const [sub, ...rest] = args;
|
|
29
|
+
if (!sub)
|
|
30
|
+
return USAGE;
|
|
31
|
+
if (sub === 'help')
|
|
32
|
+
return USAGE;
|
|
33
|
+
if (ADMIN_SUBS.has(sub) && !deps.isAdmin) {
|
|
34
|
+
return '⛔ 插件变更操作仅管理员可用(查看清单可用 /plugin list)';
|
|
35
|
+
}
|
|
36
|
+
const bridgeDir = deps.claudeConfigDir;
|
|
37
|
+
const userDir = deps.userClaudeDir && deps.userClaudeDir !== deps.claudeConfigDir
|
|
38
|
+
? deps.userClaudeDir
|
|
39
|
+
: deps.claudeConfigDir;
|
|
40
|
+
const dual = bridgeDir !== userDir; // managed 模式:变更类需按插件所在目录定向
|
|
41
|
+
const invalidateAll = () => { invalidatePluginCache(bridgeDir); if (dual)
|
|
42
|
+
invalidatePluginCache(userDir); };
|
|
43
|
+
// --dir=managed:install/marketplace 的目标目录选择(装自管目录;缺省装 ~/.claude)
|
|
44
|
+
const wantManagedDir = rest.some((s) => s === '--dir=managed' || s === '--dir=bridge');
|
|
45
|
+
const target = rest.filter((s) => s && !s.startsWith('-') && !s.startsWith('--dir='));
|
|
46
|
+
const installDir = wantManagedDir ? bridgeDir : userDir;
|
|
47
|
+
if (sub === 'list') {
|
|
48
|
+
const rows = pluginListRows(bridgeDir, dual ? userDir : null);
|
|
49
|
+
return rows
|
|
50
|
+
? `**已安装插件**${dual ? '([bridge]=托管目录 [user]=本机 ~/.claude)' : ''}\n\`\`\`\n${rows}\n\`\`\``
|
|
51
|
+
: '尚无已安装插件(/plugin install <name[@marketplace]> 安装)';
|
|
52
|
+
}
|
|
53
|
+
if (sub === 'marketplace' && target[0] === 'list') {
|
|
54
|
+
// 市场清单仍走 CLI(repo 缓存目录结构复杂,本地解析收益低);dual 时提示两处各自的市场
|
|
55
|
+
const r = await runPluginCli(['marketplace', 'list'], { claudeConfigDir: installDir });
|
|
56
|
+
if (!r.ok)
|
|
57
|
+
return `查询失败:${r.text}`;
|
|
58
|
+
const head = dual ? `(目标目录:${installDir === bridgeDir ? 'bridge 托管' : '本机 ~/.claude'},--dir=managed 可切换)\n` : '';
|
|
59
|
+
return `**插件市场**${head ? `\n${head}` : ''}\n\`\`\`\n${r.text}\n\`\`\``;
|
|
60
|
+
}
|
|
61
|
+
const requiresTarget = sub !== 'marketplace' || target[0] !== 'list';
|
|
62
|
+
const name = target.join(' ');
|
|
63
|
+
if (requiresTarget && !name)
|
|
64
|
+
return `参数缺失:/plugin ${args.join(' ')} <…>。\n\n${USAGE}`;
|
|
65
|
+
// 目标目录解析:enable/disable/uninstall 按插件实际所在目录执行(两处都有则都执行);
|
|
66
|
+
// install/marketplace 用 installDir(--dir=managed 或缺省 ~/.claude)
|
|
67
|
+
const cliArgs = [sub, ...target]; // target 已剔除 --dir* 标志;runPluginCli 自行补 plugin 前缀与 -y
|
|
68
|
+
const dirs = (sub === 'install' || sub === 'marketplace')
|
|
69
|
+
? [installDir]
|
|
70
|
+
: locatePluginDirs(name, bridgeDir, dual ? userDir : null);
|
|
71
|
+
const label = args.join(' ');
|
|
72
|
+
void (async () => {
|
|
73
|
+
const results = [];
|
|
74
|
+
for (const dir of dirs) {
|
|
75
|
+
const r = await runPluginCli(cliArgs, { claudeConfigDir: dir });
|
|
76
|
+
results.push(r.ok
|
|
77
|
+
? `✅ ${dual ? `[${dir === bridgeDir ? 'bridge' : 'user'}] ` : ''}完成:\`\`\`\n${r.text}\n\`\`\``
|
|
78
|
+
: `❌ ${dual ? `[${dir === bridgeDir ? 'bridge' : 'user'}] ` : ''}失败:${r.text}`);
|
|
79
|
+
}
|
|
80
|
+
invalidateAll();
|
|
81
|
+
await deps.send((results.length ? results.join('\n') : '❌ 未找到该插件(两处目录均无安装记录)')
|
|
82
|
+
+ '\n下一条消息起自动加载;/plugins 可查看实际加载清单');
|
|
83
|
+
})().catch((e) => deps.send(`❌ 插件操作异常(\`/plugin ${label}\`):${e instanceof Error ? e.message : String(e)}`));
|
|
84
|
+
return `⏳ 正在执行 \`/plugin ${label}\`(可能需要拉取仓库,稍候推送结果)`;
|
|
85
|
+
}
|
|
86
|
+
/** 合并渲染两处目录的已装插件清单;无任何插件返回 null。sourceTag 仅 dual 模式使用 */
|
|
87
|
+
function pluginListRows(bridgeDir, userDir) {
|
|
88
|
+
const fmt = (list) => list.map((p) => `${p.enabled ? '✅' : '⬜'} ${p.key}${p.version ? ` v${p.version}` : ''}${p.enabled ? '' : ' (未启用)'}`);
|
|
89
|
+
const bridgeList = listInstalledPlugins(bridgeDir);
|
|
90
|
+
if (!userDir) {
|
|
91
|
+
const rows = fmt(bridgeList);
|
|
92
|
+
return rows.length ? rows.join('\n') : null;
|
|
93
|
+
}
|
|
94
|
+
const rows = [
|
|
95
|
+
...bridgeList.map((p) => `[bridge] ${fmt([p])[0]}`),
|
|
96
|
+
...listInstalledPlugins(userDir).map((p) => `[user] ${fmt([p])[0]}`),
|
|
97
|
+
];
|
|
98
|
+
return rows.length ? rows.join('\n') : null;
|
|
99
|
+
}
|
|
100
|
+
/** 按插件名(name 或 name@marketplace)定位所在目录;两处都装了则返回两处(都执行) */
|
|
101
|
+
function locatePluginDirs(name, bridgeDir, userDir) {
|
|
102
|
+
const inDir = (dir) => listInstalledPlugins(dir).some((p) => p.key === name || p.name === name);
|
|
103
|
+
const dirs = [];
|
|
104
|
+
if (inDir(bridgeDir))
|
|
105
|
+
dirs.push(bridgeDir);
|
|
106
|
+
if (userDir && inDir(userDir))
|
|
107
|
+
dirs.push(userDir);
|
|
108
|
+
return dirs;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=plugin-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-command.js","sourceRoot":"","sources":["../../src/session/plugin-command.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -44,6 +44,58 @@ export interface PermissionsConfig {
|
|
|
44
44
|
allowTools?: string[];
|
|
45
45
|
dangerousCommands?: RegExp[];
|
|
46
46
|
}
|
|
47
|
+
/** Web 配置页服务器(lcb start / lcb ui 内嵌,node:http 零依赖):enabled/host/port 均为启动时读取,改动需重启 */
|
|
48
|
+
export interface ServerConfig {
|
|
49
|
+
enabled?: boolean;
|
|
50
|
+
host?: string;
|
|
51
|
+
port?: number;
|
|
52
|
+
}
|
|
53
|
+
export type ClaudeAuthMode = 'inherit' | 'managed';
|
|
54
|
+
/**
|
|
55
|
+
* 多厂商认证档案(Web 配置页「Claude 认证」管理,0.13 起)。档案仅是配置库:
|
|
56
|
+
* 当前生效配置始终是 ClaudeConfig 顶层四字段(写入 settings.json 的就是它),
|
|
57
|
+
* 「设为当前」= 把档案字段拷贝到顶层(互斥凭证同步清理),与 cc-switch 同款切换语义。
|
|
58
|
+
*/
|
|
59
|
+
export interface ClaudeProfile {
|
|
60
|
+
/** 档案名(显示用,如「官方」「中转站A」「GLM」) */
|
|
61
|
+
name: string;
|
|
62
|
+
/** 与 apiKey 二选一 */
|
|
63
|
+
authToken?: string;
|
|
64
|
+
/** 与 authToken 二选一 */
|
|
65
|
+
apiKey?: string;
|
|
66
|
+
baseUrl?: string;
|
|
67
|
+
model?: string;
|
|
68
|
+
/** 候选模型集(fable/opus/sonnet/haiku 等各存一条,页面点选即切换当前模型);model 仍为「设为当前」时的默认模型 */
|
|
69
|
+
models?: string[];
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Claude 认证与模型配置。inherit = 共享本机 ~/.claude(0.4 起默认行为,登录态/settings 全继承);
|
|
73
|
+
* managed = bridge 自管目录(~/.lark-claudecode-bridge/claude/),authToken/apiKey/baseUrl/model
|
|
74
|
+
* 写入该目录 settings.json 的 env 块——完全摆脱对本机 claude login 的依赖
|
|
75
|
+
*/
|
|
76
|
+
export interface ClaudeConfig {
|
|
77
|
+
mode?: ClaudeAuthMode;
|
|
78
|
+
/** ANTHROPIC_AUTH_TOKEN(Bearer,中转站常用);与 apiKey 二选一 */
|
|
79
|
+
authToken?: string;
|
|
80
|
+
/** ANTHROPIC_API_KEY(x-api-key);与 authToken 二选一 */
|
|
81
|
+
apiKey?: string;
|
|
82
|
+
/** ANTHROPIC_BASE_URL(第三方中转端点;官方 API 留空) */
|
|
83
|
+
baseUrl?: string;
|
|
84
|
+
/** 写 settings.json 顶层 model + env.ANTHROPIC_MODEL */
|
|
85
|
+
model?: string;
|
|
86
|
+
/** 多厂商档案库(不直接生效;Web 页「设为当前」拷贝到顶层) */
|
|
87
|
+
profiles?: ClaudeProfile[];
|
|
88
|
+
}
|
|
89
|
+
/** 飞书斜杠命令注册定义(同步到开放平台 app_slash_commands;command 不含 / 前缀) */
|
|
90
|
+
export interface SlashCommandDef {
|
|
91
|
+
command: string;
|
|
92
|
+
description: string;
|
|
93
|
+
icon?: string;
|
|
94
|
+
}
|
|
95
|
+
/** 斜杠命令同步配置:extra 为用户自定义透传命令(内置命令集见 commands.SLASH_COMMAND_META,始终参与同步) */
|
|
96
|
+
export interface SlashCommandsConfig {
|
|
97
|
+
extra?: SlashCommandDef[];
|
|
98
|
+
}
|
|
47
99
|
export interface BridgeConfig {
|
|
48
100
|
/** 多飞书应用(多机器人):每 app 一条独立 WS 长连接 + 独立会话池(sessions.<appId>.json)。
|
|
49
101
|
* 全部 app 共享本机 ~/.claude:模型设置/登录态/user MCP/skills/插件统一继承,仅会话池隔离 */
|
|
@@ -59,6 +111,12 @@ export interface BridgeConfig {
|
|
|
59
111
|
};
|
|
60
112
|
/** 权限白名单;缺省用 permission-gate 的内置默认(读工具 + Bash + 危险命令表) */
|
|
61
113
|
permissions?: PermissionsConfig;
|
|
114
|
+
/** Web 配置页服务器;缺省 enabled=true / 127.0.0.1:17317(随 lcb start 常驻) */
|
|
115
|
+
server?: ServerConfig;
|
|
116
|
+
/** Claude 认证模式;缺省 inherit(共享 ~/.claude) */
|
|
117
|
+
claude?: ClaudeConfig;
|
|
118
|
+
/** 飞书斜杠命令同步;缺省仅内置命令集 */
|
|
119
|
+
slashCommands?: SlashCommandsConfig;
|
|
62
120
|
}
|
|
63
121
|
export interface IncomingMessage {
|
|
64
122
|
chatId: string;
|
|
@@ -66,6 +124,17 @@ export interface IncomingMessage {
|
|
|
66
124
|
userId: string;
|
|
67
125
|
text: string;
|
|
68
126
|
messageId: string;
|
|
127
|
+
/** image 消息 / post 内嵌图片的 image_key(gateway 下载后把本地路径注记拼进 text,下游不再消费此字段) */
|
|
128
|
+
imageKeys?: string[];
|
|
129
|
+
}
|
|
130
|
+
/** parseIncomingMessage 对「明确发给机器人但不支持的消息类型」的拒绝信息(p2p 场景上层回提示;群聊保持静默 null) */
|
|
131
|
+
export interface RejectedMessage {
|
|
132
|
+
rejected: {
|
|
133
|
+
kind: 'unsupported-type';
|
|
134
|
+
chatId: string;
|
|
135
|
+
chatType: 'p2p' | 'group';
|
|
136
|
+
messageType: string;
|
|
137
|
+
};
|
|
69
138
|
}
|
|
70
139
|
/** 卡片回调决策:allow/deny/allow-session 为写工具确认卡;plan-* 为计划确认卡(feedback = 按意见修改时的用户输入) */
|
|
71
140
|
export type CardDecision = 'allow' | 'deny' | 'allow-session' | 'plan-approve' | 'plan-revise' | 'plan-reject';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function openBrowser(url: string): void;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// 跨平台开浏览器(best-effort:失败静默,用户可手动复制 URL)
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
export function openBrowser(url) {
|
|
4
|
+
try {
|
|
5
|
+
if (process.platform === 'win32') {
|
|
6
|
+
// cmd /c start:Windows 默认浏览器;空标题占位防 URL 被当成标题
|
|
7
|
+
spawn('cmd', ['/c', 'start', '', url], { detached: true, stdio: 'ignore', windowsHide: true }).unref();
|
|
8
|
+
}
|
|
9
|
+
else if (process.platform === 'darwin') {
|
|
10
|
+
spawn('open', [url], { detached: true, stdio: 'ignore' }).unref();
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
spawn('xdg-open', [url], { detached: true, stdio: 'ignore' }).unref();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
// 开不了浏览器不影响功能:URL 已打印在终端
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=open-browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open-browser.js","sourceRoot":"","sources":["../../src/util/open-browser.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,IAAI,CAAC;QACH,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;YACjC,8CAA8C;YAC9C,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;QACzG,CAAC;aAAM,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACzC,KAAK,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;QACpE,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;QACxE,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,yBAAyB;IAC3B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** 配置页 URL(host/port 回退默认值);server.enabled=false 时返回 null(无页面可指) */
|
|
2
|
+
export function serverUrl(config) {
|
|
3
|
+
const s = config.server;
|
|
4
|
+
if (s?.enabled === false)
|
|
5
|
+
return null;
|
|
6
|
+
const host = s?.host ?? '127.0.0.1';
|
|
7
|
+
const port = s?.port ?? 17317;
|
|
8
|
+
return `http://${host}:${port}`;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=server-url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-url.js","sourceRoot":"","sources":["../../src/util/server-url.ts"],"names":[],"mappings":"AAGA,oEAAoE;AACpE,MAAM,UAAU,SAAS,CAAC,MAAoB;IAC5C,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,OAAO,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,WAAW,CAAC;IACpC,MAAM,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,KAAK,CAAC;IAC9B,OAAO,UAAU,IAAI,IAAI,IAAI,EAAE,CAAC;AAClC,CAAC"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION
|
|
1
|
+
export declare const VERSION: string;
|
package/dist/version.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
1
|
+
// 版本号唯一来源:package.json(运行时读取,避免双份声明漂移——历史上 0.7.0~0.10.0 曾连续漏改)
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
const pkg = JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.url)), '..', 'package.json'), 'utf8'));
|
|
6
|
+
export const VERSION = pkg.version;
|
|
3
7
|
//# sourceMappingURL=version.js.map
|
package/dist/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CACpB,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CACnE,CAAC;AAEzB,MAAM,CAAC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { BridgeConfig, FeishuAppConfig } from '../types.js';
|
|
2
|
+
/** secret 字段的脱敏回显形状(真实值永不离开本机进程) */
|
|
3
|
+
export interface SecretHint {
|
|
4
|
+
secretSet: boolean;
|
|
5
|
+
secretHint?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function maskSecret(value: string | undefined): SecretHint;
|
|
8
|
+
/** 客户端提交的 secret 字段是否应视为「未修改」(空串/缺省/仍是脱敏对象都算) */
|
|
9
|
+
export declare function isUnchangedSecret(v: unknown): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* secret 回填:客户端 doc 中的 secret 字段(apps[].app_secret、claude.auth_token/api_key)
|
|
12
|
+
* 未修改时回填磁盘现值。非 secret 字段不动;其余 secret 位置(未来新增)按同模式扩展。
|
|
13
|
+
*/
|
|
14
|
+
export declare function applySecrets(newDoc: Record<string, unknown>, oldDoc: Record<string, unknown>): Record<string, unknown>;
|
|
15
|
+
/** GET /api/config 响应构建:深拷贝 doc 并把 secret 字段替换为脱敏提示 */
|
|
16
|
+
export declare function docForClient(doc: Record<string, unknown>): Record<string, unknown>;
|
|
17
|
+
/**
|
|
18
|
+
* Host header 校验(防 DNS rebinding):host 部分(去端口)必须是回环名或配置的 host。
|
|
19
|
+
* 端口不校验(localhost:port 与 127.0.0.1:port 等价放行,用户从哪个名字进来无从假设)。
|
|
20
|
+
*/
|
|
21
|
+
export declare function isAllowedHost(hostHeader: string | undefined, cfgHost: string): boolean;
|
|
22
|
+
/** Origin header 校验(存在才查;同源 fetch 一定带且 host 合法,跨站请求携带外域 Origin) */
|
|
23
|
+
export declare function isAllowedOrigin(originHeader: string | undefined, cfgHost: string, cfgPort: number): boolean;
|
|
24
|
+
/** PUT 前后比较,列出需重启的段落(其余段落经热重载器下一条消息生效) */
|
|
25
|
+
export declare function computeRestartRequired(before: BridgeConfig, after: BridgeConfig): string[];
|
|
26
|
+
/** apps 启动态摘要(GET /api/status 用;lcb ui 独立进程无法得知,标 unknown) */
|
|
27
|
+
export declare function appStatusSummary(apps: FeishuAppConfig[], started?: Array<{
|
|
28
|
+
name: string;
|
|
29
|
+
started: boolean;
|
|
30
|
+
}>): Array<{
|
|
31
|
+
name: string;
|
|
32
|
+
appId: string;
|
|
33
|
+
started: boolean | 'unknown';
|
|
34
|
+
}>;
|
|
35
|
+
/**
|
|
36
|
+
* GET /api/config 显示层权限默认回填:permissions 键缺失(undefined/null,多见于老版本升级配置)时
|
|
37
|
+
* 回显运行时默认,让用户「打开页面就能看到/编辑默认值」;键存在但为空数组 = 用户有意清空,原样返回。
|
|
38
|
+
* PUT 整段替换语义下「回显 → 保存 → 固化写盘」为预期行为(老配置保存会把该段固化为默认并重写,
|
|
39
|
+
* 丢段内手写注释;bootstrap 出身的配置磁盘已有相同默认,走「值未变跳过重写」不受影响)。
|
|
40
|
+
*/
|
|
41
|
+
export declare function applyPermissionDisplayDefaults(doc: Record<string, unknown>): Record<string, unknown>;
|
|
42
|
+
/** 当前生效 Claude 配置摘要(GET /api/status 展示用):settings.json 内容 → 凭证脱敏。inherit/managed 均适用 */
|
|
43
|
+
export interface ClaudeCurrentSummary {
|
|
44
|
+
baseUrl?: string;
|
|
45
|
+
model?: string;
|
|
46
|
+
authToken: SecretHint;
|
|
47
|
+
apiKey: SecretHint;
|
|
48
|
+
}
|
|
49
|
+
/** 纯函数:解析 settings.json(顶层 model + env 块 ANTHROPIC_*),凭证过 maskSecret,明文永不离开本机 */
|
|
50
|
+
export declare function claudeSettingsSummary(settings: unknown): ClaudeCurrentSummary;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { sameApps } from '../config.js';
|
|
2
|
+
import { DEFAULT_ALLOW_TOOLS_LIST, DEFAULT_DANGEROUS_COMMAND_SOURCES } from '../executor/permission-gate.js';
|
|
3
|
+
export function maskSecret(value) {
|
|
4
|
+
if (!value)
|
|
5
|
+
return { secretSet: false };
|
|
6
|
+
return { secretSet: true, secretHint: `••••${value.slice(-4)}` };
|
|
7
|
+
}
|
|
8
|
+
/** 客户端提交的 secret 字段是否应视为「未修改」(空串/缺省/仍是脱敏对象都算) */
|
|
9
|
+
export function isUnchangedSecret(v) {
|
|
10
|
+
if (v === undefined || v === null)
|
|
11
|
+
return true;
|
|
12
|
+
if (typeof v === 'object')
|
|
13
|
+
return true; // 仍是 GET 回显的 {secretSet...} 对象
|
|
14
|
+
if (typeof v === 'string')
|
|
15
|
+
return v.trim() === '';
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* secret 回填:客户端 doc 中的 secret 字段(apps[].app_secret、claude.auth_token/api_key)
|
|
20
|
+
* 未修改时回填磁盘现值。非 secret 字段不动;其余 secret 位置(未来新增)按同模式扩展。
|
|
21
|
+
*/
|
|
22
|
+
export function applySecrets(newDoc, oldDoc) {
|
|
23
|
+
const doc = { ...newDoc };
|
|
24
|
+
const newApps = Array.isArray(doc.apps) ? doc.apps : [];
|
|
25
|
+
const oldApps = Array.isArray(oldDoc.apps) ? oldDoc.apps : [];
|
|
26
|
+
// 按 app_id 对齐回填(而非索引):页面可能增删/重排应用,索引对齐会把别的应用 secret 错配
|
|
27
|
+
const oldSecretById = new Map(oldApps.map((a) => [String(a?.app_id ?? ''), a?.app_secret]));
|
|
28
|
+
doc.apps = newApps.map((app) => (isUnchangedSecret(app?.app_secret)
|
|
29
|
+
? { ...app, app_secret: oldSecretById.get(String(app?.app_id ?? '')) } // 新应用查不到 → undefined,loadConfig 拦截
|
|
30
|
+
: app));
|
|
31
|
+
if (doc.claude && typeof doc.claude === 'object' && !Array.isArray(doc.claude)) {
|
|
32
|
+
const newClaude = { ...doc.claude };
|
|
33
|
+
const oldClaude = oldDoc.claude && typeof oldDoc.claude === 'object' && !Array.isArray(oldDoc.claude)
|
|
34
|
+
? oldDoc.claude
|
|
35
|
+
: {};
|
|
36
|
+
for (const key of ['auth_token', 'api_key']) {
|
|
37
|
+
if (isUnchangedSecret(newClaude[key]))
|
|
38
|
+
newClaude[key] = oldClaude[key];
|
|
39
|
+
}
|
|
40
|
+
// 多厂商档案(0.13):按 name 对齐回填未修改的凭证(同 apps 按 app_id 对齐的考虑)
|
|
41
|
+
if (Array.isArray(newClaude.profiles)) {
|
|
42
|
+
const oldByName = new Map((Array.isArray(oldClaude.profiles) ? oldClaude.profiles : [])
|
|
43
|
+
.map((p) => [String(p?.name ?? ''), p]));
|
|
44
|
+
newClaude.profiles = newClaude.profiles.map((p) => {
|
|
45
|
+
const old = oldByName.get(String(p?.name ?? ''));
|
|
46
|
+
if (!old)
|
|
47
|
+
return p; // 新档案:提交值即最终值(无凭证无内容会被 normalizeClaude 剔除)
|
|
48
|
+
const merged = { ...p };
|
|
49
|
+
for (const key of ['auth_token', 'api_key']) {
|
|
50
|
+
if (isUnchangedSecret(merged[key]))
|
|
51
|
+
merged[key] = old[key];
|
|
52
|
+
}
|
|
53
|
+
return merged;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
doc.claude = newClaude;
|
|
57
|
+
}
|
|
58
|
+
return doc;
|
|
59
|
+
}
|
|
60
|
+
/** GET /api/config 响应构建:深拷贝 doc 并把 secret 字段替换为脱敏提示 */
|
|
61
|
+
export function docForClient(doc) {
|
|
62
|
+
const out = JSON.parse(JSON.stringify(doc ?? {}));
|
|
63
|
+
if (Array.isArray(out.apps)) {
|
|
64
|
+
out.apps = out.apps.map((app) => ({
|
|
65
|
+
...app,
|
|
66
|
+
app_secret: maskSecret(typeof app?.app_secret === 'string' ? app.app_secret : undefined),
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
if (out.claude && typeof out.claude === 'object') {
|
|
70
|
+
const c = { ...out.claude };
|
|
71
|
+
for (const key of ['auth_token', 'api_key']) {
|
|
72
|
+
c[key] = maskSecret(typeof c[key] === 'string' ? c[key] : undefined);
|
|
73
|
+
}
|
|
74
|
+
if (Array.isArray(c.profiles)) {
|
|
75
|
+
c.profiles = c.profiles.map((p) => ({
|
|
76
|
+
...p,
|
|
77
|
+
auth_token: maskSecret(typeof p?.auth_token === 'string' ? p.auth_token : undefined),
|
|
78
|
+
api_key: maskSecret(typeof p?.api_key === 'string' ? p.api_key : undefined),
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
81
|
+
out.claude = c;
|
|
82
|
+
}
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Host header 校验(防 DNS rebinding):host 部分(去端口)必须是回环名或配置的 host。
|
|
87
|
+
* 端口不校验(localhost:port 与 127.0.0.1:port 等价放行,用户从哪个名字进来无从假设)。
|
|
88
|
+
*/
|
|
89
|
+
export function isAllowedHost(hostHeader, cfgHost) {
|
|
90
|
+
if (!hostHeader)
|
|
91
|
+
return false;
|
|
92
|
+
let hostPart = hostHeader;
|
|
93
|
+
const bracket = hostPart.match(/^\[([^\]]+)\]/); // 规范 IPv6 host:[::1]:8080
|
|
94
|
+
if (bracket) {
|
|
95
|
+
hostPart = bracket[1];
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
// 仅单一冒号视为 host:port(裸 IPv6 多冒号整体保留;多冒号场景只可能命中 '::1' 白名单)
|
|
99
|
+
const last = hostPart.lastIndexOf(':');
|
|
100
|
+
if (last !== -1 && hostPart.indexOf(':') === last)
|
|
101
|
+
hostPart = hostPart.slice(0, last);
|
|
102
|
+
}
|
|
103
|
+
return hostPart === '127.0.0.1' || hostPart === 'localhost' || hostPart === '::1' || hostPart === cfgHost;
|
|
104
|
+
}
|
|
105
|
+
/** Origin header 校验(存在才查;同源 fetch 一定带且 host 合法,跨站请求携带外域 Origin) */
|
|
106
|
+
export function isAllowedOrigin(originHeader, cfgHost, cfgPort) {
|
|
107
|
+
if (!originHeader)
|
|
108
|
+
return true; // 非 CORS 场景(curl / 同源部分实现)无 Origin,放行给 Host 校验兜底
|
|
109
|
+
try {
|
|
110
|
+
const u = new URL(originHeader);
|
|
111
|
+
return u.origin === `http://${cfgHost}:${cfgPort}`
|
|
112
|
+
|| u.origin === `http://127.0.0.1:${cfgPort}`
|
|
113
|
+
|| u.origin === `http://localhost:${cfgPort}`;
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/** PUT 前后比较,列出需重启的段落(其余段落经热重载器下一条消息生效) */
|
|
120
|
+
export function computeRestartRequired(before, after) {
|
|
121
|
+
const sections = [];
|
|
122
|
+
if (!sameApps(before.apps, after.apps))
|
|
123
|
+
sections.push('apps');
|
|
124
|
+
if (before.concurrency !== after.concurrency)
|
|
125
|
+
sections.push('concurrency');
|
|
126
|
+
if (JSON.stringify(before.claude ?? {}) !== JSON.stringify(after.claude ?? {}))
|
|
127
|
+
sections.push('claude');
|
|
128
|
+
if (JSON.stringify(before.server ?? {}) !== JSON.stringify(after.server ?? {}))
|
|
129
|
+
sections.push('server');
|
|
130
|
+
return sections;
|
|
131
|
+
}
|
|
132
|
+
/** apps 启动态摘要(GET /api/status 用;lcb ui 独立进程无法得知,标 unknown) */
|
|
133
|
+
export function appStatusSummary(apps, started) {
|
|
134
|
+
return apps.map((a) => ({
|
|
135
|
+
name: a.name,
|
|
136
|
+
appId: a.appId,
|
|
137
|
+
started: started?.find((s) => s.name === a.name)?.started ?? 'unknown',
|
|
138
|
+
}));
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* GET /api/config 显示层权限默认回填:permissions 键缺失(undefined/null,多见于老版本升级配置)时
|
|
142
|
+
* 回显运行时默认,让用户「打开页面就能看到/编辑默认值」;键存在但为空数组 = 用户有意清空,原样返回。
|
|
143
|
+
* PUT 整段替换语义下「回显 → 保存 → 固化写盘」为预期行为(老配置保存会把该段固化为默认并重写,
|
|
144
|
+
* 丢段内手写注释;bootstrap 出身的配置磁盘已有相同默认,走「值未变跳过重写」不受影响)。
|
|
145
|
+
*/
|
|
146
|
+
export function applyPermissionDisplayDefaults(doc) {
|
|
147
|
+
const p = doc.permissions;
|
|
148
|
+
if (p === undefined || p === null) {
|
|
149
|
+
return { ...doc, permissions: { allow_tools: [...DEFAULT_ALLOW_TOOLS_LIST], dangerous_commands: [...DEFAULT_DANGEROUS_COMMAND_SOURCES] } };
|
|
150
|
+
}
|
|
151
|
+
if (typeof p !== 'object' || Array.isArray(p))
|
|
152
|
+
return doc; // 脏形状:loadConfig/parseConfigText 会拦,GET 原样透出
|
|
153
|
+
const np = { ...p };
|
|
154
|
+
let changed = false;
|
|
155
|
+
if (np.allow_tools === undefined || np.allow_tools === null) {
|
|
156
|
+
np.allow_tools = [...DEFAULT_ALLOW_TOOLS_LIST];
|
|
157
|
+
changed = true;
|
|
158
|
+
}
|
|
159
|
+
if (np.dangerous_commands === undefined || np.dangerous_commands === null) {
|
|
160
|
+
np.dangerous_commands = [...DEFAULT_DANGEROUS_COMMAND_SOURCES];
|
|
161
|
+
changed = true;
|
|
162
|
+
}
|
|
163
|
+
return changed ? { ...doc, permissions: np } : doc;
|
|
164
|
+
}
|
|
165
|
+
/** 纯函数:解析 settings.json(顶层 model + env 块 ANTHROPIC_*),凭证过 maskSecret,明文永不离开本机 */
|
|
166
|
+
export function claudeSettingsSummary(settings) {
|
|
167
|
+
if (!settings || typeof settings !== 'object' || Array.isArray(settings)) {
|
|
168
|
+
return { authToken: maskSecret(undefined), apiKey: maskSecret(undefined) };
|
|
169
|
+
}
|
|
170
|
+
const doc = settings;
|
|
171
|
+
const env = doc.env && typeof doc.env === 'object' && !Array.isArray(doc.env)
|
|
172
|
+
? doc.env
|
|
173
|
+
: {};
|
|
174
|
+
const str = (v) => (typeof v === 'string' && v.trim() ? v : undefined);
|
|
175
|
+
const baseUrl = str(env.ANTHROPIC_BASE_URL);
|
|
176
|
+
const model = str(env.ANTHROPIC_MODEL) ?? str(doc.model);
|
|
177
|
+
return {
|
|
178
|
+
...(baseUrl ? { baseUrl } : {}),
|
|
179
|
+
...(model ? { model } : {}),
|
|
180
|
+
authToken: maskSecret(str(env.ANTHROPIC_AUTH_TOKEN)),
|
|
181
|
+
apiKey: maskSecret(str(env.ANTHROPIC_API_KEY)),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=config-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-api.js","sourceRoot":"","sources":["../../src/web/config-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** 桥接器进程启动成功后自写 PID 文件(页面据此探活/跨进程停止) */
|
|
2
|
+
export declare function writePidFile(pidPath?: string): void;
|
|
3
|
+
/** 优雅关闭时自清 PID 文件;文件已被其它进程覆写(重启竞态)时不误删 */
|
|
4
|
+
export declare function clearPidFile(pidPath?: string): void;
|
|
5
|
+
export interface BridgeStatus {
|
|
6
|
+
running: boolean;
|
|
7
|
+
pid: number | null;
|
|
8
|
+
}
|
|
9
|
+
/** 探活桥接器;PID 文件指向已消亡进程(崩溃/被硬杀未及清理)时顺手清掉陈旧文件 */
|
|
10
|
+
export declare function bridgeStatus(pidPath?: string): BridgeStatus;
|
|
11
|
+
/**
|
|
12
|
+
* 解析 lcb CLI 入口(发布包 dist/bin/lcb.js;模块位置相对定位,tsx 源码模式下该路径不存在)。
|
|
13
|
+
* 源码运行时返回 error——页面按钮禁用并提示手动启停
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveLcbEntry(): {
|
|
16
|
+
ok: true;
|
|
17
|
+
entry: string;
|
|
18
|
+
} | {
|
|
19
|
+
ok: false;
|
|
20
|
+
error: string;
|
|
21
|
+
};
|
|
22
|
+
/** 后台拉起桥接器:detached 守护进程,stdio 落 bridge.log,父进程退出不影响其存活 */
|
|
23
|
+
export declare function spawnBridgeDetached(): {
|
|
24
|
+
ok: true;
|
|
25
|
+
pid: number;
|
|
26
|
+
} | {
|
|
27
|
+
ok: false;
|
|
28
|
+
error: string;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* 停止指定 PID 的桥接器。Windows 上 SIGTERM 等效 TerminateProcess(不走进程内优雅关闭
|
|
32
|
+
* handler);会话/配对状态均逐消息落盘,硬终止风险可控。同进程内(embedded)停止走
|
|
33
|
+
* server.ts 注入的 selfStop 优雅路径,不经本函数
|
|
34
|
+
*/
|
|
35
|
+
export declare function stopBridgeByPid(pid: number): boolean;
|
|
36
|
+
/** 重启桥接器:spawn detached helper 由其等待旧进程退出后拉起新进程(跨平台统一路径) */
|
|
37
|
+
export declare function restartBridgeWithHelper(oldPid: number): {
|
|
38
|
+
ok: true;
|
|
39
|
+
} | {
|
|
40
|
+
ok: false;
|
|
41
|
+
error: string;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* lcb start 启动早期调用:探活并终止 pid 文件登记的旧实例,轮询等待真正退出。
|
|
45
|
+
* 旧实例占着 Web 配置页端口会让本进程配置页静默失联(浏览器仍打到旧进程)。
|
|
46
|
+
* Windows 上 SIGTERM=硬杀仍为异步,端口释放有延迟,故轮询(300ms 节奏同 RESTART_HELPER)。
|
|
47
|
+
* 纯逻辑不打日志(由调用方输出),便于测试
|
|
48
|
+
*/
|
|
49
|
+
export declare function stopExistingBridgeAndWait(timeoutMs?: number, pidPath?: string): Promise<{
|
|
50
|
+
stopped: boolean;
|
|
51
|
+
pid: number | null;
|
|
52
|
+
}>;
|