@leviyuan/lodestar 0.18.3 → 0.18.5

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
@@ -15,7 +15,7 @@ AI 不是帮手,是倍率。它放大的不是体力,是你 —— 你的直
15
15
  - **发条消息,就能开工**:在飞书里把任务交给 Codex、Claude Code 或 DeepSeek Harness,让 Agent 在你的项目里读代码、改文件、跑命令。
16
16
  - **一个群,一个项目**:工作目录和对话跟着项目走;手头几个项目来回切换,回到群里就能接着上次的思路继续。
17
17
  - **进展看得见,问题直接答**:回复、工具调用、图片和后台进展都在卡片里,需要你补充信息时,就在群里回答。
18
- - **趁手的模型,自己选**:Codex 订阅、GLM Coding Plan、DeepSeek、OpenRouter 和 Claude native 都能接入;在群里切换[账号、模型与推理档位](docs/models.md),每个项目记住自己的选择。
18
+ - **趁手的模型,自己选**:Codex 订阅、Claude Code 订阅、GLM Coding Plan、DeepSeek、OpenRouter 和 Claude native 都能接入;在群里切换[账号、模型与推理档位](docs/models.md),每个项目记住自己的选择。
19
19
 
20
20
  ## 快速开始
21
21
 
@@ -126,7 +126,7 @@ ${V.bold}${V.cyan}╔${Q}╗${V.reset}`),console.log(`${V.bold}${V.cyan}║ ${A
126
126
  `)}function CY(A,Q,B){console.log(`
127
127
  ${V.bold}${V.yellow}[${A}/${Q}] ${B}${V.reset}
128
128
  `)}function BN(A){return A.replace(/\\/g,"\\\\").replace(/"/g,"\\\"")}function VH(A){try{let Q=Bm(A,["login","status"],{timeout:1e4,shell:process.platform==="win32"}).toString();return/Logged in using ChatGPT/i.test(Q)}catch{return!1}}async function Ym(A){return new Promise((Q)=>{let B=WH.spawn(A,["login"],{stdio:"inherit",shell:!1});B.on("exit",(I)=>Q(I===0)),B.on("error",()=>Q(!1))})}function Um(){return process.env.CLAUDE_CONFIG_DIR||EN(gm(),".claude")}async function Jm(A){try{let Q=await JF("https://open.bigmodel.cn/api/anthropic/v1/models",{headers:{Authorization:`Bearer ${A}`},signal:AbortSignal.timeout(1e4)});if(!Q.ok)return null;let B=await Q.json(),I=(Array.isArray(B?.data)?B.data:[]).map((M)=>typeof M?.display_name==="string"&&M.display_name?M.display_name:String(M?.id??"")).filter(Boolean);if(!I.length)return null;let E=(M)=>{let w=M.match(/(\d+(?:\.\d+)?)/);return w?Number(w[1]):-1},g=(M)=>M.replace(/-Turbo|-Air$/i,""),Y=[...I.filter((M)=>!/-Turbo|-Air/i.test(M))].sort((M,w)=>E(w)-E(M)),U=Y[0],N=Y[Y.length-1],G={};if(U)G.ANTHROPIC_DEFAULT_OPUS_MODEL=`${U}[1m]`,G.ANTHROPIC_DEFAULT_SONNET_MODEL=`${U}[1m]`;if(N&&g(N)!==g(U))G.ANTHROPIC_DEFAULT_HAIKU_MODEL=N;return Object.keys(G).length?G:null}catch{return null}}async function Gm(A){try{let Q=Um();ZH(Q,{recursive:!0});let B=EN(Q,"settings.json"),I={};if(IN(B)){let Y=Im(B,"utf8");try{let U=JSON.parse(Y);if(!U||typeof U!=="object"||Array.isArray(U))return{error:`${B} 内容不是 JSON 对象, 拒绝覆盖, 请手动检查`};I=U}catch{return{error:`${B} 解析失败 (JSON 语法错), 拒绝覆盖, 请手动修复后重跑`}}}let E=I.env&&typeof I.env==="object"&&!Array.isArray(I.env)?I.env:{},g={ANTHROPIC_AUTH_TOKEN:A,ANTHROPIC_BASE_URL:"https://open.bigmodel.cn/api/anthropic",API_TIMEOUT_MS:"3000000",CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC:"1"},F=await Jm(A);if(F)Object.assign(g,F);return I.env={...E,...g},NF(B,JSON.stringify(I,null,2)+`
129
- `),{path:B}}catch(Q){return{error:Q?.message??String(Q)}}}function Nm(A){try{if(process.platform==="win32")gY(process.env.ComSpec??"cmd.exe",["/c","start",'""',A],{detached:!0,stdio:"ignore",windowsHide:!0}).unref();else if(process.platform==="darwin")gY("open",[A],{detached:!0,stdio:"ignore"}).unref();else gY("xdg-open",[A],{detached:!0,stdio:"ignore"}).unref()}catch{}}async function Mm(A,Q){try{let I=await(await JF("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({app_id:A,app_secret:Q}),signal:AbortSignal.timeout(15000)})).json();if(I.tenant_access_token)return{ok:!0};return{ok:!1,error:`飞书拒绝: code=${I.code} msg=${I.msg??"(no msg)"}`}}catch(B){return{ok:!1,error:`网络错误: ${B?.message??String(B)}`}}}function wm(){try{let A=Cm(Fm(import.meta.url)),Q=EN(A,"lodestar.js");if(!IN(Q))return{error:`找不到 daemon bundle: ${Q}`};let B=gY(process.execPath,[Q],{detached:!0,stdio:"ignore",windowsHide:!0});return B.unref(),{pid:B.pid}}catch(A){return{error:A?.message??String(A)}}}async function LH(){if(!process.stdin.isTTY)console.error(`${V.red}lodestar-setup: stdin 不是 TTY,无法交互式输入。${V.reset}`),console.error("请直接在 cmd / PowerShell / Terminal 里跑,不要 pipe 或重定向 stdin。"),process.exit(1);if(IN(GF)){if(console.log(`${V.yellow}发现已有配置: ${GF}${V.reset}`),(await wE("覆盖? (y/N)",{default:"n"})).toLowerCase()!=="y"){console.log("已取消"),VF.close();return}}Dm("Lodestar 安装向导"),console.log("Lodestar 把 Feishu (飞书) 群聊接到 AI agent。"),console.log("默认后端是 Claude Code; Codex 是可选第二后端, 群里发 model 一键切换。"),console.log("每个群对应一个项目目录, agent 在那里跑、能读写文件。"),console.log(),console.log(`${V.yellow}⚠ Claude 官方限制:${V.reset}`),console.log(` ${V.bold}Claude 订阅 (Pro/Max OAuth 登录) 不支持本项目${V.reset},`),console.log(" 必须走 API 方式 —— 推荐 GLM Coding Plan, 或自备 Anthropic API key。"),console.log(),console.log("本向导依次做 4 件事:"),console.log(` ${V.dim}1) 确保 Claude Code CLI 已装好${V.reset}`),console.log(` ${V.dim}2) GLM Coding Plan API key (推荐, 可选) + Codex (可选)${V.reset}`),console.log(` ${V.dim}3) Feishu 自建应用 (含权限 / 事件 / 发版 + 凭据测试)${V.reset}`),console.log(` ${V.dim}4) 工作目录, 自动启动 daemon${V.reset}`),console.log(),await VF.question(`${V.dim}按 Enter 开始 (Ctrl+C 退出)...${V.reset}`),CY(1,4,"准备 Claude Code CLI"),await QN("claude",{report:(M)=>console.log(M)}),console.log(`${V.green}✓ Claude Code / SDK 已更新${V.reset}: ${V.dim}${AN("claude","claude")}${V.reset}`),console.log(),console.log(`${V.dim}下一步可选配 GLM Coding Plan 自动写入路由; 不配则用本机 Claude Code 现有配置。${V.reset}`),console.log(`${V.dim}记住: 别用 \`claude\` 走订阅 OAuth 登录 —— 订阅不支持本项目, 要用 API key。${V.reset}`),CY(2,4,"GLM Coding Plan (推荐, 可选)"),console.log("GLM Coding Plan 给 Claude Code 接 GLM 系列模型 (支持 1M token 上下文, 中文友好)。"),console.log("订阅后在智谱开放平台拿一个 API key, 粘到下面 —— 向导自动写进 ~/.claude/settings.json。"),console.log(` ${V.dim}拿 key: https://open.bigmodel.cn → 控制台 → API Keys${V.reset}`),console.log(` ${V.dim}不给也行: 以本机 Claude Code 现有配置启动 (确保是 API key 方式, 非订阅)。${V.reset}`),console.log();let A=await wE("GLM API key (直接回车跳过)",{});if(A){let M=await Gm(A);if("path"in M)console.log(`${V.green}✓ GLM 路由已写入${V.reset}: ${V.dim}${M.path}${V.reset}`),console.log(`${V.dim}模型 slots 按端点当前列表自动选取(最新一代 opus/sonnet, 1M ctx)${V.reset}`);else console.log(`${V.red}✗ 写入失败:${V.reset} ${M.error}`),console.log(`${V.dim}跳过 GLM 配置, 以本机 Claude Code 现有配置启动。${V.reset}`)}else console.log(`${V.dim}已跳过 GLM, 以本机 Claude Code 现有配置启动。${V.reset}`);if(console.log(),console.log(`${V.bold}Codex (可选第二后端)${V.reset}`),console.log(` ${V.dim}想用 Codex 的话, 登录 ChatGPT 订阅即可, 模型/effort 走 ~/.codex/config.toml, 群里发 model 切换。${V.reset}`),(await wE("现在顺便配置 Codex 后端吗?",{default:"n"})).toLowerCase()==="y"){await QN("codex",{report:(w)=>console.log(w)});let M=AN("codex","codex");if(VH(M))console.log(`${V.green}✓ Codex 已登录 ChatGPT${V.reset}`);else if(console.log(`${V.dim}启动 \`codex login\`...${V.reset}`),await Ym(M)&&VH(M))console.log(`${V.green}✓ Codex 已登录 ChatGPT${V.reset}`);else console.log(`${V.yellow}Codex 登录未完成 — 不影响默认 Claude 后端; 需要时随时跑 codex login。${V.reset}`)}else console.log(`${V.dim}已跳过 Codex (需要时随时跑 codex login, 群里发 model 切)。${V.reset}`);CY(3,4,"Feishu 自建应用");let B="https://open.feishu.cn/app";console.log("打开飞书开放平台 (浏览器):"),console.log(` ${V.cyan}${B}${V.reset}`),Nm(B),console.log(`${V.dim}(如果浏览器没自动开, 复制上面 URL 粘到浏览器)${V.reset}`),console.log(),console.log(`${V.bold}详细操作步骤:${V.reset}`),console.log(),console.log(` ${V.bold}① 创建应用${V.reset}`),console.log(` 点 "创建企业自建应用", 填名字 (如 ${V.dim}Lodestar${V.reset}), logo 随意。`),console.log(),console.log(` ${V.bold}② 添加机器人能力${V.reset}`),console.log(` 左侧菜单 "${V.cyan}添加应用能力${V.reset}" → 找到 "机器人" → 点 "${V.bold}添加${V.reset}" 按钮。`),console.log(),console.log(` ${V.bold}③ 申请权限 (左侧 "${V.cyan}权限管理${V.reset}" → "${V.bold}批量导入/导出权限${V.reset}")${V.reset}`),console.log(` ${V.yellow}选择应用身份权限,复制下方完整 JSON 批量导入,一次开齐账号信息、消息、卡片和云空间能力。${V.reset}`),console.log(JSON.stringify(wH,null,2)),console.log(` ${V.dim}无需用户身份权限或飞书 CLI 登录。权限申请后须完成审批,并在步骤 ⑤ 发布飞书应用版本。${V.reset}`),console.log(` ${V.dim}清单包含以下用途;也可按名称逐项开通:${V.reset}`),console.log(` ${V.dim}账号与认证信息 (排障):${V.reset}`),console.log(` • ${V.bold}verification:verification_information:readonly${V.reset} ${V.dim}# 查看账号主体认证状态${V.reset}`),console.log(` • ${V.bold}tenant:tenant:readonly${V.reset} ${V.dim}# 查看租户基本信息${V.reset}`),console.log(` ${V.dim}消息类:${V.reset}`),console.log(` • ${V.bold}im:message:send_as_bot${V.reset} ${V.dim}# 以机器人身份发消息${V.reset}`),console.log(` • ${V.bold}im:message${V.reset} ${V.dim}# 接收/操作消息 (核心)${V.reset}`),console.log(` • ${V.bold}im:chat${V.reset} ${V.dim}# 读/写群信息 (匹配群名 ↔ 项目目录)${V.reset}`),console.log(` • ${V.bold}im:chat:create${V.reset} ${V.dim}# wt: 自动创建 worktree 群${V.reset}`),console.log(` • ${V.bold}im:chat:delete${V.reset} ${V.dim}# wt: 解散 worktree 群${V.reset}`),console.log(` • ${V.bold}im:chat.members:read${V.reset} ${V.dim}# wt: 判断发起人是否已在群内${V.reset}`),console.log(` • ${V.bold}im:chat.members:write_only${V.reset} ${V.dim}# wt: 把发起人拉进已有 worktree 群${V.reset}`),console.log(` • ${V.bold}im:resource${V.reset} ${V.dim}# 上传/下载附件 (图文双向)${V.reset}`),console.log(` • ${V.bold}im:message.urgent${V.reset} ${V.dim}# 加急推送 (锁屏通知 / Ask)${V.reset}`),console.log(` • ${V.bold}im:message.group_msg${V.reset} ${V.dim}# 敏感: 接收群里所有消息${V.reset}`),console.log(` ${V.dim}└ 关键: 没它机器人只收 @ 自己的消息, 拿不到群里其他对话, 一定要开${V.reset}`),console.log(` ${V.dim}└ 敏感权限要走审批: 申请时填用途, 个人开发者通常秒过${V.reset}`),console.log(` • ${V.bold}im:message.group_at_msg:readonly${V.reset} ${V.dim}# 读 @ 机器人消息 (兜底)${V.reset}`),console.log(` ${V.dim}卡片类 (Card Kit):${V.reset}`),console.log(` • ${V.bold}cardkit:card:read${V.reset} ${V.dim}# 读卡片状态${V.reset}`),console.log(` • ${V.bold}cardkit:card:write${V.reset} ${V.dim}# 创建/更新卡片 (流式渲染核心)${V.reset}`),console.log(` ${V.dim}云空间交付 (权限预先开通,功能仍按群开启):${V.reset}`),console.log(` • ${V.bold}drive:drive${V.reset} ${V.dim}# 上传、创建目录、协作者授权、关闭并核对文件链接分享${V.reset}`),console.log(` • ${V.bold}drive:file:upload${V.reset} ${V.dim}# 文件夹改名接口单独要求此权限${V.reset}`),console.log(` ${V.dim}默认仍直接发聊天附件;在指定群发送 files on 开启云空间,files off 恢复附件。${V.reset}`),console.log(` ${V.yellow}只取得 tenant_access_token 不代表以上权限已生效;缺少权限时群内命令会明确报错。${V.reset}`),console.log(),console.log(` ${V.bold}④ 订阅事件 (左侧 "${V.cyan}事件与回调${V.reset}", 拆两个子页:)${V.reset}`),console.log(` ${V.dim}a)${V.reset} ${V.bold}事件配置${V.reset} 页:`),console.log(` ${V.yellow}• "订阅方式" → 选 "长连接" → 点保存${V.reset}`),console.log(` • 添加事件: ${V.bold}im.message.receive_v1${V.reset} ${V.dim}# 收群消息${V.reset}`),console.log(` ${V.dim}b)${V.reset} ${V.bold}回调配置${V.reset} 页:`),console.log(` ${V.yellow}• "订阅方式" → 选 "长连接" → 点保存${V.reset}`),console.log(` • 添加事件: ${V.bold}card.action.trigger${V.reset} ${V.dim}# 卡片按钮点击回调${V.reset}`),console.log(),console.log(` ${V.bold}⑤ 发布版本${V.reset}`),console.log(` 页面顶部 "${V.bold}创建版本${V.reset}" → 滚到底点 "${V.bold}保存${V.reset}" → 弹框点 "${V.bold}发布${V.reset}"。`),console.log(` ${V.yellow}没发版的应用收不到任何事件 — 这步九成新手会忘!${V.reset}`),console.log(),console.log(` ${V.bold}⑥ 拿凭据${V.reset}`),console.log(` 左侧 "凭证与基础信息" → 顶部 ${V.bold}App ID${V.reset} (${V.dim}cli_...${V.reset}) 和 ${V.bold}App Secret${V.reset}, 待会粘到下面。`),console.log(),console.log(` ${V.bold}⑦ 把机器人拉进群${V.reset}`),console.log(" 想用的飞书群 → 群设置 → 群机器人 → 添加机器人 → 选你的应用。"),console.log(` ${V.yellow}群名要等于 projects_root 下的项目目录名${V.reset} (下一步设, 默认是用户主目录)。`),console.log();let I="",E="";while(!0){I=await wE("App ID (以 cli_ 开头)",{required:!0}),E=await wE("App Secret",{required:!0}),console.log(`${V.dim}测试中... (调 tenant_access_token endpoint)${V.reset}`);let M=await Mm(I,E);if(M.ok){console.log(`${V.green}✓ Feishu 凭据测试通过${V.reset}`);break}if(console.log(`${V.red}✗ 测试失败:${V.reset} ${M.error}`),console.log(`${V.dim}最常见原因: app_id / app_secret 抄错, 或应用还没 "发布上线" (步骤 ⑤)。${V.reset}`),console.log(),(await wE("重新填? (Y/n)",{default:"y"})).toLowerCase()==="n")console.log(`${V.yellow}已取消, 配置未写盘。${V.reset}`),VF.close(),process.exit(1)}CY(4,4,"工作目录 + 启动"),console.log("每个 Feishu 群对应 projects_root 下同名的目录。"),console.log();let g=process.platform==="win32"?process.env.USERPROFILE??"C:\\Users\\Default":process.env.HOME??"/root",F=await wE("projects_root",{default:g});ZH(oG,{recursive:!0});let Y=["# Lodestar config — generated by `lodestar-setup`","# Edit by hand or re-run setup to overwrite.","","[feishu]",`app_id = "${BN(I)}"`,`app_secret = "${BN(E)}"`,"","[runtime]",`projects_root = "${BN(F)}"`,"","[runtime.agent_auto_update]","codex = false","claude = false","dsh = false",""];NF(GF,Y.join(`
129
+ `),{path:B}}catch(Q){return{error:Q?.message??String(Q)}}}function Nm(A){try{if(process.platform==="win32")gY(process.env.ComSpec??"cmd.exe",["/c","start",'""',A],{detached:!0,stdio:"ignore",windowsHide:!0}).unref();else if(process.platform==="darwin")gY("open",[A],{detached:!0,stdio:"ignore"}).unref();else gY("xdg-open",[A],{detached:!0,stdio:"ignore"}).unref()}catch{}}async function Mm(A,Q){try{let I=await(await JF("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({app_id:A,app_secret:Q}),signal:AbortSignal.timeout(15000)})).json();if(I.tenant_access_token)return{ok:!0};return{ok:!1,error:`飞书拒绝: code=${I.code} msg=${I.msg??"(no msg)"}`}}catch(B){return{ok:!1,error:`网络错误: ${B?.message??String(B)}`}}}function wm(){try{let A=Cm(Fm(import.meta.url)),Q=EN(A,"lodestar.js");if(!IN(Q))return{error:`找不到 daemon bundle: ${Q}`};let B=gY(process.execPath,[Q],{detached:!0,stdio:"ignore",windowsHide:!0});return B.unref(),{pid:B.pid}}catch(A){return{error:A?.message??String(A)}}}async function LH(){if(!process.stdin.isTTY)console.error(`${V.red}lodestar-setup: stdin 不是 TTY,无法交互式输入。${V.reset}`),console.error("请直接在 cmd / PowerShell / Terminal 里跑,不要 pipe 或重定向 stdin。"),process.exit(1);if(IN(GF)){if(console.log(`${V.yellow}发现已有配置: ${GF}${V.reset}`),(await wE("覆盖? (y/N)",{default:"n"})).toLowerCase()!=="y"){console.log("已取消"),VF.close();return}}Dm("Lodestar 安装向导"),console.log("Lodestar 把 Feishu (飞书) 群聊接到 AI agent。"),console.log("默认后端是 Claude Code; Codex 是可选第二后端, 群里发 model 一键切换。"),console.log("每个群对应一个项目目录, agent 在那里跑、能读写文件。"),console.log(),console.log("支持本机已登录的 Claude Code 订阅,也可配置 GLM Coding Plan 或 Anthropic API key。"),console.log("Claude Code 订阅与第三方来源可在 model 面板中分别选择。"),console.log(),console.log("本向导依次做 4 件事:"),console.log(` ${V.dim}1) 确保 Claude Code CLI 已装好${V.reset}`),console.log(` ${V.dim}2) GLM Coding Plan API key (推荐, 可选) + Codex (可选)${V.reset}`),console.log(` ${V.dim}3) Feishu 自建应用 (含权限 / 事件 / 发版 + 凭据测试)${V.reset}`),console.log(` ${V.dim}4) 工作目录, 自动启动 daemon${V.reset}`),console.log(),await VF.question(`${V.dim}按 Enter 开始 (Ctrl+C 退出)...${V.reset}`),CY(1,4,"准备 Claude Code CLI"),await QN("claude",{report:(M)=>console.log(M)}),console.log(`${V.green}✓ Claude Code / SDK 已更新${V.reset}: ${V.dim}${AN("claude","claude")}${V.reset}`),console.log(),console.log(`${V.dim}下一步可选配 GLM Coding Plan 自动写入路由; 不配则用本机 Claude Code 现有配置。${V.reset}`),console.log(`${V.dim}使用 Claude 订阅时,在本机运行 \`claude auth login\`;完成后在 model 面板选择 Claude Code 订阅。${V.reset}`),CY(2,4,"GLM Coding Plan (推荐, 可选)"),console.log("GLM Coding Plan 给 Claude Code 接 GLM 系列模型 (支持 1M token 上下文, 中文友好)。"),console.log("订阅后在智谱开放平台拿一个 API key, 粘到下面 —— 向导自动写进 ~/.claude/settings.json。"),console.log(` ${V.dim}拿 key: https://open.bigmodel.cn → 控制台 → API Keys${V.reset}`),console.log(` ${V.dim}直接回车跳过,可使用本机 Claude Code 订阅或其他已有配置。${V.reset}`),console.log();let A=await wE("GLM API key (直接回车跳过)",{});if(A){let M=await Gm(A);if("path"in M)console.log(`${V.green}✓ GLM 路由已写入${V.reset}: ${V.dim}${M.path}${V.reset}`),console.log(`${V.dim}模型 slots 按端点当前列表自动选取(最新一代 opus/sonnet, 1M ctx)${V.reset}`);else console.log(`${V.red}✗ 写入失败:${V.reset} ${M.error}`),console.log(`${V.dim}跳过 GLM 配置, 以本机 Claude Code 现有配置启动。${V.reset}`)}else console.log(`${V.dim}已跳过 GLM, 以本机 Claude Code 现有配置启动。${V.reset}`);if(console.log(),console.log(`${V.bold}Codex (可选第二后端)${V.reset}`),console.log(` ${V.dim}想用 Codex 的话, 登录 ChatGPT 订阅即可, 模型/effort 走 ~/.codex/config.toml, 群里发 model 切换。${V.reset}`),(await wE("现在顺便配置 Codex 后端吗?",{default:"n"})).toLowerCase()==="y"){await QN("codex",{report:(w)=>console.log(w)});let M=AN("codex","codex");if(VH(M))console.log(`${V.green}✓ Codex 已登录 ChatGPT${V.reset}`);else if(console.log(`${V.dim}启动 \`codex login\`...${V.reset}`),await Ym(M)&&VH(M))console.log(`${V.green}✓ Codex 已登录 ChatGPT${V.reset}`);else console.log(`${V.yellow}Codex 登录未完成 — 不影响默认 Claude 后端; 需要时随时跑 codex login。${V.reset}`)}else console.log(`${V.dim}已跳过 Codex (需要时随时跑 codex login, 群里发 model 切)。${V.reset}`);CY(3,4,"Feishu 自建应用");let B="https://open.feishu.cn/app";console.log("打开飞书开放平台 (浏览器):"),console.log(` ${V.cyan}${B}${V.reset}`),Nm(B),console.log(`${V.dim}(如果浏览器没自动开, 复制上面 URL 粘到浏览器)${V.reset}`),console.log(),console.log(`${V.bold}详细操作步骤:${V.reset}`),console.log(),console.log(` ${V.bold}① 创建应用${V.reset}`),console.log(` 点 "创建企业自建应用", 填名字 (如 ${V.dim}Lodestar${V.reset}), logo 随意。`),console.log(),console.log(` ${V.bold}② 添加机器人能力${V.reset}`),console.log(` 左侧菜单 "${V.cyan}添加应用能力${V.reset}" → 找到 "机器人" → 点 "${V.bold}添加${V.reset}" 按钮。`),console.log(),console.log(` ${V.bold}③ 申请权限 (左侧 "${V.cyan}权限管理${V.reset}" → "${V.bold}批量导入/导出权限${V.reset}")${V.reset}`),console.log(` ${V.yellow}选择应用身份权限,复制下方完整 JSON 批量导入,一次开齐账号信息、消息、卡片和云空间能力。${V.reset}`),console.log(JSON.stringify(wH,null,2)),console.log(` ${V.dim}无需用户身份权限或飞书 CLI 登录。权限申请后须完成审批,并在步骤 ⑤ 发布飞书应用版本。${V.reset}`),console.log(` ${V.dim}清单包含以下用途;也可按名称逐项开通:${V.reset}`),console.log(` ${V.dim}账号与认证信息 (排障):${V.reset}`),console.log(` • ${V.bold}verification:verification_information:readonly${V.reset} ${V.dim}# 查看账号主体认证状态${V.reset}`),console.log(` • ${V.bold}tenant:tenant:readonly${V.reset} ${V.dim}# 查看租户基本信息${V.reset}`),console.log(` ${V.dim}消息类:${V.reset}`),console.log(` • ${V.bold}im:message:send_as_bot${V.reset} ${V.dim}# 以机器人身份发消息${V.reset}`),console.log(` • ${V.bold}im:message${V.reset} ${V.dim}# 接收/操作消息 (核心)${V.reset}`),console.log(` • ${V.bold}im:chat${V.reset} ${V.dim}# 读/写群信息 (匹配群名 ↔ 项目目录)${V.reset}`),console.log(` • ${V.bold}im:chat:create${V.reset} ${V.dim}# wt: 自动创建 worktree 群${V.reset}`),console.log(` • ${V.bold}im:chat:delete${V.reset} ${V.dim}# wt: 解散 worktree 群${V.reset}`),console.log(` • ${V.bold}im:chat.members:read${V.reset} ${V.dim}# wt: 判断发起人是否已在群内${V.reset}`),console.log(` • ${V.bold}im:chat.members:write_only${V.reset} ${V.dim}# wt: 把发起人拉进已有 worktree 群${V.reset}`),console.log(` • ${V.bold}im:resource${V.reset} ${V.dim}# 上传/下载附件 (图文双向)${V.reset}`),console.log(` • ${V.bold}im:message.urgent${V.reset} ${V.dim}# 加急推送 (锁屏通知 / Ask)${V.reset}`),console.log(` • ${V.bold}im:message.group_msg${V.reset} ${V.dim}# 敏感: 接收群里所有消息${V.reset}`),console.log(` ${V.dim}└ 关键: 没它机器人只收 @ 自己的消息, 拿不到群里其他对话, 一定要开${V.reset}`),console.log(` ${V.dim}└ 敏感权限要走审批: 申请时填用途, 个人开发者通常秒过${V.reset}`),console.log(` • ${V.bold}im:message.group_at_msg:readonly${V.reset} ${V.dim}# 读 @ 机器人消息 (兜底)${V.reset}`),console.log(` ${V.dim}卡片类 (Card Kit):${V.reset}`),console.log(` • ${V.bold}cardkit:card:read${V.reset} ${V.dim}# 读卡片状态${V.reset}`),console.log(` • ${V.bold}cardkit:card:write${V.reset} ${V.dim}# 创建/更新卡片 (流式渲染核心)${V.reset}`),console.log(` ${V.dim}云空间交付 (权限预先开通,功能仍按群开启):${V.reset}`),console.log(` • ${V.bold}drive:drive${V.reset} ${V.dim}# 上传、创建目录、协作者授权、关闭并核对文件链接分享${V.reset}`),console.log(` • ${V.bold}drive:file:upload${V.reset} ${V.dim}# 文件夹改名接口单独要求此权限${V.reset}`),console.log(` ${V.dim}默认仍直接发聊天附件;在指定群发送 files on 开启云空间,files off 恢复附件。${V.reset}`),console.log(` ${V.yellow}只取得 tenant_access_token 不代表以上权限已生效;缺少权限时群内命令会明确报错。${V.reset}`),console.log(),console.log(` ${V.bold}④ 订阅事件 (左侧 "${V.cyan}事件与回调${V.reset}", 拆两个子页:)${V.reset}`),console.log(` ${V.dim}a)${V.reset} ${V.bold}事件配置${V.reset} 页:`),console.log(` ${V.yellow}• "订阅方式" → 选 "长连接" → 点保存${V.reset}`),console.log(` • 添加事件: ${V.bold}im.message.receive_v1${V.reset} ${V.dim}# 收群消息${V.reset}`),console.log(` ${V.dim}b)${V.reset} ${V.bold}回调配置${V.reset} 页:`),console.log(` ${V.yellow}• "订阅方式" → 选 "长连接" → 点保存${V.reset}`),console.log(` • 添加事件: ${V.bold}card.action.trigger${V.reset} ${V.dim}# 卡片按钮点击回调${V.reset}`),console.log(),console.log(` ${V.bold}⑤ 发布版本${V.reset}`),console.log(` 页面顶部 "${V.bold}创建版本${V.reset}" → 滚到底点 "${V.bold}保存${V.reset}" → 弹框点 "${V.bold}发布${V.reset}"。`),console.log(` ${V.yellow}没发版的应用收不到任何事件 — 这步九成新手会忘!${V.reset}`),console.log(),console.log(` ${V.bold}⑥ 拿凭据${V.reset}`),console.log(` 左侧 "凭证与基础信息" → 顶部 ${V.bold}App ID${V.reset} (${V.dim}cli_...${V.reset}) 和 ${V.bold}App Secret${V.reset}, 待会粘到下面。`),console.log(),console.log(` ${V.bold}⑦ 把机器人拉进群${V.reset}`),console.log(" 想用的飞书群 → 群设置 → 群机器人 → 添加机器人 → 选你的应用。"),console.log(` ${V.yellow}群名要等于 projects_root 下的项目目录名${V.reset} (下一步设, 默认是用户主目录)。`),console.log();let I="",E="";while(!0){I=await wE("App ID (以 cli_ 开头)",{required:!0}),E=await wE("App Secret",{required:!0}),console.log(`${V.dim}测试中... (调 tenant_access_token endpoint)${V.reset}`);let M=await Mm(I,E);if(M.ok){console.log(`${V.green}✓ Feishu 凭据测试通过${V.reset}`);break}if(console.log(`${V.red}✗ 测试失败:${V.reset} ${M.error}`),console.log(`${V.dim}最常见原因: app_id / app_secret 抄错, 或应用还没 "发布上线" (步骤 ⑤)。${V.reset}`),console.log(),(await wE("重新填? (Y/n)",{default:"y"})).toLowerCase()==="n")console.log(`${V.yellow}已取消, 配置未写盘。${V.reset}`),VF.close(),process.exit(1)}CY(4,4,"工作目录 + 启动"),console.log("每个 Feishu 群对应 projects_root 下同名的目录。"),console.log();let g=process.platform==="win32"?process.env.USERPROFILE??"C:\\Users\\Default":process.env.HOME??"/root",F=await wE("projects_root",{default:g});ZH(oG,{recursive:!0});let Y=["# Lodestar config — generated by `lodestar-setup`","# Edit by hand or re-run setup to overwrite.","","[feishu]",`app_id = "${BN(I)}"`,`app_secret = "${BN(E)}"`,"","[runtime]",`projects_root = "${BN(F)}"`,"","[runtime.agent_auto_update]","codex = false","claude = false","dsh = false",""];NF(GF,Y.join(`
130
130
  `)),console.log(`
131
131
  ${V.green}${V.bold}✓ 配置已写入${V.reset}`),console.log(` ${V.cyan}${GF}${V.reset}`),console.log(`
132
132
  ${V.bold}启动 daemon...${V.reset}`);let U=wm(),N=process.platform==="win32"?"\\":"/",G=process.platform==="win32"?`${process.env.LOCALAPPDATA??"%LOCALAPPDATA%"}\\Lodestar\\daemon-YYYY-MM-DD.log`:`${process.env.HOME??"~"}/.local/share/lodestar/daemon-YYYY-MM-DD.log`;if(U.pid)console.log(`${V.green}✓ daemon 已在后台启动${V.reset} (pid ${U.pid})`),console.log(),console.log(`${V.bold}最后一步: 在 Feishu 验证${V.reset}`),console.log(" ① 把机器人拉进任意飞书群"),console.log(` ② 群名 = ${V.cyan}${F}${N}<群名>${V.reset} 下的目录名 (新群第一条消息会自动建)`),console.log(" ③ 在群里发任意一条消息, 默认由 Claude 接管"),console.log(` ${V.dim}(群里发 model 可选择已配置账号、动态模型和 effort)${V.reset}`),console.log(),console.log("日志 (按日滚动, 保留近 7 天):"),console.log(` ${V.cyan}${G}${V.reset}`),console.log(),console.log(`${V.dim}若长期跑后台, Linux 配 systemd --user,macOS 配 launchd,Windows 配任务计划程序。${V.reset}`);else console.log(`${V.yellow}启动失败: ${U.error}${V.reset}`),console.log(`手动运行: ${V.cyan}lodestar-daemon${V.reset}`);console.log(),VF.close()}LH().catch((A)=>{console.error(`