@jesonliu/lark-claudecode-bridge 1.0.4 → 1.0.6
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/assets/web/js/pages/larkcli-device.js +178 -44
- package/assets/web/js/pages/overview.js +45 -18
- package/assets/web/js/ui.js +5 -2
- package/dist/bin/lcb.js +5 -4
- package/dist/bin/lcb.js.map +1 -1
- package/dist/lark-cli-manager.d.ts +132 -15
- package/dist/lark-cli-manager.js +404 -60
- package/dist/lark-cli-manager.js.map +1 -1
- package/dist/web/server.js +20 -24
- package/dist/web/server.js.map +1 -1
- package/package.json +1 -1
|
@@ -74,15 +74,22 @@ export interface LarkCliSkillDetect {
|
|
|
74
74
|
/** 命中的 skill 目录名(首个) */
|
|
75
75
|
name?: string;
|
|
76
76
|
}
|
|
77
|
+
/** skill 目录扫描的注入点(测试用);缺省读真实文件系统 */
|
|
78
|
+
export interface SkillDirFs {
|
|
79
|
+
exists(p: string): boolean;
|
|
80
|
+
readdir(d: string): string[];
|
|
81
|
+
}
|
|
77
82
|
/**
|
|
78
|
-
*
|
|
83
|
+
* 列出已装的飞书官方 SKILL 目录名(默认 ~/.claude/skills,与安装动作同源)。
|
|
79
84
|
* 判据:目录名命中 feishu/lark **且** 内含 SKILL.md(防同名散目录误报)。
|
|
80
85
|
* managed 会话的可见性由 bridgeUserSkills() 启动桥接保证,这里不查托管目录。
|
|
86
|
+
*
|
|
87
|
+
* 以扫盘而非解析 `npx skills add` 的输出来确定「装了什么」:那份输出是带 ANSI 的
|
|
88
|
+
* 进度表,既难读也不可靠;目录才是既成事实。
|
|
81
89
|
*/
|
|
82
|
-
export declare function
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}): Promise<LarkCliSkillDetect>;
|
|
90
|
+
export declare function listLarkCliSkills(skillsDir?: string, fs?: SkillDirFs): Promise<string[]>;
|
|
91
|
+
/** 检测飞书官方 SKILL 是否已装:取扫盘结果的首个(保持既有返回结构不变) */
|
|
92
|
+
export declare function detectLarkCliSkill(skillsDir?: string, fs?: SkillDirFs): Promise<LarkCliSkillDetect>;
|
|
86
93
|
export interface InstallSkillOpts {
|
|
87
94
|
/** 覆盖 npx 执行(测试注入);缺省真实 runNpx */
|
|
88
95
|
runNpxFn?: (args: string[], timeoutMs: number) => Promise<string>;
|
|
@@ -103,17 +110,22 @@ export declare function installLarkCliSkill(timeoutMs?: number, opts?: InstallSk
|
|
|
103
110
|
* detail 的两个来源(error.subtype / reason)实测均含 not_configured 字样。
|
|
104
111
|
*/
|
|
105
112
|
export declare function needsLarkCliConfig(auth: LarkCliAuthStatus): boolean;
|
|
113
|
+
export interface StartupCheckDeps {
|
|
114
|
+
detect(): Promise<LarkCliDetect>;
|
|
115
|
+
detectSkill(): Promise<LarkCliSkillDetect>;
|
|
116
|
+
log(msg: string): void;
|
|
117
|
+
}
|
|
106
118
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
119
|
+
* 启动时的飞书 CLI 检查(依赖注入可测)——**只探测,绝不安装**。
|
|
120
|
+
*
|
|
121
|
+
* 安装统一下沉到 Web 配置页(用户决策):启动时静默装会让用户对安装过程无感,
|
|
122
|
+
* 也就跳过了官方流程的后三步(SKILL / config init / auth login)——等打开配置页时
|
|
123
|
+
* CLI 已就绪却从未配置过飞书应用,直接卡在「未授权」而无从下手;用户此时若自己点
|
|
124
|
+
* 「安装」,还会和后台那次抢 npm 文件锁。这里只把现状与去处讲清楚。
|
|
125
|
+
*
|
|
126
|
+
* **绝不抛出**:桥接器启动不能被外部工具的探测异常拖垮。
|
|
109
127
|
*/
|
|
110
|
-
export declare function
|
|
111
|
-
detect(): Promise<LarkCliDetect>;
|
|
112
|
-
install(log?: (msg: string) => void): Promise<string>;
|
|
113
|
-
log?: (msg: string) => void;
|
|
114
|
-
}): Promise<LarkCliDetect>;
|
|
115
|
-
/** 生产入口:console 反馈([lark-cli] 前缀),后台异步调用(lcb start 里 void + catch) */
|
|
116
|
-
export declare function ensureLarkCli(): Promise<LarkCliDetect>;
|
|
128
|
+
export declare function checkLarkCliAtStartup(deps?: Partial<StartupCheckDeps>): Promise<LarkCliDetect>;
|
|
117
129
|
export type LarkCliAuthState = 'authorized' | 'unauthorized' | 'unknown';
|
|
118
130
|
export interface LarkCliAuthStatus {
|
|
119
131
|
state: LarkCliAuthState;
|
|
@@ -269,7 +281,7 @@ export declare function cmdEscapeArg(s: string): string;
|
|
|
269
281
|
* cwd 设为专用 tmp 子目录:lark-cli 的写路径允许根是 cwd / /tmp / ~/files(实测 cwd 生效),
|
|
270
282
|
* 故 -o 用相对名即可落进允许根。
|
|
271
283
|
*/
|
|
272
|
-
export declare function defaultMakeQr(url: string, runner?: AuthRunner, log?: (m: string) => void, tmpDir?: string): Promise<string | undefined>;
|
|
284
|
+
export declare function defaultMakeQr(url: string, runner?: AuthRunner, log?: (m: string) => void, tmpDir?: string, fileName?: string): Promise<string | undefined>;
|
|
273
285
|
export interface LarkCliDeviceDeps {
|
|
274
286
|
runner: AuthRunner;
|
|
275
287
|
finishRunner: AuthRunner;
|
|
@@ -292,6 +304,107 @@ export declare function startLarkCliDeviceAuth(opts?: {
|
|
|
292
304
|
regenerate?: boolean;
|
|
293
305
|
deps?: Partial<LarkCliDeviceDeps>;
|
|
294
306
|
}): Promise<LarkCliDeviceSessionInfo>;
|
|
307
|
+
export type LarkCliConfigState = 'pending' | 'done' | 'failed' | 'expired' | 'none';
|
|
308
|
+
export interface LarkCliConfigSessionInfo {
|
|
309
|
+
ok: boolean;
|
|
310
|
+
state?: LarkCliConfigState;
|
|
311
|
+
verificationUrl?: string;
|
|
312
|
+
userCode?: string;
|
|
313
|
+
qrDataUrl?: string;
|
|
314
|
+
reused?: boolean;
|
|
315
|
+
error?: string;
|
|
316
|
+
/** 未安装——让前端把用户导到「安装」入口而不是干瞪眼 */
|
|
317
|
+
hint?: 'install';
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* 子进程最小结构(便于测试注入假实现)。
|
|
321
|
+
* 真实实现由 defaultConfigSpawn 把 node 的 ChildProcess 收窄成它。
|
|
322
|
+
*/
|
|
323
|
+
export interface LarkCliConfigChild {
|
|
324
|
+
stdout: {
|
|
325
|
+
on(ev: 'data', cb: (chunk: Buffer) => void): unknown;
|
|
326
|
+
} | null;
|
|
327
|
+
stderr: {
|
|
328
|
+
on(ev: 'data', cb: (chunk: Buffer) => void): unknown;
|
|
329
|
+
} | null;
|
|
330
|
+
on(ev: 'exit', cb: (code: number | null) => void): unknown;
|
|
331
|
+
on(ev: 'error', cb: (err: Error) => void): unknown;
|
|
332
|
+
}
|
|
333
|
+
export interface LarkCliConfigDeps {
|
|
334
|
+
spawn: (file: string, args: string[], opts: {
|
|
335
|
+
windowsHide: boolean;
|
|
336
|
+
env: NodeJS.ProcessEnv;
|
|
337
|
+
}) => LarkCliConfigChild;
|
|
338
|
+
detect(): Promise<LarkCliDetect>;
|
|
339
|
+
checkAuth(): Promise<LarkCliAuthStatus>;
|
|
340
|
+
makeQr(url: string): Promise<string | undefined>;
|
|
341
|
+
now(): number;
|
|
342
|
+
log(msg: string): void;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* 纯函数(可测):从 `config init --new` 的输出里提取授权链接。
|
|
346
|
+
*
|
|
347
|
+
* **真实输出形态尚未用真机钉死**(本机已配置,直接跑不带 --name 的 config init 会覆盖它;
|
|
348
|
+
* 抓取步骤见 docs/e2e-checklist.md 的「页面内配置应用」一节),因此解析刻意宽容,
|
|
349
|
+
* 三层依次退让,保证形态猜错时也只是退化成更弱的匹配、而不是彻底解析不出来:
|
|
350
|
+
* ① JSON(兼容 {ok,data} 信封与 verification_uri / console_url 等字段别名)
|
|
351
|
+
* ② 裸 URL(从散文里抓首个 http(s) 链接)
|
|
352
|
+
* ③ 折行 URL(输出方按显示宽度插了换行时的尽力补救)
|
|
353
|
+
*
|
|
354
|
+
* **URL 一律视为 opaque string**:不编码、不解码、不重拼 query——lark-cli 内置 skill 明文要求。
|
|
355
|
+
*/
|
|
356
|
+
export declare function extractConfigUrl(text: string): string | undefined;
|
|
357
|
+
export interface LarkCliConfigOutcome {
|
|
358
|
+
phase: 'done' | 'failed' | 'expired';
|
|
359
|
+
error?: string;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* 纯函数(可测):配置子进程结束后判定结果。
|
|
363
|
+
*
|
|
364
|
+
* **正向判据优先于退出码**:以「应用是否真的配置上了」为准(`!needsLarkCliConfig(authAfter)`),
|
|
365
|
+
* 而不是退出码——退出码 0 却什么都没配上,比直接报错更糟(用户以为配好了,下一步授权必然失败)。
|
|
366
|
+
*
|
|
367
|
+
* 判据还必须是**明确的**探测结果:`unknown`(探测失败)不算已配置,否则一次探测抖动
|
|
368
|
+
* 就会把没配上的机器报成配好了——这与 decideDeviceFinishOutcome 的「反向兜底绝不能有」同源。
|
|
369
|
+
*/
|
|
370
|
+
export declare function decideConfigOutcome(a: {
|
|
371
|
+
exitCode: number | null;
|
|
372
|
+
output: string;
|
|
373
|
+
spawnError?: string;
|
|
374
|
+
authAfter?: LarkCliAuthStatus;
|
|
375
|
+
}): LarkCliConfigOutcome;
|
|
376
|
+
/** 内存态查询(零副作用、亚毫秒)——撑住前端 2s 轮询 */
|
|
377
|
+
export declare function getLarkCliConfigStatus(now?: number): LarkCliConfigSessionInfo;
|
|
378
|
+
/**
|
|
379
|
+
* 放弃当前配置会话(改用终端 / 新一轮发起前)。
|
|
380
|
+
* **不 kill 子进程**——与 abandonLarkCliDeviceSession 同源:Windows 上
|
|
381
|
+
* cmd → node → lark-cli.exe 的进程树 kill 会留孤儿,靠 gen 失配丢弃结果即可,
|
|
382
|
+
* 孤儿最多空转到 registration 过期后自行退出。
|
|
383
|
+
*/
|
|
384
|
+
export declare function abandonLarkCliConfigSession(): void;
|
|
385
|
+
/** 重置配置会话状态(测试用) */
|
|
386
|
+
export declare function resetLarkCliConfigState(): void;
|
|
387
|
+
/** 生产 spawn:stdin 接 /dev/null——官方要求「后台运行」,此路无人在终端应答交互输入 */
|
|
388
|
+
export declare const defaultConfigSpawn: (file: string, args: string[], opts: {
|
|
389
|
+
windowsHide: boolean;
|
|
390
|
+
env: NodeJS.ProcessEnv;
|
|
391
|
+
}) => LarkCliConfigChild;
|
|
392
|
+
/**
|
|
393
|
+
* 发起「配置应用」流程(页面二维码的主入口)。
|
|
394
|
+
*
|
|
395
|
+
* 四道闸与 startLarkCliDeviceAuth 同构:
|
|
396
|
+
* ① 幂等复用:pending 会话直接返回(挡住刷新页面 / 关弹窗再开)
|
|
397
|
+
* ② in-flight 合并:并发调用 await 同一个 promise(挡住双击)
|
|
398
|
+
* ③ regenerate:用户显式要求时才新建
|
|
399
|
+
* ④ gen 代号:新建时 +1,在飞的老子进程靠它丢弃过期结果
|
|
400
|
+
*
|
|
401
|
+
* 与设备流的一处**有意不同**:没有「剩余不足 X 秒就换新」——CLI 不吐有效期,
|
|
402
|
+
* 我们也就无从编造倒计时;会话的终结一律由子进程退出(或 CONFIG_URL_WAIT_MS 兜底)驱动。
|
|
403
|
+
*/
|
|
404
|
+
export declare function startLarkCliConfigFlow(opts?: {
|
|
405
|
+
regenerate?: boolean;
|
|
406
|
+
deps?: Partial<LarkCliConfigDeps>;
|
|
407
|
+
}): Promise<LarkCliConfigSessionInfo>;
|
|
295
408
|
export type LarkCliOp = 'install' | 'update' | 'auth' | 'config' | 'skill';
|
|
296
409
|
export interface LarkCliActionResult {
|
|
297
410
|
ok: boolean;
|
|
@@ -301,6 +414,8 @@ export interface LarkCliActionResult {
|
|
|
301
414
|
terminal?: string;
|
|
302
415
|
scriptPath?: string;
|
|
303
416
|
output?: string;
|
|
417
|
+
/** skill op 专用:装完后扫盘得到的 SKILL 名单(前端列清单用,比 npx 原始输出可靠) */
|
|
418
|
+
skills?: string[];
|
|
304
419
|
/** 为何没用终端(降级说明,前端展示用) */
|
|
305
420
|
reason?: string;
|
|
306
421
|
error?: string;
|
|
@@ -312,6 +427,8 @@ export interface LarkCliActionDeps {
|
|
|
312
427
|
install(): Promise<string>;
|
|
313
428
|
/** SKILL 静默安装(op:'skill');缺省真实 installLarkCliSkill */
|
|
314
429
|
installSkill(): Promise<string>;
|
|
430
|
+
/** SKILL 装完后的落盘扫描(op:'skill' 回传名单用);缺省真实 listLarkCliSkills */
|
|
431
|
+
listSkills(): Promise<string[]>;
|
|
315
432
|
/** 授权/配置态探测:config op 用它拒绝重复向导;install op 用它决定脚本是否插 config init 段 */
|
|
316
433
|
checkAuth(): Promise<LarkCliAuthStatus>;
|
|
317
434
|
launch(task: TerminalTask, opts?: {
|