shennian 0.5.14 → 0.5.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/publish-build-manifest.json +110 -45
  2. package/dist/src/agents/acp/adapter.js +2 -2
  3. package/dist/src/agents/acp/discovery.js +1 -1
  4. package/dist/src/agents/adapter.js +2 -1
  5. package/dist/src/agents/claude-permission-bridge.js +3 -0
  6. package/dist/src/agents/claude-permission-protocol.js +1 -0
  7. package/dist/src/agents/claude-permission-relay-server.js +3 -0
  8. package/dist/src/agents/claude.js +7 -7
  9. package/dist/src/agents/codex-runtime.js +7 -7
  10. package/dist/src/agents/project-client.js +1 -0
  11. package/dist/src/agents/workbuddy.js +3 -2
  12. package/dist/src/commands/daemon.js +9 -9
  13. package/dist/src/commands/pair-browser.js +1 -1
  14. package/dist/src/commands/pair.js +11 -11
  15. package/dist/src/commands/project.js +4 -0
  16. package/dist/src/commands/setup.js +4 -0
  17. package/dist/src/commands/steward.js +3 -0
  18. package/dist/src/daemon-ipc/agent-readiness.js +1 -1
  19. package/dist/src/daemon-ipc/control.js +1 -1
  20. package/dist/src/index.js +3 -3
  21. package/dist/src/session/handlers/chat-adapter-config.js +1 -1
  22. package/dist/src/session/handlers/chat-events.js +2 -2
  23. package/dist/src/session/handlers/chat-session-lifecycle.js +1 -1
  24. package/dist/src/session/handlers/chat.js +1 -1
  25. package/dist/src/session/handlers/steward.js +1 -0
  26. package/dist/src/session/manager.js +1 -1
  27. package/dist/src/session/queue.js +1 -1
  28. package/dist/src/session/store.js +2 -2
  29. package/dist/src/skill/hosts.js +1 -0
  30. package/dist/src/skill/updater.js +1 -1
  31. package/dist/src/steward/session.js +2 -0
  32. package/dist/src/steward/templates.js +66 -0
  33. package/dist/src/steward/workspace.js +1 -0
  34. package/dist/src/upgrade/engine.js +2 -2
  35. package/dist/src/upgrade/npm-command.js +1 -0
  36. package/dist/src/upgrade/updater-launcher.js +3 -3
  37. package/node_modules/@shennian/wire/dist/message-payload.js +5 -5
  38. package/node_modules/@shennian/wire/dist/session.js +1 -1
  39. package/package.json +1 -1
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "jsMinified": true,
4
4
  "minifier": "esbuild",
5
- "fileCount": 265,
5
+ "fileCount": 278,
6
6
  "files": [
7
7
  {
8
8
  "file": "bin/shennian-adapter-host.js",
@@ -51,8 +51,8 @@
51
51
  },
52
52
  {
53
53
  "file": "src/agents/acp/adapter.js",
54
- "beforeBytes": 27928,
55
- "afterBytes": 14294
54
+ "beforeBytes": 29185,
55
+ "afterBytes": 14875
56
56
  },
57
57
  {
58
58
  "file": "src/agents/acp/auth-state.js",
@@ -81,8 +81,8 @@
81
81
  },
82
82
  {
83
83
  "file": "src/agents/acp/discovery.js",
84
- "beforeBytes": 10037,
85
- "afterBytes": 4586
84
+ "beforeBytes": 11154,
85
+ "afterBytes": 5045
86
86
  },
87
87
  {
88
88
  "file": "src/agents/acp/events.js",
@@ -121,8 +121,8 @@
121
121
  },
122
122
  {
123
123
  "file": "src/agents/adapter.js",
124
- "beforeBytes": 3950,
125
- "afterBytes": 1948
124
+ "beforeBytes": 5709,
125
+ "afterBytes": 2700
126
126
  },
127
127
  {
128
128
  "file": "src/agents/auth-status.js",
@@ -134,10 +134,25 @@
134
134
  "beforeBytes": 10147,
135
135
  "afterBytes": 4390
136
136
  },
137
+ {
138
+ "file": "src/agents/claude-permission-bridge.js",
139
+ "beforeBytes": 2349,
140
+ "afterBytes": 901
141
+ },
142
+ {
143
+ "file": "src/agents/claude-permission-protocol.js",
144
+ "beforeBytes": 592,
145
+ "afterBytes": 194
146
+ },
147
+ {
148
+ "file": "src/agents/claude-permission-relay-server.js",
149
+ "beforeBytes": 4278,
150
+ "afterBytes": 1936
151
+ },
137
152
  {
138
153
  "file": "src/agents/claude.js",
139
- "beforeBytes": 22170,
140
- "afterBytes": 10367
154
+ "beforeBytes": 26522,
155
+ "afterBytes": 12490
141
156
  },
142
157
  {
143
158
  "file": "src/agents/codex-managed-permissions.js",
@@ -156,8 +171,8 @@
156
171
  },
157
172
  {
158
173
  "file": "src/agents/codex-runtime.js",
159
- "beforeBytes": 30730,
160
- "afterBytes": 15704
174
+ "beforeBytes": 30637,
175
+ "afterBytes": 15640
161
176
  },
162
177
  {
163
178
  "file": "src/agents/codex-utils.js",
@@ -334,6 +349,11 @@
334
349
  "beforeBytes": 2647,
335
350
  "afterBytes": 856
336
351
  },
352
+ {
353
+ "file": "src/agents/project-client.js",
354
+ "beforeBytes": 3287,
355
+ "afterBytes": 1907
356
+ },
337
357
  {
338
358
  "file": "src/agents/public-agent-client.js",
339
359
  "beforeBytes": 8149,
@@ -386,8 +406,8 @@
386
406
  },
387
407
  {
388
408
  "file": "src/agents/workbuddy.js",
389
- "beforeBytes": 18932,
390
- "afterBytes": 9931
409
+ "beforeBytes": 20120,
410
+ "afterBytes": 10409
391
411
  },
392
412
  {
393
413
  "file": "src/commands/adapter.js",
@@ -456,8 +476,8 @@
456
476
  },
457
477
  {
458
478
  "file": "src/commands/daemon.js",
459
- "beforeBytes": 37512,
460
- "afterBytes": 19028
479
+ "beforeBytes": 38777,
480
+ "afterBytes": 19473
461
481
  },
462
482
  {
463
483
  "file": "src/commands/integration.js",
@@ -481,8 +501,8 @@
481
501
  },
482
502
  {
483
503
  "file": "src/commands/pair-browser.js",
484
- "beforeBytes": 6809,
485
- "afterBytes": 3822
504
+ "beforeBytes": 8274,
505
+ "afterBytes": 4389
486
506
  },
487
507
  {
488
508
  "file": "src/commands/pair-qr.js",
@@ -491,8 +511,13 @@
491
511
  },
492
512
  {
493
513
  "file": "src/commands/pair.js",
494
- "beforeBytes": 16512,
495
- "afterBytes": 9134
514
+ "beforeBytes": 16665,
515
+ "afterBytes": 9147
516
+ },
517
+ {
518
+ "file": "src/commands/project.js",
519
+ "beforeBytes": 5588,
520
+ "afterBytes": 3743
496
521
  },
497
522
  {
498
523
  "file": "src/commands/queue.js",
@@ -514,11 +539,21 @@
514
539
  "beforeBytes": 1288,
515
540
  "afterBytes": 936
516
541
  },
542
+ {
543
+ "file": "src/commands/setup.js",
544
+ "beforeBytes": 16589,
545
+ "afterBytes": 12325
546
+ },
517
547
  {
518
548
  "file": "src/commands/skill.js",
519
549
  "beforeBytes": 1616,
520
550
  "afterBytes": 991
521
551
  },
552
+ {
553
+ "file": "src/commands/steward.js",
554
+ "beforeBytes": 3628,
555
+ "afterBytes": 1852
556
+ },
522
557
  {
523
558
  "file": "src/commands/support.js",
524
559
  "beforeBytes": 5435,
@@ -546,8 +581,8 @@
546
581
  },
547
582
  {
548
583
  "file": "src/daemon-ipc/agent-readiness.js",
549
- "beforeBytes": 5102,
550
- "afterBytes": 2553
584
+ "beforeBytes": 5262,
585
+ "afterBytes": 2622
551
586
  },
552
587
  {
553
588
  "file": "src/daemon-ipc/client.js",
@@ -556,8 +591,8 @@
556
591
  },
557
592
  {
558
593
  "file": "src/daemon-ipc/control.js",
559
- "beforeBytes": 5067,
560
- "afterBytes": 2847
594
+ "beforeBytes": 5406,
595
+ "afterBytes": 3042
561
596
  },
562
597
  {
563
598
  "file": "src/daemon-ipc/json.js",
@@ -626,8 +661,8 @@
626
661
  },
627
662
  {
628
663
  "file": "src/index.js",
629
- "beforeBytes": 45207,
630
- "afterBytes": 22296
664
+ "beforeBytes": 45702,
665
+ "afterBytes": 22628
631
666
  },
632
667
  {
633
668
  "file": "src/log-redaction.js",
@@ -1046,8 +1081,8 @@
1046
1081
  },
1047
1082
  {
1048
1083
  "file": "src/session/handlers/chat-adapter-config.js",
1049
- "beforeBytes": 2897,
1050
- "afterBytes": 1207
1084
+ "beforeBytes": 3004,
1085
+ "afterBytes": 1276
1051
1086
  },
1052
1087
  {
1053
1088
  "file": "src/session/handlers/chat-context.js",
@@ -1056,8 +1091,8 @@
1056
1091
  },
1057
1092
  {
1058
1093
  "file": "src/session/handlers/chat-events.js",
1059
- "beforeBytes": 18625,
1060
- "afterBytes": 7583
1094
+ "beforeBytes": 19549,
1095
+ "afterBytes": 7896
1061
1096
  },
1062
1097
  {
1063
1098
  "file": "src/session/handlers/chat-recovery.js",
@@ -1066,13 +1101,13 @@
1066
1101
  },
1067
1102
  {
1068
1103
  "file": "src/session/handlers/chat-session-lifecycle.js",
1069
- "beforeBytes": 4472,
1070
- "afterBytes": 2119
1104
+ "beforeBytes": 4614,
1105
+ "afterBytes": 2217
1071
1106
  },
1072
1107
  {
1073
1108
  "file": "src/session/handlers/chat.js",
1074
- "beforeBytes": 35377,
1075
- "afterBytes": 15049
1109
+ "beforeBytes": 36637,
1110
+ "afterBytes": 15539
1076
1111
  },
1077
1112
  {
1078
1113
  "file": "src/session/handlers/control.js",
@@ -1109,6 +1144,11 @@
1109
1144
  "beforeBytes": 979,
1110
1145
  "afterBytes": 451
1111
1146
  },
1147
+ {
1148
+ "file": "src/session/handlers/steward.js",
1149
+ "beforeBytes": 4879,
1150
+ "afterBytes": 2411
1151
+ },
1112
1152
  {
1113
1153
  "file": "src/session/handlers/title.js",
1114
1154
  "beforeBytes": 3146,
@@ -1141,8 +1181,8 @@
1141
1181
  },
1142
1182
  {
1143
1183
  "file": "src/session/manager.js",
1144
- "beforeBytes": 41108,
1145
- "afterBytes": 21675
1184
+ "beforeBytes": 41740,
1185
+ "afterBytes": 21934
1146
1186
  },
1147
1187
  {
1148
1188
  "file": "src/session/native-cleanup-outbox.js",
@@ -1206,8 +1246,8 @@
1206
1246
  },
1207
1247
  {
1208
1248
  "file": "src/session/queue.js",
1209
- "beforeBytes": 41453,
1210
- "afterBytes": 18387
1249
+ "beforeBytes": 42595,
1250
+ "afterBytes": 18826
1211
1251
  },
1212
1252
  {
1213
1253
  "file": "src/session/queued-chat-dispatch.js",
@@ -1246,8 +1286,8 @@
1246
1286
  },
1247
1287
  {
1248
1288
  "file": "src/session/store.js",
1249
- "beforeBytes": 32866,
1250
- "afterBytes": 16769
1289
+ "beforeBytes": 33544,
1290
+ "afterBytes": 17052
1251
1291
  },
1252
1292
  {
1253
1293
  "file": "src/session/tool-detail-store.js",
@@ -1264,10 +1304,30 @@
1264
1304
  "beforeBytes": 164,
1265
1305
  "afterBytes": 1
1266
1306
  },
1307
+ {
1308
+ "file": "src/skill/hosts.js",
1309
+ "beforeBytes": 3462,
1310
+ "afterBytes": 1577
1311
+ },
1267
1312
  {
1268
1313
  "file": "src/skill/updater.js",
1269
- "beforeBytes": 15894,
1270
- "afterBytes": 8136
1314
+ "beforeBytes": 18411,
1315
+ "afterBytes": 9229
1316
+ },
1317
+ {
1318
+ "file": "src/steward/session.js",
1319
+ "beforeBytes": 2700,
1320
+ "afterBytes": 1758
1321
+ },
1322
+ {
1323
+ "file": "src/steward/templates.js",
1324
+ "beforeBytes": 4518,
1325
+ "afterBytes": 7614
1326
+ },
1327
+ {
1328
+ "file": "src/steward/workspace.js",
1329
+ "beforeBytes": 3881,
1330
+ "afterBytes": 1828
1271
1331
  },
1272
1332
  {
1273
1333
  "file": "src/support/support-client.js",
@@ -1291,8 +1351,13 @@
1291
1351
  },
1292
1352
  {
1293
1353
  "file": "src/upgrade/engine.js",
1294
- "beforeBytes": 16718,
1295
- "afterBytes": 7089
1354
+ "beforeBytes": 16784,
1355
+ "afterBytes": 7123
1356
+ },
1357
+ {
1358
+ "file": "src/upgrade/npm-command.js",
1359
+ "beforeBytes": 1670,
1360
+ "afterBytes": 566
1296
1361
  },
1297
1362
  {
1298
1363
  "file": "src/upgrade/scheduler.js",
@@ -1306,8 +1371,8 @@
1306
1371
  },
1307
1372
  {
1308
1373
  "file": "src/upgrade/updater-launcher.js",
1309
- "beforeBytes": 10317,
1310
- "afterBytes": 5253
1374
+ "beforeBytes": 10380,
1375
+ "afterBytes": 5299
1311
1376
  },
1312
1377
  {
1313
1378
  "file": "src/upgrade/updater-protocol.js",
@@ -1,3 +1,3 @@
1
- import{randomUUID as y}from"node:crypto";import{createHash as S}from"node:crypto";import{realpathSync as w}from"node:fs";import{pathToFileURL as v}from"node:url";import*as a from"@agentclientprotocol/sdk";import{RequestError as A}from"@agentclientprotocol/sdk";import{AgentAdapter as P,registerAgent as b}from"../adapter.js";import{mapAcpSessionUpdate as q}from"./events.js";import{AcpProcessClient as E}from"./process-client.js";import{acpAgentType as I}from"./types.js";import{runAcpTerminalAuthentication as T}from"./auth.js";import{setAcpRuntimeAuthState as p}from"./auth-state.js";import{recordAcpAuthFailure as x,recordAcpImportResult as C}from"./metrics.js";import{isManagedAgentNativeFull as m}from"../../security/managed-agent-policy.js";import{buildManagedNativeFullProcessEnv as O}from"../../agent-env.js";import{assertPublicAgentPolicy as _}from"../../security/public-agent-policy.js";function g(l,e){return l.find(t=>t.category===e&&t.type==="select")}function f(l){return(l?.options??[]).flatMap(e=>"options"in e?e.options:[e])}class k extends P{manifest;options;type;get recoveryCapabilities(){const e=this.client?.capabilities;return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!!(e?.sessionCapabilities?.resume||e?.loadSession)}}client=null;workDir="";shennianSessionId="";requestedSessionId=null;agentSessionId=null;runId="";seq=0;active=!1;extraEnv={};pendingPermissions=new Map;configOptions=[];modes=null;importCapture=null;emittedToolStates=new Map;pendingAuthRetry=null;retryingAfterAuth=!1;managedAgentPolicy=null;publicTurn=!1;baseConfigurationSignature="";startedConfigurationSignature="";constructor(e,t={}){super(),this.manifest=e,this.options=t,this.type=I(e.id)}configure(e){this.extraEnv=e.env??{},this.managedAgentPolicy=e.managedAgentPolicy??null,this.baseConfigurationSignature=S("sha256").update(JSON.stringify({env:Object.entries(this.extraEnv).sort(([t],[n])=>t.localeCompare(n)),managedAgentPolicy:this.managedAgentPolicy})).digest("hex")}get configurationSignature(){return`${this.baseConfigurationSignature}:${this.publicTurn?"public":"room"}`}async start(e,t,n){this.shennianSessionId=e;try{this.workDir=w.native(t)}catch{this.workDir=t}this.requestedSessionId=n??null,this.agentSessionId=null,this.client=this.createProcessClient(),await this.client.start(this.workDir),this.startedConfigurationSignature=this.configurationSignature}async send(e,t,n,i,s,r){r?.source==="published_agent"&&_(this.managedAgentPolicy),this.publicTurn=r?.source==="published_agent",await this.refreshProcessConfiguration();const u=this.requireClient();this.runId=y(),this.seq=0,this.emittedToolStates.clear();try{await this.ensureSession(),await this.applyDynamicConfig(t,n),this.active=!0,this.emitEvent({state:"start",runPhase:"thinking",agentSessionId:this.agentSessionId??void 0});const o=[],c=[];s?.trim()&&c.push(s.trim()),c.push(e),o.push({type:"text",text:c.join(`
1
+ import{randomUUID as S}from"node:crypto";import{createHash as I}from"node:crypto";import{readFileSync as P,realpathSync as w,statSync as b}from"node:fs";import{pathToFileURL as q}from"node:url";import*as l from"@agentclientprotocol/sdk";import{RequestError as T}from"@agentclientprotocol/sdk";import{AgentAdapter as E,registerAgent as x,summarizeToolInput as O}from"../adapter.js";import{mapAcpSessionUpdate as _}from"./events.js";import{AcpProcessClient as k}from"./process-client.js";import{acpAgentType as C}from"./types.js";import{runAcpTerminalAuthentication as M}from"./auth.js";import{setAcpRuntimeAuthState as p}from"./auth-state.js";import{recordAcpAuthFailure as R,recordAcpImportResult as v}from"./metrics.js";import{isManagedAgentNativeFull as m}from"../../security/managed-agent-policy.js";import{buildManagedNativeFullProcessEnv as F}from"../../agent-env.js";import{assertPublicAgentPolicy as U}from"../../security/public-agent-policy.js";const D=10*1024*1024;function $(r){if(r.kind!=="image"||!r.mimeType.startsWith("image/"))return null;let e=r.previewData?.trim()??"";const t=e.indexOf(",");if(e.startsWith("data:")&&t>=0&&(e=e.slice(t+1)),!e&&r.path&&!/^https?:\/\//i.test(r.path))try{const s=b(r.path);s.isFile()&&s.size<=D&&(e=P(r.path).toString("base64"))}catch{e=""}return e?{data:e}:null}function g(r,e){return r.find(t=>t.category===e&&t.type==="select")}function f(r){return(r?.options??[]).flatMap(e=>"options"in e?e.options:[e])}class H extends E{manifest;options;type;get recoveryCapabilities(){const e=this.client?.capabilities;return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!!(e?.sessionCapabilities?.resume||e?.loadSession)}}client=null;workDir="";shennianSessionId="";requestedSessionId=null;agentSessionId=null;runId="";seq=0;active=!1;extraEnv={};pendingPermissions=new Map;configOptions=[];modes=null;importCapture=null;emittedToolStates=new Map;pendingAuthRetry=null;retryingAfterAuth=!1;managedAgentPolicy=null;publicTurn=!1;baseConfigurationSignature="";startedConfigurationSignature="";constructor(e,t={}){super(),this.manifest=e,this.options=t,this.type=C(e.id)}configure(e){this.extraEnv=e.env??{},this.managedAgentPolicy=e.managedAgentPolicy??null,this.baseConfigurationSignature=I("sha256").update(JSON.stringify({env:Object.entries(this.extraEnv).sort(([t],[s])=>t.localeCompare(s)),managedAgentPolicy:this.managedAgentPolicy})).digest("hex")}get configurationSignature(){return`${this.baseConfigurationSignature}:${this.publicTurn?"public":"room"}`}async start(e,t,s){this.shennianSessionId=e;try{this.workDir=w.native(t)}catch{this.workDir=t}this.requestedSessionId=s??null,this.agentSessionId=null,this.client=this.createProcessClient(),await this.client.start(this.workDir),this.startedConfigurationSignature=this.configurationSignature}async send(e,t,s,i,n,a){a?.source==="published_agent"&&U(this.managedAgentPolicy),this.publicTurn=a?.source==="published_agent",await this.refreshProcessConfiguration();const u=this.requireClient();this.runId=S(),this.seq=0,this.emittedToolStates.clear();try{await this.ensureSession(),await this.applyDynamicConfig(t,s),this.active=!0,this.emitEvent({state:"start",runPhase:"thinking",agentSessionId:this.agentSessionId??void 0});const o=[],h=[];n?.trim()&&h.push(n.trim()),h.push(e),o.push({type:"text",text:h.join(`
2
2
 
3
- `)});for(const d of i??[])o.push({type:"resource_link",uri:v(d.path).href,name:d.name,mimeType:d.mimeType,size:d.byteSize});const h=await this.promptWithTimeout(u,o);this.active=!1,h.stopReason==="cancelled"?this.emitEvent({state:"aborted",agentSessionId:this.agentSessionId??void 0}):this.emitEvent({state:"final",agentSessionId:this.agentSessionId??void 0})}catch(o){this.active=!1,this.cancelPendingPermissions();const c=o instanceof Error?o.message:String(o),h=o instanceof A&&o.code===-32e3;throw h&&(p(this.type,"required"),this.retryingAfterAuth||(this.pendingAuthRetry={text:e,...t?{modelId:t}:{},...n?{reasoningEffort:n}:{},...i?{attachments:[...i]}:{},...s!==void 0?{systemPrompt:s}:{}})),this.emitEvent({state:"error",message:c,...h?{errorCode:"acp_auth_required"}:{},agentSessionId:this.agentSessionId??void 0}),o}}async resume(e){this.requestedSessionId=e,this.agentSessionId=null,await this.ensureSession()}async stop(){this.active&&this.agentSessionId&&this.client&&await this.client.agent.notify(a.methods.agent.session.cancel,{sessionId:this.agentSessionId}),this.cancelPendingPermissions(),this.active=!1,await this.client?.close(),this.client=null,this.startedConfigurationSignature=""}async getStatus(){return{active:this.active,runId:this.active?this.runId:null,canStop:this.active}}async respondToPermission(e,t){const n=this.pendingPermissions.get(e);if(!n)throw new Error("ACP permission request is no longer pending");if(!n.optionIds.has(t))throw new Error("Invalid ACP permission option");this.pendingPermissions.delete(e),clearTimeout(n.timer),n.resolve({outcome:{outcome:"selected",optionId:t}})}getAuthMethods(){return[...this.requireClient().initializeResponse?.authMethods??[]]}hasPendingAuthenticationRetry(){return this.pendingAuthRetry!==null}getSessionOptions(){const e=g(this.configOptions,"model"),t=g(this.configOptions,"thought_level"),n=this.modes?.availableModes.map(s=>({id:s.id,name:s.name,...s.description?{description:s.description}:{}}))??[],i=(t?f(t):n).map(s=>({id:"value"in s?s.value:s.id,name:s.name,...s.description?{description:s.description}:{}}));return{models:f(e).map(s=>({id:s.value,name:s.name,...s.description?{description:s.description}:{},...s.value===e?.currentValue?{isDefault:!0}:{},...i.length?{supportedReasoningEfforts:i}:{}})),modes:n}}async authenticate(e,t={}){const n=this.requireClient(),i=n.initializeResponse?.authMethods?.find(s=>s.id===e);if(!i)throw new Error("ACP authentication method is unavailable");try{if("type"in i&&i.type==="terminal"){if(!t.interactiveTerminal)throw new Error("ACP terminal authentication must be completed on the target machine with `shennian agent auth`");await n.close(),await T({...this.manifest.authLaunch??this.manifest.launch,env:Object.fromEntries(Object.entries({...this.extraEnv,...this.manifest.authLaunch?.env??this.manifest.launch.env}).filter(s=>typeof s[1]=="string"))},i,this.workDir)}else await n.authenticate(e);await this.resumeAfterExternalAuthentication()}catch(s){throw x(),s}}async logout(){await this.requireClient().logout(),p(this.type,"required")}async resumeAfterExternalAuthentication(){await this.client?.close(),this.client=this.createProcessClient(),await this.client.start(this.workDir),this.startedConfigurationSignature=this.configurationSignature,p(this.type,"ready");const e=this.pendingAuthRetry;this.pendingAuthRetry=null,e&&this.retryAfterAuthentication(e)}async listExternalSessions(e={}){const t=this.requireClient();if(!t.capabilities.sessionCapabilities?.list)return[];const n=[];let i;for(let s=0;s<10&&n.length<500;s+=1){let r=e.cwd;if(r)try{r=w.native(r)}catch{}const u=await t.listSessions(r,i);if(n.push(...u.sessions.slice(0,500-n.length).map(o=>({agentSessionId:o.sessionId,cwd:o.cwd,...o.title?{title:o.title.slice(0,200)}:{},...o.updatedAt?{updatedAt:o.updatedAt}:{}}))),i=u.nextCursor,!i)break}return n}async loadExternalSession(e){const t=this.requireClient();if(!t.capabilities.loadSession)throw new Error("ACP session history import is unsupported");this.requestedSessionId=e,this.agentSessionId=e;const n=[];this.importCapture=n;try{const i=await t.agent.request(a.methods.agent.session.load,{sessionId:e,cwd:this.workDir,mcpServers:[]});this.configOptions=i.configOptions??[],this.modes=i.modes??null,C(!0)}catch(i){throw C(!1),i}finally{this.importCapture=null}return n.map((i,s)=>({sourceId:i.sourceHint??S("sha256").update(`${e}\0${s}\0${i.role}\0${i.payload}`).digest("hex"),role:i.role,payload:i.payload}))}async closeExternalSession(e){if(!this.requireClient().capabilities.sessionCapabilities?.close)throw new Error("ACP session close is unsupported");await this.requireClient().closeSession(e)}async deleteExternalSession(e){if(!this.requireClient().capabilities.sessionCapabilities?.delete)throw new Error("ACP session delete is unsupported");await this.requireClient().deleteSession(e)}async ensureSession(){if(this.agentSessionId)return;const e=this.requireClient();if(this.requestedSessionId){const n=e.capabilities;if(n.sessionCapabilities?.resume){const i=await e.agent.request(a.methods.agent.session.resume,{sessionId:this.requestedSessionId,cwd:this.workDir,mcpServers:[]});this.configOptions=i.configOptions??[],this.modes=i.modes??null}else if(n.loadSession){this.agentSessionId=this.requestedSessionId;const i=await e.agent.request(a.methods.agent.session.load,{sessionId:this.requestedSessionId,cwd:this.workDir,mcpServers:[]});this.configOptions=i.configOptions??[],this.modes=i.modes??null}else throw new Error(`${this.manifest.name} cannot resume ACP sessions`);this.agentSessionId=this.requestedSessionId,this.emit("sessionOptions");return}const t=await e.agent.request(a.methods.agent.session.new,{cwd:this.workDir,mcpServers:[]});this.agentSessionId=t.sessionId,this.configOptions=t.configOptions??[],this.modes=t.modes??null,this.emit("sessionOptions")}async applyDynamicConfig(e,t){if(!this.agentSessionId)return;t&&this.modes?.availableModes.some(i=>i.id===t)&&(this.modes.currentModeId!==t&&(await this.requireClient().agent.request(a.methods.agent.session.setMode,{sessionId:this.agentSessionId,modeId:t}),this.modes.currentModeId=t),t=void 0);const n=[{category:"model",value:e},{category:"thought_level",value:t}];for(const i of n){if(!i.value)continue;const s=g(this.configOptions,i.category);!s||s.currentValue===i.value||f(s).some(r=>r.value===i.value)&&(await this.requireClient().agent.request(a.methods.agent.session.setConfigOption,{sessionId:this.agentSessionId,configId:s.id,value:i.value}),s.currentValue=i.value)}}handleSessionUpdate(e){if(e.sessionId===this.agentSessionId){if(this.importCapture){this.captureImportedUpdate(e.update);return}if(this.active){if(e.update.sessionUpdate==="tool_call"||e.update.sessionUpdate==="tool_call_update"){const t=JSON.stringify(e.update);if(this.emittedToolStates.get(e.update.toolCallId)===t)return;this.emittedToolStates.set(e.update.toolCallId,t)}for(const t of q(e.update,n=>this.makeEvent(n)))this.emit("agentEvent",t)}}}captureImportedUpdate(e){if(this.importCapture){if(e.sessionUpdate==="user_message_chunk"||e.sessionUpdate==="agent_message_chunk"){const t=e.content.type==="text"?e.content.text:e.content.type==="resource_link"?e.content.name||e.content.uri:`[${e.content.type}]`,n=e.sessionUpdate==="user_message_chunk"?"user":"agent",i=e.messageId?`message:${e.messageId}`:void 0,s=i?this.importCapture.find(r=>r.sourceHint===i):this.importCapture.at(-1);s?.role===n&&s.sourceHint===i?s.payload+=t:this.importCapture.push({role:n,payload:t,...i?{sourceHint:i}:{}});return}if(e.sessionUpdate==="tool_call"){const t=`tool:${e.toolCallId}`,n=this.importCapture.find(s=>s.sourceHint===t),i={role:"agent",sourceHint:t,payload:JSON.stringify({v:1,type:"tool_use",name:e.title,toolCallId:e.toolCallId,status:e.status??"running"})};n?n.payload=i.payload:this.importCapture.push(i);return}if(e.sessionUpdate==="tool_call_update"&&(e.status==="completed"||e.status==="failed")){const t=this.importCapture.find(i=>i.sourceHint===`tool:${e.toolCallId}`),n=JSON.stringify({v:1,type:"tool_result",name:e.title??"tool",toolCallId:e.toolCallId,status:e.status});t?t.payload=n:this.importCapture.push({role:"agent",sourceHint:`tool:${e.toolCallId}`,payload:n})}}}handlePermission(e){if(!this.active||e.sessionId!==this.agentSessionId)return Promise.resolve({outcome:{outcome:"cancelled"}});const t=y();return new Promise(n=>{const i=setTimeout(()=>{this.pendingPermissions.delete(t),n({outcome:{outcome:"cancelled"}})},this.options.permissionTimeoutMs??3e5);i.unref?.(),this.pendingPermissions.set(t,{optionIds:new Set(e.options.map(s=>s.optionId)),resolve:n,timer:i}),this.emitEvent({state:"approval-pending",runPhase:"waiting_approval",approval:{title:e.toolCall.title??void 0,source:this.manifest.name},permission:{id:t,sessionId:this.shennianSessionId,agentSessionId:this.agentSessionId??void 0,runId:this.runId,toolCallId:e.toolCall.toolCallId,options:e.options.map(s=>({id:s.optionId,name:s.name,kind:s.kind}))}})})}requireClient(){if(!this.client)throw new Error("ACP adapter has not started");return this.client}createProcessClient(){return new E(this.manifest.launch,{onSessionUpdate:e=>this.handleSessionUpdate(e),onPermission:e=>this.handlePermission(e)},this.buildEnvironment(),{...this.buildClientCapabilities(),terminalAuth:!0})}async refreshProcessConfiguration(){if(!this.client||this.startedConfigurationSignature===this.configurationSignature)return;const e=this.agentSessionId??this.requestedSessionId;await this.client.close(),this.requestedSessionId=e,this.agentSessionId=null,this.configOptions=[],this.modes=null,this.client=this.createProcessClient(),await this.client.start(this.workDir),this.startedConfigurationSignature=this.configurationSignature}buildEnvironment(){return this.managedAgentPolicy?m(this.managedAgentPolicy)?O(this.extraEnv):{...this.extraEnv}:{...process.env,...this.extraEnv}}buildClientCapabilities(){const e=this.manifest.clientCapabilities??{},t=this.managedAgentPolicy?.adapterPolicy;return t?this.publicTurn?m(this.managedAgentPolicy)?{readTextFile:!!e.readTextFile,writeTextFile:!!e.writeTextFile,terminal:!1}:{readTextFile:!1,writeTextFile:!1,terminal:!1}:m(this.managedAgentPolicy)?{...e,terminal:!0,terminalPolicy:"managed-room-only"}:{readTextFile:!!e.readTextFile,writeTextFile:!!(e.writeTextFile&&t.fileAccess!=="workspace-read"),terminal:!0,terminalPolicy:"managed-room-only"}:e}async retryAfterAuthentication(e){this.retryingAfterAuth=!0;try{await this.send(e.text,e.modelId,e.reasoningEffort,e.attachments,e.systemPrompt)}catch{}finally{this.retryingAfterAuth=!1}}async promptWithTimeout(e,t){let n;try{return await Promise.race([e.agent.request(a.methods.agent.session.prompt,{sessionId:this.agentSessionId,prompt:t}),new Promise((i,s)=>{n=setTimeout(()=>s(new Error("ACP prompt timed out")),this.options.promptTimeoutMs??720*6e4),n.unref?.()})])}catch(i){throw i instanceof Error&&i.message==="ACP prompt timed out"&&(await e.close(),this.client===e&&(this.client=null)),i}finally{n&&clearTimeout(n)}}cancelPendingPermissions(){for(const e of this.pendingPermissions.values())clearTimeout(e.timer),e.resolve({outcome:{outcome:"cancelled"}});this.pendingPermissions.clear()}makeEvent(e){return{...e,runId:this.runId,seq:this.seq++}}emitEvent(e){this.emit("agentEvent",this.makeEvent(e))}}function G(l){b(I(l.id),()=>new k(l))}export{k as AcpAgentAdapter,G as registerAcpAgent};
3
+ `)});const d=u.capabilities.promptCapabilities?.image===!0;for(const c of i??[]){const y=d?$(c):null;y&&o.push({type:"image",data:y.data,mimeType:c.mimeType}),o.push({type:"resource_link",uri:q(c.path).href,name:c.name,mimeType:c.mimeType,size:c.byteSize})}const A=await this.promptWithTimeout(u,o);this.active=!1,A.stopReason==="cancelled"?this.emitEvent({state:"aborted",agentSessionId:this.agentSessionId??void 0}):this.emitEvent({state:"final",agentSessionId:this.agentSessionId??void 0})}catch(o){this.active=!1,this.cancelPendingPermissions();const h=o instanceof Error?o.message:String(o),d=o instanceof T&&o.code===-32e3;throw d&&(p(this.type,"required"),this.retryingAfterAuth||(this.pendingAuthRetry={text:e,...t?{modelId:t}:{},...s?{reasoningEffort:s}:{},...i?{attachments:[...i]}:{},...n!==void 0?{systemPrompt:n}:{}})),this.emitEvent({state:"error",message:h,...d?{errorCode:"acp_auth_required"}:{},agentSessionId:this.agentSessionId??void 0}),o}}async resume(e){this.requestedSessionId=e,this.agentSessionId=null,await this.ensureSession()}async stop(){this.active&&this.agentSessionId&&this.client&&await this.client.agent.notify(l.methods.agent.session.cancel,{sessionId:this.agentSessionId}),this.cancelPendingPermissions(),this.active=!1,await this.client?.close(),this.client=null,this.startedConfigurationSignature=""}async getStatus(){return{active:this.active,runId:this.active?this.runId:null,canStop:this.active}}async respondToPermission(e,t){const s=this.pendingPermissions.get(e);if(!s)throw new Error("ACP permission request is no longer pending");if(!s.optionIds.has(t))throw new Error("Invalid ACP permission option");this.pendingPermissions.delete(e),clearTimeout(s.timer),s.resolve({outcome:{outcome:"selected",optionId:t}})}getAuthMethods(){return[...this.requireClient().initializeResponse?.authMethods??[]]}hasPendingAuthenticationRetry(){return this.pendingAuthRetry!==null}getSessionOptions(){const e=g(this.configOptions,"model"),t=g(this.configOptions,"thought_level"),s=this.modes?.availableModes.map(n=>({id:n.id,name:n.name,...n.description?{description:n.description}:{}}))??[],i=(t?f(t):s).map(n=>({id:"value"in n?n.value:n.id,name:n.name,...n.description?{description:n.description}:{}}));return{models:f(e).map(n=>({id:n.value,name:n.name,...n.description?{description:n.description}:{},...n.value===e?.currentValue?{isDefault:!0}:{},...i.length?{supportedReasoningEfforts:i}:{}})),modes:s}}async authenticate(e,t={}){const s=this.requireClient(),i=s.initializeResponse?.authMethods?.find(n=>n.id===e);if(!i)throw new Error("ACP authentication method is unavailable");try{if("type"in i&&i.type==="terminal"){if(!t.interactiveTerminal)throw new Error("ACP terminal authentication must be completed on the target machine with `shennian agent auth`");await s.close(),await M({...this.manifest.authLaunch??this.manifest.launch,env:Object.fromEntries(Object.entries({...this.extraEnv,...this.manifest.authLaunch?.env??this.manifest.launch.env}).filter(n=>typeof n[1]=="string"))},i,this.workDir)}else await s.authenticate(e);await this.resumeAfterExternalAuthentication()}catch(n){throw R(),n}}async logout(){await this.requireClient().logout(),p(this.type,"required")}async resumeAfterExternalAuthentication(){await this.client?.close(),this.client=this.createProcessClient(),await this.client.start(this.workDir),this.startedConfigurationSignature=this.configurationSignature,p(this.type,"ready");const e=this.pendingAuthRetry;this.pendingAuthRetry=null,e&&this.retryAfterAuthentication(e)}async listExternalSessions(e={}){const t=this.requireClient();if(!t.capabilities.sessionCapabilities?.list)return[];const s=[];let i;for(let n=0;n<10&&s.length<500;n+=1){let a=e.cwd;if(a)try{a=w.native(a)}catch{}const u=await t.listSessions(a,i);if(s.push(...u.sessions.slice(0,500-s.length).map(o=>({agentSessionId:o.sessionId,cwd:o.cwd,...o.title?{title:o.title.slice(0,200)}:{},...o.updatedAt?{updatedAt:o.updatedAt}:{}}))),i=u.nextCursor,!i)break}return s}async loadExternalSession(e){const t=this.requireClient();if(!t.capabilities.loadSession)throw new Error("ACP session history import is unsupported");this.requestedSessionId=e,this.agentSessionId=e;const s=[];this.importCapture=s;try{const i=await t.agent.request(l.methods.agent.session.load,{sessionId:e,cwd:this.workDir,mcpServers:[]});this.configOptions=i.configOptions??[],this.modes=i.modes??null,v(!0)}catch(i){throw v(!1),i}finally{this.importCapture=null}return s.map((i,n)=>({sourceId:i.sourceHint??I("sha256").update(`${e}\0${n}\0${i.role}\0${i.payload}`).digest("hex"),role:i.role,payload:i.payload}))}async closeExternalSession(e){if(!this.requireClient().capabilities.sessionCapabilities?.close)throw new Error("ACP session close is unsupported");await this.requireClient().closeSession(e)}async deleteExternalSession(e){if(!this.requireClient().capabilities.sessionCapabilities?.delete)throw new Error("ACP session delete is unsupported");await this.requireClient().deleteSession(e)}async ensureSession(){if(this.agentSessionId)return;const e=this.requireClient();if(this.requestedSessionId){const s=e.capabilities;if(s.sessionCapabilities?.resume){const i=await e.agent.request(l.methods.agent.session.resume,{sessionId:this.requestedSessionId,cwd:this.workDir,mcpServers:[]});this.configOptions=i.configOptions??[],this.modes=i.modes??null}else if(s.loadSession){this.agentSessionId=this.requestedSessionId;const i=await e.agent.request(l.methods.agent.session.load,{sessionId:this.requestedSessionId,cwd:this.workDir,mcpServers:[]});this.configOptions=i.configOptions??[],this.modes=i.modes??null}else throw new Error(`${this.manifest.name} cannot resume ACP sessions`);this.agentSessionId=this.requestedSessionId,this.emit("sessionOptions");return}const t=await e.agent.request(l.methods.agent.session.new,{cwd:this.workDir,mcpServers:[]});this.agentSessionId=t.sessionId,this.configOptions=t.configOptions??[],this.modes=t.modes??null,this.emit("sessionOptions")}async applyDynamicConfig(e,t){if(!this.agentSessionId)return;t&&this.modes?.availableModes.some(i=>i.id===t)&&(this.modes.currentModeId!==t&&(await this.requireClient().agent.request(l.methods.agent.session.setMode,{sessionId:this.agentSessionId,modeId:t}),this.modes.currentModeId=t),t=void 0);const s=[{category:"model",value:e},{category:"thought_level",value:t}];for(const i of s){if(!i.value)continue;const n=g(this.configOptions,i.category);!n||n.currentValue===i.value||f(n).some(a=>a.value===i.value)&&(await this.requireClient().agent.request(l.methods.agent.session.setConfigOption,{sessionId:this.agentSessionId,configId:n.id,value:i.value}),n.currentValue=i.value)}}handleSessionUpdate(e){if(e.sessionId===this.agentSessionId){if(this.importCapture){this.captureImportedUpdate(e.update);return}if(this.active){if(e.update.sessionUpdate==="tool_call"||e.update.sessionUpdate==="tool_call_update"){const t=JSON.stringify(e.update);if(this.emittedToolStates.get(e.update.toolCallId)===t)return;this.emittedToolStates.set(e.update.toolCallId,t)}for(const t of _(e.update,s=>this.makeEvent(s)))this.emit("agentEvent",t)}}}captureImportedUpdate(e){if(this.importCapture){if(e.sessionUpdate==="user_message_chunk"||e.sessionUpdate==="agent_message_chunk"){const t=e.content.type==="text"?e.content.text:e.content.type==="resource_link"?e.content.name||e.content.uri:`[${e.content.type}]`,s=e.sessionUpdate==="user_message_chunk"?"user":"agent",i=e.messageId?`message:${e.messageId}`:void 0,n=i?this.importCapture.find(a=>a.sourceHint===i):this.importCapture.at(-1);n?.role===s&&n.sourceHint===i?n.payload+=t:this.importCapture.push({role:s,payload:t,...i?{sourceHint:i}:{}});return}if(e.sessionUpdate==="tool_call"){const t=`tool:${e.toolCallId}`,s=this.importCapture.find(n=>n.sourceHint===t),i={role:"agent",sourceHint:t,payload:JSON.stringify({v:1,type:"tool_use",name:e.title,toolCallId:e.toolCallId,status:e.status??"running"})};s?s.payload=i.payload:this.importCapture.push(i);return}if(e.sessionUpdate==="tool_call_update"&&(e.status==="completed"||e.status==="failed")){const t=this.importCapture.find(i=>i.sourceHint===`tool:${e.toolCallId}`),s=JSON.stringify({v:1,type:"tool_result",name:e.title??"tool",toolCallId:e.toolCallId,status:e.status});t?t.payload=s:this.importCapture.push({role:"agent",sourceHint:`tool:${e.toolCallId}`,payload:s})}}}handlePermission(e){if(!this.active||e.sessionId!==this.agentSessionId)return Promise.resolve({outcome:{outcome:"cancelled"}});const t=S();return new Promise(s=>{const i=setTimeout(()=>{this.pendingPermissions.delete(t),s({outcome:{outcome:"cancelled"}})},this.options.permissionTimeoutMs??3e5);i.unref?.(),this.pendingPermissions.set(t,{optionIds:new Set(e.options.map(n=>n.optionId)),resolve:s,timer:i}),this.emitEvent({state:"approval-pending",runPhase:"waiting_approval",approval:{title:e.toolCall.title??void 0,content:O(e.toolCall.rawInput),source:this.manifest.name},permission:{id:t,sessionId:this.shennianSessionId,agentSessionId:this.agentSessionId??void 0,runId:this.runId,toolCallId:e.toolCall.toolCallId,options:e.options.map(n=>({id:n.optionId,name:n.name,kind:n.kind}))}})})}requireClient(){if(!this.client)throw new Error("ACP adapter has not started");return this.client}createProcessClient(){return new k(this.manifest.launch,{onSessionUpdate:e=>this.handleSessionUpdate(e),onPermission:e=>this.handlePermission(e)},this.buildEnvironment(),{...this.buildClientCapabilities(),terminalAuth:!0})}async refreshProcessConfiguration(){if(!this.client||this.startedConfigurationSignature===this.configurationSignature)return;const e=this.agentSessionId??this.requestedSessionId;await this.client.close(),this.requestedSessionId=e,this.agentSessionId=null,this.configOptions=[],this.modes=null,this.client=this.createProcessClient(),await this.client.start(this.workDir),this.startedConfigurationSignature=this.configurationSignature}buildEnvironment(){return this.managedAgentPolicy?m(this.managedAgentPolicy)?F(this.extraEnv):{...this.extraEnv}:{...process.env,...this.extraEnv}}buildClientCapabilities(){const e=this.manifest.clientCapabilities??{},t=this.managedAgentPolicy?.adapterPolicy;return t?this.publicTurn?m(this.managedAgentPolicy)?{readTextFile:!!e.readTextFile,writeTextFile:!!e.writeTextFile,terminal:!1}:{readTextFile:!1,writeTextFile:!1,terminal:!1}:m(this.managedAgentPolicy)?{...e,terminal:!0,terminalPolicy:"managed-room-only"}:{readTextFile:!!e.readTextFile,writeTextFile:!!(e.writeTextFile&&t.fileAccess!=="workspace-read"),terminal:!0,terminalPolicy:"managed-room-only"}:e}async retryAfterAuthentication(e){this.retryingAfterAuth=!0;try{await this.send(e.text,e.modelId,e.reasoningEffort,e.attachments,e.systemPrompt)}catch{}finally{this.retryingAfterAuth=!1}}async promptWithTimeout(e,t){let s;try{return await Promise.race([e.agent.request(l.methods.agent.session.prompt,{sessionId:this.agentSessionId,prompt:t}),new Promise((i,n)=>{s=setTimeout(()=>n(new Error("ACP prompt timed out")),this.options.promptTimeoutMs??720*6e4),s.unref?.()})])}catch(i){throw i instanceof Error&&i.message==="ACP prompt timed out"&&(await e.close(),this.client===e&&(this.client=null)),i}finally{s&&clearTimeout(s)}}cancelPendingPermissions(){for(const e of this.pendingPermissions.values())clearTimeout(e.timer),e.resolve({outcome:{outcome:"cancelled"}});this.pendingPermissions.clear()}makeEvent(e){return{...e,runId:this.runId,seq:this.seq++}}emitEvent(e){this.emit("agentEvent",this.makeEvent(e))}}function te(r){x(C(r.id),()=>new H(r))}export{H as AcpAgentAdapter,te as registerAcpAgent};
@@ -1 +1 @@
1
- import{RequestError as M}from"@agentclientprotocol/sdk";import{buildCommandStringLaunchSpec as R,commandExists as E,resolveCommandFileIdentity as F,resolveCommandFilePath as P}from"../command-spec.js";import{registerAcpAgent as x}from"./adapter.js";import{getRegisteredAgents as L,unregisterAgent as N}from"../adapter.js";import{readAcpManifests as D}from"./manifests.js";import{AcpProcessClient as _}from"./process-client.js";import{acpAgentType as f}from"./types.js";import{loadAcpCatalog as q}from"./catalog.js";import{buildAcpCapabilityCacheKey as K,readAcpCapabilityCache as O,writeAcpCapabilityCache as W}from"./capability-cache.js";import{getAcpRuntimeAuthState as I,setAcpRuntimeAuthState as $}from"./auth-state.js";import{recordAcpScan as H}from"./metrics.js";import{fingerprintNativeExecutable as U}from"../../security/managed-agent-executable.js";const V=[{id:"qwen-code",name:"Qwen Code",source:"registry",launch:{command:"qwen",args:["--acp"]}},{id:"kimi",name:"Kimi CLI",source:"registry",launch:{command:"kimi",args:["acp"]}}],j=new Set(["claude","codex","codebuddy","cursor","opencode","pi"]);async function le(t={}){const i=Date.now();let s=0,n=0;const o={},h=new Set(L().filter(e=>e.startsWith("acp:"))),c=t.candidates?{candidates:t.candidates,revision:void 0}:await q(t),A=G([...c.candidates.length?c.candidates:V,...D()]).filter(e=>!t.agentType||f(e.id)===t.agentType),B=A.filter(e=>{const l=e.launch.command;return j.has(l)?!1:E(l)}).filter((e,l,g)=>g.findIndex(v=>v.id===e.id)===l),C=(await J(B,3,async e=>{const l=P(e.launch.command),g=l?U(l):void 0,u={...R(e.launch.command,e.launch.args??[],t.cwd??process.cwd()),...e.launch.env?{env:e.launch.env}:{}},y=K({manifest:e,platform:process.platform,catalogRevision:c.revision,executableIdentity:F(e.launch.command)}),d=y?O(y):null;if(d?.type===f(e.id)&&d.integration==="acp"&&d.acpCapabilities?.protocolVersion===1)return s+=1,x({...e,launch:u,authLaunch:e.launch}),{...d,authState:I(f(e.id))??d.authState,command:u.command,args:u.args??[],executableFingerprint:g,display:{...d.display,name:e.name},...c.revision?{catalogRevision:c.revision}:{}};const w=new _(u,{onSessionUpdate:()=>{},onPermission:async()=>({outcome:{outcome:"cancelled"}})},process.env,{terminalAuth:!0});try{const r=await w.start(t.cwd??process.cwd()),a=r.agentCapabilities??{},k={protocolVersion:1,listSessions:!!a.sessionCapabilities?.list,loadSession:!!a.loadSession,resumeSession:!!a.sessionCapabilities?.resume,closeSession:!!a.sessionCapabilities?.close,deleteSession:!!a.sessionCapabilities?.delete,terminal:!!e.clientCapabilities?.terminal,fileRead:!!e.clientCapabilities?.readTextFile,fileWrite:!!e.clientCapabilities?.writeTextFile,permission:!0,modelConfig:!1};let p=r.authMethods?.length?"unknown":"ready";if(a.sessionCapabilities?.list)try{await w.listSessions(t.cwd??process.cwd()),p=r.authMethods?.length?"unknown":"ready"}catch(m){p=m instanceof M&&m.code===-32e3?"required":"unknown"}const S=I(f(e.id));S?p=S:p==="required"&&$(f(e.id),p),x({...e,launch:u,authLaunch:e.launch});const b={type:f(e.id),command:u.command,args:u.args??[],version:r.agentInfo?.version??void 0,runtimePlatform:process.platform,executableFingerprint:g,integration:"acp",display:{name:e.name,version:r.agentInfo?.version??void 0},acpCapabilities:k,authState:p,acpAuthMethods:(r.authMethods??[]).slice(0,8).map(m=>({id:m.id.slice(0,128),name:m.name.slice(0,80),type:"type"in m&&m.type==="terminal"?"terminal":"agent"})),...c.revision?{catalogRevision:c.revision}:{}};return y&&W(y,b),b}catch(r){n+=1;const a=z(r);return o[a]=(o[a]??0)+1,null}finally{await w.close()}})).filter(e=>!!e),T=new Set(C.map(e=>e.type));for(const e of h)T.has(e)||N(e);return H({durationMs:Date.now()-i,candidateCount:A.length,installedCount:C.length,cacheHits:s,handshakeFailures:n,handshakeFailuresByKind:o}),C}function z(t){const i=t instanceof Error?t.message:"";return/timed out/i.test(i)?"timeout":/protocol version/i.test(i)?"version":/safety limit|exceeded/i.test(i)?"output_limit":/json|parse/i.test(i)?"invalid_protocol":/enoent|not found/i.test(i)?"launch":"other"}function G(t){const i=new Set(t.filter(n=>n.source==="local").map(n=>n.id)),s=new Map;for(const n of t){if(n.source!=="local"&&i.has(n.id))continue;const o=`${n.id}\0${n.launch.command}\0${JSON.stringify(n.launch.args??[])}`;s.has(o)||s.set(o,n)}return[...s.values()]}async function J(t,i,s){const n=new Array(t.length);let o=0;return await Promise.all(Array.from({length:Math.min(i,t.length)},async()=>{for(;;){const h=o++;if(h>=t.length)return;n[h]=await s(t[h])}})),n}export{le as discoverAcpAgents};
1
+ import{RequestError as P}from"@agentclientprotocol/sdk";import{buildCommandStringLaunchSpec as D,commandExists as L,resolveCommandFileIdentity as N,resolveCommandFilePath as _}from"../command-spec.js";import{registerAcpAgent as B}from"./adapter.js";import{getRegisteredAgents as q,unregisterAgent as K}from"../adapter.js";import{readAcpManifests as U}from"./manifests.js";import{AcpProcessClient as H}from"./process-client.js";import{acpAgentType as p}from"./types.js";import{loadAcpCatalog as O}from"./catalog.js";import{buildAcpCapabilityCacheKey as W,readAcpCapabilityCache as $,writeAcpCapabilityCache as V}from"./capability-cache.js";import{getAcpRuntimeAuthState as k,setAcpRuntimeAuthState as j}from"./auth-state.js";import{recordAcpScan as z}from"./metrics.js";import{fingerprintNativeExecutable as G}from"../../security/managed-agent-executable.js";const J=[{id:"qwen-code",name:"Qwen Code",source:"registry",launch:{command:"qwen",args:["--acp"]}},{id:"kimi",name:"Kimi CLI",source:"registry",launch:{command:"kimi",args:["acp"]}},{id:"dsh",name:"DSH",source:"registry",launch:{command:"dsh",args:["--profile","acp"]}}];let A=[];function de(){return A.map(t=>({...t,args:[...t.args]}))}const Q=new Set(["claude","codex","codebuddy","cursor","opencode","pi"]);async function fe(t={}){const a=Date.now();let o=0,n=0;const r={},g=new Set(q().filter(e=>e.startsWith("acp:"))),l=t.candidates?{candidates:t.candidates,revision:void 0}:await O(t),S=Y([...l.candidates.length?l.candidates:J,...U()]).filter(e=>!t.agentType||p(e.id)===t.agentType),M=S.filter(e=>{const s=e.launch.command;return Q.has(s)?!1:L(s)}).filter((e,s,d)=>d.findIndex(C=>C.id===e.id)===s),b=[],y=(await Z(M,3,async e=>{const s=_(e.launch.command),d=s?G(s):void 0,u={...D(e.launch.command,e.launch.args??[],t.cwd??process.cwd()),...e.launch.env?{env:e.launch.env}:{}},v=W({manifest:e,platform:process.platform,catalogRevision:l.revision,executableIdentity:N(e.launch.command)}),f=v?$(v):null;if(f?.type===p(e.id)&&f.integration==="acp"&&f.acpCapabilities?.protocolVersion===1)return o+=1,B({...e,launch:u,authLaunch:e.launch}),{...f,authState:k(p(e.id))??f.authState,command:u.command,args:u.args??[],executableFingerprint:d,display:{...f.display,name:e.name},...l.revision?{catalogRevision:l.revision}:{}};const w=new H(u,{onSessionUpdate:()=>{},onPermission:async()=>({outcome:{outcome:"cancelled"}})},process.env,{terminalAuth:!0});try{const c=await w.start(t.cwd??process.cwd()),i=c.agentCapabilities??{},F={protocolVersion:1,listSessions:!!i.sessionCapabilities?.list,loadSession:!!i.loadSession,resumeSession:!!i.sessionCapabilities?.resume,closeSession:!!i.sessionCapabilities?.close,deleteSession:!!i.sessionCapabilities?.delete,terminal:!!e.clientCapabilities?.terminal,fileRead:!!e.clientCapabilities?.readTextFile,fileWrite:!!e.clientCapabilities?.writeTextFile,permission:!0,modelConfig:!1};let h=c.authMethods?.length?"unknown":"ready";if(i.sessionCapabilities?.list)try{await w.listSessions(t.cwd??process.cwd()),h=c.authMethods?.length?"unknown":"ready"}catch(m){h=m instanceof P&&m.code===-32e3?"required":"unknown"}const I=k(p(e.id));I?h=I:h==="required"&&j(p(e.id),h),B({...e,launch:u,authLaunch:e.launch});const T={type:p(e.id),command:u.command,args:u.args??[],version:c.agentInfo?.version??void 0,runtimePlatform:process.platform,executableFingerprint:d,integration:"acp",display:{name:e.name,version:c.agentInfo?.version??void 0},acpCapabilities:F,authState:h,acpAuthMethods:(c.authMethods??[]).slice(0,8).map(m=>({id:m.id.slice(0,128),name:m.name.slice(0,80),type:"type"in m&&m.type==="terminal"?"terminal":"agent"})),...l.revision?{catalogRevision:l.revision}:{}};return v&&V(v,T),T}catch(c){n+=1;const i=X(c);return r[i]=(r[i]??0)+1,b.push({type:p(e.id),name:e.name,command:e.launch.command,args:[...e.launch.args??[]],reason:i}),null}finally{await w.close()}})).filter(e=>!!e),R=new Set(y.map(e=>e.type)),x=b.filter((e,s,d)=>!R.has(e.type)&&d.findIndex(C=>C.type===e.type)===s);A=t.agentType?[...A.filter(e=>e.type!==t.agentType),...x]:x;const E=new Set(y.map(e=>e.type));for(const e of g)E.has(e)||K(e);return z({durationMs:Date.now()-a,candidateCount:S.length,installedCount:y.length,cacheHits:o,handshakeFailures:n,handshakeFailuresByKind:r}),y}function X(t){const a=t instanceof Error?t.message:"";return/timed out/i.test(a)?"timeout":/protocol version/i.test(a)?"version":/safety limit|exceeded/i.test(a)?"output_limit":/json|parse/i.test(a)?"invalid_protocol":/enoent|not found/i.test(a)?"launch":"other"}function Y(t){const a=new Set(t.filter(n=>n.source==="local").map(n=>n.id)),o=new Map;for(const n of t){if(n.source!=="local"&&a.has(n.id))continue;const r=`${n.id}\0${n.launch.command}\0${JSON.stringify(n.launch.args??[])}`;o.has(r)||o.set(r,n)}return[...o.values()]}async function Z(t,a,o){const n=new Array(t.length);let r=0;return await Promise.all(Array.from({length:Math.min(a,t.length)},async()=>{for(;;){const g=r++;if(g>=t.length)return;n[g]=await o(t[g])}})),n}export{fe as discoverAcpAgents,de as getUnavailableAcpAgents};
@@ -1 +1,2 @@
1
- import{EventEmitter as o}from"node:events";import{RECOVERY_CONTINUE_TEXT as u}from"../session/run-recovery/schema.js";class l extends o{get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!1}}get supportsActiveInput(){return!1}async inspectInterruptedRun(e){if(!this.getStatus)return{state:"interrupted",providerRunId:e.providerRunId};const r=await this.getStatus().catch(()=>null);return r?.active?{state:"active",providerRunId:r.runId??e.providerRunId,runPhase:r.runPhase}:{state:"interrupted",providerRunId:e.providerRunId}}async recoverInterruptedRun(e){const r=await this.inspectInterruptedRun(e);if(r.state==="terminal"&&this.recoveryCapabilities.inspectTerminal)return{result:"terminal_reconciled"};if(r.state==="active"&&this.recoveryCapabilities.reattachRun)return{result:"reattached"};if(!e.agentSessionId)return{result:"interrupted_by_upgrade",reason:"missing_agent_session"};if(!this.recoveryCapabilities.resumeSession)return{result:"interrupted_by_upgrade",reason:"resume_unsupported"};if(e.continueDispatchState!=="none")return{result:"recovery_failed",reason:"continue_dispatch_outcome_unknown"};try{return e.beforeContinueDispatch?.(),await this.send(u,e.modelId??void 0,e.reasoningEffort??void 0,void 0,e.systemPrompt,e.sendContext),{result:"continued"}}catch(i){const a=i instanceof Error?i.message:String(i),n=a.toLowerCase();return{result:"recovery_failed",reason:n.includes("auth")||n.includes("login")?"authentication_required":n.includes("permission")||n.includes("capability")?"permission_context_unavailable":n.includes("session")&&n.includes("not")?"provider_session_missing":"provider_error",message:a.slice(0,500)}}}}const s=new Map;function p(t,e){s.set(t,e)}function f(t){s.delete(t)}function g(t){const e=s.get(t);return e?e():null}function m(){return[...s.keys()]}export{l as AgentAdapter,g as createAgent,m as getRegisteredAgents,p as registerAgent,f as unregisterAgent};
1
+ import{EventEmitter as a}from"node:events";import{RECOVERY_CONTINUE_TEXT as u}from"../session/run-recovery/schema.js";const c=/approval|permission|confirm|user[_-]?input|request[_-]?user|ask.*question|exit.*plan/i;function p(t){return typeof t!="string"?!1:c.test(t)}function f(t){if(t==null)return;if(typeof t=="string")return t.trim().slice(0,600)||void 0;const e=typeof t=="object"?t:null;if(e){if(Array.isArray(e.questions)){const n=e.questions.map(s=>s&&typeof s=="object"?s.question:void 0).filter(s=>typeof s=="string"&&s.trim().length>0).join(`
2
+ `);if(n)return n.slice(0,600)}const r=[e.question,e.command,e.file_path,e.path,e.url,e.pattern,e.prompt,e.reason,e.message].find(n=>typeof n=="string"&&n.trim());if(typeof r=="string")return r.trim().slice(0,600)}try{return JSON.stringify(t).slice(0,600)}catch{return}}class m extends a{get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!1}}get supportsActiveInput(){return!1}async inspectInterruptedRun(e){if(!this.getStatus)return{state:"interrupted",providerRunId:e.providerRunId};const r=await this.getStatus().catch(()=>null);return r?.active?{state:"active",providerRunId:r.runId??e.providerRunId,runPhase:r.runPhase}:{state:"interrupted",providerRunId:e.providerRunId}}async recoverInterruptedRun(e){const r=await this.inspectInterruptedRun(e);if(r.state==="terminal"&&this.recoveryCapabilities.inspectTerminal)return{result:"terminal_reconciled"};if(r.state==="active"&&this.recoveryCapabilities.reattachRun)return{result:"reattached"};if(!e.agentSessionId)return{result:"interrupted_by_upgrade",reason:"missing_agent_session"};if(!this.recoveryCapabilities.resumeSession)return{result:"interrupted_by_upgrade",reason:"resume_unsupported"};if(e.continueDispatchState!=="none")return{result:"recovery_failed",reason:"continue_dispatch_outcome_unknown"};try{return e.beforeContinueDispatch?.(),await this.send(u,e.modelId??void 0,e.reasoningEffort??void 0,void 0,e.systemPrompt,e.sendContext),{result:"continued"}}catch(n){const s=n instanceof Error?n.message:String(n),i=s.toLowerCase();return{result:"recovery_failed",reason:i.includes("auth")||i.includes("login")?"authentication_required":i.includes("permission")||i.includes("capability")?"permission_context_unavailable":i.includes("session")&&i.includes("not")?"provider_session_missing":"provider_error",message:s.slice(0,500)}}}}const o=new Map;function g(t,e){o.set(t,e)}function y(t){o.delete(t)}function _(t){const e=o.get(t);return e?e():null}function h(){return[...o.keys()]}export{m as AgentAdapter,_ as createAgent,h as getRegisteredAgents,p as isApprovalLikeName,g as registerAgent,f as summarizeToolInput,y as unregisterAgent};
@@ -0,0 +1,3 @@
1
+ import a from"node:net";import m from"node:os";import c from"node:path";import{randomBytes as h}from"node:crypto";import{createInterface as l}from"node:readline";class P{onRequest;server=null;socketPath=null;constructor(e){this.onRequest=e}async start(){await this.stop();const e=c.join(m.tmpdir(),`shp${process.pid}-${h(4).toString("hex")}.sock`),r=a.createServer(t=>{l({input:t}).once("line",n=>{let o;try{o=JSON.parse(n)}catch{t.end(`${JSON.stringify({behavior:"deny",message:"shennian_permission_request_malformed"})}
2
+ `);return}this.onRequest(o.toolName,o.input).then(i=>{t.end(`${JSON.stringify(i)}
3
+ `)})})});return await new Promise((t,s)=>{r.once("error",s),r.listen(e,()=>{r.removeListener("error",s),t()})}),this.server=r,this.socketPath=e,e}async stop(){const e=this.server;this.server=null,this.socketPath=null,e&&await new Promise(r=>e.close(()=>r()))}}export{P as ClaudePermissionBridge};
@@ -0,0 +1 @@
1
+ const E="approve",_="shennianPermission",S="SHENNIAN_CLAUDE_PERMISSION_SOCKET";export{_ as CLAUDE_PERMISSION_MCP_SERVER_NAME,S as CLAUDE_PERMISSION_SOCKET_ENV,E as CLAUDE_PERMISSION_TOOL_NAME};
@@ -0,0 +1,3 @@
1
+ import u from"node:net";import{createInterface as c}from"node:readline";import{CLAUDE_PERMISSION_MCP_SERVER_NAME as m,CLAUDE_PERMISSION_SOCKET_ENV as h,CLAUDE_PERMISSION_TOOL_NAME as _}from"./claude-permission-protocol.js";const f=5*6e4;function r(e){process.stdout.write(`${JSON.stringify({jsonrpc:"2.0",...e})}
2
+ `)}function y(e,n){const i=process.env[h];return i?new Promise(p=>{let l=!1;const o=s=>{l||(l=!0,clearTimeout(d),p(s))},d=setTimeout(()=>o({behavior:"deny",message:"shennian_permission_timeout"}),f);d.unref?.();const t=u.connect(i);t.on("error",()=>o({behavior:"deny",message:"shennian_permission_relay_unreachable"})),t.on("connect",()=>t.write(`${JSON.stringify({toolName:e,input:n})}
3
+ `)),c({input:t}).on("line",s=>{try{const a=JSON.parse(s);o({behavior:a.behavior==="allow"?"allow":"deny",updatedInput:a.updatedInput,message:a.message})}catch{o({behavior:"deny",message:"shennian_permission_relay_malformed_response"})}finally{t.end()}})}):Promise.resolve({behavior:"deny",message:"shennian_permission_socket_missing"})}function S(e){if(e.method==="initialize"){r({id:e.id,result:{protocolVersion:"2024-11-05",capabilities:{tools:{}},serverInfo:{name:m,version:"1.0.0"}}});return}if(!(e.method==="notifications/initialized"||e.id==null&&e.method?.startsWith("notifications/"))){if(e.method==="tools/list"){r({id:e.id,result:{tools:[{name:_,description:"Relays a Claude Code permission request to the Shennian app for the user to approve.",inputSchema:{type:"object",properties:{tool_name:{type:"string"},input:{type:"object"}},required:["tool_name","input"]}}]}});return}if(e.method==="tools/call"){const n=e.params?.arguments??{};y(n.tool_name,n.input).then(i=>{r({id:e.id,result:{content:[{type:"text",text:JSON.stringify(i)}]}})});return}e.id!=null&&r({id:e.id,error:{code:-32601,message:`Unhandled method: ${e.method}`}})}}const E=c({input:process.stdin});E.on("line",e=>{if(e.trim())try{S(JSON.parse(e))}catch{}});
@@ -1,10 +1,10 @@
1
- import p from"node:fs";import o from"node:path";import{createInterface as S}from"node:readline";import{randomUUID as f}from"node:crypto";import{AgentAdapter as E,registerAgent as x}from"./adapter.js";import{resolveBuiltinCommand as m,spawnAgentCommand as P,spawnResolvedCommandSync as v}from"./command-spec.js";import{spawnEnoentError as C}from"./spawn-errors.js";import{buildAgentProcessEnv as I,buildManagedAgentProcessEnv as k,buildManagedNativeFullProcessEnv as A}from"../agent-env.js";import{buildPlatformInstructions as g}from"./platform-instructions.js";import{resolveManagedAgentAdapterEnforcement as w,isManagedAgentNativeFull as c}from"../security/managed-agent-policy.js";import{assertPublicAgentPolicy as _}from"../security/public-agent-policy.js";import{registerManagedAgentRuntimeSecurity as R}from"../security/managed-agent-runtime.js";import{resolveManagedRoomIpcPaths as T}from"../daemon-ipc/paths.js";import{CLAUDE_MANAGED_RUNTIME_SECURITY as N,compileClaudeManagedPermissions as M}from"./claude-managed-permissions.js";R("claude",N);function O(n){return n?.trim()||"default"}const D=new Set(["low","medium","high","xhigh","max"]),h=new Map;function L(n){const e=n?.trim();if(e){if(D.has(e))return e;throw new Error(`Unsupported Claude reasoning effort "${e}". Supported values: low, medium, high, xhigh, max.`)}}function ne(){h.clear()}function F(n){const e=n.trim();return e?!e.includes("claude.ai connectors are disabled because"):!1}function U(){const n=m("claude");if(!n)return!1;const e=`${n.kind}:${n.path}:${n.command}:${n.args.join("\0")}`;if(h.has(e))return h.get(e)??!1;try{const t=v(n,["--help"],{encoding:"utf-8",stdio:["ignore","pipe","pipe"],timeout:3e3,env:process.env}),s=`${t.stdout??""}
2
- ${t.stderr??""}`,a=/(?:^|\s)--effort(?:\s|,|<)/.test(s);return h.set(e,a),a}catch{return h.set(e,!1),!1}}const y=64*1024;function $(n){const e=q(n);return e.length>y?`${e.slice(0,y)}
3
- \u2026[truncated]`:e}function q(n){return typeof n=="string"?n:Array.isArray(n)?n.map(e=>{if(typeof e=="string")return e;if(typeof e!="object"||e===null)return"";const t=e;return typeof t.text=="string"?t.text:t.type==="image"?"[image]":""}).filter(Boolean).join(`
4
- `):""}class z extends E{options;type="claude";get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!0}}process=null;agentSessionId=null;sessionId=null;workDir=null;seq=0;runId="";hasEmittedText=!1;toolNames=new Map;terminalState="open";authenticationRetrying=!1;pendingSuccess=null;persistNativeSession=!0;managedAgentPolicy=null;constructor(e={}){super(),this.options=e}externalChannel=null;shennianSessionId=null;extraEnv={};configure(e){this.shennianSessionId=e.sessionId??null,this.externalChannel=e.externalChannel??null,this.extraEnv=e.env??{},"managedAgentPolicy"in e&&(this.managedAgentPolicy=e.managedAgentPolicy??null),this.managedAgentPolicy&&(this.workDir=this.managedAgentPolicy.adapterPolicy.workDir)}async start(e,t,s,a){this.sessionId=e,this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??t,this.seq=0,this.persistNativeSession=a?.persistNativeSession!==!1,s&&(this.agentSessionId=s)}async send(e,t,s,a,l,r){if(r?.source==="published_agent"&&_(this.managedAgentPolicy),r?.source==="room_activation"&&!this.managedAgentPolicy)throw new Error("managed_agent_policy_missing");await this.killProcess(),this.runId=f(),this.resetRunState();const i=["-p",e,"--output-format","stream-json","--verbose",...this.buildManagedPermissionConfig(r?.source==="published_agent")?.args??[]];this.persistNativeSession||i.push("--no-session-persistence");const u=this.options.systemPrompt??g(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,l);u&&i.push("--append-system-prompt",u),this.options.hidden&&i.push("--name","Shennian Manager Substrate"),(!this.managedAgentPolicy||c(this.managedAgentPolicy))&&process.getuid?.()!==0&&i.push("--dangerously-skip-permissions"),i.push("--model",O(t));const d=L(s);d&&U()&&i.push("--effort",d),this.agentSessionId&&i.push("--resume",this.agentSessionId),this.spawnAndParse(i)}async resume(e){await this.killProcess(),this.agentSessionId=e,this.runId=f(),this.resetRunState();const t=["--resume",e,"--output-format","stream-json","--verbose",...this.buildManagedPermissionConfig()?.args??[]],s=this.options.systemPrompt??g(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0);s&&t.push("--append-system-prompt",s),this.options.hidden&&t.push("--name","Shennian Manager Substrate"),(!this.managedAgentPolicy||c(this.managedAgentPolicy))&&process.getuid?.()!==0&&t.push("--dangerously-skip-permissions"),this.spawnAndParse(t)}async stop(){await this.killProcess()}spawnAndParse(e){const t=m("claude");if(!t){this.emit("error",C(this.workDir,'Command "claude" not found. Is Claude Code CLI installed?'));return}const s=P(t,e,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:this.buildProcessEnv()});this.process=s,S({input:s.stdout}).on("line",r=>{if(r.trim())try{const i=JSON.parse(r);this.handleStreamEvent(i)}catch{}});let l="";s.stderr?.on("data",r=>{const i=r.toString();if(l+=i,this.terminalState==="open")for(const u of i.split(`
5
- `)){const d=u.trim();F(d)&&this.emitEvent({state:"delta",text:d+`
6
- `})}}),s.on("close",r=>{this.process===s&&(this.process=null,this.handleProcessClose(r,l))}),s.on("error",r=>{this.process===s&&(this.process=null,r.code==="ENOENT"?this.emit("error",new Error('Command "claude" not found. Is Claude Code CLI installed?')):this.emit("error",r))})}buildManagedPermissionConfig(e=!1){const t=this.managedAgentPolicy;if(!t||c(t))return null;const s=e?{readPaths:[],unixSockets:[]}:G();return M(w(t),t.adapterPolicy.workDir,{internalReadPaths:s.readPaths,internalUnixSockets:s.unixSockets,shellSubprocessPolicy:t.environmentPolicy.shellSubprocess})}buildProcessEnv(){return this.managedAgentPolicy?c(this.managedAgentPolicy)?A({NO_COLOR:"1",...this.extraEnv}):k({agentType:"claude",providerEnv:this.extraEnv,sessionEnv:this.extraEnv,runtimeEnv:{NO_COLOR:"1"}}):I(this.extraEnv)}handleStreamEvent(e){if(e.type==="system"&&e.subtype==="init"&&e.session_id){this.agentSessionId=e.session_id,this.emitEvent({state:"start",agentSessionId:this.agentSessionId});return}if(e.type==="system"&&e.subtype==="api_retry"&&e.error==="authentication_failed"){this.authenticationRetrying=!0,this.emitEvent({state:"heartbeat",runPhase:"thinking",errorCode:"auth_retrying",message:"Claude authentication is retrying."});return}if(e.type==="assistant"){if(this.authenticationRetrying=!1,e.message?.content){for(const t of e.message.content)if(t.type==="text"&&t.text){const s=this.hasEmittedText?`
1
+ import g from"node:fs";import l from"node:path";import{createInterface as P}from"node:readline";import{randomUUID as h}from"node:crypto";import{fileURLToPath as E}from"node:url";import{AgentAdapter as C,registerAgent as v,summarizeToolInput as I}from"./adapter.js";import{ClaudePermissionBridge as _}from"./claude-permission-bridge.js";import{CLAUDE_PERMISSION_MCP_SERVER_NAME as f,CLAUDE_PERMISSION_SOCKET_ENV as x,CLAUDE_PERMISSION_TOOL_NAME as w}from"./claude-permission-protocol.js";import{resolveBuiltinCommand as c,spawnAgentCommand as A,spawnResolvedCommandSync as k}from"./command-spec.js";import{spawnEnoentError as R}from"./spawn-errors.js";import{buildAgentProcessEnv as T,buildManagedAgentProcessEnv as M,buildManagedNativeFullProcessEnv as O}from"../agent-env.js";import{buildPlatformInstructions as y}from"./platform-instructions.js";import{resolveManagedAgentAdapterEnforcement as N,isManagedAgentNativeFull as p}from"../security/managed-agent-policy.js";import{assertPublicAgentPolicy as D}from"../security/public-agent-policy.js";import{registerManagedAgentRuntimeSecurity as L}from"../security/managed-agent-runtime.js";import{resolveManagedRoomIpcPaths as U}from"../daemon-ipc/paths.js";import{CLAUDE_MANAGED_RUNTIME_SECURITY as B,compileClaudeManagedPermissions as b}from"./claude-managed-permissions.js";L("claude",B);function $(n){return n?.trim()||"default"}const q=new Set(["low","medium","high","xhigh","max"]),m=new Map;function F(n){const e=n?.trim();if(e){if(q.has(e))return e;throw new Error(`Unsupported Claude reasoning effort "${e}". Supported values: low, medium, high, xhigh, max.`)}}function he(){m.clear()}function z(n){const e=n.trim();return e?!e.includes("claude.ai connectors are disabled because"):!1}function G(){const n=c("claude");if(!n)return!1;const e=`${n.kind}:${n.path}:${n.command}:${n.args.join("\0")}`;if(m.has(e))return m.get(e)??!1;try{const t=k(n,["--help"],{encoding:"utf-8",stdio:["ignore","pipe","pipe"],timeout:3e3,env:process.env}),s=`${t.stdout??""}
2
+ ${t.stderr??""}`,r=/(?:^|\s)--effort(?:\s|,|<)/.test(s);return m.set(e,r),r}catch{return m.set(e,!1),!1}}const S=64*1024;function J(n){const e=K(n);return e.length>S?`${e.slice(0,S)}
3
+ \u2026[truncated]`:e}function K(n){return typeof n=="string"?n:Array.isArray(n)?n.map(e=>{if(typeof e=="string")return e;if(typeof e!="object"||e===null)return"";const t=e;return typeof t.text=="string"?t.text:t.type==="image"?"[image]":""}).filter(Boolean).join(`
4
+ `):""}class V extends C{options;type="claude";get recoveryCapabilities(){return{inspectTerminal:!1,reattachRun:!1,resumeRun:!1,resumeSession:!0}}process=null;agentSessionId=null;sessionId=null;workDir=null;seq=0;runId="";hasEmittedText=!1;toolNames=new Map;terminalState="open";authenticationRetrying=!1;pendingSuccess=null;persistNativeSession=!0;managedAgentPolicy=null;permissionBridge=null;pendingClaudePermissions=new Map;constructor(e={}){super(),this.options=e}externalChannel=null;shennianSessionId=null;extraEnv={};configure(e){this.shennianSessionId=e.sessionId??null,this.externalChannel=e.externalChannel??null,this.extraEnv=e.env??{},"managedAgentPolicy"in e&&(this.managedAgentPolicy=e.managedAgentPolicy??null),this.managedAgentPolicy&&(this.workDir=this.managedAgentPolicy.adapterPolicy.workDir)}async start(e,t,s,r){this.sessionId=e,this.workDir=this.managedAgentPolicy?.adapterPolicy.workDir??t,this.seq=0,this.persistNativeSession=r?.persistNativeSession!==!1,s&&(this.agentSessionId=s)}async send(e,t,s,r,a,o){if(o?.source==="published_agent"&&D(this.managedAgentPolicy),o?.source==="room_activation"&&!this.managedAgentPolicy)throw new Error("managed_agent_policy_missing");await this.killProcess(),this.runId=h(),this.resetRunState();const i=["-p",e,"--output-format","stream-json","--verbose",...this.buildManagedPermissionConfig(o?.source==="published_agent")?.args??[]];this.persistNativeSession||i.push("--no-session-persistence");const u=this.options.systemPrompt??y(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0,a);u&&i.push("--append-system-prompt",u),this.options.hidden&&i.push("--name","Shennian Manager Substrate"),i.push(...await this.buildPermissionModeArgs()),i.push("--model",$(t));const d=F(s);d&&G()&&i.push("--effort",d),this.agentSessionId&&i.push("--resume",this.agentSessionId),this.spawnAndParse(i)}async resume(e){await this.killProcess(),this.agentSessionId=e,this.runId=h(),this.resetRunState();const t=["--resume",e,"--output-format","stream-json","--verbose",...this.buildManagedPermissionConfig()?.args??[]],s=this.options.systemPrompt??y(this.workDir??process.cwd(),this.externalChannel,this.shennianSessionId??void 0);s&&t.push("--append-system-prompt",s),this.options.hidden&&t.push("--name","Shennian Manager Substrate"),t.push(...await this.buildPermissionModeArgs()),this.spawnAndParse(t)}async stop(){await this.killProcess()}spawnAndParse(e){const t=c("claude");if(!t){this.emit("error",R(this.workDir,'Command "claude" not found. Is Claude Code CLI installed?'));return}const s=A(t,e,{cwd:this.workDir??void 0,stdio:["ignore","pipe","pipe"],env:this.buildProcessEnv()});this.process=s,P({input:s.stdout}).on("line",o=>{if(o.trim())try{const i=JSON.parse(o);this.handleStreamEvent(i)}catch{}});let a="";s.stderr?.on("data",o=>{const i=o.toString();if(a+=i,this.terminalState==="open")for(const u of i.split(`
5
+ `)){const d=u.trim();z(d)&&this.emitEvent({state:"delta",text:d+`
6
+ `})}}),s.on("close",o=>{this.process===s&&(this.process=null,this.handleProcessClose(o,a))}),s.on("error",o=>{this.process===s&&(this.process=null,o.code==="ENOENT"?this.emit("error",new Error('Command "claude" not found. Is Claude Code CLI installed?')):this.emit("error",o))})}async buildPermissionModeArgs(){const e=["--disallowedTools","AskUserQuestion"];if(process.getuid?.()===0)return e;if(this.managedAgentPolicy&&p(this.managedAgentPolicy)){const t=await this.startPermissionBridge(),s={mcpServers:{[f]:{command:process.execPath,args:[E(new URL("./claude-permission-relay-server.js",import.meta.url))],env:{[x]:t}}}};return e.push("--permission-prompts","host","--permission-prompt-tool",`mcp__${f}__${w}`,"--mcp-config",JSON.stringify(s)),e}return this.managedAgentPolicy||e.push("--dangerously-skip-permissions"),e}async startPermissionBridge(){const e=this.permissionBridge??new _((t,s)=>this.requestClaudePermission(t,s));return this.permissionBridge=e,e.start()}requestClaudePermission(e,t){const s=h();return new Promise(r=>{const a=setTimeout(()=>{this.pendingClaudePermissions.delete(s),r({behavior:"deny",message:"shennian_permission_timeout"})},3e5);a.unref?.(),this.pendingClaudePermissions.set(s,{resolve:r,timer:a}),this.emitEvent({state:"approval-pending",runPhase:"waiting_approval",approval:{title:typeof e=="string"&&e.trim()?e:"\u9700\u8981\u7528\u6237\u786E\u8BA4",content:I(t),source:"claude"},permission:{id:s,sessionId:this.shennianSessionId??void 0,agentSessionId:this.agentSessionId??void 0,runId:this.runId,toolCallId:s,options:[{id:"allow",name:"\u5141\u8BB8",kind:"allow_once"},{id:"deny",name:"\u62D2\u7EDD",kind:"reject_once"}]}})})}async respondToPermission(e,t){const s=this.pendingClaudePermissions.get(e);if(!s)throw new Error("Claude permission request is no longer pending");this.pendingClaudePermissions.delete(e),clearTimeout(s.timer),s.resolve({behavior:t==="allow"?"allow":"deny"})}buildManagedPermissionConfig(e=!1){const t=this.managedAgentPolicy;if(!t||p(t))return null;const s=e?{readPaths:[],unixSockets:[]}:H();return b(N(t),t.adapterPolicy.workDir,{internalReadPaths:s.readPaths,internalUnixSockets:s.unixSockets,shellSubprocessPolicy:t.environmentPolicy.shellSubprocess})}buildProcessEnv(){return this.managedAgentPolicy?p(this.managedAgentPolicy)?O({NO_COLOR:"1",...this.extraEnv}):M({agentType:"claude",providerEnv:this.extraEnv,sessionEnv:this.extraEnv,runtimeEnv:{NO_COLOR:"1"}}):T(this.extraEnv)}handleStreamEvent(e){if(e.type==="system"&&e.subtype==="init"&&e.session_id){this.agentSessionId=e.session_id,this.emitEvent({state:"start",agentSessionId:this.agentSessionId});return}if(e.type==="system"&&e.subtype==="api_retry"&&e.error==="authentication_failed"){this.authenticationRetrying=!0,this.emitEvent({state:"heartbeat",runPhase:"thinking",errorCode:"auth_retrying",message:"Claude authentication is retrying."});return}if(e.type==="assistant"){if(this.authenticationRetrying=!1,e.message?.content){for(const t of e.message.content)if(t.type==="text"&&t.text){const s=this.hasEmittedText?`
7
7
 
8
8
  `:"";this.emitEvent({state:"delta",text:s+t.text}),this.hasEmittedText=!0}else t.type==="thinking"&&t.thinking?this.emitEvent({state:"delta",text:t.thinking,thinking:!0}):t.type==="tool_use"&&(t.id&&t.name&&this.toolNames.set(t.id,t.name),this.emitEvent({state:"tool-call",name:t.name,args:t.input,...t.id?{toolCallId:t.id}:{}}));return}if(e.subtype==="text"&&e.text){const t=this.hasEmittedText?`
9
9
 
10
- `:"";this.emitEvent({state:"delta",text:t+e.text}),this.hasEmittedText=!0}else e.subtype==="thinking"&&e.thinking?this.emitEvent({state:"delta",text:e.thinking,thinking:!0}):e.subtype==="tool_use"&&this.emitEvent({state:"tool-call",name:e.name,args:e.input});return}if(e.type==="user"){for(const t of e.message?.content??[])t.type!=="tool_result"||!t.tool_use_id||this.emitEvent({state:"tool-result",name:this.toolNames.get(t.tool_use_id),toolCallId:t.tool_use_id,toolStatus:t.is_error===!0?"failed":"completed",result:$(t.content)});return}if(e.type==="result")if(e.subtype==="tool_result"){const t=typeof e.content=="string"?e.content:JSON.stringify(e.content);this.emitEvent({state:"tool-result",name:e.name,result:t})}else if(e.subtype==="success"){e.session_id&&(this.agentSessionId=e.session_id);const t=typeof e.result=="string"?e.result:"";!this.hasEmittedText&&t.trim()&&(this.emitEvent({state:"delta",text:t}),this.hasEmittedText=!0);const s=e.usage??e.message?.usage;this.pendingSuccess={agentSessionId:this.agentSessionId??void 0,usage:s?{inputTokens:s.input_tokens,outputTokens:s.output_tokens}:void 0}}else e.subtype==="error"&&this.emitErrorIfOpen({state:"error",message:e.error??e.result??"unknown error",...this.authenticationRetrying?{errorCode:"auth_required"}:{}})}handleProcessClose(e,t){if(e!==0&&e!==null){const s=t.trim()||`claude exited with code ${e}`;this.emitErrorIfOpen({state:"error",message:s,...this.authenticationRetrying?{errorCode:"auth_required"}:{}});return}if(!this.hasEmittedText){this.emitErrorIfOpen({state:"error",message:"Claude completed without response text"});return}this.emitFinalIfOpen({state:"final",agentSessionId:this.pendingSuccess?.agentSessionId??this.agentSessionId??void 0,usage:this.pendingSuccess?.usage})}emitFinalIfOpen(e){this.terminalState==="open"&&(this.terminalState="final",this.emitEvent(e))}emitErrorIfOpen(e){this.terminalState==="open"&&(this.terminalState="error",this.emitEvent(e))}resetRunState(){this.seq=0,this.hasEmittedText=!1,this.toolNames.clear(),this.terminalState="open",this.authenticationRetrying=!1,this.pendingSuccess=null}emitEvent(e){const t={...e,runId:this.runId,seq:this.seq++};this.emit("agentEvent",t)}async killProcess(){const e=this.process;e&&(this.process=null,e.kill("SIGTERM"),await new Promise(t=>{e.on("close",t),setTimeout(()=>{e.kill("SIGKILL"),t()},3e3)}))}}function G(){const n=T(),e=[n.secretFile],t=n.transport==="unix_socket"?[n.endpoint]:[];n.transport==="unix_socket"&&e.push(n.endpoint);const s=m("pi");return s?.path&&e.push(...b(s.path)),{readPaths:[...new Set(e)].sort(),unixSockets:[...new Set(t)].sort()}}function b(n){const e=o.normalize(n.trim());if(!e||!o.isAbsolute(e))return[];const t=[e];try{const s=p.realpathSync(e);t.push(s,o.dirname(s),o.dirname(o.dirname(s)));let a=o.dirname(s);for(let l=0;l<8;l+=1){const r=o.join(a,"package.json");try{if(JSON.parse(p.readFileSync(r,"utf8")).name==="shennian"){t.push(a);break}}catch{}const i=o.dirname(a);if(i===a)break;a=i}}catch{}return[...new Set(t)].sort()}x("claude",()=>new z);export{z as ClaudeAdapter,O as normalizeClaudeModelId,L as normalizeClaudeReasoningEffort,ne as resetClaudeCapabilityCacheForTests,G as resolveClaudeManagedInternalAccess,b as resolveClaudeShennianCliReadPaths,F as shouldForwardClaudeStderrLine,U as supportsClaudeReasoningEffort};
10
+ `:"";this.emitEvent({state:"delta",text:t+e.text}),this.hasEmittedText=!0}else e.subtype==="thinking"&&e.thinking?this.emitEvent({state:"delta",text:e.thinking,thinking:!0}):e.subtype==="tool_use"&&this.emitEvent({state:"tool-call",name:e.name,args:e.input});return}if(e.type==="user"){for(const t of e.message?.content??[])t.type!=="tool_result"||!t.tool_use_id||this.emitEvent({state:"tool-result",name:this.toolNames.get(t.tool_use_id),toolCallId:t.tool_use_id,toolStatus:t.is_error===!0?"failed":"completed",result:J(t.content)});return}if(e.type==="result")if(e.subtype==="tool_result"){const t=typeof e.content=="string"?e.content:JSON.stringify(e.content);this.emitEvent({state:"tool-result",name:e.name,result:t})}else if(e.subtype==="success"){e.session_id&&(this.agentSessionId=e.session_id);const t=typeof e.result=="string"?e.result:"";!this.hasEmittedText&&t.trim()&&(this.emitEvent({state:"delta",text:t}),this.hasEmittedText=!0);const s=e.usage??e.message?.usage;this.pendingSuccess={agentSessionId:this.agentSessionId??void 0,usage:s?{inputTokens:s.input_tokens,outputTokens:s.output_tokens}:void 0}}else e.subtype==="error"&&this.emitErrorIfOpen({state:"error",message:e.error??e.result??"unknown error",...this.authenticationRetrying?{errorCode:"auth_required"}:{}})}handleProcessClose(e,t){if(e!==0&&e!==null){const s=t.trim()||`claude exited with code ${e}`;this.emitErrorIfOpen({state:"error",message:s,...this.authenticationRetrying?{errorCode:"auth_required"}:{}});return}if(!this.hasEmittedText){this.emitErrorIfOpen({state:"error",message:"Claude completed without response text"});return}this.emitFinalIfOpen({state:"final",agentSessionId:this.pendingSuccess?.agentSessionId??this.agentSessionId??void 0,usage:this.pendingSuccess?.usage})}emitFinalIfOpen(e){this.terminalState==="open"&&(this.terminalState="final",this.emitEvent(e))}emitErrorIfOpen(e){this.terminalState==="open"&&(this.terminalState="error",this.emitEvent(e))}resetRunState(){this.seq=0,this.hasEmittedText=!1,this.toolNames.clear(),this.terminalState="open",this.authenticationRetrying=!1,this.pendingSuccess=null}emitEvent(e){const t={...e,runId:this.runId,seq:this.seq++};this.emit("agentEvent",t)}async killProcess(){for(const[t,s]of this.pendingClaudePermissions)clearTimeout(s.timer),s.resolve({behavior:"deny",message:"shennian_permission_run_ended"}),this.pendingClaudePermissions.delete(t);if(this.permissionBridge){const t=this.permissionBridge;this.permissionBridge=null,await t.stop()}const e=this.process;e&&(this.process=null,e.kill("SIGTERM"),await new Promise(t=>{e.on("close",t),setTimeout(()=>{e.kill("SIGKILL"),t()},3e3)}))}}function H(){const n=U(),e=[n.secretFile],t=n.transport==="unix_socket"?[n.endpoint]:[];n.transport==="unix_socket"&&e.push(n.endpoint);const s=c("pi");return s?.path&&e.push(...Q(s.path)),{readPaths:[...new Set(e)].sort(),unixSockets:[...new Set(t)].sort()}}function Q(n){const e=l.normalize(n.trim());if(!e||!l.isAbsolute(e))return[];const t=[e];try{const s=g.realpathSync(e);t.push(s,l.dirname(s),l.dirname(l.dirname(s)));let r=l.dirname(s);for(let a=0;a<8;a+=1){const o=l.join(r,"package.json");try{if(JSON.parse(g.readFileSync(o,"utf8")).name==="shennian"){t.push(r);break}}catch{}const i=l.dirname(r);if(i===r)break;r=i}}catch{}return[...new Set(t)].sort()}v("claude",()=>new V);export{V as ClaudeAdapter,$ as normalizeClaudeModelId,F as normalizeClaudeReasoningEffort,he as resetClaudeCapabilityCacheForTests,H as resolveClaudeManagedInternalAccess,Q as resolveClaudeShennianCliReadPaths,z as shouldForwardClaudeStderrLine,G as supportsClaudeReasoningEffort};