@jesonliu/lark-claudecode-bridge 1.0.2 → 1.0.4

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 (57) hide show
  1. package/assets/web/css/main.css +13 -0
  2. package/assets/web/js/core.js +3 -1
  3. package/assets/web/js/pages/larkcli-device.js +188 -0
  4. package/assets/web/js/pages/overview.js +244 -5
  5. package/assets/web/js/ui.js +66 -2
  6. package/config.example.yaml +3 -0
  7. package/dist/bin/lcb.js +10 -0
  8. package/dist/bin/lcb.js.map +1 -1
  9. package/dist/executor/notify-server.d.ts +0 -2
  10. package/dist/executor/notify-server.js +3 -10
  11. package/dist/executor/notify-server.js.map +1 -1
  12. package/dist/executor/plugin-manager.d.ts +16 -0
  13. package/dist/executor/plugin-manager.js +40 -1
  14. package/dist/executor/plugin-manager.js.map +1 -1
  15. package/dist/gateway/card-builder.d.ts +6 -5
  16. package/dist/gateway/card-builder.js +10 -9
  17. package/dist/gateway/card-builder.js.map +1 -1
  18. package/dist/gateway/diff-card.d.ts +7 -7
  19. package/dist/gateway/diff-card.js +14 -8
  20. package/dist/gateway/diff-card.js.map +1 -1
  21. package/dist/gateway/feishu-gateway.d.ts +7 -1
  22. package/dist/gateway/feishu-gateway.js +8 -3
  23. package/dist/gateway/feishu-gateway.js.map +1 -1
  24. package/dist/index.js +100 -30
  25. package/dist/index.js.map +1 -1
  26. package/dist/lark-cli-manager.d.ts +336 -0
  27. package/dist/lark-cli-manager.js +985 -0
  28. package/dist/lark-cli-manager.js.map +1 -0
  29. package/dist/notify-sop.d.ts +1 -1
  30. package/dist/notify-sop.js +3 -3
  31. package/dist/notify-sop.js.map +1 -1
  32. package/dist/session/commands.d.ts +3 -0
  33. package/dist/session/commands.js +3 -3
  34. package/dist/session/commands.js.map +1 -1
  35. package/dist/session/plugin-command.js +18 -2
  36. package/dist/session/plugin-command.js.map +1 -1
  37. package/dist/session/session-store.d.ts +9 -2
  38. package/dist/session/session-store.js +9 -3
  39. package/dist/session/session-store.js.map +1 -1
  40. package/dist/util/file-tracker.d.ts +13 -6
  41. package/dist/util/file-tracker.js +28 -10
  42. package/dist/util/file-tracker.js.map +1 -1
  43. package/dist/util/npm.d.ts +13 -0
  44. package/dist/util/npm.js +44 -0
  45. package/dist/util/npm.js.map +1 -0
  46. package/dist/util/terminal-window.d.ts +111 -0
  47. package/dist/util/terminal-window.js +425 -0
  48. package/dist/util/terminal-window.js.map +1 -0
  49. package/dist/util/workspace-diff.d.ts +4 -7
  50. package/dist/util/workspace-diff.js +30 -35
  51. package/dist/util/workspace-diff.js.map +1 -1
  52. package/dist/web/server.js +94 -4
  53. package/dist/web/server.js.map +1 -1
  54. package/dist/web/update.d.ts +1 -5
  55. package/dist/web/update.js +2 -20
  56. package/dist/web/update.js.map +1 -1
  57. package/package.json +1 -1
@@ -0,0 +1,111 @@
1
+ import type { ChildProcess } from 'node:child_process';
2
+ export type TerminalTask = 'install' | 'auth' | 'config';
3
+ /** 烘焙进脚本的绝对路径(全部来自 OS,不含任何用户输入) */
4
+ export interface ScriptBake {
5
+ /** 桥接器进程的 PATH —— 它跑通过 `npm prefix -g`,在 GUI 终端里最可信的来源 */
6
+ pathEnv?: string;
7
+ /** node 绝对路径(PATH 上没有 lark-cli 时直跑包内入口兜底) */
8
+ nodePath?: string;
9
+ /** lark-cli 包内入口 scripts/run.js 绝对路径 */
10
+ larkEntry?: string;
11
+ }
12
+ /** 脚本流程开关(bridge 端判定后传入;脚本本身保持纯渲染) */
13
+ export interface ScriptOpts {
14
+ /**
15
+ * 未配置应用时先跑 `lark-cli config init --new`(官方安装第 ③ 步)再 auth login。
16
+ * 由调用方用 needsLarkCliConfig() 判定传入;缺省 false(不插 config 段,兼容旧流程)。
17
+ */
18
+ needConfig?: boolean;
19
+ }
20
+ export declare const LARK_CLI_SCRIPT_PREFIX = "lcb-larkcli-";
21
+ /** Unix 单引号封装;值内单引号用 close-escape-reopen 拼接(`'` → `'\''`) */
22
+ export declare function shQuote(v: string): string;
23
+ /**
24
+ * Windows `set "VAR=..."` 的值安全校验:含 cmd 元字符就返回 undefined(调用方整行省略)。
25
+ * 宁可不烘焙这段 PATH 也不冒注入风险——空格不在禁用之列,因为 `set "VAR=值"` 的引号已覆盖它。
26
+ */
27
+ export declare function cmdSafeEnvValue(v: string): string | undefined;
28
+ /**
29
+ * Windows .cmd:CRLF 行尾、UTF-8 无 BOM、**全文纯 ASCII**。
30
+ *
31
+ * 真机实测(Win11):cmd 按 512 字节块读批处理文件,**多字节 UTF-8 字符跨块时该行会被
32
+ * 从中间截断、后半截当命令执行**(幻影换行)——垫字节对齐可以复现/消除,但烘焙的 PATH
33
+ * 动辄数 KB,文件必然跨多个块边界,对齐守不住;BOM 也救不了。故中文指引放配置页弹窗,
34
+ * 终端里的固定文案用英文;`chcp 65001` 保留,让 lark-cli 自己的 UTF-8 输出正常显示。
35
+ *
36
+ * 不用 goto/标签(顺带规避 goto 在多字节批处理里的定位漂移),失败路径用
37
+ * `exit /b 1` 终止(cmd /k 下落到交互提示符,窗口保持打开)。
38
+ */
39
+ export declare function buildWindowsScript(task: TerminalTask, bake?: ScriptBake, opts?: ScriptOpts): string;
40
+ /** Unix .sh:LF 行尾(CRLF 会毁掉 shebang:/bin/sh^M: bad interpreter) */
41
+ export declare function buildUnixScript(task: TerminalTask, bake?: ScriptBake, opts?: ScriptOpts): string;
42
+ export interface WhichFs {
43
+ exists(p: string): boolean;
44
+ executable(p: string): boolean;
45
+ }
46
+ /**
47
+ * 在 PATH 里查可执行文件(自己拆 PATH,不 spawn `which`——12 条候选要起 12 个进程,
48
+ * 且 `which` 本身可能不存在)。
49
+ *
50
+ * 拼接刻意不走 path.join:那会让分隔符由**宿主**决定而非 platform 参数,
51
+ * 注入非宿主平台(测试)时就会拼出 `/usr/bin\konsole` 这种四不像。
52
+ */
53
+ export declare function whichFromPath(bin: string, env: NodeJS.ProcessEnv, platform: NodeJS.Platform, fs?: WhichFs): string | undefined;
54
+ export interface TerminalCandidate {
55
+ /** 要 spawn 的程序 */
56
+ bin: string;
57
+ /** 人类可读名称(日志/测试断言用) */
58
+ terminal: string;
59
+ args(scriptPath: string): string[];
60
+ }
61
+ export interface DetectOpts {
62
+ platform?: NodeJS.Platform;
63
+ env?: NodeJS.ProcessEnv;
64
+ fs?: WhichFs;
65
+ }
66
+ export interface ListCandidatesResult {
67
+ candidates: TerminalCandidate[];
68
+ reason?: string;
69
+ }
70
+ /**
71
+ * 列出可用的终端候选(按优先级)。
72
+ * Linux 上先用 DISPLAY/WAYLAND_DISPLAY 挡掉 SSH/headless —— 省掉一轮无谓的 spawn 试探。
73
+ */
74
+ export declare function listTerminalCandidates(opts?: DetectOpts): ListCandidatesResult;
75
+ export type DetectTerminalResult = ({
76
+ ok: true;
77
+ } & TerminalCandidate) | {
78
+ ok: false;
79
+ reason: string;
80
+ code: 'no-terminal';
81
+ };
82
+ /** 探测首个可用终端(只探测,不落盘、不 spawn) */
83
+ export declare function detectTerminal(opts?: DetectOpts): DetectTerminalResult;
84
+ export type SpawnFn = (file: string, args: string[], opts: Record<string, unknown>) => ChildProcess;
85
+ export interface LaunchTerminalOpts extends DetectOpts {
86
+ bake?: ScriptBake;
87
+ /** 未配置应用时先跑 config init --new(透传给脚本 builder,见 ScriptOpts) */
88
+ needConfig?: boolean;
89
+ tmpDir?: string;
90
+ spawnFn?: SpawnFn;
91
+ /** 注入点:写脚本并返回实际落盘路径(生产实现另做 24h 残留清扫) */
92
+ writeScript?: (filePath: string, text: string) => string;
93
+ /** 注入点:候选列表(生产实现为 listTerminalCandidates) */
94
+ listCandidates?: (opts?: DetectOpts) => ListCandidatesResult;
95
+ }
96
+ export type LaunchTerminalResult = {
97
+ ok: true;
98
+ terminal: string;
99
+ scriptPath: string;
100
+ } | {
101
+ ok: false;
102
+ reason: string;
103
+ code: 'no-terminal' | 'spawn-failed' | 'script-write-failed';
104
+ };
105
+ /**
106
+ * 写脚本 → 逐个候选拉起终端。全部失败时返回 ok:false,由调用方决定降级(静默安装)。
107
+ *
108
+ * 注意:spawn 只捕获**同步**异常。候选已由 listCandidates 预筛过存在性,异步 'error'
109
+ * 事件(极端的权限场景)不再下探——那时进程已返回,重新拉起反而可能开出多个窗口。
110
+ */
111
+ export declare function launchInTerminal(task: TerminalTask, opts?: LaunchTerminalOpts): Promise<LaunchTerminalResult>;
@@ -0,0 +1,425 @@
1
+ // 跨平台拉起终端窗口执行一段脚本(飞书 CLI 的安装/更新 + 授权登录引导)。
2
+ //
3
+ // 三个关键设计决定:
4
+ // ① 与 src/web/lifecycle.ts 的 spawnBridgeDetached 同款:detached + stdio:ignore + unref,
5
+ // 不保留 child 引用、绝不 kill —— 桥接器重启/退出都不能连累已经打开的终端
6
+ // (授权是分钟级流程,而「一键更新」恰好会重启桥接器)。
7
+ // ② Windows 写临时 .cmd 文件而非内联命令串:内联要穿过「Node argv 引号 → cmd 解析 →
8
+ // start 的标题规则 → 嵌套 .cmd 再解析」四层,& / && / 空格路径任一处出错都是静默失败。
9
+ // 写成文件后整条命令只剩下一个路径参数。
10
+ // ③ 纯函数与副作用分离:platform / env / fs / spawnFn / writeScript 全部可注入,
11
+ // 单测不真拉终端、不真写盘。
12
+ import { spawn } from 'node:child_process';
13
+ import { accessSync, chmodSync, constants, readdirSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
14
+ import { dirname, join } from 'node:path';
15
+ import { tmpdir } from 'node:os';
16
+ /**
17
+ * Agent 上下文变量:lark-cli 检测到会走「Agent 凭证绑定」分支(拒绝 config init、
18
+ * auth status 报 not bound)。GUI 终端继承的是注册表/登录会话环境而非 bridge 进程环境
19
+ * (bridge 入口剔除管不到它),所以脚本里必须自己清。与 lark-cli-manager 的
20
+ * AGENT_CONTEXT_ENV_KEYS 同源——菜单化重复声明是为了避免 util 反向依赖 src 根模块。
21
+ */
22
+ const AGENT_CONTEXT_ENV_KEYS = ['HERMES_HOME', 'OPENCLAW_HOME', 'LARK_CHANNEL'];
23
+ export const LARK_CLI_SCRIPT_PREFIX = 'lcb-larkcli-';
24
+ // ============ 纯函数:Shell 转义 ============
25
+ /** Unix 单引号封装;值内单引号用 close-escape-reopen 拼接(`'` → `'\''`) */
26
+ export function shQuote(v) {
27
+ return `'${v.replace(/'/g, "'\\''")}'`;
28
+ }
29
+ /**
30
+ * Windows `set "VAR=..."` 的值安全校验:含 cmd 元字符就返回 undefined(调用方整行省略)。
31
+ * 宁可不烘焙这段 PATH 也不冒注入风险——空格不在禁用之列,因为 `set "VAR=值"` 的引号已覆盖它。
32
+ */
33
+ export function cmdSafeEnvValue(v) {
34
+ return /[%^&|<>"\r\n]/.test(v) ? undefined : v;
35
+ }
36
+ // ============ 纯函数:脚本生成 ============
37
+ /**
38
+ * Windows .cmd:CRLF 行尾、UTF-8 无 BOM、**全文纯 ASCII**。
39
+ *
40
+ * 真机实测(Win11):cmd 按 512 字节块读批处理文件,**多字节 UTF-8 字符跨块时该行会被
41
+ * 从中间截断、后半截当命令执行**(幻影换行)——垫字节对齐可以复现/消除,但烘焙的 PATH
42
+ * 动辄数 KB,文件必然跨多个块边界,对齐守不住;BOM 也救不了。故中文指引放配置页弹窗,
43
+ * 终端里的固定文案用英文;`chcp 65001` 保留,让 lark-cli 自己的 UTF-8 输出正常显示。
44
+ *
45
+ * 不用 goto/标签(顺带规避 goto 在多字节批处理里的定位漂移),失败路径用
46
+ * `exit /b 1` 终止(cmd /k 下落到交互提示符,窗口保持打开)。
47
+ */
48
+ export function buildWindowsScript(task, bake = {}, opts = {}) {
49
+ const L = [];
50
+ // 绝不能加 BOM:它会让首行的 @echo off 变成垃圾并被回显
51
+ L.push('@echo off');
52
+ L.push('chcp 65001 >nul 2>&1');
53
+ L.push('title lark-cli install / config / auth (from lcb)');
54
+ const safePath = bake.pathEnv ? cmdSafeEnvValue(bake.pathEnv) : undefined;
55
+ if (safePath)
56
+ L.push(`set "PATH=${safePath};%PATH%"`);
57
+ // Agent 上下文清场:不清则 lark-cli 走「Agent 绑定」分支(拒绝 config init)——见上方常量注释
58
+ for (const k of AGENT_CONTEXT_ENV_KEYS)
59
+ L.push(`set "${k}="`);
60
+ L.push('echo.');
61
+ L.push('echo ============================================================');
62
+ // 步骤总数随任务/流程开关变化,编号 [n/total] 动态拼
63
+ const total = task === 'install' ? (opts.needConfig ? 3 : 2) : task === 'config' ? 2 : 1;
64
+ if (task === 'install') {
65
+ L.push('echo Lark CLI (@larksuite/cli) install / update + skill + config + auth');
66
+ L.push('echo Launched from the lcb web console. Keep this window open;');
67
+ L.push('echo the following steps run automatically once install finishes.');
68
+ }
69
+ else if (task === 'config') {
70
+ L.push('echo Lark CLI (@larksuite/cli) app configuration (config init --new)');
71
+ L.push('echo Launched from the lcb web console. Complete the setup in the');
72
+ L.push('echo browser page it prints; auth login starts automatically after.');
73
+ }
74
+ else {
75
+ L.push('echo Lark CLI (@larksuite/cli) auth login');
76
+ L.push('echo Launched from the lcb web console. Follow the prompts below.');
77
+ }
78
+ L.push('echo ============================================================');
79
+ L.push('echo.');
80
+ if (task === 'install') {
81
+ L.push('where npm >nul 2>&1');
82
+ L.push('if errorlevel 1 (');
83
+ L.push(' echo [x] npm not found. Install Node.js first and make sure npm is on PATH.');
84
+ L.push(' echo.');
85
+ L.push(' exit /b 1');
86
+ L.push(')');
87
+ L.push('echo ^> npm install -g @larksuite/cli@latest');
88
+ // 必须 call:npm 是 .cmd shim,批处理里不加 call 会移交控制权且永不返回
89
+ L.push('call npm install -g @larksuite/cli@latest');
90
+ L.push('if errorlevel 1 (');
91
+ L.push(' echo.');
92
+ L.push(' echo [x] Install failed (see npm output above). Auth login skipped.');
93
+ L.push(' echo Check network / registry mirror, then retry.');
94
+ L.push(' echo.');
95
+ L.push(' exit /b 1');
96
+ L.push(')');
97
+ L.push('echo.');
98
+ L.push(`echo [1/${total}] Install/update done. Installing the official SKILL (teaches AI tools how to drive lark-cli)...`);
99
+ L.push('echo.');
100
+ // npx 同为 .cmd shim 必须 call;失败仅提示不阻断(SKILL 可稍后在 lcb 配置页补装)
101
+ L.push('call npx -y skills add https://open.feishu.cn --skill "*" -g -a claude-code --copy -y');
102
+ L.push('if errorlevel 1 (');
103
+ L.push(' echo.');
104
+ L.push(' echo [!] SKILL install failed (non-fatal). Retry later via the lcb web console.');
105
+ L.push(' echo.');
106
+ L.push(')');
107
+ }
108
+ if (task === 'config' || opts.needConfig) {
109
+ const n = task === 'config' ? 1 : 2;
110
+ L.push('echo.');
111
+ L.push(`echo [${n}/${total}] Configuring the Feishu app: complete the setup in the browser page it prints...`);
112
+ L.push('echo.');
113
+ L.push('call lark-cli config init --new');
114
+ L.push('if errorlevel 1 (');
115
+ L.push(' echo.');
116
+ L.push(' echo [x] Config not completed or cancelled. Auth login skipped.');
117
+ L.push(' echo You can retry via the lcb web console.');
118
+ L.push(' echo.');
119
+ L.push(' exit /b 1');
120
+ L.push(')');
121
+ }
122
+ L.push('echo.');
123
+ if (total > 1)
124
+ L.push(`echo [${total}/${total}] Starting auth login (confirm in browser or Feishu/Lark app)...`);
125
+ L.push('echo.');
126
+ L.push('call lark-cli auth login --recommend');
127
+ L.push('if errorlevel 1 (');
128
+ L.push(' echo.');
129
+ L.push(' echo [x] Auth not completed or cancelled. You can retry via the web console.');
130
+ L.push(' echo If not configured yet, run first: lark-cli config init');
131
+ L.push(') else (');
132
+ L.push(' echo.');
133
+ L.push(' echo [Done] Auth flow finished. Click "Check" on the web console to verify.');
134
+ L.push(')');
135
+ L.push('echo.');
136
+ return L.join('\r\n') + '\r\n';
137
+ }
138
+ /** Unix .sh:LF 行尾(CRLF 会毁掉 shebang:/bin/sh^M: bad interpreter) */
139
+ export function buildUnixScript(task, bake = {}, opts = {}) {
140
+ const L = [];
141
+ L.push('#!/bin/sh');
142
+ L.push('# 由 lcb 配置页拉起;窗口保持打开是刻意的——用户可能需要就地补跑 config init');
143
+ if (bake.nodePath)
144
+ L.push(`LARK_NODE=${shQuote(bake.nodePath)}`);
145
+ if (bake.larkEntry)
146
+ L.push(`LARK_ENTRY=${shQuote(bake.larkEntry)}`);
147
+ L.push('');
148
+ // 1) 先用桥接器自己的 PATH(它跑通过 npm prefix -g)
149
+ if (bake.pathEnv)
150
+ L.push(`export PATH=${shQuote(bake.pathEnv)}:"$PATH"`);
151
+ // 2) GUI 终端(macOS Terminal.app / 桌面双击)常不加载 .zshrc / .bashrc:补 nvm 与常见 node 位置
152
+ L.push('[ -s "$HOME/.nvm/nvm.sh" ] && . "$HOME/.nvm/nvm.sh" >/dev/null 2>&1 || true');
153
+ L.push('export PATH="$HOME/.volta/bin:$HOME/.asdf/shims:$HOME/.local/share/mise/shims:$HOME/.bun/bin:/opt/homebrew/bin:/usr/local/bin:$HOME/.local/bin:$PATH"');
154
+ // 3) Agent 上下文清场:不清则 lark-cli 走「Agent 绑定」分支(拒绝 config init)——见常量注释
155
+ L.push('unset HERMES_HOME OPENCLAW_HOME LARK_CHANNEL');
156
+ L.push('');
157
+ const total = task === 'install' ? (opts.needConfig ? 3 : 2) : task === 'config' ? 2 : 1;
158
+ L.push('echo "============================================================"');
159
+ if (task === 'install') {
160
+ L.push('echo " 飞书官方 CLI(@larksuite/cli)安装 / 更新 + SKILL + 配置 + 授权"');
161
+ L.push('echo " 本窗口由 lcb 配置页拉起,请勿关闭;各步骤会自动依次执行"');
162
+ }
163
+ else if (task === 'config') {
164
+ L.push('echo " 飞书官方 CLI(@larksuite/cli)应用配置(config init --new)"');
165
+ L.push('echo " 本窗口由 lcb 配置页拉起,按它打印的链接在浏览器完成创建后自动继续"');
166
+ }
167
+ else {
168
+ L.push('echo " 飞书官方 CLI(@larksuite/cli)授权登录"');
169
+ L.push('echo " 本窗口由 lcb 配置页拉起,请按提示完成授权"');
170
+ }
171
+ L.push('echo "============================================================"');
172
+ L.push('echo');
173
+ if (task === 'install') {
174
+ L.push('if ! command -v npm >/dev/null 2>&1; then');
175
+ L.push(' echo "[x] 未找到 npm:请先安装 Node.js(nvm/asdf 用户请确认已设置 default 版本)"');
176
+ L.push(' echo " 按回车关闭本窗口"; read -r _ || true');
177
+ L.push(' exit 1');
178
+ L.push('fi');
179
+ L.push('');
180
+ L.push('echo "> npm install -g @larksuite/cli@latest"');
181
+ L.push('npm install -g @larksuite/cli@latest');
182
+ L.push('if [ $? -ne 0 ]; then');
183
+ L.push(' echo');
184
+ L.push(' echo "[x] 安装失败(见上方 npm 输出),已跳过后续步骤。请检查网络 / registry 镜像后重试。"');
185
+ L.push(' echo " 按回车关闭本窗口"; read -r _ || true');
186
+ L.push(' exit 1');
187
+ L.push('fi');
188
+ L.push('');
189
+ L.push(`echo "[1/${total}] 安装/更新完成,安装官方 SKILL(教 AI 工具使用 lark-cli;失败不影响后续)..."`);
190
+ L.push("npx -y skills add https://open.feishu.cn --skill '*' -g -a claude-code --copy -y \\");
191
+ L.push(' || echo "[!] SKILL 安装失败(不影响后续步骤),可稍后在 lcb 配置页重试"');
192
+ L.push('');
193
+ }
194
+ if (task === 'config' || opts.needConfig) {
195
+ const n = task === 'config' ? 1 : 2;
196
+ L.push(`echo "[${n}/${total}] 配置飞书应用:按它打印的链接/页面在浏览器完成创建,完成后自动继续..."`);
197
+ L.push('if command -v lark-cli >/dev/null 2>&1; then');
198
+ L.push(' lark-cli config init --new');
199
+ if (bake.nodePath && bake.larkEntry) {
200
+ L.push('else');
201
+ L.push(' "$LARK_NODE" "$LARK_ENTRY" config init --new');
202
+ }
203
+ else {
204
+ L.push('else');
205
+ L.push(' echo "[x] 未找到 lark-cli:请确认全局安装目录在 PATH 中(npm prefix -g)"');
206
+ }
207
+ L.push('fi');
208
+ L.push('if [ $? -ne 0 ]; then');
209
+ L.push(' echo');
210
+ L.push(' echo "[x] 配置未完成或已取消,已跳过授权登录。可回 lcb 配置页重试。"');
211
+ L.push(' echo " 按回车关闭本窗口"; read -r _ || true');
212
+ L.push(' exit 1');
213
+ L.push('fi');
214
+ L.push('');
215
+ }
216
+ if (total > 1)
217
+ L.push(`echo "[${total}/${total}] 开始授权登录(按提示在浏览器或飞书中确认)..."`);
218
+ L.push('if command -v lark-cli >/dev/null 2>&1; then');
219
+ L.push(' lark-cli auth login --recommend');
220
+ if (bake.nodePath && bake.larkEntry) {
221
+ // 两段各自加引号:路径带空格也安全,不能拼成单个 $LARK(会被词分割)
222
+ L.push('else');
223
+ L.push(' "$LARK_NODE" "$LARK_ENTRY" auth login --recommend');
224
+ }
225
+ else {
226
+ L.push('else');
227
+ L.push(' echo "[x] 未找到 lark-cli:请确认全局安装目录在 PATH 中(npm prefix -g)"');
228
+ }
229
+ L.push('fi');
230
+ L.push('if [ $? -ne 0 ]; then');
231
+ L.push(' echo');
232
+ L.push(' echo "[x] 授权未完成或已取消。可在概览页点「去终端授权」重新发起。"');
233
+ L.push(' echo " 若提示未配置应用,请先在本窗口执行:lark-cli config init"');
234
+ L.push('fi');
235
+ L.push('echo');
236
+ L.push('echo "[完成] 请回到配置页点「检测」查看状态。"');
237
+ L.push('echo "按回车关闭本窗口"; read -r _ || true');
238
+ return L.join('\n') + '\n';
239
+ }
240
+ const realFs = {
241
+ exists: (p) => { try {
242
+ accessSync(p, constants.F_OK);
243
+ return true;
244
+ }
245
+ catch {
246
+ return false;
247
+ } },
248
+ executable: (p) => { try {
249
+ accessSync(p, constants.X_OK);
250
+ return true;
251
+ }
252
+ catch {
253
+ return false;
254
+ } },
255
+ };
256
+ /**
257
+ * 在 PATH 里查可执行文件(自己拆 PATH,不 spawn `which`——12 条候选要起 12 个进程,
258
+ * 且 `which` 本身可能不存在)。
259
+ *
260
+ * 拼接刻意不走 path.join:那会让分隔符由**宿主**决定而非 platform 参数,
261
+ * 注入非宿主平台(测试)时就会拼出 `/usr/bin\konsole` 这种四不像。
262
+ */
263
+ export function whichFromPath(bin, env, platform, fs = realFs) {
264
+ const raw = env.PATH ?? env.Path ?? '';
265
+ if (!raw)
266
+ return undefined;
267
+ const listSep = platform === 'win32' ? ';' : ':';
268
+ const dirSep = platform === 'win32' ? '\\' : '/';
269
+ const exts = platform === 'win32'
270
+ ? (env.PATHEXT ?? '.COM;.EXE;.BAT;.CMD').split(';').filter(Boolean)
271
+ : [''];
272
+ for (const dir of raw.split(listSep).filter(Boolean)) {
273
+ for (const ext of exts) {
274
+ const full = dir.endsWith(dirSep) ? `${dir}${bin}${ext}` : `${dir}${dirSep}${bin}${ext}`;
275
+ if (fs.exists(full) && fs.executable(full))
276
+ return full;
277
+ }
278
+ }
279
+ return undefined;
280
+ }
281
+ /** Linux 终端候选表:顺序即优先级;args 按各终端自己的语法(kitty/foot 直接吃命令,不吃 -e) */
282
+ const LINUX_TERMINALS = [
283
+ { bin: 'x-terminal-emulator', args: (s) => ['-e', s] },
284
+ { bin: 'gnome-terminal', args: (s) => ['--', s] },
285
+ { bin: 'kgx', args: (s) => ['--', s] },
286
+ { bin: 'konsole', args: (s) => ['-e', s] },
287
+ { bin: 'xfce4-terminal', args: (s) => ['-x', s] },
288
+ { bin: 'mate-terminal', args: (s) => ['-x', s] },
289
+ { bin: 'tilix', args: (s) => ['-e', s] },
290
+ { bin: 'kitty', args: (s) => [s] },
291
+ { bin: 'alacritty', args: (s) => ['-e', s] },
292
+ { bin: 'foot', args: (s) => [s] },
293
+ { bin: 'wezterm', args: (s) => ['start', s] },
294
+ { bin: 'xterm', args: (s) => ['-e', s] },
295
+ ];
296
+ /**
297
+ * 列出可用的终端候选(按优先级)。
298
+ * Linux 上先用 DISPLAY/WAYLAND_DISPLAY 挡掉 SSH/headless —— 省掉一轮无谓的 spawn 试探。
299
+ */
300
+ export function listTerminalCandidates(opts = {}) {
301
+ const platform = opts.platform ?? process.platform;
302
+ const env = opts.env ?? process.env;
303
+ const fs = opts.fs ?? realFs;
304
+ if (platform === 'win32') {
305
+ // Windows 必有控制台,无需探测
306
+ return { candidates: [{ bin: 'cmd', terminal: '命令提示符', args: (s) => ['/c', 'start', '', 'cmd', '/k', s] }] };
307
+ }
308
+ if (platform === 'darwin') {
309
+ // open -a 是 execFile 语义(路径是单个 argv),不像 osascript 要在 AppleScript 里再嵌一层 shell 转义
310
+ return { candidates: [{ bin: 'open', terminal: 'Terminal.app', args: (s) => ['-a', 'Terminal', s] }] };
311
+ }
312
+ if (!env.DISPLAY && !env.WAYLAND_DISPLAY) {
313
+ return { candidates: [], reason: '无图形会话(SSH / 无桌面环境),无法打开终端窗口' };
314
+ }
315
+ const table = [...LINUX_TERMINALS];
316
+ // $TERMINAL 优先——但仅当它是**裸 token**:含空格的 "kitty --single-instance" 按裸名查会全盘落空
317
+ const preferred = env.TERMINAL;
318
+ if (preferred && /^[A-Za-z0-9._/-]+$/.test(preferred)) {
319
+ const name = preferred.split('/').pop() ?? preferred;
320
+ const known = table.find((t) => t.bin === name);
321
+ const bin = known ? whichFromPath(name, env, platform, fs) : undefined;
322
+ if (bin) {
323
+ const idx = table.findIndex((t) => t.bin === name);
324
+ const entry = table[idx];
325
+ table.splice(idx, 1);
326
+ table.unshift(entry);
327
+ }
328
+ }
329
+ const candidates = [];
330
+ for (const t of table) {
331
+ const bin = whichFromPath(t.bin, env, platform, fs);
332
+ if (bin)
333
+ candidates.push({ bin, terminal: t.bin, args: t.args });
334
+ }
335
+ return candidates.length
336
+ ? { candidates }
337
+ : { candidates: [], reason: '未找到可用的终端程序(已尝试 x-terminal-emulator / gnome-terminal / konsole / xterm 等)' };
338
+ }
339
+ /** 探测首个可用终端(只探测,不落盘、不 spawn) */
340
+ export function detectTerminal(opts = {}) {
341
+ const { candidates, reason } = listTerminalCandidates(opts);
342
+ const first = candidates[0];
343
+ if (!first)
344
+ return { ok: false, reason: reason ?? '未找到可用的终端程序', code: 'no-terminal' };
345
+ return { ok: true, ...first };
346
+ }
347
+ /** 脚本文件名自增序号(同毫秒内的连续调用也要拿到互不相同的文件名) */
348
+ let scriptSeq = 0;
349
+ /** best-effort 清扫历史残留(系统 tmp 也会自清,这里只是不让它们无限堆积) */
350
+ function sweepStaleScripts(dir, maxAgeMs = 24 * 3600_000) {
351
+ try {
352
+ const now = Date.now();
353
+ for (const f of readdirSync(dir)) {
354
+ if (!f.startsWith(LARK_CLI_SCRIPT_PREFIX))
355
+ continue;
356
+ const p = join(dir, f);
357
+ try {
358
+ if (now - statSync(p).mtimeMs > maxAgeMs)
359
+ unlinkSync(p);
360
+ }
361
+ catch { /* 被占用 / 无权限:留给系统清理 */ }
362
+ }
363
+ }
364
+ catch { /* tmp 目录不可读 */ }
365
+ }
366
+ function defaultWriteScript(filePath, text) {
367
+ sweepStaleScripts(dirname(filePath));
368
+ // Node 默认 UTF-8 无 BOM;.cmd 绝不能有 BOM(首行会变垃圾)
369
+ writeFileSync(filePath, text);
370
+ if (!filePath.endsWith('.cmd')) {
371
+ // open -a Terminal / 各 Linux 终端都要求脚本可执行
372
+ try {
373
+ chmodSync(filePath, 0o755);
374
+ }
375
+ catch { /* 权限受限时留给调用方降级 */ }
376
+ }
377
+ return filePath;
378
+ }
379
+ /**
380
+ * 写脚本 → 逐个候选拉起终端。全部失败时返回 ok:false,由调用方决定降级(静默安装)。
381
+ *
382
+ * 注意:spawn 只捕获**同步**异常。候选已由 listCandidates 预筛过存在性,异步 'error'
383
+ * 事件(极端的权限场景)不再下探——那时进程已返回,重新拉起反而可能开出多个窗口。
384
+ */
385
+ export async function launchInTerminal(task, opts = {}) {
386
+ const platform = opts.platform ?? process.platform;
387
+ const env = opts.env ?? process.env;
388
+ const list = opts.listCandidates ?? listTerminalCandidates;
389
+ const { candidates, reason } = list({ platform, env, fs: opts.fs });
390
+ if (!candidates.length) {
391
+ return { ok: false, code: 'no-terminal', reason: reason ?? '未找到可用的终端程序' };
392
+ }
393
+ const bake = opts.bake ?? {};
394
+ const scriptOpts = { needConfig: opts.needConfig };
395
+ const text = platform === 'win32'
396
+ ? buildWindowsScript(task, bake, scriptOpts)
397
+ : buildUnixScript(task, bake, scriptOpts);
398
+ const ext = platform === 'win32' ? 'cmd' : 'sh';
399
+ // 文件名唯一(task + pid + 时间戳 + 自增序号):重复点击不会覆盖正在运行的脚本
400
+ // (序号兜住同毫秒内的连续调用——Date.now() 单独用不够)
401
+ const name = `${LARK_CLI_SCRIPT_PREFIX}${task}-${process.pid}-${Date.now()}-${++scriptSeq}.${ext}`;
402
+ const filePath = join(opts.tmpDir ?? tmpdir(), name);
403
+ let scriptPath;
404
+ try {
405
+ scriptPath = (opts.writeScript ?? defaultWriteScript)(filePath, text);
406
+ }
407
+ catch (e) {
408
+ return { ok: false, code: 'script-write-failed', reason: e instanceof Error ? e.message : String(e) };
409
+ }
410
+ const spawnFn = (opts.spawnFn ?? spawn);
411
+ let lastErr = '';
412
+ for (const c of candidates) {
413
+ try {
414
+ // windowsHide 刻意不传:它映射 CREATE_NO_WINDOW,可能把终端窗口一起藏掉
415
+ const child = spawnFn(c.bin, c.args(scriptPath), { detached: true, stdio: 'ignore' });
416
+ child.unref?.();
417
+ return { ok: true, terminal: c.terminal, scriptPath };
418
+ }
419
+ catch (e) {
420
+ lastErr = e instanceof Error ? e.message : String(e);
421
+ }
422
+ }
423
+ return { ok: false, code: 'spawn-failed', reason: lastErr || '拉起终端失败' };
424
+ }
425
+ //# sourceMappingURL=terminal-window.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-window.js","sourceRoot":"","sources":["../../src/util/terminal-window.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,6 @@
1
- export interface WorkspaceDiff {
2
- diff: string;
3
- files: number;
4
- }
5
1
  /**
6
- * 收集工作区全部未提交改动(staged + unstaged + untracked)为 unified diff 文本与文件数。
7
- * 返回 null = 非 git 仓库(调用方回退旧行为);diff 空串 = git 仓库但无改动。
2
+ * 收集单个文件的未提交改动(staged + unstaged + untracked)为 unified diff 文本。
3
+ * - 返回 null = 非 git 仓库 / 路径在工作区外 / 文件不可读(二进制、untracked 已删等)
4
+ * - 返回空串 = git 仓库内该文件无改动
8
5
  */
9
- export declare function collectWorkspaceDiff(wsPath: string): Promise<WorkspaceDiff | null>;
6
+ export declare function collectFileDiff(wsPath: string, file: string): Promise<string | null>;