@vibe-lark/larkpal 0.1.83 → 0.1.85

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 CHANGED
@@ -1,7 +1,59 @@
1
+ # LarkPal
2
+
3
+ LarkPal connects Lark/Feishu conversations to agent runtimes. The first setup path is now organized around Feishu's Agent integration layers:
4
+
5
+ 1. **凭据层**:用飞书官方扫码创建应用能力获取 App ID 和 App Secret。
6
+ 2. **交互层**:LarkPal 的 Feishu channel 接收消息、评论、卡片交互并流式回复。
7
+ 3. **执行层**:飞书 CLI 作为 Agent 操作文档、日历、表格、邮件、任务等业务对象的工具来源。
8
+
9
+ > Agent 协作入口:先读 [AGENTS.md](./AGENTS.md),再按 [agent-workspace/INDEX.md](./agent-workspace/INDEX.md) 选择相关领域文档。
10
+
11
+ ## 快速开始
12
+
13
+ ### 1. 安装依赖
14
+
15
+ ```bash
16
+ pnpm install
17
+ pnpm -s build
18
+ ```
19
+
20
+ 运行服务时仍需要一个 agent runtime:
21
+
22
+ ```bash
23
+ npm install -g @anthropic-ai/claude-code
24
+ ```
25
+
26
+ 如果使用 Codex app-server runtime,请安装并配置 Codex CLI,并设置 `LARKPAL_RUNTIME=codex-app-server`。
27
+
28
+ ### 2. 连接飞书
29
+
30
+ ```bash
31
+ pnpm start -- init
32
+ ```
33
+
34
+ 初始化向导默认使用飞书官方一键创建应用能力。用户打开或扫码向导中的链接后,LarkPal 会收到并保存 App ID 和 App Secret;不需要去飞书开发者后台手动复制 App Secret。
35
+
36
+ 也可以选择手动输入 App ID/App Secret,或使用旧的 `lark-cli config init` 兼容流程。
37
+
38
+ ### 3. 按需授权执行层
39
+
40
+ 基础飞书 bot 会话只需要应用凭据。只有当 Agent 需要以用户身份访问个人日历、私信、云文档、邮箱等数据时,才需要飞书 CLI 用户授权:
41
+
42
+ ```bash
43
+ npx @larksuite/cli@latest install
44
+ lark-cli auth login
45
+ ```
46
+
47
+ 这一步属于执行层,不是应用凭据配置的一部分。
48
+
49
+ ---
50
+
1
51
  # LarkPal 外部接入规范
2
52
 
3
53
  本文档描述外部业务方接入 LarkPal 平台时需遵循的协议和配置规范。
4
54
 
55
+ > Agent 协作入口:先读 [AGENTS.md](./AGENTS.md),再按 [agent-workspace/INDEX.md](./agent-workspace/INDEX.md) 选择相关领域文档。
56
+
5
57
  ---
6
58
 
7
59
  ## 目录
@@ -225,6 +277,12 @@ interface RuntimeAdapter {
225
277
  // 查询会话进程信息
226
278
  getProcessInfo(sessionId: string): RuntimeProcessInfo | undefined;
227
279
  getAllProcessInfo(): RuntimeProcessInfo[];
280
+
281
+ // 可选能力契约:上层通过能力判断是否展示交互入口
282
+ getCapabilities?(): RuntimeCapabilities;
283
+ getLastUserMessageId?(sessionId: string): string | undefined;
284
+ previewRewind?(params: RuntimeRewindParams): Promise<RuntimeRewindPreview>;
285
+ confirmRewind?(params: RuntimeRewindParams): Promise<RuntimeRewindResult>;
228
286
  }
229
287
  ```
230
288
 
@@ -263,9 +321,18 @@ interface RuntimeStreamCallbacks {
263
321
 
264
322
  ```bash
265
323
  LARKPAL_RUNTIME=claude-code # 默认,使用 Claude Code 子进程
324
+ LARKPAL_RUNTIME=codex-app-server # 使用 OpenAI Codex app-server
266
325
  LARKPAL_RUNTIME=larkpal-agent # 使用 larkpal-agent 引擎(火山方舟 LLM)
267
326
  ```
268
327
 
328
+ Runtime 能力矩阵:
329
+
330
+ | Runtime | 流式回复 | 多模态输入 | 停止当前任务 | 交互卡片续跑 | 文件撤销 |
331
+ |---------|----------|------------|--------------|--------------|----------|
332
+ | `claude-code` | 支持 | 支持 | 支持 | 支持 | 支持 |
333
+ | `codex-app-server` | 支持 | 支持 | 支持 | 支持 | 支持 |
334
+ | `larkpal-agent` | 支持 | 由 agent/provider 决定 | 支持 | 支持 | 暂不支持 |
335
+
269
336
  使用 `larkpal-agent` 时的完整配置示例:
270
337
 
271
338
  ```bash
@@ -278,7 +345,7 @@ LARKPAL_AGENT_MAX_TURNS=25
278
345
 
279
346
  **工具发现**:由 larkpal-agent 自身的 MCP Client 负责。larkpal-agent 启动时自动连接配置的 MCP Server,发现并注册外部工具。larkpal 平台层不涉及工具层。
280
347
 
281
- **systemPrompt 来源**:读取 `~/.claude/CLAUDE.md` 文件内容。可通过修改此文件自定义 Agent 人设。
348
+ **人设 / system instructions 来源**:LarkPal 以飞书应用信息和人设文档为唯一来源,同步到 runtime 各自能读取的指令文件。Claude Code 读取 `~/.claude/CLAUDE.md` 和会话目录 `CLAUDE.md`;Codex 读取 workspace / 会话目录中的 `AGENTS.md`,内容由 LarkPal 从同一份人设自动镜像生成。
282
349
 
283
350
  ---
284
351
 
package/dist/cli.mjs CHANGED
@@ -34,12 +34,22 @@ ${BOLD}LarkPal${RESET} ${DIM}v${version}${RESET} — 飞书 AI Bot 服务
34
34
  ${BOLD}用法:${RESET}
35
35
  larkpal 启动服务
36
36
  larkpal init 交互式初始化向导
37
+ larkpal meeting-live-smoke --meeting-number <number>
38
+ 实验:固定文本进入飞书会议语音链路
39
+ 可加 --listen-ms <ms> --raw-output <path> --summary-output <path>
40
+ larkpal meeting-live-teammate --meeting-number <number> --owner-user-id <id>
41
+ 实验:实时听会转写后用 teammate 策略语音参与
42
+ 可加 --summary-output <path> 留存脱敏运行摘要
43
+ larkpal meeting-live-check
44
+ 实验:检查会议语音链路 TTS/ASR 配置,不入会
45
+ 可加 --summary-output <path> 留存脱敏检查结果
37
46
  larkpal --help 显示帮助信息
38
47
  larkpal --version 显示版本号
39
48
 
40
49
  ${BOLD}环境变量:${RESET}
41
50
  LARK_APP_ID 飞书应用 App ID(可选,覆盖 lark-cli 配置)
42
51
  LARK_APP_SECRET 飞书应用 App Secret(可选,覆盖 lark-cli 配置)
52
+ LARK_USER_ACCESS_TOKEN 飞书用户访问令牌(会议实验能力需要)
43
53
  LARKPAL_WORKSPACE 工作目录根路径(默认 ~/.larkpal/workspace)
44
54
  CLAUDE_MODEL Claude 模型名称(如 ark-code-latest)
45
55
 
@@ -47,7 +57,8 @@ ${DIM}首次使用?运行 ${CYAN}larkpal init${DIM} 开始配置。${RESET}
47
57
  `);
48
58
  }
49
59
  async function cli() {
50
- const command = process.argv.slice(2)[0];
60
+ const args = process.argv.slice(2);
61
+ const command = args[0];
51
62
  if (command === "--version" || command === "-v") {
52
63
  console.log(getVersion());
53
64
  return;
@@ -57,21 +68,36 @@ async function cli() {
57
68
  return;
58
69
  }
59
70
  if (command === "init") {
60
- const { runInteractiveInit } = await import("./interactive-init-BYF2-otj.mjs");
71
+ const { runInteractiveInit } = await import("./interactive-init-B6j8j_Ap.mjs");
61
72
  const exitCode = await runInteractiveInit();
62
73
  process.exit(exitCode);
63
74
  }
75
+ if (command === "meeting-live-smoke") {
76
+ const { runMeetingLiveSmokeCli } = await import("./live-smoke-nvTUPtrv.mjs").then((n) => n.t);
77
+ await runMeetingLiveSmokeCli(args.slice(1));
78
+ return;
79
+ }
80
+ if (command === "meeting-live-teammate") {
81
+ const { runMeetingLiveTeammateCli } = await import("./live-smoke-nvTUPtrv.mjs").then((n) => n.t);
82
+ await runMeetingLiveTeammateCli(args.slice(1));
83
+ return;
84
+ }
85
+ if (command === "meeting-live-check") {
86
+ const { runMeetingLiveCheckCli } = await import("./live-smoke-nvTUPtrv.mjs").then((n) => n.t);
87
+ const exitCode = await runMeetingLiveCheckCli(args.slice(1));
88
+ process.exit(exitCode);
89
+ }
64
90
  if (command && !command.startsWith("-")) {
65
91
  console.log(`${YELLOW}未知命令: ${command}${RESET}\n`);
66
92
  printHelp();
67
93
  process.exit(1);
68
94
  }
69
95
  if (!(process.env.LARKPAL_HEADLESS === "1" || process.env.LARKPAL_HEADLESS === "true")) {
70
- const { LarkCliCredentialProvider } = await import("./lark-cli-provider-CdgwmqSz.mjs").then((n) => n.n);
96
+ const { LarkCliCredentialProvider } = await import("./lark-cli-provider-7LvtOIF_.mjs").then((n) => n.n);
71
97
  if (!LarkCliCredentialProvider.isConfigured()) {
72
98
  console.log(`\n${YELLOW}⚠️ 飞书应用凭证未配置${RESET}\n`);
73
99
  console.log(` LarkPal 需要飞书应用凭证才能启动。正在进入初始化向导...\n`);
74
- const { runInteractiveInit } = await import("./interactive-init-BYF2-otj.mjs");
100
+ const { runInteractiveInit } = await import("./interactive-init-B6j8j_Ap.mjs");
75
101
  const exitCode = await runInteractiveInit();
76
102
  if (exitCode !== 0) process.exit(exitCode);
77
103
  console.log(`${DIM}凭证配置完成,正在启动服务...${RESET}\n`);
@@ -4,6 +4,124 @@ import { join } from "node:path";
4
4
  import { homedir } from "node:os";
5
5
  import { execSync, spawn } from "node:child_process";
6
6
  import { createInterface } from "node:readline";
7
+ import * as Lark from "@larksuiteoapi/node-sdk";
8
+ import qrcodeTerminal from "qrcode-terminal";
9
+ //#region src/credentials/app-registration.ts
10
+ async function registerFeishuAppCredentials(options) {
11
+ const result = await (options.registerApp ?? defaultRegisterApp)({
12
+ source: options.source ?? "larkpal",
13
+ signal: options.signal,
14
+ onQRCodeReady: options.onQRCodeReady,
15
+ onStatusChange: options.onStatusChange
16
+ });
17
+ if (!result.client_id || !result.client_secret) throw new Error("飞书应用创建完成但未返回 App ID 或 App Secret");
18
+ await options.saveCredentials({
19
+ appId: result.client_id,
20
+ appSecret: result.client_secret
21
+ });
22
+ return {
23
+ appId: result.client_id,
24
+ appSecret: result.client_secret,
25
+ creatorOpenId: result.user_info?.open_id,
26
+ tenantBrand: result.user_info?.tenant_brand
27
+ };
28
+ }
29
+ async function defaultRegisterApp(options) {
30
+ return Lark.registerApp(options);
31
+ }
32
+ //#endregion
33
+ //#region src/init/landing-presentation.ts
34
+ function renderFeishuAppCreationQRCode(input) {
35
+ return [
36
+ " 请扫码创建飞书智能体应用,或打开下面的链接:",
37
+ "",
38
+ renderQRCodeOrFallback(input.url, input.createQRCode ?? createQRCode),
39
+ ` ${input.url}`,
40
+ ` 链接有效期 ${input.expireIn} 秒。`
41
+ ].join("\n");
42
+ }
43
+ function formatRuntimeSelectionSummary(runtimeName) {
44
+ switch (runtimeName) {
45
+ case "codex-app-server": return [
46
+ "已选择 Codex app-server 作为 agent runtime。",
47
+ "启动前请确保 Codex CLI 可用:codex",
48
+ "启动配置:LARKPAL_RUNTIME=codex-app-server"
49
+ ].join("\n");
50
+ case "larkpal-agent": return [
51
+ "已选择 larkpal-agent 作为 agent runtime。",
52
+ "启动前请配置 larkpal-agent 所需的 LLM 和 scenario provider 环境变量。",
53
+ "启动配置:LARKPAL_RUNTIME=larkpal-agent"
54
+ ].join("\n");
55
+ case "claude-code": return [
56
+ "已选择 Claude Code 作为 agent runtime。",
57
+ "启动前请确保 Claude Code CLI 可用:claude",
58
+ "启动配置:LARKPAL_RUNTIME=claude-code"
59
+ ].join("\n");
60
+ }
61
+ }
62
+ function renderRuntimeSelectionPrompt(currentRuntime) {
63
+ return [
64
+ "Agent runtime 选择",
65
+ "",
66
+ ` [1] Claude Code (claude-code)${currentRuntime === "claude-code" ? "(当前)" : ""}`,
67
+ ` [2] Codex app-server (codex-app-server)${currentRuntime === "codex-app-server" ? "(当前)" : ""}`,
68
+ ` [3] larkpal-agent${currentRuntime === "larkpal-agent" ? "(当前)" : ""}`
69
+ ].join("\n");
70
+ }
71
+ function resolveRuntimeSelection(choice, currentRuntime) {
72
+ const normalized = choice.trim().toLowerCase();
73
+ if (!normalized) return currentRuntime;
74
+ if (normalized === "1" || normalized === "claude" || normalized === "claude-code") return "claude-code";
75
+ if (normalized === "2" || normalized === "codex" || normalized === "codex-app-server") return "codex-app-server";
76
+ if (normalized === "3" || normalized === "larkpal-agent") return "larkpal-agent";
77
+ return currentRuntime;
78
+ }
79
+ function createQRCode(url) {
80
+ let qrCode = "";
81
+ qrcodeTerminal.setErrorLevel("L");
82
+ qrcodeTerminal.generate(url, { small: true }, (code) => {
83
+ qrCode = code;
84
+ });
85
+ return qrCode.trimEnd();
86
+ }
87
+ function renderQRCodeOrFallback(url, renderer) {
88
+ try {
89
+ return renderer(url).trimEnd() || " [二维码渲染失败,请使用下方链接]";
90
+ } catch {
91
+ return " [二维码渲染失败,请使用下方链接]";
92
+ }
93
+ }
94
+ //#endregion
95
+ //#region src/init/prerequisites.ts
96
+ function assessInitPrerequisites(deps) {
97
+ const larkCli = deps.detectCli("lark-cli");
98
+ const runtimeCliName = resolveRuntimeCliName(deps.runtimeName);
99
+ const runtimeCli = runtimeCliName ? deps.detectCli(runtimeCliName) : { installed: true };
100
+ const warnings = [];
101
+ if (runtimeCliName && !runtimeCli.installed) warnings.push(runtimeCliName === "codex" ? "OpenAI Codex CLI is not installed. Feishu app credentials can still be configured now, but service startup with LARKPAL_RUNTIME=codex-app-server will require codex later." : "Claude Code is not installed. Feishu app credentials can still be configured now, but service startup with the default runtime will require Claude Code later.");
102
+ if (!larkCli.installed) warnings.push("lark-cli is not installed. Basic Feishu bot chat can be configured with app credentials, but execution-layer tools for documents, calendars, mail, tasks, and personal data will require lark-cli later.");
103
+ return {
104
+ canConfigureFeishuCredentials: true,
105
+ larkCli: {
106
+ ...larkCli,
107
+ ready: larkCli.installed,
108
+ requiredForBasicChat: false
109
+ },
110
+ runtime: {
111
+ ...runtimeCli,
112
+ ready: runtimeCli.installed,
113
+ name: deps.runtimeName,
114
+ cliName: runtimeCliName ?? deps.runtimeName
115
+ },
116
+ warnings
117
+ };
118
+ }
119
+ function resolveRuntimeCliName(runtimeName) {
120
+ if (runtimeName === "codex-app-server") return "codex";
121
+ if (runtimeName === "larkpal-agent") return void 0;
122
+ return "claude";
123
+ }
124
+ //#endregion
7
125
  //#region src/init/interactive-init.ts
8
126
  /**
9
127
  * 交互式初始化流程
@@ -88,6 +206,9 @@ function writeCredentials(appId, appSecret) {
88
206
  return false;
89
207
  }
90
208
  }
209
+ async function saveCredentialsOrThrow(credentials) {
210
+ if (!writeCredentials(credentials.appId, credentials.appSecret)) throw new Error("凭证保存失败");
211
+ }
91
212
  /** 检查 LarkPal 凭证文件是否已有有效凭证 */
92
213
  function hasLarkPalCredentials() {
93
214
  if (!existsSync(LARKPAL_CREDENTIALS_PATH)) return null;
@@ -101,30 +222,29 @@ function hasLarkPalCredentials() {
101
222
  } catch {}
102
223
  return null;
103
224
  }
104
- function checkPrerequisites() {
225
+ function checkPrerequisites(runtimeName) {
105
226
  console.log(`\n${BOLD}🔍 检查前置依赖${RESET}\n`);
106
- if (isCliInstalled("claude")) console.log(` ${GREEN}✅ claude 已安装${RESET}`);
107
- else {
108
- console.log(` ${RED}❌ claude 未安装${RESET}`);
109
- console.log(`\n Claude Code 是 LarkPal 的 AI 推理引擎,必须安装。`);
110
- console.log(` ${DIM}安装命令:${RESET} npm install -g @anthropic-ai/claude-code`);
111
- console.log(` ${DIM}文档:${RESET} https://docs.anthropic.com/en/docs/claude-code\n`);
112
- log.error("前置依赖检查失败: claude 未安装");
113
- return false;
114
- }
115
- if (isCliInstalled("lark-cli")) console.log(` ${GREEN}✅ lark-cli 已安装${RESET}`);
116
- else {
117
- console.log(` ${RED}❌ lark-cli 未安装${RESET}`);
118
- console.log(`\n lark-cli 提供飞书原生能力和凭证管理,必须安装。`);
119
- console.log(` ${DIM}安装命令:${RESET}`);
120
- console.log(` npm install -g @larksuite/cli`);
121
- console.log(` npx skills add larksuite/cli -y -g`);
122
- console.log(` ${DIM}文档:${RESET} https://github.com/larksuite/cli\n`);
123
- log.error("前置依赖检查失败: lark-cli 未安装");
124
- return false;
125
- }
227
+ const assessment = assessInitPrerequisites({
228
+ runtimeName,
229
+ detectCli: (name) => ({ installed: isCliInstalled(name) })
230
+ });
231
+ if (assessment.runtime.ready) console.log(` ${GREEN}✅ ${assessment.runtime.cliName} 已安装${RESET}`);
232
+ else console.log(` ${YELLOW}⚠️ ${assessment.runtime.cliName} 未安装${RESET}`);
233
+ if (assessment.larkCli.ready) console.log(` ${GREEN}✅ lark-cli 已安装${RESET}`);
234
+ else console.log(` ${YELLOW}⚠️ lark-cli 未安装(基础飞书连接不阻塞)${RESET}`);
235
+ for (const warning of assessment.warnings) console.log(` ${DIM}${warning}${RESET}`);
126
236
  console.log();
127
- return true;
237
+ }
238
+ async function configureRuntime(rl) {
239
+ const currentRuntime = resolveConfiguredRuntime(process.env.LARKPAL_RUNTIME);
240
+ console.log(`\n${BOLD}🤖 Agent runtime 配置${RESET}\n`);
241
+ console.log(renderRuntimeSelectionPrompt(currentRuntime));
242
+ console.log();
243
+ const selectedRuntime = resolveRuntimeSelection(await ask(rl, ` 请选择 [1/2/3](默认当前): `), currentRuntime);
244
+ process.env.LARKPAL_RUNTIME = selectedRuntime;
245
+ console.log(`\n${formatRuntimeSelectionSummary(selectedRuntime)}\n`);
246
+ log.info("用户选择 agent runtime", { runtimeName: selectedRuntime });
247
+ return selectedRuntime;
128
248
  }
129
249
  /**
130
250
  * 通过 lark-cli config init 子进程配置凭证。
@@ -219,6 +339,34 @@ async function manualCredentialInput(rl) {
219
339
  console.log(`\n${RED}凭证保存失败${RESET}`);
220
340
  return false;
221
341
  }
342
+ async function scanCreateAppCredentials() {
343
+ console.log(`\n${BOLD}📱 扫码创建飞书智能体应用${RESET}\n`);
344
+ console.log(` LarkPal 会通过飞书官方一键创建应用能力获取 App ID 和 App Secret。`);
345
+ console.log(` ${DIM}这一步只配置应用凭据;个人日历、文档、邮件等能力后续通过 lark-cli auth login 授权。${RESET}\n`);
346
+ try {
347
+ const result = await registerFeishuAppCredentials({
348
+ saveCredentials: saveCredentialsOrThrow,
349
+ onQRCodeReady: ({ url, expireIn }) => {
350
+ console.log(renderFeishuAppCreationQRCode({
351
+ url,
352
+ expireIn
353
+ }));
354
+ console.log();
355
+ },
356
+ onStatusChange: ({ status }) => {
357
+ if (status === "polling") console.log(` ${DIM}等待飞书确认中...${RESET}`);
358
+ else if (status === "slow_down") console.log(` ${DIM}飞书要求降低轮询频率,继续等待...${RESET}`);
359
+ else if (status === "domain_switched") console.log(` ${DIM}已根据租户切换认证域名,继续等待...${RESET}`);
360
+ },
361
+ source: "larkpal-init"
362
+ });
363
+ console.log(`\n${GREEN}✅ 飞书应用创建并保存成功${RESET} ${DIM}(App ID: ${result.appId})${RESET}`);
364
+ return true;
365
+ } catch (err) {
366
+ console.log(`\n${RED}扫码创建飞书应用失败: ${err instanceof Error ? err.message : String(err)}${RESET}`);
367
+ return false;
368
+ }
369
+ }
222
370
  async function configureCredentials(rl) {
223
371
  if (process.env.LARK_APP_ID && process.env.LARK_APP_SECRET) {
224
372
  console.log(`${GREEN}✅ 飞书应用凭证已通过环境变量配置${RESET}`);
@@ -238,14 +386,20 @@ async function configureCredentials(rl) {
238
386
  return promptAppSecret(rl, existingAppId);
239
387
  }
240
388
  console.log(`${BOLD}📋 飞书应用配置${RESET}\n`);
241
- console.log(` LarkPal 需要飞书应用凭证才能运行。推荐通过 lark-cli 一键配置:\n`);
242
- console.log(` ${CYAN}👉 运行: lark-cli config init${RESET}\n`);
243
- console.log(` 这会打开浏览器,引导你在飞书开放平台完成应用配置。\n`);
244
- console.log(` ${DIM}[1] 运行 lark-cli config init(推荐)${RESET}`);
245
- console.log(` ${DIM}[2] 手动输入 App ID 和 App Secret${RESET}\n`);
246
- const option = await ask(rl, ` 请选择 [1/2](默认 1): `) === "2" ? 2 : 1;
389
+ console.log(` LarkPal 需要飞书应用凭据才能进入飞书会话。推荐使用飞书官方扫码创建应用能力:\n`);
390
+ console.log(` ${DIM}[1] 扫码创建飞书智能体应用(推荐)${RESET}`);
391
+ console.log(` ${DIM}[2] 手动输入 App ID 和 App Secret${RESET}`);
392
+ console.log(` ${DIM}[3] 使用 lark-cli config init(兼容旧流程)${RESET}\n`);
393
+ const choice = await ask(rl, ` 请选择 [1/2/3](默认 1): `);
394
+ const option = choice === "2" ? 2 : choice === "3" ? 3 : 1;
247
395
  log.info("用户选择凭证配置方式", { option });
248
396
  if (option === 1) {
397
+ if (await scanCreateAppCredentials()) return true;
398
+ console.log(`\n ${YELLOW}扫码创建未完成,是否手动输入凭证?${RESET}`);
399
+ if ((await ask(rl, ` 手动输入? [y/N]: `)).toLowerCase() === "y") return manualCredentialInput(rl);
400
+ return false;
401
+ }
402
+ if (option === 3) {
249
403
  const appId = await runLarkCliConfigInit();
250
404
  if (appId) return promptAppSecret(rl, appId);
251
405
  console.log(`\n ${YELLOW}lark-cli 配置未成功,是否手动输入凭证?${RESET}`);
@@ -264,16 +418,15 @@ async function runInteractiveInit() {
264
418
  console.log(`${BOLD}${CYAN}║ LarkPal 初始化向导 ║${RESET}`);
265
419
  console.log(`${BOLD}${CYAN}╚══════════════════════════════════════╝${RESET}\n`);
266
420
  log.info("开始交互式初始化流程");
267
- if (!checkPrerequisites()) {
268
- console.log(`${RED}请安装缺失的依赖后重新运行 ${CYAN}larkpal init${RESET}\n`);
269
- return 1;
270
- }
271
421
  const rl = createInterface({
272
422
  input: process.stdin,
273
423
  output: process.stdout
274
424
  });
275
- let credentialsOk = false;
425
+ let credentialsOk;
426
+ let selectedRuntime;
276
427
  try {
428
+ selectedRuntime = await configureRuntime(rl);
429
+ checkPrerequisites(selectedRuntime);
277
430
  credentialsOk = await configureCredentials(rl);
278
431
  } finally {
279
432
  rl.close();
@@ -284,9 +437,14 @@ async function runInteractiveInit() {
284
437
  }
285
438
  console.log(`\n${BOLD}${GREEN}🎉 初始化完成!${RESET}\n`);
286
439
  console.log(` ${DIM}下一步:${RESET}`);
440
+ console.log(` ${formatRuntimeSelectionSummary(selectedRuntime)}`);
287
441
  console.log(` 运行 ${CYAN}larkpal${RESET} 启动服务\n`);
288
442
  log.info("交互式初始化流程完成");
289
443
  return 0;
290
444
  }
445
+ function resolveConfiguredRuntime(value) {
446
+ if (value === "codex-app-server" || value === "larkpal-agent" || value === "claude-code") return value;
447
+ return "claude-code";
448
+ }
291
449
  //#endregion
292
450
  export { runInteractiveInit };
@@ -1,21 +1,10 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-wcPFST8Q.mjs";
1
2
  import { t as larkLogger } from "./lark-logger-D7_pEVQc.mjs";
2
3
  import { existsSync, readFileSync } from "node:fs";
3
4
  import { join } from "node:path";
4
5
  import { homedir } from "node:os";
5
6
  import { execSync } from "node:child_process";
6
7
  import { createHash } from "node:crypto";
7
- //#region \0rolldown/runtime.js
8
- var __defProp = Object.defineProperty;
9
- var __exportAll = (all, no_symbols) => {
10
- let target = {};
11
- for (var name in all) __defProp(target, name, {
12
- get: all[name],
13
- enumerable: true
14
- });
15
- if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
16
- return target;
17
- };
18
- //#endregion
19
8
  //#region src/credentials/lark-cli-provider.ts
20
9
  /**
21
10
  * 飞书应用凭证提供者
@@ -121,18 +110,21 @@ var LarkCliCredentialProvider = class LarkCliCredentialProvider {
121
110
  else log.warn("未找到 lark-cli(应由 preflight 检查保证安装)");
122
111
  const envAppId = process.env.LARK_APP_ID;
123
112
  const envAppSecret = process.env.LARK_APP_SECRET;
113
+ const envUserAccessToken = process.env.LARK_USER_ACCESS_TOKEN;
124
114
  let cliConfig = {};
125
- const larkpalCreds = this.loadFromLarkPalCredentials();
126
- if (larkpalCreds?.appId && larkpalCreds?.appSecret) cliConfig = larkpalCreds;
127
- else if (this.larkCliPath) try {
128
- cliConfig = this.loadFromCli();
129
- } catch (err) {
130
- log.warn("从 lark-cli 读取配置失败,将使用环境变量", { error: err instanceof Error ? err.message : String(err) });
115
+ if (!envAppId || !envAppSecret) {
116
+ const larkpalCreds = this.loadFromLarkPalCredentials();
117
+ if (larkpalCreds?.appId && larkpalCreds?.appSecret) cliConfig = larkpalCreds;
118
+ else if (this.larkCliPath) try {
119
+ cliConfig = this.loadFromCli();
120
+ } catch (err) {
121
+ log.warn("从 lark-cli 读取配置失败,将使用环境变量", { error: err instanceof Error ? err.message : String(err) });
122
+ }
131
123
  }
132
124
  this.appId = envAppId ?? cliConfig.appId ?? "";
133
125
  this.appSecret = envAppSecret ?? cliConfig.appSecret ?? "";
134
126
  this.tenantAccessToken = cliConfig.tenant_access_token ?? "";
135
- this.userAccessToken = cliConfig.user_access_token ?? "";
127
+ this.userAccessToken = envUserAccessToken ?? cliConfig.user_access_token ?? "";
136
128
  if (!this.appId) {
137
129
  const msg = [
138
130
  "无法获取飞书应用凭证 (app_id)",