shennian 0.4.11 → 0.4.13

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 (122) hide show
  1. package/dist/publish-build-manifest.json +183 -53
  2. package/dist/src/agents/acp/adapter.d.ts +78 -0
  3. package/dist/src/agents/acp/adapter.js +3 -0
  4. package/dist/src/agents/acp/auth-state.d.ts +3 -0
  5. package/dist/src/agents/acp/auth-state.js +1 -0
  6. package/dist/src/agents/acp/auth.d.ts +7 -0
  7. package/dist/src/agents/acp/auth.js +1 -0
  8. package/dist/src/agents/acp/capability-cache.d.ts +14 -0
  9. package/dist/src/agents/acp/capability-cache.js +2 -0
  10. package/dist/src/agents/acp/catalog.d.ts +11 -0
  11. package/dist/src/agents/acp/catalog.js +2 -0
  12. package/dist/src/agents/acp/client-services.d.ts +32 -0
  13. package/dist/src/agents/acp/client-services.js +3 -0
  14. package/dist/src/agents/acp/discovery.d.ts +9 -0
  15. package/dist/src/agents/acp/discovery.js +1 -0
  16. package/dist/src/agents/acp/events.d.ts +4 -0
  17. package/dist/src/agents/acp/events.js +3 -0
  18. package/dist/src/agents/acp/manifests.d.ts +63 -0
  19. package/dist/src/agents/acp/manifests.js +2 -0
  20. package/dist/src/agents/acp/metrics.d.ts +24 -0
  21. package/dist/src/agents/acp/metrics.js +1 -0
  22. package/dist/src/agents/acp/package-commands.d.ts +4 -0
  23. package/dist/src/agents/acp/package-commands.js +1 -0
  24. package/dist/src/agents/acp/process-client.d.ts +39 -0
  25. package/dist/src/agents/acp/process-client.js +1 -0
  26. package/dist/src/agents/acp/process-tree.d.ts +2 -0
  27. package/dist/src/agents/acp/process-tree.js +1 -0
  28. package/dist/src/agents/acp/types.d.ts +31 -0
  29. package/dist/src/agents/acp/types.js +1 -0
  30. package/dist/src/agents/acp/watcher.d.ts +22 -0
  31. package/dist/src/agents/acp/watcher.js +1 -0
  32. package/dist/src/agents/adapter.d.ts +96 -2
  33. package/dist/src/agents/adapter.js +1 -1
  34. package/dist/src/agents/claude.d.ts +14 -0
  35. package/dist/src/agents/claude.js +5 -5
  36. package/dist/src/agents/codex.d.ts +6 -0
  37. package/dist/src/agents/codex.js +1 -1
  38. package/dist/src/agents/command-spec.d.ts +5 -0
  39. package/dist/src/agents/command-spec.js +3 -3
  40. package/dist/src/agents/cursor.d.ts +6 -0
  41. package/dist/src/agents/cursor.js +1 -1
  42. package/dist/src/agents/custom-recovery-conformance.d.ts +2 -0
  43. package/dist/src/agents/custom-recovery-conformance.js +2 -0
  44. package/dist/src/agents/custom.d.ts +9 -0
  45. package/dist/src/agents/custom.js +4 -4
  46. package/dist/src/agents/detect.d.ts +11 -2
  47. package/dist/src/agents/detect.js +1 -1
  48. package/dist/src/agents/gemini.d.ts +6 -0
  49. package/dist/src/agents/gemini.js +1 -1
  50. package/dist/src/agents/manager.d.ts +2 -0
  51. package/dist/src/agents/manager.js +5 -5
  52. package/dist/src/agents/model-registry/service.js +1 -1
  53. package/dist/src/agents/opencode.d.ts +6 -0
  54. package/dist/src/agents/opencode.js +1 -1
  55. package/dist/src/agents/pi-coding-agent.d.ts +6 -0
  56. package/dist/src/agents/pi-coding-agent.js +4 -4
  57. package/dist/src/agents/workbuddy.d.ts +6 -0
  58. package/dist/src/agents/workbuddy.js +2 -2
  59. package/dist/src/commands/agent.d.ts +2 -0
  60. package/dist/src/commands/agent.js +2 -0
  61. package/dist/src/commands/daemon.d.ts +6 -2
  62. package/dist/src/commands/daemon.js +19 -23
  63. package/dist/src/commands/pair.js +10 -10
  64. package/dist/src/commands/upgrade.d.ts +7 -1
  65. package/dist/src/commands/upgrade.js +1 -1
  66. package/dist/src/config/index.d.ts +1 -1
  67. package/dist/src/config/index.js +2 -2
  68. package/dist/src/daemon-ipc/control.d.ts +16 -0
  69. package/dist/src/daemon-ipc/control.js +1 -0
  70. package/dist/src/index.js +3 -3
  71. package/dist/src/log-reporter.d.ts +23 -0
  72. package/dist/src/log-reporter.js +1 -1
  73. package/dist/src/relay/client.d.ts +1 -0
  74. package/dist/src/relay/client.js +1 -1
  75. package/dist/src/session/handlers/agents.d.ts +1 -0
  76. package/dist/src/session/handlers/agents.js +1 -1
  77. package/dist/src/session/handlers/chat.d.ts +3 -0
  78. package/dist/src/session/handlers/chat.js +2 -2
  79. package/dist/src/session/manager.d.ts +20 -2
  80. package/dist/src/session/manager.js +3 -1
  81. package/dist/src/session/queue.js +2 -2
  82. package/dist/src/session/run-recovery/barrier.d.ts +12 -0
  83. package/dist/src/session/run-recovery/barrier.js +1 -0
  84. package/dist/src/session/run-recovery/coordinator.d.ts +32 -0
  85. package/dist/src/session/run-recovery/coordinator.js +1 -0
  86. package/dist/src/session/run-recovery/journal.d.ts +30 -0
  87. package/dist/src/session/run-recovery/journal.js +2 -0
  88. package/dist/src/session/run-recovery/schema.d.ts +43 -0
  89. package/dist/src/session/run-recovery/schema.js +1 -0
  90. package/dist/src/session/types.d.ts +10 -0
  91. package/dist/src/upgrade/engine.d.ts +6 -5
  92. package/dist/src/upgrade/engine.js +2 -2
  93. package/dist/src/upgrade/scheduler.d.ts +14 -0
  94. package/dist/src/upgrade/scheduler.js +1 -1
  95. package/dist/src/upgrade/updater-bootstrap.d.ts +12 -0
  96. package/dist/src/upgrade/updater-bootstrap.js +2 -0
  97. package/dist/src/upgrade/updater-launcher.d.ts +28 -0
  98. package/dist/src/upgrade/updater-launcher.js +3 -0
  99. package/dist/src/upgrade/updater-protocol.d.ts +37 -0
  100. package/dist/src/upgrade/updater-protocol.js +1 -0
  101. package/dist/src/upgrade/updater-worker.d.ts +11 -0
  102. package/dist/src/upgrade/updater-worker.js +2 -0
  103. package/node_modules/@shennian/wire/dist/events.d.ts +31 -0
  104. package/node_modules/@shennian/wire/dist/index.d.ts +1 -0
  105. package/node_modules/@shennian/wire/dist/index.js +1 -0
  106. package/node_modules/@shennian/wire/dist/machine.d.ts +49 -1
  107. package/node_modules/@shennian/wire/dist/message-payload.d.ts +1 -0
  108. package/node_modules/@shennian/wire/dist/message-payload.js +4 -1
  109. package/node_modules/@shennian/wire/dist/methods.d.ts +1 -1
  110. package/node_modules/@shennian/wire/dist/relay-connectivity.d.ts +30 -0
  111. package/node_modules/@shennian/wire/dist/relay-connectivity.js +29 -0
  112. package/node_modules/@shennian/wire/dist/session-sync.d.ts +2 -2
  113. package/node_modules/@shennian/wire/dist/session-sync.js +2 -0
  114. package/node_modules/@shennian/wire/dist/session.d.ts +84 -1
  115. package/node_modules/@shennian/wire/dist/session.js +5 -1
  116. package/package.json +5 -3
  117. package/dist/native/macos-background-client/Shennian.app/Contents/CodeResources +0 -0
  118. package/dist/native/macos-background-client/Shennian.app/Contents/Info.plist +0 -17
  119. package/dist/native/macos-background-client/Shennian.app/Contents/MacOS/ShennianClientLauncher +0 -0
  120. package/dist/native/macos-background-client/Shennian.app/Contents/Resources/en.lproj/InfoPlist.strings +0 -2
  121. package/dist/native/macos-background-client/Shennian.app/Contents/Resources/zh-Hans.lproj/InfoPlist.strings +0 -2
  122. package/dist/native/macos-background-client/Shennian.app/Contents/_CodeSignature/CodeResources +0 -153
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": 1,
3
3
  "jsMinified": true,
4
4
  "minifier": "esbuild",
5
- "fileCount": 152,
5
+ "fileCount": 178,
6
6
  "files": [
7
7
  {
8
8
  "file": "bin/shennian.js",
@@ -14,10 +14,85 @@
14
14
  "beforeBytes": 9854,
15
15
  "afterBytes": 4529
16
16
  },
17
+ {
18
+ "file": "src/agents/acp/adapter.js",
19
+ "beforeBytes": 24351,
20
+ "afterBytes": 12664
21
+ },
22
+ {
23
+ "file": "src/agents/acp/auth-state.js",
24
+ "beforeBytes": 297,
25
+ "afterBytes": 138
26
+ },
27
+ {
28
+ "file": "src/agents/acp/auth.js",
29
+ "beforeBytes": 1112,
30
+ "afterBytes": 651
31
+ },
32
+ {
33
+ "file": "src/agents/acp/capability-cache.js",
34
+ "beforeBytes": 2374,
35
+ "afterBytes": 1411
36
+ },
37
+ {
38
+ "file": "src/agents/acp/catalog.js",
39
+ "beforeBytes": 5188,
40
+ "afterBytes": 2657
41
+ },
42
+ {
43
+ "file": "src/agents/acp/client-services.js",
44
+ "beforeBytes": 5088,
45
+ "afterBytes": 2769
46
+ },
47
+ {
48
+ "file": "src/agents/acp/discovery.js",
49
+ "beforeBytes": 9047,
50
+ "afterBytes": 4281
51
+ },
52
+ {
53
+ "file": "src/agents/acp/events.js",
54
+ "beforeBytes": 3018,
55
+ "afterBytes": 1463
56
+ },
57
+ {
58
+ "file": "src/agents/acp/manifests.js",
59
+ "beforeBytes": 4036,
60
+ "afterBytes": 2299
61
+ },
62
+ {
63
+ "file": "src/agents/acp/metrics.js",
64
+ "beforeBytes": 1229,
65
+ "afterBytes": 807
66
+ },
67
+ {
68
+ "file": "src/agents/acp/package-commands.js",
69
+ "beforeBytes": 3450,
70
+ "afterBytes": 1693
71
+ },
72
+ {
73
+ "file": "src/agents/acp/process-client.js",
74
+ "beforeBytes": 7214,
75
+ "afterBytes": 4379
76
+ },
77
+ {
78
+ "file": "src/agents/acp/process-tree.js",
79
+ "beforeBytes": 698,
80
+ "afterBytes": 371
81
+ },
82
+ {
83
+ "file": "src/agents/acp/types.js",
84
+ "beforeBytes": 148,
85
+ "afterBytes": 58
86
+ },
87
+ {
88
+ "file": "src/agents/acp/watcher.js",
89
+ "beforeBytes": 2743,
90
+ "afterBytes": 1533
91
+ },
17
92
  {
18
93
  "file": "src/agents/adapter.js",
19
- "beforeBytes": 552,
20
- "afterBytes": 322
94
+ "beforeBytes": 3557,
95
+ "afterBytes": 1913
21
96
  },
22
97
  {
23
98
  "file": "src/agents/claude-managed-permissions.js",
@@ -26,8 +101,8 @@
26
101
  },
27
102
  {
28
103
  "file": "src/agents/claude.js",
29
- "beforeBytes": 15474,
30
- "afterBytes": 8088
104
+ "beforeBytes": 17063,
105
+ "afterBytes": 8544
31
106
  },
32
107
  {
33
108
  "file": "src/agents/codex-managed-permissions.js",
@@ -46,13 +121,13 @@
46
121
  },
47
122
  {
48
123
  "file": "src/agents/codex.js",
49
- "beforeBytes": 65975,
50
- "afterBytes": 33808
124
+ "beforeBytes": 66278,
125
+ "afterBytes": 33907
51
126
  },
52
127
  {
53
128
  "file": "src/agents/command-spec.js",
54
- "beforeBytes": 17521,
55
- "afterBytes": 7863
129
+ "beforeBytes": 18239,
130
+ "afterBytes": 8225
56
131
  },
57
132
  {
58
133
  "file": "src/agents/config-status.js",
@@ -66,23 +141,28 @@
66
141
  },
67
142
  {
68
143
  "file": "src/agents/cursor.js",
69
- "beforeBytes": 12051,
70
- "afterBytes": 5791
144
+ "beforeBytes": 12192,
145
+ "afterBytes": 5890
71
146
  },
72
147
  {
73
148
  "file": "src/agents/custom-managed-runtime.js",
74
149
  "beforeBytes": 9992,
75
150
  "afterBytes": 5280
76
151
  },
152
+ {
153
+ "file": "src/agents/custom-recovery-conformance.js",
154
+ "beforeBytes": 1998,
155
+ "afterBytes": 1084
156
+ },
77
157
  {
78
158
  "file": "src/agents/custom.js",
79
- "beforeBytes": 16524,
80
- "afterBytes": 8695
159
+ "beforeBytes": 17754,
160
+ "afterBytes": 9426
81
161
  },
82
162
  {
83
163
  "file": "src/agents/detect.js",
84
- "beforeBytes": 3366,
85
- "afterBytes": 1504
164
+ "beforeBytes": 3496,
165
+ "afterBytes": 1591
86
166
  },
87
167
  {
88
168
  "file": "src/agents/external-channel-instructions.js",
@@ -91,13 +171,13 @@
91
171
  },
92
172
  {
93
173
  "file": "src/agents/gemini.js",
94
- "beforeBytes": 6212,
95
- "afterBytes": 3210
174
+ "beforeBytes": 6353,
175
+ "afterBytes": 3309
96
176
  },
97
177
  {
98
178
  "file": "src/agents/manager.js",
99
- "beforeBytes": 10675,
100
- "afterBytes": 5749
179
+ "beforeBytes": 10984,
180
+ "afterBytes": 5949
101
181
  },
102
182
  {
103
183
  "file": "src/agents/model-registry/cache.js",
@@ -121,8 +201,8 @@
121
201
  },
122
202
  {
123
203
  "file": "src/agents/model-registry/service.js",
124
- "beforeBytes": 4571,
125
- "afterBytes": 1869
204
+ "beforeBytes": 5605,
205
+ "afterBytes": 2531
126
206
  },
127
207
  {
128
208
  "file": "src/agents/model-registry/types.js",
@@ -151,8 +231,8 @@
151
231
  },
152
232
  {
153
233
  "file": "src/agents/opencode.js",
154
- "beforeBytes": 11310,
155
- "afterBytes": 6249
234
+ "beforeBytes": 11451,
235
+ "afterBytes": 6348
156
236
  },
157
237
  {
158
238
  "file": "src/agents/pi-coding-agent-managed-permissions.js",
@@ -161,8 +241,8 @@
161
241
  },
162
242
  {
163
243
  "file": "src/agents/pi-coding-agent.js",
164
- "beforeBytes": 24240,
165
- "afterBytes": 13052
244
+ "beforeBytes": 24381,
245
+ "afterBytes": 13151
166
246
  },
167
247
  {
168
248
  "file": "src/agents/pi-managed-extension.js",
@@ -201,8 +281,13 @@
201
281
  },
202
282
  {
203
283
  "file": "src/agents/workbuddy.js",
204
- "beforeBytes": 18087,
205
- "afterBytes": 9384
284
+ "beforeBytes": 18228,
285
+ "afterBytes": 9483
286
+ },
287
+ {
288
+ "file": "src/commands/agent.js",
289
+ "beforeBytes": 5136,
290
+ "afterBytes": 2826
206
291
  },
207
292
  {
208
293
  "file": "src/commands/daemon-process.js",
@@ -221,8 +306,8 @@
221
306
  },
222
307
  {
223
308
  "file": "src/commands/daemon.js",
224
- "beforeBytes": 46411,
225
- "afterBytes": 22150
309
+ "beforeBytes": 44904,
310
+ "afterBytes": 21716
226
311
  },
227
312
  {
228
313
  "file": "src/commands/integration.js",
@@ -256,8 +341,8 @@
256
341
  },
257
342
  {
258
343
  "file": "src/commands/pair.js",
259
- "beforeBytes": 16410,
260
- "afterBytes": 9073
344
+ "beforeBytes": 16528,
345
+ "afterBytes": 9150
261
346
  },
262
347
  {
263
348
  "file": "src/commands/room.js",
@@ -276,19 +361,24 @@
276
361
  },
277
362
  {
278
363
  "file": "src/commands/upgrade.js",
279
- "beforeBytes": 9786,
280
- "afterBytes": 5083
364
+ "beforeBytes": 9789,
365
+ "afterBytes": 5176
281
366
  },
282
367
  {
283
368
  "file": "src/config/index.js",
284
- "beforeBytes": 2709,
285
- "afterBytes": 1613
369
+ "beforeBytes": 2801,
370
+ "afterBytes": 1662
286
371
  },
287
372
  {
288
373
  "file": "src/daemon-ipc/client.js",
289
374
  "beforeBytes": 2754,
290
375
  "afterBytes": 1393
291
376
  },
377
+ {
378
+ "file": "src/daemon-ipc/control.js",
379
+ "beforeBytes": 3975,
380
+ "afterBytes": 2196
381
+ },
292
382
  {
293
383
  "file": "src/daemon-ipc/json.js",
294
384
  "beforeBytes": 11,
@@ -346,8 +436,8 @@
346
436
  },
347
437
  {
348
438
  "file": "src/index.js",
349
- "beforeBytes": 27270,
350
- "afterBytes": 13879
439
+ "beforeBytes": 35733,
440
+ "afterBytes": 17671
351
441
  },
352
442
  {
353
443
  "file": "src/log-redaction.js",
@@ -356,8 +446,8 @@
356
446
  },
357
447
  {
358
448
  "file": "src/log-reporter.js",
359
- "beforeBytes": 479,
360
- "afterBytes": 214
449
+ "beforeBytes": 2022,
450
+ "afterBytes": 970
361
451
  },
362
452
  {
363
453
  "file": "src/manager/prompt.js",
@@ -481,8 +571,8 @@
481
571
  },
482
572
  {
483
573
  "file": "src/relay/client.js",
484
- "beforeBytes": 15036,
485
- "afterBytes": 7402
574
+ "beforeBytes": 15242,
575
+ "afterBytes": 7525
486
576
  },
487
577
  {
488
578
  "file": "src/room/activation-audit.js",
@@ -641,13 +731,13 @@
641
731
  },
642
732
  {
643
733
  "file": "src/session/handlers/agents.js",
644
- "beforeBytes": 1853,
645
- "afterBytes": 966
734
+ "beforeBytes": 2274,
735
+ "afterBytes": 1134
646
736
  },
647
737
  {
648
738
  "file": "src/session/handlers/chat.js",
649
- "beforeBytes": 44520,
650
- "afterBytes": 18490
739
+ "beforeBytes": 56203,
740
+ "afterBytes": 24136
651
741
  },
652
742
  {
653
743
  "file": "src/session/handlers/control.js",
@@ -706,8 +796,8 @@
706
796
  },
707
797
  {
708
798
  "file": "src/session/manager.js",
709
- "beforeBytes": 32004,
710
- "afterBytes": 16673
799
+ "beforeBytes": 48167,
800
+ "afterBytes": 25714
711
801
  },
712
802
  {
713
803
  "file": "src/session/native-cleanup-outbox.js",
@@ -726,8 +816,28 @@
726
816
  },
727
817
  {
728
818
  "file": "src/session/queue.js",
729
- "beforeBytes": 35970,
730
- "afterBytes": 16080
819
+ "beforeBytes": 36642,
820
+ "afterBytes": 16429
821
+ },
822
+ {
823
+ "file": "src/session/run-recovery/barrier.js",
824
+ "beforeBytes": 1061,
825
+ "afterBytes": 521
826
+ },
827
+ {
828
+ "file": "src/session/run-recovery/coordinator.js",
829
+ "beforeBytes": 7193,
830
+ "afterBytes": 3313
831
+ },
832
+ {
833
+ "file": "src/session/run-recovery/journal.js",
834
+ "beforeBytes": 8568,
835
+ "afterBytes": 4162
836
+ },
837
+ {
838
+ "file": "src/session/run-recovery/schema.js",
839
+ "beforeBytes": 5964,
840
+ "afterBytes": 3907
731
841
  },
732
842
  {
733
843
  "file": "src/session/store.js",
@@ -751,13 +861,33 @@
751
861
  },
752
862
  {
753
863
  "file": "src/upgrade/engine.js",
754
- "beforeBytes": 16698,
755
- "afterBytes": 7021
864
+ "beforeBytes": 15883,
865
+ "afterBytes": 6563
756
866
  },
757
867
  {
758
868
  "file": "src/upgrade/scheduler.js",
759
- "beforeBytes": 4585,
760
- "afterBytes": 2534
869
+ "beforeBytes": 7340,
870
+ "afterBytes": 4250
871
+ },
872
+ {
873
+ "file": "src/upgrade/updater-bootstrap.js",
874
+ "beforeBytes": 3291,
875
+ "afterBytes": 1732
876
+ },
877
+ {
878
+ "file": "src/upgrade/updater-launcher.js",
879
+ "beforeBytes": 7949,
880
+ "afterBytes": 3904
881
+ },
882
+ {
883
+ "file": "src/upgrade/updater-protocol.js",
884
+ "beforeBytes": 2814,
885
+ "afterBytes": 1677
886
+ },
887
+ {
888
+ "file": "src/upgrade/updater-worker.js",
889
+ "beforeBytes": 13778,
890
+ "afterBytes": 7385
761
891
  },
762
892
  {
763
893
  "file": "src/windows-shell.js",
@@ -0,0 +1,78 @@
1
+ import type { AcpAgentType, ChatAttachmentMeta } from '@shennian/wire';
2
+ import { AgentAdapter, type ImportedAgentMessage } from '../adapter.js';
3
+ import { type AcpAgentManifest } from './types.js';
4
+ import type { CompiledManagedAgentPolicy } from '../../security/managed-agent-policy.js';
5
+ export declare class AcpAgentAdapter extends AgentAdapter {
6
+ private readonly manifest;
7
+ private readonly options;
8
+ readonly type: AcpAgentType;
9
+ get recoveryCapabilities(): {
10
+ inspectTerminal: boolean;
11
+ reattachRun: boolean;
12
+ resumeRun: boolean;
13
+ resumeSession: boolean;
14
+ };
15
+ private client;
16
+ private workDir;
17
+ private shennianSessionId;
18
+ private requestedSessionId;
19
+ private agentSessionId;
20
+ private runId;
21
+ private seq;
22
+ private active;
23
+ private extraEnv;
24
+ private pendingPermissions;
25
+ private configOptions;
26
+ private modes;
27
+ private importCapture;
28
+ private emittedToolStates;
29
+ private pendingAuthRetry;
30
+ private retryingAfterAuth;
31
+ private managedAgentPolicy;
32
+ constructor(manifest: AcpAgentManifest, options?: {
33
+ permissionTimeoutMs?: number;
34
+ promptTimeoutMs?: number;
35
+ });
36
+ configure(options: {
37
+ env?: NodeJS.ProcessEnv;
38
+ managedAgentPolicy?: CompiledManagedAgentPolicy | null;
39
+ }): void;
40
+ start(sessionId: string, workDir: string, agentSessionId?: string | null): Promise<void>;
41
+ send(text: string, modelId?: string, reasoningEffort?: string, attachments?: ChatAttachmentMeta[], systemPrompt?: string | null): Promise<void>;
42
+ resume(agentSessionId: string): Promise<void>;
43
+ stop(): Promise<void>;
44
+ getStatus(): Promise<{
45
+ active: boolean;
46
+ runId: string | null;
47
+ canStop: boolean;
48
+ }>;
49
+ respondToPermission(permissionId: string, optionId: string): Promise<void>;
50
+ getAuthMethods(): import('@agentclientprotocol/sdk').AuthMethod[];
51
+ hasPendingAuthenticationRetry(): boolean;
52
+ getSessionOptions(): import('../adapter.js').AgentSessionOptions;
53
+ authenticate(methodId: string, options?: {
54
+ interactiveTerminal?: boolean;
55
+ }): Promise<void>;
56
+ logout(): Promise<void>;
57
+ resumeAfterExternalAuthentication(): Promise<void>;
58
+ listExternalSessions(options?: {
59
+ cwd?: string;
60
+ }): Promise<import("@shennian/wire").AcpExternalSessionInfo[]>;
61
+ loadExternalSession(agentSessionId: string): Promise<ImportedAgentMessage[]>;
62
+ closeExternalSession(agentSessionId: string): Promise<void>;
63
+ deleteExternalSession(agentSessionId: string): Promise<void>;
64
+ private ensureSession;
65
+ private applyDynamicConfig;
66
+ private handleSessionUpdate;
67
+ private captureImportedUpdate;
68
+ private handlePermission;
69
+ private requireClient;
70
+ private buildEnvironment;
71
+ private buildClientCapabilities;
72
+ private retryAfterAuthentication;
73
+ private promptWithTimeout;
74
+ private cancelPendingPermissions;
75
+ private makeEvent;
76
+ private emitEvent;
77
+ }
78
+ export declare function registerAcpAgent(manifest: AcpAgentManifest): void;
@@ -0,0 +1,3 @@
1
+ import{randomUUID as p}from"node:crypto";import{createHash as w}from"node:crypto";import{realpathSync as m}from"node:fs";import{pathToFileURL as I}from"node:url";import*as l from"@agentclientprotocol/sdk";import{RequestError as S}from"@agentclientprotocol/sdk";import{AgentAdapter as v,registerAgent as C}from"../adapter.js";import{mapAcpSessionUpdate as A}from"./events.js";import{AcpProcessClient as f}from"./process-client.js";import{acpAgentType as g}from"./types.js";import{runAcpTerminalAuthentication as P}from"./auth.js";import{setAcpRuntimeAuthState as u}from"./auth-state.js";import{recordAcpAuthFailure as q,recordAcpImportResult as y}from"./metrics.js";class b extends v{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;constructor(e,i={}){super(),this.manifest=e,this.options=i,this.type=g(e.id)}configure(e){this.extraEnv=e.env??{},this.managedAgentPolicy=e.managedAgentPolicy??null}async start(e,i,s){this.shennianSessionId=e;try{this.workDir=m.native(i)}catch{this.workDir=i}this.requestedSessionId=s??null,this.agentSessionId=null,this.client=new f(this.manifest.launch,{onSessionUpdate:t=>this.handleSessionUpdate(t),onPermission:t=>this.handlePermission(t)},this.buildEnvironment(),{...this.buildClientCapabilities(),terminalAuth:!0}),await this.client.start(this.workDir)}async send(e,i,s,t,n){const o=this.requireClient();this.runId=p(),this.seq=0,this.emittedToolStates.clear();try{await this.ensureSession(),await this.applyDynamicConfig(i,s),this.active=!0,this.emitEvent({state:"start",runPhase:"thinking",agentSessionId:this.agentSessionId??void 0});const r=[],a=[];n?.trim()&&a.push(n.trim()),a.push(e),r.push({type:"text",text:a.join(`
2
+
3
+ `)});for(const h of t??[])r.push({type:"resource_link",uri:I(h.path).href,name:h.name,mimeType:h.mimeType,size:h.byteSize});const c=await this.promptWithTimeout(o,r);this.active=!1,c.stopReason==="cancelled"?this.emitEvent({state:"aborted",agentSessionId:this.agentSessionId??void 0}):this.emitEvent({state:"final",agentSessionId:this.agentSessionId??void 0})}catch(r){this.active=!1,this.cancelPendingPermissions();const a=r instanceof Error?r.message:String(r),c=r instanceof S&&r.code===-32e3;throw c&&(u(this.type,"required"),this.retryingAfterAuth||(this.pendingAuthRetry={text:e,...i?{modelId:i}:{},...s?{reasoningEffort:s}:{},...t?{attachments:[...t]}:{},...n!==void 0?{systemPrompt:n}:{}})),this.emitEvent({state:"error",message:a,...c?{errorCode:"acp_auth_required"}:{},agentSessionId:this.agentSessionId??void 0}),r}}async resume(e){this.requestedSessionId=e,this.agentSessionId=null,await this.ensureSession()}async stop(){this.active&&this.agentSessionId&&this.client&&await this.client.agent.notify(l.methods.agent.session.cancel,{sessionId:this.agentSessionId}),this.cancelPendingPermissions(),this.active=!1,await this.client?.close(),this.client=null}async getStatus(){return{active:this.active,runId:this.active?this.runId:null,canStop:this.active}}async respondToPermission(e,i){const s=this.pendingPermissions.get(e);if(!s)throw new Error("ACP permission request is no longer pending");if(!s.optionIds.has(i))throw new Error("Invalid ACP permission option");this.pendingPermissions.delete(e),clearTimeout(s.timer),s.resolve({outcome:{outcome:"selected",optionId:i}})}getAuthMethods(){return[...this.requireClient().initializeResponse?.authMethods??[]]}hasPendingAuthenticationRetry(){return this.pendingAuthRetry!==null}getSessionOptions(){const e=this.configOptions.find(o=>o.category==="model"&&o.type==="select"),i=this.configOptions.find(o=>o.category==="thought_level"&&o.type==="select"),s=this.modes?.availableModes.map(o=>({id:o.id,name:o.name,...o.description?{description:o.description}:{}}))??[],t=o=>(o?.options??[]).flatMap(r=>"options"in r?r.options:[r]),n=(i?t(i):s).map(o=>({id:"value"in o?o.value:o.id,name:o.name,...o.description?{description:o.description}:{}}));return{models:t(e).map(o=>({id:o.value,name:o.name,...o.description?{description:o.description}:{},...o.value===e?.currentValue?{isDefault:!0}:{},...n.length?{supportedReasoningEfforts:n}:{}})),modes:s}}async authenticate(e,i={}){const s=this.requireClient(),t=s.initializeResponse?.authMethods?.find(n=>n.id===e);if(!t)throw new Error("ACP authentication method is unavailable");try{if("type"in t&&t.type==="terminal"){if(!i.interactiveTerminal)throw new Error("ACP terminal authentication must be completed on the target machine with `shennian agent auth`");await s.close(),await P({...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"))},t,this.workDir)}else await s.authenticate(e);await this.resumeAfterExternalAuthentication()}catch(n){throw q(),n}}async logout(){await this.requireClient().logout(),u(this.type,"required")}async resumeAfterExternalAuthentication(){await this.client?.close(),this.client=new f(this.manifest.launch,{onSessionUpdate:i=>this.handleSessionUpdate(i),onPermission:i=>this.handlePermission(i)},this.buildEnvironment(),{...this.buildClientCapabilities(),terminalAuth:!0}),await this.client.start(this.workDir),u(this.type,"ready");const e=this.pendingAuthRetry;this.pendingAuthRetry=null,e&&this.retryAfterAuthentication(e)}async listExternalSessions(e={}){const i=this.requireClient();if(!i.capabilities.sessionCapabilities?.list)return[];const s=[];let t;for(let n=0;n<10&&s.length<500;n+=1){let o=e.cwd;if(o)try{o=m.native(o)}catch{}const r=await i.listSessions(o,t);if(s.push(...r.sessions.slice(0,500-s.length).map(a=>({agentSessionId:a.sessionId,cwd:a.cwd,...a.title?{title:a.title.slice(0,200)}:{},...a.updatedAt?{updatedAt:a.updatedAt}:{}}))),t=r.nextCursor,!t)break}return s}async loadExternalSession(e){const i=this.requireClient();if(!i.capabilities.loadSession)throw new Error("ACP session history import is unsupported");this.requestedSessionId=e,this.agentSessionId=e;const s=[];this.importCapture=s;try{const t=await i.agent.request(l.methods.agent.session.load,{sessionId:e,cwd:this.workDir,mcpServers:[]});this.configOptions=t.configOptions??[],this.modes=t.modes??null,y(!0)}catch(t){throw y(!1),t}finally{this.importCapture=null}return s.map((t,n)=>({sourceId:t.sourceHint??w("sha256").update(`${e}\0${n}\0${t.role}\0${t.payload}`).digest("hex"),role:t.role,payload:t.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 t=await e.agent.request(l.methods.agent.session.resume,{sessionId:this.requestedSessionId,cwd:this.workDir,mcpServers:[]});this.configOptions=t.configOptions??[],this.modes=t.modes??null}else if(s.loadSession){this.agentSessionId=this.requestedSessionId;const t=await e.agent.request(l.methods.agent.session.load,{sessionId:this.requestedSessionId,cwd:this.workDir,mcpServers:[]});this.configOptions=t.configOptions??[],this.modes=t.modes??null}else throw new Error(`${this.manifest.name} cannot resume ACP sessions`);this.agentSessionId=this.requestedSessionId;return}const i=await e.agent.request(l.methods.agent.session.new,{cwd:this.workDir,mcpServers:[]});this.agentSessionId=i.sessionId,this.configOptions=i.configOptions??[],this.modes=i.modes??null}async applyDynamicConfig(e,i){if(!this.agentSessionId)return;i&&this.modes?.availableModes.some(t=>t.id===i)&&(this.modes.currentModeId!==i&&(await this.requireClient().agent.request(l.methods.agent.session.setMode,{sessionId:this.agentSessionId,modeId:i}),this.modes.currentModeId=i),i=void 0);const s=[{category:"model",value:e},{category:"thought_level",value:i}];for(const t of s){if(!t.value)continue;const n=this.configOptions.find(o=>o.category===t.category&&o.type==="select");!n||n.currentValue===t.value||(await this.requireClient().agent.request(l.methods.agent.session.setConfigOption,{sessionId:this.agentSessionId,configId:n.id,value:t.value}),n.currentValue=t.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 i=JSON.stringify(e.update);if(this.emittedToolStates.get(e.update.toolCallId)===i)return;this.emittedToolStates.set(e.update.toolCallId,i)}for(const i of A(e.update,s=>this.makeEvent(s)))this.emit("agentEvent",i)}}}captureImportedUpdate(e){if(this.importCapture){if(e.sessionUpdate==="user_message_chunk"||e.sessionUpdate==="agent_message_chunk"){const i=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",t=e.messageId?`message:${e.messageId}`:void 0,n=t?this.importCapture.find(o=>o.sourceHint===t):this.importCapture.at(-1);n?.role===s&&n.sourceHint===t?n.payload+=i:this.importCapture.push({role:s,payload:i,...t?{sourceHint:t}:{}});return}if(e.sessionUpdate==="tool_call"){const i=`tool:${e.toolCallId}`,s=this.importCapture.find(n=>n.sourceHint===i),t={role:"agent",sourceHint:i,payload:JSON.stringify({v:1,type:"tool_use",name:e.title,toolCallId:e.toolCallId,status:e.status??"running"})};s?s.payload=t.payload:this.importCapture.push(t);return}if(e.sessionUpdate==="tool_call_update"&&(e.status==="completed"||e.status==="failed")){const i=this.importCapture.find(t=>t.sourceHint===`tool:${e.toolCallId}`),s=JSON.stringify({v:1,type:"tool_result",name:e.title??"tool",toolCallId:e.toolCallId,status:e.status});i?i.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 i=p();return new Promise(s=>{const t=setTimeout(()=>{this.pendingPermissions.delete(i),s({outcome:{outcome:"cancelled"}})},this.options.permissionTimeoutMs??3e5);t.unref?.(),this.pendingPermissions.set(i,{optionIds:new Set(e.options.map(n=>n.optionId)),resolve:s,timer:t}),this.emitEvent({state:"approval-pending",runPhase:"waiting_approval",approval:{title:e.toolCall.title??void 0,source:this.manifest.name},permission:{id:i,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}buildEnvironment(){return this.managedAgentPolicy?{...this.extraEnv}:{...process.env,...this.extraEnv}}buildClientCapabilities(){const e=this.manifest.clientCapabilities??{},i=this.managedAgentPolicy?.adapterPolicy;return i?{readTextFile:!!e.readTextFile,writeTextFile:!!(e.writeTextFile&&i.fileAccess!=="workspace-read"),terminal:!1}: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,i){let s;try{return await Promise.race([e.agent.request(l.methods.agent.session.prompt,{sessionId:this.agentSessionId,prompt:i}),new Promise((t,n)=>{s=setTimeout(()=>n(new Error("ACP prompt timed out")),this.options.promptTimeoutMs??720*6e4),s.unref?.()})])}catch(t){throw t instanceof Error&&t.message==="ACP prompt timed out"&&(await e.close(),this.client===e&&(this.client=null)),t}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 F(d){C(g(d.id),()=>new b(d))}export{b as AcpAgentAdapter,F as registerAcpAgent};
@@ -0,0 +1,3 @@
1
+ import type { AcpAgentType, AgentAuthState } from '@shennian/wire';
2
+ export declare function getAcpRuntimeAuthState(type: AcpAgentType): AgentAuthState | undefined;
3
+ export declare function setAcpRuntimeAuthState(type: AcpAgentType, state: AgentAuthState): void;
@@ -0,0 +1 @@
1
+ const e=new Map;function u(t){return e.get(t)}function c(t,n){e.set(t,n)}export{u as getAcpRuntimeAuthState,c as setAcpRuntimeAuthState};
@@ -0,0 +1,7 @@
1
+ import { type StdioOptions } from 'node:child_process';
2
+ import type { AuthMethodTerminal } from '@agentclientprotocol/sdk';
3
+ import type { AcpLaunchSpec } from './types.js';
4
+ export declare function runAcpTerminalAuthentication(launch: AcpLaunchSpec, method: AuthMethodTerminal, cwd: string, options?: {
5
+ requireTty?: boolean;
6
+ stdio?: StdioOptions;
7
+ }): Promise<void>;
@@ -0,0 +1 @@
1
+ import{spawn as d}from"node:child_process";import{buildCommandStringLaunchSpec as u}from"../command-spec.js";async function w(n,r,e,i={}){if(i.requireTty!==!1&&(!process.stdin.isTTY||!process.stdout.isTTY))throw new Error("ACP terminal authentication requires an interactive terminal");const t=u(n.command,[...n.args??[],...r.args??[]],e);await new Promise((c,o)=>{const s=d(t.command,t.args??[],{cwd:e,env:{...process.env,...n.env,...r.env},stdio:i.stdio??"inherit",windowsHide:!1});s.once("error",o),s.once("exit",(a,m)=>a===0?c():o(new Error(`ACP terminal authentication failed (${a??m??"unknown"})`)))})}export{w as runAcpTerminalAuthentication};
@@ -0,0 +1,14 @@
1
+ import type { DetectedAgent } from '../detect.js';
2
+ import type { AcpAgentManifest } from './types.js';
3
+ export declare function buildAcpCapabilityCacheKey(input: {
4
+ manifest: AcpAgentManifest;
5
+ platform: NodeJS.Platform;
6
+ catalogRevision?: string;
7
+ executableIdentity?: {
8
+ pathHash: string;
9
+ fingerprint: string;
10
+ } | null;
11
+ }): string | null;
12
+ export declare function readAcpCapabilityCache(key: string): DetectedAgent | null;
13
+ export declare function writeAcpCapabilityCache(key: string, agent: DetectedAgent): void;
14
+ export declare function clearAcpCapabilityCache(): void;
@@ -0,0 +1,2 @@
1
+ import c from"node:crypto";import n from"node:fs";import l from"node:path";import{resolveShennianPath as r}from"../../config/index.js";const a="acp-capabilities-v1.json",m=2*1024*1024;function h(e){return e.executableIdentity?c.createHash("sha256").update(JSON.stringify({id:e.manifest.id,command:e.manifest.launch.command,args:e.manifest.launch.args??[],env:e.manifest.launch.env??{},clientCapabilities:e.manifest.clientCapabilities??{},platform:e.platform,catalogRevision:e.catalogRevision??"local",executable:e.executableIdentity})).digest("hex"):null}function b(e){return o().entries[e]??null}function C(e,t){const i=o();i.entries[e]=t;const s=Object.entries(i.entries).slice(-256);f({version:1,entries:Object.fromEntries(s)})}function v(){try{n.unlinkSync(r(a))}catch{}}function o(){try{const e=r(a);if(n.statSync(e).size>m)return{version:1,entries:{}};const t=JSON.parse(n.readFileSync(e,"utf8"));if(t.version!==1||!t.entries||typeof t.entries!="object")throw new Error("invalid");return t}catch{return{version:1,entries:{}}}}function f(e){const t=r(a);n.mkdirSync(l.dirname(t),{recursive:!0,mode:448});const i=`${t}.tmp-${process.pid}-${c.randomUUID()}`;try{n.writeFileSync(i,`${JSON.stringify(e)}
2
+ `,{mode:384,flag:"wx"}),n.renameSync(i,t)}finally{try{n.unlinkSync(i)}catch{}}}export{h as buildAcpCapabilityCacheKey,v as clearAcpCapabilityCache,b as readAcpCapabilityCache,C as writeAcpCapabilityCache};
@@ -0,0 +1,11 @@
1
+ import type { AcpCatalogPlatform } from '@shennian/wire';
2
+ import type { AcpAgentManifest } from './types.js';
3
+ export declare function loadAcpCatalog(options?: {
4
+ serverUrl?: string;
5
+ authToken?: string;
6
+ fetchImpl?: typeof fetch;
7
+ }): Promise<{
8
+ revision?: string;
9
+ candidates: AcpAgentManifest[];
10
+ }>;
11
+ export declare function currentAcpPlatform(): AcpCatalogPlatform;
@@ -0,0 +1,2 @@
1
+ import n from"node:fs";import u from"node:path";import{resolveShennianPath as f}from"../../config/index.js";import{deriveInstalledPackageCommands as g}from"./package-commands.js";const p="acp-registry-v1.json",s=2*1024*1024;async function S(a={}){const r=i();let e=null;return a.serverUrl&&a.authToken&&(e=await w(a).catch(()=>null),e&&(!r||Date.parse(e.fetchedAt)>=Date.parse(r.fetchedAt))?y(e):e&&r&&(e=r)),e??=r,!e||e.platform!==c()?{candidates:[]}:{revision:e.revision,candidates:e.candidates.flatMap(t=>t.duplicateOf?[]:[...new Set([...t.commands,...g({npm:t.npmPackage,uv:t.uvPackage})])].map(l=>({id:t.id,name:t.name,source:"registry",...t.website?{homepage:t.website}:{},...t.npmPackage||t.uvPackage?{packageHints:{...t.npmPackage?{npm:t.npmPackage}:{},...t.uvPackage?{uv:t.uvPackage}:{}}}:{},launch:{command:l,args:t.args}})))}}function c(){const a=process.platform==="win32"?"windows":process.platform==="darwin"?"darwin":"linux",r=process.arch==="arm64"?"aarch64":"x86_64";return`${a}-${r}`}async function w(a){const r=new AbortController,e=setTimeout(()=>r.abort(),5e3);try{const t=new URL("/api/acp/registry",a.serverUrl);t.searchParams.set("platform",c());const o=await(a.fetchImpl??fetch)(t,{headers:{authorization:`Bearer ${a.authToken}`,...i()?.revision?{"x-shennian-acp-revision":i().revision}:{}},signal:r.signal});if(!o.ok)throw new Error(`ACP catalog request failed (${o.status})`);if(Number(o.headers.get("content-length")??0)>s)throw new Error("ACP catalog exceeds size limit");const m=new Uint8Array(await o.arrayBuffer());if(m.byteLength>s)throw new Error("ACP catalog exceeds size limit");return h(JSON.parse(new TextDecoder().decode(m)))}finally{clearTimeout(e)}}function h(a){if(!a||typeof a!="object")throw new Error("Invalid ACP catalog");const r=a;if(!/^[a-z0-9]+-[a-f0-9]{16}$/.test(r.revision)||!/^[a-f0-9]{64}$/.test(r.digest)||Number.isNaN(Date.parse(r.fetchedAt))||r.platform!==c()||!Array.isArray(r.candidates))throw new Error("Invalid ACP catalog");for(const e of r.candidates)if(!/^[a-z][a-z0-9-]{0,63}$/.test(e.id)||!e.name||e.name.length>80||!Array.isArray(e.commands)||e.commands.some(t=>!/^[a-zA-Z0-9._-]{1,128}$/.test(t))||!Array.isArray(e.args))throw new Error("Invalid ACP catalog candidate");return r}function i(){try{const a=f(p);return n.statSync(a).size>s?null:h(JSON.parse(n.readFileSync(a,"utf8")))}catch{return null}}function y(a){const r=f(p);n.mkdirSync(u.dirname(r),{recursive:!0,mode:448});const e=`${r}.tmp-${process.pid}`;try{n.writeFileSync(e,`${JSON.stringify(a)}
2
+ `,{mode:384,flag:"wx"}),n.renameSync(e,r)}finally{try{n.unlinkSync(e)}catch{}}}export{c as currentAcpPlatform,S as loadAcpCatalog};
@@ -0,0 +1,32 @@
1
+ import type * as acp from '@agentclientprotocol/sdk';
2
+ export declare class AcpClientServices {
3
+ readonly enabled: {
4
+ readTextFile?: boolean;
5
+ writeTextFile?: boolean;
6
+ terminal?: boolean;
7
+ };
8
+ private readonly root;
9
+ private readonly terminals;
10
+ constructor(workDir: string, enabled: {
11
+ readTextFile?: boolean;
12
+ writeTextFile?: boolean;
13
+ terminal?: boolean;
14
+ });
15
+ get capabilities(): {
16
+ fs: {
17
+ readTextFile: boolean;
18
+ writeTextFile: boolean;
19
+ };
20
+ terminal: boolean;
21
+ };
22
+ readTextFile(params: acp.ReadTextFileRequest): Promise<acp.ReadTextFileResponse>;
23
+ writeTextFile(params: acp.WriteTextFileRequest): Promise<void>;
24
+ createTerminal(params: acp.CreateTerminalRequest): Promise<acp.CreateTerminalResponse>;
25
+ terminalOutput(params: acp.TerminalOutputRequest): acp.TerminalOutputResponse;
26
+ waitForTerminalExit(params: acp.WaitForTerminalExitRequest): Promise<acp.WaitForTerminalExitResponse>;
27
+ killTerminal(params: acp.KillTerminalRequest): void;
28
+ releaseTerminal(params: acp.ReleaseTerminalRequest): void;
29
+ close(): void;
30
+ private requireTerminal;
31
+ private resolve;
32
+ }
@@ -0,0 +1,3 @@
1
+ import c from"node:fs";import n from"node:path";import{randomUUID as p}from"node:crypto";import{spawn as w}from"node:child_process";import{terminateProcessTree as m}from"./process-tree.js";class F{enabled;root;terminals=new Map;constructor(t,e){this.enabled=e,this.root=c.realpathSync(t)}get capabilities(){return{fs:{readTextFile:!!this.enabled.readTextFile,writeTextFile:!!this.enabled.writeTextFile},terminal:!!this.enabled.terminal}}async readTextFile(t){if(!this.enabled.readTextFile)throw new Error("ACP file reads are disabled");const r=(await c.promises.readFile(await this.resolve(t.path,!1),"utf8")).split(`
2
+ `),a=Math.max(0,(t.line??1)-1),i=Math.min(Math.max(0,t.limit??r.length),1e5);return{content:r.slice(a,a+i).join(`
3
+ `)}}async writeTextFile(t){if(!this.enabled.writeTextFile)throw new Error("ACP file writes are disabled");const e=await this.resolve(t.path,!0);await c.promises.writeFile(e,t.content,"utf8")}async createTerminal(t){if(!this.enabled.terminal)throw new Error("ACP terminals are disabled");const e=await this.resolve(t.cwd??this.root,!1),r=w(t.command,t.args??[],{cwd:e,env:{...process.env,...Object.fromEntries((t.env??[]).map(s=>[s.name,s.value]))},stdio:["pipe","pipe","pipe"],detached:process.platform!=="win32",windowsHide:!0}),a=Math.min(Number(t.outputByteLimit??1024*1024),4*1024*1024),i={child:r,output:Buffer.alloc(0),limit:a,truncated:!1,exitStatus:null,exited:new Promise(s=>r.once("exit",(o,h)=>{const d={exitCode:o,signal:h};i.exitStatus=d,s(d)}))},l=s=>{if(i.output=Buffer.concat([i.output,s]),i.output.byteLength>i.limit){let o=i.output.byteLength-i.limit;for(;o<i.output.byteLength&&(i.output[o]&192)===128;)o+=1;i.output=i.output.subarray(o),i.truncated=!0}};r.stdout.on("data",l),r.stderr.on("data",l);const u=p();return this.terminals.set(u,i),{terminalId:u}}terminalOutput(t){const e=this.requireTerminal(t.terminalId);return{output:e.output.toString("utf8"),truncated:e.truncated,exitStatus:e.exitStatus}}async waitForTerminalExit(t){return this.requireTerminal(t.terminalId).exited}killTerminal(t){m(this.requireTerminal(t.terminalId).child)}releaseTerminal(t){const e=this.requireTerminal(t.terminalId);e.exitStatus||m(e.child),this.terminals.delete(t.terminalId)}close(){for(const t of this.terminals.values())t.exitStatus||m(t.child);this.terminals.clear()}requireTerminal(t){const e=this.terminals.get(t);if(!e)throw new Error("Unknown ACP terminal");return e}async resolve(t,e){if(!n.isAbsolute(t))throw new Error("ACP path must be absolute");const r=n.resolve(t),a=e?n.dirname(r):r,i=await c.promises.realpath(a),l=e?n.join(i,n.basename(r)):i,u=n.relative(this.root,l);if(u.startsWith("..")||n.isAbsolute(u))throw new Error("ACP path is outside the session workspace");return l}}export{F as AcpClientServices};
@@ -0,0 +1,9 @@
1
+ import type { DetectedAgent } from '../detect.js';
2
+ import { type AcpAgentManifest } from './types.js';
3
+ export declare function discoverAcpAgents(options?: {
4
+ candidates?: AcpAgentManifest[];
5
+ cwd?: string;
6
+ serverUrl?: string;
7
+ authToken?: string;
8
+ fetchImpl?: typeof fetch;
9
+ }): Promise<DetectedAgent[]>;
@@ -0,0 +1 @@
1
+ import{RequestError as B}from"@agentclientprotocol/sdk";import{buildCommandStringLaunchSpec as k,commandExists as x,resolveCommandFileIdentity as M}from"../command-spec.js";import{registerAcpAgent as v}from"./adapter.js";import{getRegisteredAgents as R,unregisterAgent as T}from"../adapter.js";import{readAcpManifests as E}from"./manifests.js";import{AcpProcessClient as L}from"./process-client.js";import{acpAgentType as h}from"./types.js";import{loadAcpCatalog as D}from"./catalog.js";import{buildAcpCapabilityCacheKey as F,readAcpCapabilityCache as N,writeAcpCapabilityCache as P}from"./capability-cache.js";import{getAcpRuntimeAuthState as S,setAcpRuntimeAuthState as _}from"./auth-state.js";import{recordAcpScan as q}from"./metrics.js";const K=[{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"]}}],O=new Set(["claude","codex","codebuddy","cursor","opencode","pi"]);async function ne(t={}){const i=Date.now();let r=0,n=0;const c={};for(const e of R())e.startsWith("acp:")&&T(e);const s=t.candidates?{candidates:t.candidates,revision:void 0}:await D(t),y=$([...s.candidates.length?s.candidates:K,...E()]),b=y.filter(e=>{const f=e.launch.command;return O.has(f)?!1:x(f)}).filter((e,f,o)=>o.findIndex(m=>m.id===e.id)===f),C=(await H(b,3,async e=>{const o={...k(e.launch.command,e.launch.args??[],t.cwd??process.cwd()),...e.launch.env?{env:e.launch.env}:{}},m=F({manifest:e,platform:process.platform,catalogRevision:s.revision,executableIdentity:M(e.launch.command)}),d=m?N(m):null;if(d?.type===h(e.id)&&d.integration==="acp"&&d.acpCapabilities?.protocolVersion===1)return r+=1,v({...e,launch:o,authLaunch:e.launch}),{...d,authState:S(h(e.id))??d.authState,command:o.command,args:o.args??[],display:{...d.display,name:e.name},...s.revision?{catalogRevision:s.revision}:{}};const g=new L(o,{onSessionUpdate:()=>{},onPermission:async()=>({outcome:{outcome:"cancelled"}})},process.env,{terminalAuth:!0});try{const l=await g.start(t.cwd??process.cwd()),a=l.agentCapabilities??{},I={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=l.authMethods?.length?"unknown":"ready";if(a.sessionCapabilities?.list)try{await g.listSessions(t.cwd??process.cwd()),p=l.authMethods?.length?"unknown":"ready"}catch(u){p=u instanceof B&&u.code===-32e3?"required":"unknown"}const A=S(h(e.id));A?p=A:p==="required"&&_(h(e.id),p),v({...e,launch:o,authLaunch:e.launch});const w={type:h(e.id),command:o.command,args:o.args??[],version:l.agentInfo?.version??void 0,runtimePlatform:process.platform,integration:"acp",display:{name:e.name,version:l.agentInfo?.version??void 0},acpCapabilities:I,authState:p,acpAuthMethods:(l.authMethods??[]).slice(0,8).map(u=>({id:u.id.slice(0,128),name:u.name.slice(0,80),type:"type"in u&&u.type==="terminal"?"terminal":"agent"})),...s.revision?{catalogRevision:s.revision}:{}};return m&&P(m,w),w}catch(l){n+=1;const a=W(l);return c[a]=(c[a]??0)+1,null}finally{await g.close()}})).filter(e=>!!e);return q({durationMs:Date.now()-i,candidateCount:y.length,installedCount:C.length,cacheHits:r,handshakeFailures:n,handshakeFailuresByKind:c}),C}function W(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 $(t){const i=new Set(t.filter(n=>n.source==="local").map(n=>n.id)),r=new Map;for(const n of t){if(n.source!=="local"&&i.has(n.id))continue;const c=`${n.id}\0${n.launch.command}\0${JSON.stringify(n.launch.args??[])}`;r.has(c)||r.set(c,n)}return[...r.values()]}async function H(t,i,r){const n=new Array(t.length);let c=0;return await Promise.all(Array.from({length:Math.min(i,t.length)},async()=>{for(;;){const s=c++;if(s>=t.length)return;n[s]=await r(t[s])}})),n}export{ne as discoverAcpAgents};
@@ -0,0 +1,4 @@
1
+ import type { SessionUpdate } from '@agentclientprotocol/sdk';
2
+ import type { AgentEvent } from '../adapter.js';
3
+ export type AcpEventFactory = (partial: Omit<AgentEvent, 'runId' | 'seq'>) => AgentEvent;
4
+ export declare function mapAcpSessionUpdate(update: SessionUpdate, makeEvent: AcpEventFactory): AgentEvent[];
@@ -0,0 +1,3 @@
1
+ function n(t){if(typeof t=="string")return t;try{return JSON.stringify(t)}catch{return String(t)}}function r(t){return t.type==="text"?t.text:t.type==="resource_link"?t.name||t.uri:t.type==="resource"?"text"in t.resource?t.resource.text:`[${t.resource.mimeType??"resource"}]`:`[${t.type}: ${t.mimeType}]`}function o(t){return t?.length?t.map(e=>e.type==="content"?r(e.content):e.type==="diff"?`${e.path}
2
+ ${e.newText}`:`[terminal: ${e.terminalId}]`).join(`
3
+ `):""}function l(t,e){switch(t.sessionUpdate){case"agent_message_chunk":return[e({state:"delta",text:r(t.content)})];case"agent_thought_chunk":return[e({state:"delta",text:r(t.content),thinking:!0})];case"tool_call":return[e({state:"tool-call",toolCallId:t.toolCallId,toolStatus:"running",name:t.title,args:typeof t.rawInput=="object"&&t.rawInput!==null?t.rawInput:t.rawInput===void 0?void 0:{input:t.rawInput}})];case"tool_call_update":{if(t.status!=="completed"&&t.status!=="failed")return[];const s=o(t.content)||(t.rawOutput===void 0?t.status:n(t.rawOutput));return[e({state:"tool-result",toolCallId:t.toolCallId,toolStatus:t.status,name:t.title??t.toolCallId,result:s})]}case"usage_update":return[e({state:"notify",title:"Context usage",text:`${t.used}/${t.size}`})];case"plan":case"plan_update":return[e({state:"notify",title:"Plan updated",text:n(t)})];case"session_info_update":return t.title?[e({state:"notify",title:"Session",text:t.title})]:[];default:return[]}}export{l as mapAcpSessionUpdate};