shennian 0.5.2 → 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.
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "jsMinified": true,
4
4
  "minifier": "esbuild",
5
- "fileCount": 234,
5
+ "fileCount": 235,
6
6
  "files": [
7
7
  {
8
8
  "file": "bin/shennian.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,8 +196,8 @@
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",
@@ -211,8 +206,8 @@
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": 8864,
230
- "afterBytes": 3358
224
+ "beforeBytes": 9489,
225
+ "afterBytes": 3505
231
226
  },
232
227
  {
233
228
  "file": "src/agents/model-registry/types.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,8 +261,8 @@
266
261
  },
267
262
  {
268
263
  "file": "src/agents/pi-coding-agent.js",
269
- "beforeBytes": 22758,
270
- "afterBytes": 12494
264
+ "beforeBytes": 28451,
265
+ "afterBytes": 15071
271
266
  },
272
267
  {
273
268
  "file": "src/agents/pi-managed-extension.js",
@@ -284,11 +279,21 @@
284
279
  "beforeBytes": 2397,
285
280
  "afterBytes": 1328
286
281
  },
282
+ {
283
+ "file": "src/agents/pi-turn-diagnostics.js",
284
+ "beforeBytes": 7200,
285
+ "afterBytes": 3920
286
+ },
287
287
  {
288
288
  "file": "src/agents/platform-instructions.js",
289
289
  "beforeBytes": 2829,
290
290
  "afterBytes": 1705
291
291
  },
292
+ {
293
+ "file": "src/agents/process-tree.js",
294
+ "beforeBytes": 2647,
295
+ "afterBytes": 856
296
+ },
292
297
  {
293
298
  "file": "src/agents/runtime-compatibility.js",
294
299
  "beforeBytes": 1587,
@@ -316,8 +321,8 @@
316
321
  },
317
322
  {
318
323
  "file": "src/commands/agent-readiness.js",
319
- "beforeBytes": 7032,
320
- "afterBytes": 5639
324
+ "beforeBytes": 7770,
325
+ "afterBytes": 6041
321
326
  },
322
327
  {
323
328
  "file": "src/commands/agent.js",
@@ -401,8 +406,8 @@
401
406
  },
402
407
  {
403
408
  "file": "src/commands/room.js",
404
- "beforeBytes": 18602,
405
- "afterBytes": 10736
409
+ "beforeBytes": 18609,
410
+ "afterBytes": 10774
406
411
  },
407
412
  {
408
413
  "file": "src/commands/runtime.js",
@@ -436,8 +441,8 @@
436
441
  },
437
442
  {
438
443
  "file": "src/daemon-ipc/agent-readiness.js",
439
- "beforeBytes": 4838,
440
- "afterBytes": 2425
444
+ "beforeBytes": 5145,
445
+ "afterBytes": 2587
441
446
  },
442
447
  {
443
448
  "file": "src/daemon-ipc/client.js",
@@ -511,8 +516,8 @@
511
516
  },
512
517
  {
513
518
  "file": "src/index.js",
514
- "beforeBytes": 42379,
515
- "afterBytes": 20999
519
+ "beforeBytes": 42698,
520
+ "afterBytes": 21157
516
521
  },
517
522
  {
518
523
  "file": "src/log-redaction.js",
@@ -541,8 +546,8 @@
541
546
  },
542
547
  {
543
548
  "file": "src/manager/runtime.js",
544
- "beforeBytes": 35299,
545
- "afterBytes": 17196
549
+ "beforeBytes": 35692,
550
+ "afterBytes": 17388
546
551
  },
547
552
  {
548
553
  "file": "src/manager/worker-ipc.js",
@@ -701,8 +706,8 @@
701
706
  },
702
707
  {
703
708
  "file": "src/room/activation-service.js",
704
- "beforeBytes": 28566,
705
- "afterBytes": 15641
709
+ "beforeBytes": 28666,
710
+ "afterBytes": 15706
706
711
  },
707
712
  {
708
713
  "file": "src/room/attachment-cache.js",
@@ -711,8 +716,8 @@
711
716
  },
712
717
  {
713
718
  "file": "src/room/attachment-upload.js",
714
- "beforeBytes": 6996,
715
- "afterBytes": 3546
719
+ "beforeBytes": 7283,
720
+ "afterBytes": 3698
716
721
  },
717
722
  {
718
723
  "file": "src/room/device-authorization-client.js",
@@ -756,13 +761,13 @@
756
761
  },
757
762
  {
758
763
  "file": "src/room/managed-room-ipc.js",
759
- "beforeBytes": 15469,
760
- "afterBytes": 7269
764
+ "beforeBytes": 15570,
765
+ "afterBytes": 7327
761
766
  },
762
767
  {
763
768
  "file": "src/room/mirror-sync-service.js",
764
- "beforeBytes": 12115,
765
- "afterBytes": 5558
769
+ "beforeBytes": 12375,
770
+ "afterBytes": 5688
766
771
  },
767
772
  {
768
773
  "file": "src/room/public-attachment-cache.js",
@@ -786,8 +791,8 @@
786
791
  },
787
792
  {
788
793
  "file": "src/room/room-action-client.js",
789
- "beforeBytes": 29197,
790
- "afterBytes": 14837
794
+ "beforeBytes": 29246,
795
+ "afterBytes": 14863
791
796
  },
792
797
  {
793
798
  "file": "src/room/room-binding-client.js",
@@ -891,8 +896,8 @@
891
896
  },
892
897
  {
893
898
  "file": "src/session/handlers/agent-workspace-validation.js",
894
- "beforeBytes": 9136,
895
- "afterBytes": 4977
899
+ "beforeBytes": 10525,
900
+ "afterBytes": 5385
896
901
  },
897
902
  {
898
903
  "file": "src/session/handlers/agents.js",
@@ -916,8 +921,8 @@
916
921
  },
917
922
  {
918
923
  "file": "src/session/handlers/chat-recovery.js",
919
- "beforeBytes": 6623,
920
- "afterBytes": 3485
924
+ "beforeBytes": 6918,
925
+ "afterBytes": 3623
921
926
  },
922
927
  {
923
928
  "file": "src/session/handlers/chat-session-lifecycle.js",
@@ -926,8 +931,8 @@
926
931
  },
927
932
  {
928
933
  "file": "src/session/handlers/chat.js",
929
- "beforeBytes": 35005,
930
- "afterBytes": 14959
934
+ "beforeBytes": 35377,
935
+ "afterBytes": 15049
931
936
  },
932
937
  {
933
938
  "file": "src/session/handlers/control.js",
@@ -996,8 +1001,8 @@
996
1001
  },
997
1002
  {
998
1003
  "file": "src/session/manager.js",
999
- "beforeBytes": 40313,
1000
- "afterBytes": 21179
1004
+ "beforeBytes": 40733,
1005
+ "afterBytes": 21391
1001
1006
  },
1002
1007
  {
1003
1008
  "file": "src/session/native-cleanup-outbox.js",
@@ -1061,8 +1066,8 @@
1061
1066
  },
1062
1067
  {
1063
1068
  "file": "src/session/queue.js",
1064
- "beforeBytes": 40313,
1065
- "afterBytes": 17923
1069
+ "beforeBytes": 41453,
1070
+ "afterBytes": 18387
1066
1071
  },
1067
1072
  {
1068
1073
  "file": "src/session/queued-chat-dispatch.js",
@@ -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 +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 v}from"../config-status.js";import{isCacheFresh as M,readCache as f,writeCache as g}from"./cache.js";import{discoverModelsForAgent as b}from"./discovery.js";import{ModelDiscoveryFallbackError as x}from"./types.js";import{getAgentRuntimeSummary as C}from"../runtime-compatibility.js";import{isRestrictedRoomChatUnsupported as F,resolveManagedAgentRuntimeProtection as w}from"../../security/managed-agent-runtime.js";const E={claude:"claude-alias-v2",codex:"codex-app-server-v2",opencode:"opencode-connected-v1"};function O(t,s,e){console.warn(`[model-discovery] agent=${t} source=fallback reason=${s} usedCache=${e}`)}function A(t){const s=new Set,e=[];for(const r of t)!r.id||s.has(r.id)||(s.add(r.id),e.push(r));return e}function S(t){const s=t.type!=="manager"&&t.type!=="pi"&&t.type!=="openclaw",e=s,r=e&&!t.type.startsWith("acp:"),i=e?w({agentType:t.type,runtimeVersion:t.version,platform:t.runtimePlatform,isWsl:t.runtimeIsWsl,executableFingerprint:t.executableFingerprint,requireExecutableFingerprint:!0}):null,p=r&&!F(t.type)&&(i?.level==="hard"||i?.level==="partial"),o=e,n=p||o,a=s;return{supportsStandardSession:s,supportsManagedAgent:p,supportsManagedNativeFull:o,supportsRoomTools:n,supportsWorker:a,supportsManagerMode:n&&a,supportsExternalWorkerTarget:a,...i?{managedAgentProtection:i}:{}}}function R(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=A(s);if(e.length===0)return!1;const r=f(),i=r.agents[t];return JSON.stringify(i?.models)===JSON.stringify(e)?!1:(r.agents[t]={refreshedAt:Date.now(),models:e},g(r),!0)}function V(t){const s=f();return t.map(e=>{const r=v(e.type),i=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}:{},...S(e),...r?{config:r}:{},...i?{runtime:i}:{}}})}async function _(t,s){return k(t,s,{forceRefresh:!0})}async function k(t,s,e={}){const r=f();let i=!1;const p=[];for(const o of t){const n=r.agents[o.type],a=E[o.type],u=n&&(!a||n.sourceRevision===a)?n:void 0;let c;if(!e.forceRefresh&&M(n,o.version,a))c=n.models;else{let d=null;try{d=A(await b(o,s)),c=d.length>0?d:u?.models??o.models??[]}catch(l){if(l instanceof x){const y=!!u?.models.length;c=y?u.models:l.fallbackModels,O(o.type,l.failureCode,y)}else c=u?.models??o.models??[]}if(d&&d.length>0){const l={version:o.version,...a?{sourceRevision:a}:{},refreshedAt:Date.now(),models:c};JSON.stringify(n)!==JSON.stringify(l)&&(r.agents[o.type]=l,i=!0)}}const h=v(o.type),m=C(o);p.push({type:o.type,models:c,...o.integration?{integration:o.integration}:{},...o.display?{display:o.display}:{},...o.acpCapabilities?{acpCapabilities:o.acpCapabilities}:{},...R(o,c),...o.acpAuthMethods?{acpAuthMethods:o.acpAuthMethods}:{},...o.catalogRevision?{catalogRevision:o.catalogRevision}:{},...S(o),...h?{config:h}:{},...m?{runtime:m}:{}})}return i&&g(r),p}export{V as getCachedAgentInfos,P as recordAcpAgentModels,_ as refreshAgentInfos,k 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{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};
@@ -1,3 +1,3 @@
1
- import d from"node:fs";import h from"node:path";import{randomUUID as P}from"node:crypto";import{AgentAdapter as A,registerAgent as x}from"./adapter.js";import{resolveBuiltinCommand as v,spawnAgentCommand as R}from"./command-spec.js";import{buildAgentProcessEnv as N,buildManagedAgentProcessEnv as C,buildManagedNativeFullProcessEnv as T}from"../agent-env.js";import{resolveShennianPath as m}from"../config/index.js";import{buildInlineChannelPreamble as b,buildPlatformInstructions as k}from"./platform-instructions.js";import{isManagedAgentNativeFull as _}from"../security/managed-agent-policy.js";import{PiRpcClient as D}from"./pi-rpc-client.js";import{registerManagedAgentRuntimeSecurity as M}from"../security/managed-agent-runtime.js";import{PI_CODING_AGENT_MANAGED_RUNTIME_SECURITY as O}from"./pi-coding-agent-managed-permissions.js";import{writePiManagedExtension as q}from"./pi-managed-extension.js";import{recordPiSessionOwnership as j}from"./pi-session-ownership.js";M("pi-coding-agent",O);const F=32*1024,$=256*1024,U=3e3;function g(n){return n.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,180)||"session"}function B(n){return n.data&&typeof n.data=="object"&&!Array.isArray(n.data)?n.data:{}}function G(n){if(typeof n=="string")return n;if(!n||typeof n!="object")return"";const t=n.content;return Array.isArray(t)?t.map(s=>{if(!s||typeof s!="object")return"";const e=s;return e.type==="text"&&typeof e.text=="string"?e.text:""}).join(""):""}function f(n,t=$){return n.length<=t?n:`${n.slice(0,t)}
2
- [truncated]`}function z(n){return f(n,2e3).replace(/Bearer\s+[A-Za-z0-9._~-]+/gi,"Bearer [redacted]").replace(/\b(?:pimc|mrc)_[A-Za-z0-9_-]{20,}\b/g,"[redacted-capability]").replace(/\bsk-[A-Za-z0-9_-]{12,}\b/g,"[redacted-key]")}function H(n){try{return f(JSON.stringify(n))}catch{return"[unserializable]"}}function E(n){if(!n||typeof n!="object")return;const t=n;if(!(typeof t.input!="number"&&typeof t.output!="number"))return{inputTokens:typeof t.input=="number"?t.input:0,outputTokens:typeof t.output=="number"?t.output:0}}function X(n){const t=n?.trim();if(!t)return{};const s=t.indexOf("/");return s<=0||s===t.length-1?{modelId:t}:{provider:t.slice(0,s),modelId:t.slice(s+1)}}function w(n,t,s,e,r,l){const c=b(s,e,r,l),u=t?.filter(a=>a.kind!=="image")??[];if(!u.length)return`${c}${n}`;const o=u.map(a=>`[${a.name}](<${a.path}>)`);return`${c}${[n,"",...o].join(`
3
- `)}`}function I(n,t){const s=[];for(const e of n??[]){if(e.kind!=="image"||!e.mimeType.startsWith("image/"))continue;let r=e.previewData?.trim()??"";const l=r.indexOf(",");if(r.startsWith("data:")&&l>=0&&(r=r.slice(l+1)),!r&&t&&e.path&&!/^https?:\/\//i.test(e.path))try{const c=d.statSync(e.path);c.isFile()&&c.size<=10*1024*1024&&(r=d.readFileSync(e.path).toString("base64"))}catch{r=""}r&&s.push({type:"image",data:r,mimeType:e.mimeType})}return s}class Z extends A{type="pi-coding-agent";get supportsActiveInput(){return!0}async injectActiveInput(t){const s=await this.readState();if(!this.rpc||!this.runId||!s.isStreaming&&!s.isCompacting)throw new Error("pi_active_turn_unavailable");const e={message:w(t.text,t.attachments,this.workDir,this.externalChannel,this.shennianSessionId,null)},r=I(t.attachments,!this.managedAgentPolicy);r.length&&(e.images=r),await this.rpc.request("steer",e)}get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!0}}process=null;rpc=null;shennianSessionId="";workDir="";sessionDir="";agentSessionId=null;externalChannel=null;extraEnv={};spawnedRoomContext=null;managedAgentPolicy=null;runId="";seq=0;active=!1;terminal=!0;stderr="";lastUsage;promptFile=null;persistNativeSession=!0;validationRoot=null;runPhase=null;configure(t){t.sessionId&&(this.shennianSessionId=t.sessionId),this.externalChannel=t.externalChannel??null,this.extraEnv=t.env??{},"managedAgentPolicy"in t&&(this.managedAgentPolicy=t.managedAgentPolicy??null)}async start(t,s,e,r){await this.stopProcess(),this.shennianSessionId=t,this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??s,this.agentSessionId=e??null;const l=m("runtime","pi-coding-agent",g(t));this.persistNativeSession=r?.persistNativeSession!==!1,this.validationRoot=this.persistNativeSession?null:h.join(l,`validation-${P()}`),this.sessionDir=this.validationRoot?h.join(this.validationRoot,"sessions"):h.join(l,"sessions"),d.mkdirSync(this.sessionDir,{recursive:!0,mode:448}),process.platform!=="win32"&&d.chmodSync(this.sessionDir,448),this.active=!1,this.terminal=!0}async send(t,s,e,r,l,c){await this.ensureProcess(l);const u=this.requireRpc(),o=await this.readState(),a=!!(o.isStreaming||o.isCompacting);(!a||!this.runId)&&(this.runId=P(),this.seq=0,this.terminal=!1,this.lastUsage=void 0,this.runPhase="thinking");const i=X(s);if(i.modelId&&!a&&(o.model?.id!==i.modelId||i.provider&&o.model?.provider!==i.provider)){if(!i.provider)throw new Error("Pi model selection must include provider/modelId");await u.request("set_model",{provider:i.provider,modelId:i.modelId})}e&&!a&&await u.request("set_thinking_level",{level:e});const p=a?c?.source==="room_activation"?"follow_up":"steer":"prompt",y={message:w(t,r,this.workDir,this.externalChannel,this.shennianSessionId,null)},S=I(r,!this.managedAgentPolicy);S.length&&(y.images=S),await u.request(p,y)}async resume(t){await this.stopProcess(),this.agentSessionId=t}async stop(){const t=this.rpc;t&&(await t.request("clear_queue").catch(()=>{}),await t.request("abort").catch(()=>{})),!this.terminal&&this.runId&&this.emitTerminal({state:"aborted"}),await this.stopProcess()}async getStatus(){if(!this.rpc||!this.process)return{active:!1,runId:null,canStop:!1};const t=await this.readState().catch(()=>null),s=!!(t?.isStreaming||t?.isCompacting||this.active);return{active:s,runId:s?this.runId:null,runPhase:s?this.runPhase??"thinking":null,canStop:s}}async setTitle(t,s){this.rpc&&await this.rpc.request("set_session_name",{name:s.slice(0,200)})}async ensureProcess(t){if(this.process&&this.rpc){if(!await this.roomContextStale())return;await this.stopProcess()}const s=v("pi-coding-agent");if(!s)throw new Error('Command "pi" not found. Install @earendil-works/pi-coding-agent from the official package.');const e=["--mode","rpc","--session-dir",this.sessionDir,"--offline"];if(this.agentSessionId&&e.push("--session",this.agentSessionId),this.managedAgentPolicy&&!_(this.managedAgentPolicy)){e.push("--no-extensions","--no-skills","--no-prompt-templates","--no-context-files");const i=this.managedTools(),p=q({outputPath:h.join(m("runtime","pi-coding-agent",g(this.shennianSessionId)),"managed-extension.ts"),policy:this.managedAgentPolicy,allowRoomControl:!!this.extraEnv.SHENNIAN_MANAGED_ROOM_CONTEXT,allowManagerControl:!!this.extraEnv.SHENNIAN_MANAGER_SESSION_ID,allowHostShell:this.managedAgentPolicy.adapterPolicy.fileAccess==="host-full"});e.push("--no-builtin-tools","--extension",p),i.length?e.push("--tools",i.join(",")):e.push("--no-tools")}const r=k(this.workDir,this.externalChannel,this.shennianSessionId,t),l=this.validationRoot??m("runtime","pi-coding-agent",g(this.shennianSessionId));d.mkdirSync(l,{recursive:!0,mode:448}),this.promptFile=h.join(l,"instructions.md"),d.writeFileSync(this.promptFile,r,{encoding:"utf8",mode:384}),process.platform!=="win32"&&d.chmodSync(this.promptFile,384),e.push("--append-system-prompt",this.promptFile);const c={NO_COLOR:"1"},u=this.managedAgentPolicy&&!_(this.managedAgentPolicy)?C({agentType:this.type,providerEnv:this.extraEnv,sessionEnv:this.extraEnv,runtimeEnv:c}):this.managedAgentPolicy?T({...c,...this.extraEnv}):N({...c,...this.extraEnv}),o=R(s,e,{cwd:this.workDir,stdio:["pipe","pipe","pipe"],env:u});this.process=o,this.spawnedRoomContext=this.currentRoomContext(),this.stderr="",o.stderr?.on("data",i=>{const p=typeof i=="string"?i:i.toString("utf8");this.stderr=f(`${this.stderr}${p}`,F)});const a=new D(o);this.rpc=a,a.on("event",i=>this.handleRpcEvent(i)),a.on("protocolError",i=>this.emitError(i.message)),o.once("close",i=>{this.process===o&&(this.process=null,this.rpc=null,this.terminal||this.emitError(i===0?"Pi RPC process closed before agent_settled":`Pi RPC process exited with code ${i??"unknown"}${this.stderr?`: ${this.stderr}`:""}`))}),o.once("error",i=>{this.process===o&&this.emitError(i.message)});try{const i=await this.readState();if(!i.sessionId)throw new Error("Pi RPC did not return a session ID");if(i.isStreaming||i.isCompacting)throw new Error("Pi RPC session is not idle after startup");if(this.agentSessionId&&i.sessionId!==this.agentSessionId)throw new Error("Pi RPC resumed a different session");if(!i.sessionFile||!this.ownsSessionFile(i.sessionFile))throw new Error("Pi RPC returned a session file outside the Shennian-owned directory");this.agentSessionId=i.sessionId,this.persistNativeSession&&j(i.sessionId,this.sessionDir)}catch(i){throw await this.stopProcess(),i}}currentRoomContext(){return this.extraEnv.SHENNIAN_MANAGED_ROOM_CONTEXT??null}async roomContextStale(){if(this.currentRoomContext()===this.spawnedRoomContext)return!1;const t=await this.readState().catch(()=>null);return!t?.isStreaming&&!t?.isCompacting}managedTools(){const t=this.managedAgentPolicy?.adapterPolicy;if(!t)return[];const s=["read","grep","find","ls"];(t.fileAccess==="workspace-write"||t.fileAccess==="host-full")&&s.push("edit","write");const e=!!this.extraEnv.SHENNIAN_MANAGER_SESSION_ID,r=!!this.extraEnv.SHENNIAN_MANAGED_ROOM_CONTEXT;return(e||r||t.fileAccess==="host-full")&&s.push("bash"),s}ownsSessionFile(t){const s=h.resolve(this.sessionDir),e=h.resolve(t),r=h.relative(s,e);return r!==""&&!r.startsWith("..")&&!h.isAbsolute(r)}async readState(){const t=await this.requireRpc().request("get_state");return B(t)}requireRpc(){if(!this.rpc)throw new Error("Pi RPC process is not running");return this.rpc}handleRpcEvent(t){if(t.type==="agent_start"){this.active=!0,this.runPhase="thinking",this.emitEvent({state:"start",agentSessionId:this.agentSessionId??void 0});return}if(t.type==="message_update"){this.lastUsage=E(t.usage)??this.lastUsage;const s=t.assistantMessageEvent;if(!s||typeof s!="object")return;const e=s;e.type==="text_delta"&&typeof e.delta=="string"?(this.runPhase="streaming_text",this.emitEvent({state:"delta",text:e.delta})):e.type==="thinking_delta"&&typeof e.delta=="string"&&(this.runPhase="thinking",this.emitEvent({state:"delta",text:e.delta,thinking:!0}));return}if(t.type==="tool_execution_start"){this.runPhase="tool_running",this.emitEvent({state:"tool-call",name:typeof t.toolName=="string"?t.toolName:"tool",args:t.args&&typeof t.args=="object"&&!Array.isArray(t.args)?t.args:{}});return}if(t.type==="tool_execution_end"){this.runPhase="thinking",this.emitEvent({state:"tool-result",name:typeof t.toolName=="string"?t.toolName:"tool",result:G(t.result)||H(t.result)});return}if(t.type==="tool_execution_update"){this.emitEvent({state:"notify",runPhase:"tool_running",message:"Pi tool is running"});return}if(t.type==="message_end"){const s=t.message;if(s&&typeof s=="object"){const e=s;this.lastUsage=E(e.usage)??this.lastUsage,e.stopReason==="error"&&this.emitError(typeof e.errorMessage=="string"?e.errorMessage:"Pi model request failed")}return}if(t.type==="compaction_start"){this.runPhase="thinking",this.emitEvent({state:"notify",runPhase:"thinking",message:"Pi is compacting context"});return}if(t.type==="auto_retry_start"||t.type==="summarization_retry_scheduled"){this.runPhase="thinking",this.emitEvent({state:"notify",runPhase:"thinking",message:"Pi is retrying"});return}if(t.type==="extension_ui_request"){typeof t.id=="string"&&this.rpc?.notify("extension_ui_response",{id:t.id,cancelled:!0});return}if(t.type==="extension_error"){this.emitError(typeof t.error=="string"?t.error:"Pi extension failed");return}t.type==="agent_settled"&&(this.active=!1,this.emitTerminal({state:"final",agentSessionId:this.agentSessionId??void 0,usage:this.lastUsage}))}emitEvent(t){this.runId&&this.emit("agentEvent",{...t,runId:this.runId,seq:this.seq++})}emitTerminal(t){this.terminal||(this.terminal=!0,this.active=!1,this.runPhase=null,this.emitEvent(t))}emitError(t){this.emitTerminal({state:"error",message:z(t)})}async stopProcess(){const t=this.process;this.process=null,this.rpc?.close(),this.rpc=null,t&&(t.kill("SIGTERM"),await new Promise(s=>{let e=!1;const r=()=>{e||(e=!0,s())};t.once("close",r),setTimeout(()=>{t.kill("SIGKILL"),r()},U).unref()})),this.validationRoot&&(d.rmSync(this.validationRoot,{recursive:!0,force:!0}),this.validationRoot=null)}}x("pi-coding-agent",()=>new Z);export{Z as PiCodingAgentAdapter};
1
+ import f from"node:fs";import p from"node:path";import{randomUUID as A}from"node:crypto";import{AgentAdapter as O,registerAgent as M}from"./adapter.js";import{resolveBuiltinCommand as $,spawnAgentCommand as j}from"./command-spec.js";import{buildAgentProcessEnv as F,buildManagedAgentProcessEnv as U,buildManagedNativeFullProcessEnv as G}from"../agent-env.js";import{resolveShennianPath as w}from"../config/index.js";import{buildInlineChannelPreamble as H,buildPlatformInstructions as B}from"./platform-instructions.js";import{isManagedAgentNativeFull as x}from"../security/managed-agent-policy.js";import{PiRpcClient as X}from"./pi-rpc-client.js";import{registerManagedAgentRuntimeSecurity as z}from"../security/managed-agent-runtime.js";import{PI_CODING_AGENT_MANAGED_RUNTIME_SECURITY as L}from"./pi-coding-agent-managed-permissions.js";import{writePiManagedExtension as W}from"./pi-managed-extension.js";import{recordPiSessionOwnership as Y}from"./pi-session-ownership.js";import{classifyPiFailure as _,createPiDiagnosticMarker as J,formatPiDiagnostic as P,inspectPiTurnConfiguration as K,sanitizePiDiagnosticDimension as S}from"./pi-turn-diagnostics.js";z("pi-coding-agent",L);const V=32*1024,Z=256*1024,Q=3e3;function E(n){return n.replace(/[^a-zA-Z0-9_.-]/g,"_").slice(0,180)||"session"}function tt(n){return n.data&&typeof n.data=="object"&&!Array.isArray(n.data)?n.data:{}}function et(n){if(typeof n=="string")return n;if(!n||typeof n!="object")return"";const t=n.content;return Array.isArray(t)?t.map(e=>{if(!e||typeof e!="object")return"";const i=e;return i.type==="text"&&typeof i.text=="string"?i.text:""}).join(""):""}function D(n,t=Z){return n.length<=t?n:`${n.slice(0,t)}
2
+ [truncated]`}function R(n){const t=_(n),e=t.safeDetail??"Upstream error details were omitted";return`Pi model request failed${t.httpStatus?` (HTTP ${t.httpStatus})`:""}: ${e}`}function it(n){try{return D(JSON.stringify(n))}catch{return"[unserializable]"}}function N(n){if(!n||typeof n!="object")return;const t=n;if(!(typeof t.input!="number"&&typeof t.output!="number"))return{inputTokens:typeof t.input=="number"?t.input:0,outputTokens:typeof t.output=="number"?t.output:0}}function st(n){const t=n?.trim();if(!t)return{};const e=t.indexOf("/");return e<=0||e===t.length-1?{modelId:t}:{provider:t.slice(0,e),modelId:t.slice(e+1)}}function T(n,t,e,i,s,c){const l=H(e,i,s,c),m=t?.filter(u=>u.kind!=="image")??[];if(!m.length)return`${l}${n}`;const a=m.map(u=>`[${u.name}](<${u.path}>)`);return`${l}${[n,"",...a].join(`
3
+ `)}`}function k(n,t){const e=[];for(const i of n??[]){if(i.kind!=="image"||!i.mimeType.startsWith("image/"))continue;let s=i.previewData?.trim()??"";const c=s.indexOf(",");if(s.startsWith("data:")&&c>=0&&(s=s.slice(c+1)),!s&&t&&i.path&&!/^https?:\/\//i.test(i.path))try{const l=f.statSync(i.path);l.isFile()&&l.size<=10*1024*1024&&(s=f.readFileSync(i.path).toString("base64"))}catch{s=""}s&&e.push({type:"image",data:s,mimeType:i.mimeType})}return e}class nt extends O{type="pi-coding-agent";get supportsActiveInput(){return!0}async injectActiveInput(t){const e=await this.readState();if(!this.rpc||!this.runId||!e.isStreaming&&!e.isCompacting)throw new Error("pi_active_turn_unavailable");const i={message:T(t.text,t.attachments,this.workDir,this.externalChannel,this.shennianSessionId,null)},s=k(t.attachments,!this.managedAgentPolicy);s.length&&(i.images=s),await this.rpc.request("steer",i)}get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!0}}process=null;rpc=null;shennianSessionId="";workDir="";sessionDir="";agentSessionId=null;externalChannel=null;extraEnv={};spawnedRoomContext=null;managedAgentPolicy=null;runId="";seq=0;active=!1;terminal=!0;stderr="";lastUsage;promptFile=null;persistNativeSession=!0;validationRoot=null;runPhase=null;processEnv={};turnDiagnostic=null;configure(t){t.sessionId&&(this.shennianSessionId=t.sessionId),this.externalChannel=t.externalChannel??null,this.extraEnv=t.env??{},"managedAgentPolicy"in t&&(this.managedAgentPolicy=t.managedAgentPolicy??null)}async start(t,e,i,s){await this.stopProcess(),this.shennianSessionId=t,this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??e,this.agentSessionId=i??null;const c=w("runtime","pi-coding-agent",E(t));this.persistNativeSession=s?.persistNativeSession!==!1,this.validationRoot=this.persistNativeSession?null:p.join(c,`validation-${A()}`),this.sessionDir=this.validationRoot?p.join(this.validationRoot,"sessions"):p.join(c,"sessions"),f.mkdirSync(this.sessionDir,{recursive:!0,mode:448}),process.platform!=="win32"&&f.chmodSync(this.sessionDir,448),this.active=!1,this.terminal=!0}async send(t,e,i,s,c,l){const m=J(),a=st(e),u=s?.length??0,r=s?.filter(y=>y.kind==="image").length??0;let h="process_start",I=!1;try{await this.ensureProcess(c);const y=this.requireRpc();h="state_read";let o=await this.readState();const g=!!(o.isStreaming||o.isCompacting);(!g||!this.runId)&&(this.runId=A(),this.seq=0,this.terminal=!1,this.lastUsage=void 0,this.runPhase="thinking");const d=a;if(d.modelId&&!g&&(o.model?.id!==d.modelId||d.provider&&o.model?.provider!==d.provider)){if(!d.provider)throw new Error("Pi model selection must include provider/modelId");h="model_selection",await y.request("set_model",{provider:d.provider,modelId:d.modelId}),h="state_read",o=await this.readState()}i&&!g&&(h="thinking_selection",await y.request("set_thinking_level",{level:i}));const b=K({model:o.model,env:this.processEnv});this.turnDiagnostic={marker:m,phase:"request_config",...S(d.provider)?{requestedProvider:S(d.provider)}:{},...S(d.modelId)?{requestedModel:S(d.modelId)}:{},modelSelectionSource:l?.modelSelectionSource??(e?"request_model":"pi_default_model"),piObservedRequestConfig:!0,finalHttpRequestObserved:!1,...b,historyMessageCount:Number.isSafeInteger(o.messageCount)?o.messageCount:null,attachmentCount:u,imageAttachmentCount:r,toolCallCount:0,queuedIntoActiveRun:g},console.info(P(this.turnDiagnostic)),I=!0;const q=g?l?.source==="room_activation"?"follow_up":"steer":"prompt",v={message:T(t,s,this.workDir,this.externalChannel,this.shennianSessionId,null)},C=k(s,!this.managedAgentPolicy);C.length&&(v.images=C),h="prompt_dispatch",await y.request(q,v)}catch(y){const o=_(y),g=this.turnDiagnostic??{marker:m,phase:"request_config",...S(a.provider)?{requestedProvider:S(a.provider)}:{},...S(a.modelId)?{requestedModel:S(a.modelId)}:{},modelSelectionSource:l?.modelSelectionSource??(e?"request_model":"pi_default_model"),piObservedRequestConfig:!1,finalHttpRequestObserved:!1,providerConfigSource:"unknown",credentialSource:"unknown",credentialPresent:"unknown",agentDirSource:this.processEnv.PI_CODING_AGENT_DIR?"pi_agent_dir_environment":"user_home_default",historyMessageCount:null,attachmentCount:u,imageAttachmentCount:r,toolCallCount:0,queuedIntoActiveRun:!1};throw I||console.info(P(g)),console.warn(P({...g,phase:"outcome",outcome:"failed",errorStage:h,errorCode:o.errorCode,...o.httpStatus?{httpStatus:o.httpStatus}:{}})),this.turnDiagnostic=null,new Error(`Pi ${h} failed${o.httpStatus?` (HTTP ${o.httpStatus})`:""}: ${o.safeDetail??o.errorCode}`)}}async resume(t){await this.stopProcess(),this.agentSessionId=t}async stop(){const t=this.rpc;t&&(await t.request("clear_queue").catch(()=>{}),await t.request("abort").catch(()=>{})),!this.terminal&&this.runId&&(this.logDiagnosticOutcome("aborted"),this.emitTerminal({state:"aborted"})),await this.stopProcess()}async getStatus(){if(!this.rpc||!this.process)return{active:!1,runId:null,canStop:!1};const t=await this.readState().catch(()=>null),e=!!(t?.isStreaming||t?.isCompacting||this.active);return{active:e,runId:e?this.runId:null,runPhase:e?this.runPhase??"thinking":null,canStop:e}}async setTitle(t,e){this.rpc&&await this.rpc.request("set_session_name",{name:e.slice(0,200)})}async ensureProcess(t){if(this.process&&this.rpc){if(!await this.roomContextStale())return;await this.stopProcess()}const e=$("pi-coding-agent");if(!e)throw new Error('Command "pi" not found. Install @earendil-works/pi-coding-agent from the official package.');const i=["--mode","rpc","--session-dir",this.sessionDir,"--offline"];if(this.agentSessionId&&i.push("--session",this.agentSessionId),this.managedAgentPolicy&&!x(this.managedAgentPolicy)){i.push("--no-extensions","--no-skills","--no-prompt-templates","--no-context-files");const r=this.managedTools(),h=W({outputPath:p.join(w("runtime","pi-coding-agent",E(this.shennianSessionId)),"managed-extension.ts"),policy:this.managedAgentPolicy,allowRoomControl:!!this.extraEnv.SHENNIAN_MANAGED_ROOM_CONTEXT,allowManagerControl:!!this.extraEnv.SHENNIAN_MANAGER_SESSION_ID,allowHostShell:this.managedAgentPolicy.adapterPolicy.fileAccess==="host-full"});i.push("--no-builtin-tools","--extension",h),r.length?i.push("--tools",r.join(",")):i.push("--no-tools")}const s=B(this.workDir,this.externalChannel,this.shennianSessionId,t),c=this.validationRoot??w("runtime","pi-coding-agent",E(this.shennianSessionId));f.mkdirSync(c,{recursive:!0,mode:448}),this.promptFile=p.join(c,"instructions.md"),f.writeFileSync(this.promptFile,s,{encoding:"utf8",mode:384}),process.platform!=="win32"&&f.chmodSync(this.promptFile,384),i.push("--append-system-prompt",this.promptFile);const l={NO_COLOR:"1"},m=this.managedAgentPolicy&&!x(this.managedAgentPolicy)?U({agentType:this.type,providerEnv:this.extraEnv,sessionEnv:this.extraEnv,runtimeEnv:l}):this.managedAgentPolicy?G({...l,...this.extraEnv}):F({...l,...this.extraEnv});this.processEnv=m;const a=j(e,i,{cwd:this.workDir,stdio:["pipe","pipe","pipe"],env:m});this.process=a,this.spawnedRoomContext=this.currentRoomContext(),this.stderr="",a.stderr?.on("data",r=>{const h=typeof r=="string"?r:r.toString("utf8");this.stderr=D(`${this.stderr}${h}`,V)});const u=new X(a);this.rpc=u,u.on("event",r=>this.handleRpcEvent(r)),u.on("protocolError",r=>this.emitError(r.message)),a.once("close",r=>{this.process===a&&(this.process=null,this.rpc=null,this.terminal||this.emitError(r===0?"Pi RPC process closed before agent_settled":`Pi RPC process exited with code ${r??"unknown"}${this.stderr?`: ${this.stderr}`:""}`))}),a.once("error",r=>{this.process===a&&this.emitError(r.message)});try{const r=await this.readState();if(!r.sessionId)throw new Error("Pi RPC did not return a session ID");if(r.isStreaming||r.isCompacting)throw new Error("Pi RPC session is not idle after startup");if(this.agentSessionId&&r.sessionId!==this.agentSessionId)throw new Error("Pi RPC resumed a different session");if(!r.sessionFile||!this.ownsSessionFile(r.sessionFile))throw new Error("Pi RPC returned a session file outside the Shennian-owned directory");this.agentSessionId=r.sessionId,this.persistNativeSession&&Y(r.sessionId,this.sessionDir)}catch(r){throw await this.stopProcess(),r}}currentRoomContext(){return this.extraEnv.SHENNIAN_MANAGED_ROOM_CONTEXT??null}async roomContextStale(){if(this.currentRoomContext()===this.spawnedRoomContext)return!1;const t=await this.readState().catch(()=>null);return!t?.isStreaming&&!t?.isCompacting}managedTools(){const t=this.managedAgentPolicy?.adapterPolicy;if(!t)return[];const e=["read","grep","find","ls"];(t.fileAccess==="workspace-write"||t.fileAccess==="host-full")&&e.push("edit","write");const i=!!this.extraEnv.SHENNIAN_MANAGER_SESSION_ID,s=!!this.extraEnv.SHENNIAN_MANAGED_ROOM_CONTEXT;return(i||s||t.fileAccess==="host-full")&&e.push("bash"),e}ownsSessionFile(t){const e=p.resolve(this.sessionDir),i=p.resolve(t),s=p.relative(e,i);return s!==""&&!s.startsWith("..")&&!p.isAbsolute(s)}async readState(){const t=await this.requireRpc().request("get_state");return tt(t)}requireRpc(){if(!this.rpc)throw new Error("Pi RPC process is not running");return this.rpc}handleRpcEvent(t){if(t.type==="agent_start"){this.active=!0,this.runPhase="thinking",this.emitEvent({state:"start",agentSessionId:this.agentSessionId??void 0});return}if(t.type==="message_update"){this.lastUsage=N(t.usage)??this.lastUsage;const e=t.assistantMessageEvent;if(!e||typeof e!="object")return;const i=e;i.type==="text_delta"&&typeof i.delta=="string"?(this.runPhase="streaming_text",this.emitEvent({state:"delta",text:i.delta})):i.type==="thinking_delta"&&typeof i.delta=="string"&&(this.runPhase="thinking",this.emitEvent({state:"delta",text:i.delta,thinking:!0}));return}if(t.type==="tool_execution_start"){this.turnDiagnostic&&(this.turnDiagnostic.toolCallCount+=1),this.runPhase="tool_running",this.emitEvent({state:"tool-call",name:typeof t.toolName=="string"?t.toolName:"tool",args:t.args&&typeof t.args=="object"&&!Array.isArray(t.args)?t.args:{}});return}if(t.type==="tool_execution_end"){this.runPhase="thinking",this.emitEvent({state:"tool-result",name:typeof t.toolName=="string"?t.toolName:"tool",result:et(t.result)||it(t.result)});return}if(t.type==="tool_execution_update"){this.emitEvent({state:"notify",runPhase:"tool_running",message:"Pi tool is running"});return}if(t.type==="message_end"){const e=t.message;if(e&&typeof e=="object"){const i=e;if(this.lastUsage=N(i.usage)??this.lastUsage,i.stopReason==="error"){const s=_(i.errorMessage);this.logDiagnosticOutcome("failed",{errorStage:"pi_model_turn",errorCode:s.errorCode,...s.httpStatus?{httpStatus:s.httpStatus}:{}}),this.emitError(R(i.errorMessage))}}return}if(t.type==="compaction_start"){this.runPhase="thinking",this.emitEvent({state:"notify",runPhase:"thinking",message:"Pi is compacting context"});return}if(t.type==="auto_retry_start"||t.type==="summarization_retry_scheduled"){this.runPhase="thinking",this.emitEvent({state:"notify",runPhase:"thinking",message:"Pi is retrying"});return}if(t.type==="extension_ui_request"){typeof t.id=="string"&&this.rpc?.notify("extension_ui_response",{id:t.id,cancelled:!0});return}if(t.type==="extension_error"){this.logDiagnosticOutcome("failed",{errorStage:"pi_process",errorCode:"extension_error"}),this.emitError(typeof t.error=="string"?t.error:"Pi extension failed");return}t.type==="agent_settled"&&(this.active=!1,this.logDiagnosticOutcome("completed"),this.emitTerminal({state:"final",agentSessionId:this.agentSessionId??void 0,usage:this.lastUsage}))}emitEvent(t){this.runId&&this.emit("agentEvent",{...t,runId:this.runId,seq:this.seq++})}emitTerminal(t){this.terminal||(this.terminal=!0,this.active=!1,this.runPhase=null,this.emitEvent(t))}logDiagnosticOutcome(t,e={}){this.turnDiagnostic&&(console.info(P({...this.turnDiagnostic,phase:"outcome",outcome:t,...e})),this.turnDiagnostic=null)}emitError(t){if(this.turnDiagnostic){const e=_(t);this.logDiagnosticOutcome("failed",{errorStage:"pi_process",errorCode:e.errorCode,...e.httpStatus?{httpStatus:e.httpStatus}:{}})}this.emitTerminal({state:"error",message:t.startsWith("Pi model request failed")?t:R(t)})}async stopProcess(){const t=this.process;this.process=null,this.rpc?.close(),this.rpc=null,t&&(t.kill("SIGTERM"),await new Promise(e=>{let i=!1;const s=()=>{i||(i=!0,e())};t.once("close",s),setTimeout(()=>{t.kill("SIGKILL"),s()},Q).unref()})),this.validationRoot&&(f.rmSync(this.validationRoot,{recursive:!0,force:!0}),this.validationRoot=null)}}M("pi-coding-agent",()=>new nt);export{nt as PiCodingAgentAdapter};
@@ -0,0 +1 @@
1
+ import _ from"node:fs";import v from"node:os";import p from"node:path";import{randomBytes as P}from"node:crypto";const y={anthropic:["ANTHROPIC_AUTH_TOKEN","ANTHROPIC_OAUTH_TOKEN","ANTHROPIC_API_KEY"],deepseek:["DEEPSEEK_API_KEY"],openai:["OPENAI_API_KEY"],openrouter:["OPENROUTER_API_KEY"],google:["GEMINI_API_KEY"],groq:["GROQ_API_KEY"],xai:["XAI_API_KEY"],mistral:["MISTRAL_API_KEY"],opencode:["OPENCODE_API_KEY"]};function f(e,t){if(typeof e!="string")return t;const n=e.trim();return/^[A-Za-z0-9][A-Za-z0-9._:/+-]{0,159}$/.test(n)?n:t}function w(e){return f(e,"")||void 0}function A(e){try{const t=_.statSync(e);if(!t.isFile()||t.size>1024*1024)return null;const n=JSON.parse(_.readFileSync(e,"utf8"));return n&&typeof n=="object"&&!Array.isArray(n)?n:null}catch{return null}}function I(e){const t=new Set;for(const n of e.matchAll(/\$(?:\{([A-Za-z_][A-Za-z0-9_]*)\}|([A-Za-z_][A-Za-z0-9_]*))/g))t.add(n[1]??n[2]);return[...t]}function g(e,t){if(typeof e!="string"||!e.trim())return{source:"unknown",present:!1};const n=e.trim();if(n.startsWith("!"))return{source:"models_file_command",present:"unknown"};const r=I(n);return r.length?{source:"models_file_environment",present:!!r.every(i=>!!t[i])}:{source:"models_file_literal",present:!0}}function O(e,t){if(!e||typeof e!="object"||Array.isArray(e))return null;const n=e;if(n.type==="oauth")return{source:"oauth",present:typeof n.access=="string"&&n.access.length>0};if(n.type!=="api_key")return null;const r=n.env&&typeof n.env=="object"&&!Array.isArray(n.env)?Object.fromEntries(Object.entries(n.env).filter(o=>typeof o[1]=="string")):{};return{source:"auth_file",present:g(n.key,{...t,...r}).present}}function D(e){if(typeof e=="string")try{const t=new URL(e);return t.protocol!=="http:"&&t.protocol!=="https:"||!t.hostname?void 0:{scheme:t.protocol.slice(0,-1),host:t.hostname,...t.port?{port:t.port}:{}}}catch{return}}function T(e){const t=f(e.model?.provider,"unknown"),n=f(e.model?.id,"unknown"),r=e.agentDir??(e.env.PI_CODING_AGENT_DIR?.trim()||p.join(e.env.HOME?.trim()||v.homedir(),".pi","agent")),i=e.agentDir||e.env.PI_CODING_AGENT_DIR?.trim()?"pi_agent_dir_environment":"user_home_default",o=A(p.join(r,"models.json")),c=(o?.providers&&typeof o.providers=="object"&&!Array.isArray(o.providers)?o.providers:null)?.[t],s=c&&typeof c=="object"&&!Array.isArray(c)?c:null,h=s?"models_file":t==="unknown"?"unknown":"pi_runtime_catalog",E=A(p.join(r,"auth.json")),l=O(E?.[t],e.env);let a="unknown",d=y[t]||s?!1:"unknown";if(l)a=l.source,d=l.present;else if((y[t]??[]).some(u=>!!e.env[u]))a="process_environment",d=!0;else if(s&&"apiKey"in s){const u=g(s.apiKey,e.env);a=u.source,d=u.present}return{provider:t,model:n,api:f(e.model?.api,"unknown"),target:D(e.model?.baseUrl),providerConfigSource:h,credentialSource:a,credentialPresent:d,agentDirSource:i}}function k(){return P(9).toString("base64url")}function S(e){const t=e instanceof Error?e.message:typeof e=="string"?e:"",n=t.match(/(?:^|\D)([1-5]\d\d)(?:\D|$)/),r=n?Number(n[1]):void 0,o=[[/request not allowed/i,"request_not_allowed","Request not allowed"],[/provider unavailable/i,"provider_unavailable","Provider unavailable"],[/model not found/i,"model_not_found","Model not found"],[/rate[ -]?limit/i,"rate_limited","Rate limited"],[/quota/i,"quota_exceeded","Quota exceeded"],[/unauthori[sz]ed|authentication required|invalid api key/i,"authentication_rejected","Authentication rejected"],[/forbidden/i,"forbidden","Forbidden"],[/timed? out|timeout/i,"timeout","Timed out"],[/connection (?:refused|reset)|fetch failed/i,"connection_failed","Connection failed"]].find(([m])=>m.test(t));return{errorCode:r?`http_${r}`:o?.[1]??"pi_error",...r?{httpStatus:r}:{},...o?{safeDetail:o[2]}:{}}}function C(e){return`[pi.diagnostic] ${JSON.stringify(e)}`}export{S as classifyPiFailure,k as createPiDiagnosticMarker,C as formatPiDiagnostic,T as inspectPiTurnConfiguration,w as sanitizePiDiagnosticDimension};
@@ -0,0 +1 @@
1
+ import{spawn as p}from"node:child_process";const m=process.platform!=="win32";function n(e){return e.exitCode!==null||e.signalCode!==null}function o(e,r,t){if(process.platform==="win32"){p("taskkill",["/PID",String(r),"/T",...t?["/F"]:[]],{stdio:"ignore",windowsHide:!0}).unref();return}try{process.kill(-r,t?"SIGKILL":"SIGTERM")}catch{try{e.kill(t?"SIGKILL":"SIGTERM")}catch{}}}function w(e,r=!1){!e.pid||n(e)||o(e,e.pid,r)}async function c(e,r=3e3){const t=e.pid;if(!t)return;let i=null;const u=n(e)?Promise.resolve():new Promise(a=>{e.once("exit",()=>a())}),s=async a=>{await Promise.race([u,new Promise(f=>{i=setTimeout(f,a)})]),i&&clearTimeout(i)};if(process.platform==="win32"){n(e)||o(e,t,!0),await s(r);return}n(e)||o(e,t,!1),await s(r),o(e,t,!0),n(e)||await s(1e3)}export{m as DETACH_PROCESS_GROUP,c as stopProcessTree,w as terminateProcessTree};
@@ -1,2 +1,2 @@
1
- import{callDaemonIpc as s}from"../daemon-ipc/client.js";import{DaemonIpcError as i}from"../daemon-ipc/protocol.js";const d={method_not_found:"Update the existing Shennian installation: Desktop through Desktop updates, standalone CLI through its own update flow. Do not install a second Client.",daemon_unavailable:"Check shennian status --json on the target computer. Do not resume an intentional pause without the user requesting it.",daemon_paused:"Shennian is paused. Ask the user to resume it before checking.",ipc_timeout:"The result is unknown. Check the target machine and wait for the current check to finish; do not repeatedly send tests.",agent_check_in_progress:"Wait for the running check to finish before trying again.",agent_validation_runtime_unavailable:"Refresh discovery. If the tool is still missing, guide the user through its official installation on this computer.",agent_validation_runtime_auth_required:"Guide the user through the provider\u2019s own sign-in on this computer, then retry the selected AI and model.",agent_validation_model_unavailable:"Choose a model returned by discovery and check the provider account\u2019s model access.",agent_validation_quota_exceeded:"Check the provider account\u2019s credits, subscription or rate limit before another test.",agent_validation_network_failed:"Check the target computer\u2019s connection to the provider, then retry when it is available.",agent_validation_workdir_invalid:"Use an existing absolute project directory on this computer that the user allows Shennian to use.",agent_validation_workdir_not_found:"The working directory does not exist on this computer. Ask the user for an existing absolute project directory (it may have been moved, deleted or is on an unmounted drive); do not create it for them.",agent_validation_workdir_not_directory:"The working directory path is a file, not a folder. Ask the user for the project folder.",agent_validation_workdir_unavailable:"The working directory exists but this user cannot access it. Check its permissions on this computer or choose another directory.",agent_validation_start_failed:"The AI could not start. Run the tool once on this computer to see its own error, fix its installation or configuration, then retry.",agent_validation_response_timeout:"The AI started but gave no hello reply within 60 seconds. Check its provider sign-in, selected model and network, then retry once; do not repeatedly send tests.",agent_validation_response_mismatch:"The AI replied but not with hello. Check the selected model; a reply that ignores simple instructions usually means a wrong or misconfigured model.",agent_validation_response_failed:"The AI started but failed while replying. Check its provider sign-in, selected model, quota and network, then retry once."},r={agent_validation_runtime_unavailable:"start",agent_validation_workdir_invalid:"start",agent_validation_workdir_not_found:"start",agent_validation_workdir_not_directory:"start",agent_validation_workdir_unavailable:"start",agent_validation_start_failed:"start",agent_validation_runtime_auth_required:"auth",agent_validation_model_unavailable:"model",agent_validation_quota_exceeded:"quota",agent_validation_network_failed:"network",agent_validation_response_timeout:"reply",agent_validation_response_mismatch:"reply",agent_validation_response_failed:"reply"},l="A successful check only proves one standard-mode hello reply; it does not prove the AI can send messages in a Room.",c={authState:'unknown means Shennian has no login probe for this AI; it is not "not logged in".',defaultModelId:"null means no model is marked default; it does not mean no model is available. The AI picks its own model when none is passed."};async function u(t,a,o=s){try{const e=await o({method:t,params:a,timeoutMs:9e4});if(t==="agent.check"&&(!e||typeof e!="object"||Array.isArray(e)||e.ready!==!0))throw new i("agent_check_invalid_response","The daemon did not confirm a successful hello reply.");return t==="agent.discover"&&e&&typeof e=="object"&&!Array.isArray(e)?{ok:!0,command:t,result:{...e,notes:c}}:t==="agent.check"&&e&&typeof e=="object"&&!Array.isArray(e)?{ok:!0,command:t,result:{...e,note:l}}:{ok:!0,command:t,result:e}}catch(e){const n=e instanceof i?e.code:"agent_check_failed";return{ok:!1,command:t,error:n,...r[n]?{stage:r[n]}:{},nextAction:d[n]??"Return to the AI preparation guide on this machine. Check the selected directory, account, model and network; do not reinstall by default."}}}function m(t){const a=async(o,e)=>{const n=await u(o,e);process.stdout.write(`${JSON.stringify(n)}
2
- `),n.ok||(process.exitCode=1)};t.command("discover").description("Read the daemon AI snapshot; use --refresh only to rerun local provider and model discovery").option("--agent <type>","Return only one discovered Agent type").option("--compact","Return capability summary without the full model list").option("--refresh","Rerun discovery; with --agent, probe only that Agent").option("--json","Print JSON (default)").action(o=>a("agent.discover",{...o.agent?{agentType:o.agent}:{},compact:o.compact===!0,refresh:o.refresh===!0})),t.command("check <agentType>").description("Send one hello test using the selected AI and model; uses provider quota, creates no managed Agent or room").requiredOption("--workdir <path>","Absolute project directory on this machine").option("--model <id>","Model returned by discovery; otherwise use the provider default").option("--json","Print JSON (default)").action((o,e)=>a("agent.check",{agentType:o,workDir:e.workdir,modelId:e.model??null}))}export{u as executeAgentReadinessCommand,m as registerAgentReadinessCommands};
1
+ import{callDaemonIpc as s}from"../daemon-ipc/client.js";import{DaemonIpcError as r}from"../daemon-ipc/protocol.js";const d={method_not_found:"Update the existing Shennian installation: Desktop through Desktop updates, standalone CLI through its own update flow. Do not install a second Client.",daemon_unavailable:"Check shennian status --json on the target computer. Do not resume an intentional pause without the user requesting it.",daemon_paused:"Shennian is paused. Ask the user to resume it before checking.",ipc_timeout:"The daemon did not answer in time, so the result is unknown; the machine is usually overloaded. Check its load and memory (uptime, free -m) and wait for the running check to end; do not repeatedly send tests. If the AI's own processes are still running afterwards, stop only those exact processes.",agent_check_in_progress:"Wait for the running check to finish before trying again.",agent_validation_runtime_unavailable:"Refresh discovery. If the tool is still missing, guide the user through its official installation on this computer.",agent_validation_runtime_auth_required:"Guide the user through the provider\u2019s own sign-in on this computer, then retry the selected AI and model.",agent_validation_model_unavailable:"Choose a model returned by discovery and check the provider account\u2019s model access.",agent_validation_quota_exceeded:"Check the provider account\u2019s credits, subscription or rate limit before another test.",agent_validation_network_failed:"Check the target computer\u2019s connection to the provider, then retry when it is available.",agent_validation_workdir_invalid:"Use an existing absolute project directory on this computer that the user allows Shennian to use.",agent_validation_workdir_not_found:"The working directory does not exist on this computer. Ask the user for an existing absolute project directory (it may have been moved, deleted or is on an unmounted drive); do not create it for them.",agent_validation_workdir_not_directory:"The working directory path is a file, not a folder. Ask the user for the project folder.",agent_validation_workdir_unavailable:"The working directory exists but this user cannot access it. Check its permissions on this computer or choose another directory.",agent_validation_start_failed:"The AI could not start, or did not finish starting within 60 seconds. Run the tool once on this computer to see its own error, fix its installation or configuration, then retry once.",agent_validation_response_timeout:"The AI started but gave no hello reply within 60 seconds and its processes were stopped. Check the computer's load and free memory first, then its provider sign-in, selected model and network; retry once and do not repeatedly send tests.",agent_validation_response_mismatch:"The AI replied but not with hello. Check the selected model; a reply that ignores simple instructions usually means a wrong or misconfigured model.",agent_validation_response_failed:"The AI started but failed while replying. Check its provider sign-in, selected model, quota and network, then retry once."},l={agent_validation_runtime_unavailable:"start",agent_validation_workdir_invalid:"start",agent_validation_workdir_not_found:"start",agent_validation_workdir_not_directory:"start",agent_validation_workdir_unavailable:"start",agent_validation_start_failed:"start",agent_validation_runtime_auth_required:"auth",agent_validation_model_unavailable:"model",agent_validation_quota_exceeded:"quota",agent_validation_network_failed:"network",agent_validation_response_timeout:"reply",agent_validation_response_mismatch:"reply",agent_validation_response_failed:"reply"},c=9e4,u="A successful check only proves one standard-mode hello reply; it does not prove the AI can send messages in a Room.",h={authState:'unknown means Shennian has no login probe for this AI; it is not "not logged in".',defaultModelId:"null means no model is marked default; it does not mean no model is available. The AI picks its own model when none is passed."};async function _(t,a,o=s){try{const e=await o({method:t,params:a,timeoutMs:c});if(t==="agent.check"&&(!e||typeof e!="object"||Array.isArray(e)||e.ready!==!0))throw new r("agent_check_invalid_response","The daemon did not confirm a successful hello reply.");return t==="agent.discover"&&e&&typeof e=="object"&&!Array.isArray(e)?{ok:!0,command:t,result:{...e,notes:h}}:t==="agent.check"&&e&&typeof e=="object"&&!Array.isArray(e)?{ok:!0,command:t,result:{...e,note:u}}:{ok:!0,command:t,result:e}}catch(e){const n=e instanceof r?e.code:"agent_check_failed",i=l[n]??(t==="agent.check"&&n==="ipc_timeout"?"reply":void 0);return{ok:!1,command:t,error:n,...i?{stage:i}:{},nextAction:d[n]??"Return to the AI preparation guide on this machine. Check the selected directory, account, model and network; do not reinstall by default."}}}function g(t){const a=async(o,e)=>{const n=await _(o,e);process.stdout.write(`${JSON.stringify(n)}
2
+ `),n.ok||(process.exitCode=1)};t.command("discover").description("Read the daemon AI snapshot; use --refresh only to rerun local provider and model discovery").option("--agent <type>","Return only one discovered Agent type").option("--compact","Return capability summary without the full model list").option("--refresh","Rerun discovery; with --agent, probe only that Agent").option("--json","Print JSON (default)").action(o=>a("agent.discover",{...o.agent?{agentType:o.agent}:{},compact:o.compact===!0,refresh:o.refresh===!0})),t.command("check <agentType>").description("Send one hello test using the selected AI and model; uses provider quota, creates no managed Agent or room").requiredOption("--workdir <path>","Absolute project directory on this machine").option("--model <id>","Model returned by discovery; otherwise use the provider default").option("--json","Print JSON (default)").action((o,e)=>a("agent.check",{agentType:o,workDir:e.workdir,modelId:e.model??null}))}export{c as AGENT_READINESS_IPC_TIMEOUT_MS,_ as executeAgentReadinessCommand,g as registerAgentReadinessCommands};