@leviyuan/lodestar 0.17.1 → 0.17.2
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 +23 -171
- package/dist/dsh-bridge.js +30 -11
- package/dist/lodestar-setup.js +13 -11
- package/dist/lodestar-stop.js +2 -2
- package/dist/lodestar-update.js +7 -4
- package/dist/lodestar-version.js +1 -1
- package/dist/lodestar.js +168 -163
- package/docs/AGENTS.md +14 -0
- package/docs/claude-agent-backend.md +135 -0
- package/docs/configuration.md +55 -0
- package/docs/dsh-testing-report.md +189 -0
- package/docs/models.md +76 -0
- package/docs/usage.md +79 -0
- package/package.json +238 -245
- package/scripts/postinstall.cjs +1 -26
package/README.md
CHANGED
|
@@ -4,189 +4,43 @@
|
|
|
4
4
|
|
|
5
5
|
# 夜航星 (Lodestar)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
在飞书群里使用 Codex、Claude Code 和 DeepSeek Harness。每个群对应一个项目目录和会话,回复、工具调用、图片、提问及后台任务通过卡片展示。
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
支持 Codex 订阅、GLM Coding Plan、DeepSeek、OpenRouter 和 Claude native;账号、模型与 effort 可在群里切换并保存。
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
## 快速开始
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
支持 Codex、GLM Coding Plan、DeepSeek、OpenRouter、Claude native 和 DeepSeek Harness 原生后端。账号、模型与 effort 可在群里切换,选择按群保存。
|
|
16
|
-
|
|
17
|
-
## 安装
|
|
18
|
-
|
|
19
|
-
支持 Windows、macOS 和 Linux,需要 Node.js ≥ 18.15。Bun 用于源码开发和构建。
|
|
20
|
-
|
|
21
|
-
DeepSeek Harness 子进程另需 Node 22.19+(22.x)或 Node 24+;可通过其账号配置的 `bin` 指定 Node 可执行文件。
|
|
13
|
+
需要 Node.js ≥ 18.15,支持 Windows、macOS 和 Linux。使用 DSH 时,其子进程需要 Node 22.19+(22.x)或 24+。
|
|
22
14
|
|
|
23
15
|
```bash
|
|
24
16
|
npm i -g @leviyuan/lodestar
|
|
25
17
|
lodestar-setup
|
|
26
18
|
```
|
|
27
19
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
把机器人拉进群,群名设为 `projects_root` 下的目录名。目录不存在时会自动创建。首次消息默认使用 Claude 侧已配置的账号;发 `model` 可切换到其他账号。
|
|
31
|
-
|
|
32
|
-
安装后提供以下命令:
|
|
33
|
-
|
|
34
|
-
| 命令 | 作用 |
|
|
35
|
-
| --- | --- |
|
|
36
|
-
| `lodestar-setup` | 配置向导 |
|
|
37
|
-
| `lodestar-daemon` | 启动 daemon |
|
|
38
|
-
| `lodestar-stop` | 停止 daemon |
|
|
39
|
-
| `lodestar-update` | 升级 Lodestar、Codex CLI、Claude Code 和相关 SDK |
|
|
40
|
-
| `lodestar-version` | 查看 Lodestar、Claude Code、Codex CLI 和运行时版本 |
|
|
41
|
-
| `lodestar-agent` | 由会话中的 Agent 调用其他模型执行任务 |
|
|
42
|
-
|
|
43
|
-
长期运行可交给 Linux `systemd --user`、macOS `launchd` 或 Windows 任务计划程序。daemon 重启后会恢复上次活跃的会话。
|
|
44
|
-
|
|
45
|
-
## 群内命令
|
|
46
|
-
|
|
47
|
-
直接发送下列词语,不加斜杠,大小写不敏感。这些命令控制当前群的 Agent 会话。
|
|
48
|
-
|
|
49
|
-
| 指令 | 行为 |
|
|
50
|
-
| --- | --- |
|
|
51
|
-
| `hi` | 打开控制台;会话未运行时先启动 |
|
|
52
|
-
| `stop` / `st` | 打断当前回复并取消排队消息,保留进程 |
|
|
53
|
-
| `kill` / `kl` | 关闭当前 Agent 进程,保存可恢复的会话记录 |
|
|
54
|
-
| `restart` / `rs` | 进程存活时打断并恢复当前会话;已停止时列出同目录的历史会话,选择后创建独立分支 |
|
|
55
|
-
| `clear` / `cl` | 关闭当前进程并开始新会话;已停止时提示先启动 |
|
|
56
|
-
| `compact` / `cm` | 压缩当前会话的上下文 |
|
|
57
|
-
| `model` / `md` | 按账号 → 模型 → effort 选择并保存 |
|
|
58
|
-
| `agents` | 查看可调用的 Agent 身份及可用状态 |
|
|
59
|
-
| `task` | 创建、查看或删除绑定的飞书任务清单 |
|
|
60
|
-
|
|
61
|
-
模型列表来自各账号的模型目录,获取失败显示 `MISS`。同账号切换 Claude 模型从后续回复生效,Codex 的持久模型设置需重启会话生效;跨账号或后端切换只允许在空闲时进行。
|
|
20
|
+
完成向导后,把机器人拉进群,将群名设为项目目录名。发送消息开始工作,发送 `md` 选择账号和模型。
|
|
62
21
|
|
|
63
|
-
|
|
22
|
+
Agent 默认自动跟随上游 `latest`,在 daemon 启动时及每 6 小时检查更新;也可用 `lodestar-update --agents-only` 立即更新。
|
|
64
23
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
需要独立修改文件时,在项目主群使用 worktree:
|
|
68
|
-
|
|
69
|
-
| 指令 | 行为 |
|
|
24
|
+
| 常用指令 | 作用 |
|
|
70
25
|
| --- | --- |
|
|
71
|
-
| `
|
|
72
|
-
| `
|
|
26
|
+
| `hi` | 查看会话、额度和 Codex 重置卡余量 |
|
|
27
|
+
| `md` | 按 Agent 分组选账号、模型和 effort;支持补录及隐藏 |
|
|
28
|
+
| `stop` | 打断当前回复 |
|
|
29
|
+
| `rs` / `cl` | 恢复会话 / 开始新会话 |
|
|
30
|
+
| `cm` | 压缩上下文 |
|
|
31
|
+
| `wt` / `btw` | 创建独立工作区 / 临时会话 |
|
|
73
32
|
|
|
74
|
-
|
|
33
|
+
单个发送文件不超过 **30 MB**。Codex 生图的提示词和图片默认折叠展示。
|
|
75
34
|
|
|
76
|
-
|
|
35
|
+
## 详细文档
|
|
77
36
|
|
|
78
|
-
|
|
|
37
|
+
| 文档 | 内容 |
|
|
79
38
|
| --- | --- |
|
|
80
|
-
|
|
|
81
|
-
|
|
|
82
|
-
|
|
|
83
|
-
|
|
|
84
|
-
|
|
85
|
-
`fk`、`bk` 和从历史记录恢复的 `rs` 都使用后端原生 fork,保留源对话。选第 N 条输入表示回到它发出之前,选中的输入不包含在新分支内。Claude 的新分支在首条输入时获得会话 id,准备状态会持久保存。
|
|
86
|
-
|
|
87
|
-
**分叉和回退只改变对话历史,不回滚文件或撤销 Shell、MCP 等外部操作。** `bk` 会附上已观察到的文件变更记录;需要目录隔离时使用 `wt`。
|
|
88
|
-
|
|
89
|
-
## 多模型任务
|
|
90
|
-
|
|
91
|
-
主 Agent 可以通过 `lodestar-agent` 查询实时身份,再把任务交给一个或多个模型。同一个任务选择多个身份时并发执行;后续追问可继续使用各模型的原生会话。
|
|
92
|
-
|
|
93
|
-
被调用的 Agent 可以编辑文件、执行命令、使用 MCP 和 Skill;委派只允许一层,被调用的 Agent 不能继续派工。它们与主 Agent 共享工作区,修改会立即可见。运行状态和结果通过卡片展示;需要用户输入时暂停,由主 Agent 回填答案后继续。委派产生的会话不会混入主群的 `rs` 历史列表。
|
|
94
|
-
|
|
95
|
-
`lodestar-agent` 只能在 Lodestar 管理的 Agent 进程里调用。命令用法见 [Agent Skill](src/agent-skill.ts)。
|
|
96
|
-
|
|
97
|
-
## 飞书任务清单
|
|
98
|
-
|
|
99
|
-
发 `task`,点“启用”可创建并绑定 `<project>[lodestar]` 任务清单。删除需要在卡片上再次确认,会删除整个清单及其中任务。该面板管理清单绑定,任务执行由用户和 Agent 安排。
|
|
100
|
-
|
|
101
|
-
## 本机通知
|
|
102
|
-
|
|
103
|
-
脚本可通过 HTTP 向项目群发送通知,支持 `info`、`warn`、`error`,以及本地图片、按钮和点击回调:
|
|
104
|
-
|
|
105
|
-
```bash
|
|
106
|
-
curl -sS -X POST http://127.0.0.1:9876/notify \
|
|
107
|
-
-H 'Content-Type: application/json' \
|
|
108
|
-
-d '{"project":"ops","level":"error","text":"构建失败,截图如下","images":["/abs/shot.png"]}'
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
按钮点击结果可以 POST 到指定的本机 `callback`,或通过 `GET /notify/result/<notify_id>` 查询。字段和协议见 [feishu-notify Skill](src/notify-skill.ts)。daemon 启动时会将该 Skill 同步到 Codex 和 Claude 的 Skill 目录。
|
|
112
|
-
|
|
113
|
-
## 配置
|
|
114
|
-
|
|
115
|
-
默认配置文件是 `~/.config/lodestar/config.toml`,可通过 `LODESTAR_CONFIG` 指定文件。日志和会话状态位于 `~/.local/share/lodestar/`;Windows 使用相应的应用数据目录。完整路径定义见 [src/paths.ts](src/paths.ts)。
|
|
116
|
-
|
|
117
|
-
```toml
|
|
118
|
-
[runtime]
|
|
119
|
-
projects_root = "/abs/projects"
|
|
120
|
-
live_elapsed = "bucket" # bucket 按档位刷新耗时;second 按秒刷新
|
|
121
|
-
|
|
122
|
-
[projects.calculator]
|
|
123
|
-
cwd = "/abs/projects/calculator" # 对两个后端均生效
|
|
124
|
-
setting_sources = "project" # Claude 后端;仅未绑定 Token Source 时使用
|
|
125
|
-
strict_mcp = "true" # 以下字段用于 Claude 主会话
|
|
126
|
-
load_project_mcp = "true"
|
|
127
|
-
tools = "Read,Write,Edit,Bash,Glob,Grep"
|
|
128
|
-
|
|
129
|
-
[claude]
|
|
130
|
-
bin = "/abs/path/to/claude-wrapper" # 可选的 Claude 可执行文件
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
账号配置使用 `[token_source.glm]`、`[token_source.deepseek]` 等节。GLM、DeepSeek 和 OpenRouter 也可以从本机 Claude settings 中识别;识别后由对应 Token Source 注入凭据,避免不同账号的环境变量串用。项目的工具限制只作用于主会话,委派 Agent 使用完整工具集。
|
|
134
|
-
|
|
135
|
-
`md` / `model` 首页用独立分组展示 `claude`、`codex`、`dsh`:每组都有浅蓝标题栏、边框和 `Agent · 名称` 标题,默认展开,Token Source 行放在组内。选账号后进入模型和 effort 选择。除 OpenRouter 的默认九项外,各来源默认显示接口目录。接口中的模型使用「隐藏 / 显示」,只调整面板可见性,接口新增模型仍会出现。
|
|
136
|
-
|
|
137
|
-
所有 Token Source 都提供「补录模型」,用于登记接口列表外的模型,并支持「删除」补录记录。记录保存在 `custom_models`;支持端点验证的来源会先验证,无法确认模型能力或 effort 的记录明确显示 `MISS`,不会凭空赋予运行能力。接口后来收录同名模型时自动转为接口项,不重复显示。删除补录记录需要先切换仍选用它的会话;默认模型和辅助模型中指向已删除补录项的配置也会清理。
|
|
138
|
-
|
|
139
|
-
所有对话卡的模型标识固定为 `claude · 模型名/effort`、`codex · 模型名/effort` 或 `dsh · 模型名/effort`。窗口额度沿用原来的紧凑格式,如 `4.1h·7%·[6.9d·17%]`(重置倒计时与已用百分比);余额显示 `余额 $12.34` 或 `余额 ¥12.34`。缺失或读取失败显示 `MISS`。
|
|
140
|
-
|
|
141
|
-
OpenRouter 通过 Claude Agent SDK 运行。在群内发送 `openrouter-setup <api_key>`,再通过 `model` 面板选择模型和 effort;自建兼容端点用 `openrouter-setup <base_url> <api_key>`。也可在配置文件中添加:
|
|
142
|
-
|
|
143
|
-
```toml
|
|
144
|
-
[token_source.openrouter]
|
|
145
|
-
agent = "claude"
|
|
146
|
-
api_key = "填写自己的 OpenRouter API key"
|
|
147
|
-
# base_url = "https://openrouter.ai/api" # SDK 自动追加 /v1/messages
|
|
148
|
-
# model = "anthropic/claude-fable-5.1" # 可选:默认运行模型,须获账号目录确认
|
|
149
|
-
# effort = "max" # 可选:仅覆盖默认运行模型的档位
|
|
150
|
-
# models = "anthropic/claude-fable-5.1,moonshotai/kimi-k3" # 可选:自定义可选列表
|
|
151
|
-
# slots = "haiku=anthropic/claude-fable-5.1" # 可选:辅助任务模型,须获账号目录确认且使用相同的 effort 参数模式
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
OpenRouter 默认可选列表按 [Arena Agent Labs 榜单](https://arena.ai/leaderboard/agent?rankBy=labs) 的 2026-09-08 快照设置:前 12 家各取排名最高的模型,排除 OpenAI、Z.ai / GLM、DeepSeek,保留以下 9 项。
|
|
155
|
-
|
|
156
|
-
| Labs 排名 | 厂商 | OpenRouter 模型 | 默认档位 |
|
|
157
|
-
| --- | --- | --- | --- |
|
|
158
|
-
| 1 | Anthropic | `anthropic/claude-fable-5.1` | max |
|
|
159
|
-
| 3 | Moonshot | `moonshotai/kimi-k3` | max |
|
|
160
|
-
| 4 | Tencent | `tencent/hy4-preview` | high |
|
|
161
|
-
| 7 | Google | `google/gemini-3.8-flash` | high |
|
|
162
|
-
| 8 | SpaceXAI | `x-ai/grok-4.5` | high |
|
|
163
|
-
| 9 | Alibaba | `qwen/qwen3.8-max-0902` | xhigh |
|
|
164
|
-
| 10 | Meta | `meta/muse-spark-1.2` | xhigh |
|
|
165
|
-
| 11 | Xiaomi | `xiaomi/mimo-v2.5-pro` | 模型默认 |
|
|
166
|
-
| 12 | MiniMax | `minimax/minimax-m3` | 模型默认 |
|
|
167
|
-
|
|
168
|
-
在 `md` / `model` → claude → OpenRouter 中,点「显示模型」选择账号目录中的模型,点每行「隐藏」移出面板列表。可见性自动持久化,不改当前运行模型;全部隐藏后也能继续显示或补录。未配置 `models` 时才使用上述九项;`models = ""` 明确表示没有已显示的接口模型,刷新或重启不会补回默认项。榜单变化不会覆盖用户维护的列表。
|
|
169
|
-
|
|
170
|
-
候选目录来自 `/api/v1/models/user`,按账号供应商和隐私设置筛选,仅纳入支持文本和工具调用的交互模型;OpenAI、GLM、DeepSeek 及无法保证厂商范围的自动路由不会出现在添加候选中。目录刷新失败显示 `MISS`。显式配置但已下线的模型保留为可删除的 `MISS` 项。
|
|
171
|
-
|
|
172
|
-
effort 按上游声明提供。小米、MiniMax 等没有 effort 选择器的模型使用「模型默认」,实际请求不携带 effort 参数。两种参数模式之间切换时,空闲进程会保存原生会话并在下一轮用新环境恢复;相同模式下继续使用 SDK 热切换。未配置 `model` 时需要通过面板明确选择运行模型。
|
|
173
|
-
|
|
174
|
-
OpenRouter 余额来自 `/api/v1/credits`,按 `total_credits - total_usage` 计算,卡片仅显示 `余额 $…`,不附加 Key 限额或累计消费。现有 Key 已实测返回 200;接口权限和错误以实际响应为准。SDK 使用 Bearer token,并显式清空 `ANTHROPIC_API_KEY`。OpenRouter 官方的兼容保证限于 Anthropic 第一方供应商;上述九项的工具调用、模型与档位参数已做真实验证,验证范围见 [后端说明](docs/claude-agent-backend.md)。
|
|
175
|
-
|
|
176
|
-
DeepSeek Harness 使用独立的 `[token_source.deepseek-harness]` 账号与原生会话。在群内发送 `deepseek-harness-setup <api_key>`,再通过 `model` 面板选择该来源即可启用。自建端点用 `deepseek-harness-setup <base_url> <api_key>`;这里使用原生 API 根地址,不带 `/anthropic`。
|
|
177
|
-
|
|
178
|
-
DSH 也支持 GLM Coding Plan:已有 `[token_source.glm]` 时自动复用该账号,在 `md` → dsh → GLM Coding Plan 中选择模型。独立凭据用 `dsh-glm-setup [base_url] <api_key>`,配置节为 `[token_source.dsh-glm]`。它调用 Coding Plan 的 OpenAI 端点,复用 GLM 额度查询;不经过 OpenRouter 或 Claude SDK。账号接口返回的模型都进入列表,当前 DSH 原生目录未声明能力的项显示 `MISS`,也可隐藏和恢复。
|
|
179
|
-
|
|
180
|
-
```toml
|
|
181
|
-
[token_source.deepseek-harness]
|
|
182
|
-
agent = "dsh"
|
|
183
|
-
api_key = "填写自己的 API key"
|
|
184
|
-
# bin = "/abs/path/to/node" # 可选:运行 DSH 的 Node 可执行文件
|
|
185
|
-
# model = "deepseek-v4-pro" # 可选:必须存在于 DSH 返回的模型目录
|
|
186
|
-
# effort = "high" # 可选:必须是该模型支持的推理强度
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
手动修改配置后需重启 daemon;群内账号启用和模型补录会自行重载相关配置。模型路由、配置优先级和后端差异见 [后端说明](docs/claude-agent-backend.md)。
|
|
39
|
+
| [安装与配置](docs/configuration.md) | CLI、配置文件、服务运行、Agent 自动更新 |
|
|
40
|
+
| [群内使用指南](docs/usage.md) | 完整命令、会话恢复、worktree、多模型任务、文件及通知 |
|
|
41
|
+
| [账号与模型](docs/models.md) | Token Source、effort、OpenRouter 默认模型、DSH 与 GLM 接入 |
|
|
42
|
+
| [后端与路由](docs/claude-agent-backend.md) | 运行机制、接口差异和维护说明 |
|
|
43
|
+
| [DSH 测试记录](docs/dsh-testing-report.md) | 原生工具、会话和飞书实测记录 |
|
|
190
44
|
|
|
191
45
|
## 开发
|
|
192
46
|
|
|
@@ -197,8 +51,6 @@ bun test
|
|
|
197
51
|
bun run build
|
|
198
52
|
```
|
|
199
53
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
## 许可
|
|
54
|
+
源码运行:`bun run start`。真实飞书探针使用前请阅读[脚本说明](scripts/AGENTS.md)。
|
|
203
55
|
|
|
204
|
-
[MIT](LICENSE)
|
|
56
|
+
[MIT License](LICENSE)
|
package/dist/dsh-bridge.js
CHANGED
|
@@ -1,15 +1,27 @@
|
|
|
1
1
|
// src/dsh-bridge.ts
|
|
2
2
|
import { createInterface } from "node:readline";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
import { readFileSync } from "node:fs";
|
|
4
6
|
import { realpath } from "node:fs/promises";
|
|
5
7
|
import { createUserMessage, ReasoningEffortId } from "@deepseek-ai/dsh-llm";
|
|
6
8
|
import { SessionLogOffset } from "@deepseek-ai/dsh-session";
|
|
9
|
+
|
|
10
|
+
// src/dsh-protocol.ts
|
|
11
|
+
var DSH_PROTOCOL_VERSION = 1;
|
|
12
|
+
|
|
13
|
+
// src/dsh-bridge.ts
|
|
7
14
|
var name = "lodestar-bridge";
|
|
8
15
|
var inject = ["agents", "llm", "agentDefaultModel", "sessionPersistence", "tools", "systemPrompt", "userQuestions", "compaction", "shellEnv", "attachments", "sdkAppStartup"];
|
|
9
16
|
var PROVIDER = process.env.LODESTAR_DSH_PROVIDER ?? "deepseek-official";
|
|
10
17
|
if (!["deepseek-official", "zai-coding-cn", "zai"].includes(PROVIDER))
|
|
11
18
|
throw new Error(`Unsupported DSH provider: ${PROVIDER}`);
|
|
12
19
|
var DELEGATION_TOOLS = ["subagent", "subagent_fork", "workflow", "ralph", "send_message"];
|
|
20
|
+
function nativeErrorMessage(error, depth = 0) {
|
|
21
|
+
if (!(error instanceof Error))
|
|
22
|
+
return String(error);
|
|
23
|
+
return error.cause && depth < 4 ? `${error.message}: ${nativeErrorMessage(error.cause, depth + 1)}` : error.message;
|
|
24
|
+
}
|
|
13
25
|
function apply(ctx) {
|
|
14
26
|
let root;
|
|
15
27
|
let rootId;
|
|
@@ -30,7 +42,7 @@ function apply(ctx) {
|
|
|
30
42
|
`);
|
|
31
43
|
};
|
|
32
44
|
const fail = (error) => {
|
|
33
|
-
const message =
|
|
45
|
+
const message = nativeErrorMessage(error);
|
|
34
46
|
process.stderr.write(`lodestar-dsh: ${message}
|
|
35
47
|
`);
|
|
36
48
|
notify("failure", { message });
|
|
@@ -91,7 +103,9 @@ function apply(ctx) {
|
|
|
91
103
|
settle();
|
|
92
104
|
});
|
|
93
105
|
ctx.on("agent/error", ({ agent, error }) => {
|
|
94
|
-
const message =
|
|
106
|
+
const message = nativeErrorMessage(error);
|
|
107
|
+
process.stderr.write(`lodestar-dsh agent error: ${message}
|
|
108
|
+
`);
|
|
95
109
|
if (agent.session.id === rootId)
|
|
96
110
|
turnFailure = message;
|
|
97
111
|
notify("agent.error", { sessionId: agent.session.id, message });
|
|
@@ -133,8 +147,13 @@ function apply(ctx) {
|
|
|
133
147
|
notify("question", { id, questions: request.questions });
|
|
134
148
|
});
|
|
135
149
|
});
|
|
136
|
-
async function catalog() {
|
|
137
|
-
const models = await ctx.llm.listModels(PROVIDER);
|
|
150
|
+
async function catalog(extra = []) {
|
|
151
|
+
const models = [...await ctx.llm.listModels(PROVIDER)];
|
|
152
|
+
const listed = new Set(models.map((model) => model.id));
|
|
153
|
+
for (const id of new Set(extra)) {
|
|
154
|
+
if (!listed.has(id))
|
|
155
|
+
models.push(await ctx.llm.resolveModelInfo(PROVIDER, id));
|
|
156
|
+
}
|
|
138
157
|
if (!models.length)
|
|
139
158
|
throw new Error("DSH model catalog is empty");
|
|
140
159
|
return Promise.all(models.map(async (model) => {
|
|
@@ -148,14 +167,12 @@ function apply(ctx) {
|
|
|
148
167
|
efforts: info.reasoning.efforts.map((e) => e.id),
|
|
149
168
|
defaultEffort: info.reasoning.defaultEffort,
|
|
150
169
|
contextWindow: info.context?.contextWindow ?? null,
|
|
151
|
-
isDefault: ctx.agentDefaultModel.currentSelection().provider === PROVIDER && ctx.agentDefaultModel.currentSelection().model === model.id
|
|
170
|
+
isDefault: ctx.agentDefaultModel.currentSelection().provider === PROVIDER && ctx.agentDefaultModel.currentSelection().model === model.id,
|
|
171
|
+
isCustom: !listed.has(model.id)
|
|
152
172
|
};
|
|
153
173
|
}));
|
|
154
174
|
}
|
|
155
175
|
async function route(model, effort) {
|
|
156
|
-
const info = (await catalog()).find((entry) => entry.model === model);
|
|
157
|
-
if (!info || !info.efforts.some((e) => e === effort))
|
|
158
|
-
throw new Error(`DSH model/effort unavailable: ${model}/${effort}`);
|
|
159
176
|
return ctx.llm.resolveCallConfig({ provider: PROVIDER, model, reasoningEffort: ReasoningEffortId(effort) });
|
|
160
177
|
}
|
|
161
178
|
async function open(input) {
|
|
@@ -231,7 +248,7 @@ function apply(ctx) {
|
|
|
231
248
|
}
|
|
232
249
|
await ctx.sessionPersistence.flush();
|
|
233
250
|
lifecycle.signal.throwIfAborted();
|
|
234
|
-
return { sessionId: rootId, models: await catalog() };
|
|
251
|
+
return { sessionId: rootId, models: await catalog([input.model]) };
|
|
235
252
|
} catch (error) {
|
|
236
253
|
if (!root)
|
|
237
254
|
rootId = undefined;
|
|
@@ -246,13 +263,15 @@ function apply(ctx) {
|
|
|
246
263
|
throw new Error("DSH already initialized");
|
|
247
264
|
await ctx.get("loader")?.await();
|
|
248
265
|
initialized = true;
|
|
249
|
-
|
|
266
|
+
const require2 = createRequire(import.meta.url);
|
|
267
|
+
const manifest = JSON.parse(readFileSync(require2.resolve("@deepseek-ai/dsh/package.json"), "utf8"));
|
|
268
|
+
return { protocolVersion: DSH_PROTOCOL_VERSION, runtimeVersion: manifest.version };
|
|
250
269
|
}
|
|
251
270
|
if (!initialized)
|
|
252
271
|
throw new Error("DSH not initialized");
|
|
253
272
|
switch (method) {
|
|
254
273
|
case "model/list":
|
|
255
|
-
return catalog();
|
|
274
|
+
return catalog(params.models ?? []);
|
|
256
275
|
case "session/open": {
|
|
257
276
|
if (opening)
|
|
258
277
|
throw new Error("DSH session initialization is already in progress");
|
package/dist/lodestar-setup.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{execSync as C,spawn as G}from"node:child_process";import{existsSync as B,mkdirSync as I,readFileSync as e}from"node:fs";import{createInterface as zz}from"node:readline/promises";import{delimiter as $z,dirname as qz,join as F}from"node:path";import{homedir as Jz}from"node:os";import{fileURLToPath as Qz}from"node:url";import{homedir as h}from"node:os";import{join as Y}from"node:path";var w=h(),g=process.platform==="win32";function S($,q,J){if($)return $;if(q)return Y(q,"lodestar");return J}function m(){if(g)return Y(process.env.APPDATA??Y(w,"AppData","Roaming"),"Lodestar");return Y(w,".config","lodestar")}function p(){if(g)return Y(process.env.LOCALAPPDATA??Y(w,"AppData","Local"),"Lodestar");return Y(w,".local","share","lodestar")}var v=S(process.env.LODESTAR_CONFIG_DIR,process.env.XDG_CONFIG_HOME,m()),H=S(process.env.LODESTAR_DATA_DIR,process.env.XDG_DATA_HOME,p()),O=process.env.LODESTAR_CONFIG??Y(v,"config.toml"),Lz=Y(H,"daemon.pid"),Mz=Y(H,"daemon.log"),Gz=Y(H,"session-chat-map.json"),kz=Y(H,"session-resume-map.json"),Oz=Y(H,"session-turns-map.json"),wz=Y(H,"session-model-map.json"),Ez=Y(H,"temp-session-leases.json"),xz=Y(H,"tasklist-map.json"),Bz=Y(H,"agent-runs"),Fz=Y(H,"agent-session-ids.json"),vz=Y(H,"managed-claude-plugin"),yz=Y(H,"dsh"),Rz=Y(H,"context-window-cache.json"),Tz=Y(H,"notify-callbacks.json"),uz=Y(H,"alive-on-shutdown.json"),gz=Y(H,"inbox"),Sz=Y(H,"debug.sock"),jz=Y(H,"debug-context.json");import{chmodSync as c,closeSync as y,fsyncSync as j,mkdirSync as l,openSync as P,renameSync as r,unlinkSync as s,writeFileSync as d}from"node:fs";import{randomUUID as a}from"node:crypto";import{dirname as _}from"node:path";var o=384;var i=448;function n($){let q=_($);l(q,{recursive:!0,mode:i})}function t($,q,J){n($);let Q=`${$}.${process.pid}.${a()}.tmp`,X=null;try{X=P(Q,"wx",J),d(X,q),j(X),y(X),X=null,r(Q,$);try{c($,J)}catch{}if(process.platform!=="win32"){let W=null;try{W=P(_($),"r"),j(W)}catch{}finally{if(W!==null)try{y(W)}catch{}}}}catch(W){if(X!==null)try{y(X)}catch{}try{s(Q)}catch{}throw W}}function R($,q){t($,q,o)}var z={reset:"\x1B[0m",bold:"\x1B[1m",dim:"\x1B[2m",green:"\x1B[32m",yellow:"\x1B[33m",cyan:"\x1B[36m",red:"\x1B[31m"},M=zz({input:process.stdin,output:process.stdout});async function L($,q={}){while(!0){let J=q.default?`${z.dim} [${q.default}]${z.reset}`:"",Q=(await M.question(`${z.cyan}? ${z.reset}${$}${J}
|
|
3
|
-
${
|
|
4
|
-
|
|
5
|
-
`)}function
|
|
6
|
-
${
|
|
7
|
-
|
|
8
|
-
`)
|
|
9
|
-
${
|
|
2
|
+
import{createRequire as K1}from"node:module";var Y1=Object.create;var{getPrototypeOf:H1,defineProperty:$0,getOwnPropertyNames:V1}=Object;var L1=Object.prototype.hasOwnProperty;function U1(q){return this[q]}var W1,B1,q0=(q,z,J)=>{var Q=q!=null&&typeof q==="object";if(Q){var Z=z?W1??=new WeakMap:B1??=new WeakMap,X=Z.get(q);if(X)return X}J=q!=null?Y1(H1(q)):{};let Y=z||!q||!q.__esModule?$0(J,"default",{value:q,enumerable:!0}):J;for(let H of V1(q))if(!L1.call(Y,H))$0(Y,H,{get:U1.bind(q,H),enumerable:!0});if(Q)Z.set(q,Y);return Y};var G=(q,z)=>()=>(z||q((z={exports:{}}).exports,z),z.exports);var F=K1(import.meta.url);var X0=G((y8,Z0)=>{Z0.exports=Q0;Q0.sync=G1;var z0=F("fs");function M1(q,z){var J=z.pathExt!==void 0?z.pathExt:process.env.PATHEXT;if(!J)return!0;if(J=J.split(";"),J.indexOf("")!==-1)return!0;for(var Q=0;Q<J.length;Q++){var Z=J[Q].toLowerCase();if(Z&&q.substr(-Z.length).toLowerCase()===Z)return!0}return!1}function J0(q,z,J){if(!q.isSymbolicLink()&&!q.isFile())return!1;return M1(z,J)}function Q0(q,z,J){z0.stat(q,function(Q,Z){J(Q,Q?!1:J0(Z,q,z))})}function G1(q,z){return J0(z0.statSync(q),q,z)}});var U0=G((j8,L0)=>{L0.exports=H0;H0.sync=N1;var Y0=F("fs");function H0(q,z,J){Y0.stat(q,function(Q,Z){J(Q,Q?!1:V0(Z,z))})}function N1(q,z){return V0(Y0.statSync(q),z)}function V0(q,z){return q.isFile()&&O1(q,z)}function O1(q,z){var{mode:J,uid:Q,gid:Z}=q,X=z.uid!==void 0?z.uid:process.getuid&&process.getuid(),Y=z.gid!==void 0?z.gid:process.getgid&&process.getgid(),H=parseInt("100",8),V=parseInt("010",8),U=parseInt("001",8),W=H|V,L=J&U||J&V&&Z===Y||J&H&&Q===X||J&W&&X===0;return L}});var B0=G((D8,W0)=>{var S8=F("fs"),R;if(process.platform==="win32"||global.TESTING_WINDOWS)R=X0();else R=U0();W0.exports=D;D.sync=k1;function D(q,z,J){if(typeof z==="function")J=z,z={};if(!J){if(typeof Promise!=="function")throw TypeError("callback not provided");return new Promise(function(Q,Z){D(q,z||{},function(X,Y){if(X)Z(X);else Q(Y)})})}R(q,z||{},function(Q,Z){if(Q){if(Q.code==="EACCES"||z&&z.ignoreErrors)Q=null,Z=!1}J(Q,Z)})}function k1(q,z){try{return R.sync(q,z||{})}catch(J){if(z&&z.ignoreErrors||J.code==="EACCES")return!1;else throw J}}});var F0=G((v8,k0)=>{var _=process.platform==="win32"||process.env.OSTYPE==="cygwin"||process.env.OSTYPE==="msys",K0=F("path"),F1=_?";":":",M0=B0(),G0=(q)=>Object.assign(Error(`not found: ${q}`),{code:"ENOENT"}),N0=(q,z)=>{let J=z.colon||F1,Q=q.match(/\//)||_&&q.match(/\\/)?[""]:[..._?[process.cwd()]:[],...(z.path||process.env.PATH||"").split(J)],Z=_?z.pathExt||process.env.PATHEXT||".EXE;.CMD;.BAT;.COM":"",X=_?Z.split(J):[""];if(_){if(q.indexOf(".")!==-1&&X[0]!=="")X.unshift("")}return{pathEnv:Q,pathExt:X,pathExtExe:Z}},O0=(q,z,J)=>{if(typeof z==="function")J=z,z={};if(!z)z={};let{pathEnv:Q,pathExt:Z,pathExtExe:X}=N0(q,z),Y=[],H=(U)=>new Promise((W,L)=>{if(U===Q.length)return z.all&&Y.length?W(Y):L(G0(q));let K=Q[U],O=/^".*"$/.test(K)?K.slice(1,-1):K,k=K0.join(O,q),S=!O&&/^\.[\\\/]/.test(q)?q.slice(0,2)+k:k;W(V(S,U,0))}),V=(U,W,L)=>new Promise((K,O)=>{if(L===Z.length)return K(H(W+1));let k=Z[L];M0(U+k,{pathExt:X},(S,X1)=>{if(!S&&X1)if(z.all)Y.push(U+k);else return K(U+k);return K(V(U,W,L+1))})});return J?H(0).then((U)=>J(null,U),J):H(0)},T1=(q,z)=>{z=z||{};let{pathEnv:J,pathExt:Q,pathExtExe:Z}=N0(q,z),X=[];for(let Y=0;Y<J.length;Y++){let H=J[Y],V=/^".*"$/.test(H)?H.slice(1,-1):H,U=K0.join(V,q),W=!V&&/^\.[\\\/]/.test(q)?q.slice(0,2)+U:U;for(let L=0;L<Q.length;L++){let K=W+Q[L];try{if(M0.sync(K,{pathExt:Z}))if(z.all)X.push(K);else return K}catch(O){}}}if(z.all&&X.length)return X;if(z.nothrow)return null;throw G0(q)};k0.exports=O0;O0.sync=T1});var _0=G((w8,v)=>{var T0=(q={})=>{let z=q.env||process.env;if((q.platform||process.platform)!=="win32")return"PATH";return Object.keys(z).reverse().find((Q)=>Q.toUpperCase()==="PATH")||"Path"};v.exports=T0;v.exports.default=T0});var I0=G((A8,b0)=>{var x0=F("path"),_1=F0(),x1=_0();function P0(q,z){let J=q.options.env||process.env,Q=process.cwd(),Z=q.options.cwd!=null,X=Z&&process.chdir!==void 0&&!process.chdir.disabled;if(X)try{process.chdir(q.options.cwd)}catch(H){}let Y;try{Y=_1.sync(q.command,{path:J[x1({env:J})],pathExt:z?x0.delimiter:void 0})}catch(H){}finally{if(X)process.chdir(Q)}if(Y)Y=x0.resolve(Z?q.options.cwd:"",Y);return Y}function P1(q){return P0(q)||P0(q,!0)}b0.exports=P1});var R0=G((R1,A)=>{var w=/([()\][%!^"`<>&|;, *?])/g;function b1(q){return q=q.replace(w,"^$1"),q}function I1(q,z){if(q=`${q}`,q=q.replace(/(?=(\\+?)?)\1"/g,"$1$1\\\""),q=q.replace(/(?=(\\+?)?)\1$/,"$1$1"),q=`"${q}"`,q=q.replace(w,"^$1"),z)q=q.replace(w,"^$1");return q}R1.command=b1;R1.argument=I1});var y0=G((E8,f0)=>{f0.exports=/^#!(.*)/});var S0=G((u8,j0)=>{var j1=y0();j0.exports=(q="")=>{let z=q.match(j1);if(!z)return null;let[J,Q]=z[0].replace(/#! ?/,"").split(" "),Z=J.split("/").pop();if(Z==="env")return Q;return Q?`${Z} ${Q}`:Z}});var v0=G((h8,D0)=>{var E=F("fs"),S1=S0();function D1(q){let J=Buffer.alloc(150),Q;try{Q=E.openSync(q,"r"),E.readSync(Q,J,0,150,0),E.closeSync(Q)}catch(Z){}return S1(J.toString())}D0.exports=D1});var u0=G((g8,E0)=>{var v1=F("path"),w0=I0(),A0=R0(),w1=v0(),A1=process.platform==="win32",E1=/\.(?:com|exe)$/i,u1=/node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;function h1(q){q.file=w0(q);let z=q.file&&w1(q.file);if(z)return q.args.unshift(q.file),q.command=z,w0(q);return q.file}function g1(q){if(!A1)return q;let z=h1(q),J=!E1.test(z);if(q.options.forceShell||J){let Q=u1.test(z);q.command=v1.normalize(q.command),q.command=A0.command(q.command),q.args=q.args.map((X)=>A0.argument(X,Q));let Z=[q.command].concat(q.args).join(" ");q.args=["/d","/s","/c",`"${Z}"`],q.command=process.env.comspec||"cmd.exe",q.options.windowsVerbatimArguments=!0}return q}function c1(q,z,J){if(z&&!Array.isArray(z))J=z,z=null;z=z?z.slice(0):[],J=Object.assign({},J);let Q={command:q,args:z,options:J,file:void 0,original:{command:q,args:z}};return J.shell?Q:g1(Q)}E0.exports=c1});var c0=G((c8,g0)=>{var u=process.platform==="win32";function h(q,z){return Object.assign(Error(`${z} ${q.command} ENOENT`),{code:"ENOENT",errno:"ENOENT",syscall:`${z} ${q.command}`,path:q.command,spawnargs:q.args})}function m1(q,z){if(!u)return;let J=q.emit;q.emit=function(Q,Z){if(Q==="exit"){let X=h0(Z,z);if(X)return J.call(q,"error",X)}return J.apply(q,arguments)}}function h0(q,z){if(u&&q===1&&!z.file)return h(z.original,"spawn");return null}function l1(q,z){if(u&&q===1&&!z.file)return h(z.original,"spawnSync");return null}g0.exports={hookChildProcess:m1,verifyENOENT:h0,verifyENOENTSync:l1,notFoundError:h}});var m=G((m8,x)=>{var m0=F("child_process"),g=u0(),c=c0();function l0(q,z,J){let Q=g(q,z,J),Z=m0.spawn(Q.command,Q.args,Q.options);return c.hookChildProcess(Z,Q),Z}function C1(q,z,J){let Q=g(q,z,J),Z=m0.spawnSync(Q.command,Q.args,Q.options);return Z.error=Z.error||c.verifyENOENTSync(Z.status,Q),Z}x.exports=l0;x.exports.spawn=l0;x.exports.sync=C1;x.exports._parse=g;x.exports._enoent=c});var J1=q0(m(),1);import{execFileSync as B8,spawn as j}from"node:child_process";import{existsSync as a,mkdirSync as Q1,readFileSync as K8}from"node:fs";import{createInterface as M8}from"node:readline/promises";import{dirname as G8,join as e}from"node:path";import{homedir as N8}from"node:os";import{fileURLToPath as O8}from"node:url";import{homedir as d1}from"node:os";import{join as B}from"node:path";var f=d1(),C0=process.platform==="win32";function d0(q,z,J){if(q)return q;if(z)return B(z,"lodestar");return J}function p1(){if(C0)return B(process.env.APPDATA??B(f,"AppData","Roaming"),"Lodestar");return B(f,".config","lodestar")}function i1(){if(C0)return B(process.env.LOCALAPPDATA??B(f,"AppData","Local"),"Lodestar");return B(f,".local","share","lodestar")}var l=d0(process.env.LODESTAR_CONFIG_DIR,process.env.XDG_CONFIG_HOME,p1()),M=d0(process.env.LODESTAR_DATA_DIR,process.env.XDG_DATA_HOME,i1()),P=process.env.LODESTAR_CONFIG??B(l,"config.toml"),d8=B(M,"daemon.pid"),p8=B(M,"daemon.log"),i8=B(M,"session-chat-map.json"),n8=B(M,"session-resume-map.json"),r8=B(M,"session-turns-map.json"),s8=B(M,"session-model-map.json"),o8=B(M,"temp-session-leases.json"),t8=B(M,"tasklist-map.json"),a8=B(M,"agent-runs"),e8=B(M,"agent-session-ids.json"),$$=B(M,"managed-claude-plugin"),q$=B(M,"dsh"),C=B(M,"agent-runtimes"),z$=B(M,"context-window-cache.json"),J$=B(M,"notify-callbacks.json"),Q$=B(M,"alive-on-shutdown.json"),Z$=B(M,"inbox"),X$=B(M,"debug.sock"),Y$=B(M,"debug-context.json");import{chmodSync as n1,closeSync as d,fsyncSync as p0,mkdirSync as r1,openSync as i0,renameSync as s1,unlinkSync as o1,writeFileSync as t1}from"node:fs";import{randomUUID as a1}from"node:crypto";import{dirname as n0}from"node:path";var e1=384;var $8=448;function q8(q){let z=n0(q);r1(z,{recursive:!0,mode:$8})}function z8(q,z,J){q8(q);let Q=`${q}.${process.pid}.${a1()}.tmp`,Z=null;try{Z=i0(Q,"wx",J),t1(Z,z),p0(Z),d(Z),Z=null,s1(Q,q);try{n1(q,J)}catch{}if(process.platform!=="win32"){let X=null;try{X=i0(n0(q),"r"),p0(X)}catch{}finally{if(X!==null)try{d(X)}catch{}}}}catch(X){if(Z!==null)try{d(Z)}catch{}try{o1(Q)}catch{}throw X}}function p(q,z){z8(q,z,e1)}import{createHash as J8}from"node:crypto";var e0=q0(m(),1);import{existsSync as n,readFileSync as s0}from"node:fs";import{mkdir as o0,mkdtemp as Q8,readFile as t0,rename as a0,rm as i,writeFile as r}from"node:fs/promises";import{join as N,isAbsolute as Z8}from"node:path";import{fileURLToPath as X8,pathToFileURL as O$}from"node:url";var $1="https://registry.npmjs.org",b={codex:["@openai/codex"],claude:["@anthropic-ai/claude-code","@anthropic-ai/claude-agent-sdk","@anthropic-ai/sdk"],dsh:["@deepseek-ai/dsh","@deepseek-ai/dsh-llm-pi-ai","@deepseek-ai/dsh-tool-ask-user"]},Y8=(q)=>q instanceof Error?q.message:String(q);function q1(q,z=C){let J=N(z,q,"current.json");if(!n(J))return null;let Q=JSON.parse(s0(J,"utf8"));if(!Number.isFinite(Q.checkedAt)||Q.directory!==void 0&&!Z8(Q.directory))throw Error(`Invalid ${q} runtime state: ${J}`);return Q}function H8(q){let z=q1(q);if(z?.error)throw Error(`${q} 自动更新失败: ${z.error}`);if(!z?.directory)throw Error(`${q} runtime 未安装,请运行 lodestar-update --agents-only`);return z.directory}function s(q,z){let J=N(H8(q),"node_modules",".bin",`${z}${process.platform==="win32"?".cmd":""}`);if(!n(J))throw Error(`${q} executable missing: ${J}`);return J}async function V8(q,z,J){let Q=new AbortController,Z=()=>Q.abort(J?.reason);if(J?.addEventListener("abort",Z,{once:!0}),J?.aborted)Z();let X=setTimeout(()=>Q.abort(Error("npm registry request timed out")),30000);try{let Y=await fetch(`${$1}/${encodeURIComponent(q)}/${encodeURIComponent(z)}`,{signal:Q.signal});if(!Y.ok)throw Error(`${q}@${z}: npm HTTP ${Y.status}`);let H=await Y.json();if(H.name!==q||typeof H.version!=="string"||!H.version)throw Error(`Invalid npm manifest: ${q}@${z}`);return H}finally{clearTimeout(X),J?.removeEventListener("abort",Z)}}async function L8(q,z){let J={};if(q!=="dsh"){let Y=await Promise.all(b[q].map((H)=>z(H,"latest")));for(let H of Y)J[H.name]=H.version;return J}let Q=await z("@deepseek-ai/dsh","latest"),Z=new Set(b.dsh),X=new Set;while(Z.size){let Y=[...Z].slice(0,12);for(let V of Y)Z.delete(V),X.add(V);let H=await Promise.all(Y.map((V)=>V===Q.name?Q:z(V,Q.version)));for(let V of H){if(V.version!==Q.version)throw Error(`DSH release package mismatch: ${V.name}@${V.version}, expected ${Q.version}`);J[V.name]=V.version;for(let U of Object.keys({...V.dependencies,...V.peerDependencies,...V.optionalDependencies}))if(U.startsWith("@deepseek-ai/dsh")&&!X.has(U))Z.add(U)}}return J}function U8(q,z){return new Promise((J,Q)=>{let Z=e0.spawn("npm",["install","--prefix",q,"--include=optional","--no-fund","--no-audit",`--registry=${$1}`],{cwd:q,stdio:["ignore","pipe","pipe"],shell:!1}),X="",Y,H=(W)=>{X=(X+W.toString()).slice(-16384)};Z.stdout.on("data",H),Z.stderr.on("data",H);let V=()=>{Y=Error("Agent runtime install aborted"),Z.kill("SIGTERM")};if(z?.addEventListener("abort",V,{once:!0}),z?.aborted)V();let U=setTimeout(()=>{Y=Error("Agent runtime install timed out after 5 minutes"),Z.kill("SIGTERM")},300000);Z.on("error",(W)=>{Y=W}),Z.once("close",(W)=>{if(clearTimeout(U),z?.removeEventListener("abort",V),Y||W!==0)Q(Error(`${Y?.message??`npm install exited ${W}`}
|
|
3
|
+
${X}`));else J()})})}async function r0(q,z){let J=N(q,`current-${process.pid}-${Date.now()}.json`);await r(J,JSON.stringify(z)+`
|
|
4
|
+
`,{mode:384}),await a0(J,N(q,"current.json"))}async function W8(q,z){let J=N(q,"update.lock"),Q=Date.now()+360000;for(;;){z?.throwIfAborted();try{return await o0(J),await r(N(J,"pid"),String(process.pid)),()=>i(J,{recursive:!0})}catch(Z){if(Z.code!=="EEXIST")throw Z;try{let X=Number(await t0(N(J,"pid"),"utf8"));if(!Number.isSafeInteger(X)||X<=0)throw Error(`Invalid runtime update lock: ${J}`);try{process.kill(X,0)}catch(Y){if(Y.code!=="ESRCH")throw Y;await i(J,{recursive:!0});continue}}catch(X){if(X.code!=="ENOENT")throw X}if(Date.now()>=Q)throw Error(`Timed out waiting for runtime update lock: ${J}`);await new Promise((X)=>setTimeout(X,200))}}}async function o(q,z={}){let J=z.root??C,Q=N(J,q);await o0(Q,{recursive:!0,mode:448});let Z=await W8(Q,z.signal),X;try{z.report?.(`${q}: 检查 upstream latest`);let Y=q1(q,J),H=await L8(q,z.metadata??((K,O)=>V8(K,O,z.signal)));z.signal?.throwIfAborted();let V=JSON.parse(s0(X8(new URL("../package.json",import.meta.url)),"utf8")).overrides??{},U=J8("sha256").update(JSON.stringify({installFormat:2,versions:Object.entries(H).sort(),security:V,platform:process.platform,arch:process.arch})).digest("hex").slice(0,20),W=N(Q,U);if(!n(W)){X=await Q8(N(Q,".install-")),await r(N(X,"package.json"),JSON.stringify({name:`lodestar-runtime-${q}`,version:H[b[q][0]],private:!0,type:"module",dependencies:H,overrides:{...V,...q==="dsh"?H:{}}})+`
|
|
5
|
+
`,{mode:384}),await(z.install??U8)(X,z.signal);for(let[K,O]of Object.entries(H)){let k=JSON.parse(await t0(N(X,"node_modules",K,"package.json"),"utf8"));if(k.version!==O)throw Error(`npm installed ${K}@${k.version}, expected ${O}`)}z.signal?.throwIfAborted(),await a0(X,W),X=void 0}let L={directory:W,versions:H,checkedAt:Date.now()};return await r0(Q,L),z.report?.(`${q}: ${b[q][0]}@${H[b[q][0]]}${Y?.directory===W?" 已是 latest":" 已更新,新进程使用新版"}`),L}catch(Y){throw await r0(Q,{checkedAt:Date.now(),error:Y8(Y)}),Y}finally{try{if(X)await i(X,{recursive:!0})}finally{await Z()}}}var $={reset:"\x1B[0m",bold:"\x1B[1m",dim:"\x1B[2m",green:"\x1B[32m",yellow:"\x1B[33m",cyan:"\x1B[36m",red:"\x1B[31m"},I=M8({input:process.stdin,output:process.stdout});async function T(q,z={}){while(!0){let J=z.default?`${$.dim} [${z.default}]${$.reset}`:"",Q=(await I.question(`${$.cyan}? ${$.reset}${q}${J}
|
|
6
|
+
${$.green}>${$.reset} `)).trim();if(!Q&&z.default!==void 0)return z.default;if(!Q&&z.required){console.log(`${$.red}必填,请重新输入${$.reset}`);continue}return Q}}function k8(q){let z="═".repeat(58);console.log(`
|
|
7
|
+
${$.bold}${$.cyan}╔${z}╗${$.reset}`),console.log(`${$.bold}${$.cyan}║ ${q.padEnd(54)} ║${$.reset}`),console.log(`${$.bold}${$.cyan}╚${z}╝${$.reset}
|
|
8
|
+
`)}function y(q,z,J){console.log(`
|
|
9
|
+
${$.bold}${$.yellow}[${q}/${z}] ${J}${$.reset}
|
|
10
|
+
`)}function t(q){return q.replace(/\\/g,"\\\\").replace(/"/g,"\\\"")}function z1(q){try{let z=B8(q,["login","status"],{timeout:1e4,shell:process.platform==="win32"}).toString();return/Logged in using ChatGPT/i.test(z)}catch{return!1}}async function F8(q){return new Promise((z)=>{let J=J1.spawn(q,["login"],{stdio:"inherit",shell:!1});J.on("exit",(Q)=>z(Q===0)),J.on("error",()=>z(!1))})}function T8(){return process.env.CLAUDE_CONFIG_DIR||e(N8(),".claude")}async function _8(q){try{let z=await fetch("https://open.bigmodel.cn/api/anthropic/v1/models",{headers:{Authorization:`Bearer ${q}`},signal:AbortSignal.timeout(1e4)});if(!z.ok)return null;let J=await z.json(),Q=(Array.isArray(J?.data)?J.data:[]).map((L)=>typeof L?.display_name==="string"&&L.display_name?L.display_name:String(L?.id??"")).filter(Boolean);if(!Q.length)return null;let Z=(L)=>{let K=L.match(/(\d+(?:\.\d+)?)/);return K?Number(K[1]):-1},X=(L)=>L.replace(/-Turbo|-Air$/i,""),H=[...Q.filter((L)=>!/-Turbo|-Air/i.test(L))].sort((L,K)=>Z(K)-Z(L)),V=H[0],U=H[H.length-1],W={};if(V)W.ANTHROPIC_DEFAULT_OPUS_MODEL=`${V}[1m]`,W.ANTHROPIC_DEFAULT_SONNET_MODEL=`${V}[1m]`;if(U&&X(U)!==X(V))W.ANTHROPIC_DEFAULT_HAIKU_MODEL=U;return Object.keys(W).length?W:null}catch{return null}}async function x8(q){try{let z=T8();Q1(z,{recursive:!0});let J=e(z,"settings.json"),Q={};if(a(J)){let H=K8(J,"utf8");try{let V=JSON.parse(H);if(!V||typeof V!=="object"||Array.isArray(V))return{error:`${J} 内容不是 JSON 对象, 拒绝覆盖, 请手动检查`};Q=V}catch{return{error:`${J} 解析失败 (JSON 语法错), 拒绝覆盖, 请手动修复后重跑`}}}let Z=Q.env&&typeof Q.env==="object"&&!Array.isArray(Q.env)?Q.env:{},X={ANTHROPIC_AUTH_TOKEN:q,ANTHROPIC_BASE_URL:"https://open.bigmodel.cn/api/anthropic",API_TIMEOUT_MS:"3000000",CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC:"1"},Y=await _8(q);if(Y)Object.assign(X,Y);return Q.env={...Z,...X},p(J,JSON.stringify(Q,null,2)+`
|
|
11
|
+
`),{path:J}}catch(z){return{error:z?.message??String(z)}}}function P8(q){try{if(process.platform==="win32")j(process.env.ComSpec??"cmd.exe",["/c","start",'""',q],{detached:!0,stdio:"ignore",windowsHide:!0}).unref();else if(process.platform==="darwin")j("open",[q],{detached:!0,stdio:"ignore"}).unref();else j("xdg-open",[q],{detached:!0,stdio:"ignore"}).unref()}catch{}}async function b8(q,z){try{let Q=await(await fetch("https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({app_id:q,app_secret:z}),signal:AbortSignal.timeout(15000)})).json();if(Q.tenant_access_token)return{ok:!0};return{ok:!1,error:`飞书拒绝: code=${Q.code} msg=${Q.msg??"(no msg)"}`}}catch(J){return{ok:!1,error:`网络错误: ${J?.message??String(J)}`}}}function I8(){try{let q=G8(O8(import.meta.url)),z=e(q,"lodestar.js");if(!a(z))return{error:`找不到 daemon bundle: ${z}`};let J=j(process.execPath,[z],{detached:!0,stdio:"ignore",windowsHide:!0});return J.unref(),{pid:J.pid}}catch(q){return{error:q?.message??String(q)}}}async function Z1(){if(!process.stdin.isTTY)console.error(`${$.red}lodestar-setup: stdin 不是 TTY,无法交互式输入。${$.reset}`),console.error("请直接在 cmd / PowerShell / Terminal 里跑,不要 pipe 或重定向 stdin。"),process.exit(1);if(a(P)){if(console.log(`${$.yellow}发现已有配置: ${P}${$.reset}`),(await T("覆盖? (y/N)",{default:"n"})).toLowerCase()!=="y"){console.log("已取消"),I.close();return}}k8("Lodestar 安装向导"),console.log("Lodestar 把 Feishu (飞书) 群聊接到 AI agent。"),console.log("默认后端是 Claude Code; Codex 是可选第二后端, 群里发 model 一键切换。"),console.log("每个群对应一个项目目录, agent 在那里跑、能读写文件。"),console.log(),console.log(`${$.yellow}⚠ Claude 官方限制:${$.reset}`),console.log(` ${$.bold}Claude 订阅 (Pro/Max OAuth 登录) 不支持本项目${$.reset},`),console.log(" 必须走 API 方式 —— 推荐 GLM Coding Plan, 或自备 Anthropic API key。"),console.log(),console.log("本向导依次做 4 件事:"),console.log(` ${$.dim}1) 确保 Claude Code CLI 已装好${$.reset}`),console.log(` ${$.dim}2) GLM Coding Plan API key (推荐, 可选) + Codex (可选)${$.reset}`),console.log(` ${$.dim}3) Feishu 自建应用 (含权限 / 事件 / 发版 + 凭据测试)${$.reset}`),console.log(` ${$.dim}4) 工作目录, 自动启动 daemon${$.reset}`),console.log(),await I.question(`${$.dim}按 Enter 开始 (Ctrl+C 退出)...${$.reset}`),y(1,4,"准备 Claude Code CLI"),await o("claude",{report:(L)=>console.log(L)}),console.log(`${$.green}✓ Claude Code / SDK 已更新${$.reset}: ${$.dim}${s("claude","claude")}${$.reset}`),console.log(),console.log(`${$.dim}下一步可选配 GLM Coding Plan 自动写入路由; 不配则用本机 Claude Code 现有配置。${$.reset}`),console.log(`${$.dim}记住: 别用 \`claude\` 走订阅 OAuth 登录 —— 订阅不支持本项目, 要用 API key。${$.reset}`),y(2,4,"GLM Coding Plan (推荐, 可选)"),console.log("GLM Coding Plan 给 Claude Code 接 GLM 系列模型 (支持 1M token 上下文, 中文友好)。"),console.log("订阅后在智谱开放平台拿一个 API key, 粘到下面 —— 向导自动写进 ~/.claude/settings.json。"),console.log(` ${$.dim}拿 key: https://open.bigmodel.cn → 控制台 → API Keys${$.reset}`),console.log(` ${$.dim}不给也行: 以本机 Claude Code 现有配置启动 (确保是 API key 方式, 非订阅)。${$.reset}`),console.log();let q=await T("GLM API key (直接回车跳过)",{});if(q){let L=await x8(q);if("path"in L)console.log(`${$.green}✓ GLM 路由已写入${$.reset}: ${$.dim}${L.path}${$.reset}`),console.log(`${$.dim}模型 slots 按端点当前列表自动选取(最新一代 opus/sonnet, 1M ctx)${$.reset}`);else console.log(`${$.red}✗ 写入失败:${$.reset} ${L.error}`),console.log(`${$.dim}跳过 GLM 配置, 以本机 Claude Code 现有配置启动。${$.reset}`)}else console.log(`${$.dim}已跳过 GLM, 以本机 Claude Code 现有配置启动。${$.reset}`);if(console.log(),console.log(`${$.bold}Codex (可选第二后端)${$.reset}`),console.log(` ${$.dim}想用 Codex 的话, 登录 ChatGPT 订阅即可, 模型/effort 走 ~/.codex/config.toml, 群里发 model 切换。${$.reset}`),(await T("现在顺便配置 Codex 后端吗?",{default:"n"})).toLowerCase()==="y"){await o("codex",{report:(K)=>console.log(K)});let L=s("codex","codex");if(z1(L))console.log(`${$.green}✓ Codex 已登录 ChatGPT${$.reset}`);else if(console.log(`${$.dim}启动 \`codex login\`...${$.reset}`),await F8(L)&&z1(L))console.log(`${$.green}✓ Codex 已登录 ChatGPT${$.reset}`);else console.log(`${$.yellow}Codex 登录未完成 — 不影响默认 Claude 后端; 需要时随时跑 codex login。${$.reset}`)}else console.log(`${$.dim}已跳过 Codex (需要时随时跑 codex login, 群里发 model 切)。${$.reset}`);y(3,4,"Feishu 自建应用");let J="https://open.feishu.cn/app";console.log("打开飞书开放平台 (浏览器):"),console.log(` ${$.cyan}${J}${$.reset}`),P8(J),console.log(`${$.dim}(如果浏览器没自动开, 复制上面 URL 粘到浏览器)${$.reset}`),console.log(),console.log(`${$.bold}详细操作步骤:${$.reset}`),console.log(),console.log(` ${$.bold}① 创建应用${$.reset}`),console.log(` 点 "创建企业自建应用", 填名字 (如 ${$.dim}Lodestar${$.reset}), logo 随意。`),console.log(),console.log(` ${$.bold}② 添加机器人能力${$.reset}`),console.log(` 左侧菜单 "${$.cyan}添加应用能力${$.reset}" → 找到 "机器人" → 点 "${$.bold}添加${$.reset}" 按钮。`),console.log(),console.log(` ${$.bold}③ 申请权限 (左侧 "${$.cyan}权限管理${$.reset}" → "${$.bold}开通权限${$.reset}")${$.reset}`),console.log(` ${$.yellow}缺一个都会让 daemon 启动后默默丢消息, 一定要全开。${$.reset}`),console.log(` ${$.dim}消息类:${$.reset}`),console.log(` • ${$.bold}im:message:send_as_bot${$.reset} ${$.dim}# 以机器人身份发消息${$.reset}`),console.log(` • ${$.bold}im:message${$.reset} ${$.dim}# 接收/操作消息 (核心)${$.reset}`),console.log(` • ${$.bold}im:chat${$.reset} ${$.dim}# 读/写群信息 (匹配群名 ↔ 项目目录)${$.reset}`),console.log(` • ${$.bold}im:chat:create${$.reset} ${$.dim}# wt: 自动创建 worktree 群${$.reset}`),console.log(` • ${$.bold}im:chat:delete${$.reset} ${$.dim}# wt: 解散 worktree 群${$.reset}`),console.log(` • ${$.bold}im:chat.members:read${$.reset} ${$.dim}# wt: 判断发起人是否已在群内${$.reset}`),console.log(` • ${$.bold}im:chat.members:write_only${$.reset} ${$.dim}# wt: 把发起人拉进已有 worktree 群${$.reset}`),console.log(` • ${$.bold}im:resource${$.reset} ${$.dim}# 上传/下载附件 (图文双向)${$.reset}`),console.log(` • ${$.bold}im:message.urgent${$.reset} ${$.dim}# 加急推送 (锁屏通知 / Ask)${$.reset}`),console.log(` • ${$.bold}im:message.group_msg${$.reset} ${$.dim}# 敏感: 接收群里所有消息${$.reset}`),console.log(` ${$.dim}└ 关键: 没它机器人只收 @ 自己的消息, 拿不到群里其他对话, 一定要开${$.reset}`),console.log(` ${$.dim}└ 敏感权限要走审批: 申请时填用途, 个人开发者通常秒过${$.reset}`),console.log(` • ${$.bold}im:message.group_at_msg:readonly${$.reset} ${$.dim}# 读 @ 机器人消息 (兜底)${$.reset}`),console.log(` ${$.dim}卡片类 (Card Kit):${$.reset}`),console.log(` • ${$.bold}cardkit:card:read${$.reset} ${$.dim}# 读卡片状态${$.reset}`),console.log(` • ${$.bold}cardkit:card:write${$.reset} ${$.dim}# 创建/更新卡片 (流式渲染核心)${$.reset}`),console.log(),console.log(` ${$.bold}④ 订阅事件 (左侧 "${$.cyan}事件与回调${$.reset}", 拆两个子页:)${$.reset}`),console.log(` ${$.dim}a)${$.reset} ${$.bold}事件配置${$.reset} 页:`),console.log(` ${$.yellow}• "订阅方式" → 选 "长连接" → 点保存${$.reset}`),console.log(` • 添加事件: ${$.bold}im.message.receive_v1${$.reset} ${$.dim}# 收群消息${$.reset}`),console.log(` ${$.dim}b)${$.reset} ${$.bold}回调配置${$.reset} 页:`),console.log(` ${$.yellow}• "订阅方式" → 选 "长连接" → 点保存${$.reset}`),console.log(` • 添加事件: ${$.bold}card.action.trigger${$.reset} ${$.dim}# 卡片按钮点击回调${$.reset}`),console.log(),console.log(` ${$.bold}⑤ 发布版本${$.reset}`),console.log(` 页面顶部 "${$.bold}创建版本${$.reset}" → 滚到底点 "${$.bold}保存${$.reset}" → 弹框点 "${$.bold}发布${$.reset}"。`),console.log(` ${$.yellow}没发版的应用收不到任何事件 — 这步九成新手会忘!${$.reset}`),console.log(),console.log(` ${$.bold}⑥ 拿凭据${$.reset}`),console.log(` 左侧 "凭证与基础信息" → 顶部 ${$.bold}App ID${$.reset} (${$.dim}cli_...${$.reset}) 和 ${$.bold}App Secret${$.reset}, 待会粘到下面。`),console.log(),console.log(` ${$.bold}⑦ 把机器人拉进群${$.reset}`),console.log(" 想用的飞书群 → 群设置 → 群机器人 → 添加机器人 → 选你的应用。"),console.log(` ${$.yellow}群名要等于 projects_root 下的项目目录名${$.reset} (下一步设, 默认是用户主目录)。`),console.log();let Q="",Z="";while(!0){Q=await T("App ID (以 cli_ 开头)",{required:!0}),Z=await T("App Secret",{required:!0}),console.log(`${$.dim}测试中... (调 tenant_access_token endpoint)${$.reset}`);let L=await b8(Q,Z);if(L.ok){console.log(`${$.green}✓ Feishu 凭据测试通过${$.reset}`);break}if(console.log(`${$.red}✗ 测试失败:${$.reset} ${L.error}`),console.log(`${$.dim}最常见原因: app_id / app_secret 抄错, 或应用还没 "发布上线" (步骤 ⑤)。${$.reset}`),console.log(),(await T("重新填? (Y/n)",{default:"y"})).toLowerCase()==="n")console.log(`${$.yellow}已取消, 配置未写盘。${$.reset}`),I.close(),process.exit(1)}y(4,4,"工作目录 + 启动"),console.log("每个 Feishu 群对应 projects_root 下同名的目录。"),console.log();let X=process.platform==="win32"?process.env.USERPROFILE??"C:\\Users\\Default":process.env.HOME??"/root",Y=await T("projects_root",{default:X});Q1(l,{recursive:!0});let H=["# Lodestar config — generated by `lodestar-setup`","# Edit by hand or re-run setup to overwrite.","","[feishu]",`app_id = "${t(Q)}"`,`app_secret = "${t(Z)}"`,"","[runtime]",`projects_root = "${t(Y)}"`,""];p(P,H.join(`
|
|
10
12
|
`)),console.log(`
|
|
11
|
-
${
|
|
12
|
-
${
|
|
13
|
-
lodestar-setup: ${
|
|
13
|
+
${$.green}${$.bold}✓ 配置已写入${$.reset}`),console.log(` ${$.cyan}${P}${$.reset}`),console.log(`
|
|
14
|
+
${$.bold}启动 daemon...${$.reset}`);let V=I8(),U=process.platform==="win32"?"\\":"/",W=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(V.pid)console.log(`${$.green}✓ daemon 已在后台启动${$.reset} (pid ${V.pid})`),console.log(),console.log(`${$.bold}最后一步: 在 Feishu 验证${$.reset}`),console.log(" ① 把机器人拉进任意飞书群"),console.log(` ② 群名 = ${$.cyan}${Y}${U}<群名>${$.reset} 下的目录名 (新群第一条消息会自动建)`),console.log(" ③ 在群里发任意一条消息, 默认由 Claude 接管"),console.log(` ${$.dim}(群里发 model 可选择已配置账号、动态模型和 effort)${$.reset}`),console.log(),console.log("日志 (按日滚动, 保留近 7 天):"),console.log(` ${$.cyan}${W}${$.reset}`),console.log(),console.log(`${$.dim}若长期跑后台, Linux 配 systemd --user,macOS 配 launchd,Windows 配任务计划程序。${$.reset}`);else console.log(`${$.yellow}启动失败: ${V.error}${$.reset}`),console.log(`手动运行: ${$.cyan}lodestar-daemon${$.reset}`);console.log(),I.close()}Z1().catch((q)=>{console.error(`
|
|
15
|
+
lodestar-setup: ${q?.message??q}`),process.exit(1)});
|
package/dist/lodestar-stop.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{execSync as f}from"node:child_process";import{existsSync as U,readFileSync as y}from"node:fs";import{homedir as W}from"node:os";import{join as q}from"node:path";var X=W(),B=process.platform==="win32";function b(
|
|
3
|
-
`),Q=parseInt((
|
|
2
|
+
import{execSync as f}from"node:child_process";import{existsSync as U,readFileSync as y}from"node:fs";import{homedir as W}from"node:os";import{join as q}from"node:path";var X=W(),B=process.platform==="win32";function b(K,Q,Y){if(K)return K;if(Q)return q(Q,"lodestar");return Y}function H(){if(B)return q(process.env.APPDATA??q(X,"AppData","Roaming"),"Lodestar");return q(X,".config","lodestar")}function V(){if(B)return q(process.env.LOCALAPPDATA??q(X,"AppData","Local"),"Lodestar");return q(X,".local","share","lodestar")}var w=b(process.env.LODESTAR_CONFIG_DIR,process.env.XDG_CONFIG_HOME,H()),J=b(process.env.LODESTAR_DATA_DIR,process.env.XDG_DATA_HOME,V()),x=process.env.LODESTAR_CONFIG??q(w,"config.toml"),Z=q(J,"daemon.pid"),S=q(J,"daemon.log"),E=q(J,"session-chat-map.json"),v=q(J,"session-resume-map.json"),h=q(J,"session-turns-map.json"),k=q(J,"session-model-map.json"),F=q(J,"temp-session-leases.json"),R=q(J,"tasklist-map.json"),T=q(J,"agent-runs"),m=q(J,"agent-session-ids.json"),C=q(J,"managed-claude-plugin"),l=q(J,"dsh"),c=q(J,"agent-runtimes"),j=q(J,"context-window-cache.json"),t=q(J,"notify-callbacks.json"),_=q(J,"alive-on-shutdown.json"),A=q(J,"inbox"),I=q(J,"debug.sock"),p=q(J,"debug-context.json");import{execSync as G}from"node:child_process";import{readFileSync as L,writeFileSync as o}from"node:fs";function M(K){try{if(process.platform==="linux")return L(`/proc/${K}/cmdline`,"utf8").replace(/\0/g," ").trim();if(process.platform==="darwin")return G(`ps -p ${K} -o args=`,{encoding:"utf8",timeout:2000}).trim();if(process.platform==="win32")return G(`powershell -NoProfile -Command "(Get-CimInstance Win32_Process -Filter 'ProcessId=${K}').CommandLine"`,{encoding:"utf8",timeout:5000}).trim()||null;return null}catch{return null}}function N(K,Q){if(!Number.isFinite(K)||K<=0||!Q)return!1;let Y=M(K);if(!Y)return!1;if(process.platform==="win32")return Y.toLowerCase().includes(Q.toLowerCase());return Y.includes(Q)}var z={reset:"\x1B[0m",bold:"\x1B[1m",green:"\x1B[32m",yellow:"\x1B[33m",red:"\x1B[31m",dim:"\x1B[2m"};function P(K){return new Promise((Q)=>setTimeout(Q,K))}async function u(){if(!U(Z)){console.log(`${z.yellow}Lodestar daemon 未运行${z.reset} ${z.dim}(${Z} 不存在)${z.reset}`);return}let K=y(Z,"utf8").split(`
|
|
3
|
+
`),Q=parseInt((K[0]??"").trim(),10),Y=(K[1]??"").trim();if(!Number.isFinite(Q)||Q<=0)console.error(`${z.red}PID 文件格式坏:${z.reset} ${Z}`),process.exit(1);if(Y&&!N(Q,Y)){console.log(`${z.yellow}PID ${Q} 上没有 daemon (stale 文件)${z.reset}`),console.log(`${z.dim}手删 ${Z} 后再试${z.reset}`);return}console.log(`${z.bold}停止 daemon${z.reset} (pid ${Q})...`);try{if(process.platform==="win32")f(`taskkill /PID ${Q} /T /F`,{stdio:"ignore"});else process.kill(Q,"SIGTERM")}catch($){console.error(`${z.red}发信号失败:${z.reset} ${$?.message??$}`),process.exit(1)}for(let $=0;$<50;$++){if(!U(Z)){console.log(`${z.green}✓ daemon 已停${z.reset}`);return}await P(100)}console.log(`${z.yellow}已发 SIGTERM, 但 5s 内 daemon 没清掉 ${Z}${z.reset}`),console.log(`${z.dim}它可能还在收尾 (落盘 alive marker / 关 WS); 下次启动 pid-guard 会自动判别。${z.reset}`)}u().catch((K)=>{console.error(`${z.red}lodestar-stop:${z.reset} ${K?.message??K}`),process.exit(1)});
|
package/dist/lodestar-update.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{spawn as g}from"node:child_process";import{existsSync as x}from"node:fs";import{homedir as p}from"node:os";import{join as s}from"node:path";var m=p(),a=process.platform==="win32";function $(t,l,r){if(t)return t;if(l)return s(l,"lodestar");return r}function u(){if(a)return s(process.env.APPDATA??s(m,"AppData","Roaming"),"Lodestar");return s(m,".config","lodestar")}function y(){if(a)return s(process.env.LOCALAPPDATA??s(m,"AppData","Local"),"Lodestar");return s(m,".local","share","lodestar")}var C=$(process.env.LODESTAR_CONFIG_DIR,process.env.XDG_CONFIG_HOME,u()),e=$(process.env.LODESTAR_DATA_DIR,process.env.XDG_DATA_HOME,y()),K=process.env.LODESTAR_CONFIG??s(C,"config.toml"),n=s(e,"daemon.pid"),f=s(e,"daemon.log"),S=s(e,"session-chat-map.json"),q=s(e,"session-resume-map.json"),z=s(e,"session-turns-map.json"),J=s(e,"session-model-map.json"),Q=s(e,"temp-session-leases.json"),Y=s(e,"tasklist-map.json"),Z=s(e,"agent-runs"),W=s(e,"agent-session-ids.json"),X=s(e,"managed-claude-plugin"),B=s(e,"dsh"),G=s(e,"context-window-cache.json"),N=s(e,"notify-callbacks.json"),U=s(e,"alive-on-shutdown.json"),i=s(e,"inbox"),F=s(e,"debug.sock"),h=s(e,"debug-context.json");var o={reset:"\x1B[0m",bold:"\x1B[1m",cyan:"\x1B[36m",green:"\x1B[32m",yellow:"\x1B[33m",red:"\x1B[31m",dim:"\x1B[2m"},d=["@leviyuan/lodestar@latest","@openai/codex@latest","@anthropic-ai/claude-code@latest","@anthropic-ai/claude-agent-sdk@latest","@anthropic-ai/sdk@latest"];function b(){let t=process.platform==="win32"?"npm.cmd":"npm";return new Promise((l)=>{let r=g(t,["install","-g","--include=optional",...d],{stdio:"inherit",shell:process.platform==="win32"});r.on("exit",(c)=>l(c??1)),r.on("error",(c)=>{console.error(`${o.red}spawn npm 失败:${o.reset} ${c.message}`),l(1)})})}async function w(){console.log(`${o.bold}更新 Lodestar + Codex CLI + Claude Code / SDK${o.reset}`),console.log(`${o.dim}npm i -g ${d.join(" ")}${o.reset}
|
|
3
|
-
`);let
|
|
4
|
-
${
|
|
5
|
-
|
|
2
|
+
import{createRequire as a$}from"node:module";var d$=Object.create;var{getPrototypeOf:p$,defineProperty:h,getOwnPropertyNames:i$}=Object;var n$=Object.prototype.hasOwnProperty;function t$($){return this[$]}var s$,o$,r$=($,L,q)=>{var J=$!=null&&typeof $==="object";if(J){var Q=L?s$??=new WeakMap:o$??=new WeakMap,X=Q.get($);if(X)return X}q=$!=null?d$(p$($)):{};let Z=L||!$||!$.__esModule?h(q,"default",{value:$,enumerable:!0}):q;for(let z of i$($))if(!n$.call(Z,z))h(Z,z,{get:t$.bind($,z),enumerable:!0});if(J)Q.set($,Z);return Z};var M=($,L)=>()=>(L||$((L={exports:{}}).exports,L),L.exports);var F=a$(import.meta.url);var n=M((G0,i)=>{i.exports=p;p.sync=Q1;var g=F("fs");function J1($,L){var q=L.pathExt!==void 0?L.pathExt:process.env.PATHEXT;if(!q)return!0;if(q=q.split(";"),q.indexOf("")!==-1)return!0;for(var J=0;J<q.length;J++){var Q=q[J].toLowerCase();if(Q&&$.substr(-Q.length).toLowerCase()===Q)return!0}return!1}function d($,L,q){if(!$.isSymbolicLink()&&!$.isFile())return!1;return J1(L,q)}function p($,L,q){g.stat($,function(J,Q){q(J,J?!1:d(Q,$,L))})}function Q1($,L){return d(g.statSync($),$,L)}});var a=M((M0,r)=>{r.exports=s;s.sync=X1;var t=F("fs");function s($,L,q){t.stat($,function(J,Q){q(J,J?!1:o(Q,L))})}function X1($,L){return o(t.statSync($),L)}function o($,L){return $.isFile()&&Z1($,L)}function Z1($,L){var{mode:q,uid:J,gid:Q}=$,X=L.uid!==void 0?L.uid:process.getuid&&process.getuid(),Z=L.gid!==void 0?L.gid:process.getgid&&process.getgid(),z=parseInt("100",8),B=parseInt("010",8),V=parseInt("001",8),K=z|B,G=q&V||q&B&&Q===Z||q&z&&J===X||q&K&&X===0;return G}});var $$=M((O0,e)=>{var P0=F("fs"),C;if(process.platform==="win32"||global.TESTING_WINDOWS)C=n();else C=a();e.exports=_;_.sync=z1;function _($,L,q){if(typeof L==="function")q=L,L={};if(!q){if(typeof Promise!=="function")throw TypeError("callback not provided");return new Promise(function(J,Q){_($,L||{},function(X,Z){if(X)Q(X);else J(Z)})})}C($,L||{},function(J,Q){if(J){if(J.code==="EACCES"||L&&L.ignoreErrors)J=null,Q=!1}q(J,Q)})}function z1($,L){try{return C.sync($,L||{})}catch(q){if(L&&L.ignoreErrors||q.code==="EACCES")return!1;else throw q}}});var z$=M((f0,Z$)=>{var k=process.platform==="win32"||process.env.OSTYPE==="cygwin"||process.env.OSTYPE==="msys",L$=F("path"),B1=k?";":":",q$=$$(),J$=($)=>Object.assign(Error(`not found: ${$}`),{code:"ENOENT"}),Q$=($,L)=>{let q=L.colon||B1,J=$.match(/\//)||k&&$.match(/\\/)?[""]:[...k?[process.cwd()]:[],...(L.path||process.env.PATH||"").split(q)],Q=k?L.pathExt||process.env.PATHEXT||".EXE;.CMD;.BAT;.COM":"",X=k?Q.split(q):[""];if(k){if($.indexOf(".")!==-1&&X[0]!=="")X.unshift("")}return{pathEnv:J,pathExt:X,pathExtExe:Q}},X$=($,L,q)=>{if(typeof L==="function")q=L,L={};if(!L)L={};let{pathEnv:J,pathExt:Q,pathExtExe:X}=Q$($,L),Z=[],z=(V)=>new Promise((K,G)=>{if(V===J.length)return L.all&&Z.length?K(Z):G(J$($));let W=J[V],O=/^".*"$/.test(W)?W.slice(1,-1):W,f=L$.join(O,$),I=!O&&/^\.[\\\/]/.test($)?$.slice(0,2)+f:f;K(B(I,V,0))}),B=(V,K,G)=>new Promise((W,O)=>{if(G===Q.length)return W(z(K+1));let f=Q[G];q$(V+f,{pathExt:X},(I,g$)=>{if(!I&&g$)if(L.all)Z.push(V+f);else return W(V+f);return W(B(V,K,G+1))})});return q?z(0).then((V)=>q(null,V),q):z(0)},Y1=($,L)=>{L=L||{};let{pathEnv:q,pathExt:J,pathExtExe:Q}=Q$($,L),X=[];for(let Z=0;Z<q.length;Z++){let z=q[Z],B=/^".*"$/.test(z)?z.slice(1,-1):z,V=L$.join(B,$),K=!B&&/^\.[\\\/]/.test($)?$.slice(0,2)+V:V;for(let G=0;G<J.length;G++){let W=K+J[G];try{if(q$.sync(W,{pathExt:Q}))if(L.all)X.push(W);else return W}catch(O){}}}if(L.all&&X.length)return X;if(L.nothrow)return null;throw J$($)};Z$.exports=X$;X$.sync=Y1});var Y$=M((F0,T)=>{var B$=($={})=>{let L=$.env||process.env;if(($.platform||process.platform)!=="win32")return"PATH";return Object.keys(L).reverse().find((J)=>J.toUpperCase()==="PATH")||"Path"};T.exports=B$;T.exports.default=B$});var U$=M((k0,K$)=>{var H$=F("path"),H1=z$(),V1=Y$();function V$($,L){let q=$.options.env||process.env,J=process.cwd(),Q=$.options.cwd!=null,X=Q&&process.chdir!==void 0&&!process.chdir.disabled;if(X)try{process.chdir($.options.cwd)}catch(z){}let Z;try{Z=H1.sync($.command,{path:q[V1({env:q})],pathExt:L?H$.delimiter:void 0})}catch(z){}finally{if(X)process.chdir(J)}if(Z)Z=H$.resolve(Q?$.options.cwd:"",Z);return Z}function K1($){return V$($)||V$($,!0)}K$.exports=K1});var W$=M((G1,w)=>{var b=/([()\][%!^"`<>&|;, *?])/g;function U1($){return $=$.replace(b,"^$1"),$}function W1($,L){if($=`${$}`,$=$.replace(/(?=(\\+?)?)\1"/g,"$1$1\\\""),$=$.replace(/(?=(\\+?)?)\1$/,"$1$1"),$=`"${$}"`,$=$.replace(b,"^$1"),L)$=$.replace(b,"^$1");return $}G1.command=U1;G1.argument=W1});var M$=M((y0,G$)=>{G$.exports=/^#!(.*)/});var O$=M((x0,P$)=>{var O1=M$();P$.exports=($="")=>{let L=$.match(O1);if(!L)return null;let[q,J]=L[0].replace(/#! ?/,"").split(" "),Q=q.split("/").pop();if(Q==="env")return J;return J?`${Q} ${J}`:Q}});var F$=M((N0,f$)=>{var R=F("fs"),f1=O$();function F1($){let q=Buffer.alloc(150),J;try{J=R.openSync($,"r"),R.readSync(J,q,0,150,0),R.closeSync(J)}catch(Q){}return f1(q.toString())}f$.exports=F1});var N$=M((C0,x$)=>{var k1=F("path"),k$=U$(),y$=W$(),y1=F$(),x1=process.platform==="win32",N1=/\.(?:com|exe)$/i,C1=/node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;function I1($){$.file=k$($);let L=$.file&&y1($.file);if(L)return $.args.unshift($.file),$.command=L,k$($);return $.file}function S1($){if(!x1)return $;let L=I1($),q=!N1.test(L);if($.options.forceShell||q){let J=C1.test(L);$.command=k1.normalize($.command),$.command=y$.command($.command),$.args=$.args.map((X)=>y$.argument(X,J));let Q=[$.command].concat($.args).join(" ");$.args=["/d","/s","/c",`"${Q}"`],$.command=process.env.comspec||"cmd.exe",$.options.windowsVerbatimArguments=!0}return $}function _1($,L,q){if(L&&!Array.isArray(L))q=L,L=null;L=L?L.slice(0):[],q=Object.assign({},q);let J={command:$,args:L,options:q,file:void 0,original:{command:$,args:L}};return q.shell?J:S1(J)}x$.exports=_1});var S$=M((I0,I$)=>{var D=process.platform==="win32";function j($,L){return Object.assign(Error(`${L} ${$.command} ENOENT`),{code:"ENOENT",errno:"ENOENT",syscall:`${L} ${$.command}`,path:$.command,spawnargs:$.args})}function T1($,L){if(!D)return;let q=$.emit;$.emit=function(J,Q){if(J==="exit"){let X=C$(Q,L);if(X)return q.call($,"error",X)}return q.apply($,arguments)}}function C$($,L){if(D&&$===1&&!L.file)return j(L.original,"spawn");return null}function b1($,L){if(D&&$===1&&!L.file)return j(L.original,"spawnSync");return null}I$.exports={hookChildProcess:T1,verifyENOENT:C$,verifyENOENTSync:b1,notFoundError:j}});var b$=M((S0,y)=>{var _$=F("child_process"),u=N$(),v=S$();function T$($,L,q){let J=u($,L,q),Q=_$.spawn(J.command,J.args,J.options);return v.hookChildProcess(Q,J),Q}function w1($,L,q){let J=u($,L,q),Q=_$.spawnSync(J.command,J.args,J.options);return Q.error=Q.error||v.verifyENOENTSync(Q.status,J),Q}y.exports=T$;y.exports.spawn=T$;y.exports.sync=w1;y.exports._parse=u;y.exports._enoent=v});import{spawn as m1}from"node:child_process";import{existsSync as g1}from"node:fs";import{homedir as e$}from"node:os";import{join as Y}from"node:path";var N=e$(),l=process.platform==="win32";function c($,L,q){if($)return $;if(L)return Y(L,"lodestar");return q}function $1(){if(l)return Y(process.env.APPDATA??Y(N,"AppData","Roaming"),"Lodestar");return Y(N,".config","lodestar")}function L1(){if(l)return Y(process.env.LOCALAPPDATA??Y(N,"AppData","Local"),"Lodestar");return Y(N,".local","share","lodestar")}var q1=c(process.env.LODESTAR_CONFIG_DIR,process.env.XDG_CONFIG_HOME,$1()),U=c(process.env.LODESTAR_DATA_DIR,process.env.XDG_DATA_HOME,L1()),o1=process.env.LODESTAR_CONFIG??Y(q1,"config.toml"),m=Y(U,"daemon.pid"),r1=Y(U,"daemon.log"),a1=Y(U,"session-chat-map.json"),e1=Y(U,"session-resume-map.json"),$0=Y(U,"session-turns-map.json"),L0=Y(U,"session-model-map.json"),q0=Y(U,"temp-session-leases.json"),J0=Y(U,"tasklist-map.json"),Q0=Y(U,"agent-runs"),X0=Y(U,"agent-session-ids.json"),Z0=Y(U,"managed-claude-plugin"),z0=Y(U,"dsh"),S=Y(U,"agent-runtimes"),B0=Y(U,"context-window-cache.json"),Y0=Y(U,"notify-callbacks.json"),H0=Y(U,"alive-on-shutdown.json"),V0=Y(U,"inbox"),K0=Y(U,"debug.sock"),U0=Y(U,"debug-context.json");import{createHash as R1}from"node:crypto";var A$=r$(b$(),1);import{existsSync as D$,readFileSync as j$}from"node:fs";import{mkdir as u$,mkdtemp as D1,readFile as v$,rename as E$,rm as E,writeFile as A}from"node:fs/promises";import{join as P,isAbsolute as j1}from"node:path";import{fileURLToPath as u1,pathToFileURL as D0}from"node:url";var w$=["codex","claude","dsh"];var h$="https://registry.npmjs.org",x={codex:["@openai/codex"],claude:["@anthropic-ai/claude-code","@anthropic-ai/claude-agent-sdk","@anthropic-ai/sdk"],dsh:["@deepseek-ai/dsh","@deepseek-ai/dsh-llm-pi-ai","@deepseek-ai/dsh-tool-ask-user"]},l$=($)=>$ instanceof Error?$.message:String($);function v1($,L=S){let q=P(L,$,"current.json");if(!D$(q))return null;let J=JSON.parse(j$(q,"utf8"));if(!Number.isFinite(J.checkedAt)||J.directory!==void 0&&!j1(J.directory))throw Error(`Invalid ${$} runtime state: ${q}`);return J}async function E1($,L,q){let J=new AbortController,Q=()=>J.abort(q?.reason);if(q?.addEventListener("abort",Q,{once:!0}),q?.aborted)Q();let X=setTimeout(()=>J.abort(Error("npm registry request timed out")),30000);try{let Z=await fetch(`${h$}/${encodeURIComponent($)}/${encodeURIComponent(L)}`,{signal:J.signal});if(!Z.ok)throw Error(`${$}@${L}: npm HTTP ${Z.status}`);let z=await Z.json();if(z.name!==$||typeof z.version!=="string"||!z.version)throw Error(`Invalid npm manifest: ${$}@${L}`);return z}finally{clearTimeout(X),q?.removeEventListener("abort",Q)}}async function A1($,L){let q={};if($!=="dsh"){let Z=await Promise.all(x[$].map((z)=>L(z,"latest")));for(let z of Z)q[z.name]=z.version;return q}let J=await L("@deepseek-ai/dsh","latest"),Q=new Set(x.dsh),X=new Set;while(Q.size){let Z=[...Q].slice(0,12);for(let B of Z)Q.delete(B),X.add(B);let z=await Promise.all(Z.map((B)=>B===J.name?J:L(B,J.version)));for(let B of z){if(B.version!==J.version)throw Error(`DSH release package mismatch: ${B.name}@${B.version}, expected ${J.version}`);q[B.name]=B.version;for(let V of Object.keys({...B.dependencies,...B.peerDependencies,...B.optionalDependencies}))if(V.startsWith("@deepseek-ai/dsh")&&!X.has(V))Q.add(V)}}return q}function h1($,L){return new Promise((q,J)=>{let Q=A$.spawn("npm",["install","--prefix",$,"--include=optional","--no-fund","--no-audit",`--registry=${h$}`],{cwd:$,stdio:["ignore","pipe","pipe"],shell:!1}),X="",Z,z=(K)=>{X=(X+K.toString()).slice(-16384)};Q.stdout.on("data",z),Q.stderr.on("data",z);let B=()=>{Z=Error("Agent runtime install aborted"),Q.kill("SIGTERM")};if(L?.addEventListener("abort",B,{once:!0}),L?.aborted)B();let V=setTimeout(()=>{Z=Error("Agent runtime install timed out after 5 minutes"),Q.kill("SIGTERM")},300000);Q.on("error",(K)=>{Z=K}),Q.once("close",(K)=>{if(clearTimeout(V),L?.removeEventListener("abort",B),Z||K!==0)J(Error(`${Z?.message??`npm install exited ${K}`}
|
|
3
|
+
${X}`));else q()})})}async function R$($,L){let q=P($,`current-${process.pid}-${Date.now()}.json`);await A(q,JSON.stringify(L)+`
|
|
4
|
+
`,{mode:384}),await E$(q,P($,"current.json"))}async function l1($,L){let q=P($,"update.lock"),J=Date.now()+360000;for(;;){L?.throwIfAborted();try{return await u$(q),await A(P(q,"pid"),String(process.pid)),()=>E(q,{recursive:!0})}catch(Q){if(Q.code!=="EEXIST")throw Q;try{let X=Number(await v$(P(q,"pid"),"utf8"));if(!Number.isSafeInteger(X)||X<=0)throw Error(`Invalid runtime update lock: ${q}`);try{process.kill(X,0)}catch(Z){if(Z.code!=="ESRCH")throw Z;await E(q,{recursive:!0});continue}}catch(X){if(X.code!=="ENOENT")throw X}if(Date.now()>=J)throw Error(`Timed out waiting for runtime update lock: ${q}`);await new Promise((X)=>setTimeout(X,200))}}}async function c1($,L={}){let q=L.root??S,J=P(q,$);await u$(J,{recursive:!0,mode:448});let Q=await l1(J,L.signal),X;try{L.report?.(`${$}: 检查 upstream latest`);let Z=v1($,q),z=await A1($,L.metadata??((W,O)=>E1(W,O,L.signal)));L.signal?.throwIfAborted();let B=JSON.parse(j$(u1(new URL("../package.json",import.meta.url)),"utf8")).overrides??{},V=R1("sha256").update(JSON.stringify({installFormat:2,versions:Object.entries(z).sort(),security:B,platform:process.platform,arch:process.arch})).digest("hex").slice(0,20),K=P(J,V);if(!D$(K)){X=await D1(P(J,".install-")),await A(P(X,"package.json"),JSON.stringify({name:`lodestar-runtime-${$}`,version:z[x[$][0]],private:!0,type:"module",dependencies:z,overrides:{...B,...$==="dsh"?z:{}}})+`
|
|
5
|
+
`,{mode:384}),await(L.install??h1)(X,L.signal);for(let[W,O]of Object.entries(z)){let f=JSON.parse(await v$(P(X,"node_modules",W,"package.json"),"utf8"));if(f.version!==O)throw Error(`npm installed ${W}@${f.version}, expected ${O}`)}L.signal?.throwIfAborted(),await E$(X,K),X=void 0}let G={directory:K,versions:z,checkedAt:Date.now()};return await R$(J,G),L.report?.(`${$}: ${x[$][0]}@${z[x[$][0]]}${Z?.directory===K?" 已是 latest":" 已更新,新进程使用新版"}`),G}catch(Z){throw await R$(J,{checkedAt:Date.now(),error:l$(Z)}),Z}finally{try{if(X)await E(X,{recursive:!0})}finally{await Q()}}}async function c$($={}){let L=await Promise.allSettled(w$.map((J)=>c1(J,$))),q=[];for(let J=0;J<L.length;J++){let Q=L[J];if(Q.status==="rejected"){let X=Error(`${w$[J]}: ${l$(Q.reason)}`);$.report?.(`Agent 自动更新失败: ${X.message}`),q.push(X)}}if(q.length)throw AggregateError(q,q.map((J)=>J.message).join(`
|
|
6
|
+
`))}var H={reset:"\x1B[0m",bold:"\x1B[1m",cyan:"\x1B[36m",green:"\x1B[32m",yellow:"\x1B[33m",red:"\x1B[31m",dim:"\x1B[2m"},m$=["@leviyuan/lodestar@latest"];function d1(){let $=process.platform==="win32"?"npm.cmd":"npm";return new Promise((L)=>{let q=m1($,["install","-g","--include=optional",...m$],{stdio:"inherit",shell:process.platform==="win32"});q.on("exit",(J)=>L(J??1)),q.on("error",(J)=>{console.error(`${H.red}spawn npm 失败:${H.reset} ${J.message}`),L(1)})})}async function p1(){let $=process.argv.includes("--agents-only");if(process.argv.slice(2).some((L)=>L!=="--agents-only"))throw Error("用法: lodestar-update [--agents-only]");if(console.log(`${H.bold}更新 ${$?"":"Lodestar + "}Codex、Claude Code/SDK、DSH${H.reset}`),!$){console.log(`${H.dim}npm i -g ${m$.join(" ")}${H.reset}
|
|
7
|
+
`);let L=await d1();if(L!==0)throw Error(`Lodestar 更新失败 (npm exit ${L})`)}if(await c$({report:(L)=>console.log(L)}),console.log(`
|
|
8
|
+
${H.green}✓ Agent 更新完成,新进程使用新版${H.reset}`),!$&&g1(m))console.log(),console.log(`${H.yellow}检测到 daemon 仍在跑老版本进程, 用新版本需要重启:${H.reset}`),console.log(` ${H.dim}# Linux systemd --user 托管的:${H.reset}`),console.log(` ${H.cyan}systemctl --user restart lodestar${H.reset} ${H.dim}# Linux${H.reset}`),console.log(` ${H.dim}# macOS launchd / Windows 任务计划:用对应服务管理器重启。${H.reset}`),console.log(` ${H.dim}# 或手动重启:${H.reset}`),console.log(` ${H.cyan}lodestar-stop && lodestar-daemon${H.reset}`)}p1().catch(($)=>{console.error(`${H.red}lodestar-update:${H.reset} ${$?.message??$}`),process.exit(1)});
|
package/dist/lodestar-version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{
|
|
2
|
+
import{createRequire as E$}from"node:module";var T$=Object.create;var{getPrototypeOf:_$,defineProperty:v,getOwnPropertyNames:R$}=Object;var b$=Object.prototype.hasOwnProperty;function j$($){return this[$]}var v$,D$,w$=($,q,L)=>{var J=$!=null&&typeof $==="object";if(J){var Q=q?v$??=new WeakMap:D$??=new WeakMap,Z=Q.get($);if(Z)return Z}L=$!=null?T$(_$($)):{};let z=q||!$||!$.__esModule?v(L,"default",{value:$,enumerable:!0}):L;for(let Y of R$($))if(!b$.call(z,Y))v(z,Y,{get:j$.bind($,Y),enumerable:!0});if(J)Q.set($,z);return z};var V=($,q)=>()=>(q||$((q={exports:{}}).exports,q),q.exports);var W=E$(import.meta.url);var u=V((x0,A)=>{A.exports=E;E.sync=u$;var D=W("fs");function A$($,q){var L=q.pathExt!==void 0?q.pathExt:process.env.PATHEXT;if(!L)return!0;if(L=L.split(";"),L.indexOf("")!==-1)return!0;for(var J=0;J<L.length;J++){var Q=L[J].toLowerCase();if(Q&&$.substr(-Q.length).toLowerCase()===Q)return!0}return!1}function w($,q,L){if(!$.isSymbolicLink()&&!$.isFile())return!1;return A$(q,L)}function E($,q,L){D.stat($,function(J,Q){L(J,J?!1:w(Q,$,q))})}function u$($,q){return w(D.statSync($),$,q)}});var g=V((T0,m)=>{m.exports=c;c.sync=h$;var h=W("fs");function c($,q,L){h.stat($,function(J,Q){L(J,J?!1:l(Q,q))})}function h$($,q){return l(h.statSync($),q)}function l($,q){return $.isFile()&&c$($,q)}function c$($,q){var{mode:L,uid:J,gid:Q}=$,Z=q.uid!==void 0?q.uid:process.getuid&&process.getuid(),z=q.gid!==void 0?q.gid:process.getgid&&process.getgid(),Y=parseInt("100",8),G=parseInt("010",8),H=parseInt("001",8),M=Y|G,U=L&H||L&G&&Q===z||L&Y&&J===Z||L&M&&Z===0;return U}});var p=V((R0,d)=>{var _0=W("fs"),P;if(process.platform==="win32"||global.TESTING_WINDOWS)P=u();else P=g();d.exports=I;I.sync=l$;function I($,q,L){if(typeof q==="function")L=q,q={};if(!L){if(typeof Promise!=="function")throw TypeError("callback not provided");return new Promise(function(J,Q){I($,q||{},function(Z,z){if(Z)Q(Z);else J(z)})})}P($,q||{},function(J,Q){if(J){if(J.code==="EACCES"||q&&q.ignoreErrors)J=null,Q=!1}L(J,Q)})}function l$($,q){try{return P.sync($,q||{})}catch(L){if(q&&q.ignoreErrors||L.code==="EACCES")return!1;else throw L}}});var a=V((b0,o)=>{var O=process.platform==="win32"||process.env.OSTYPE==="cygwin"||process.env.OSTYPE==="msys",i=W("path"),m$=O?";":":",n=p(),t=($)=>Object.assign(Error(`not found: ${$}`),{code:"ENOENT"}),r=($,q)=>{let L=q.colon||m$,J=$.match(/\//)||O&&$.match(/\\/)?[""]:[...O?[process.cwd()]:[],...(q.path||process.env.PATH||"").split(L)],Q=O?q.pathExt||process.env.PATHEXT||".EXE;.CMD;.BAT;.COM":"",Z=O?Q.split(L):[""];if(O){if($.indexOf(".")!==-1&&Z[0]!=="")Z.unshift("")}return{pathEnv:J,pathExt:Z,pathExtExe:Q}},s=($,q,L)=>{if(typeof q==="function")L=q,q={};if(!q)q={};let{pathEnv:J,pathExt:Q,pathExtExe:Z}=r($,q),z=[],Y=(H)=>new Promise((M,U)=>{if(H===J.length)return q.all&&z.length?M(z):U(t($));let K=J[H],f=/^".*"$/.test(K)?K.slice(1,-1):K,k=i.join(f,$),S=!f&&/^\.[\\\/]/.test($)?$.slice(0,2)+k:k;M(G(S,H,0))}),G=(H,M,U)=>new Promise((K,f)=>{if(U===Q.length)return K(Y(M+1));let k=Q[U];n(H+k,{pathExt:Z},(S,x$)=>{if(!S&&x$)if(q.all)z.push(H+k);else return K(H+k);return K(G(H,M,U+1))})});return L?Y(0).then((H)=>L(null,H),L):Y(0)},g$=($,q)=>{q=q||{};let{pathEnv:L,pathExt:J,pathExtExe:Q}=r($,q),Z=[];for(let z=0;z<L.length;z++){let Y=L[z],G=/^".*"$/.test(Y)?Y.slice(1,-1):Y,H=i.join(G,$),M=!G&&/^\.[\\\/]/.test($)?$.slice(0,2)+H:H;for(let U=0;U<J.length;U++){let K=M+J[U];try{if(n.sync(K,{pathExt:Q}))if(q.all)Z.push(K);else return K}catch(f){}}}if(q.all&&Z.length)return Z;if(q.nothrow)return null;throw t($)};o.exports=s;s.sync=g$});var $$=V((j0,C)=>{var e=($={})=>{let q=$.env||process.env;if(($.platform||process.platform)!=="win32")return"PATH";return Object.keys(q).reverse().find((J)=>J.toUpperCase()==="PATH")||"Path"};C.exports=e;C.exports.default=e});var Q$=V((v0,J$)=>{var q$=W("path"),d$=a(),p$=$$();function L$($,q){let L=$.options.env||process.env,J=process.cwd(),Q=$.options.cwd!=null,Z=Q&&process.chdir!==void 0&&!process.chdir.disabled;if(Z)try{process.chdir($.options.cwd)}catch(Y){}let z;try{z=d$.sync($.command,{path:L[p$({env:L})],pathExt:q?q$.delimiter:void 0})}catch(Y){}finally{if(Z)process.chdir(J)}if(z)z=q$.resolve(Q?$.options.cwd:"",z);return z}function i$($){return L$($)||L$($,!0)}J$.exports=i$});var X$=V((r$,x)=>{var y=/([()\][%!^"`<>&|;, *?])/g;function n$($){return $=$.replace(y,"^$1"),$}function t$($,q){if($=`${$}`,$=$.replace(/(?=(\\+?)?)\1"/g,"$1$1\\\""),$=$.replace(/(?=(\\+?)?)\1$/,"$1$1"),$=`"${$}"`,$=$.replace(y,"^$1"),q)$=$.replace(y,"^$1");return $}r$.command=n$;r$.argument=t$});var z$=V((D0,Z$)=>{Z$.exports=/^#!(.*)/});var Y$=V((w0,B$)=>{var a$=z$();B$.exports=($="")=>{let q=$.match(a$);if(!q)return null;let[L,J]=q[0].replace(/#! ?/,"").split(" "),Q=L.split("/").pop();if(Q==="env")return J;return J?`${Q} ${J}`:Q}});var V$=V((E0,H$)=>{var T=W("fs"),e$=Y$();function $0($){let L=Buffer.alloc(150),J;try{J=T.openSync($,"r"),T.readSync(J,L,0,150,0),T.closeSync(J)}catch(Q){}return e$(L.toString())}H$.exports=$0});var G$=V((A0,M$)=>{var q0=W("path"),U$=Q$(),K$=X$(),L0=V$(),J0=process.platform==="win32",Q0=/\.(?:com|exe)$/i,X0=/node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;function Z0($){$.file=U$($);let q=$.file&&L0($.file);if(q)return $.args.unshift($.file),$.command=q,U$($);return $.file}function z0($){if(!J0)return $;let q=Z0($),L=!Q0.test(q);if($.options.forceShell||L){let J=X0.test(q);$.command=q0.normalize($.command),$.command=K$.command($.command),$.args=$.args.map((Z)=>K$.argument(Z,J));let Q=[$.command].concat($.args).join(" ");$.args=["/d","/s","/c",`"${Q}"`],$.command=process.env.comspec||"cmd.exe",$.options.windowsVerbatimArguments=!0}return $}function B0($,q,L){if(q&&!Array.isArray(q))L=q,q=null;q=q?q.slice(0):[],L=Object.assign({},L);let J={command:$,args:q,options:L,file:void 0,original:{command:$,args:q}};return L.shell?J:z0(J)}M$.exports=B0});var O$=V((u0,k$)=>{var _=process.platform==="win32";function R($,q){return Object.assign(Error(`${q} ${$.command} ENOENT`),{code:"ENOENT",errno:"ENOENT",syscall:`${q} ${$.command}`,path:$.command,spawnargs:$.args})}function Y0($,q){if(!_)return;let L=$.emit;$.emit=function(J,Q){if(J==="exit"){let Z=W$(Q,q);if(Z)return L.call($,"error",Z)}return L.apply($,arguments)}}function W$($,q){if(_&&$===1&&!q.file)return R(q.original,"spawn");return null}function H0($,q){if(_&&$===1&&!q.file)return R(q.original,"spawnSync");return null}k$.exports={hookChildProcess:Y0,verifyENOENT:W$,verifyENOENTSync:H0,notFoundError:R}});var P$=V((h0,F)=>{var F$=W("child_process"),b=G$(),j=O$();function f$($,q,L){let J=b($,q,L),Q=F$.spawn(J.command,J.args,J.options);return j.hookChildProcess(Q,J),Q}function V0($,q,L){let J=b($,q,L),Q=F$.spawnSync(J.command,J.args,J.options);return Q.error=Q.error||j.verifyENOENTSync(Q.status,J),Q}F.exports=f$;F.exports.spawn=f$;F.exports.sync=V0;F.exports._parse=b;F.exports._enoent=j});import{readFileSync as N0}from"node:fs";import{fileURLToPath as S0}from"node:url";import{existsSync as W0,readFileSync as k0}from"node:fs";import{join as O0,isAbsolute as F0}from"node:path";var f0=w$(P$(),1);import{homedir as U0}from"node:os";import{join as X}from"node:path";var N=U0(),N$=process.platform==="win32";function S$($,q,L){if($)return $;if(q)return X(q,"lodestar");return L}function K0(){if(N$)return X(process.env.APPDATA??X(N,"AppData","Roaming"),"Lodestar");return X(N,".config","lodestar")}function M0(){if(N$)return X(process.env.LOCALAPPDATA??X(N,"AppData","Local"),"Lodestar");return X(N,".local","share","lodestar")}var G0=S$(process.env.LODESTAR_CONFIG_DIR,process.env.XDG_CONFIG_HOME,K0()),B=S$(process.env.LODESTAR_DATA_DIR,process.env.XDG_DATA_HOME,M0()),m0=process.env.LODESTAR_CONFIG??X(G0,"config.toml"),g0=X(B,"daemon.pid"),d0=X(B,"daemon.log"),p0=X(B,"session-chat-map.json"),i0=X(B,"session-resume-map.json"),n0=X(B,"session-turns-map.json"),t0=X(B,"session-model-map.json"),r0=X(B,"temp-session-leases.json"),s0=X(B,"tasklist-map.json"),o0=X(B,"agent-runs"),a0=X(B,"agent-session-ids.json"),e0=X(B,"managed-claude-plugin"),$1=X(B,"dsh"),I$=X(B,"agent-runtimes"),q1=X(B,"context-window-cache.json"),L1=X(B,"notify-callbacks.json"),J1=X(B,"alive-on-shutdown.json"),Q1=X(B,"inbox"),X1=X(B,"debug.sock"),Z1=X(B,"debug-context.json");var C$=["codex","claude","dsh"];function P0($,q=I$){let L=O0(q,$,"current.json");if(!W0(L))return null;let J=JSON.parse(k0(L,"utf8"));if(!Number.isFinite(J.checkedAt)||J.directory!==void 0&&!F0(J.directory))throw Error(`Invalid ${$} runtime state: ${L}`);return J}function y$($){return P0($)}var I0=JSON.parse(N0(S0(new URL("../package.json",import.meta.url)),"utf8"));console.log(`Lodestar v${I0.version}`);for(let $ of C$)try{let q=y$($);if(!q){console.log(`${$}: MISS(尚未自动安装)`);continue}if(q.error){console.log(`${$}: MISS(自动更新失败:${q.error})`),process.exitCode=1;continue}let L=$==="dsh"?["@deepseek-ai/dsh"]:Object.keys(q.versions??{});console.log(`${$}: ${L.map((J)=>`${J}@${q.versions?.[J]??"MISS"}`).join(", ")}`),console.log(` ${q.directory}`)}catch(q){console.error(`${$}: MISS(${q})`),process.exitCode=1}console.log(`Runtime: ${process.version} (${process.platform}-${process.arch})`);
|