@leviyuan/lodestar 0.16.0 → 0.16.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 CHANGED
@@ -35,7 +35,7 @@ npm i -g @leviyuan/lodestar
35
35
  | `lodestar-stop` | 停止 daemon |
36
36
  | `lodestar-update` | 升级到最新版(含 Codex CLI、Claude Code 和 Claude SDK)|
37
37
  | `lodestar-version` | 查看 Lodestar 和 Codex CLI 版本 |
38
- | `lodestar-consult` | 供项目群主 Agent 查询全局身份并调用其他模型 |
38
+ | `lodestar-agent` | 供主 Agent 把完整任务委派给其他模型并续跑原生会话 |
39
39
 
40
40
  **2. 跑向导**
41
41
 
@@ -62,7 +62,7 @@ lodestar-setup
62
62
  | `clear` / `cl` | 用状态卡展示杀进程并开新 thread(等价 `/clear`)|
63
63
  | `compact` / `cm` | 主动触发当前 thread 的上下文压缩,完成后状态卡收束 |
64
64
  | `model` / `md` | 展示账号→动态模型→effort 面板,按群持久化 |
65
- | `reviewers` | 管理所有项目共用的评审身份与角色预设 |
65
+ | `agents` | 查看当前所有可调用的完整 Agent 身份 |
66
66
  | `task` | 打开基础飞书任务清单绑定/删除面板 |
67
67
 
68
68
  **并发 worktree 群**
@@ -97,17 +97,17 @@ lodestar-setup
97
97
 
98
98
  ## 🎁 附加能力
99
99
 
100
- ### 🧠 多模型咨询与评审
100
+ ### 🧠 完整多模型 Agent 委派
101
101
 
102
- daemon 会为每个 Token Source 目录中的每个模型生成一个 `max` 默认身份。项目群发 `reviewers` 可把任意底层模型预设为正确性、架构、安全、测试或可维护性审查员;这些身份由所有项目共用。
102
+ daemon 会为每个 Token Source 目录中的每个模型生成一个实时 Agent 身份,并采用模型目录声明的真实默认 effort。项目群发 `agents` 可查看身份、模型、默认 effort 与当前 MISS;身份只负责模型路由,不再自动注入任何评审角色或提示词。
103
103
 
104
- 主 Agent 每次发起咨询前都必须通过 `lodestar-consult identities --json` 重新获取实时身份,再创建 `question` / `review` / `critique` run。选中多个身份时必须把全部 `--identity` 合并进同一个 run,由 daemon 在该 run 内并发 fan-out;禁止一身份一个 run 后台串行。`--cross-review` 会在首轮全部成功后进行且仅进行一轮交叉复核。任何指定身份失败都会保留在报告和卡片中,不会替换模型。
104
+ 主 Agent 每次委派前通过 `lodestar-agent identities --json` 获取实时身份,再把完整原始 prompt 交给 `lodestar-agent run`。同一 prompt 选择多个身份时用重复 `--identity` 合并为一个 run,由 daemon 并发 fan-out;不同任务可以建立多个并行 run。daemon 不理解“评审/实现/研究”等任务语义,也不改写输出格式,全部行为约束都来自主 Agent prompt。
105
105
 
106
- Reviewer 的文件系统保持只读,但网络完全开放:Codex 可使用 live Web Search 和只读沙箱内的出站网络,Claude/GLM/DeepSeek 可使用 WebSearch/WebFetch。reviewer 仍不会继承主 Agent consult capability。
106
+ Delegated Agent 使用完整能力:Codex 固定 `danger-full-access`,保留 apps、plugins、multi-agent、MCP hooks;Claude/GLM/DeepSeek 使用标准 `claude_code` preset、完整工具、项目 MCP daemon-managed Skills。它们可以真实修改文件、运行命令、联网、调用外部系统并再次委派;这些副作用与主 Agent 在同一工作区立即可见。
107
107
 
108
- `lodestar-consult` 只能在 Lodestar 管理的主 Agent 进程内使用。daemon 为当前 Session 注入短期 capability,reviewer 子进程会强制移除它,避免递归调用。daemon 每次启动都会先主动安装/更新裸 `lodestar-consult` 命令,再把它与 `feishu-notify` canonical Skill 同步到 Codex、Claude standalone 目录及一个 Claude SDK 本地插件;因此排除 user settings/env GLM/DeepSeek 主会话也能发现两项 Skill。源码运行与 npm 发布安装使用同一条命令契约。
108
+ `lodestar-agent` 只能在 Lodestar 管理的 Agent 进程内使用。主 Session 和每个 child 都得到独立随机 capability;child capability 只允许访问自己的 run 子树,父 run 取消时递归吊销。进程治理上限为同时运行 8 turn、全局 128 个在途 worker、每 Session 64 active run、每子树 32 active run、递归深度 8;排队原因会在 run 状态中透明显示,这些上限不改变 Agent 权限。daemon 启动时会安装/更新裸命令和 canonical Skill,并安全清理旧 daemon-owned `lodestar-consult` 命令/Skill。
109
109
 
110
- 本机 API 闭环为 `GET /consult/identities` 查身份、`POST /consult/runs` 建 run、`GET /consult/runs/<id>` 查结果、`DELETE /consult/runs/<id>` 取消。四个端点都要求当前主 Agent Bearer capability,不接受项目名/cwd 猜测路由。
110
+ 本机 API `GET /agents/identities`、`POST /agents/runs`、`GET|DELETE /agents/runs/<id>`、`POST /agents/runs/<id>/answer` 与 `POST /agents/runs/<id>/follow-up`。模型调用 `AskUserQuestion`/`request_user_input` 时 run 进入 `needs_input`,主 Agent 精确回答后继续;follow-up 新建可追踪 run,但复用同一 provider 原生 session。run 生命周期元数据原子落盘,大 prompt/输出各自存入私有正文文件,避免状态转换反复同步重写巨型 JSON;委派 session 不会混入主会话 `rs`/`fk` 列表。
111
111
 
112
112
  ### 📋 基础飞书任务清单
113
113
 
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import{resolve as E}from"node:path";import{fileURLToPath as b}from"node:url";async function C(e=process.argv.slice(2)){let n=e.shift()??"";if(!n||n==="help"||n==="--help"||n==="-h"){process.stdout.write(`${w()}
3
+ `);return}let t=q();switch(n){case"identities":{let r=await d(t,"GET","/agents/identities");process.stdout.write(e.includes("--json")?`${JSON.stringify(r,null,2)}
4
+ `:A(r));return}case"run":await P(t,e);return;case"follow-up":case"followup":await T(t,e);return;case"answer":await k(t,e);return;case"status":{let r=c(e[0],"status requires run_id"),s=await d(t,"GET",`/agents/runs/${encodeURIComponent(r)}`);if(process.stdout.write($(s)),s.status==="failed"||s.status==="cancelled")process.exitCode=1;return}case"cancel":{let r=c(e[0],"cancel requires run_id"),s=await d(t,"DELETE",`/agents/runs/${encodeURIComponent(r)}`);process.stdout.write(`${JSON.stringify(s)}
5
+ `);return}default:throw Error(w())}}async function P(e,n){let t=g(n,!0),r=await m(t),s={identity_ids:t.identityIds,prompt:r,...t.effort?{effort:t.effort}:{}},i=await d(e,"POST","/agents/runs",s);await y(e,i,t.noWait)}async function T(e,n){let t=c(n.shift(),"follow-up requires run_id"),r=g(n,!1),i={prompt:await m(r),...r.identityId?{identity_id:r.identityId}:{},...r.effort?{effort:r.effort}:{}},o=await d(e,"POST",`/agents/runs/${encodeURIComponent(t)}/follow-up`,i);await y(e,o,r.noWait)}async function k(e,n){let t=c(n.shift(),"answer requires run_id"),r="",s="",i=!1,o={};for(let u=0;u<n.length;u++){let a=n[u],f=()=>c(n[++u],`${a} requires a value`);switch(a){case"--identity":case"-i":r=f();break;case"--request":s=f();break;case"--answer":{let p=f(),l=p.indexOf("=");if(l<=0)throw Error("--answer must be question-or-id=value");o[p.slice(0,l)]=p.slice(l+1);break}case"--stdin":i=!0;break;default:throw Error(`unknown answer option: ${a}`)}}if(i){let u=(await S()).trim(),a;try{a=JSON.parse(u)}catch{throw Error("answer stdin must be a JSON object")}if(!a||typeof a!=="object"||Array.isArray(a))throw Error("answer stdin must be a JSON object");for(let[f,p]of Object.entries(a))o[f]=String(p)}if(!s)throw Error("answer requires --request");if(Object.keys(o).length===0)throw Error("answer requires --answer or --stdin");let I=await d(e,"POST",`/agents/runs/${encodeURIComponent(t)}/answer`,{request_id:s,answers:o,...r?{identity_id:r}:{}});await h(e,String(I.run_id??t))}function g(e,n){let t={identityIds:[],identityId:"",effort:"",prompt:"",noWait:!1,readStdin:!1},r=[];for(let s=0;s<e.length;s++){let i=e[s],o=()=>c(e[++s],`${i} requires a value`);switch(i){case"--identity":case"-i":if(n)t.identityIds.push(o());else t.identityId=o();break;case"--effort":t.effort=o();break;case"--prompt":t.prompt=o();break;case"--stdin":t.readStdin=!0;break;case"--no-wait":t.noWait=!0;break;default:if(i.startsWith("-"))throw Error(`unknown option: ${i}`);r.push(i)}}if(t.identityIds=[...new Set(t.identityIds)],n&&t.identityIds.length===0)throw Error("run requires at least one --identity");if(!t.prompt&&r.length)t.prompt=r.join(" ");if(!t.prompt)t.readStdin=!0;return t}async function m(e){let n=e.readStdin?await S():"",t=e.prompt||n;if(!t.trim())throw Error("agent prompt is empty");return t}async function y(e,n,t){let r=String(n.run_id??"");if(!r)throw Error("agent API returned no run_id");if(t){process.stdout.write(`${JSON.stringify(n,null,2)}
6
+ `);return}await h(e,r)}async function h(e,n){let t=!1,r=()=>{if(t)return;t=!0,d(e,"DELETE",`/agents/runs/${encodeURIComponent(n)}`).then(()=>process.exit(130),(s)=>{process.stderr.write(`lodestar-agent: cancellation failed: ${_(s)}
7
+ `),process.exit(1)})};process.once("SIGINT",r),process.once("SIGTERM",r);try{while(!0){let s=await d(e,"GET",`/agents/runs/${encodeURIComponent(n)}`);if(s.status==="needs_input"||s.status==="completed"||s.status==="failed"||s.status==="cancelled"){if(process.stdout.write($(s)),s.status==="failed"||s.status==="cancelled")process.exitCode=1;return}await new Promise((i)=>setTimeout(i,1000))}}finally{process.off("SIGINT",r),process.off("SIGTERM",r)}}function q(){let e=String(process.env.LODESTAR_AGENT_URL??"").replace(/\/+$/,""),n=String(process.env.LODESTAR_AGENT_CAPABILITY??"");if(!e||!n)throw Error("lodestar-agent must run inside a Lodestar-managed Agent session (missing capability)");return{baseUrl:e,capability:n}}async function d(e,n,t,r){let s=await fetch(`${e.baseUrl}${t}`,{method:n,headers:{authorization:`Bearer ${e.capability}`,...r?{"content-type":"application/json"}:{}},...r?{body:JSON.stringify(r)}:{}}),i=await s.text(),o;try{o=JSON.parse(i)}catch{throw Error(`agent API ${n} ${t} returned HTTP ${s.status}: ${i||"(empty)"}`)}if(!s.ok)throw Error(o?.error??`agent API HTTP ${s.status}`);return o}function A(e){let n=[`catalog ${e.catalog_generation??"MISS"}`];for(let t of e.identities??[])n.push([t.status==="ready"?"✅":"MISS",t.id,t.display_name,t.model,`default-effort=${t.default_effort}`,t.source_default?"source-default":"",t.reason??""].filter(Boolean).join(" · "));for(let t of e.source_failures??[])n.push(`MISS · ${t.display} · ${t.reason}`);return`${n.join(`
8
+ `)}
9
+ `}function $(e){let n=[`# Lodestar agent ${e.run_id??"MISS"}`,"",`- Status: ${e.status??"MISS"}`,`- Depth: ${e.depth??"MISS"}`,...e.parent_run_id?[`- Parent: ${e.parent_run_id} (${e.parent_kind??"delegate"})`]:[]];if(e.error)n.push(`- Error: ${e.error}`);for(let t of e.workers??[]){if(n.push("",`## ${t.identity_name??t.identity_id}`,"",`Status: ${t.status}`),t.session_id)n.push(`Session: ${t.session_id}`);if(t.error)n.push("",`Error: ${t.error}`);if(t.pending_input){n.push("",`Input request: ${t.pending_input.request_id}`);for(let r of t.pending_input.questions??[])if(n.push(`- [${r.id}] ${r.question}`),r.options?.length)n.push(` Options: ${r.options.map((s)=>s.label).join(" / ")}`);n.push("","Answer with:",`lodestar-agent answer ${e.run_id} --identity '${t.identity_id}' --request '${t.pending_input.request_id}' --stdin`)}if(t.output)n.push("",t.output)}if(e.presentation_errors?.length)n.push("","Presentation errors:",...e.presentation_errors.map((t)=>`- ${t}`));return`${n.join(`
10
+ `)}
11
+ `}async function S(){if(process.stdin.isTTY)return"";let e=[];for await(let n of process.stdin)e.push(Buffer.isBuffer(n)?n:Buffer.from(n));return Buffer.concat(e).toString("utf8")}function c(e,n){if(!e?.trim())throw Error(n);return e.trim()}function w(){return["Usage:"," lodestar-agent identities [--json]"," lodestar-agent run --identity <id> [--identity <id>...] [--effort <level>] --stdin"," lodestar-agent follow-up <run_id> [--identity <id>] [--effort <level>] --stdin"," lodestar-agent answer <run_id> [--identity <id>] --request <id> (--answer key=value | --stdin)"," lodestar-agent status <run_id>"," lodestar-agent cancel <run_id>"].join(`
12
+ `)}function _(e){return e instanceof Error?e.message:String(e)}if(process.argv[1]&&E(process.argv[1])===b(import.meta.url))C().catch((e)=>{process.stderr.write(`lodestar-agent: ${_(e)}
13
+ `),process.exitCode=1});export{g as parsePromptArgs,C as main};
@@ -1,5 +1,5 @@
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,"consult-identities.json"),Fz=Y(H,"consult-runs"),vz=Y(H,"managed-claude-plugin"),yz=Y(H,"context-window-cache.json"),Rz=Y(H,"notify-callbacks.json"),Tz=Y(H,"alive-on-shutdown.json"),uz=Y(H,"inbox"),gz=Y(H,"debug.sock"),Sz=Y(H,"debug-context.json");import{chmodSync as c,closeSync as y,fsyncSync as j,mkdirSync as l,openSync as _,renameSync as r,unlinkSync as s,writeFileSync as d}from"node:fs";import{randomUUID as a}from"node:crypto";import{dirname as P}from"node:path";var o=384;var i=448;function n($){let q=P($);l(q,{recursive:!0,mode:i})}function t($,q,J){n($);let Q=`${$}.${process.pid}.${a()}.tmp`,X=null;try{X=_(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}
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,"context-window-cache.json"),Rz=Y(H,"notify-callbacks.json"),Tz=Y(H,"alive-on-shutdown.json"),uz=Y(H,"inbox"),gz=Y(H,"debug.sock"),Sz=Y(H,"debug-context.json");import{chmodSync as c,closeSync as y,fsyncSync as j,mkdirSync as l,openSync as _,renameSync as r,unlinkSync as s,writeFileSync as d}from"node:fs";import{randomUUID as a}from"node:crypto";import{dirname as P}from"node:path";var o=384;var i=448;function n($){let q=P($);l(q,{recursive:!0,mode:i})}function t($,q,J){n($);let Q=`${$}.${process.pid}.${a()}.tmp`,X=null;try{X=_(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
3
  ${z.green}>${z.reset} `)).trim();if(!Q&&q.default!==void 0)return q.default;if(!Q&&q.required){console.log(`${z.red}必填,请重新输入${z.reset}`);continue}return Q}}function Yz($){let q="═".repeat(58);console.log(`
4
4
  ${z.bold}${z.cyan}╔${q}╗${z.reset}`),console.log(`${z.bold}${z.cyan}║ ${$.padEnd(54)} ║${z.reset}`),console.log(`${z.bold}${z.cyan}╚${q}╝${z.reset}
5
5
  `)}function E($,q,J){console.log(`
@@ -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(J,K,Y){if(J)return J;if(K)return q(K,"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()),Q=b(process.env.LODESTAR_DATA_DIR,process.env.XDG_DATA_HOME,V()),x=process.env.LODESTAR_CONFIG??q(w,"config.toml"),Z=q(Q,"daemon.pid"),S=q(Q,"daemon.log"),E=q(Q,"session-chat-map.json"),v=q(Q,"session-resume-map.json"),h=q(Q,"session-turns-map.json"),k=q(Q,"session-model-map.json"),R=q(Q,"temp-session-leases.json"),F=q(Q,"tasklist-map.json"),T=q(Q,"consult-identities.json"),m=q(Q,"consult-runs"),C=q(Q,"managed-claude-plugin"),j=q(Q,"context-window-cache.json"),l=q(Q,"notify-callbacks.json"),c=q(Q,"alive-on-shutdown.json"),_=q(Q,"inbox"),t=q(Q,"debug.sock"),A=q(Q,"debug-context.json");import{execSync as G}from"node:child_process";import{readFileSync as L,writeFileSync as D}from"node:fs";function M(J){try{if(process.platform==="linux")return L(`/proc/${J}/cmdline`,"utf8").replace(/\0/g," ").trim();if(process.platform==="darwin")return G(`ps -p ${J} -o args=`,{encoding:"utf8",timeout:2000}).trim();if(process.platform==="win32")return G(`powershell -NoProfile -Command "(Get-CimInstance Win32_Process -Filter 'ProcessId=${J}').CommandLine"`,{encoding:"utf8",timeout:5000}).trim()||null;return null}catch{return null}}function N(J,K){if(!Number.isFinite(J)||J<=0||!K)return!1;let Y=M(J);if(!Y)return!1;if(process.platform==="win32")return Y.toLowerCase().includes(K.toLowerCase());return Y.includes(K)}var z={reset:"\x1B[0m",bold:"\x1B[1m",green:"\x1B[32m",yellow:"\x1B[33m",red:"\x1B[31m",dim:"\x1B[2m"};function P(J){return new Promise((K)=>setTimeout(K,J))}async function u(){if(!U(Z)){console.log(`${z.yellow}Lodestar daemon 未运行${z.reset} ${z.dim}(${Z} 不存在)${z.reset}`);return}let J=y(Z,"utf8").split(`
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(J,K,Y){if(J)return J;if(K)return q(K,"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()),Q=b(process.env.LODESTAR_DATA_DIR,process.env.XDG_DATA_HOME,V()),x=process.env.LODESTAR_CONFIG??q(w,"config.toml"),Z=q(Q,"daemon.pid"),S=q(Q,"daemon.log"),E=q(Q,"session-chat-map.json"),v=q(Q,"session-resume-map.json"),h=q(Q,"session-turns-map.json"),k=q(Q,"session-model-map.json"),R=q(Q,"temp-session-leases.json"),F=q(Q,"tasklist-map.json"),T=q(Q,"agent-runs"),m=q(Q,"agent-session-ids.json"),C=q(Q,"managed-claude-plugin"),j=q(Q,"context-window-cache.json"),l=q(Q,"notify-callbacks.json"),c=q(Q,"alive-on-shutdown.json"),_=q(Q,"inbox"),t=q(Q,"debug.sock"),A=q(Q,"debug-context.json");import{execSync as G}from"node:child_process";import{readFileSync as L,writeFileSync as D}from"node:fs";function M(J){try{if(process.platform==="linux")return L(`/proc/${J}/cmdline`,"utf8").replace(/\0/g," ").trim();if(process.platform==="darwin")return G(`ps -p ${J} -o args=`,{encoding:"utf8",timeout:2000}).trim();if(process.platform==="win32")return G(`powershell -NoProfile -Command "(Get-CimInstance Win32_Process -Filter 'ProcessId=${J}').CommandLine"`,{encoding:"utf8",timeout:5000}).trim()||null;return null}catch{return null}}function N(J,K){if(!Number.isFinite(J)||J<=0||!K)return!1;let Y=M(J);if(!Y)return!1;if(process.platform==="win32")return Y.toLowerCase().includes(K.toLowerCase());return Y.includes(K)}var z={reset:"\x1B[0m",bold:"\x1B[1m",green:"\x1B[32m",yellow:"\x1B[33m",red:"\x1B[31m",dim:"\x1B[2m"};function P(J){return new Promise((K)=>setTimeout(K,J))}async function u(){if(!U(Z)){console.log(`${z.yellow}Lodestar daemon 未运行${z.reset} ${z.dim}(${Z} 不存在)${z.reset}`);return}let J=y(Z,"utf8").split(`
3
3
  `),K=parseInt((J[0]??"").trim(),10),Y=(J[1]??"").trim();if(!Number.isFinite(K)||K<=0)console.error(`${z.red}PID 文件格式坏:${z.reset} ${Z}`),process.exit(1);if(Y&&!N(K,Y)){console.log(`${z.yellow}PID ${K} 上没有 daemon (stale 文件)${z.reset}`),console.log(`${z.dim}手删 ${Z} 后再试${z.reset}`);return}console.log(`${z.bold}停止 daemon${z.reset} (pid ${K})...`);try{if(process.platform==="win32")f(`taskkill /PID ${K} /T /F`,{stdio:"ignore"});else process.kill(K,"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((J)=>{console.error(`${z.red}lodestar-stop:${z.reset} ${J?.message??J}`),process.exit(1)});
@@ -1,5 +1,5 @@
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 o}from"node:path";var m=p(),a=process.platform==="win32";function $(t,l,r){if(t)return t;if(l)return o(l,"lodestar");return r}function u(){if(a)return o(process.env.APPDATA??o(m,"AppData","Roaming"),"Lodestar");return o(m,".config","lodestar")}function y(){if(a)return o(process.env.LOCALAPPDATA??o(m,"AppData","Local"),"Lodestar");return o(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??o(C,"config.toml"),n=o(e,"daemon.pid"),f=o(e,"daemon.log"),S=o(e,"session-chat-map.json"),q=o(e,"session-resume-map.json"),z=o(e,"session-turns-map.json"),J=o(e,"session-model-map.json"),Q=o(e,"temp-session-leases.json"),Y=o(e,"tasklist-map.json"),Z=o(e,"consult-identities.json"),W=o(e,"consult-runs"),X=o(e,"managed-claude-plugin"),i=o(e,"context-window-cache.json"),B=o(e,"notify-callbacks.json"),G=o(e,"alive-on-shutdown.json"),N=o(e,"inbox"),U=o(e,"debug.sock"),F=o(e,"debug-context.json");var s={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(`${s.red}spawn npm 失败:${s.reset} ${c.message}`),l(1)})})}async function w(){console.log(`${s.bold}更新 Lodestar + Codex CLI + Claude Code / SDK${s.reset}`),console.log(`${s.dim}npm i -g ${d.join(" ")}${s.reset}
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 o}from"node:path";var m=p(),a=process.platform==="win32";function $(t,l,r){if(t)return t;if(l)return o(l,"lodestar");return r}function u(){if(a)return o(process.env.APPDATA??o(m,"AppData","Roaming"),"Lodestar");return o(m,".config","lodestar")}function y(){if(a)return o(process.env.LOCALAPPDATA??o(m,"AppData","Local"),"Lodestar");return o(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??o(C,"config.toml"),n=o(e,"daemon.pid"),f=o(e,"daemon.log"),S=o(e,"session-chat-map.json"),q=o(e,"session-resume-map.json"),z=o(e,"session-turns-map.json"),J=o(e,"session-model-map.json"),Q=o(e,"temp-session-leases.json"),Y=o(e,"tasklist-map.json"),Z=o(e,"agent-runs"),W=o(e,"agent-session-ids.json"),X=o(e,"managed-claude-plugin"),i=o(e,"context-window-cache.json"),B=o(e,"notify-callbacks.json"),G=o(e,"alive-on-shutdown.json"),N=o(e,"inbox"),U=o(e,"debug.sock"),F=o(e,"debug-context.json");var s={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(`${s.red}spawn npm 失败:${s.reset} ${c.message}`),l(1)})})}async function w(){console.log(`${s.bold}更新 Lodestar + Codex CLI + Claude Code / SDK${s.reset}`),console.log(`${s.dim}npm i -g ${d.join(" ")}${s.reset}
3
3
  `);let t=await b();if(t!==0)console.error(`
4
4
  ${s.red}更新失败 (npm exit ${t})${s.reset}`),process.exit(t);if(console.log(`
5
5
  ${s.green}✓ 更新完成${s.reset}`),x(n))console.log(),console.log(`${s.yellow}检测到 daemon 仍在跑老版本进程, 用新版本需要重启:${s.reset}`),console.log(` ${s.dim}# Linux systemd --user 托管的:${s.reset}`),console.log(` ${s.cyan}systemctl --user restart lodestar${s.reset} ${s.dim}# Linux${s.reset}`),console.log(` ${s.dim}# macOS launchd / Windows 任务计划:用对应服务管理器重启。${s.reset}`),console.log(` ${s.dim}# 或手动重启:${s.reset}`),console.log(` ${s.cyan}lodestar-stop && lodestar-daemon${s.reset}`)}w().catch((t)=>{console.error(`${s.red}lodestar-update:${s.reset} ${t?.message??t}`),process.exit(1)});