shennian 0.4.71 → 0.4.72

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.
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "jsMinified": true,
4
4
  "minifier": "esbuild",
5
- "fileCount": 219,
5
+ "fileCount": 220,
6
6
  "files": [
7
7
  {
8
8
  "file": "bin/shennian.js",
@@ -106,8 +106,8 @@
106
106
  },
107
107
  {
108
108
  "file": "src/agents/claude.js",
109
- "beforeBytes": 18877,
110
- "afterBytes": 9108
109
+ "beforeBytes": 18953,
110
+ "afterBytes": 8992
111
111
  },
112
112
  {
113
113
  "file": "src/agents/codex-managed-permissions.js",
@@ -201,8 +201,8 @@
201
201
  },
202
202
  {
203
203
  "file": "src/agents/model-registry/discovery.js",
204
- "beforeBytes": 11070,
205
- "afterBytes": 5176
204
+ "beforeBytes": 11711,
205
+ "afterBytes": 5499
206
206
  },
207
207
  {
208
208
  "file": "src/agents/model-registry/opencode-api.js",
@@ -211,8 +211,8 @@
211
211
  },
212
212
  {
213
213
  "file": "src/agents/model-registry/parsers.js",
214
- "beforeBytes": 22727,
215
- "afterBytes": 11534
214
+ "beforeBytes": 23995,
215
+ "afterBytes": 12356
216
216
  },
217
217
  {
218
218
  "file": "src/agents/model-registry/runner.js",
@@ -221,13 +221,13 @@
221
221
  },
222
222
  {
223
223
  "file": "src/agents/model-registry/service.js",
224
- "beforeBytes": 6036,
225
- "afterBytes": 2605
224
+ "beforeBytes": 7401,
225
+ "afterBytes": 2929
226
226
  },
227
227
  {
228
228
  "file": "src/agents/model-registry/types.js",
229
- "beforeBytes": 384,
230
- "afterBytes": 235
229
+ "beforeBytes": 906,
230
+ "afterBytes": 495
231
231
  },
232
232
  {
233
233
  "file": "src/agents/model-registry.js",
@@ -306,8 +306,8 @@
306
306
  },
307
307
  {
308
308
  "file": "src/commands/agent-readiness.js",
309
- "beforeBytes": 3425,
310
- "afterBytes": 2819
309
+ "beforeBytes": 3718,
310
+ "afterBytes": 3018
311
311
  },
312
312
  {
313
313
  "file": "src/commands/agent.js",
@@ -361,8 +361,8 @@
361
361
  },
362
362
  {
363
363
  "file": "src/commands/manager.js",
364
- "beforeBytes": 11819,
365
- "afterBytes": 7639
364
+ "beforeBytes": 9692,
365
+ "afterBytes": 6336
366
366
  },
367
367
  {
368
368
  "file": "src/commands/pair-authorization.js",
@@ -409,6 +409,11 @@
409
409
  "beforeBytes": 13446,
410
410
  "afterBytes": 6795
411
411
  },
412
+ {
413
+ "file": "src/commands/worker.js",
414
+ "beforeBytes": 6654,
415
+ "afterBytes": 4212
416
+ },
412
417
  {
413
418
  "file": "src/config/index.js",
414
419
  "beforeBytes": 2801,
@@ -416,8 +421,8 @@
416
421
  },
417
422
  {
418
423
  "file": "src/daemon-ipc/agent-readiness.js",
419
- "beforeBytes": 2884,
420
- "afterBytes": 1555
424
+ "beforeBytes": 4154,
425
+ "afterBytes": 2206
421
426
  },
422
427
  {
423
428
  "file": "src/daemon-ipc/client.js",
@@ -486,8 +491,8 @@
486
491
  },
487
492
  {
488
493
  "file": "src/index.js",
489
- "beforeBytes": 40923,
490
- "afterBytes": 20430
494
+ "beforeBytes": 41017,
495
+ "afterBytes": 20498
491
496
  },
492
497
  {
493
498
  "file": "src/log-redaction.js",
@@ -501,13 +506,13 @@
501
506
  },
502
507
  {
503
508
  "file": "src/manager/prompt.js",
504
- "beforeBytes": 5115,
505
- "afterBytes": 8460
509
+ "beforeBytes": 5067,
510
+ "afterBytes": 8427
506
511
  },
507
512
  {
508
513
  "file": "src/manager/registry.js",
509
- "beforeBytes": 12065,
510
- "afterBytes": 5661
514
+ "beforeBytes": 16879,
515
+ "afterBytes": 8079
511
516
  },
512
517
  {
513
518
  "file": "src/manager/retired-external-channel-compat.js",
@@ -516,13 +521,13 @@
516
521
  },
517
522
  {
518
523
  "file": "src/manager/runtime.js",
519
- "beforeBytes": 33902,
520
- "afterBytes": 16475
524
+ "beforeBytes": 34449,
525
+ "afterBytes": 16700
521
526
  },
522
527
  {
523
528
  "file": "src/manager/worker-ipc.js",
524
- "beforeBytes": 11457,
525
- "afterBytes": 6210
529
+ "beforeBytes": 19731,
530
+ "afterBytes": 11321
526
531
  },
527
532
  {
528
533
  "file": "src/manager/worker-markdown.js",
@@ -836,8 +841,8 @@
836
841
  },
837
842
  {
838
843
  "file": "src/session/handlers/agent-workspace-validation.js",
839
- "beforeBytes": 9962,
840
- "afterBytes": 5313
844
+ "beforeBytes": 9750,
845
+ "afterBytes": 5155
841
846
  },
842
847
  {
843
848
  "file": "src/session/handlers/agents.js",
@@ -996,8 +1001,8 @@
996
1001
  },
997
1002
  {
998
1003
  "file": "src/session/queue.js",
999
- "beforeBytes": 49532,
1000
- "afterBytes": 21739
1004
+ "beforeBytes": 49538,
1005
+ "afterBytes": 21745
1001
1006
  },
1002
1007
  {
1003
1008
  "file": "src/session/queued-chat-dispatch.js",
@@ -1,8 +1,8 @@
1
- import p from"node:fs";import o from"node:path";import{createInterface as y}from"node:readline";import{randomUUID as f}from"node:crypto";import{AgentAdapter as S,registerAgent as E}from"./adapter.js";import{resolveBuiltinCommand as m,spawnAgentCommand as x,spawnResolvedCommandSync as v}from"./command-spec.js";import{buildAgentProcessEnv as P,buildManagedAgentProcessEnv as I,buildManagedNativeFullProcessEnv as C}from"../agent-env.js";import{buildPlatformInstructions as g}from"./platform-instructions.js";import{resolveManagedAgentAdapterEnforcement as k,isManagedAgentNativeFull as c}from"../security/managed-agent-policy.js";import{registerManagedAgentRuntimeSecurity as w}from"../security/managed-agent-runtime.js";import{resolveManagedRoomIpcPaths as A}from"../daemon-ipc/paths.js";import{CLAUDE_MANAGED_RUNTIME_SECURITY as _,compileClaudeManagedPermissions as T}from"./claude-managed-permissions.js";w("claude",_);function R(n){return n?.trim()||"default"}const O=new Set(["low","medium","high","xhigh","max"]),h=new Map;function M(n){const e=n?.trim();if(e){if(O.has(e))return e;throw new Error(`Unsupported Claude reasoning effort "${e}". Supported values: low, medium, high, xhigh, max.`)}}function X(){h.clear()}function N(n){const e=n.trim();return e?!e.includes("claude.ai connectors are disabled because"):!1}function D(){const n=m("claude");if(!n)return!1;const e=`${n.kind}:${n.path}:${n.command}:${n.args.join("\0")}`;if(h.has(e))return h.get(e)??!1;try{const t=v(n,["--help"],{encoding:"utf-8",stdio:["ignore","pipe","pipe"],timeout:3e3,env:process.env}),s=`${t.stdout??""}
2
- ${t.stderr??""}`,a=/(?:^|\s)--effort(?:\s|,|<)/.test(s);return h.set(e,a),a}catch{return h.set(e,!1),!1}}class F extends S{options;type="claude";get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!0}}process=null;agentSessionId=null;sessionId=null;workDir=null;seq=0;runId="";hasEmittedText=!1;terminalState="open";pendingSuccess=null;persistNativeSession=!0;managedAgentPolicy=null;constructor(e={}){super(),this.options=e}externalChannel=null;shennianSessionId=null;extraEnv={};configure(e){this.shennianSessionId=e.sessionId??null,this.externalChannel=e.externalChannel??null,this.extraEnv=e.env??{},"managedAgentPolicy"in e&&(this.managedAgentPolicy=e.managedAgentPolicy??null),this.managedAgentPolicy&&(this.workDir=this.managedAgentPolicy.adapterPolicy.workDir)}async start(e,t,s,a){this.sessionId=e,this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??t,this.seq=0,this.persistNativeSession=a?.persistNativeSession!==!1,s&&(this.agentSessionId=s)}async send(e,t,s,a,l,r){if(r?.source==="room_activation"&&!this.managedAgentPolicy)throw new Error("managed_agent_policy_missing");await this.killProcess(),this.runId=f(),this.resetRunState();const i=["-p",e,"--output-format","stream-json","--verbose",...this.buildManagedPermissionConfig()?.args??[]];this.persistNativeSession||i.push("--no-session-persistence");const u=this.options.systemPrompt??g(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,l);u&&i.push("--append-system-prompt",u),this.options.hidden&&i.push("--name","Shennian Manager Substrate"),(!this.managedAgentPolicy||c(this.managedAgentPolicy))&&process.getuid?.()!==0&&i.push("--dangerously-skip-permissions"),i.push("--model",R(t));const d=M(s);d&&D()&&i.push("--effort",d),this.agentSessionId&&i.push("--resume",this.agentSessionId),this.spawnAndParse(i)}async resume(e){await this.killProcess(),this.agentSessionId=e,this.runId=f(),this.resetRunState();const t=["--resume",e,"--output-format","stream-json","--verbose",...this.buildManagedPermissionConfig()?.args??[]],s=this.options.systemPrompt??g(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0);s&&t.push("--append-system-prompt",s),this.options.hidden&&t.push("--name","Shennian Manager Substrate"),(!this.managedAgentPolicy||c(this.managedAgentPolicy))&&process.getuid?.()!==0&&t.push("--dangerously-skip-permissions"),this.spawnAndParse(t)}async stop(){await this.killProcess()}spawnAndParse(e){const t=m("claude");if(!t){this.emit("error",new Error('Command "claude" not found. Is Claude Code CLI installed?'));return}const s=x(t,e,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:this.buildProcessEnv()});this.process=s,y({input:s.stdout}).on("line",r=>{if(r.trim())try{const i=JSON.parse(r);this.handleStreamEvent(i)}catch{}});let l="";s.stderr?.on("data",r=>{const i=r.toString();if(l+=i,this.terminalState==="open")for(const u of i.split(`
1
+ import p from"node:fs";import o from"node:path";import{createInterface as y}from"node:readline";import{randomUUID as f}from"node:crypto";import{AgentAdapter as S,registerAgent as E}from"./adapter.js";import{resolveBuiltinCommand as m,spawnAgentCommand as x,spawnResolvedCommandSync as v}from"./command-spec.js";import{buildAgentProcessEnv as P,buildManagedAgentProcessEnv as I,buildManagedNativeFullProcessEnv as C}from"../agent-env.js";import{buildPlatformInstructions as g}from"./platform-instructions.js";import{resolveManagedAgentAdapterEnforcement as k,isManagedAgentNativeFull as h}from"../security/managed-agent-policy.js";import{registerManagedAgentRuntimeSecurity as w}from"../security/managed-agent-runtime.js";import{resolveManagedRoomIpcPaths as A}from"../daemon-ipc/paths.js";import{CLAUDE_MANAGED_RUNTIME_SECURITY as _,compileClaudeManagedPermissions as T}from"./claude-managed-permissions.js";w("claude",_);function R(n){return n?.trim()||"default"}const M=new Set(["low","medium","high","xhigh","max"]),c=new Map;function O(n){const e=n?.trim();if(e){if(M.has(e))return e;throw new Error(`Unsupported Claude reasoning effort "${e}". Supported values: low, medium, high, xhigh, max.`)}}function X(){c.clear()}function N(n){const e=n.trim();return e?!e.includes("claude.ai connectors are disabled because"):!1}function D(){const n=m("claude");if(!n)return!1;const e=`${n.kind}:${n.path}:${n.command}:${n.args.join("\0")}`;if(c.has(e))return c.get(e)??!1;try{const t=v(n,["--help"],{encoding:"utf-8",stdio:["ignore","pipe","pipe"],timeout:3e3,env:process.env}),s=`${t.stdout??""}
2
+ ${t.stderr??""}`,a=/(?:^|\s)--effort(?:\s|,|<)/.test(s);return c.set(e,a),a}catch{return c.set(e,!1),!1}}class F extends S{options;type="claude";get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!0}}process=null;agentSessionId=null;sessionId=null;workDir=null;seq=0;runId="";hasEmittedText=!1;terminalState="open";pendingSuccess=null;persistNativeSession=!0;managedAgentPolicy=null;constructor(e={}){super(),this.options=e}externalChannel=null;shennianSessionId=null;extraEnv={};configure(e){this.shennianSessionId=e.sessionId??null,this.externalChannel=e.externalChannel??null,this.extraEnv=e.env??{},"managedAgentPolicy"in e&&(this.managedAgentPolicy=e.managedAgentPolicy??null),this.managedAgentPolicy&&(this.workDir=this.managedAgentPolicy.adapterPolicy.workDir)}async start(e,t,s,a){this.sessionId=e,this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??t,this.seq=0,this.persistNativeSession=a?.persistNativeSession!==!1,s&&(this.agentSessionId=s)}async send(e,t,s,a,l,r){if(r?.source==="room_activation"&&!this.managedAgentPolicy)throw new Error("managed_agent_policy_missing");await this.killProcess(),this.runId=f(),this.resetRunState();const i=["-p",e,"--output-format","stream-json","--verbose",...this.buildManagedPermissionConfig()?.args??[]];this.persistNativeSession||i.push("--no-session-persistence");const u=this.options.systemPrompt??g(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,l);u&&i.push("--append-system-prompt",u),this.options.hidden&&i.push("--name","Shennian Manager Substrate"),(!this.managedAgentPolicy||h(this.managedAgentPolicy))&&process.getuid?.()!==0&&i.push("--dangerously-skip-permissions"),i.push("--model",R(t));const d=O(s);d&&D()&&i.push("--effort",d),this.agentSessionId&&i.push("--resume",this.agentSessionId),this.spawnAndParse(i)}async resume(e){await this.killProcess(),this.agentSessionId=e,this.runId=f(),this.resetRunState();const t=["--resume",e,"--output-format","stream-json","--verbose",...this.buildManagedPermissionConfig()?.args??[]],s=this.options.systemPrompt??g(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0);s&&t.push("--append-system-prompt",s),this.options.hidden&&t.push("--name","Shennian Manager Substrate"),(!this.managedAgentPolicy||h(this.managedAgentPolicy))&&process.getuid?.()!==0&&t.push("--dangerously-skip-permissions"),this.spawnAndParse(t)}async stop(){await this.killProcess()}spawnAndParse(e){const t=m("claude");if(!t){this.emit("error",new Error('Command "claude" not found. Is Claude Code CLI installed?'));return}const s=x(t,e,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:this.buildProcessEnv()});this.process=s,y({input:s.stdout}).on("line",r=>{if(r.trim())try{const i=JSON.parse(r);this.handleStreamEvent(i)}catch{}});let l="";s.stderr?.on("data",r=>{const i=r.toString();if(l+=i,this.terminalState==="open")for(const u of i.split(`
3
3
  `)){const d=u.trim();N(d)&&this.emitEvent({state:"delta",text:d+`
4
- `})}}),s.on("close",r=>{this.process===s&&(this.process=null,this.handleProcessClose(r,l))}),s.on("error",r=>{this.process===s&&(this.process=null,r.code==="ENOENT"?this.emit("error",new Error('Command "claude" not found. Is Claude Code CLI installed?')):this.emit("error",r))})}buildManagedPermissionConfig(){const e=this.managedAgentPolicy;if(!e||c(e))return null;const t=L();return T(k(e),e.adapterPolicy.workDir,{internalReadPaths:t.readPaths,internalUnixSockets:t.unixSockets,shellSubprocessPolicy:e.environmentPolicy.shellSubprocess})}buildProcessEnv(){return this.managedAgentPolicy?c(this.managedAgentPolicy)?C({NO_COLOR:"1",...this.extraEnv}):I({agentType:"claude",providerEnv:this.extraEnv,sessionEnv:this.extraEnv,runtimeEnv:{NO_COLOR:"1"}}):P(this.extraEnv)}handleStreamEvent(e){if(e.type==="system"&&e.subtype==="init"&&e.session_id){this.agentSessionId=e.session_id,this.emitEvent({state:"start",agentSessionId:this.agentSessionId});return}if(e.type==="system"&&e.subtype==="api_retry"&&e.error==="authentication_failed"){this.emitErrorIfOpen({state:"error",message:'Claude authentication failed. Run "claude auth login" and retry.'});return}if(e.type==="assistant"){if(e.message?.content){for(const t of e.message.content)if(t.type==="text"&&t.text){const s=this.hasEmittedText?`
4
+ `})}}),s.on("close",r=>{this.process===s&&(this.process=null,this.handleProcessClose(r,l))}),s.on("error",r=>{this.process===s&&(this.process=null,r.code==="ENOENT"?this.emit("error",new Error('Command "claude" not found. Is Claude Code CLI installed?')):this.emit("error",r))})}buildManagedPermissionConfig(){const e=this.managedAgentPolicy;if(!e||h(e))return null;const t=L();return T(k(e),e.adapterPolicy.workDir,{internalReadPaths:t.readPaths,internalUnixSockets:t.unixSockets,shellSubprocessPolicy:e.environmentPolicy.shellSubprocess})}buildProcessEnv(){return this.managedAgentPolicy?h(this.managedAgentPolicy)?C({NO_COLOR:"1",...this.extraEnv}):I({agentType:"claude",providerEnv:this.extraEnv,sessionEnv:this.extraEnv,runtimeEnv:{NO_COLOR:"1"}}):P(this.extraEnv)}handleStreamEvent(e){if(e.type==="system"&&e.subtype==="init"&&e.session_id){this.agentSessionId=e.session_id,this.emitEvent({state:"start",agentSessionId:this.agentSessionId});return}if(!(e.type==="system"&&e.subtype==="api_retry"&&e.error==="authentication_failed")){if(e.type==="assistant"){if(e.message?.content){for(const t of e.message.content)if(t.type==="text"&&t.text){const s=this.hasEmittedText?`
5
5
 
6
6
  `:"";this.emitEvent({state:"delta",text:s+t.text}),this.hasEmittedText=!0}else t.type==="thinking"&&t.thinking?this.emitEvent({state:"delta",text:t.thinking,thinking:!0}):t.type==="tool_use"&&this.emitEvent({state:"tool-call",name:t.name,args:t.input});return}if(e.subtype==="text"&&e.text){const t=this.hasEmittedText?`
7
7
 
8
- `:"";this.emitEvent({state:"delta",text:t+e.text}),this.hasEmittedText=!0}else e.subtype==="thinking"&&e.thinking?this.emitEvent({state:"delta",text:e.thinking,thinking:!0}):e.subtype==="tool_use"&&this.emitEvent({state:"tool-call",name:e.name,args:e.input});return}if(e.type==="result")if(e.subtype==="tool_result"){const t=typeof e.content=="string"?e.content:JSON.stringify(e.content);this.emitEvent({state:"tool-result",name:e.name,result:t})}else if(e.subtype==="success"){e.session_id&&(this.agentSessionId=e.session_id);const t=typeof e.result=="string"?e.result:"";!this.hasEmittedText&&t.trim()&&(this.emitEvent({state:"delta",text:t}),this.hasEmittedText=!0);const s=e.usage??e.message?.usage;this.pendingSuccess={agentSessionId:this.agentSessionId??void 0,usage:s?{inputTokens:s.input_tokens,outputTokens:s.output_tokens}:void 0}}else e.subtype==="error"&&this.emitErrorIfOpen({state:"error",message:e.error??e.result??"unknown error"})}handleProcessClose(e,t){if(e!==0&&e!==null){const s=t.trim()||`claude exited with code ${e}`;this.emitErrorIfOpen({state:"error",message:s});return}if(!this.hasEmittedText){this.emitErrorIfOpen({state:"error",message:"Claude completed without response text"});return}this.emitFinalIfOpen({state:"final",agentSessionId:this.pendingSuccess?.agentSessionId??this.agentSessionId??void 0,usage:this.pendingSuccess?.usage})}emitFinalIfOpen(e){this.terminalState==="open"&&(this.terminalState="final",this.emitEvent(e))}emitErrorIfOpen(e){this.terminalState==="open"&&(this.terminalState="error",this.emitEvent(e))}resetRunState(){this.seq=0,this.hasEmittedText=!1,this.terminalState="open",this.pendingSuccess=null}emitEvent(e){const t={...e,runId:this.runId,seq:this.seq++};this.emit("agentEvent",t)}async killProcess(){const e=this.process;e&&(this.process=null,e.kill("SIGTERM"),await new Promise(t=>{e.on("close",t),setTimeout(()=>{e.kill("SIGKILL"),t()},3e3)}))}}function L(){const n=A(),e=[n.secretFile],t=n.transport==="unix_socket"?[n.endpoint]:[];n.transport==="unix_socket"&&e.push(n.endpoint);const s=m("pi");return s?.path&&e.push(...U(s.path)),{readPaths:[...new Set(e)].sort(),unixSockets:[...new Set(t)].sort()}}function U(n){const e=o.normalize(n.trim());if(!e||!o.isAbsolute(e))return[];const t=[e];try{const s=p.realpathSync(e);t.push(s,o.dirname(s),o.dirname(o.dirname(s)));let a=o.dirname(s);for(let l=0;l<8;l+=1){const r=o.join(a,"package.json");try{if(JSON.parse(p.readFileSync(r,"utf8")).name==="shennian"){t.push(a);break}}catch{}const i=o.dirname(a);if(i===a)break;a=i}}catch{}return[...new Set(t)].sort()}E("claude",()=>new F);export{F as ClaudeAdapter,R as normalizeClaudeModelId,M as normalizeClaudeReasoningEffort,X as resetClaudeCapabilityCacheForTests,L as resolveClaudeManagedInternalAccess,U as resolveClaudeShennianCliReadPaths,N as shouldForwardClaudeStderrLine,D as supportsClaudeReasoningEffort};
8
+ `:"";this.emitEvent({state:"delta",text:t+e.text}),this.hasEmittedText=!0}else e.subtype==="thinking"&&e.thinking?this.emitEvent({state:"delta",text:e.thinking,thinking:!0}):e.subtype==="tool_use"&&this.emitEvent({state:"tool-call",name:e.name,args:e.input});return}if(e.type==="result")if(e.subtype==="tool_result"){const t=typeof e.content=="string"?e.content:JSON.stringify(e.content);this.emitEvent({state:"tool-result",name:e.name,result:t})}else if(e.subtype==="success"){e.session_id&&(this.agentSessionId=e.session_id);const t=typeof e.result=="string"?e.result:"";!this.hasEmittedText&&t.trim()&&(this.emitEvent({state:"delta",text:t}),this.hasEmittedText=!0);const s=e.usage??e.message?.usage;this.pendingSuccess={agentSessionId:this.agentSessionId??void 0,usage:s?{inputTokens:s.input_tokens,outputTokens:s.output_tokens}:void 0}}else e.subtype==="error"&&this.emitErrorIfOpen({state:"error",message:e.error??e.result??"unknown error"})}}handleProcessClose(e,t){if(e!==0&&e!==null){const s=t.trim()||`claude exited with code ${e}`;this.emitErrorIfOpen({state:"error",message:s});return}if(!this.hasEmittedText){this.emitErrorIfOpen({state:"error",message:"Claude completed without response text"});return}this.emitFinalIfOpen({state:"final",agentSessionId:this.pendingSuccess?.agentSessionId??this.agentSessionId??void 0,usage:this.pendingSuccess?.usage})}emitFinalIfOpen(e){this.terminalState==="open"&&(this.terminalState="final",this.emitEvent(e))}emitErrorIfOpen(e){this.terminalState==="open"&&(this.terminalState="error",this.emitEvent(e))}resetRunState(){this.seq=0,this.hasEmittedText=!1,this.terminalState="open",this.pendingSuccess=null}emitEvent(e){const t={...e,runId:this.runId,seq:this.seq++};this.emit("agentEvent",t)}async killProcess(){const e=this.process;e&&(this.process=null,e.kill("SIGTERM"),await new Promise(t=>{e.on("close",t),setTimeout(()=>{e.kill("SIGKILL"),t()},3e3)}))}}function L(){const n=A(),e=[n.secretFile],t=n.transport==="unix_socket"?[n.endpoint]:[];n.transport==="unix_socket"&&e.push(n.endpoint);const s=m("pi");return s?.path&&e.push(...U(s.path)),{readPaths:[...new Set(e)].sort(),unixSockets:[...new Set(t)].sort()}}function U(n){const e=o.normalize(n.trim());if(!e||!o.isAbsolute(e))return[];const t=[e];try{const s=p.realpathSync(e);t.push(s,o.dirname(s),o.dirname(o.dirname(s)));let a=o.dirname(s);for(let l=0;l<8;l+=1){const r=o.join(a,"package.json");try{if(JSON.parse(p.readFileSync(r,"utf8")).name==="shennian"){t.push(a);break}}catch{}const i=o.dirname(a);if(i===a)break;a=i}}catch{}return[...new Set(t)].sort()}E("claude",()=>new F);export{F as ClaudeAdapter,R as normalizeClaudeModelId,O as normalizeClaudeReasoningEffort,X as resetClaudeCapabilityCacheForTests,L as resolveClaudeManagedInternalAccess,U as resolveClaudeShennianCliReadPaths,N as shouldForwardClaudeStderrLine,D as supportsClaudeReasoningEffort};
@@ -1,3 +1,3 @@
1
- import{createInterface as b}from"node:readline";import{resolveBuiltinCommand as l,spawnResolvedCommand as M}from"../command-spec.js";import{fallbackClaudeAliasModels as k,discoverClaudeAliasModelsFromEnv as E,fallbackCodexModels as R,fallbackWorkBuddyModels as x,fallbackGeminiModels as _,parseCodexAppServerModels as O,parseCursorModels as A,parseOpenCodeModels as I}from"./parsers.js";import{runResolvedCommand as m}from"./runner.js";import{DISCOVERY_WORKDIR as w}from"./types.js";import{buildAgentProcessEnv as C,readLatestUserEnv as S}from"../../agent-env.js";import{CODEX_APP_SERVER_CLIENT_INFO as T}from"../codex-utils.js";import{PiRpcClient as P}from"../pi-rpc-client.js";import{loadConfig as $}from"../../config/index.js";import{discoverOpenCodeModelsViaApi as D}from"./opencode-api.js";function v(r,e,t,s,n,i){return r.stdin?new Promise((o,a)=>{const c=setTimeout(()=>{e.delete(t),a(new Error(`codex app-server request timed out: ${s}`))},i);e.set(t,{resolve:o,reject:a,timer:c}),r.stdin.write(`${JSON.stringify({id:t,method:s,params:n})}
2
- `,p=>{p&&(clearTimeout(c),e.delete(t),a(p))})}):Promise.reject(new Error("codex app-server stdin unavailable"))}async function L(r){const e=M(r,["app-server","--listen","stdio://"],{cwd:w,stdio:["pipe","pipe","pipe"],env:C({NO_COLOR:"1"})}),t=new Map;let s=1;b({input:e.stdout}).on("line",i=>{if(!i.trim())return;let o;try{o=JSON.parse(i)}catch{return}if(o.id==null)return;const a=t.get(o.id);a&&(clearTimeout(a.timer),t.delete(o.id),o.error?a.reject(new Error(o.error.message||`codex app-server error ${o.error.code??""}`.trim())):a.resolve(o.result))});try{await v(e,t,s++,"initialize",{clientInfo:T,capabilities:{experimentalApi:!0}},1e4);const[i,o]=await Promise.all([v(e,t,s++,"model/list",{},15e3),v(e,t,s++,"config/read",{},15e3).catch(()=>null)]),a=typeof o=="object"&&o!==null&&"config"in o?o.config:void 0;return O({...typeof i=="object"&&i!==null?i:{},config:a})}finally{for(const[i,o]of t)clearTimeout(o.timer),o.reject(new Error("codex app-server stopped")),t.delete(i);e.kill("SIGTERM"),setTimeout(()=>e.kill("SIGKILL"),1e3).unref()}}async function q(){const r=l("cursor");if(!r)return[];const e=await m(r,["--list-models"]);return A(e.stdout)}async function j(){const r=l("opencode");if(!r)return[];const e=await D().catch(()=>[]);if(e.length>0)return e;const t=await m(r,["models"]);return I(t.stdout)}async function G(){const r={id:"shennian-dashscope/deepseek-v4-flash-0731",name:"DeepSeek V4 Flash",provider:"shennian-dashscope",isDefault:!0,supportedReasoningEfforts:["low","high","max"].map(n=>({id:n,name:n})),defaultReasoningEffort:"high"},e=l("pi-coding-agent");if(!e)return[];if($().machineToken?.trim())return[r];const t=M(e,["--mode","rpc","--no-session","--offline","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--no-tools"],{cwd:w,stdio:["pipe","pipe","pipe"],env:C({NO_COLOR:"1"})}),s=new P(t,{requestTimeoutMs:1e4});try{const[n,i]=await Promise.all([s.request("get_available_models"),s.request("get_state")]),o=n.data&&typeof n.data=="object"?n.data:{},a=i.data&&typeof i.data=="object"?i.data:{},c=typeof a.model?.id=="string"&&typeof a.model.provider=="string"?`${a.model.provider}/${a.model.id}`:null;return Array.isArray(o.models)?o.models.flatMap(f=>{if(!f||typeof f!="object")return[];const d=f;if(typeof d.id!="string"||typeof d.provider!="string")return[];const h=`${d.provider}/${d.id}`,g=d.reasoning===!0?["off","minimal","low","medium","high","xhigh","max"].map(y=>({id:y,name:y})):void 0;return[{id:h,name:typeof d.name=="string"&&d.name.trim()?d.name:d.id,provider:d.provider,isDefault:h===c,...g?{supportedReasoningEfforts:g,defaultReasoningEffort:"medium"}:{}}]}):[]}catch{return[]}finally{s.close(),t.kill("SIGTERM"),setTimeout(()=>t.kill("SIGKILL"),1e3).unref()}}async function N(){const r=l("claude");if(!r)return[];const e=S(),t=E(e);if(t.length>0)return t;const s=k(e),n=await m(r,["--help"],3e3).catch(()=>null);return!n||/\bfable\b/i.test(`${n.stdout}
3
- ${n.stderr}`)?s:s.filter(i=>i.id!=="fable")}async function V(){const r=l("codex");if(!r)return[];const e=await L(r).catch(()=>[]);return e.length>0?e:R()}async function B(){return l("gemini")?_():[]}const u=[{id:"qwen3.6-plus",name:"Qwen 3.6 Plus",provider:"dashscope",isDefault:!0}],F=[{id:"codex",name:"Codex",provider:"shennian",isDefault:!0},{id:"claude",name:"Claude Code",provider:"shennian"}];async function K(r){if(!r.serverUrl||!r.authToken)return u;try{const e=await fetch(`${r.serverUrl.replace(/\/$/,"")}/api/models`,{headers:{Authorization:`Bearer ${r.authToken}`}});if(!e.ok)return u;const t=await e.json(),s=(t.models??[]).map(n=>({id:n.id,name:n.name?.trim()||n.id,provider:n.provider,isDefault:n.id===t.default}));return s.length>0?s:u}catch{return u}}async function U(r,e){switch(r){case"claude":return N();case"codex":return V();case"workbuddy":return l("workbuddy")?x():[];case"gemini":return B();case"cursor":return q();case"openclaw":return[];case"opencode":return j();case"pi":return K(e);case"pi-coding-agent":return G();case"manager":return F}}async function te(r,e){return r.type.startsWith("custom:")?r.models??[]:U(r.type,e)}export{te as discoverModelsForAgent};
1
+ import{createInterface as k}from"node:readline";import{resolveBuiltinCommand as l,spawnResolvedCommand as w}from"../command-spec.js";import{fallbackClaudeAliasModels as E,discoverClaudeAliasModelsFromEnv as x,fallbackCodexModels as M,fallbackWorkBuddyModels as R,fallbackGeminiModels as O,parseCodexAppServerModels as A,parseCursorModels as D,parseOpenCodeModels as I}from"./parsers.js";import{runResolvedCommand as m}from"./runner.js";import{DISCOVERY_WORKDIR as b,ModelDiscoveryFallbackError as C}from"./types.js";import{buildAgentProcessEnv as _,readLatestUserEnv as S}from"../../agent-env.js";import{CODEX_APP_SERVER_CLIENT_INFO as T}from"../codex-utils.js";import{PiRpcClient as P}from"../pi-rpc-client.js";import{loadConfig as $}from"../../config/index.js";import{discoverOpenCodeModelsViaApi as L}from"./opencode-api.js";function q(r){const e=r instanceof Error?r.message:"";return/timed out/i.test(e)?"app_server_timeout":/\berror\b|invalid|unsupported|unknown (?:method|field)/i.test(e)?"app_server_rpc_error":"app_server_unavailable"}function v(r,e,t,s,n,i){return r.stdin?new Promise((o,a)=>{const c=setTimeout(()=>{e.delete(t),a(new Error(`codex app-server request timed out: ${s}`))},i);e.set(t,{resolve:o,reject:a,timer:c}),r.stdin.write(`${JSON.stringify({id:t,method:s,params:n})}
2
+ `,p=>{p&&(clearTimeout(c),e.delete(t),a(p))})}):Promise.reject(new Error("codex app-server stdin unavailable"))}async function j(r){const e=w(r,["app-server","--listen","stdio://"],{cwd:b,stdio:["pipe","pipe","pipe"],env:_({NO_COLOR:"1"})}),t=new Map;let s=1;k({input:e.stdout}).on("line",i=>{if(!i.trim())return;let o;try{o=JSON.parse(i)}catch{return}if(o.id==null)return;const a=t.get(o.id);a&&(clearTimeout(a.timer),t.delete(o.id),o.error?a.reject(new Error(o.error.message||`codex app-server error ${o.error.code??""}`.trim())):a.resolve(o.result))});try{await v(e,t,s++,"initialize",{clientInfo:T,capabilities:{experimentalApi:!0}},1e4);const[i,o]=await Promise.all([v(e,t,s++,"model/list",{},15e3),v(e,t,s++,"config/read",{},15e3).catch(()=>null)]),a=typeof o=="object"&&o!==null&&"config"in o?o.config:void 0;return A({...typeof i=="object"&&i!==null?i:{},config:a})}finally{for(const[i,o]of t)clearTimeout(o.timer),o.reject(new Error("codex app-server stopped")),t.delete(i);e.kill("SIGTERM"),setTimeout(()=>e.kill("SIGKILL"),1e3).unref()}}async function F(){const r=l("cursor");if(!r)return[];const e=await m(r,["--list-models"]);return D(e.stdout)}async function G(){const r=l("opencode");if(!r)return[];const e=await L().catch(()=>[]);if(e.length>0)return e;const t=await m(r,["models"]);return I(t.stdout)}async function N(){const r={id:"shennian-dashscope/deepseek-v4-flash-0731",name:"DeepSeek V4 Flash",provider:"shennian-dashscope",isDefault:!0,supportedReasoningEfforts:["low","high","max"].map(n=>({id:n,name:n})),defaultReasoningEffort:"high"},e=l("pi-coding-agent");if(!e)return[];if($().machineToken?.trim())return[r];const t=w(e,["--mode","rpc","--no-session","--offline","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--no-tools"],{cwd:b,stdio:["pipe","pipe","pipe"],env:_({NO_COLOR:"1"})}),s=new P(t,{requestTimeoutMs:1e4});try{const[n,i]=await Promise.all([s.request("get_available_models"),s.request("get_state")]),o=n.data&&typeof n.data=="object"?n.data:{},a=i.data&&typeof i.data=="object"?i.data:{},c=typeof a.model?.id=="string"&&typeof a.model.provider=="string"?`${a.model.provider}/${a.model.id}`:null;return Array.isArray(o.models)?o.models.flatMap(f=>{if(!f||typeof f!="object")return[];const d=f;if(typeof d.id!="string"||typeof d.provider!="string")return[];const h=`${d.provider}/${d.id}`,g=d.reasoning===!0?["off","minimal","low","medium","high","xhigh","max"].map(y=>({id:y,name:y})):void 0;return[{id:h,name:typeof d.name=="string"&&d.name.trim()?d.name:d.id,provider:d.provider,isDefault:h===c,...g?{supportedReasoningEfforts:g,defaultReasoningEffort:"medium"}:{}}]}):[]}catch{return[]}finally{s.close(),t.kill("SIGTERM"),setTimeout(()=>t.kill("SIGKILL"),1e3).unref()}}async function V(){const r=l("claude");if(!r)return[];const e=S(),t=x(e);if(t.length>0)return t;const s=E(e),n=await m(r,["--help"],3e3).catch(()=>null);return!n||/\bfable\b/i.test(`${n.stdout}
3
+ ${n.stderr}`)?s:s.filter(i=>i.id!=="fable")}async function B(){const r=l("codex");if(!r)return[];let e;try{e=await j(r)}catch(t){throw new C("codex",q(t),M())}if(e.length===0)throw new C("codex","empty_model_list",M());return e}async function K(){return l("gemini")?O():[]}const u=[{id:"qwen3.6-plus",name:"Qwen 3.6 Plus",provider:"dashscope",isDefault:!0}],U=[{id:"codex",name:"Codex",provider:"shennian",isDefault:!0},{id:"claude",name:"Claude Code",provider:"shennian"}];async function W(r){if(!r.serverUrl||!r.authToken)return u;try{const e=await fetch(`${r.serverUrl.replace(/\/$/,"")}/api/models`,{headers:{Authorization:`Bearer ${r.authToken}`}});if(!e.ok)return u;const t=await e.json(),s=(t.models??[]).map(n=>({id:n.id,name:n.name?.trim()||n.id,provider:n.provider,isDefault:n.id===t.default}));return s.length>0?s:u}catch{return u}}async function z(r,e){switch(r){case"claude":return V();case"codex":return B();case"workbuddy":return l("workbuddy")?R():[];case"gemini":return K();case"cursor":return F();case"openclaw":return[];case"opencode":return G();case"pi":return W(e);case"pi-coding-agent":return N();case"manager":return U}}async function ne(r,e){return r.type.startsWith("custom:")?r.models??[]:z(r.type,e)}export{ne as discoverModelsForAgent};
@@ -1,4 +1,4 @@
1
- function b(e){return e.replace(/\u001b\[[0-9;?]*[a-zA-Z]/g,"").replace(/\u001b\][^\u0007]*\u0007/g,"").replace(/[\u0000-\u0008\u000b-\u001f\u007f]/g,"")}function m(e){const t=new Set,n=[];for(const o of e)!o.id||t.has(o.id)||(t.add(o.id),n.push(o));return n}function y(e){return e&&e[0].toUpperCase()+e.slice(1)}function x(e){return e.split("-").map(t=>t==="gpt"?"GPT":t==="codex"?"Codex":/^\d/.test(t)?t:y(t)).join("-")}function O(e){switch(e){case"low":return"Low";case"medium":return"Medium";case"high":return"High";case"xhigh":return"Extra High";default:return y(e)}}const C=[{id:"gpt-5.6-sol",name:"GPT-5.6 Sol",description:"Latest GPT-5.6 Codex model.",provider:"openai"},{id:"gpt-5.6-terra",name:"GPT-5.6 Terra",description:"Latest GPT-5.6 Codex model.",provider:"openai"},{id:"gpt-5.6-luna",name:"GPT-5.6 Luna",description:"Latest GPT-5.6 Codex model.",provider:"openai"}];function M(e){const t={...e};return e.supportedReasoningEfforts&&(t.supportedReasoningEfforts=e.supportedReasoningEfforts.map(n=>({...n}))),e.additionalSpeedTiers&&(t.additionalSpeedTiers=[...e.additionalSpeedTiers]),t}function k(e,t){const n=t??e.find(i=>i.isDefault)?.id,o=m([...e.map(M),...C.map(i=>M(i))]);return n?o.map(i=>({...i,isDefault:i.id===n})):o}function G(){return C.map((e,t)=>({...M(e),...t===0?{isDefault:!0}:{}}))}function I(){return[{id:"auto",name:"Auto",provider:"workbuddy",isDefault:!0,supportedReasoningEfforts:["minimal","low","medium","high","xhigh","max"].map(e=>({id:e,name:O(e)})),defaultReasoningEffort:"medium"}]}function w(e){return e.split("-").map(t=>/^\d/.test(t)?t:y(t)).join(" ")}function _(e,t,n=!1){const o=t.toLowerCase().replace(/\s+/g,"-");return`gemini-${e}-${o}${n?"-preview":""}`}function N(e){const t=[],n=b(e);for(const o of n.split(`
2
- `)){const i=o.trim().match(/^(\S+)\s+-\s+(.+?)(?:\s+\(([^)]+)\))?$/);if(!i)continue;const[,s,r,d]=i,l=d?.split(",").map(u=>u.trim().toLowerCase())??[];t.push({id:s,name:r.trim()||w(s),description:d?.trim(),isDefault:l.includes("default")||l.includes("current")})}return m(t)}function H(e){try{const n=(JSON.parse(e).models??[]).filter(o=>o.available).map(o=>({id:o.key,name:o.name?.trim()||o.key,provider:o.key.split("/")[0],description:o.tags?.join(", "),isDefault:o.tags?.includes("default")??!1}));return m(n)}catch{return[]}}function U(e){const t=b(e).split(`
3
- `).map(n=>n.trim()).filter(Boolean).filter(n=>!n.includes(" ")).map(n=>({id:n,name:n,provider:n.includes("/")?n.split("/")[0]:void 0}));return m(t)}function B(e,t){if(!e||typeof e!="object")return[];const n=e;if(!Array.isArray(n.all)||!Array.isArray(n.connected))return[];const o=new Set(n.connected.filter(u=>typeof u=="string")),i=t&&typeof t=="object"?t:{},s=typeof i.model=="string"?i.model:"",r=i.provider&&typeof i.provider=="object"?i.provider:{},d=new Set;for(const[u,a]of Object.entries(r)){if(!a||typeof a!="object")continue;const p=a.models;if(!(!p||typeof p!="object"))for(const f of Object.keys(p))d.add(`${u}/${f}`)}const l=[];for(const u of n.all){if(!u||typeof u!="object")continue;const a=u;if(!(typeof a.id!="string"||!o.has(a.id))&&!(!a.models||typeof a.models!="object"))for(const[p,f]of Object.entries(a.models)){if(!f||typeof f!="object")continue;const c=f;if(c.status==="deprecated"||c.status==="unavailable"||c.capabilities?.input?.text===!1||c.capabilities?.output?.text===!1||c.capabilities?.toolcall===!1)continue;const g=typeof c.id=="string"&&c.id?c.id:p,h=`${a.id}/${g}`;l.push({id:h,name:typeof c.name=="string"&&c.name.trim()?c.name:h,provider:a.id,...h===s?{isDefault:!0}:{}})}}return m(l).sort((u,a)=>{const p=f=>f.id===s?0:d.has(f.id)?1:f.provider&&Object.hasOwn(r,f.provider)?2:3;return p(u)-p(a)||u.id.localeCompare(a.id)})}function V(e){const t=b(e).replace(/\s+/g," "),n=[[/\d+\.Default\(recommended\).*?(?:Sonnet|currently\s*Sonnet)\s*([\d.]+)/i,"default","Default (recommended)"],[/\d+\.Best.*?Opus\s*([\d.]+)/i,"best","Best","Most capable available model"],[/\d+\.Fable.*?Fable\s*([\d.]+)/i,"fable","Fable","Most capable for the hardest, longest-running tasks"],[/\d+\.Opus\(1Mcontext\).*?Opus\s*([\d.]+)/i,"opus[1m]","Opus (1M context)"],[/\d+\.OpusPlan.*?Opus\s*([\d.]+)/i,"opusplan","Opus Plan","Opus for planning \xB7 Sonnet for execution"],[/\d+\.Opus(?!\(1Mcontext\)).*?Opus\s*([\d.]+)/i,"opus","Opus"],[/\d+\.Sonnet\(1Mcontext\).*?Sonnet\s*([\d.]+)/i,"sonnet[1m]","Sonnet (1M context)"],[/\d+\.Sonnet(?!\(1Mcontext\)).*?Sonnet\s*([\d.]+)/i,"sonnet","Sonnet"],[/\d+\.Haiku.*?Haiku\s*([\d.]+)/i,"haiku","Haiku"]],o=[];for(const[d,l,u,a]of n){const p=t.match(d);p&&o.push(v({id:l,name:u,description:a?`${a} \xB7 v${p[1]}`:`v${p[1]}`,provider:"anthropic",isDefault:l==="default"}))}if(o.length>0)return m(o);const i=[],s=t.match(/currently\s*(Sonnet|Opus|Haiku)\s*([34](?:\.\d)?)/i),r={sonnet:"sonnet",opus:"opus",haiku:"haiku"};for(const d of t.matchAll(/\b(Sonnet|Opus|Haiku)\s*([34](?:\.\d)?)\b/gi)){const l=(d[1]??"").toLowerCase(),u=r[l];if(!u)continue;const a=d[2]??"",p=s&&s[1]?.toLowerCase()===l&&s[2]===a;i.push(v({id:u,name:`${y(l)} ${a}`,provider:"anthropic",isDefault:!!p}))}return m(i)}function R(e,t){const n=Math.max(e.length,t.length);for(let o=0;o<n;o++){const i=e[o]??-1,s=t[o]??-1;if(i!==s)return i-s}return 0}function T(e,t){const n=e.match(new RegExp(`^claude-${t}-([0-9]+(?:-[0-9]+)*)$`,"i"));if(!n?.[1])return null;const o=n[1].split("-").map(i=>Number.parseInt(i,10)).filter(i=>Number.isFinite(i));return o.length===0||o.length>2?null:o}function $(e){if(e?.length)return`v${e.join(".")}`}const A={default:"Default (recommended)",sonnet:"Sonnet",opus:"Opus",haiku:"Haiku"},S={default:"ANTHROPIC_MODEL",sonnet:"ANTHROPIC_DEFAULT_SONNET_MODEL",opus:"ANTHROPIC_DEFAULT_OPUS_MODEL",haiku:"ANTHROPIC_DEFAULT_HAIKU_MODEL"},P=[{id:"max",name:"Max"}],j=[{id:"low",name:"Low"},{id:"medium",name:"Medium"},{id:"high",name:"High"},{id:"xhigh",name:"Extra High"},{id:"max",name:"Max"}];function v(e){return{...e,supportedReasoningEfforts:j,defaultReasoningEffort:"medium"}}function E(e,t){return e[t]?.trim()||null}function D(e,t){const n=E(t,"ANTHROPIC_BASE_URL")?.toLowerCase()??"";return n.includes("deepseek.com")||e.toLowerCase().startsWith("deepseek-")?"deepseek":n?"custom":"anthropic"}function L(e){const t=new Set;for(const o of Object.values(S)){const i=E(e,o);i&&t.add(i)}const n=Array.from(t).map((o,i)=>{const s=D(o,e),r={id:o,name:o,provider:s,isDefault:i===0};return s==="deepseek"?{...r,supportedReasoningEfforts:P,defaultReasoningEffort:E(e,"CLAUDE_CODE_EFFORT_LEVEL")??"max"}:v(r)});return m(n)}function z(e=process.env){return L(e)}function F(e,t=process.env){return e.map(n=>{if(!["default","sonnet","opus","haiku"].includes(n.id))return n;const o=n.id,i=E(t,S[o]);if(!i)return n;const r=`Claude Code alias: ${A[o]}`;return{...n,name:i,description:n.description?`${r} \xB7 ${n.description}`:r,provider:D(i,t)}})}function K(e){const t=b(e),n=new Map;for(const i of["sonnet","opus","haiku"])for(const s of t.matchAll(new RegExp(`\\bclaude-${i}-[0-9.-]+\\b`,"gi"))){const r=s[0].trim().toLowerCase().replace(/\./g,"-").replace(/-+$/g,""),d=T(r,i);if(!d)continue;const l=n.get(i);(!l||R(l,d)<0)&&n.set(i,d)}const o=[];for(const i of["default","sonnet","opus","haiku"]){if(!new RegExp(`\\b${i}\\b`,"i").test(t))continue;const s=(i==="default"?n.get("sonnet"):n.get(i))??null;o.push(v({id:i,name:A[i],description:$(s),provider:"anthropic",isDefault:i==="default"}))}return m(o)}function q(e=process.env){const t=L(e);return t.length>0?t:F([{id:"default",name:"Default (recommended)",description:"Recommended model for your account",provider:"anthropic",isDefault:!0},{id:"sonnet",name:"Sonnet",description:"Latest Sonnet \xB7 everyday coding",provider:"anthropic"},{id:"fable",name:"Fable",description:"Most capable for the hardest, longest-running tasks",provider:"anthropic"},{id:"opus",name:"Opus",description:"Latest Opus \xB7 complex reasoning",provider:"anthropic"},{id:"haiku",name:"Haiku",description:"Fast and efficient \xB7 simple tasks",provider:"anthropic"},{id:"best",name:"Best",description:"Most capable available model",provider:"anthropic"},{id:"opus[1m]",name:"Opus (1M context)",description:"Latest Opus \xB7 long sessions",provider:"anthropic"},{id:"sonnet[1m]",name:"Sonnet (1M context)",description:"Latest Sonnet \xB7 long sessions",provider:"anthropic"},{id:"opusplan",name:"Opus Plan",description:"Opus for planning \xB7 Sonnet for execution",provider:"anthropic"}],e).map(n=>n.id==="haiku"?n:v(n))}function W(e){const t=b(e),n=[];for(const o of t.split(`
4
- `)){const i=o.match(/\b(gpt-[a-z0-9][a-z0-9.-]*)\b/i);if(!i)continue;const s=i[1].trim(),r=o.replace(s,"").replace(/^[^\w]+/,"").trim()||void 0;n.push({id:s,name:x(s),description:r,provider:"openai",isDefault:/\bcurrent\b/i.test(o)||/\bselected\b/i.test(o)})}return m(n)}function J(e){const t=typeof e=="object"&&e!==null?e:{},n=typeof t.config?.model=="string"?t.config.model:void 0,o=typeof t.config?.model_reasoning_effort=="string"?t.config.model_reasoning_effort:void 0,i=[];for(const s of t.data??[]){if(typeof s!="object"||s===null)continue;const r=s,d=typeof r.id=="string"?r.id:typeof r.model=="string"?r.model:"";if(!d)continue;const l=typeof r.displayName=="string"?r.displayName:typeof r.name=="string"?r.name:void 0,u=typeof r.description=="string"?r.description:void 0,a=typeof r.defaultReasoningEffort=="string"?r.defaultReasoningEffort:void 0,p=Array.isArray(r.supportedReasoningEfforts)?r.supportedReasoningEfforts.map(c=>{if(typeof c!="object"||c===null)return null;const g=c,h=typeof g.reasoningEffort=="string"?g.reasoningEffort:typeof g.id=="string"?g.id:"";return h?{id:h,name:O(h),description:typeof g.description=="string"?g.description:void 0}:null}).filter(c=>c!=null):void 0,f=Array.isArray(r.additionalSpeedTiers)?r.additionalSpeedTiers.filter(c=>typeof c=="string"):void 0;i.push({id:d,name:l||x(d),description:u,provider:"openai",isDefault:n?n===d:r.isDefault===!0,supportedReasoningEfforts:p,defaultReasoningEffort:a,additionalSpeedTiers:f})}return n&&!i.some(s=>s.id===n)&&i.unshift({id:n,name:x(n),provider:"openai",isDefault:!0,defaultReasoningEffort:o}),k(m(i),n)}function X(e){const t=b(e),n=[];for(const o of t.matchAll(/\b(?:auto-)?gemini-[a-z0-9.-]+\b/gi)){const i=o[0].trim();n.push({id:i,name:i,provider:"google",isDefault:/\bcurrent\b/i.test(t)&&t.includes(i)})}for(const o of t.matchAll(/\bGemini\s*(\d(?:\.\d)?)\s*(Pro|Flash(?:[- ]Lite)?)\s*(Preview)?\b/gi)){const i=o[1]??"",s=(o[2]??"").replace(/\s+/g,"-"),r=!!o[3],d=_(i,s,r);n.push({id:d,name:`Gemini ${i} ${s.replace(/-/g," ")}`.trim(),provider:"google",isDefault:/\bcurrent\b/i.test(t)&&t.includes(o[0]??"")})}for(const o of t.matchAll(/\bAuto\s*Gemini\s*(\d(?:\.\d)?)\b/gi)){const i=o[1]??"",s=`auto-gemini-${i}`;n.push({id:s,name:`Auto Gemini ${i}`,provider:"google",isDefault:/\bcurrent\b/i.test(t)&&t.includes(o[0]??"")})}return m(n)}function Z(){return[{id:"gemini-2.5-pro",name:"Gemini 2.5 Pro",provider:"google",isDefault:!0},{id:"gemini-2.5-flash",name:"Gemini 2.5 Flash",provider:"google"},{id:"auto-gemini-2.5",name:"Auto Gemini 2.5",provider:"google"}]}export{F as applyClaudeModelEnvOverrides,z as discoverClaudeAliasModelsFromEnv,q as fallbackClaudeAliasModels,G as fallbackCodexModels,Z as fallbackGeminiModels,I as fallbackWorkBuddyModels,D as inferClaudeOverrideProvider,K as parseClaudeBinaryModels,V as parseClaudeModels,J as parseCodexAppServerModels,W as parseCodexModels,N as parseCursorModels,X as parseGeminiModels,H as parseOpenClawModels,U as parseOpenCodeModels,B as parseOpenCodeProviderModels,E as readEnvValue,b as stripAnsi};
1
+ function b(e){return e.replace(/\u001b\[[0-9;?]*[a-zA-Z]/g,"").replace(/\u001b\][^\u0007]*\u0007/g,"").replace(/[\u0000-\u0008\u000b-\u001f\u007f]/g,"")}function m(e){const t=new Set,n=[];for(const o of e)!o.id||t.has(o.id)||(t.add(o.id),n.push(o));return n}function y(e){return e&&e[0].toUpperCase()+e.slice(1)}function M(e){return e.split("-").map(t=>t==="gpt"?"GPT":t==="codex"?"Codex":/^\d/.test(t)?t:y(t)).join("-")}function A(e){switch(e){case"low":return"Low";case"medium":return"Medium";case"high":return"High";case"xhigh":return"Extra High";default:return y(e)}}const E=[{id:"low",name:"Low"},{id:"medium",name:"Medium"},{id:"high",name:"High"},{id:"xhigh",name:"Extra High"},{id:"max",name:"Max"},{id:"ultra",name:"Ultra"}],C=[{id:"gpt-6-astra",name:"GPT-6 Astra",description:"Most capable Codex model for complex, demanding work.",provider:"openai",supportedReasoningEfforts:E,defaultReasoningEffort:"medium"},{id:"gpt-5.6-sol",name:"GPT-5.6 Sol",description:"Reliable agentic workhorse for everyday tasks.",provider:"openai",supportedReasoningEfforts:E,defaultReasoningEffort:"low"},{id:"gpt-5.6-terra",name:"GPT-5.6 Terra",description:"Balanced agentic coding model for everyday work.",provider:"openai",supportedReasoningEfforts:E,defaultReasoningEffort:"medium"},{id:"gpt-5.6-luna",name:"GPT-5.6 Luna",description:"Fast and affordable agentic coding model.",provider:"openai",supportedReasoningEfforts:E.filter(e=>e.id!=="ultra"),defaultReasoningEffort:"medium"},{id:"gpt-5.5",name:"GPT-5.5",description:"Proven previous-generation model for coding and general work.",provider:"openai",supportedReasoningEfforts:E.filter(e=>e.id!=="max"&&e.id!=="ultra"),defaultReasoningEffort:"medium"}];function O(e){const t={...e};return e.supportedReasoningEfforts&&(t.supportedReasoningEfforts=e.supportedReasoningEfforts.map(n=>({...n}))),e.additionalSpeedTiers&&(t.additionalSpeedTiers=[...e.additionalSpeedTiers]),t}function L(e,t){const n=t??e.find(i=>i.isDefault)?.id,o=m([...e.map(O),...C.map(i=>O(i))]);return n?o.map(i=>({...i,isDefault:i.id===n})):o}function G(){return C.map((e,t)=>({...O(e),...t===0?{isDefault:!0}:{}}))}function H(){return[{id:"auto",name:"Auto",provider:"workbuddy",isDefault:!0,supportedReasoningEfforts:["minimal","low","medium","high","xhigh","max"].map(e=>({id:e,name:A(e)})),defaultReasoningEffort:"medium"}]}function w(e){return e.split("-").map(t=>/^\d/.test(t)?t:y(t)).join(" ")}function _(e,t,n=!1){const o=t.toLowerCase().replace(/\s+/g,"-");return`gemini-${e}-${o}${n?"-preview":""}`}function I(e){const t=[],n=b(e);for(const o of n.split(`
2
+ `)){const i=o.trim().match(/^(\S+)\s+-\s+(.+?)(?:\s+\(([^)]+)\))?$/);if(!i)continue;const[,s,r,d]=i,l=d?.split(",").map(u=>u.trim().toLowerCase())??[];t.push({id:s,name:r.trim()||w(s),description:d?.trim(),isDefault:l.includes("default")||l.includes("current")})}return m(t)}function U(e){try{const n=(JSON.parse(e).models??[]).filter(o=>o.available).map(o=>({id:o.key,name:o.name?.trim()||o.key,provider:o.key.split("/")[0],description:o.tags?.join(", "),isDefault:o.tags?.includes("default")??!1}));return m(n)}catch{return[]}}function B(e){const t=b(e).split(`
3
+ `).map(n=>n.trim()).filter(Boolean).filter(n=>!n.includes(" ")).map(n=>({id:n,name:n,provider:n.includes("/")?n.split("/")[0]:void 0}));return m(t)}function V(e,t){if(!e||typeof e!="object")return[];const n=e;if(!Array.isArray(n.all)||!Array.isArray(n.connected))return[];const o=new Set(n.connected.filter(u=>typeof u=="string")),i=t&&typeof t=="object"?t:{},s=typeof i.model=="string"?i.model:"",r=i.provider&&typeof i.provider=="object"?i.provider:{},d=new Set;for(const[u,a]of Object.entries(r)){if(!a||typeof a!="object")continue;const f=a.models;if(!(!f||typeof f!="object"))for(const p of Object.keys(f))d.add(`${u}/${p}`)}const l=[];for(const u of n.all){if(!u||typeof u!="object")continue;const a=u;if(!(typeof a.id!="string"||!o.has(a.id))&&!(!a.models||typeof a.models!="object"))for(const[f,p]of Object.entries(a.models)){if(!p||typeof p!="object")continue;const c=p;if(c.status==="deprecated"||c.status==="unavailable"||c.capabilities?.input?.text===!1||c.capabilities?.output?.text===!1||c.capabilities?.toolcall===!1)continue;const g=typeof c.id=="string"&&c.id?c.id:f,h=`${a.id}/${g}`;l.push({id:h,name:typeof c.name=="string"&&c.name.trim()?c.name:h,provider:a.id,...h===s?{isDefault:!0}:{}})}}return m(l).sort((u,a)=>{const f=p=>p.id===s?0:d.has(p.id)?1:p.provider&&Object.hasOwn(r,p.provider)?2:3;return f(u)-f(a)||u.id.localeCompare(a.id)})}function z(e){const t=b(e).replace(/\s+/g," "),n=[[/\d+\.Default\(recommended\).*?(?:Sonnet|currently\s*Sonnet)\s*([\d.]+)/i,"default","Default (recommended)"],[/\d+\.Best.*?Opus\s*([\d.]+)/i,"best","Best","Most capable available model"],[/\d+\.Fable.*?Fable\s*([\d.]+)/i,"fable","Fable","Most capable for the hardest, longest-running tasks"],[/\d+\.Opus\(1Mcontext\).*?Opus\s*([\d.]+)/i,"opus[1m]","Opus (1M context)"],[/\d+\.OpusPlan.*?Opus\s*([\d.]+)/i,"opusplan","Opus Plan","Opus for planning \xB7 Sonnet for execution"],[/\d+\.Opus(?!\(1Mcontext\)).*?Opus\s*([\d.]+)/i,"opus","Opus"],[/\d+\.Sonnet\(1Mcontext\).*?Sonnet\s*([\d.]+)/i,"sonnet[1m]","Sonnet (1M context)"],[/\d+\.Sonnet(?!\(1Mcontext\)).*?Sonnet\s*([\d.]+)/i,"sonnet","Sonnet"],[/\d+\.Haiku.*?Haiku\s*([\d.]+)/i,"haiku","Haiku"]],o=[];for(const[d,l,u,a]of n){const f=t.match(d);f&&o.push(v({id:l,name:u,description:a?`${a} \xB7 v${f[1]}`:`v${f[1]}`,provider:"anthropic",isDefault:l==="default"}))}if(o.length>0)return m(o);const i=[],s=t.match(/currently\s*(Sonnet|Opus|Haiku)\s*([34](?:\.\d)?)/i),r={sonnet:"sonnet",opus:"opus",haiku:"haiku"};for(const d of t.matchAll(/\b(Sonnet|Opus|Haiku)\s*([34](?:\.\d)?)\b/gi)){const l=(d[1]??"").toLowerCase(),u=r[l];if(!u)continue;const a=d[2]??"",f=s&&s[1]?.toLowerCase()===l&&s[2]===a;i.push(v({id:u,name:`${y(l)} ${a}`,provider:"anthropic",isDefault:!!f}))}return m(i)}function T(e,t){const n=Math.max(e.length,t.length);for(let o=0;o<n;o++){const i=e[o]??-1,s=t[o]??-1;if(i!==s)return i-s}return 0}function $(e,t){const n=e.match(new RegExp(`^claude-${t}-([0-9]+(?:-[0-9]+)*)$`,"i"));if(!n?.[1])return null;const o=n[1].split("-").map(i=>Number.parseInt(i,10)).filter(i=>Number.isFinite(i));return o.length===0||o.length>2?null:o}function F(e){if(e?.length)return`v${e.join(".")}`}const S={default:"Default (recommended)",sonnet:"Sonnet",opus:"Opus",haiku:"Haiku"},D={default:"ANTHROPIC_MODEL",sonnet:"ANTHROPIC_DEFAULT_SONNET_MODEL",opus:"ANTHROPIC_DEFAULT_OPUS_MODEL",haiku:"ANTHROPIC_DEFAULT_HAIKU_MODEL"},P=[{id:"max",name:"Max"}],j=[{id:"low",name:"Low"},{id:"medium",name:"Medium"},{id:"high",name:"High"},{id:"xhigh",name:"Extra High"},{id:"max",name:"Max"}];function v(e){return{...e,supportedReasoningEfforts:j,defaultReasoningEffort:"medium"}}function x(e,t){return e[t]?.trim()||null}function R(e,t){const n=x(t,"ANTHROPIC_BASE_URL")?.toLowerCase()??"";return n.includes("deepseek.com")||e.toLowerCase().startsWith("deepseek-")?"deepseek":n?"custom":"anthropic"}function k(e){const t=new Set;for(const o of Object.values(D)){const i=x(e,o);i&&t.add(i)}const n=Array.from(t).map((o,i)=>{const s=R(o,e),r={id:o,name:o,provider:s,isDefault:i===0};return s==="deepseek"?{...r,supportedReasoningEfforts:P,defaultReasoningEffort:x(e,"CLAUDE_CODE_EFFORT_LEVEL")??"max"}:v(r)});return m(n)}function K(e=process.env){return k(e)}function N(e,t=process.env){return e.map(n=>{if(!["default","sonnet","opus","haiku"].includes(n.id))return n;const o=n.id,i=x(t,D[o]);if(!i)return n;const r=`Claude Code alias: ${S[o]}`;return{...n,name:i,description:n.description?`${r} \xB7 ${n.description}`:r,provider:R(i,t)}})}function q(e){const t=b(e),n=new Map;for(const i of["sonnet","opus","haiku"])for(const s of t.matchAll(new RegExp(`\\bclaude-${i}-[0-9.-]+\\b`,"gi"))){const r=s[0].trim().toLowerCase().replace(/\./g,"-").replace(/-+$/g,""),d=$(r,i);if(!d)continue;const l=n.get(i);(!l||T(l,d)<0)&&n.set(i,d)}const o=[];for(const i of["default","sonnet","opus","haiku"]){if(!new RegExp(`\\b${i}\\b`,"i").test(t))continue;const s=(i==="default"?n.get("sonnet"):n.get(i))??null;o.push(v({id:i,name:S[i],description:F(s),provider:"anthropic",isDefault:i==="default"}))}return m(o)}function W(e=process.env){const t=k(e);return t.length>0?t:N([{id:"default",name:"Default (recommended)",description:"Recommended model for your account",provider:"anthropic",isDefault:!0},{id:"sonnet",name:"Sonnet",description:"Latest Sonnet \xB7 everyday coding",provider:"anthropic"},{id:"fable",name:"Fable",description:"Most capable for the hardest, longest-running tasks",provider:"anthropic"},{id:"opus",name:"Opus",description:"Latest Opus \xB7 complex reasoning",provider:"anthropic"},{id:"haiku",name:"Haiku",description:"Fast and efficient \xB7 simple tasks",provider:"anthropic"},{id:"best",name:"Best",description:"Most capable available model",provider:"anthropic"},{id:"opus[1m]",name:"Opus (1M context)",description:"Latest Opus \xB7 long sessions",provider:"anthropic"},{id:"sonnet[1m]",name:"Sonnet (1M context)",description:"Latest Sonnet \xB7 long sessions",provider:"anthropic"},{id:"opusplan",name:"Opus Plan",description:"Opus for planning \xB7 Sonnet for execution",provider:"anthropic"}],e).map(n=>n.id==="haiku"?n:v(n))}function X(e){const t=b(e),n=[];for(const o of t.split(`
4
+ `)){const i=o.match(/\b(gpt-[a-z0-9][a-z0-9.-]*)\b/i);if(!i)continue;const s=i[1].trim(),r=o.replace(s,"").replace(/^[^\w]+/,"").trim()||void 0;n.push({id:s,name:M(s),description:r,provider:"openai",isDefault:/\bcurrent\b/i.test(o)||/\bselected\b/i.test(o)})}return m(n)}function J(e){const t=typeof e=="object"&&e!==null?e:{},n=typeof t.config?.model=="string"?t.config.model:void 0,o=typeof t.config?.model_reasoning_effort=="string"?t.config.model_reasoning_effort:void 0,i=[];for(const s of t.data??[]){if(typeof s!="object"||s===null)continue;const r=s,d=typeof r.id=="string"?r.id:typeof r.model=="string"?r.model:"";if(!d)continue;const l=typeof r.displayName=="string"?r.displayName:typeof r.name=="string"?r.name:void 0,u=typeof r.description=="string"?r.description:void 0,a=typeof r.defaultReasoningEffort=="string"?r.defaultReasoningEffort:void 0,f=Array.isArray(r.supportedReasoningEfforts)?r.supportedReasoningEfforts.map(c=>{if(typeof c!="object"||c===null)return null;const g=c,h=typeof g.reasoningEffort=="string"?g.reasoningEffort:typeof g.id=="string"?g.id:"";return h?{id:h,name:A(h),description:typeof g.description=="string"?g.description:void 0}:null}).filter(c=>c!=null):void 0,p=Array.isArray(r.additionalSpeedTiers)?r.additionalSpeedTiers.filter(c=>typeof c=="string"):void 0;i.push({id:d,name:l||M(d),description:u,provider:"openai",isDefault:n?n===d:r.isDefault===!0,supportedReasoningEfforts:f,defaultReasoningEffort:a,additionalSpeedTiers:p})}return n&&!i.some(s=>s.id===n)&&i.unshift({id:n,name:M(n),provider:"openai",isDefault:!0,defaultReasoningEffort:o}),L(m(i),n)}function Z(e){const t=b(e),n=[];for(const o of t.matchAll(/\b(?:auto-)?gemini-[a-z0-9.-]+\b/gi)){const i=o[0].trim();n.push({id:i,name:i,provider:"google",isDefault:/\bcurrent\b/i.test(t)&&t.includes(i)})}for(const o of t.matchAll(/\bGemini\s*(\d(?:\.\d)?)\s*(Pro|Flash(?:[- ]Lite)?)\s*(Preview)?\b/gi)){const i=o[1]??"",s=(o[2]??"").replace(/\s+/g,"-"),r=!!o[3],d=_(i,s,r);n.push({id:d,name:`Gemini ${i} ${s.replace(/-/g," ")}`.trim(),provider:"google",isDefault:/\bcurrent\b/i.test(t)&&t.includes(o[0]??"")})}for(const o of t.matchAll(/\bAuto\s*Gemini\s*(\d(?:\.\d)?)\b/gi)){const i=o[1]??"",s=`auto-gemini-${i}`;n.push({id:s,name:`Auto Gemini ${i}`,provider:"google",isDefault:/\bcurrent\b/i.test(t)&&t.includes(o[0]??"")})}return m(n)}function Q(){return[{id:"gemini-2.5-pro",name:"Gemini 2.5 Pro",provider:"google",isDefault:!0},{id:"gemini-2.5-flash",name:"Gemini 2.5 Flash",provider:"google"},{id:"auto-gemini-2.5",name:"Auto Gemini 2.5",provider:"google"}]}export{N as applyClaudeModelEnvOverrides,K as discoverClaudeAliasModelsFromEnv,W as fallbackClaudeAliasModels,G as fallbackCodexModels,Q as fallbackGeminiModels,H as fallbackWorkBuddyModels,R as inferClaudeOverrideProvider,q as parseClaudeBinaryModels,z as parseClaudeModels,J as parseCodexAppServerModels,X as parseCodexModels,I as parseCursorModels,Z as parseGeminiModels,U as parseOpenClawModels,B as parseOpenCodeModels,V as parseOpenCodeProviderModels,x as readEnvValue,b as stripAnsi};
@@ -1,6 +1,10 @@
1
1
  import type { AgentInfo } from '@shennian/wire';
2
2
  import type { DetectedAgent } from '../detect.js';
3
- import type { DiscoveryContext } from './types.js';
3
+ import { type DiscoveryContext } from './types.js';
4
+ type ResolveAgentInfoOptions = {
5
+ forceRefresh?: boolean;
6
+ };
4
7
  export declare function getCachedAgentInfos(detectedAgents: DetectedAgent[]): AgentInfo[];
5
8
  export declare function refreshAgentInfos(detectedAgents: DetectedAgent[], context: DiscoveryContext): Promise<AgentInfo[]>;
6
- export declare function resolveAgentInfos(detectedAgents: DetectedAgent[], context: DiscoveryContext): Promise<AgentInfo[]>;
9
+ export declare function resolveAgentInfos(detectedAgents: DetectedAgent[], context: DiscoveryContext, options?: ResolveAgentInfoOptions): Promise<AgentInfo[]>;
10
+ export {};
@@ -1 +1 @@
1
- import{getAgentConfigSummary as m}from"../config-status.js";import{isCacheFresh as g,readCache as l,writeCache as y}from"./cache.js";import{discoverModelsForAgent as A}from"./discovery.js";import{getAgentRuntimeSummary as f}from"../runtime-compatibility.js";import{resolveManagedAgentRuntimeProtection as C}from"../../security/managed-agent-runtime.js";const M={claude:"claude-alias-v2",opencode:"opencode-connected-v1"};function S(o){const s=new Set,e=[];for(const i of o)!i.id||s.has(i.id)||(s.add(i.id),e.push(i));return e}function v(o){const s=o.type!=="pi"&&o.type!=="openclaw",e=s&&!o.type.startsWith("acp:"),i=s?C({agentType:o.type,runtimeVersion:o.version,platform:o.runtimePlatform,isWsl:o.runtimeIsWsl,executableFingerprint:o.executableFingerprint,requireExecutableFingerprint:!0}):null;return{supportsManagedAgent:e&&(i?.level==="hard"||i?.level==="partial"),supportsManagedNativeFull:s,supportsWorker:o.type!=="pi"&&o.type!=="openclaw"&&!o.type.startsWith("acp:"),supportsManagerMode:o.type==="codex"||o.type==="claude"||o.type==="pi-coding-agent",...i?{managedAgentProtection:i}:{}}}function E(o){const s=l();return o.map(e=>{const i=m(e.type),n=f(e);return{type:e.type,models:s.agents[e.type]?.models??e.models??[],...e.integration?{integration:e.integration}:{},...e.display?{display:e.display}:{},...e.acpCapabilities?{acpCapabilities:e.acpCapabilities}:{},...e.authState?{authState:e.authState}:{},...e.acpAuthMethods?{acpAuthMethods:e.acpAuthMethods}:{},...e.catalogRevision?{catalogRevision:e.catalogRevision}:{},...v(e),...i?{config:i}:{},...n?{runtime:n}:{}}})}async function O(o,s){const e=l();for(const i of o)delete e.agents[i.type];return y(e),R(o,s)}async function R(o,s){const e=l();let i=!1;const n=[];for(const t of o){const a=e.agents[t.type],p=M[t.type];let r;if(g(a,t.version,p))r=a.models;else{let c=null;try{c=S(await A(t,s)),r=c.length>0?c:a?.models??t.models??[]}catch{r=a?.models??t.models??[]}if(c&&c.length>0){const h={version:t.version,...p?{sourceRevision:p}:{},refreshedAt:Date.now(),models:r};JSON.stringify(a)!==JSON.stringify(h)&&(e.agents[t.type]=h,i=!0)}}const u=m(t.type),d=f(t);n.push({type:t.type,models:r,...t.integration?{integration:t.integration}:{},...t.display?{display:t.display}:{},...t.acpCapabilities?{acpCapabilities:t.acpCapabilities}:{},...t.authState?{authState:t.authState}:{},...t.acpAuthMethods?{acpAuthMethods:t.acpAuthMethods}:{},...t.catalogRevision?{catalogRevision:t.catalogRevision}:{},...v(t),...u?{config:u}:{},...d?{runtime:d}:{}})}return i&&y(e),n}export{E as getCachedAgentInfos,O as refreshAgentInfos,R as resolveAgentInfos};
1
+ import{getAgentConfigSummary as y}from"../config-status.js";import{isCacheFresh as A,readCache as v,writeCache as S}from"./cache.js";import{discoverModelsForAgent as M}from"./discovery.js";import{ModelDiscoveryFallbackError as R}from"./types.js";import{getAgentRuntimeSummary as g}from"../runtime-compatibility.js";import{resolveManagedAgentRuntimeProtection as b}from"../../security/managed-agent-runtime.js";const x={claude:"claude-alias-v2",codex:"codex-app-server-v2",opencode:"opencode-connected-v1"};function F(o,s,e){console.warn(`[model-discovery] agent=${o} source=fallback reason=${s} usedCache=${e}`)}function E(o){const s=new Set,e=[];for(const i of o)!i.id||s.has(i.id)||(s.add(i.id),e.push(i));return e}function C(o){const s=o.type!=="manager"&&o.type!=="pi"&&o.type!=="openclaw",e=s,i=e&&!o.type.startsWith("acp:"),r=e?b({agentType:o.type,runtimeVersion:o.version,platform:o.runtimePlatform,isWsl:o.runtimeIsWsl,executableFingerprint:o.executableFingerprint,requireExecutableFingerprint:!0}):null,p=i&&(r?.level==="hard"||r?.level==="partial"),t=e,n=p||t,a=s;return{supportsStandardSession:s,supportsManagedAgent:p,supportsManagedNativeFull:t,supportsRoomTools:n,supportsWorker:a,supportsManagerMode:n&&a,supportsExternalWorkerTarget:a,...r?{managedAgentProtection:r}:{}}}function q(o){const s=v();return o.map(e=>{const i=y(e.type),r=g(e);return{type:e.type,models:s.agents[e.type]?.models??e.models??[],...e.integration?{integration:e.integration}:{},...e.display?{display:e.display}:{},...e.acpCapabilities?{acpCapabilities:e.acpCapabilities}:{},...e.authState?{authState:e.authState}:{},...e.acpAuthMethods?{acpAuthMethods:e.acpAuthMethods}:{},...e.catalogRevision?{catalogRevision:e.catalogRevision}:{},...C(e),...i?{config:i}:{},...r?{runtime:r}:{}}})}async function P(o,s){return I(o,s,{forceRefresh:!0})}async function I(o,s,e={}){const i=v();let r=!1;const p=[];for(const t of o){const n=i.agents[t.type],a=x[t.type],u=n&&(!a||n.sourceRevision===a)?n:void 0;let c;if(!e.forceRefresh&&A(n,t.version,a))c=n.models;else{let d=null;try{d=E(await M(t,s)),c=d.length>0?d:u?.models??t.models??[]}catch(l){if(l instanceof R){const m=!!u?.models.length;c=m?u.models:l.fallbackModels,F(t.type,l.failureCode,m)}else c=u?.models??t.models??[]}if(d&&d.length>0){const l={version:t.version,...a?{sourceRevision:a}:{},refreshedAt:Date.now(),models:c};JSON.stringify(n)!==JSON.stringify(l)&&(i.agents[t.type]=l,r=!0)}}const f=y(t.type),h=g(t);p.push({type:t.type,models:c,...t.integration?{integration:t.integration}:{},...t.display?{display:t.display}:{},...t.acpCapabilities?{acpCapabilities:t.acpCapabilities}:{},...t.authState?{authState:t.authState}:{},...t.acpAuthMethods?{acpAuthMethods:t.acpAuthMethods}:{},...t.catalogRevision?{catalogRevision:t.catalogRevision}:{},...C(t),...f?{config:f}:{},...h?{runtime:h}:{}})}return r&&S(i),p}export{q as getCachedAgentInfos,P as refreshAgentInfos,I as resolveAgentInfos};
@@ -1,4 +1,4 @@
1
- import type { ModelInfo } from '@shennian/wire';
1
+ import type { BuiltinAgentType, ModelInfo } from '@shennian/wire';
2
2
  export declare const CACHE_VERSION = 1;
3
3
  export declare const CACHE_TTL_MS: number;
4
4
  export declare const MODEL_CACHE_PATH: string;
@@ -17,6 +17,14 @@ export type DiscoveryContext = {
17
17
  serverUrl?: string;
18
18
  authToken?: string;
19
19
  };
20
+ export type ModelDiscoveryFailureCode = 'app_server_unavailable' | 'app_server_timeout' | 'app_server_rpc_error' | 'empty_model_list';
21
+ /** An emergency list that is safe to display but must never become authoritative cache data. */
22
+ export declare class ModelDiscoveryFallbackError extends Error {
23
+ readonly agentType: BuiltinAgentType;
24
+ readonly failureCode: ModelDiscoveryFailureCode;
25
+ readonly fallbackModels: ModelInfo[];
26
+ constructor(agentType: BuiltinAgentType, failureCode: ModelDiscoveryFailureCode, fallbackModels: ModelInfo[]);
27
+ }
20
28
  export type PtyOptions = {
21
29
  startupArgs?: string[];
22
30
  readyPatterns: RegExp[];
@@ -1 +1 @@
1
- import o from"node:os";import{resolveShennianPath as t}from"../../config/index.js";const n=1,p=1440*60*1e3,s=t("model-cache.json"),C=o.tmpdir();export{p as CACHE_TTL_MS,n as CACHE_VERSION,C as DISCOVERY_WORKDIR,s as MODEL_CACHE_PATH};
1
+ import s from"node:os";import{resolveShennianPath as t}from"../../config/index.js";const i=1,n=1440*60*1e3,d=t("model-cache.json"),p=s.tmpdir();class E extends Error{agentType;failureCode;fallbackModels;constructor(o,r,e){super(`Model discovery fell back for ${o}: ${r}`),this.agentType=o,this.failureCode=r,this.fallbackModels=e,this.name="ModelDiscoveryFallbackError"}}export{n as CACHE_TTL_MS,i as CACHE_VERSION,p as DISCOVERY_WORKDIR,d as MODEL_CACHE_PATH,E as ModelDiscoveryFallbackError};
@@ -1,2 +1,2 @@
1
- import{callDaemonIpc as a}from"../daemon-ipc/client.js";import{DaemonIpcError as r}from"../daemon-ipc/protocol.js";const s={method_not_found:"Update the existing Shennian installation: Desktop through Desktop updates, standalone CLI through its own update flow. Do not install a second Client.",daemon_unavailable:"Check shennian status --json on the target computer. Do not resume an intentional pause without the user requesting it.",daemon_paused:"Shennian is paused. Ask the user to resume it before checking.",ipc_timeout:"The result is unknown. Check the target machine and wait for the current check to finish; do not repeatedly send tests.",agent_check_in_progress:"Wait for the running check to finish before trying again.",agent_validation_runtime_unavailable:"Refresh discovery. If the tool is still missing, guide the user through its official installation on this computer.",agent_validation_runtime_auth_required:"Guide the user through the provider\u2019s own sign-in on this computer, then retry the selected AI and model.",agent_validation_model_unavailable:"Choose a model returned by discovery and check the provider account\u2019s model access.",agent_validation_quota_exceeded:"Check the provider account\u2019s credits, subscription or rate limit before another test.",agent_validation_network_failed:"Check the target computer\u2019s connection to the provider, then retry when it is available."};async function c(t,i,n=a){try{const e=await n({method:t,params:i,timeoutMs:9e4});if(t==="agent.check"&&(!e||typeof e!="object"||Array.isArray(e)||e.ready!==!0))throw new r("agent_check_invalid_response","The daemon did not confirm a successful hello reply.");return{ok:!0,command:t,result:e}}catch(e){const o=e instanceof r?e.code:"agent_check_failed";return{ok:!1,command:t,error:o,nextAction:s[o]??"Return to the AI preparation guide on this machine. Check the selected directory, account, model and network; do not reinstall by default."}}}function h(t){const i=async(n,e)=>{const o=await c(n,e);process.stdout.write(`${JSON.stringify(o)}
2
- `),o.ok||(process.exitCode=1)};t.command("discover").description("Refresh AI discovery and sign-in summaries on the running local daemon; no model requests").option("--json","Print JSON (default)").action(()=>i("agent.discover")),t.command("check <agentType>").description("Send one hello test using the selected AI and model; uses provider quota, creates no managed Agent or room").requiredOption("--workdir <path>","Absolute project directory on this machine").option("--model <id>","Model returned by discovery; otherwise use the provider default").option("--json","Print JSON (default)").action((n,e)=>i("agent.check",{agentType:n,workDir:e.workdir,modelId:e.model??null}))}export{c as executeAgentReadinessCommand,h as registerAgentReadinessCommands};
1
+ import{callDaemonIpc as a}from"../daemon-ipc/client.js";import{DaemonIpcError as r}from"../daemon-ipc/protocol.js";const s={method_not_found:"Update the existing Shennian installation: Desktop through Desktop updates, standalone CLI through its own update flow. Do not install a second Client.",daemon_unavailable:"Check shennian status --json on the target computer. Do not resume an intentional pause without the user requesting it.",daemon_paused:"Shennian is paused. Ask the user to resume it before checking.",ipc_timeout:"The result is unknown. Check the target machine and wait for the current check to finish; do not repeatedly send tests.",agent_check_in_progress:"Wait for the running check to finish before trying again.",agent_validation_runtime_unavailable:"Refresh discovery. If the tool is still missing, guide the user through its official installation on this computer.",agent_validation_runtime_auth_required:"Guide the user through the provider\u2019s own sign-in on this computer, then retry the selected AI and model.",agent_validation_model_unavailable:"Choose a model returned by discovery and check the provider account\u2019s model access.",agent_validation_quota_exceeded:"Check the provider account\u2019s credits, subscription or rate limit before another test.",agent_validation_network_failed:"Check the target computer\u2019s connection to the provider, then retry when it is available."};async function c(n,i,t=a){try{const e=await t({method:n,params:i,timeoutMs:9e4});if(n==="agent.check"&&(!e||typeof e!="object"||Array.isArray(e)||e.ready!==!0))throw new r("agent_check_invalid_response","The daemon did not confirm a successful hello reply.");return{ok:!0,command:n,result:e}}catch(e){const o=e instanceof r?e.code:"agent_check_failed";return{ok:!1,command:n,error:o,nextAction:s[o]??"Return to the AI preparation guide on this machine. Check the selected directory, account, model and network; do not reinstall by default."}}}function l(n){const i=async(t,e)=>{const o=await c(t,e);process.stdout.write(`${JSON.stringify(o)}
2
+ `),o.ok||(process.exitCode=1)};n.command("discover").description("Refresh AI discovery and sign-in summaries on the running local daemon; no model requests").option("--agent <type>","Return only one discovered Agent type").option("--compact","Return capability summary without the full model list").option("--json","Print JSON (default)").action(t=>i("agent.discover",{...t.agent?{agentType:t.agent}:{},compact:t.compact===!0})),n.command("check <agentType>").description("Send one hello test using the selected AI and model; uses provider quota, creates no managed Agent or room").requiredOption("--workdir <path>","Absolute project directory on this machine").option("--model <id>","Model returned by discovery; otherwise use the provider default").option("--json","Print JSON (default)").action((t,e)=>i("agent.check",{agentType:t,workDir:e.workdir,modelId:e.model??null}))}export{c as executeAgentReadinessCommand,l as registerAgentReadinessCommands};
@@ -1 +1 @@
1
- import l from"node:fs";import g from"node:path";import{resolveShennianPath as f}from"../config/index.js";import{callDaemonIpc as h}from"../daemon-ipc/client.js";import{DaemonIpcError as w}from"../daemon-ipc/protocol.js";import{MANAGED_ROOM_IPC_ROOT_ENV as I,resolveManagedRoomIpcPaths as k}from"../daemon-ipc/paths.js";import{MANAGED_ROOM_CONTEXT_ENV as S}from"../room/managed-context.js";function y(){const o=process.env.CODEX_SESSION_ID?.trim()||process.env.CODEX_THREAD_ID?.trim();if(o)return{host:"codex",hostSessionId:o};const t=process.env.CLAUDE_CODE_SESSION_ID?.trim()||process.env.CLAUDE_SESSION_ID?.trim();return t?{host:"claude",hostSessionId:t}:null}function O(){const o=f("runtime","manager-ipc.json"),t=l.statSync(o);if(process.platform!=="win32"){const e=typeof process.getuid=="function"?process.getuid():t.uid;if(t.uid!==e||(t.mode&63)!==0)throw new Error("Shennian daemon Manager runtime file has unsafe permissions")}const n=JSON.parse(l.readFileSync(o,"utf-8")),i=typeof n.url=="string"?n.url:"",r=typeof n.token=="string"?n.token:"";if(!/^http:\/\/127\.0\.0\.1:\d+$/.test(i)||!r)throw new Error("Shennian daemon Manager runtime is unavailable");return{url:i,token:r}}async function N(){const o=process.env.SHENNIAN_MANAGER_IPC_URL,t=process.env.SHENNIAN_MANAGER_IPC_TOKEN,n=process.env.SHENNIAN_MANAGER_SESSION_ID;if(o&&t&&n)return{url:o,token:t,managerSessionId:n};const i=y();if(!i)throw new Error("This command requires a Shennian Manager session or a current Codex/Claude Code conversation.");const r=O(),e=await fetch(`${r.url}/skill/context`,{method:"POST",headers:{authorization:`Bearer ${r.token}`,"content-type":"application/json"},body:JSON.stringify({...i,workDir:process.cwd()})}),s=await e.json().catch(()=>({ok:!1,error:e.statusText}));if(!e.ok||!s.ok||typeof s.managerSessionId!="string")throw new Error(s.error||"Unable to establish the native Agent controller context");return{...r,managerSessionId:s.managerSessionId}}async function d(o,t){const n=process.env[S]?.trim();if(n){const s=M[o];if(!s)throw new Error(`Manager IPC path is unavailable in managed Room context: ${o}`);const a=process.env[I]?.trim();if(!a||!_(a))throw new w("managed_room_context_unavailable","Managed Room IPC context is unavailable.");return await h({method:"managed-room.execute",params:{context:n,action:s,...t},paths:k(a),timeoutMs:s==="manager.sessions.start"||s==="manager.sessions.send"?18e4:15e3})}const i=await N(),r=await fetch(`${i.url}${o}`,{method:"POST",headers:{authorization:`Bearer ${i.token}`,"content-type":"application/json","x-shennian-manager-session-id":i.managerSessionId},body:JSON.stringify({...t,managerSessionId:i.managerSessionId})}),e=await r.json().catch(()=>({ok:!1,error:r.statusText}));if(!r.ok||!e.ok)throw new Error(e.error||`Manager IPC failed: ${r.status}`);return e}const M={"/sessions/list":"manager.sessions.list","/sessions/start":"manager.sessions.start","/sessions/send":"manager.sessions.send","/sessions/queue":"manager.sessions.queue","/sessions/queue/edit":"manager.sessions.queue.edit","/sessions/queue/delete":"manager.sessions.queue.delete","/sessions/stop":"manager.sessions.stop","/sessions/read":"manager.sessions.read","/memory/path":"manager.memory.path"};function _(o){return g.isAbsolute(o)}function c(o){console.log(JSON.stringify(o,null,2))}function u(o){console.log(typeof o.markdown=="string"?o.markdown:"ok")}function p(o){return o.messageFile?l.readFileSync(o.messageFile,"utf-8"):o.message??""}function D(o){const t=o.command("manager",{hidden:!0}).description("Manager Session local tools"),n=t.command("sessions").description("Manage same-project worker sessions");n.command("list").description("List same-project sessions visible to this Manager").option("--json","Print JSON").action(async e=>{const s=await d("/sessions/list",{});if(e.json)c(s);else{const a=s.sessions??[];for(const m of a)console.log(`${m.sessionId} ${m.agentType} ${m.role??""} ${m.status} ${m.title??m.summary??""}`)}}),n.command("start").description("Start a worker session in the same project").requiredOption("--agent <agent>","Worker agent type, e.g. codex, claude, cursor, opencode, pi, or custom:<name>").requiredOption("--workdir <path>","Worker workdir; must match Manager workdir").option("--title <title>","Short worker title").option("--model <model>","Worker model id").option("--message <text>","Worker prompt").option("--message-file <path>","Read worker prompt from file").option("--json","Print JSON").action(async e=>{const s=await d("/sessions/start",{agentType:e.agent,workDir:e.workdir,title:e.title,modelId:e.model,message:p(e)});e.json?c(s):u(s)}),n.command("send").description("Queue a message for a managed worker; runs immediately if idle").requiredOption("--session-id <id>","Worker session id").option("--message <text>","Message text").option("--message-file <path>","Read message from file").option("--direct","Deprecated compatibility flag; delivery still uses the durable queue").action(async e=>{const s=await d("/sessions/send",{sessionId:e.sessionId,message:p(e),enqueue:!e.direct});u(s)});const i=n.command("queue").description("Inspect and edit pending worker messages");i.command("list").description("List pending messages for a managed worker").requiredOption("--session-id <id>","Worker session id").option("--json","Print JSON").action(async e=>{const s=await d("/sessions/queue",{sessionId:e.sessionId});if(e.json)c(s);else{const a=s.queue?.pending??[];for(const m of a)console.log(`${m.id} ${m.text.replace(/\s+/g," ").slice(0,120)}`)}}),i.command("edit").description("Edit a pending worker message").requiredOption("--session-id <id>","Worker session id").requiredOption("--message-id <id>","Queued message id").option("--message <text>","Replacement message text").option("--message-file <path>","Read replacement message from file").action(async e=>{await d("/sessions/queue/edit",{sessionId:e.sessionId,queueMessageId:e.messageId,message:p(e)}),console.log("ok")}),i.command("delete").description("Delete a pending worker message").requiredOption("--session-id <id>","Worker session id").requiredOption("--message-id <id>","Queued message id").action(async e=>{await d("/sessions/queue/delete",{sessionId:e.sessionId,queueMessageId:e.messageId}),console.log("ok")});const r=async e=>{const s=await d("/sessions/stop",{sessionId:e.sessionId});u(s)};n.command("stop").aliases(["terminate","kill"]).description("Stop or terminate a running managed worker").requiredOption("--session-id <id>","Worker session id").action(r),n.command("read").description("Read a managed worker transcript").requiredOption("--session-id <id>","Worker session id").option("--limit <n>","Message limit","200").option("--json","Print JSON").action(async e=>{const s=await d("/sessions/read",{sessionId:e.sessionId,limit:Number(e.limit)});e.json?c(s):c(s.messages??[])}),n.command("wait").description("Wait up to a bounded timeout for the next worker progress or terminal event").requiredOption("--session-id <id>","Worker session id").option("--timeout <seconds>","Maximum wait in seconds (1-600)","600").option("--json","Print JSON").action(async e=>{const s=Math.max(1,Math.min(Number(e.timeout)||600,600)),a=await d("/sessions/wait",{sessionId:e.sessionId,timeoutMs:s*1e3});e.json?c(a):a.timedOut?console.log(`\u7B49\u5F85\u8D85\u65F6\uFF1BAgent \u5F53\u524D\u72B6\u6001\uFF1A${String(a.status||"unknown")}`):u(a)}),t.command("memory").description("Manager project memory helpers").command("path").description("Print project memory directory path").action(async()=>{const e=await d("/memory/path",{});console.log(e.path)})}export{D as registerManagerCommand};
1
+ import g from"node:fs";import p from"node:path";import{callDaemonIpc as f}from"../daemon-ipc/client.js";import{DaemonIpcError as w}from"../daemon-ipc/protocol.js";import{MANAGED_ROOM_IPC_ROOT_ENV as k,resolveManagedRoomIpcPaths as I}from"../daemon-ipc/paths.js";import{MANAGED_ROOM_CONTEXT_ENV as h}from"../room/managed-context.js";async function y(){const o=process.env.SHENNIAN_MANAGER_IPC_URL,r=process.env.SHENNIAN_MANAGER_IPC_TOKEN,n=process.env.SHENNIAN_MANAGER_SESSION_ID;if(o&&r&&n)return{url:o,token:r,managerSessionId:n};throw new Error("manager_context_required: this command is only available inside a Shennian managed Manager session")}async function t(o,r){const n=process.env[h]?.trim();if(n){const s=M[o];if(!s)throw new Error(`Manager IPC path is unavailable in managed Room context: ${o}`);const i=process.env[k]?.trim();if(!i||!N(i))throw new w("managed_room_context_unavailable","Managed Room IPC context is unavailable.");return await f({method:"managed-room.execute",params:{context:n,action:s,...r},paths:I(i),timeoutMs:s==="manager.sessions.start"||s==="manager.sessions.send"?18e4:15e3})}const d=await y(),m=await fetch(`${d.url}${o}`,{method:"POST",headers:{authorization:`Bearer ${d.token}`,"content-type":"application/json","x-shennian-manager-session-id":d.managerSessionId},body:JSON.stringify({...r,managerSessionId:d.managerSessionId})}),e=await m.json().catch(()=>({ok:!1,error:m.statusText}));if(!m.ok||!e.ok)throw new Error(e.error||`Manager IPC failed: ${m.status}`);return e}const M={"/sessions/list":"manager.sessions.list","/sessions/start":"manager.sessions.start","/sessions/send":"manager.sessions.send","/sessions/queue":"manager.sessions.queue","/sessions/queue/edit":"manager.sessions.queue.edit","/sessions/queue/delete":"manager.sessions.queue.delete","/sessions/stop":"manager.sessions.stop","/sessions/read":"manager.sessions.read","/memory/path":"manager.memory.path"};function N(o){return p.isAbsolute(o)}function c(o){console.log(JSON.stringify(o,null,2))}function l(o){console.log(typeof o.markdown=="string"?o.markdown:"ok")}function u(o){return o.messageFile?g.readFileSync(o.messageFile,"utf-8"):o.message??""}function E(o){const r=o.command("manager",{hidden:!0}).description("Manager Session local tools"),n=r.command("sessions").description("Manage same-project worker sessions");n.command("list").description("List same-project sessions visible to this Manager").option("--json","Print JSON").action(async e=>{const s=await t("/sessions/list",{});if(e.json)c(s);else{const i=s.sessions??[];for(const a of i)console.log(`${a.sessionId} ${a.agentType} ${a.role??""} ${a.status} ${a.title??a.summary??""}`)}}),n.command("start").description("Start a worker session in the same project").requiredOption("--agent <agent>","Worker agent type, e.g. codex, claude, cursor, opencode, pi, or custom:<name>").option("--workdir <path>","Worker workdir; defaults to the Manager-bound directory").option("--title <title>","Short worker title").option("--model <model>","Worker model id").option("--message <text>","Worker prompt").option("--message-file <path>","Read worker prompt from file").option("--json","Print JSON").action(async e=>{const s=await t("/sessions/start",{agentType:e.agent,workDir:e.workdir,title:e.title,modelId:e.model,message:u(e)});e.json?c(s):l(s)}),n.command("send").description("Queue a message for a managed worker; runs immediately if idle").requiredOption("--session-id <id>","Worker session id").option("--message <text>","Message text").option("--message-file <path>","Read message from file").option("--direct","Deprecated compatibility flag; delivery still uses the durable queue").action(async e=>{const s=await t("/sessions/send",{sessionId:e.sessionId,message:u(e),enqueue:!e.direct});l(s)});const d=n.command("queue").description("Inspect and edit pending worker messages");d.command("list").description("List pending messages for a managed worker").requiredOption("--session-id <id>","Worker session id").option("--json","Print JSON").action(async e=>{const s=await t("/sessions/queue",{sessionId:e.sessionId});if(e.json)c(s);else{const i=s.queue?.pending??[];for(const a of i)console.log(`${a.id} ${a.text.replace(/\s+/g," ").slice(0,120)}`)}}),d.command("edit").description("Edit a pending worker message").requiredOption("--session-id <id>","Worker session id").requiredOption("--message-id <id>","Queued message id").option("--message <text>","Replacement message text").option("--message-file <path>","Read replacement message from file").action(async e=>{await t("/sessions/queue/edit",{sessionId:e.sessionId,queueMessageId:e.messageId,message:u(e)}),console.log("ok")}),d.command("delete").description("Delete a pending worker message").requiredOption("--session-id <id>","Worker session id").requiredOption("--message-id <id>","Queued message id").action(async e=>{await t("/sessions/queue/delete",{sessionId:e.sessionId,queueMessageId:e.messageId}),console.log("ok")});const m=async e=>{const s=await t("/sessions/stop",{sessionId:e.sessionId});l(s)};n.command("stop").aliases(["terminate","kill"]).description("Stop or terminate a running managed worker").requiredOption("--session-id <id>","Worker session id").action(m),n.command("read").description("Read a managed worker transcript").requiredOption("--session-id <id>","Worker session id").option("--limit <n>","Message limit","200").option("--json","Print JSON").action(async e=>{const s=await t("/sessions/read",{sessionId:e.sessionId,limit:Number(e.limit)});e.json?c(s):c(s.messages??[])}),n.command("wait").description("Wait up to a bounded timeout for the next worker progress or terminal event").requiredOption("--session-id <id>","Worker session id").option("--timeout <seconds>","Maximum wait in seconds (1-600)","600").option("--json","Print JSON").action(async e=>{const s=Math.max(1,Math.min(Number(e.timeout)||600,600)),i=await t("/sessions/wait",{sessionId:e.sessionId,timeoutMs:s*1e3});e.json?c(i):i.timedOut?console.log(`\u7B49\u5F85\u8D85\u65F6\uFF1BAgent \u5F53\u524D\u72B6\u6001\uFF1A${String(i.status||"unknown")}`):l(i)}),r.command("memory").description("Manager project memory helpers").command("path").description("Print project memory directory path").action(async()=>{const e=await t("/memory/path",{});console.log(e.path)})}export{E as registerManagerCommand};
@@ -0,0 +1,11 @@
1
+ import type { Command } from 'commander';
2
+ type WorkerCommandResponse = {
3
+ ok: boolean;
4
+ error?: string;
5
+ message?: string;
6
+ nextAction?: string;
7
+ [key: string]: unknown;
8
+ };
9
+ export declare function executeWorkerCommand(operation: 'start' | 'read' | 'send' | 'wait' | 'stop', body: Record<string, unknown>): Promise<WorkerCommandResponse>;
10
+ export declare function registerWorkerCommand(program: Command): void;
11
+ export {};
@@ -0,0 +1,2 @@
1
+ import c from"node:fs";import{resolveShennianPath as d}from"../config/index.js";function u(){const r=d("runtime","manager-ipc.json");let t;try{t=c.statSync(r)}catch{throw new Error("daemon_unavailable")}if(process.platform!=="win32"){const o=typeof process.getuid=="function"?process.getuid():t.uid;if(t.uid!==o||(t.mode&63)!==0)throw new Error("worker_runtime_permissions_invalid")}const e=JSON.parse(c.readFileSync(r,"utf-8")),n=typeof e.url=="string"?e.url:"",a=typeof e.token=="string"?e.token:"";if(!/^http:\/\/127\.0\.0\.1:\d+$/.test(n)||!a)throw new Error("daemon_unavailable");return{url:n,token:a}}function f(r){return r==="daemon_unavailable"?"Check shennian status --json and start the existing paired daemon if it was not intentionally paused.":r==="worker_runtime_permissions_invalid"?"Repair or update the existing Shennian installation; do not bypass the local runtime file permissions.":"Check the local Shennian daemon and retry the same command once."}async function i(r,t){try{const e=u(),n=r==="wait"?Math.max(2e3,Math.min(Number(t.timeoutMs||6e5)+5e3,605e3)):r==="start"||r==="send"?18e4:15e3,a=await fetch(`${e.url}/workers/${r}`,{method:"POST",headers:{authorization:`Bearer ${e.token}`,"content-type":"application/json"},body:JSON.stringify(t),signal:AbortSignal.timeout(n)}),o=await a.json().catch(()=>({ok:!1,error:"worker_invalid_response",message:a.statusText}));return a.ok&&o.ok?o:{ok:!1,error:o.error||"worker_command_failed",...o.message?{message:o.message}:{},nextAction:o.nextAction||"Check the selected Agent, working directory, account, and Worker reference."}}catch(e){const n=e instanceof Error&&e.message==="daemon_unavailable"||e instanceof Error&&e.message==="worker_runtime_permissions_invalid"?e.message:e instanceof Error&&e.name==="TimeoutError"?"ipc_timeout":"worker_command_failed";return{ok:!1,error:n,message:e instanceof Error?e.message:String(e),nextAction:f(n)}}}function m(r){return r.messageFile?c.readFileSync(r.messageFile,"utf8"):r.message??""}function s(r){process.stdout.write(`${JSON.stringify(r)}
2
+ `),r.ok||(process.exitCode=1)}function k(r){const t=r.command("worker").description("Start and control an external temporary Worker by opaque reference");t.command("start").description("Start a new Worker; returns the only reference that can control it").requiredOption("--agent <agent>","Agent type returned by shennian agent discover").option("--workdir <path>","Working directory; defaults to the current directory").option("--title <title>","Short Worker title").option("--model <model>","Model id returned by discovery").option("--message <text>","Worker task").option("--message-file <path>","Read the Worker task from a file").option("--json","Print JSON (default)").action(async e=>s(await i("start",{agentType:e.agent,workDir:e.workdir??process.cwd(),title:e.title,modelId:e.model,message:m(e)}))),t.command("read").description("Read a Worker transcript using the reference returned by worker start").requiredOption("--ref <worker-ref>","Opaque Worker reference").option("--limit <n>","Message limit","200").option("--json","Print JSON (default)").action(async e=>s(await i("read",{workerRef:e.ref,limit:Number(e.limit)}))),t.command("send").description("Queue another message for a Worker").requiredOption("--ref <worker-ref>","Opaque Worker reference").option("--message <text>","Message text").option("--message-file <path>","Read the message from a file").option("--json","Print JSON (default)").action(async e=>s(await i("send",{workerRef:e.ref,message:m(e)}))),t.command("wait").description("Wait once for Worker progress or a terminal event").requiredOption("--ref <worker-ref>","Opaque Worker reference").option("--timeout <seconds>","Maximum wait in seconds (1-600)","600").option("--json","Print JSON (default)").action(async e=>{const n=Math.max(1,Math.min(Number(e.timeout)||600,600));s(await i("wait",{workerRef:e.ref,timeoutMs:n*1e3}))}),t.command("stop").description("Stop a Worker using its opaque reference").requiredOption("--ref <worker-ref>","Opaque Worker reference").option("--json","Print JSON (default)").action(async e=>s(await i("stop",{workerRef:e.ref})))}export{i as executeWorkerCommand,k as registerWorkerCommand};
@@ -1 +1 @@
1
- import{isAvailableAgentType as s}from"@shennian/wire";import{DaemonIpcError as n}from"./protocol.js";function u(i){let r=!1;const l=()=>{const e=i.getStatus();if(e.remoteAccessDisabled)throw new n("daemon_paused","Shennian is paused; resume it only when requested.");if(!e.running)throw new n("daemon_unavailable","Shennian is not running.")};return{"agent.discover":async()=>(l(),{modelTested:!1,agents:(await i.discover()).map(t=>({type:t.type,name:t.display?.name??t.type,authState:t.authState??"unknown",...t.runtime?.cliVersion?{version:t.runtime.cliVersion}:{},...t.runtime?.compatibility?{compatibility:t.runtime.compatibility}:{},...t.runtimePlatform?{runtimePlatform:t.runtimePlatform}:{},...t.runtimeIsWsl!==void 0?{runtimeIsWsl:t.runtimeIsWsl}:{},models:t.models.map(o=>({id:o.id,name:o.name,isDefault:o.isDefault===!0}))}))}),"agent.check":async e=>{if(l(),!e||typeof e!="object"||Array.isArray(e)||typeof e.agentType!="string"||!s(e.agentType)||typeof e.workDir!="string"||!e.workDir.trim()||e.modelId!=null&&typeof e.modelId!="string")throw new n("agent_validation_invalid_configuration","Select an AI and its absolute working directory.");if(r)throw new n("agent_check_in_progress","An AI reply check is already running.");r=!0;try{const t=await i.validate({runtimeAdapter:e.agentType,workDir:e.workDir,modelId:e.modelId??null,sessionMode:"standard"});if(!t.ok)throw new n(t.errorCode,t.errorCode);return{ready:!0,agentType:e.agentType,modelId:e.modelId??null,scope:"hello_reply"}}finally{r=!1}}}}export{u as createAgentReadinessHandlers};
1
+ import{isAvailableAgentType as a}from"@shennian/wire";import{DaemonIpcError as n}from"./protocol.js";function c(i){let s=!1;const l=()=>{const e=i.getStatus();if(e.remoteAccessDisabled)throw new n("daemon_paused","Shennian is paused; resume it only when requested.");if(!e.running)throw new n("daemon_unavailable","Shennian is not running.")};return{"agent.discover":async e=>{l();const r=e&&typeof e=="object"&&!Array.isArray(e)&&typeof e.agentType=="string"?e.agentType:null,u=!!(e&&typeof e=="object"&&!Array.isArray(e)&&e.compact===!0),d=(await i.discover()).filter(t=>!r||t.type===r);return{modelTested:!1,compact:u,agents:d.map(t=>({type:t.type,name:t.display?.name??t.type,authState:t.authState??"unknown",...t.runtime?.cliVersion?{version:t.runtime.cliVersion}:{},...t.runtime?.compatibility?{compatibility:t.runtime.compatibility}:{},...t.runtimePlatform?{runtimePlatform:t.runtimePlatform}:{},...t.runtimeIsWsl!==void 0?{runtimeIsWsl:t.runtimeIsWsl}:{},supportsStandardSession:t.supportsStandardSession===!0,supportsManagedAgent:t.supportsManagedAgent===!0,supportsManagedNativeFull:t.supportsManagedNativeFull===!0,supportsRoomTools:t.supportsRoomTools===!0,supportsWorker:t.supportsWorker===!0,supportsManagerMode:t.supportsManagerMode===!0,supportsExternalWorkerTarget:t.supportsExternalWorkerTarget===!0,...u?{modelCount:t.models.length,defaultModelId:t.models.find(o=>o.isDefault)?.id??null}:{models:t.models.map(o=>({id:o.id,name:o.name,isDefault:o.isDefault===!0}))}}))}},"agent.check":async e=>{if(l(),!e||typeof e!="object"||Array.isArray(e)||typeof e.agentType!="string"||!a(e.agentType)||typeof e.workDir!="string"||!e.workDir.trim()||e.modelId!=null&&typeof e.modelId!="string")throw new n("agent_validation_invalid_configuration","Select an AI and its absolute working directory.");if(s)throw new n("agent_check_in_progress","An AI reply check is already running.");s=!0;try{const r=await i.validate({runtimeAdapter:e.agentType,workDir:e.workDir,modelId:e.modelId??null,sessionMode:"standard"});if(!r.ok)throw new n(r.errorCode,r.errorCode);return{ready:!0,agentType:e.agentType,modelId:e.modelId??null,scope:"hello_reply"}}finally{s=!1}}}}export{c as createAgentReadinessHandlers};