shennian 0.5.1 → 0.5.3

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 +65 -70
  2. package/dist/src/agents/acp/adapter.js +2 -2
  3. package/dist/src/agents/acp/client-services.js +1 -1
  4. package/dist/src/agents/acp/process-client.js +1 -1
  5. package/dist/src/agents/config-status.js +1 -1
  6. package/dist/src/agents/model-registry/cache.js +1 -1
  7. package/dist/src/agents/model-registry/discovery.js +3 -3
  8. package/dist/src/agents/model-registry/opencode-api.js +1 -1
  9. package/dist/src/agents/model-registry/service.js +1 -1
  10. package/dist/src/agents/model-registry.js +1 -1
  11. package/dist/src/agents/opencode.js +1 -1
  12. package/dist/src/agents/pi-coding-agent.js +3 -4
  13. package/dist/src/agents/pi-turn-diagnostics.js +1 -0
  14. package/dist/src/agents/process-tree.js +1 -0
  15. package/dist/src/commands/agent-readiness.js +2 -2
  16. package/dist/src/commands/room.js +3 -3
  17. package/dist/src/daemon-ipc/agent-readiness.js +1 -1
  18. package/dist/src/index.js +3 -3
  19. package/dist/src/manager/runtime.js +4 -4
  20. package/dist/src/room/activation-service.js +1 -1
  21. package/dist/src/room/attachment-upload.js +1 -1
  22. package/dist/src/room/managed-room-ipc.js +2 -2
  23. package/dist/src/room/mirror-sync-service.js +1 -1
  24. package/dist/src/room/room-action-client.js +1 -1
  25. package/dist/src/session/handlers/agent-workspace-validation.js +1 -1
  26. package/dist/src/session/handlers/chat-events.js +2 -2
  27. package/dist/src/session/handlers/chat-recovery.js +1 -1
  28. package/dist/src/session/handlers/chat.js +1 -1
  29. package/dist/src/session/manager.js +1 -1
  30. package/dist/src/session/queue.js +1 -1
  31. package/node_modules/@shennian/wire/dist/session.js +1 -1
  32. package/package.json +1 -1
  33. package/dist/src/agents/acp/process-tree.js +0 -1
  34. package/dist/src/agents/pi-managed-model-broker.js +0 -1
  35. package/dist/src/session/handlers/pi-validation-session.js +0 -1
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "jsMinified": true,
4
4
  "minifier": "esbuild",
5
- "fileCount": 236,
5
+ "fileCount": 235,
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": 25920,
20
- "afterBytes": 13755
19
+ "beforeBytes": 26392,
20
+ "afterBytes": 13813
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": 6336,
45
- "afterBytes": 3535
44
+ "beforeBytes": 6337,
45
+ "afterBytes": 3536
46
46
  },
47
47
  {
48
48
  "file": "src/agents/acp/discovery.js",
@@ -71,13 +71,8 @@
71
71
  },
72
72
  {
73
73
  "file": "src/agents/acp/process-client.js",
74
- "beforeBytes": 7304,
75
- "afterBytes": 4420
76
- },
77
- {
78
- "file": "src/agents/acp/process-tree.js",
79
- "beforeBytes": 698,
80
- "afterBytes": 371
74
+ "beforeBytes": 7305,
75
+ "afterBytes": 4421
81
76
  },
82
77
  {
83
78
  "file": "src/agents/acp/types.js",
@@ -146,8 +141,8 @@
146
141
  },
147
142
  {
148
143
  "file": "src/agents/config-status.js",
149
- "beforeBytes": 7976,
150
- "afterBytes": 4126
144
+ "beforeBytes": 7855,
145
+ "afterBytes": 3923
151
146
  },
152
147
  {
153
148
  "file": "src/agents/cursor-managed-permissions.js",
@@ -201,18 +196,18 @@
201
196
  },
202
197
  {
203
198
  "file": "src/agents/model-registry/cache.js",
204
- "beforeBytes": 1491,
205
- "afterBytes": 640
199
+ "beforeBytes": 1745,
200
+ "afterBytes": 673
206
201
  },
207
202
  {
208
203
  "file": "src/agents/model-registry/discovery.js",
209
- "beforeBytes": 11711,
210
- "afterBytes": 5499
204
+ "beforeBytes": 11107,
205
+ "afterBytes": 5219
211
206
  },
212
207
  {
213
208
  "file": "src/agents/model-registry/opencode-api.js",
214
- "beforeBytes": 3026,
215
- "afterBytes": 1539
209
+ "beforeBytes": 3259,
210
+ "afterBytes": 1580
216
211
  },
217
212
  {
218
213
  "file": "src/agents/model-registry/parsers.js",
@@ -226,8 +221,8 @@
226
221
  },
227
222
  {
228
223
  "file": "src/agents/model-registry/service.js",
229
- "beforeBytes": 8102,
230
- "afterBytes": 3106
224
+ "beforeBytes": 9489,
225
+ "afterBytes": 3505
231
226
  },
232
227
  {
233
228
  "file": "src/agents/model-registry/types.js",
@@ -236,8 +231,8 @@
236
231
  },
237
232
  {
238
233
  "file": "src/agents/model-registry.js",
239
- "beforeBytes": 964,
240
- "afterBytes": 876
234
+ "beforeBytes": 986,
235
+ "afterBytes": 928
241
236
  },
242
237
  {
243
238
  "file": "src/agents/native-capabilities.js",
@@ -256,8 +251,8 @@
256
251
  },
257
252
  {
258
253
  "file": "src/agents/opencode.js",
259
- "beforeBytes": 13286,
260
- "afterBytes": 6985
254
+ "beforeBytes": 13890,
255
+ "afterBytes": 7062
261
256
  },
262
257
  {
263
258
  "file": "src/agents/pi-coding-agent-managed-permissions.js",
@@ -266,19 +261,14 @@
266
261
  },
267
262
  {
268
263
  "file": "src/agents/pi-coding-agent.js",
269
- "beforeBytes": 26430,
270
- "afterBytes": 14271
264
+ "beforeBytes": 28451,
265
+ "afterBytes": 15071
271
266
  },
272
267
  {
273
268
  "file": "src/agents/pi-managed-extension.js",
274
269
  "beforeBytes": 10227,
275
270
  "afterBytes": 9273
276
271
  },
277
- {
278
- "file": "src/agents/pi-managed-model-broker.js",
279
- "beforeBytes": 8635,
280
- "afterBytes": 4663
281
- },
282
272
  {
283
273
  "file": "src/agents/pi-rpc-client.js",
284
274
  "beforeBytes": 5326,
@@ -289,11 +279,21 @@
289
279
  "beforeBytes": 2397,
290
280
  "afterBytes": 1328
291
281
  },
282
+ {
283
+ "file": "src/agents/pi-turn-diagnostics.js",
284
+ "beforeBytes": 7200,
285
+ "afterBytes": 3920
286
+ },
292
287
  {
293
288
  "file": "src/agents/platform-instructions.js",
294
289
  "beforeBytes": 2829,
295
290
  "afterBytes": 1705
296
291
  },
292
+ {
293
+ "file": "src/agents/process-tree.js",
294
+ "beforeBytes": 2647,
295
+ "afterBytes": 856
296
+ },
297
297
  {
298
298
  "file": "src/agents/runtime-compatibility.js",
299
299
  "beforeBytes": 1587,
@@ -321,8 +321,8 @@
321
321
  },
322
322
  {
323
323
  "file": "src/commands/agent-readiness.js",
324
- "beforeBytes": 7032,
325
- "afterBytes": 5639
324
+ "beforeBytes": 7770,
325
+ "afterBytes": 6041
326
326
  },
327
327
  {
328
328
  "file": "src/commands/agent.js",
@@ -406,8 +406,8 @@
406
406
  },
407
407
  {
408
408
  "file": "src/commands/room.js",
409
- "beforeBytes": 18602,
410
- "afterBytes": 10736
409
+ "beforeBytes": 18609,
410
+ "afterBytes": 10774
411
411
  },
412
412
  {
413
413
  "file": "src/commands/runtime.js",
@@ -441,8 +441,8 @@
441
441
  },
442
442
  {
443
443
  "file": "src/daemon-ipc/agent-readiness.js",
444
- "beforeBytes": 4838,
445
- "afterBytes": 2425
444
+ "beforeBytes": 5145,
445
+ "afterBytes": 2587
446
446
  },
447
447
  {
448
448
  "file": "src/daemon-ipc/client.js",
@@ -516,8 +516,8 @@
516
516
  },
517
517
  {
518
518
  "file": "src/index.js",
519
- "beforeBytes": 42379,
520
- "afterBytes": 20999
519
+ "beforeBytes": 42698,
520
+ "afterBytes": 21157
521
521
  },
522
522
  {
523
523
  "file": "src/log-redaction.js",
@@ -546,8 +546,8 @@
546
546
  },
547
547
  {
548
548
  "file": "src/manager/runtime.js",
549
- "beforeBytes": 35299,
550
- "afterBytes": 17196
549
+ "beforeBytes": 35692,
550
+ "afterBytes": 17388
551
551
  },
552
552
  {
553
553
  "file": "src/manager/worker-ipc.js",
@@ -706,8 +706,8 @@
706
706
  },
707
707
  {
708
708
  "file": "src/room/activation-service.js",
709
- "beforeBytes": 28566,
710
- "afterBytes": 15641
709
+ "beforeBytes": 28666,
710
+ "afterBytes": 15706
711
711
  },
712
712
  {
713
713
  "file": "src/room/attachment-cache.js",
@@ -716,8 +716,8 @@
716
716
  },
717
717
  {
718
718
  "file": "src/room/attachment-upload.js",
719
- "beforeBytes": 6996,
720
- "afterBytes": 3546
719
+ "beforeBytes": 7283,
720
+ "afterBytes": 3698
721
721
  },
722
722
  {
723
723
  "file": "src/room/device-authorization-client.js",
@@ -761,13 +761,13 @@
761
761
  },
762
762
  {
763
763
  "file": "src/room/managed-room-ipc.js",
764
- "beforeBytes": 15469,
765
- "afterBytes": 7269
764
+ "beforeBytes": 15570,
765
+ "afterBytes": 7327
766
766
  },
767
767
  {
768
768
  "file": "src/room/mirror-sync-service.js",
769
- "beforeBytes": 12115,
770
- "afterBytes": 5558
769
+ "beforeBytes": 12375,
770
+ "afterBytes": 5688
771
771
  },
772
772
  {
773
773
  "file": "src/room/public-attachment-cache.js",
@@ -791,8 +791,8 @@
791
791
  },
792
792
  {
793
793
  "file": "src/room/room-action-client.js",
794
- "beforeBytes": 29197,
795
- "afterBytes": 14837
794
+ "beforeBytes": 29246,
795
+ "afterBytes": 14863
796
796
  },
797
797
  {
798
798
  "file": "src/room/room-binding-client.js",
@@ -896,8 +896,8 @@
896
896
  },
897
897
  {
898
898
  "file": "src/session/handlers/agent-workspace-validation.js",
899
- "beforeBytes": 9845,
900
- "afterBytes": 5250
899
+ "beforeBytes": 10525,
900
+ "afterBytes": 5385
901
901
  },
902
902
  {
903
903
  "file": "src/session/handlers/agents.js",
@@ -916,13 +916,13 @@
916
916
  },
917
917
  {
918
918
  "file": "src/session/handlers/chat-events.js",
919
- "beforeBytes": 17576,
920
- "afterBytes": 7241
919
+ "beforeBytes": 18625,
920
+ "afterBytes": 7583
921
921
  },
922
922
  {
923
923
  "file": "src/session/handlers/chat-recovery.js",
924
- "beforeBytes": 6623,
925
- "afterBytes": 3485
924
+ "beforeBytes": 6918,
925
+ "afterBytes": 3623
926
926
  },
927
927
  {
928
928
  "file": "src/session/handlers/chat-session-lifecycle.js",
@@ -931,8 +931,8 @@
931
931
  },
932
932
  {
933
933
  "file": "src/session/handlers/chat.js",
934
- "beforeBytes": 35005,
935
- "afterBytes": 14959
934
+ "beforeBytes": 35377,
935
+ "afterBytes": 15049
936
936
  },
937
937
  {
938
938
  "file": "src/session/handlers/control.js",
@@ -949,11 +949,6 @@
949
949
  "beforeBytes": 676,
950
950
  "afterBytes": 392
951
951
  },
952
- {
953
- "file": "src/session/handlers/pi-validation-session.js",
954
- "beforeBytes": 2016,
955
- "afterBytes": 1147
956
- },
957
952
  {
958
953
  "file": "src/session/handlers/project-fs.js",
959
954
  "beforeBytes": 3778,
@@ -1006,8 +1001,8 @@
1006
1001
  },
1007
1002
  {
1008
1003
  "file": "src/session/manager.js",
1009
- "beforeBytes": 40247,
1010
- "afterBytes": 21132
1004
+ "beforeBytes": 40733,
1005
+ "afterBytes": 21391
1011
1006
  },
1012
1007
  {
1013
1008
  "file": "src/session/native-cleanup-outbox.js",
@@ -1071,8 +1066,8 @@
1071
1066
  },
1072
1067
  {
1073
1068
  "file": "src/session/queue.js",
1074
- "beforeBytes": 40313,
1075
- "afterBytes": 17923
1069
+ "beforeBytes": 41453,
1070
+ "afterBytes": 18387
1076
1071
  },
1077
1072
  {
1078
1073
  "file": "src/session/queued-chat-dispatch.js",
@@ -1,3 +1,3 @@
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(`
1
+ import{randomUUID as g}from"node:crypto";import{createHash as f}from"node:crypto";import{realpathSync as y}from"node:fs";import{pathToFileURL as v}from"node:url";import*as l from"@agentclientprotocol/sdk";import{RequestError as C}from"@agentclientprotocol/sdk";import{AgentAdapter as A,registerAgent as P}from"../adapter.js";import{mapAcpSessionUpdate as q}from"./events.js";import{AcpProcessClient as E}from"./process-client.js";import{acpAgentType as S}from"./types.js";import{runAcpTerminalAuthentication as b}from"./auth.js";import{setAcpRuntimeAuthState as d}from"./auth-state.js";import{recordAcpAuthFailure as x,recordAcpImportResult as I}from"./metrics.js";import{isManagedAgentNativeFull as w}from"../../security/managed-agent-policy.js";import{buildManagedNativeFullProcessEnv as O}from"../../agent-env.js";function p(c,e){return c.find(t=>t.category===e&&t.type==="select")}function m(c){return(c?.options??[]).flatMap(e=>"options"in e?e.options:[e])}class T extends A{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=S(e.id)}configure(e){this.extraEnv=e.env??{},this.managedAgentPolicy=e.managedAgentPolicy??null,this.configurationSignature=f("sha256").update(JSON.stringify({env:Object.entries(this.extraEnv).sort(([t],[n])=>t.localeCompare(n)),managedAgentPolicy:this.managedAgentPolicy})).digest("hex")}async start(e,t,n){this.shennianSessionId=e;try{this.workDir=y.native(t)}catch{this.workDir=t}this.requestedSessionId=n??null,this.agentSessionId=null,this.client=this.createProcessClient(),await this.client.start(this.workDir),this.startedConfigurationSignature=this.configurationSignature}async send(e,t,n,i,s){await this.refreshProcessConfiguration();const a=this.requireClient();this.runId=g(),this.seq=0,this.emittedToolStates.clear();try{await this.ensureSession(),await this.applyDynamicConfig(t,n),this.active=!0,this.emitEvent({state:"start",runPhase:"thinking",agentSessionId:this.agentSessionId??void 0});const o=[],r=[];s?.trim()&&r.push(s.trim()),r.push(e),o.push({type:"text",text:r.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,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};
3
+ `)});for(const h of i??[])o.push({type:"resource_link",uri:v(h.path).href,name:h.name,mimeType:h.mimeType,size:h.byteSize});const u=await this.promptWithTimeout(a,o);this.active=!1,u.stopReason==="cancelled"?this.emitEvent({state:"aborted",agentSessionId:this.agentSessionId??void 0}):this.emitEvent({state:"final",agentSessionId:this.agentSessionId??void 0})}catch(o){this.active=!1,this.cancelPendingPermissions();const r=o instanceof Error?o.message:String(o),u=o instanceof C&&o.code===-32e3;throw u&&(d(this.type,"required"),this.retryingAfterAuth||(this.pendingAuthRetry={text:e,...t?{modelId:t}:{},...n?{reasoningEffort:n}:{},...i?{attachments:[...i]}:{},...s!==void 0?{systemPrompt:s}:{}})),this.emitEvent({state:"error",message:r,...u?{errorCode:"acp_auth_required"}:{},agentSessionId:this.agentSessionId??void 0}),o}}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 n=this.pendingPermissions.get(e);if(!n)throw new Error("ACP permission request is no longer pending");if(!n.optionIds.has(t))throw new Error("Invalid ACP permission option");this.pendingPermissions.delete(e),clearTimeout(n.timer),n.resolve({outcome:{outcome:"selected",optionId:t}})}getAuthMethods(){return[...this.requireClient().initializeResponse?.authMethods??[]]}hasPendingAuthenticationRetry(){return this.pendingAuthRetry!==null}getSessionOptions(){const e=p(this.configOptions,"model"),t=p(this.configOptions,"thought_level"),n=this.modes?.availableModes.map(s=>({id:s.id,name:s.name,...s.description?{description:s.description}:{}}))??[],i=(t?m(t):n).map(s=>({id:"value"in s?s.value:s.id,name:s.name,...s.description?{description:s.description}:{}}));return{models:m(e).map(s=>({id:s.value,name:s.name,...s.description?{description:s.description}:{},...s.value===e?.currentValue?{isDefault:!0}:{},...i.length?{supportedReasoningEfforts:i}:{}})),modes:n}}async authenticate(e,t={}){const n=this.requireClient(),i=n.initializeResponse?.authMethods?.find(s=>s.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 n.close(),await b({...this.manifest.authLaunch??this.manifest.launch,env:Object.fromEntries(Object.entries({...this.extraEnv,...this.manifest.authLaunch?.env??this.manifest.launch.env}).filter(s=>typeof s[1]=="string"))},i,this.workDir)}else await n.authenticate(e);await this.resumeAfterExternalAuthentication()}catch(s){throw x(),s}}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 n=[];let i;for(let s=0;s<10&&n.length<500;s+=1){let a=e.cwd;if(a)try{a=y.native(a)}catch{}const o=await t.listSessions(a,i);if(n.push(...o.sessions.slice(0,500-n.length).map(r=>({agentSessionId:r.sessionId,cwd:r.cwd,...r.title?{title:r.title.slice(0,200)}:{},...r.updatedAt?{updatedAt:r.updatedAt}:{}}))),i=o.nextCursor,!i)break}return n}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 n=[];this.importCapture=n;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,I(!0)}catch(i){throw I(!1),i}finally{this.importCapture=null}return n.map((i,s)=>({sourceId:i.sourceHint??f("sha256").update(`${e}\0${s}\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 n=e.capabilities;if(n.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(n.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,this.emit("sessionOptions");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,this.emit("sessionOptions")}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 n=[{category:"model",value:e},{category:"thought_level",value:t}];for(const i of n){if(!i.value)continue;const s=p(this.configOptions,i.category);!s||s.currentValue===i.value||m(s).some(a=>a.value===i.value)&&(await this.requireClient().agent.request(l.methods.agent.session.setConfigOption,{sessionId:this.agentSessionId,configId:s.id,value:i.value}),s.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 q(e.update,n=>this.makeEvent(n)))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}]`,n=e.sessionUpdate==="user_message_chunk"?"user":"agent",i=e.messageId?`message:${e.messageId}`:void 0,s=i?this.importCapture.find(a=>a.sourceHint===i):this.importCapture.at(-1);s?.role===n&&s.sourceHint===i?s.payload+=t:this.importCapture.push({role:n,payload:t,...i?{sourceHint:i}:{}});return}if(e.sessionUpdate==="tool_call"){const t=`tool:${e.toolCallId}`,n=this.importCapture.find(s=>s.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"})};n?n.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}`),n=JSON.stringify({v:1,type:"tool_result",name:e.title??"tool",toolCallId:e.toolCallId,status:e.status});t?t.payload=n:this.importCapture.push({role:"agent",sourceHint:`tool:${e.toolCallId}`,payload:n})}}}handlePermission(e){if(!this.active||e.sessionId!==this.agentSessionId)return Promise.resolve({outcome:{outcome:"cancelled"}});const t=g();return new Promise(n=>{const i=setTimeout(()=>{this.pendingPermissions.delete(t),n({outcome:{outcome:"cancelled"}})},this.options.permissionTimeoutMs??3e5);i.unref?.(),this.pendingPermissions.set(t,{optionIds:new Set(e.options.map(s=>s.optionId)),resolve:n,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(s=>({id:s.optionId,name:s.name,kind:s.kind}))}})})}requireClient(){if(!this.client)throw new Error("ACP adapter has not started");return this.client}createProcessClient(){return new E(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?w(this.managedAgentPolicy)?O(this.extraEnv):{...this.extraEnv}:{...process.env,...this.extraEnv}}buildClientCapabilities(){const e=this.manifest.clientCapabilities??{},t=this.managedAgentPolicy?.adapterPolicy;return t?w(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 n;try{return await Promise.race([e.agent.request(l.methods.agent.session.prompt,{sessionId:this.agentSessionId,prompt:t}),new Promise((i,s)=>{n=setTimeout(()=>s(new Error("ACP prompt timed out")),this.options.promptTimeoutMs??720*6e4),n.unref?.()})])}catch(i){throw i instanceof Error&&i.message==="ACP prompt timed out"&&(await e.close(),this.client===e&&(this.client=null)),i}finally{n&&clearTimeout(n)}}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 L(c){P(S(c.id),()=>new T(c))}export{T as AcpAgentAdapter,L as registerAcpAgent};
@@ -1,3 +1,3 @@
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(`
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
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
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 +1 @@
1
- import{spawn as m}from"node:child_process";import{Readable as d,Transform as p,Writable as S}from"node:stream";import*as n from"@agentclientprotocol/sdk";import{AcpClientServices as f}from"./client-services.js";import{terminateProcessTree as h}from"./process-tree.js";class _{launch;handlers;environment;clientCapabilities;timeouts;process=null;connection=null;initialization=null;stderr="";clientServices=null;constructor(i,t,s=process.env,r={},o={}){this.launch=i,this.handlers=t,this.environment=s,this.clientCapabilities=r,this.timeouts=o}get capabilities(){return this.initialization?.agentCapabilities??{}}get initializeResponse(){return this.initialization}async listSessions(i,t){return a(this.agent.request(n.methods.agent.session.list,{cwd:i,cursor:t}),this.timeouts.sessionMs??8e3,"ACP session list timed out")}async authenticate(i){await a(this.agent.request(n.methods.agent.authenticate,{methodId:i}),this.timeouts.authMs??12e4,"ACP authentication timed out")}async logout(){await a(this.agent.request(n.methods.agent.logout,{}),8e3,"ACP logout timed out")}async closeSession(i){await a(this.agent.request(n.methods.agent.session.close,{sessionId:i}),8e3,"ACP session close timed out")}async deleteSession(i){await a(this.agent.request(n.methods.agent.session.delete,{sessionId:i}),8e3,"ACP session delete timed out")}get agent(){if(!this.connection)throw new Error("ACP process is not connected");return this.connection.agent}async start(i){if(this.connection)return this.initialization;const t=m(this.launch.command,this.launch.args??[],{cwd:i,env:{...this.environment,...this.launch.env},stdio:["pipe","pipe","pipe"],detached:process.platform!=="win32",windowsHide:!0});this.process=t,t.stderr.on("data",e=>{this.stderr.length<16384&&(this.stderr+=e.toString())}),this.clientServices=Object.values(this.clientCapabilities).some(Boolean)?new f(i,this.clientCapabilities,{...this.environment,...this.launch.env}):null;let s=n.client({name:"Shennian"}).onRequest(n.methods.client.session.requestPermission,({params:e})=>this.handlers.onPermission(e)).onNotification(n.methods.client.session.update,({params:e})=>this.handlers.onSessionUpdate(e));this.clientServices?.enabled.readTextFile&&(s=s.onRequest(n.methods.client.fs.readTextFile,({params:e})=>this.clientServices.readTextFile(e))),this.clientServices?.enabled.writeTextFile&&(s=s.onRequest(n.methods.client.fs.writeTextFile,({params:e})=>this.clientServices.writeTextFile(e))),this.clientServices?.enabled.terminal&&(s=s.onRequest(n.methods.client.terminal.create,({params:e})=>this.clientServices.createTerminal(e)).onRequest(n.methods.client.terminal.output,({params:e})=>this.clientServices.terminalOutput(e)).onRequest(n.methods.client.terminal.waitForExit,({params:e})=>this.clientServices.waitForTerminalExit(e)).onRequest(n.methods.client.terminal.kill,({params:e})=>this.clientServices.killTerminal(e)).onRequest(n.methods.client.terminal.release,({params:e})=>this.clientServices.releaseTerminal(e)));const r=new p({transform:v(()=>h(t,!0))});t.stdout.pipe(r);const o=n.ndJsonStream(S.toWeb(t.stdin),d.toWeb(r)),l=s.connect(o);this.connection=l,t.once("error",e=>l.close(e)),t.once("exit",(e,u)=>{l.close(new Error(`ACP agent exited (${e??u??"unknown"})`))});try{const e=await a(l.agent.request(n.methods.agent.initialize,{protocolVersion:n.PROTOCOL_VERSION,clientCapabilities:{...this.clientServices?.capabilities??{},...this.clientCapabilities.terminalAuth?{auth:{terminal:!0}}:{}},clientInfo:{name:"Shennian",version:"0.4.13"}}),this.timeouts.initializeMs??8e3,"ACP initialize timed out");if(e.protocolVersion!==n.PROTOCOL_VERSION)throw new Error(`Unsupported ACP protocol version ${e.protocolVersion}`);return this.initialization=e,e}catch(e){throw await this.close(),e}}async close(){const i=this.connection,t=this.process;this.connection=null,this.process=null,this.initialization=null,this.clientServices?.close(),this.clientServices=null,i?.close(),t&&t.exitCode===null&&t.signalCode===null&&(h(t),setTimeout(()=>h(t,!0),2e3).unref?.())}}const g=4*1024*1024,w=64*1024*1024;function v(c){let i=0,t=0;return function(s,r,o){i+=s.length;for(const l of s)t=l===10?0:t+1;if(i>w||t>g){c(),o(new Error("ACP output exceeded safety limit"));return}o(null,s)}}async function a(c,i,t){let s;try{return await Promise.race([c,new Promise((r,o)=>{s=setTimeout(()=>o(new Error(t)),i)})])}finally{s&&clearTimeout(s)}}export{_ as AcpProcessClient};
1
+ import{spawn as m}from"node:child_process";import{Readable as d,Transform as p,Writable as S}from"node:stream";import*as n from"@agentclientprotocol/sdk";import{AcpClientServices as f}from"./client-services.js";import{terminateProcessTree as h}from"../process-tree.js";class _{launch;handlers;environment;clientCapabilities;timeouts;process=null;connection=null;initialization=null;stderr="";clientServices=null;constructor(i,t,s=process.env,r={},o={}){this.launch=i,this.handlers=t,this.environment=s,this.clientCapabilities=r,this.timeouts=o}get capabilities(){return this.initialization?.agentCapabilities??{}}get initializeResponse(){return this.initialization}async listSessions(i,t){return a(this.agent.request(n.methods.agent.session.list,{cwd:i,cursor:t}),this.timeouts.sessionMs??8e3,"ACP session list timed out")}async authenticate(i){await a(this.agent.request(n.methods.agent.authenticate,{methodId:i}),this.timeouts.authMs??12e4,"ACP authentication timed out")}async logout(){await a(this.agent.request(n.methods.agent.logout,{}),8e3,"ACP logout timed out")}async closeSession(i){await a(this.agent.request(n.methods.agent.session.close,{sessionId:i}),8e3,"ACP session close timed out")}async deleteSession(i){await a(this.agent.request(n.methods.agent.session.delete,{sessionId:i}),8e3,"ACP session delete timed out")}get agent(){if(!this.connection)throw new Error("ACP process is not connected");return this.connection.agent}async start(i){if(this.connection)return this.initialization;const t=m(this.launch.command,this.launch.args??[],{cwd:i,env:{...this.environment,...this.launch.env},stdio:["pipe","pipe","pipe"],detached:process.platform!=="win32",windowsHide:!0});this.process=t,t.stderr.on("data",e=>{this.stderr.length<16384&&(this.stderr+=e.toString())}),this.clientServices=Object.values(this.clientCapabilities).some(Boolean)?new f(i,this.clientCapabilities,{...this.environment,...this.launch.env}):null;let s=n.client({name:"Shennian"}).onRequest(n.methods.client.session.requestPermission,({params:e})=>this.handlers.onPermission(e)).onNotification(n.methods.client.session.update,({params:e})=>this.handlers.onSessionUpdate(e));this.clientServices?.enabled.readTextFile&&(s=s.onRequest(n.methods.client.fs.readTextFile,({params:e})=>this.clientServices.readTextFile(e))),this.clientServices?.enabled.writeTextFile&&(s=s.onRequest(n.methods.client.fs.writeTextFile,({params:e})=>this.clientServices.writeTextFile(e))),this.clientServices?.enabled.terminal&&(s=s.onRequest(n.methods.client.terminal.create,({params:e})=>this.clientServices.createTerminal(e)).onRequest(n.methods.client.terminal.output,({params:e})=>this.clientServices.terminalOutput(e)).onRequest(n.methods.client.terminal.waitForExit,({params:e})=>this.clientServices.waitForTerminalExit(e)).onRequest(n.methods.client.terminal.kill,({params:e})=>this.clientServices.killTerminal(e)).onRequest(n.methods.client.terminal.release,({params:e})=>this.clientServices.releaseTerminal(e)));const r=new p({transform:v(()=>h(t,!0))});t.stdout.pipe(r);const o=n.ndJsonStream(S.toWeb(t.stdin),d.toWeb(r)),l=s.connect(o);this.connection=l,t.once("error",e=>l.close(e)),t.once("exit",(e,u)=>{l.close(new Error(`ACP agent exited (${e??u??"unknown"})`))});try{const e=await a(l.agent.request(n.methods.agent.initialize,{protocolVersion:n.PROTOCOL_VERSION,clientCapabilities:{...this.clientServices?.capabilities??{},...this.clientCapabilities.terminalAuth?{auth:{terminal:!0}}:{}},clientInfo:{name:"Shennian",version:"0.4.13"}}),this.timeouts.initializeMs??8e3,"ACP initialize timed out");if(e.protocolVersion!==n.PROTOCOL_VERSION)throw new Error(`Unsupported ACP protocol version ${e.protocolVersion}`);return this.initialization=e,e}catch(e){throw await this.close(),e}}async close(){const i=this.connection,t=this.process;this.connection=null,this.process=null,this.initialization=null,this.clientServices?.close(),this.clientServices=null,i?.close(),t&&t.exitCode===null&&t.signalCode===null&&(h(t),setTimeout(()=>h(t,!0),2e3).unref?.())}}const g=4*1024*1024,w=64*1024*1024;function v(c){let i=0,t=0;return function(s,r,o){i+=s.length;for(const l of s)t=l===10?0:t+1;if(i>w||t>g){c(),o(new Error("ACP output exceeded safety limit"));return}o(null,s)}}async function a(c,i,t){let s;try{return await Promise.race([c,new Promise((r,o)=>{s=setTimeout(()=>o(new Error(t)),i)})])}finally{s&&clearTimeout(s)}}export{_ as AcpProcessClient};
@@ -1 +1 @@
1
- import i from"node:fs";import E from"node:os";import c from"node:path";import{readLatestUserEnv as g}from"../agent-env.js";import{loadConfig as k,resolveShennianPath as S}from"../config/index.js";const a=S("agent-provider-config.json"),U=4;function A(e){return e==="codex"||e==="claude"||e==="pi"}const O={codex:{baseUrl:["OPENAI_BASE_URL","OPENAI_API_BASE","OPENAI_API_URL"],token:["OPENAI_API_KEY","OPENAI_TOKEN"]},claude:{baseUrl:["ANTHROPIC_BASE_URL","ANTHROPIC_API_URL"],token:["ANTHROPIC_API_KEY","ANTHROPIC_AUTH_TOKEN"]},pi:{baseUrl:["DASHSCOPE_BASE_URL","DASHSCOPE_API_BASE","DASHSCOPE_API_URL"],token:["DASHSCOPE_API_KEY","DASHSCOPE_TOKEN"]}};function P(e){return u().configs[e]}function v(e){const n=u(),o=n.configs[e.agent],t={agent:e.agent,baseUrl:e.baseUrl?.trim()||o?.baseUrl,token:e.token?.trim()||o?.token,updatedAt:new Date().toISOString()};return n.configs[e.agent]=t,_(n),t}function B(e){const n=u();delete n.configs[e],_(n)}function K(e){if(!A(e))return{};const n=P(e);return n?l(e==="codex"?{OPENAI_BASE_URL:n.baseUrl,OPENAI_API_KEY:n.token}:e==="claude"?{ANTHROPIC_BASE_URL:n.baseUrl,ANTHROPIC_API_KEY:n.token}:{DASHSCOPE_BASE_URL:n.baseUrl,DASHSCOPE_API_KEY:n.token}):{}}function j(e,n=g()){if(e==="pi-coding-agent"){const s=!!k().machineToken?.trim();return{status:s?"managed":"missing",source:"shennian",tokenPresent:!1,baseUrlHost:"shennian.net",...s?{}:{error:"Pair Shennian before using the managed Pi model."}}}if(!A(e))return;const o=P(e);if(o?.token||o?.baseUrl)return f({agent:e,source:"shennian",status:o.token?"managed":"missing",baseUrl:o.baseUrl,token:o.token,tokenPresent:!!o.token});const t=h(e,n);if(t.tokenPresent||t.baseUrl)return f({agent:e,source:"env",status:t.tokenPresent?"detected":"missing",baseUrl:t.baseUrl,token:t.token,tokenPresent:t.tokenPresent});const r=p(e);return r.tokenPresent||r.baseUrl?f({agent:e,source:"config-file",status:r.tokenPresent?"detected":"missing",baseUrl:r.baseUrl,token:r.token,tokenPresent:r.tokenPresent}):f({agent:e,source:"unknown",status:"missing",tokenPresent:!1})}function u(){try{return{configs:JSON.parse(i.readFileSync(a,"utf-8")).configs??{}}}catch{return{configs:{}}}}function _(e){i.mkdirSync(c.dirname(a),{recursive:!0}),i.writeFileSync(a,JSON.stringify(e,null,2),{mode:384});try{i.chmodSync(a,384)}catch{}}function l(e){const n={};for(const[o,t]of Object.entries(e))t&&(n[o]=t);return n}function h(e,n){const o=O[e],t=m(n,o.baseUrl),r=m(n,o.token);return{baseUrl:t,token:r,tokenPresent:!!r}}function m(e,n){for(const o of n){const t=e[o]?.trim();if(t)return t}}function p(e){const n=E.homedir();if(e==="pi"){const r=k().apiKeys?.dashscope?.trim();if(r)return{token:r,tokenPresent:!0}}const o=e==="codex"?[c.join(n,".codex","config.toml"),c.join(n,".codex","auth.json")]:e==="claude"?[c.join(n,".claude","settings.json"),c.join(n,".claude.json")]:[c.join(n,".dashscope","config.json")];for(const t of o){const r=I(t);if(!r)continue;const s=C(r,e),d=b(r);if(s||d)return{token:s,baseUrl:d,tokenPresent:!!s}}return{tokenPresent:!1}}function I(e){try{const n=i.statSync(e);return!n.isFile()||n.size>1024*1024?null:i.readFileSync(e,"utf-8")}catch{return null}}function b(e){return e.match(/(?:base_url|baseURL|api_url|apiUrl|ANTHROPIC_BASE_URL|OPENAI_BASE_URL|DASHSCOPE_BASE_URL)["'\s:=]+([^"'\s,}]+)/i)?.[1]?.trim()}function C(e,n){const o=n==="claude"?"sk-ant-":"sk-",t=e.match(new RegExp(`${o.replace(/-/g,"\\-")}[A-Za-z0-9_\\-]{8,}`));return t?.[0]?t[0]:e.match(/(?:api[_-]?key|auth[_-]?token|token|dashscope)["'\s:=]+([A-Za-z0-9_\-.]{12,})/i)?.[1]?.trim()}function f(e){return{status:e.status,source:e.source,tokenPresent:e.tokenPresent,...e.baseUrl?{baseUrlHost:H(e.baseUrl)}:{},...e.token?{tokenHint:N(e.token)}:{},updatedAt:new Date().toISOString()}}function N(e){const n=e.trim();return n?`\u2022\u2022\u2022\u2022${n.slice(-U)}`:""}function H(e){try{return new URL(e).host||e}catch{return e.replace(/^https?:\/\//i,"").replace(/\/.*$/,"")||e}}export{K as buildManagedAgentEnv,B as deleteManagedAgentProviderConfig,j as getAgentConfigSummary,P as getManagedAgentProviderConfig,N as maskToken,v as upsertManagedAgentProviderConfig};
1
+ import s from"node:fs";import m from"node:os";import i from"node:path";import{readLatestUserEnv as E}from"../agent-env.js";import{loadConfig as S,resolveShennianPath as g}from"../config/index.js";const c=g("agent-provider-config.json"),U=4;function A(e){return e==="codex"||e==="claude"||e==="pi"}const O={codex:{baseUrl:["OPENAI_BASE_URL","OPENAI_API_BASE","OPENAI_API_URL"],token:["OPENAI_API_KEY","OPENAI_TOKEN"]},claude:{baseUrl:["ANTHROPIC_BASE_URL","ANTHROPIC_API_URL"],token:["ANTHROPIC_API_KEY","ANTHROPIC_AUTH_TOKEN"]},pi:{baseUrl:["DASHSCOPE_BASE_URL","DASHSCOPE_API_BASE","DASHSCOPE_API_URL"],token:["DASHSCOPE_API_KEY","DASHSCOPE_TOKEN"]}};function k(e){return u().configs[e]}function v(e){const n=u(),o=n.configs[e.agent],t={agent:e.agent,baseUrl:e.baseUrl?.trim()||o?.baseUrl,token:e.token?.trim()||o?.token,updatedAt:new Date().toISOString()};return n.configs[e.agent]=t,_(n),t}function B(e){const n=u();delete n.configs[e],_(n)}function K(e){if(!A(e))return{};const n=k(e);return n?l(e==="codex"?{OPENAI_BASE_URL:n.baseUrl,OPENAI_API_KEY:n.token}:e==="claude"?{ANTHROPIC_BASE_URL:n.baseUrl,ANTHROPIC_API_KEY:n.token}:{DASHSCOPE_BASE_URL:n.baseUrl,DASHSCOPE_API_KEY:n.token}):{}}function j(e,n=E()){if(e==="pi-coding-agent"||!A(e))return;const o=k(e);if(o?.token||o?.baseUrl)return a({agent:e,source:"shennian",status:o.token?"managed":"missing",baseUrl:o.baseUrl,token:o.token,tokenPresent:!!o.token});const t=I(e,n);if(t.tokenPresent||t.baseUrl)return a({agent:e,source:"env",status:t.tokenPresent?"detected":"missing",baseUrl:t.baseUrl,token:t.token,tokenPresent:t.tokenPresent});const r=p(e);return r.tokenPresent||r.baseUrl?a({agent:e,source:"config-file",status:r.tokenPresent?"detected":"missing",baseUrl:r.baseUrl,token:r.token,tokenPresent:r.tokenPresent}):a({agent:e,source:"unknown",status:"missing",tokenPresent:!1})}function u(){try{return{configs:JSON.parse(s.readFileSync(c,"utf-8")).configs??{}}}catch{return{configs:{}}}}function _(e){s.mkdirSync(i.dirname(c),{recursive:!0}),s.writeFileSync(c,JSON.stringify(e,null,2),{mode:384});try{s.chmodSync(c,384)}catch{}}function l(e){const n={};for(const[o,t]of Object.entries(e))t&&(n[o]=t);return n}function I(e,n){const o=O[e],t=P(n,o.baseUrl),r=P(n,o.token);return{baseUrl:t,token:r,tokenPresent:!!r}}function P(e,n){for(const o of n){const t=e[o]?.trim();if(t)return t}}function p(e){const n=m.homedir();if(e==="pi"){const r=S().apiKeys?.dashscope?.trim();if(r)return{token:r,tokenPresent:!0}}const o=e==="codex"?[i.join(n,".codex","config.toml"),i.join(n,".codex","auth.json")]:e==="claude"?[i.join(n,".claude","settings.json"),i.join(n,".claude.json")]:[i.join(n,".dashscope","config.json")];for(const t of o){const r=C(t);if(!r)continue;const f=N(r,e),d=b(r);if(f||d)return{token:f,baseUrl:d,tokenPresent:!!f}}return{tokenPresent:!1}}function C(e){try{const n=s.statSync(e);return!n.isFile()||n.size>1024*1024?null:s.readFileSync(e,"utf-8")}catch{return null}}function b(e){return e.match(/(?:base_url|baseURL|api_url|apiUrl|ANTHROPIC_BASE_URL|OPENAI_BASE_URL|DASHSCOPE_BASE_URL)["'\s:=]+([^"'\s,}]+)/i)?.[1]?.trim()}function N(e,n){const o=n==="claude"?"sk-ant-":"sk-",t=e.match(new RegExp(`${o.replace(/-/g,"\\-")}[A-Za-z0-9_\\-]{8,}`));return t?.[0]?t[0]:e.match(/(?:api[_-]?key|auth[_-]?token|token|dashscope)["'\s:=]+([A-Za-z0-9_\-.]{12,})/i)?.[1]?.trim()}function a(e){return{status:e.status,source:e.source,tokenPresent:e.tokenPresent,...e.baseUrl?{baseUrlHost:R(e.baseUrl)}:{},...e.token?{tokenHint:h(e.token)}:{},updatedAt:new Date().toISOString()}}function h(e){const n=e.trim();return n?`\u2022\u2022\u2022\u2022${n.slice(-U)}`:""}function R(e){try{return new URL(e).host||e}catch{return e.replace(/^https?:\/\//i,"").replace(/\/.*$/,"")||e}}export{K as buildManagedAgentEnv,B as deleteManagedAgentProviderConfig,j as getAgentConfigSummary,k as getManagedAgentProviderConfig,h as maskToken,v as upsertManagedAgentProviderConfig};
@@ -1 +1 @@
1
- import t from"node:fs";import c from"node:path";import{CACHE_TTL_MS as a,CACHE_VERSION as i,MODEL_CACHE_PATH as n}from"./types.js";function f(){t.mkdirSync(c.dirname(n),{recursive:!0})}function C(){try{const e=JSON.parse(t.readFileSync(n,"utf-8"));if(e.version===i&&e.agents&&typeof e.agents=="object")return e}catch{}return{version:i,agents:{}}}function d(e){try{f(),t.writeFileSync(n,JSON.stringify(e,null,2))}catch{}}function l(e,o,r){if(!e||e.version!==o||r&&e.sourceRevision!==r)return!1;const s=r?.startsWith("opencode-connected-")?900*1e3:a;return Date.now()-e.refreshedAt<s}export{l as isCacheFresh,C as readCache,d as writeCache};
1
+ import e from"node:fs";import s from"node:path";import{CACHE_TTL_MS as a,CACHE_VERSION as i,MODEL_CACHE_PATH as n}from"./types.js";function f(){e.mkdirSync(s.dirname(n),{recursive:!0})}function h(){try{const r=JSON.parse(e.readFileSync(n,"utf-8"));if(r.version===i&&r.agents&&typeof r.agents=="object")return r}catch{}return{version:i,agents:{}}}function m(r){try{f(),e.writeFileSync(n,JSON.stringify(r,null,2))}catch{}}function l(r,o,t){if(!r||r.version!==o||t&&r.sourceRevision!==t)return!1;const c=t?.startsWith("opencode-connected-")||t?.startsWith("pi-configured-")?900*1e3:a;return Date.now()-r.refreshedAt<c}export{l as isCacheFresh,h as readCache,m as writeCache};
@@ -1,3 +1,3 @@
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
+ import{createInterface as _}from"node:readline";import{resolveBuiltinCommand as l,spawnResolvedCommand as w}from"../command-spec.js";import{fallbackClaudeAliasModels as E,discoverClaudeAliasModelsFromEnv as k,fallbackCodexModels as h,fallbackWorkBuddyModels as x,fallbackGeminiModels as R,parseCodexAppServerModels as O,parseCursorModels as A,parseOpenCodeModels as I}from"./parsers.js";import{runResolvedCommand as f}from"./runner.js";import{DISCOVERY_WORKDIR as M,ModelDiscoveryFallbackError as b}from"./types.js";import{buildAgentProcessEnv as C,readLatestUserEnv as P}from"../../agent-env.js";import{CODEX_APP_SERVER_CLIENT_INFO as S}from"../codex-utils.js";import{PiRpcClient as T}from"../pi-rpc-client.js";import{discoverOpenCodeModelsViaApi as $}from"./opencode-api.js";function D(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 m(r,e,t,n,s,i){return r.stdin?new Promise((o,a)=>{const p=setTimeout(()=>{e.delete(t),a(new Error(`codex app-server request timed out: ${n}`))},i);e.set(t,{resolve:o,reject:a,timer:p}),r.stdin.write(`${JSON.stringify({id:t,method:n,params:s})}
2
+ `,c=>{c&&(clearTimeout(p),e.delete(t),a(c))})}):Promise.reject(new Error("codex app-server stdin unavailable"))}async function L(r){const e=w(r,["app-server","--listen","stdio://"],{cwd:M,stdio:["pipe","pipe","pipe"],env:C({NO_COLOR:"1"})}),t=new Map;let n=1;_({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 m(e,t,n++,"initialize",{clientInfo:S,capabilities:{experimentalApi:!0}},1e4);const[i,o]=await Promise.all([m(e,t,n++,"model/list",{},15e3),m(e,t,n++,"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 f(r,["--list-models"]);return A(e.stdout)}async function j(){const r=l("opencode");if(!r)return[];const e=await $().catch(()=>[]);if(e.length>0)return e;const t=await f(r,["models"]);return I(t.stdout)}async function G(){const r=l("pi-coding-agent");if(!r)return[];const e=w(r,["--mode","rpc","--no-session","--offline","--no-extensions","--no-skills","--no-prompt-templates","--no-context-files","--no-tools"],{cwd:M,stdio:["pipe","pipe","pipe"],env:C({NO_COLOR:"1"})}),t=new T(e,{requestTimeoutMs:1e4});try{const[n,s]=await Promise.all([t.request("get_available_models"),t.request("get_state")]),i=n.data&&typeof n.data=="object"?n.data:{},o=s.data&&typeof s.data=="object"?s.data:{},a=typeof o.model?.id=="string"&&typeof o.model.provider=="string"?`${o.model.provider}/${o.model.id}`:null;return Array.isArray(i.models)?i.models.flatMap(c=>{if(!c||typeof c!="object")return[];const d=c;if(typeof d.id!="string"||typeof d.provider!="string")return[];const v=`${d.provider}/${d.id}`,y=d.reasoning===!0?["off","minimal","low","medium","high","xhigh","max"].map(g=>({id:g,name:g})):void 0;return[{id:v,name:typeof d.name=="string"&&d.name.trim()?d.name:d.id,provider:d.provider,isDefault:v===a,...y?{supportedReasoningEfforts:y,defaultReasoningEffort:"medium"}:{}}]}):[]}catch{return[]}finally{t.close(),e.kill("SIGTERM"),setTimeout(()=>e.kill("SIGKILL"),1e3).unref()}}async function N(){const r=l("claude");if(!r)return[];const e=P(),t=k(e);if(t.length>0)return t;const n=E(e),s=await f(r,["--help"],3e3).catch(()=>null);return!s||/\bfable\b/i.test(`${s.stdout}
3
+ ${s.stderr}`)?n:n.filter(i=>i.id!=="fable")}async function F(){const r=l("codex");if(!r)return[];let e;try{e=await L(r)}catch(t){throw new b("codex",D(t),h())}if(e.length===0)throw new b("codex","empty_model_list",h());return e}async function B(){return l("gemini")?R():[]}const u=[{id:"qwen3.6-plus",name:"Qwen 3.6 Plus",provider:"dashscope",isDefault:!0}],V=[{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(),n=(t.models??[]).map(s=>({id:s.id,name:s.name?.trim()||s.id,provider:s.provider,isDefault:s.id===t.default}));return n.length>0?n:u}catch{return u}}async function K(r,e){switch(r){case"claude":return N();case"codex":return F();case"workbuddy":return l("workbuddy")?x():[];case"gemini":return B();case"cursor":return q();case"openclaw":return[];case"opencode":return j();case"pi":return W(e);case"pi-coding-agent":return G();case"manager":return V}}async function re(r,e){return r.type.startsWith("custom:")?r.models??[]:r.type.startsWith("acp:")?[]:K(r.type,e)}export{re as discoverModelsForAgent};
@@ -1 +1 @@
1
- import{randomBytes as m}from"node:crypto";import{createServer as u}from"node:net";import{resolveBuiltinCommand as f,spawnResolvedCommand as w}from"../command-spec.js";import{buildAgentProcessEnv as v}from"../../agent-env.js";import{DISCOVERY_WORKDIR as g}from"./types.js";import{parseOpenCodeProviderModels as h}from"./parsers.js";async function O(){return new Promise((s,r)=>{const o=u();o.once("error",r),o.listen(0,"127.0.0.1",()=>{const e=o.address(),t=e&&typeof e!="string"?e.port:0;o.close(()=>t?s(t):r(new Error("OpenCode discovery port unavailable")))})})}async function _(){const s=f("opencode");if(!s)return[];const r=await O(),o=m(24).toString("hex"),e=w(s,["serve","--hostname","127.0.0.1","--port",String(r)],{cwd:g,stdio:["ignore","pipe","pipe"],env:v({NO_COLOR:"1",OPENCODE_SERVER_PASSWORD:o})});e.stdout?.resume(),e.stderr?.resume();const t=`Basic ${Buffer.from(`opencode:${o}`).toString("base64")}`,a=`http://127.0.0.1:${r}`;let i=!1;e.once("close",()=>{i=!0}),e.once("error",()=>{i=!0});try{const d=Date.now()+1e4;for(;Date.now()<d&&!i;){try{const n=new AbortController,p=setTimeout(()=>n.abort(),2e3);try{const[c,l]=await Promise.all([fetch(`${a}/provider`,{headers:{Authorization:t},signal:n.signal}),fetch(`${a}/config`,{headers:{Authorization:t},signal:n.signal})]);if(c.ok&&l.ok)return h(await c.json(),await l.json())}finally{clearTimeout(p)}}catch{}await new Promise(n=>setTimeout(n,200))}return[]}finally{e.kill("SIGTERM"),setTimeout(()=>e.kill("SIGKILL"),1e3).unref()}}export{_ as discoverOpenCodeModelsViaApi};
1
+ import{randomBytes as m}from"node:crypto";import{createServer as f}from"node:net";import{resolveBuiltinCommand as u,spawnResolvedCommand as w}from"../command-spec.js";import{DETACH_PROCESS_GROUP as v,stopProcessTree as h}from"../process-tree.js";import{buildAgentProcessEnv as O}from"../../agent-env.js";import{DISCOVERY_WORKDIR as g}from"./types.js";import{parseOpenCodeProviderModels as C}from"./parsers.js";async function P(){return new Promise((s,r)=>{const e=f();e.once("error",r),e.listen(0,"127.0.0.1",()=>{const o=e.address(),t=o&&typeof o!="string"?o.port:0;e.close(()=>t?s(t):r(new Error("OpenCode discovery port unavailable")))})})}async function b(){const s=u("opencode");if(!s)return[];const r=await P(),e=m(24).toString("hex"),o=w(s,["serve","--hostname","127.0.0.1","--port",String(r)],{cwd:g,stdio:["ignore","pipe","pipe"],env:O({NO_COLOR:"1",OPENCODE_SERVER_PASSWORD:e}),detached:v});o.stdout?.resume(),o.stderr?.resume();const t=`Basic ${Buffer.from(`opencode:${e}`).toString("base64")}`,a=`http://127.0.0.1:${r}`;let i=!1;o.once("close",()=>{i=!0}),o.once("error",()=>{i=!0});try{const p=Date.now()+1e4;for(;Date.now()<p&&!i;){try{const n=new AbortController,l=setTimeout(()=>n.abort(),2e3);try{const[c,d]=await Promise.all([fetch(`${a}/provider`,{headers:{Authorization:t},signal:n.signal}),fetch(`${a}/config`,{headers:{Authorization:t},signal:n.signal})]);if(c.ok&&d.ok)return C(await c.json(),await d.json())}finally{clearTimeout(l)}}catch{}await new Promise(n=>setTimeout(n,200))}return[]}finally{await h(o,1e3)}}export{b as discoverOpenCodeModelsViaApi};
@@ -1 +1 @@
1
- import{getAgentConfigSummary as y}from"../config-status.js";import{isCacheFresh as S,readCache as v,writeCache as A}from"./cache.js";import{discoverModelsForAgent as M}from"./discovery.js";import{ModelDiscoveryFallbackError as b}from"./types.js";import{getAgentRuntimeSummary as C}from"../runtime-compatibility.js";import{isRestrictedRoomChatUnsupported as x,resolveManagedAgentRuntimeProtection as F}from"../../security/managed-agent-runtime.js";const E={claude:"claude-alias-v2",codex:"codex-app-server-v2",opencode:"opencode-connected-v1"};function k(o,s,e){console.warn(`[model-discovery] agent=${o} source=fallback reason=${s} usedCache=${e}`)}function w(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 g(o){const s=o.type!=="manager"&&o.type!=="pi"&&o.type!=="openclaw",e=s,i=e&&!o.type.startsWith("acp:"),r=e?F({agentType:o.type,runtimeVersion:o.version,platform:o.runtimePlatform,isWsl:o.runtimeIsWsl,executableFingerprint:o.executableFingerprint,requireExecutableFingerprint:!0}):null,p=i&&!x(o.type)&&(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 R(o,s){return o.type==="opencode"&&(!o.authState||o.authState==="unknown")&&s.length>0?{authState:"ready"}:o.authState?{authState:o.authState}:{}}function T(o){const s=v();return o.map(e=>{const i=y(e.type),r=C(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}:{},...R(e,s.agents[e.type]?.models??e.models??[]),...e.acpAuthMethods?{acpAuthMethods:e.acpAuthMethods}:{},...e.catalogRevision?{catalogRevision:e.catalogRevision}:{},...g(e),...i?{config:i}:{},...r?{runtime:r}:{}}})}async function V(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=E[t.type],u=n&&(!a||n.sourceRevision===a)?n:void 0;let c;if(!e.forceRefresh&&S(n,t.version,a))c=n.models;else{let d=null;try{d=w(await M(t,s)),c=d.length>0?d:u?.models??t.models??[]}catch(l){if(l instanceof b){const m=!!u?.models.length;c=m?u.models:l.fallbackModels,k(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=C(t);p.push({type:t.type,models:c,...t.integration?{integration:t.integration}:{},...t.display?{display:t.display}:{},...t.acpCapabilities?{acpCapabilities:t.acpCapabilities}:{},...R(t,c),...t.acpAuthMethods?{acpAuthMethods:t.acpAuthMethods}:{},...t.catalogRevision?{catalogRevision:t.catalogRevision}:{},...g(t),...f?{config:f}:{},...h?{runtime:h}:{}})}return r&&A(i),p}export{T as getCachedAgentInfos,V as refreshAgentInfos,I as resolveAgentInfos};
1
+ import{getAgentConfigSummary as v}from"../config-status.js";import{isCacheFresh as b,readCache as f,writeCache as g}from"./cache.js";import{discoverModelsForAgent as x}from"./discovery.js";import{ModelDiscoveryFallbackError as F}from"./types.js";import{getAgentRuntimeSummary as A}from"../runtime-compatibility.js";import{isRestrictedRoomChatUnsupported as E,resolveManagedAgentRuntimeProtection as w}from"../../security/managed-agent-runtime.js";const C={claude:"claude-alias-v2",codex:"codex-app-server-v2",opencode:"opencode-connected-v1","pi-coding-agent":"pi-configured-v1"};function O(t,s,e){console.warn(`[model-discovery] agent=${t} source=fallback reason=${s} usedCache=${e}`)}function R(t){const s=new Set,e=[];for(const n of t)!n.id||s.has(n.id)||(s.add(n.id),e.push(n));return e}function S(t){const s=t.type!=="manager"&&t.type!=="pi"&&t.type!=="openclaw",e=s,n=e&&!t.type.startsWith("acp:"),r=e?w({agentType:t.type,runtimeVersion:t.version,platform:t.runtimePlatform,isWsl:t.runtimeIsWsl,executableFingerprint:t.executableFingerprint,requireExecutableFingerprint:!0}):null,c=n&&!E(t.type)&&(r?.level==="hard"||r?.level==="partial"),o=e,i=e,p=[...o?["native-full"]:[],...c?["restricted"]:[]],l=i,a=s;return{supportsStandardSession:s,supportsAgent:i,supportedAgentExecutionModes:p,supportsManagedAgent:c,supportsManagedNativeFull:o,supportsRoomTools:l,supportsWorker:a,supportsManagerMode:l&&a,supportsExternalWorkerTarget:a,...r?{managedAgentProtection:r}:{}}}function M(t,s){return t.type==="opencode"&&(!t.authState||t.authState==="unknown")&&s.length>0?{authState:"ready"}:t.authState?{authState:t.authState}:{}}function P(t,s){if(!t.startsWith("acp:"))return!1;const e=R(s);if(e.length===0)return!1;const n=f(),r=n.agents[t];return JSON.stringify(r?.models)===JSON.stringify(e)?!1:(n.agents[t]={refreshedAt:Date.now(),models:e},g(n),!0)}function V(t){const s=f();return t.map(e=>{const n=s.agents[e.type],r=C[e.type],c=n&&(!r||n.sourceRevision===r)?n.models:e.models??[],o=v(e.type),i=A(e);return{type:e.type,models:c,...e.integration?{integration:e.integration}:{},...e.display?{display:e.display}:{},...e.acpCapabilities?{acpCapabilities:e.acpCapabilities}:{},...M(e,c),...e.acpAuthMethods?{acpAuthMethods:e.acpAuthMethods}:{},...e.catalogRevision?{catalogRevision:e.catalogRevision}:{},...S(e),...o?{config:o}:{},...i?{runtime:i}:{}}})}async function _(t,s){return k(t,s,{forceRefresh:!0})}async function k(t,s,e={}){const n=f();let r=!1;const c=[];for(const o of t){const i=n.agents[o.type],p=C[o.type],l=i&&(!p||i.sourceRevision===p)?i:void 0;let a;if(!e.forceRefresh&&b(i,o.version,p))a=i.models;else{let d=null;try{d=R(await x(o,s)),a=d.length>0?d:l?.models??o.models??[]}catch(u){if(u instanceof F){const y=!!l?.models.length;a=y?l.models:u.fallbackModels,O(o.type,u.failureCode,y)}else a=l?.models??o.models??[]}if(d&&d.length>0){const u={version:o.version,...p?{sourceRevision:p}:{},refreshedAt:Date.now(),models:a};JSON.stringify(i)!==JSON.stringify(u)&&(n.agents[o.type]=u,r=!0)}}const h=v(o.type),m=A(o);c.push({type:o.type,models:a,...o.integration?{integration:o.integration}:{},...o.display?{display:o.display}:{},...o.acpCapabilities?{acpCapabilities:o.acpCapabilities}:{},...M(o,a),...o.acpAuthMethods?{acpAuthMethods:o.acpAuthMethods}:{},...o.catalogRevision?{catalogRevision:o.catalogRevision}:{},...S(o),...h?{config:h}:{},...m?{runtime:m}:{}})}return r&&g(n),c}export{V as getCachedAgentInfos,P as recordAcpAgentModels,_ as refreshAgentInfos,k as resolveAgentInfos};
@@ -1 +1 @@
1
- import{getCachedAgentInfos as m,refreshAgentInfos as u,resolveAgentInfos as v}from"./model-registry/service.js";import{applyClaudeModelEnvOverrides as e,discoverClaudeAliasModelsFromEnv as s,fallbackCodexModels as o,fallbackClaudeAliasModels as l,parseClaudeBinaryModels as r,parseClaudeModels as d,parseCodexModels as a,parseCodexAppServerModels as p,parseCursorModels as n,parseGeminiModels as i,parseOpenClawModels as t,stripAnsi as C}from"./model-registry/parsers.js";const f={applyClaudeModelEnvOverrides:e,discoverClaudeAliasModelsFromEnv:s,fallbackCodexModels:o,fallbackClaudeAliasModels:l,parseClaudeBinaryModels:r,parseClaudeModels:d,parseCodexModels:a,parseCodexAppServerModels:p,parseCursorModels:n,parseOpenClawModels:t,parseGeminiModels:i,stripAnsi:C};export{m as getCachedAgentInfos,f as modelSwitchingTestExports,u as refreshAgentInfos,v as resolveAgentInfos};
1
+ import{getCachedAgentInfos as g,recordAcpAgentModels as m,refreshAgentInfos as u,resolveAgentInfos as v}from"./model-registry/service.js";import{applyClaudeModelEnvOverrides as e,discoverClaudeAliasModelsFromEnv as s,fallbackCodexModels as o,fallbackClaudeAliasModels as r,parseClaudeBinaryModels as l,parseClaudeModels as d,parseCodexModels as a,parseCodexAppServerModels as p,parseCursorModels as n,parseGeminiModels as t,parseOpenClawModels as i,stripAnsi as M}from"./model-registry/parsers.js";const A={applyClaudeModelEnvOverrides:e,discoverClaudeAliasModelsFromEnv:s,fallbackCodexModels:o,fallbackClaudeAliasModels:r,parseClaudeBinaryModels:l,parseClaudeModels:d,parseCodexModels:a,parseCodexAppServerModels:p,parseCursorModels:n,parseOpenClawModels:i,parseGeminiModels:t,stripAnsi:M};export{g as getCachedAgentInfos,A as modelSwitchingTestExports,m as recordAcpAgentModels,u as refreshAgentInfos,v as resolveAgentInfos};
@@ -1 +1 @@
1
- import{createInterface as g}from"node:readline";import{randomUUID as l}from"node:crypto";import{AgentAdapter as h,registerAgent as f}from"./adapter.js";import{resolveBuiltinCommand as m,spawnAgentCommand as E}from"./command-spec.js";import{spawnEnoentError as C}from"./spawn-errors.js";import{buildAgentProcessEnv as y,buildManagedAgentProcessEnv as O,buildManagedNativeFullProcessEnv as D}from"../agent-env.js";import{buildInlineChannelPreamble as I}from"./platform-instructions.js";import{resolveManagedAgentAdapterEnforcement as S,isManagedAgentNativeFull as P}from"../security/managed-agent-policy.js";import{registerManagedAgentRuntimeSecurity as w}from"../security/managed-agent-runtime.js";import{compileOpenCodeManagedPermissions as _,createOpenCodeManagedConfigDirectory as A,disposeOpenCodeManagedConfigDirectory as v,OPENCODE_MANAGED_RUNTIME_SECURITY as N}from"./opencode-managed-permissions.js";w("opencode",N);function k(n){if(!n)return;const e=n.input,t=n.output;if(!(typeof e!="number"&&typeof t!="number"))return{inputTokens:typeof e=="number"?e:0,outputTokens:typeof t=="number"?t:0}}function u(n){if(n==null)return"";if(typeof n=="string")return n;try{return JSON.stringify(n)}catch{return String(n)}}function c(n){if(!n)return"opencode request failed";if(typeof n=="string")return n;if(typeof n!="object")return String(n);const e=n;return typeof e.message=="string"?e.message:typeof e.name=="string"?e.name:"data"in e?c(e.data):u(n)||"opencode request failed"}class x extends h{type="opencode";get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!0}}process=null;agentSessionId=null;workDir=null;seq=0;runId="";terminalState="closed";runUsage;externalChannel=null;shennianSessionId=null;extraEnv={};managedAgentPolicy=null;managedConfigDir=null;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,o){this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??t,o&&(this.agentSessionId=o),this.resetRunState()}async send(e,t,o,i,s,d){if(d?.source==="room_activation"&&!this.managedAgentPolicy)throw new Error("managed_agent_policy_missing");await this.killProcess(),this.runId=l(),this.resetRunState();const a=["run","--format","json","--dir",this.workDir??process.cwd()];this.agentSessionId&&a.push("--session",this.agentSessionId),t&&a.push("--model",t);const r=`${I(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,s)}${e}`;await this.spawnAndParse(a,r)}async resume(e){await this.killProcess(),this.agentSessionId=e,this.runId=l(),this.resetRunState(),this.emitEvent({state:"start",agentSessionId:e}),this.emitFinalIfOpen({state:"final",agentSessionId:e})}async stop(){await this.killProcess()}resetRunState(){this.seq=0,this.terminalState="open",this.runUsage=void 0}async spawnAndParse(e,t){const o=m("opencode");if(!o){this.emit("error",new Error('Command "opencode" not found. Install it with "npm i -g opencode-ai@latest".'));return}const i=await this.prepareManagedLaunch();let s;try{s=E(o,[e[0],...i.args,...e.slice(1)],{cwd:this.workDir??void 0,stdio:["pipe","pipe","pipe"],env:i.env})}catch(r){throw await this.disposeManagedConfig(i.configDir),r}this.process=s,this.managedConfigDir=i.configDir,g({input:s.stdout}).on("line",r=>{this.handleProcessLine(s,r)});let a="";s.stderr?.on("data",r=>{a+=r.toString()}),s.on("close",(r,p)=>{this.process===s&&(this.process=null,this.disposeManagedConfig(i.configDir),this.terminalState==="open"&&this.completeRunAfterProcessExit(r,p,a.trim()))}),s.on("error",r=>{this.process===s&&(this.process=null,this.disposeManagedConfig(i.configDir),r.code==="ENOENT"?this.emit("error",C(this.workDir,'Command "opencode" not found. Install it with "npm i -g opencode-ai@latest".')):this.emit("error",r))}),s.stdin.on("error",r=>{this.process===s&&this.emitErrorIfOpen({state:"error",message:r.message})}),s.stdin.end(t)}async prepareManagedLaunch(){const e=this.managedAgentPolicy;if(!e)return{args:["--auto"],env:y({NO_COLOR:"1",...this.extraEnv}),configDir:null};if(P(e))return{args:["--auto"],env:D({NO_COLOR:"1",...this.extraEnv}),configDir:null};const t=_(S(e),e.adapterPolicy.workDir),o=await A(t),i=O({agentType:"opencode",providerEnv:this.extraEnv,sessionEnv:this.extraEnv,runtimeEnv:{NO_COLOR:"1"}});return i.OPENCODE_CONFIG=o.configPath,i.OPENCODE_CONFIG_DIR=o.directory,i.OPENCODE_CONFIG_CONTENT=JSON.stringify(t.config),i.OPENCODE_DISABLE_PROJECT_CONFIG="true",i.OPENCODE_DISABLE_CLAUDE_CODE="1",i.OPENCODE_DISABLE_CLAUDE_CODE_PROMPT="1",i.OPENCODE_DISABLE_CLAUDE_CODE_SKILLS="1",{args:t.args,env:i,configDir:o.directory}}async disposeManagedConfig(e){e&&(this.managedConfigDir===e&&(this.managedConfigDir=null),await v(e).catch(()=>{}))}handleStreamEvent(e){e.sessionID&&e.sessionID!==this.agentSessionId&&(this.agentSessionId=e.sessionID,this.emitEvent({state:"start",agentSessionId:e.sessionID}));const t=e.part;if(e.type==="text"&&t?.text){this.emitEvent({state:"delta",text:t.text});return}if(e.type==="reasoning"&&t?.text){this.emitEvent({state:"delta",text:t.text,thinking:!0});return}if(e.type==="tool_use"&&t?.type==="tool"){t.state?.status==="completed"||t.state?.status==="error"?this.emitEvent({state:"tool-result",name:t.tool??"tool",result:t.state.status==="error"?t.state.error??"tool failed":u(t.state?.output)}):this.emitEvent({state:"tool-call",name:t.tool??"tool",args:t.state?.input??{}});return}if(e.type==="error"){this.emitErrorIfOpen({state:"error",message:c(e.error)});return}e.type==="step_finish"&&this.recordStepUsage(k(t?.tokens))}handleProcessLine(e,t){if(!(this.process!==e||!t.trim()))try{this.handleStreamEvent(JSON.parse(t))}catch{this.emitEvent({state:"delta",text:t})}}recordStepUsage(e){e&&(this.runUsage={inputTokens:(this.runUsage?.inputTokens??0)+e.inputTokens,outputTokens:(this.runUsage?.outputTokens??0)+e.outputTokens})}completeRunAfterProcessExit(e=0,t=null,o=""){if(e!==0||t!==null){this.emitErrorIfOpen({state:"error",message:o||(t?`opencode exited with signal ${t}`:`opencode exited with code ${String(e)}`)});return}this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0,usage:this.runUsage})}emitEvent(e){const t={...e,runId:this.runId,seq:this.seq++};this.emit("agentEvent",t)}emitFinalIfOpen(e){this.terminalState==="open"&&(this.terminalState="closed",this.emitEvent(e))}emitErrorIfOpen(e){this.terminalState==="open"&&(this.terminalState="closed",this.emitEvent(e))}async killProcess(){const e=this.process;if(!e){await this.disposeManagedConfig(this.managedConfigDir);return}this.process=null,e.kill("SIGTERM"),await new Promise(t=>{e.on("close",t),setTimeout(()=>{e.kill("SIGKILL"),t()},3e3)}),await this.disposeManagedConfig(this.managedConfigDir)}}f("opencode",()=>new x);export{x as OpenCodeAdapter};
1
+ import{createInterface as g}from"node:readline";import{randomUUID as u}from"node:crypto";import{AgentAdapter as f,registerAgent as h}from"./adapter.js";import{resolveBuiltinCommand as m,spawnAgentCommand as E}from"./command-spec.js";import{spawnEnoentError as C}from"./spawn-errors.js";import{DETACH_PROCESS_GROUP as y,stopProcessTree as O}from"./process-tree.js";import{buildAgentProcessEnv as D,buildManagedAgentProcessEnv as I,buildManagedNativeFullProcessEnv as S}from"../agent-env.js";import{buildInlineChannelPreamble as P}from"./platform-instructions.js";import{resolveManagedAgentAdapterEnforcement as _,isManagedAgentNativeFull as w}from"../security/managed-agent-policy.js";import{registerManagedAgentRuntimeSecurity as A}from"../security/managed-agent-runtime.js";import{compileOpenCodeManagedPermissions as v,createOpenCodeManagedConfigDirectory as N,disposeOpenCodeManagedConfigDirectory as x,OPENCODE_MANAGED_RUNTIME_SECURITY as k}from"./opencode-managed-permissions.js";A("opencode",k);const T=64*1024;function R(n){if(!n)return;const e=n.input,t=n.output;if(!(typeof e!="number"&&typeof t!="number"))return{inputTokens:typeof e=="number"?e:0,outputTokens:typeof t=="number"?t:0}}function l(n){if(n==null)return"";if(typeof n=="string")return n;try{return JSON.stringify(n)}catch{return String(n)}}function p(n){if(!n)return"opencode request failed";if(typeof n=="string")return n;if(typeof n!="object")return String(n);const e=n;return typeof e.message=="string"?e.message:typeof e.name=="string"?e.name:"data"in e?p(e.data):l(n)||"opencode request failed"}class M extends f{type="opencode";get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!0}}process=null;agentSessionId=null;workDir=null;seq=0;runId="";terminalState="closed";runUsage;externalChannel=null;shennianSessionId=null;extraEnv={};managedAgentPolicy=null;managedConfigDir=null;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,o){this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??t,o&&(this.agentSessionId=o),this.resetRunState()}async send(e,t,o,i,s,c){if(c?.source==="room_activation"&&!this.managedAgentPolicy)throw new Error("managed_agent_policy_missing");await this.killProcess(),this.runId=u(),this.resetRunState();const a=["run","--format","json","--dir",this.workDir??process.cwd()];this.agentSessionId&&a.push("--session",this.agentSessionId),t&&a.push("--model",t);const r=`${P(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,s)}${e}`;await this.spawnAndParse(a,r)}async resume(e){await this.killProcess(),this.agentSessionId=e,this.runId=u(),this.resetRunState(),this.emitEvent({state:"start",agentSessionId:e}),this.emitFinalIfOpen({state:"final",agentSessionId:e})}async stop(){await this.killProcess()}resetRunState(){this.seq=0,this.terminalState="open",this.runUsage=void 0}async spawnAndParse(e,t){const o=m("opencode");if(!o){this.emit("error",new Error('Command "opencode" not found. Install it with "npm i -g opencode-ai@latest".'));return}const i=await this.prepareManagedLaunch();let s;try{s=E(o,[e[0],...i.args,...e.slice(1)],{cwd:this.workDir??void 0,stdio:["pipe","pipe","pipe"],env:i.env,detached:y})}catch(r){throw await this.disposeManagedConfig(i.configDir),r}this.process=s,this.managedConfigDir=i.configDir,g({input:s.stdout}).on("line",r=>{this.handleProcessLine(s,r)});let a=Buffer.alloc(0);s.stderr?.on("data",r=>{const d=T-a.byteLength;d>0&&(a=Buffer.concat([a,r.subarray(0,d)]))}),s.on("close",(r,d)=>{this.process===s&&(this.disposeManagedConfig(i.configDir),this.terminalState==="open"&&this.completeRunAfterProcessExit(r,d,a.toString("utf8").trim()))}),s.on("error",r=>{this.process===s&&(this.process=null,this.disposeManagedConfig(i.configDir),r.code==="ENOENT"?this.emit("error",C(this.workDir,'Command "opencode" not found. Install it with "npm i -g opencode-ai@latest".')):this.emit("error",r))}),s.stdin.on("error",r=>{this.process===s&&this.emitErrorIfOpen({state:"error",message:r.message})}),s.stdin.end(t)}async prepareManagedLaunch(){const e=this.managedAgentPolicy;if(!e)return{args:["--auto"],env:D({NO_COLOR:"1",...this.extraEnv}),configDir:null};if(w(e))return{args:["--auto"],env:S({NO_COLOR:"1",...this.extraEnv}),configDir:null};const t=v(_(e),e.adapterPolicy.workDir),o=await N(t),i=I({agentType:"opencode",providerEnv:this.extraEnv,sessionEnv:this.extraEnv,runtimeEnv:{NO_COLOR:"1"}});return i.OPENCODE_CONFIG=o.configPath,i.OPENCODE_CONFIG_DIR=o.directory,i.OPENCODE_CONFIG_CONTENT=JSON.stringify(t.config),i.OPENCODE_DISABLE_PROJECT_CONFIG="true",i.OPENCODE_DISABLE_CLAUDE_CODE="1",i.OPENCODE_DISABLE_CLAUDE_CODE_PROMPT="1",i.OPENCODE_DISABLE_CLAUDE_CODE_SKILLS="1",{args:t.args,env:i,configDir:o.directory}}async disposeManagedConfig(e){e&&(this.managedConfigDir===e&&(this.managedConfigDir=null),await x(e).catch(()=>{}))}handleStreamEvent(e){e.sessionID&&e.sessionID!==this.agentSessionId&&(this.agentSessionId=e.sessionID,this.emitEvent({state:"start",agentSessionId:e.sessionID}));const t=e.part;if(e.type==="text"&&t?.text){this.emitEvent({state:"delta",text:t.text});return}if(e.type==="reasoning"&&t?.text){this.emitEvent({state:"delta",text:t.text,thinking:!0});return}if(e.type==="tool_use"&&t?.type==="tool"){t.state?.status==="completed"||t.state?.status==="error"?this.emitEvent({state:"tool-result",name:t.tool??"tool",result:t.state.status==="error"?t.state.error??"tool failed":l(t.state?.output)}):this.emitEvent({state:"tool-call",name:t.tool??"tool",args:t.state?.input??{}});return}if(e.type==="error"){this.emitErrorIfOpen({state:"error",message:p(e.error)});return}e.type==="step_finish"&&this.recordStepUsage(R(t?.tokens))}handleProcessLine(e,t){if(!(this.process!==e||!t.trim()))try{this.handleStreamEvent(JSON.parse(t))}catch{this.emitEvent({state:"delta",text:t})}}recordStepUsage(e){e&&(this.runUsage={inputTokens:(this.runUsage?.inputTokens??0)+e.inputTokens,outputTokens:(this.runUsage?.outputTokens??0)+e.outputTokens})}completeRunAfterProcessExit(e=0,t=null,o=""){if(e!==0||t!==null){this.emitErrorIfOpen({state:"error",message:o||(t?`opencode exited with signal ${t}`:`opencode exited with code ${String(e)}`)});return}this.emitFinalIfOpen({state:"final",agentSessionId:this.agentSessionId??void 0,usage:this.runUsage})}emitEvent(e){const t={...e,runId:this.runId,seq:this.seq++};this.emit("agentEvent",t)}emitFinalIfOpen(e){this.terminalState==="open"&&(this.terminalState="closed",this.emitEvent(e))}emitErrorIfOpen(e){this.terminalState==="open"&&(this.terminalState="closed",this.emitEvent(e))}async killProcess(){const e=this.process;if(!e){await this.disposeManagedConfig(this.managedConfigDir);return}this.process=null,await O(e),await this.disposeManagedConfig(this.managedConfigDir)}}h("opencode",()=>new M);export{M as OpenCodeAdapter};