@leviyuan/lodestar 0.10.1 → 0.11.1

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
@@ -14,6 +14,12 @@ AI 不是帮手,是倍率。它放大的不是体力,是你 —— 你的直觉
14
14
 
15
15
  跨平台 (Windows / macOS / Linux),npm 全局安装后由 Node.js 运行,需要 Node.js ≥ 18;Bun 只用于源码开发和发布构建。
16
16
 
17
+ ### 🧠 双后端:Claude Code + Codex
18
+
19
+ 夜航星同时接入 Claude Code 和 Codex 两个 agent 后端,**默认 Claude Code**。群里发 `model` 可在 Claude·GLM-5.2 与 Codex·GPT-5.5 之间一键切换,选择按群持久化。
20
+
21
+ 强烈推荐 Claude Code 搭配 **GLM-5.2** —— 开放 1M token 上下文窗口,长会话不易丢前文。订阅了 GLM Coding Plan,`hi` 控制台会直接展示套餐档位、5 小时滚动窗口与月度用量;每条回复的 footer 也会带上当前 5h 窗口的已用百分比(`5h·N%`),额度消耗随时可见。
22
+
17
23
  **1. 装包**
18
24
 
19
25
  ```bash
@@ -40,7 +46,7 @@ lodestar-setup
40
46
 
41
47
  **3. 拉机器人进群**
42
48
 
43
- 群名 = `projects_root` 下的目录名(没建会自动建)。发条消息,Codex 接管。
49
+ 群名 = `projects_root` 下的目录名(没建会自动建)。发条消息,默认由 Claude·GLM-5.2 接管(群里发 `model` 可切到 Codex·GPT-5.5)。
44
50
 
45
51
  群里发这些**裸词**(不要斜杠,大小写不敏感)可以控 daemon:
46
52
 
@@ -52,7 +58,7 @@ lodestar-setup
52
58
  | `restart` / `rs` | 用状态卡展示按上次 `threadId` 重启(保留上下文)|
53
59
  | `clear` / `cl` | 用状态卡展示杀进程并开新 thread(等价 `/clear`)|
54
60
  | `compact` / `cm` | 主动触发当前 thread 的上下文压缩,完成后状态卡收束 |
55
- | `model` / `md` | 展示可用 Codex 模型面板,先选模型再选 reasoning effort,并按群持久化 |
61
+ | `model` / `md` | 展示固定两项面板(Codex·GPT-5.5 / Claude·GLM-5.2),一键生效,按群持久化 |
56
62
  | `task` | 打开项目任务清单面板,启用飞书任务清单自动化(预览版) |
57
63
 
58
64
  **并发 worktree 群**
@@ -9,5 +9,5 @@ ${z.red}安装失败。${z.reset}`),console.error("请手动运行后再开向
9
9
  ${z.red}Codex ChatGPT 登录未完成。${z.reset}`),console.error(`请手动运行 ${z.cyan}codex login${z.reset} 后再开向导。`),Z.close(),process.exit(1);console.log(`${z.green}✓ Codex 已登录 ChatGPT${z.reset}`)}M(3,4,"Feishu 自建应用");let q="https://open.feishu.cn/app";console.log("打开飞书开放平台 (浏览器):"),console.log(` ${z.cyan}${q}${z.reset}`),l(q),console.log(`${z.dim}(如果浏览器没自动开, 复制上面 URL 粘到浏览器)${z.reset}`),console.log(),console.log(`${z.bold}详细操作步骤:${z.reset}`),console.log(),console.log(` ${z.bold}① 创建应用${z.reset}`),console.log(` 点 "创建企业自建应用", 填名字 (如 ${z.dim}Lodestar${z.reset}), logo 随意。`),console.log(),console.log(` ${z.bold}② 添加机器人能力${z.reset}`),console.log(` 左侧菜单 "${z.cyan}添加应用能力${z.reset}" → 找到 "机器人" → 点 "${z.bold}添加${z.reset}" 按钮。`),console.log(),console.log(` ${z.bold}③ 申请权限 (左侧 "${z.cyan}权限管理${z.reset}" → "${z.bold}开通权限${z.reset}")${z.reset}`),console.log(` ${z.yellow}缺一个都会让 daemon 启动后默默丢消息, 一定要全开。${z.reset}`),console.log(` ${z.dim}消息类:${z.reset}`),console.log(` • ${z.bold}im:message:send_as_bot${z.reset} ${z.dim}# 以机器人身份发消息${z.reset}`),console.log(` • ${z.bold}im:message${z.reset} ${z.dim}# 接收/操作消息 (核心)${z.reset}`),console.log(` • ${z.bold}im:chat${z.reset} ${z.dim}# 读/写群信息 (匹配群名 ↔ 项目目录)${z.reset}`),console.log(` • ${z.bold}im:chat:create${z.reset} ${z.dim}# wt: 自动创建 worktree 群${z.reset}`),console.log(` • ${z.bold}im:chat:delete${z.reset} ${z.dim}# wt: 解散 worktree 群${z.reset}`),console.log(` • ${z.bold}im:chat.members:read${z.reset} ${z.dim}# wt: 判断发起人是否已在群内${z.reset}`),console.log(` • ${z.bold}im:chat.members:write_only${z.reset} ${z.dim}# wt: 把发起人拉进已有 worktree 群${z.reset}`),console.log(` • ${z.bold}im:resource${z.reset} ${z.dim}# 上传/下载附件 (图文双向)${z.reset}`),console.log(` • ${z.bold}im:message.urgent${z.reset} ${z.dim}# 加急推送 (锁屏通知 / Ask)${z.reset}`),console.log(` • ${z.bold}im:message.group_msg${z.reset} ${z.red}# 敏感: 接收群里所有消息${z.reset}`),console.log(` ${z.dim}└ 关键: 没它机器人只收 @ 自己的消息, 拿不到群里其他对话, 一定要开${z.reset}`),console.log(` ${z.dim}└ 敏感权限要走审批: 申请时填用途, 个人开发者通常秒过${z.reset}`),console.log(` • ${z.bold}im:message.group_at_msg:readonly${z.reset} ${z.dim}# 读 @ 机器人消息 (兜底)${z.reset}`),console.log(` ${z.dim}卡片类 (Card Kit):${z.reset}`),console.log(` • ${z.bold}cardkit:card:read${z.reset} ${z.dim}# 读卡片状态${z.reset}`),console.log(` • ${z.bold}cardkit:card:write${z.reset} ${z.dim}# 创建/更新卡片 (流式渲染核心)${z.reset}`),console.log(),console.log(` ${z.bold}④ 订阅事件 (左侧 "${z.cyan}事件与回调${z.reset}", 拆两个子页:)${z.reset}`),console.log(` ${z.dim}a)${z.reset} ${z.bold}事件配置${z.reset} 页:`),console.log(` ${z.yellow}• "订阅方式" → 选 "长连接" → 点保存${z.reset}`),console.log(` • 添加事件: ${z.bold}im.message.receive_v1${z.reset} ${z.dim}# 收群消息${z.reset}`),console.log(` ${z.dim}b)${z.reset} ${z.bold}回调配置${z.reset} 页:`),console.log(` ${z.yellow}• "订阅方式" → 选 "长连接" → 点保存${z.reset}`),console.log(` • 添加事件: ${z.bold}card.action.trigger${z.reset} ${z.dim}# 卡片按钮点击回调${z.reset}`),console.log(),console.log(` ${z.bold}⑤ 发布版本${z.reset}`),console.log(` 页面顶部 "${z.bold}创建版本${z.reset}" → 滚到底点 "${z.bold}保存${z.reset}" → 弹框点 "${z.bold}发布${z.reset}"。`),console.log(` ${z.yellow}没发版的应用收不到任何事件 — 这步九成新手会忘!${z.reset}`),console.log(),console.log(` ${z.bold}⑥ 拿凭据${z.reset}`),console.log(` 左侧 "凭证与基础信息" → 顶部 ${z.bold}App ID${z.reset} (${z.dim}cli_...${z.reset}) 和 ${z.bold}App Secret${z.reset}, 待会粘到下面。`),console.log(),console.log(` ${z.bold}⑦ 把机器人拉进群${z.reset}`),console.log(" 想用的飞书群 → 群设置 → 群机器人 → 添加机器人 → 选你的应用。"),console.log(` ${z.yellow}群名要等于 projects_root 下的项目目录名${z.reset} (下一步设, 默认是用户主目录)。`),console.log();let J="",K="";while(!0){J=await V("App ID (以 cli_ 开头)",{required:!0}),K=await V("App Secret",{required:!0}),console.log(`${z.dim}测试中... (调 tenant_access_token endpoint)${z.reset}`);let y=await p(J,K);if(y.ok){console.log(`${z.green}✓ Feishu 凭据测试通过${z.reset}`);break}if(console.log(`${z.red}✗ 测试失败:${z.reset} ${y.error}`),console.log(`${z.dim}最常见原因: app_id / app_secret 抄错, 或应用还没 "发布上线" (步骤 ⑤)。${z.reset}`),console.log(),(await V("重新填? (Y/n)",{default:"y"})).toLowerCase()==="n")console.log(`${z.yellow}已取消, 配置未写盘。${z.reset}`),Z.close(),process.exit(1)}M(4,4,"工作目录 + 启动"),console.log("每个 Feishu 群对应 projects_root 下同名的目录。"),console.log();let H=process.platform==="win32"?process.env.USERPROFILE??"C:\\Users\\Default":process.env.HOME??"/root",X=await V("projects_root",{default:H});A(N,{recursive:!0});let F=["# Lodestar config — generated by `lodestar-setup`","# Edit by hand or re-run setup to overwrite.","","[feishu]",`app_id = "${P(J)}"`,`app_secret = "${P(K)}"`,"","[runtime]",`projects_root = "${P(X)}"`,""];_(W,F.join(`
10
10
  `),{mode:384}),console.log(`
11
11
  ${z.green}${z.bold}✓ 配置已写入${z.reset}`),console.log(` ${z.cyan}${W}${z.reset}`),console.log(`
12
- ${z.bold}启动 daemon...${z.reset}`);let U=r(),u=process.platform==="win32"?"\\":"/",R=process.platform==="win32"?`${process.env.LOCALAPPDATA??"%LOCALAPPDATA%"}\\Lodestar\\daemon.log`:`${process.env.HOME??"~"}/.local/share/lodestar/daemon.log`;if(U.pid)console.log(`${z.green}✓ daemon 已在后台启动${z.reset} (pid ${U.pid})`),console.log(),console.log(`${z.bold}最后一步: 在 Feishu 验证${z.reset}`),console.log(" ① 把机器人拉进任意飞书群"),console.log(` ② 群名 = ${z.cyan}${X}${u}<群名>${z.reset} 下的目录名 (新群第一条消息会自动建)`),console.log(" ③ 在群里发任意一条消息, Codex 上线"),console.log(),console.log("日志:"),console.log(` ${z.cyan}${R}${z.reset}`),console.log(),console.log(`${z.dim}若长期跑后台, 参考 README "7×24 守护" 一节配 systemd / Windows 后台托管。${z.reset}`);else console.log(`${z.yellow}启动失败: ${U.error}${z.reset}`),console.log(`手动运行: ${z.cyan}lodestar-daemon${z.reset}`);console.log(),Z.close()}O().catch(($)=>{console.error(`
12
+ ${z.bold}启动 daemon...${z.reset}`);let U=r(),u=process.platform==="win32"?"\\":"/",R=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(`${z.green}✓ daemon 已在后台启动${z.reset} (pid ${U.pid})`),console.log(),console.log(`${z.bold}最后一步: 在 Feishu 验证${z.reset}`),console.log(" ① 把机器人拉进任意飞书群"),console.log(` ② 群名 = ${z.cyan}${X}${u}<群名>${z.reset} 下的目录名 (新群第一条消息会自动建)`),console.log(" ③ 在群里发任意一条消息, Codex 上线"),console.log(),console.log("日志 (按日滚动, 保留近 7 天):"),console.log(` ${z.cyan}${R}${z.reset}`),console.log(),console.log(`${z.dim}若长期跑后台, 参考 README "7×24 守护" 一节配 systemd / Windows 后台托管。${z.reset}`);else console.log(`${z.yellow}启动失败: ${U.error}${z.reset}`),console.log(`手动运行: ${z.cyan}lodestar-daemon${z.reset}`);console.log(),Z.close()}O().catch(($)=>{console.error(`
13
13
  lodestar-setup: ${$?.message??$}`),process.exit(1)});