shennian 0.4.71 → 0.4.73

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.
Files changed (35) hide show
  1. package/dist/publish-build-manifest.json +47 -37
  2. package/dist/src/agents/acp/adapter.js +1 -1
  3. package/dist/src/agents/acp/client-services.d.ts +4 -0
  4. package/dist/src/agents/acp/client-services.js +3 -3
  5. package/dist/src/agents/acp/process-client.d.ts +2 -0
  6. package/dist/src/agents/adapter.d.ts +1 -1
  7. package/dist/src/agents/claude.d.ts +1 -0
  8. package/dist/src/agents/claude.js +5 -5
  9. package/dist/src/agents/event-terminal-gate.d.ts +16 -0
  10. package/dist/src/agents/event-terminal-gate.js +1 -0
  11. package/dist/src/agents/model-registry/discovery.js +3 -3
  12. package/dist/src/agents/model-registry/parsers.js +4 -4
  13. package/dist/src/agents/model-registry/service.d.ts +6 -2
  14. package/dist/src/agents/model-registry/service.js +1 -1
  15. package/dist/src/agents/model-registry/types.d.ts +9 -1
  16. package/dist/src/agents/model-registry/types.js +1 -1
  17. package/dist/src/commands/agent-readiness.js +2 -2
  18. package/dist/src/commands/manager.js +1 -1
  19. package/dist/src/commands/worker.d.ts +11 -0
  20. package/dist/src/commands/worker.js +2 -0
  21. package/dist/src/daemon-ipc/agent-readiness.js +1 -1
  22. package/dist/src/index.js +3 -3
  23. package/dist/src/manager/prompt.d.ts +1 -1
  24. package/dist/src/manager/prompt.js +6 -6
  25. package/dist/src/manager/registry.d.ts +49 -2
  26. package/dist/src/manager/registry.js +1 -1
  27. package/dist/src/manager/runtime.d.ts +2 -2
  28. package/dist/src/manager/runtime.js +5 -5
  29. package/dist/src/manager/worker-ipc.d.ts +7 -0
  30. package/dist/src/manager/worker-ipc.js +1 -1
  31. package/dist/src/session/handlers/agent-workspace-validation.js +1 -1
  32. package/dist/src/session/handlers/chat-events.js +2 -2
  33. package/dist/src/session/queue.js +1 -1
  34. package/node_modules/@shennian/wire/dist/session.d.ts +6 -0
  35. package/package.json +1 -1
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "jsMinified": true,
4
4
  "minifier": "esbuild",
5
- "fileCount": 219,
5
+ "fileCount": 221,
6
6
  "files": [
7
7
  {
8
8
  "file": "bin/shennian.js",
@@ -16,8 +16,8 @@
16
16
  },
17
17
  {
18
18
  "file": "src/agents/acp/adapter.js",
19
- "beforeBytes": 25702,
20
- "afterBytes": 13667
19
+ "beforeBytes": 25920,
20
+ "afterBytes": 13755
21
21
  },
22
22
  {
23
23
  "file": "src/agents/acp/auth-state.js",
@@ -41,8 +41,8 @@
41
41
  },
42
42
  {
43
43
  "file": "src/agents/acp/client-services.js",
44
- "beforeBytes": 5184,
45
- "afterBytes": 2824
44
+ "beforeBytes": 6336,
45
+ "afterBytes": 3535
46
46
  },
47
47
  {
48
48
  "file": "src/agents/acp/discovery.js",
@@ -106,8 +106,8 @@
106
106
  },
107
107
  {
108
108
  "file": "src/agents/claude.js",
109
- "beforeBytes": 18877,
110
- "afterBytes": 9108
109
+ "beforeBytes": 19582,
110
+ "afterBytes": 9365
111
111
  },
112
112
  {
113
113
  "file": "src/agents/codex-managed-permissions.js",
@@ -179,6 +179,11 @@
179
179
  "beforeBytes": 3767,
180
180
  "afterBytes": 1707
181
181
  },
182
+ {
183
+ "file": "src/agents/event-terminal-gate.js",
184
+ "beforeBytes": 1178,
185
+ "afterBytes": 468
186
+ },
182
187
  {
183
188
  "file": "src/agents/external-channel-instructions.js",
184
189
  "beforeBytes": 9452,
@@ -201,8 +206,8 @@
201
206
  },
202
207
  {
203
208
  "file": "src/agents/model-registry/discovery.js",
204
- "beforeBytes": 11070,
205
- "afterBytes": 5176
209
+ "beforeBytes": 11711,
210
+ "afterBytes": 5499
206
211
  },
207
212
  {
208
213
  "file": "src/agents/model-registry/opencode-api.js",
@@ -211,8 +216,8 @@
211
216
  },
212
217
  {
213
218
  "file": "src/agents/model-registry/parsers.js",
214
- "beforeBytes": 22727,
215
- "afterBytes": 11534
219
+ "beforeBytes": 23995,
220
+ "afterBytes": 12356
216
221
  },
217
222
  {
218
223
  "file": "src/agents/model-registry/runner.js",
@@ -221,13 +226,13 @@
221
226
  },
222
227
  {
223
228
  "file": "src/agents/model-registry/service.js",
224
- "beforeBytes": 6036,
225
- "afterBytes": 2605
229
+ "beforeBytes": 7401,
230
+ "afterBytes": 2929
226
231
  },
227
232
  {
228
233
  "file": "src/agents/model-registry/types.js",
229
- "beforeBytes": 384,
230
- "afterBytes": 235
234
+ "beforeBytes": 906,
235
+ "afterBytes": 495
231
236
  },
232
237
  {
233
238
  "file": "src/agents/model-registry.js",
@@ -306,8 +311,8 @@
306
311
  },
307
312
  {
308
313
  "file": "src/commands/agent-readiness.js",
309
- "beforeBytes": 3425,
310
- "afterBytes": 2819
314
+ "beforeBytes": 3718,
315
+ "afterBytes": 3018
311
316
  },
312
317
  {
313
318
  "file": "src/commands/agent.js",
@@ -361,8 +366,8 @@
361
366
  },
362
367
  {
363
368
  "file": "src/commands/manager.js",
364
- "beforeBytes": 11819,
365
- "afterBytes": 7639
369
+ "beforeBytes": 9692,
370
+ "afterBytes": 6336
366
371
  },
367
372
  {
368
373
  "file": "src/commands/pair-authorization.js",
@@ -409,6 +414,11 @@
409
414
  "beforeBytes": 13446,
410
415
  "afterBytes": 6795
411
416
  },
417
+ {
418
+ "file": "src/commands/worker.js",
419
+ "beforeBytes": 6654,
420
+ "afterBytes": 4212
421
+ },
412
422
  {
413
423
  "file": "src/config/index.js",
414
424
  "beforeBytes": 2801,
@@ -416,8 +426,8 @@
416
426
  },
417
427
  {
418
428
  "file": "src/daemon-ipc/agent-readiness.js",
419
- "beforeBytes": 2884,
420
- "afterBytes": 1555
429
+ "beforeBytes": 4154,
430
+ "afterBytes": 2206
421
431
  },
422
432
  {
423
433
  "file": "src/daemon-ipc/client.js",
@@ -486,8 +496,8 @@
486
496
  },
487
497
  {
488
498
  "file": "src/index.js",
489
- "beforeBytes": 40923,
490
- "afterBytes": 20430
499
+ "beforeBytes": 41017,
500
+ "afterBytes": 20498
491
501
  },
492
502
  {
493
503
  "file": "src/log-redaction.js",
@@ -501,13 +511,13 @@
501
511
  },
502
512
  {
503
513
  "file": "src/manager/prompt.js",
504
- "beforeBytes": 5115,
505
- "afterBytes": 8460
514
+ "beforeBytes": 5067,
515
+ "afterBytes": 8427
506
516
  },
507
517
  {
508
518
  "file": "src/manager/registry.js",
509
- "beforeBytes": 12065,
510
- "afterBytes": 5661
519
+ "beforeBytes": 16879,
520
+ "afterBytes": 8079
511
521
  },
512
522
  {
513
523
  "file": "src/manager/retired-external-channel-compat.js",
@@ -516,13 +526,13 @@
516
526
  },
517
527
  {
518
528
  "file": "src/manager/runtime.js",
519
- "beforeBytes": 33902,
520
- "afterBytes": 16475
529
+ "beforeBytes": 35179,
530
+ "afterBytes": 17108
521
531
  },
522
532
  {
523
533
  "file": "src/manager/worker-ipc.js",
524
- "beforeBytes": 11457,
525
- "afterBytes": 6210
534
+ "beforeBytes": 20224,
535
+ "afterBytes": 11508
526
536
  },
527
537
  {
528
538
  "file": "src/manager/worker-markdown.js",
@@ -836,8 +846,8 @@
836
846
  },
837
847
  {
838
848
  "file": "src/session/handlers/agent-workspace-validation.js",
839
- "beforeBytes": 9962,
840
- "afterBytes": 5313
849
+ "beforeBytes": 9750,
850
+ "afterBytes": 5155
841
851
  },
842
852
  {
843
853
  "file": "src/session/handlers/agents.js",
@@ -856,8 +866,8 @@
856
866
  },
857
867
  {
858
868
  "file": "src/session/handlers/chat-events.js",
859
- "beforeBytes": 15787,
860
- "afterBytes": 6851
869
+ "beforeBytes": 16226,
870
+ "afterBytes": 6965
861
871
  },
862
872
  {
863
873
  "file": "src/session/handlers/chat-recovery.js",
@@ -996,8 +1006,8 @@
996
1006
  },
997
1007
  {
998
1008
  "file": "src/session/queue.js",
999
- "beforeBytes": 49532,
1000
- "afterBytes": 21739
1009
+ "beforeBytes": 49538,
1010
+ "afterBytes": 21745
1001
1011
  },
1002
1012
  {
1003
1013
  "file": "src/session/queued-chat-dispatch.js",
@@ -1,3 +1,3 @@
1
1
  import{randomUUID as p}from"node:crypto";import{createHash as m}from"node:crypto";import{realpathSync as g}from"node:fs";import{pathToFileURL as I}from"node:url";import*as l from"@agentclientprotocol/sdk";import{RequestError as w}from"@agentclientprotocol/sdk";import{AgentAdapter as C,registerAgent as v}from"../adapter.js";import{mapAcpSessionUpdate as A}from"./events.js";import{AcpProcessClient as P}from"./process-client.js";import{acpAgentType as f}from"./types.js";import{runAcpTerminalAuthentication as q}from"./auth.js";import{setAcpRuntimeAuthState as d}from"./auth-state.js";import{recordAcpAuthFailure as E,recordAcpImportResult as y}from"./metrics.js";import{isManagedAgentNativeFull as S}from"../../security/managed-agent-policy.js";import{buildManagedNativeFullProcessEnv as b}from"../../agent-env.js";class x extends C{manifest;options;type;get recoveryCapabilities(){const e=this.client?.capabilities;return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!!(e?.sessionCapabilities?.resume||e?.loadSession)}}client=null;workDir="";shennianSessionId="";requestedSessionId=null;agentSessionId=null;runId="";seq=0;active=!1;extraEnv={};pendingPermissions=new Map;configOptions=[];modes=null;importCapture=null;emittedToolStates=new Map;pendingAuthRetry=null;retryingAfterAuth=!1;managedAgentPolicy=null;configurationSignature="";startedConfigurationSignature="";constructor(e,t={}){super(),this.manifest=e,this.options=t,this.type=f(e.id)}configure(e){this.extraEnv=e.env??{},this.managedAgentPolicy=e.managedAgentPolicy??null,this.configurationSignature=m("sha256").update(JSON.stringify({env:Object.entries(this.extraEnv).sort(([t],[s])=>t.localeCompare(s)),managedAgentPolicy:this.managedAgentPolicy})).digest("hex")}async start(e,t,s){this.shennianSessionId=e;try{this.workDir=g.native(t)}catch{this.workDir=t}this.requestedSessionId=s??null,this.agentSessionId=null,this.client=this.createProcessClient(),await this.client.start(this.workDir),this.startedConfigurationSignature=this.configurationSignature}async send(e,t,s,i,n){await this.refreshProcessConfiguration();const o=this.requireClient();this.runId=p(),this.seq=0,this.emittedToolStates.clear();try{await this.ensureSession(),await this.applyDynamicConfig(t,s),this.active=!0,this.emitEvent({state:"start",runPhase:"thinking",agentSessionId:this.agentSessionId??void 0});const r=[],a=[];n?.trim()&&a.push(n.trim()),a.push(e),r.push({type:"text",text:a.join(`
2
2
 
3
- `)});for(const h of i??[])r.push({type:"resource_link",uri:I(h.path).href,name:h.name,mimeType:h.mimeType,size:h.byteSize});const c=await this.promptWithTimeout(o,r);this.active=!1,c.stopReason==="cancelled"?this.emitEvent({state:"aborted",agentSessionId:this.agentSessionId??void 0}):this.emitEvent({state:"final",agentSessionId:this.agentSessionId??void 0})}catch(r){this.active=!1,this.cancelPendingPermissions();const a=r instanceof Error?r.message:String(r),c=r instanceof w&&r.code===-32e3;throw c&&(d(this.type,"required"),this.retryingAfterAuth||(this.pendingAuthRetry={text:e,...t?{modelId:t}:{},...s?{reasoningEffort:s}:{},...i?{attachments:[...i]}:{},...n!==void 0?{systemPrompt:n}:{}})),this.emitEvent({state:"error",message:a,...c?{errorCode:"acp_auth_required"}:{},agentSessionId:this.agentSessionId??void 0}),r}}async resume(e){this.requestedSessionId=e,this.agentSessionId=null,await this.ensureSession()}async stop(){this.active&&this.agentSessionId&&this.client&&await this.client.agent.notify(l.methods.agent.session.cancel,{sessionId:this.agentSessionId}),this.cancelPendingPermissions(),this.active=!1,await this.client?.close(),this.client=null,this.startedConfigurationSignature=""}async getStatus(){return{active:this.active,runId:this.active?this.runId:null,canStop:this.active}}async respondToPermission(e,t){const s=this.pendingPermissions.get(e);if(!s)throw new Error("ACP permission request is no longer pending");if(!s.optionIds.has(t))throw new Error("Invalid ACP permission option");this.pendingPermissions.delete(e),clearTimeout(s.timer),s.resolve({outcome:{outcome:"selected",optionId:t}})}getAuthMethods(){return[...this.requireClient().initializeResponse?.authMethods??[]]}hasPendingAuthenticationRetry(){return this.pendingAuthRetry!==null}getSessionOptions(){const e=this.configOptions.find(o=>o.category==="model"&&o.type==="select"),t=this.configOptions.find(o=>o.category==="thought_level"&&o.type==="select"),s=this.modes?.availableModes.map(o=>({id:o.id,name:o.name,...o.description?{description:o.description}:{}}))??[],i=o=>(o?.options??[]).flatMap(r=>"options"in r?r.options:[r]),n=(t?i(t):s).map(o=>({id:"value"in o?o.value:o.id,name:o.name,...o.description?{description:o.description}:{}}));return{models:i(e).map(o=>({id:o.value,name:o.name,...o.description?{description:o.description}:{},...o.value===e?.currentValue?{isDefault:!0}:{},...n.length?{supportedReasoningEfforts:n}:{}})),modes:s}}async authenticate(e,t={}){const s=this.requireClient(),i=s.initializeResponse?.authMethods?.find(n=>n.id===e);if(!i)throw new Error("ACP authentication method is unavailable");try{if("type"in i&&i.type==="terminal"){if(!t.interactiveTerminal)throw new Error("ACP terminal authentication must be completed on the target machine with `shennian agent auth`");await s.close(),await q({...this.manifest.authLaunch??this.manifest.launch,env:Object.fromEntries(Object.entries({...this.extraEnv,...this.manifest.authLaunch?.env??this.manifest.launch.env}).filter(n=>typeof n[1]=="string"))},i,this.workDir)}else await s.authenticate(e);await this.resumeAfterExternalAuthentication()}catch(n){throw E(),n}}async logout(){await this.requireClient().logout(),d(this.type,"required")}async resumeAfterExternalAuthentication(){await this.client?.close(),this.client=this.createProcessClient(),await this.client.start(this.workDir),this.startedConfigurationSignature=this.configurationSignature,d(this.type,"ready");const e=this.pendingAuthRetry;this.pendingAuthRetry=null,e&&this.retryAfterAuthentication(e)}async listExternalSessions(e={}){const t=this.requireClient();if(!t.capabilities.sessionCapabilities?.list)return[];const s=[];let i;for(let n=0;n<10&&s.length<500;n+=1){let o=e.cwd;if(o)try{o=g.native(o)}catch{}const r=await t.listSessions(o,i);if(s.push(...r.sessions.slice(0,500-s.length).map(a=>({agentSessionId:a.sessionId,cwd:a.cwd,...a.title?{title:a.title.slice(0,200)}:{},...a.updatedAt?{updatedAt:a.updatedAt}:{}}))),i=r.nextCursor,!i)break}return s}async loadExternalSession(e){const t=this.requireClient();if(!t.capabilities.loadSession)throw new Error("ACP session history import is unsupported");this.requestedSessionId=e,this.agentSessionId=e;const s=[];this.importCapture=s;try{const i=await t.agent.request(l.methods.agent.session.load,{sessionId:e,cwd:this.workDir,mcpServers:[]});this.configOptions=i.configOptions??[],this.modes=i.modes??null,y(!0)}catch(i){throw y(!1),i}finally{this.importCapture=null}return s.map((i,n)=>({sourceId:i.sourceHint??m("sha256").update(`${e}\0${n}\0${i.role}\0${i.payload}`).digest("hex"),role:i.role,payload:i.payload}))}async closeExternalSession(e){if(!this.requireClient().capabilities.sessionCapabilities?.close)throw new Error("ACP session close is unsupported");await this.requireClient().closeSession(e)}async deleteExternalSession(e){if(!this.requireClient().capabilities.sessionCapabilities?.delete)throw new Error("ACP session delete is unsupported");await this.requireClient().deleteSession(e)}async ensureSession(){if(this.agentSessionId)return;const e=this.requireClient();if(this.requestedSessionId){const s=e.capabilities;if(s.sessionCapabilities?.resume){const i=await e.agent.request(l.methods.agent.session.resume,{sessionId:this.requestedSessionId,cwd:this.workDir,mcpServers:[]});this.configOptions=i.configOptions??[],this.modes=i.modes??null}else if(s.loadSession){this.agentSessionId=this.requestedSessionId;const i=await e.agent.request(l.methods.agent.session.load,{sessionId:this.requestedSessionId,cwd:this.workDir,mcpServers:[]});this.configOptions=i.configOptions??[],this.modes=i.modes??null}else throw new Error(`${this.manifest.name} cannot resume ACP sessions`);this.agentSessionId=this.requestedSessionId;return}const t=await e.agent.request(l.methods.agent.session.new,{cwd:this.workDir,mcpServers:[]});this.agentSessionId=t.sessionId,this.configOptions=t.configOptions??[],this.modes=t.modes??null}async applyDynamicConfig(e,t){if(!this.agentSessionId)return;t&&this.modes?.availableModes.some(i=>i.id===t)&&(this.modes.currentModeId!==t&&(await this.requireClient().agent.request(l.methods.agent.session.setMode,{sessionId:this.agentSessionId,modeId:t}),this.modes.currentModeId=t),t=void 0);const s=[{category:"model",value:e},{category:"thought_level",value:t}];for(const i of s){if(!i.value)continue;const n=this.configOptions.find(o=>o.category===i.category&&o.type==="select");!n||n.currentValue===i.value||(await this.requireClient().agent.request(l.methods.agent.session.setConfigOption,{sessionId:this.agentSessionId,configId:n.id,value:i.value}),n.currentValue=i.value)}}handleSessionUpdate(e){if(e.sessionId===this.agentSessionId){if(this.importCapture){this.captureImportedUpdate(e.update);return}if(this.active){if(e.update.sessionUpdate==="tool_call"||e.update.sessionUpdate==="tool_call_update"){const t=JSON.stringify(e.update);if(this.emittedToolStates.get(e.update.toolCallId)===t)return;this.emittedToolStates.set(e.update.toolCallId,t)}for(const t of A(e.update,s=>this.makeEvent(s)))this.emit("agentEvent",t)}}}captureImportedUpdate(e){if(this.importCapture){if(e.sessionUpdate==="user_message_chunk"||e.sessionUpdate==="agent_message_chunk"){const t=e.content.type==="text"?e.content.text:e.content.type==="resource_link"?e.content.name||e.content.uri:`[${e.content.type}]`,s=e.sessionUpdate==="user_message_chunk"?"user":"agent",i=e.messageId?`message:${e.messageId}`:void 0,n=i?this.importCapture.find(o=>o.sourceHint===i):this.importCapture.at(-1);n?.role===s&&n.sourceHint===i?n.payload+=t:this.importCapture.push({role:s,payload:t,...i?{sourceHint:i}:{}});return}if(e.sessionUpdate==="tool_call"){const t=`tool:${e.toolCallId}`,s=this.importCapture.find(n=>n.sourceHint===t),i={role:"agent",sourceHint:t,payload:JSON.stringify({v:1,type:"tool_use",name:e.title,toolCallId:e.toolCallId,status:e.status??"running"})};s?s.payload=i.payload:this.importCapture.push(i);return}if(e.sessionUpdate==="tool_call_update"&&(e.status==="completed"||e.status==="failed")){const t=this.importCapture.find(i=>i.sourceHint===`tool:${e.toolCallId}`),s=JSON.stringify({v:1,type:"tool_result",name:e.title??"tool",toolCallId:e.toolCallId,status:e.status});t?t.payload=s:this.importCapture.push({role:"agent",sourceHint:`tool:${e.toolCallId}`,payload:s})}}}handlePermission(e){if(!this.active||e.sessionId!==this.agentSessionId)return Promise.resolve({outcome:{outcome:"cancelled"}});const t=p();return new Promise(s=>{const i=setTimeout(()=>{this.pendingPermissions.delete(t),s({outcome:{outcome:"cancelled"}})},this.options.permissionTimeoutMs??3e5);i.unref?.(),this.pendingPermissions.set(t,{optionIds:new Set(e.options.map(n=>n.optionId)),resolve:s,timer:i}),this.emitEvent({state:"approval-pending",runPhase:"waiting_approval",approval:{title:e.toolCall.title??void 0,source:this.manifest.name},permission:{id:t,sessionId:this.shennianSessionId,agentSessionId:this.agentSessionId??void 0,runId:this.runId,toolCallId:e.toolCall.toolCallId,options:e.options.map(n=>({id:n.optionId,name:n.name,kind:n.kind}))}})})}requireClient(){if(!this.client)throw new Error("ACP adapter has not started");return this.client}createProcessClient(){return new P(this.manifest.launch,{onSessionUpdate:e=>this.handleSessionUpdate(e),onPermission:e=>this.handlePermission(e)},this.buildEnvironment(),{...this.buildClientCapabilities(),terminalAuth:!0})}async refreshProcessConfiguration(){if(!this.client||this.startedConfigurationSignature===this.configurationSignature)return;const e=this.agentSessionId??this.requestedSessionId;await this.client.close(),this.requestedSessionId=e,this.agentSessionId=null,this.configOptions=[],this.modes=null,this.client=this.createProcessClient(),await this.client.start(this.workDir),this.startedConfigurationSignature=this.configurationSignature}buildEnvironment(){return this.managedAgentPolicy?S(this.managedAgentPolicy)?b(this.extraEnv):{...this.extraEnv}:{...process.env,...this.extraEnv}}buildClientCapabilities(){const e=this.manifest.clientCapabilities??{},t=this.managedAgentPolicy?.adapterPolicy;return!t||S(this.managedAgentPolicy)?e:{readTextFile:!!e.readTextFile,writeTextFile:!!(e.writeTextFile&&t.fileAccess!=="workspace-read"),terminal:!1}}async retryAfterAuthentication(e){this.retryingAfterAuth=!0;try{await this.send(e.text,e.modelId,e.reasoningEffort,e.attachments,e.systemPrompt)}catch{}finally{this.retryingAfterAuth=!1}}async promptWithTimeout(e,t){let s;try{return await Promise.race([e.agent.request(l.methods.agent.session.prompt,{sessionId:this.agentSessionId,prompt:t}),new Promise((i,n)=>{s=setTimeout(()=>n(new Error("ACP prompt timed out")),this.options.promptTimeoutMs??720*6e4),s.unref?.()})])}catch(i){throw i instanceof Error&&i.message==="ACP prompt timed out"&&(await e.close(),this.client===e&&(this.client=null)),i}finally{s&&clearTimeout(s)}}cancelPendingPermissions(){for(const e of this.pendingPermissions.values())clearTimeout(e.timer),e.resolve({outcome:{outcome:"cancelled"}});this.pendingPermissions.clear()}makeEvent(e){return{...e,runId:this.runId,seq:this.seq++}}emitEvent(e){this.emit("agentEvent",this.makeEvent(e))}}function J(u){v(f(u.id),()=>new x(u))}export{x as AcpAgentAdapter,J as registerAcpAgent};
3
+ `)});for(const h of i??[])r.push({type:"resource_link",uri:I(h.path).href,name:h.name,mimeType:h.mimeType,size:h.byteSize});const c=await this.promptWithTimeout(o,r);this.active=!1,c.stopReason==="cancelled"?this.emitEvent({state:"aborted",agentSessionId:this.agentSessionId??void 0}):this.emitEvent({state:"final",agentSessionId:this.agentSessionId??void 0})}catch(r){this.active=!1,this.cancelPendingPermissions();const a=r instanceof Error?r.message:String(r),c=r instanceof w&&r.code===-32e3;throw c&&(d(this.type,"required"),this.retryingAfterAuth||(this.pendingAuthRetry={text:e,...t?{modelId:t}:{},...s?{reasoningEffort:s}:{},...i?{attachments:[...i]}:{},...n!==void 0?{systemPrompt:n}:{}})),this.emitEvent({state:"error",message:a,...c?{errorCode:"acp_auth_required"}:{},agentSessionId:this.agentSessionId??void 0}),r}}async resume(e){this.requestedSessionId=e,this.agentSessionId=null,await this.ensureSession()}async stop(){this.active&&this.agentSessionId&&this.client&&await this.client.agent.notify(l.methods.agent.session.cancel,{sessionId:this.agentSessionId}),this.cancelPendingPermissions(),this.active=!1,await this.client?.close(),this.client=null,this.startedConfigurationSignature=""}async getStatus(){return{active:this.active,runId:this.active?this.runId:null,canStop:this.active}}async respondToPermission(e,t){const s=this.pendingPermissions.get(e);if(!s)throw new Error("ACP permission request is no longer pending");if(!s.optionIds.has(t))throw new Error("Invalid ACP permission option");this.pendingPermissions.delete(e),clearTimeout(s.timer),s.resolve({outcome:{outcome:"selected",optionId:t}})}getAuthMethods(){return[...this.requireClient().initializeResponse?.authMethods??[]]}hasPendingAuthenticationRetry(){return this.pendingAuthRetry!==null}getSessionOptions(){const e=this.configOptions.find(o=>o.category==="model"&&o.type==="select"),t=this.configOptions.find(o=>o.category==="thought_level"&&o.type==="select"),s=this.modes?.availableModes.map(o=>({id:o.id,name:o.name,...o.description?{description:o.description}:{}}))??[],i=o=>(o?.options??[]).flatMap(r=>"options"in r?r.options:[r]),n=(t?i(t):s).map(o=>({id:"value"in o?o.value:o.id,name:o.name,...o.description?{description:o.description}:{}}));return{models:i(e).map(o=>({id:o.value,name:o.name,...o.description?{description:o.description}:{},...o.value===e?.currentValue?{isDefault:!0}:{},...n.length?{supportedReasoningEfforts:n}:{}})),modes:s}}async authenticate(e,t={}){const s=this.requireClient(),i=s.initializeResponse?.authMethods?.find(n=>n.id===e);if(!i)throw new Error("ACP authentication method is unavailable");try{if("type"in i&&i.type==="terminal"){if(!t.interactiveTerminal)throw new Error("ACP terminal authentication must be completed on the target machine with `shennian agent auth`");await s.close(),await q({...this.manifest.authLaunch??this.manifest.launch,env:Object.fromEntries(Object.entries({...this.extraEnv,...this.manifest.authLaunch?.env??this.manifest.launch.env}).filter(n=>typeof n[1]=="string"))},i,this.workDir)}else await s.authenticate(e);await this.resumeAfterExternalAuthentication()}catch(n){throw E(),n}}async logout(){await this.requireClient().logout(),d(this.type,"required")}async resumeAfterExternalAuthentication(){await this.client?.close(),this.client=this.createProcessClient(),await this.client.start(this.workDir),this.startedConfigurationSignature=this.configurationSignature,d(this.type,"ready");const e=this.pendingAuthRetry;this.pendingAuthRetry=null,e&&this.retryAfterAuthentication(e)}async listExternalSessions(e={}){const t=this.requireClient();if(!t.capabilities.sessionCapabilities?.list)return[];const s=[];let i;for(let n=0;n<10&&s.length<500;n+=1){let o=e.cwd;if(o)try{o=g.native(o)}catch{}const r=await t.listSessions(o,i);if(s.push(...r.sessions.slice(0,500-s.length).map(a=>({agentSessionId:a.sessionId,cwd:a.cwd,...a.title?{title:a.title.slice(0,200)}:{},...a.updatedAt?{updatedAt:a.updatedAt}:{}}))),i=r.nextCursor,!i)break}return s}async loadExternalSession(e){const t=this.requireClient();if(!t.capabilities.loadSession)throw new Error("ACP session history import is unsupported");this.requestedSessionId=e,this.agentSessionId=e;const s=[];this.importCapture=s;try{const i=await t.agent.request(l.methods.agent.session.load,{sessionId:e,cwd:this.workDir,mcpServers:[]});this.configOptions=i.configOptions??[],this.modes=i.modes??null,y(!0)}catch(i){throw y(!1),i}finally{this.importCapture=null}return s.map((i,n)=>({sourceId:i.sourceHint??m("sha256").update(`${e}\0${n}\0${i.role}\0${i.payload}`).digest("hex"),role:i.role,payload:i.payload}))}async closeExternalSession(e){if(!this.requireClient().capabilities.sessionCapabilities?.close)throw new Error("ACP session close is unsupported");await this.requireClient().closeSession(e)}async deleteExternalSession(e){if(!this.requireClient().capabilities.sessionCapabilities?.delete)throw new Error("ACP session delete is unsupported");await this.requireClient().deleteSession(e)}async ensureSession(){if(this.agentSessionId)return;const e=this.requireClient();if(this.requestedSessionId){const s=e.capabilities;if(s.sessionCapabilities?.resume){const i=await e.agent.request(l.methods.agent.session.resume,{sessionId:this.requestedSessionId,cwd:this.workDir,mcpServers:[]});this.configOptions=i.configOptions??[],this.modes=i.modes??null}else if(s.loadSession){this.agentSessionId=this.requestedSessionId;const i=await e.agent.request(l.methods.agent.session.load,{sessionId:this.requestedSessionId,cwd:this.workDir,mcpServers:[]});this.configOptions=i.configOptions??[],this.modes=i.modes??null}else throw new Error(`${this.manifest.name} cannot resume ACP sessions`);this.agentSessionId=this.requestedSessionId;return}const t=await e.agent.request(l.methods.agent.session.new,{cwd:this.workDir,mcpServers:[]});this.agentSessionId=t.sessionId,this.configOptions=t.configOptions??[],this.modes=t.modes??null}async applyDynamicConfig(e,t){if(!this.agentSessionId)return;t&&this.modes?.availableModes.some(i=>i.id===t)&&(this.modes.currentModeId!==t&&(await this.requireClient().agent.request(l.methods.agent.session.setMode,{sessionId:this.agentSessionId,modeId:t}),this.modes.currentModeId=t),t=void 0);const s=[{category:"model",value:e},{category:"thought_level",value:t}];for(const i of s){if(!i.value)continue;const n=this.configOptions.find(o=>o.category===i.category&&o.type==="select");!n||n.currentValue===i.value||(await this.requireClient().agent.request(l.methods.agent.session.setConfigOption,{sessionId:this.agentSessionId,configId:n.id,value:i.value}),n.currentValue=i.value)}}handleSessionUpdate(e){if(e.sessionId===this.agentSessionId){if(this.importCapture){this.captureImportedUpdate(e.update);return}if(this.active){if(e.update.sessionUpdate==="tool_call"||e.update.sessionUpdate==="tool_call_update"){const t=JSON.stringify(e.update);if(this.emittedToolStates.get(e.update.toolCallId)===t)return;this.emittedToolStates.set(e.update.toolCallId,t)}for(const t of A(e.update,s=>this.makeEvent(s)))this.emit("agentEvent",t)}}}captureImportedUpdate(e){if(this.importCapture){if(e.sessionUpdate==="user_message_chunk"||e.sessionUpdate==="agent_message_chunk"){const t=e.content.type==="text"?e.content.text:e.content.type==="resource_link"?e.content.name||e.content.uri:`[${e.content.type}]`,s=e.sessionUpdate==="user_message_chunk"?"user":"agent",i=e.messageId?`message:${e.messageId}`:void 0,n=i?this.importCapture.find(o=>o.sourceHint===i):this.importCapture.at(-1);n?.role===s&&n.sourceHint===i?n.payload+=t:this.importCapture.push({role:s,payload:t,...i?{sourceHint:i}:{}});return}if(e.sessionUpdate==="tool_call"){const t=`tool:${e.toolCallId}`,s=this.importCapture.find(n=>n.sourceHint===t),i={role:"agent",sourceHint:t,payload:JSON.stringify({v:1,type:"tool_use",name:e.title,toolCallId:e.toolCallId,status:e.status??"running"})};s?s.payload=i.payload:this.importCapture.push(i);return}if(e.sessionUpdate==="tool_call_update"&&(e.status==="completed"||e.status==="failed")){const t=this.importCapture.find(i=>i.sourceHint===`tool:${e.toolCallId}`),s=JSON.stringify({v:1,type:"tool_result",name:e.title??"tool",toolCallId:e.toolCallId,status:e.status});t?t.payload=s:this.importCapture.push({role:"agent",sourceHint:`tool:${e.toolCallId}`,payload:s})}}}handlePermission(e){if(!this.active||e.sessionId!==this.agentSessionId)return Promise.resolve({outcome:{outcome:"cancelled"}});const t=p();return new Promise(s=>{const i=setTimeout(()=>{this.pendingPermissions.delete(t),s({outcome:{outcome:"cancelled"}})},this.options.permissionTimeoutMs??3e5);i.unref?.(),this.pendingPermissions.set(t,{optionIds:new Set(e.options.map(n=>n.optionId)),resolve:s,timer:i}),this.emitEvent({state:"approval-pending",runPhase:"waiting_approval",approval:{title:e.toolCall.title??void 0,source:this.manifest.name},permission:{id:t,sessionId:this.shennianSessionId,agentSessionId:this.agentSessionId??void 0,runId:this.runId,toolCallId:e.toolCall.toolCallId,options:e.options.map(n=>({id:n.optionId,name:n.name,kind:n.kind}))}})})}requireClient(){if(!this.client)throw new Error("ACP adapter has not started");return this.client}createProcessClient(){return new P(this.manifest.launch,{onSessionUpdate:e=>this.handleSessionUpdate(e),onPermission:e=>this.handlePermission(e)},this.buildEnvironment(),{...this.buildClientCapabilities(),terminalAuth:!0})}async refreshProcessConfiguration(){if(!this.client||this.startedConfigurationSignature===this.configurationSignature)return;const e=this.agentSessionId??this.requestedSessionId;await this.client.close(),this.requestedSessionId=e,this.agentSessionId=null,this.configOptions=[],this.modes=null,this.client=this.createProcessClient(),await this.client.start(this.workDir),this.startedConfigurationSignature=this.configurationSignature}buildEnvironment(){return this.managedAgentPolicy?S(this.managedAgentPolicy)?b(this.extraEnv):{...this.extraEnv}:{...process.env,...this.extraEnv}}buildClientCapabilities(){const e=this.manifest.clientCapabilities??{},t=this.managedAgentPolicy?.adapterPolicy;return t?S(this.managedAgentPolicy)?{...e,terminal:!0,terminalPolicy:"managed-room-only"}:{readTextFile:!!e.readTextFile,writeTextFile:!!(e.writeTextFile&&t.fileAccess!=="workspace-read"),terminal:!0,terminalPolicy:"managed-room-only"}:e}async retryAfterAuthentication(e){this.retryingAfterAuth=!0;try{await this.send(e.text,e.modelId,e.reasoningEffort,e.attachments,e.systemPrompt)}catch{}finally{this.retryingAfterAuth=!1}}async promptWithTimeout(e,t){let s;try{return await Promise.race([e.agent.request(l.methods.agent.session.prompt,{sessionId:this.agentSessionId,prompt:t}),new Promise((i,n)=>{s=setTimeout(()=>n(new Error("ACP prompt timed out")),this.options.promptTimeoutMs??720*6e4),s.unref?.()})])}catch(i){throw i instanceof Error&&i.message==="ACP prompt timed out"&&(await e.close(),this.client===e&&(this.client=null)),i}finally{s&&clearTimeout(s)}}cancelPendingPermissions(){for(const e of this.pendingPermissions.values())clearTimeout(e.timer),e.resolve({outcome:{outcome:"cancelled"}});this.pendingPermissions.clear()}makeEvent(e){return{...e,runId:this.runId,seq:this.seq++}}emitEvent(e){this.emit("agentEvent",this.makeEvent(e))}}function J(u){v(f(u.id),()=>new x(u))}export{x as AcpAgentAdapter,J as registerAcpAgent};
@@ -1,9 +1,11 @@
1
1
  import type * as acp from '@agentclientprotocol/sdk';
2
+ export type AcpTerminalPolicy = 'unrestricted' | 'managed-room-only';
2
3
  export declare class AcpClientServices {
3
4
  readonly enabled: {
4
5
  readTextFile?: boolean;
5
6
  writeTextFile?: boolean;
6
7
  terminal?: boolean;
8
+ terminalPolicy?: AcpTerminalPolicy;
7
9
  };
8
10
  private readonly root;
9
11
  private readonly environment;
@@ -12,6 +14,7 @@ export declare class AcpClientServices {
12
14
  readTextFile?: boolean;
13
15
  writeTextFile?: boolean;
14
16
  terminal?: boolean;
17
+ terminalPolicy?: AcpTerminalPolicy;
15
18
  }, environment?: NodeJS.ProcessEnv);
16
19
  get capabilities(): {
17
20
  fs: {
@@ -29,5 +32,6 @@ export declare class AcpClientServices {
29
32
  releaseTerminal(params: acp.ReleaseTerminalRequest): void;
30
33
  close(): void;
31
34
  private requireTerminal;
35
+ private resolveTerminalInvocation;
32
36
  private resolve;
33
37
  }
@@ -1,3 +1,3 @@
1
- import c from"node:fs";import n from"node:path";import{randomUUID as p}from"node:crypto";import{spawn as w}from"node:child_process";import{terminateProcessTree as m}from"./process-tree.js";class F{enabled;root;environment;terminals=new Map;constructor(t,e,r=process.env){this.enabled=e,this.root=c.realpathSync(t),this.environment={...r}}get capabilities(){return{fs:{readTextFile:!!this.enabled.readTextFile,writeTextFile:!!this.enabled.writeTextFile},terminal:!!this.enabled.terminal}}async readTextFile(t){if(!this.enabled.readTextFile)throw new Error("ACP file reads are disabled");const r=(await c.promises.readFile(await this.resolve(t.path,!1),"utf8")).split(`
2
- `),a=Math.max(0,(t.line??1)-1),i=Math.min(Math.max(0,t.limit??r.length),1e5);return{content:r.slice(a,a+i).join(`
3
- `)}}async writeTextFile(t){if(!this.enabled.writeTextFile)throw new Error("ACP file writes are disabled");const e=await this.resolve(t.path,!0);await c.promises.writeFile(e,t.content,"utf8")}async createTerminal(t){if(!this.enabled.terminal)throw new Error("ACP terminals are disabled");const e=await this.resolve(t.cwd??this.root,!1),r=w(t.command,t.args??[],{cwd:e,env:{...this.environment,...Object.fromEntries((t.env??[]).map(s=>[s.name,s.value]))},stdio:["pipe","pipe","pipe"],detached:process.platform!=="win32",windowsHide:!0}),a=Math.min(Number(t.outputByteLimit??1024*1024),4*1024*1024),i={child:r,output:Buffer.alloc(0),limit:a,truncated:!1,exitStatus:null,exited:new Promise(s=>r.once("exit",(o,h)=>{const d={exitCode:o,signal:h};i.exitStatus=d,s(d)}))},l=s=>{if(i.output=Buffer.concat([i.output,s]),i.output.byteLength>i.limit){let o=i.output.byteLength-i.limit;for(;o<i.output.byteLength&&(i.output[o]&192)===128;)o+=1;i.output=i.output.subarray(o),i.truncated=!0}};r.stdout.on("data",l),r.stderr.on("data",l);const u=p();return this.terminals.set(u,i),{terminalId:u}}terminalOutput(t){const e=this.requireTerminal(t.terminalId);return{output:e.output.toString("utf8"),truncated:e.truncated,exitStatus:e.exitStatus}}async waitForTerminalExit(t){return this.requireTerminal(t.terminalId).exited}killTerminal(t){m(this.requireTerminal(t.terminalId).child)}releaseTerminal(t){const e=this.requireTerminal(t.terminalId);e.exitStatus||m(e.child),this.terminals.delete(t.terminalId)}close(){for(const t of this.terminals.values())t.exitStatus||m(t.child);this.terminals.clear()}requireTerminal(t){const e=this.terminals.get(t);if(!e)throw new Error("Unknown ACP terminal");return e}async resolve(t,e){if(!n.isAbsolute(t))throw new Error("ACP path must be absolute");const r=n.resolve(t),a=e?n.dirname(r):r,i=await c.promises.realpath(a),l=e?n.join(i,n.basename(r)):i,u=n.relative(this.root,l);if(u.startsWith("..")||n.isAbsolute(u))throw new Error("ACP path is outside the session workspace");return l}}export{F as AcpClientServices};
1
+ import c from"node:fs";import o from"node:path";import{randomUUID as w}from"node:crypto";import{spawn as f}from"node:child_process";import{terminateProcessTree as u}from"./process-tree.js";import{resolveBuiltinCommand as b}from"../command-spec.js";class A{enabled;root;environment;terminals=new Map;constructor(t,e,n=process.env){this.enabled=e,this.root=c.realpathSync(t),this.environment={...n}}get capabilities(){return{fs:{readTextFile:!!this.enabled.readTextFile,writeTextFile:!!this.enabled.writeTextFile},terminal:!!this.enabled.terminal}}async readTextFile(t){if(!this.enabled.readTextFile)throw new Error("ACP file reads are disabled");const n=(await c.promises.readFile(await this.resolve(t.path,!1),"utf8")).split(`
2
+ `),r=Math.max(0,(t.line??1)-1),a=Math.min(Math.max(0,t.limit??n.length),1e5);return{content:n.slice(r,r+a).join(`
3
+ `)}}async writeTextFile(t){if(!this.enabled.writeTextFile)throw new Error("ACP file writes are disabled");const e=await this.resolve(t.path,!0);await c.promises.writeFile(e,t.content,"utf8")}async createTerminal(t){if(!this.enabled.terminal)throw new Error("ACP terminals are disabled");const e=await this.resolve(t.cwd??this.root,!1),n=this.resolveTerminalInvocation(t.command,t.args??[]),r=f(n.command,n.args,{cwd:e,env:this.enabled.terminalPolicy==="managed-room-only"?{...this.environment}:{...this.environment,...Object.fromEntries((t.env??[]).map(s=>[s.name,s.value]))},stdio:["pipe","pipe","pipe"],detached:process.platform!=="win32",windowsHide:!0}),a=Math.min(Number(t.outputByteLimit??1024*1024),4*1024*1024),i={child:r,output:Buffer.alloc(0),limit:a,truncated:!1,exitStatus:null,exited:new Promise(s=>r.once("exit",(l,p)=>{const h={exitCode:l,signal:p};i.exitStatus=h,s(h)}))},m=s=>{if(i.output=Buffer.concat([i.output,s]),i.output.byteLength>i.limit){let l=i.output.byteLength-i.limit;for(;l<i.output.byteLength&&(i.output[l]&192)===128;)l+=1;i.output=i.output.subarray(l),i.truncated=!0}};r.stdout.on("data",m),r.stderr.on("data",m);const d=w();return this.terminals.set(d,i),{terminalId:d}}terminalOutput(t){const e=this.requireTerminal(t.terminalId);return{output:e.output.toString("utf8"),truncated:e.truncated,exitStatus:e.exitStatus}}async waitForTerminalExit(t){return this.requireTerminal(t.terminalId).exited}killTerminal(t){u(this.requireTerminal(t.terminalId).child)}releaseTerminal(t){const e=this.requireTerminal(t.terminalId);e.exitStatus||u(e.child),this.terminals.delete(t.terminalId)}close(){for(const t of this.terminals.values())t.exitStatus||u(t.child);this.terminals.clear()}requireTerminal(t){const e=this.terminals.get(t);if(!e)throw new Error("Unknown ACP terminal");return e}resolveTerminalInvocation(t,e){if(this.enabled.terminalPolicy!=="managed-room-only")return{command:t,args:e};const n=e[1],r=n!=="attachment"||e[2]==="get";if(o.basename(t).replace(/\.(?:cmd|exe)$/i,"")!=="shennian"||e[0]!=="room"||!["status","read","send","attachment","pause","schedule"].includes(n??"")||!r)throw new Error("ACP managed terminal only permits Shennian Room commands");const a=b("pi");if(!a)throw new Error("Shennian CLI is unavailable for ACP managed Room tools");return{command:a.command,args:[...a.args,...e]}}async resolve(t,e){if(!o.isAbsolute(t))throw new Error("ACP path must be absolute");const n=o.resolve(t),r=e?o.dirname(n):n,a=await c.promises.realpath(r),i=e?o.join(a,o.basename(n)):a,m=o.relative(this.root,i);if(m.startsWith("..")||o.isAbsolute(m))throw new Error("ACP path is outside the session workspace");return i}}export{A as AcpClientServices};
@@ -1,6 +1,7 @@
1
1
  import * as acp from '@agentclientprotocol/sdk';
2
2
  import type { InitializeResponse, RequestPermissionRequest, RequestPermissionResponse, SessionNotification } from '@agentclientprotocol/sdk';
3
3
  import type { AcpLaunchSpec } from './types.js';
4
+ import { type AcpTerminalPolicy } from './client-services.js';
4
5
  export type AcpProcessClientHandlers = {
5
6
  onSessionUpdate(params: SessionNotification): void | Promise<void>;
6
7
  onPermission(params: RequestPermissionRequest): Promise<RequestPermissionResponse>;
@@ -21,6 +22,7 @@ export declare class AcpProcessClient {
21
22
  writeTextFile?: boolean;
22
23
  terminal?: boolean;
23
24
  terminalAuth?: boolean;
25
+ terminalPolicy?: AcpTerminalPolicy;
24
26
  }, timeouts?: {
25
27
  initializeMs?: number;
26
28
  sessionMs?: number;
@@ -16,7 +16,7 @@ export type AgentEvent = {
16
16
  result?: string;
17
17
  durationMs?: number;
18
18
  message?: string;
19
- errorCode?: 'acp_auth_required';
19
+ errorCode?: 'acp_auth_required' | 'auth_required' | 'auth_retrying';
20
20
  approval?: {
21
21
  title?: string;
22
22
  content?: string;
@@ -23,6 +23,7 @@ export declare class ClaudeAdapter extends AgentAdapter {
23
23
  private runId;
24
24
  private hasEmittedText;
25
25
  private terminalState;
26
+ private authenticationRetrying;
26
27
  private pendingSuccess;
27
28
  private persistNativeSession;
28
29
  private managedAgentPolicy;
@@ -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(`
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?`
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 C,buildManagedNativeFullProcessEnv as I}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 R}from"./claude-managed-permissions.js";w("claude",_);function T(n){return n?.trim()||"default"}const M=new Set(["low","medium","high","xhigh","max"]),h=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 W(){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";authenticationRetrying=!1;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,u,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 l=this.options.systemPrompt??g(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,u);l&&i.push("--append-system-prompt",l),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",T(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||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 u="";s.stderr?.on("data",r=>{const i=r.toString();if(u+=i,this.terminalState==="open")for(const l of i.split(`
3
+ `)){const d=l.trim();N(d)&&this.emitEvent({state:"delta",text:d+`
4
+ `})}}),s.on("close",r=>{this.process===s&&(this.process=null,this.handleProcessClose(r,u))}),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 R(k(e),e.adapterPolicy.workDir,{internalReadPaths:t.readPaths,internalUnixSockets:t.unixSockets,shellSubprocessPolicy:e.environmentPolicy.shellSubprocess})}buildProcessEnv(){return this.managedAgentPolicy?c(this.managedAgentPolicy)?I({NO_COLOR:"1",...this.extraEnv}):C({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.authenticationRetrying=!0,this.emitEvent({state:"heartbeat",runPhase:"thinking",errorCode:"auth_retrying",message:"Claude authentication is retrying."});return}if(e.type==="assistant"){if(this.authenticationRetrying=!1,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",...this.authenticationRetrying?{errorCode:"auth_required"}:{}})}handleProcessClose(e,t){if(e!==0&&e!==null){const s=t.trim()||`claude exited with code ${e}`;this.emitErrorIfOpen({state:"error",message:s,...this.authenticationRetrying?{errorCode:"auth_required"}:{}});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.authenticationRetrying=!1,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 u=0;u<8;u+=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,T as normalizeClaudeModelId,O as normalizeClaudeReasoningEffort,W as resetClaudeCapabilityCacheForTests,L as resolveClaudeManagedInternalAccess,U as resolveClaudeShennianCliReadPaths,N as shouldForwardClaudeStderrLine,D as supportsClaudeReasoningEffort};
@@ -0,0 +1,16 @@
1
+ import type { AgentEvent } from './adapter.js';
2
+ /**
3
+ * Provider adapters do not all expose the same native lifecycle. This gate is
4
+ * the common, provider-independent boundary that makes a Shennian run
5
+ * terminal exactly once and hides every late event for that run.
6
+ *
7
+ * The bounded history protects long-lived daemon sessions without relying on
8
+ * provider run ids being globally unique forever.
9
+ */
10
+ export declare class AgentEventTerminalGate {
11
+ private readonly historyLimit;
12
+ private readonly terminalRunIds;
13
+ private readonly terminalOrder;
14
+ constructor(historyLimit?: number);
15
+ accept(event: AgentEvent): boolean;
16
+ }
@@ -0,0 +1 @@
1
+ const e=new Set(["final","error","aborted"]);class n{historyLimit;terminalRunIds=new Set;terminalOrder=[];constructor(t=256){this.historyLimit=t}accept(t){if(this.terminalRunIds.has(t.runId))return!1;if(!e.has(t.state))return!0;for(this.terminalRunIds.add(t.runId),this.terminalOrder.push(t.runId);this.terminalOrder.length>this.historyLimit;){const r=this.terminalOrder.shift();r!==void 0&&this.terminalRunIds.delete(r)}return!0}}export{n as AgentEventTerminalGate};
@@ -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};