dsh-loop-engine-allinone 0.0.0-stage → 0.4.0

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 (143) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/CONTRIBUTING.md +78 -0
  3. package/LICENSE +23 -0
  4. package/NOTICE +45 -0
  5. package/README.md +221 -2
  6. package/README.zh.md +89 -0
  7. package/SECURITY.md +39 -0
  8. package/cordis.patch.yml +3 -0
  9. package/lib/client.js +2166 -0
  10. package/lib/index.js +11621 -0
  11. package/lib/invariant.js +453 -0
  12. package/lib/types/agent-preset-ids.d.ts +276 -0
  13. package/lib/types/client/LoopEngineBadge.d.ts +71 -0
  14. package/lib/types/client/LoopEngineComposerSelect.d.ts +126 -0
  15. package/lib/types/client/LoopEngineSection.d.ts +35 -0
  16. package/lib/types/client/engine-marks.d.ts +87 -0
  17. package/lib/types/client/index.d.ts +39 -0
  18. package/lib/types/client/locales.d.ts +182 -0
  19. package/lib/types/client/reload.d.ts +135 -0
  20. package/lib/types/client/session-engine.d.ts +508 -0
  21. package/lib/types/client/store.d.ts +103 -0
  22. package/lib/types/client/turn-status.d.ts +234 -0
  23. package/lib/types/client/use-session-engine.d.ts +74 -0
  24. package/lib/types/commands.d.ts +77 -0
  25. package/lib/types/compat.d.ts +25 -0
  26. package/lib/types/driver-acp/agent.d.ts +289 -0
  27. package/lib/types/driver-acp/approval.d.ts +27 -0
  28. package/lib/types/driver-acp/capabilities.d.ts +200 -0
  29. package/lib/types/driver-acp/client.d.ts +297 -0
  30. package/lib/types/driver-acp/executable.d.ts +53 -0
  31. package/lib/types/driver-acp/mapping.d.ts +76 -0
  32. package/lib/types/driver-acp/profile.d.ts +126 -0
  33. package/lib/types/driver-acp/runtime.d.ts +45 -0
  34. package/lib/types/driver-acp/subprocess.d.ts +19 -0
  35. package/lib/types/driver-acp/terminal.d.ts +98 -0
  36. package/lib/types/driver-acp/transport.d.ts +43 -0
  37. package/lib/types/driver-acp/types.d.ts +152 -0
  38. package/lib/types/driver-cli/capability.d.ts +42 -0
  39. package/lib/types/driver-cli/cli-agent.d.ts +258 -0
  40. package/lib/types/driver-cli/cli-loop.d.ts +46 -0
  41. package/lib/types/driver-cli/flatten.d.ts +35 -0
  42. package/lib/types/driver-cli/frames.d.ts +128 -0
  43. package/lib/types/driver-cli/ndjson.d.ts +106 -0
  44. package/lib/types/driver-cli/session-sink.d.ts +333 -0
  45. package/lib/types/driver-cli/stream-json.d.ts +61 -0
  46. package/lib/types/driver-cli/text.d.ts +66 -0
  47. package/lib/types/driver-cli/transport.d.ts +84 -0
  48. package/lib/types/driver-core/agents-md-skill-provider.d.ts +72 -0
  49. package/lib/types/driver-core/assistant-stream.d.ts +68 -0
  50. package/lib/types/driver-core/context-files.d.ts +62 -0
  51. package/lib/types/driver-core/host-servers.d.ts +119 -0
  52. package/lib/types/driver-core/hosted-engine-runtime.d.ts +190 -0
  53. package/lib/types/driver-core/hosted-tool-vocabulary.d.ts +78 -0
  54. package/lib/types/driver-core/idle-child.d.ts +57 -0
  55. package/lib/types/driver-core/image-access.d.ts +25 -0
  56. package/lib/types/driver-core/inbox.d.ts +104 -0
  57. package/lib/types/driver-core/model-handover.d.ts +134 -0
  58. package/lib/types/driver-core/ownership.d.ts +41 -0
  59. package/lib/types/driver-core/permission-knobs.d.ts +26 -0
  60. package/lib/types/driver-core/prompt.d.ts +64 -0
  61. package/lib/types/driver-core/session-lifetime.d.ts +62 -0
  62. package/lib/types/driver-core/session-model.d.ts +128 -0
  63. package/lib/types/driver-core/skill-inject.d.ts +59 -0
  64. package/lib/types/driver-core/step-close.d.ts +49 -0
  65. package/lib/types/driver-core/step-images.d.ts +62 -0
  66. package/lib/types/driver-core/step-tools.d.ts +43 -0
  67. package/lib/types/driver-core/system-head.d.ts +43 -0
  68. package/lib/types/engine-agy/agent.d.ts +67 -0
  69. package/lib/types/engine-agy/frames.d.ts +90 -0
  70. package/lib/types/engine-agy/loop.d.ts +64 -0
  71. package/lib/types/engine-agy/process.d.ts +173 -0
  72. package/lib/types/engine-claude/agent.d.ts +186 -0
  73. package/lib/types/engine-claude/loop.d.ts +73 -0
  74. package/lib/types/engine-claude/mapping.d.ts +108 -0
  75. package/lib/types/engine-claude/permission.d.ts +41 -0
  76. package/lib/types/engine-claude/process.d.ts +59 -0
  77. package/lib/types/engine-claude/sdk.d.ts +67 -0
  78. package/lib/types/engine-claude/types.d.ts +28 -0
  79. package/lib/types/engine-codex/agent.d.ts +216 -0
  80. package/lib/types/engine-codex/appserver/client.d.ts +80 -0
  81. package/lib/types/engine-codex/appserver/mapping.d.ts +67 -0
  82. package/lib/types/engine-codex/appserver/thread.d.ts +66 -0
  83. package/lib/types/engine-codex/appserver/types.d.ts +225 -0
  84. package/lib/types/engine-codex/loop.d.ts +75 -0
  85. package/lib/types/engine-codex/model-handover.d.ts +56 -0
  86. package/lib/types/engine-codex/permission.d.ts +126 -0
  87. package/lib/types/engine-codex/skills.d.ts +28 -0
  88. package/lib/types/engine-codex/types.d.ts +36 -0
  89. package/lib/types/engine-drivers.d.ts +132 -0
  90. package/lib/types/engine-grok/agent.d.ts +24 -0
  91. package/lib/types/engine-grok/loop.d.ts +61 -0
  92. package/lib/types/engine-grok/process.d.ts +46 -0
  93. package/lib/types/engine-grok/profile.d.ts +82 -0
  94. package/lib/types/engine-hermes/agent.d.ts +47 -0
  95. package/lib/types/engine-hermes/loop.d.ts +56 -0
  96. package/lib/types/engine-hermes/process.d.ts +92 -0
  97. package/lib/types/engine-kimi/acp/client.d.ts +123 -0
  98. package/lib/types/engine-kimi/acp/mapping.d.ts +73 -0
  99. package/lib/types/engine-kimi/acp/types.d.ts +143 -0
  100. package/lib/types/engine-kimi/agent.d.ts +24 -0
  101. package/lib/types/engine-kimi/commands.d.ts +44 -0
  102. package/lib/types/engine-kimi/loop.d.ts +62 -0
  103. package/lib/types/engine-kimi/model-handover.d.ts +32 -0
  104. package/lib/types/engine-kimi/permission.d.ts +28 -0
  105. package/lib/types/engine-kimi/process.d.ts +47 -0
  106. package/lib/types/engine-kimi/profile.d.ts +19 -0
  107. package/lib/types/engine-kimi/skills.d.ts +52 -0
  108. package/lib/types/engine-kimi/types.d.ts +25 -0
  109. package/lib/types/engine-minimaxcode/agent.d.ts +24 -0
  110. package/lib/types/engine-minimaxcode/loop.d.ts +83 -0
  111. package/lib/types/engine-minimaxcode/process.d.ts +53 -0
  112. package/lib/types/engine-minimaxcode/profile.d.ts +72 -0
  113. package/lib/types/engine-of-session.d.ts +97 -0
  114. package/lib/types/engine-pi/agent.d.ts +230 -0
  115. package/lib/types/engine-pi/loop.d.ts +72 -0
  116. package/lib/types/engine-pi/model-handover.d.ts +84 -0
  117. package/lib/types/engine-pi/permission.d.ts +47 -0
  118. package/lib/types/engine-pi/rpc/client.d.ts +107 -0
  119. package/lib/types/engine-pi/rpc/mapping.d.ts +37 -0
  120. package/lib/types/engine-pi/rpc/types.d.ts +249 -0
  121. package/lib/types/engine-pi/skills.d.ts +47 -0
  122. package/lib/types/engine-pi/types.d.ts +36 -0
  123. package/lib/types/engine-qoderclicn/agent.d.ts +59 -0
  124. package/lib/types/engine-qoderclicn/loop.d.ts +51 -0
  125. package/lib/types/engine-qoderclicn/process.d.ts +113 -0
  126. package/lib/types/engine-registry.d.ts +584 -0
  127. package/lib/types/engine-remote.d.ts +192 -0
  128. package/lib/types/engine-surface.d.ts +36 -0
  129. package/lib/types/engine-zcode/agent.d.ts +50 -0
  130. package/lib/types/engine-zcode/loop.d.ts +47 -0
  131. package/lib/types/engine-zcode/process.d.ts +111 -0
  132. package/lib/types/index.d.ts +205 -0
  133. package/lib/types/invariant.d.ts +26 -0
  134. package/lib/types/model-selection-reset.d.ts +271 -0
  135. package/lib/types/namespace.d.ts +25 -0
  136. package/lib/types/patch-manager.d.ts +104 -0
  137. package/lib/types/preset.d.ts +254 -0
  138. package/lib/types/provider-route.d.ts +245 -0
  139. package/lib/types/router-loop.d.ts +458 -0
  140. package/lib/types/session-engine-store.d.ts +138 -0
  141. package/lib/types/settings.d.ts +60 -0
  142. package/lib/types/skills.d.ts +85 -0
  143. package/package.json +150 -4
@@ -0,0 +1,297 @@
1
+ /**
2
+ * JSON-RPC 2.0 client for an ACP agent subprocess (Agent Client Protocol over
3
+ * stdio), shared by every ACP engine driver.
4
+ *
5
+ * The driver hands the client a process handle carrying its stdin/stdout/stderr
6
+ * (projected from the dsh subprocess seam). The client frames JSON-RPC 2.0
7
+ * records on a bare `\n` (via a byte decoder, tolerating a trailing `\r`),
8
+ * correlates request responses by `id`, dispatches every `session/update`
9
+ * notification to a buffered event stream, and answers the reverse-RPC
10
+ * `session/request_permission` requests the agent publishes. The child is
11
+ * long-lived (one per factory) and stepped over via `newSession` + `prompt`.
12
+ *
13
+ * ## What is per-ENGINE here, and what is not
14
+ *
15
+ * The framing, correlation and dispatch are protocol facts and identical for
16
+ * every ACP engine. Three things are NOT:
17
+ *
18
+ * - the `protocolVersion` announced at `initialize`, which is a REGISTRY
19
+ * DECLARATION (`capabilities.acpProtocolVersion`, default 1) rather than a
20
+ * constant: three engines sharing one skeleton must not share one hardcoded
21
+ * version, which is the protocol-drift risk this parameter removes;
22
+ * - how a MODEL is selected (`session/set_model` on kimi,
23
+ * `session/set_config_option` on grok and MiniMax Code), exposed as separate
24
+ * methods so each driver calls the one its engine was measured to accept;
25
+ * - the engine's name in diagnostics, which travels as `label` so a message
26
+ * from a `grok agent stdio` child never says "kimi".
27
+ *
28
+ * @module dsh-loop-engine-allinone/driver-acp/client
29
+ */
30
+ import type { AcpProcess, AcpSpawnCapability, AcpSpawnSpec } from './transport.ts';
31
+ import { type AcpClientCapabilities, type AcpReverseHandlers } from './capabilities.ts';
32
+ import { type AcpFrame, type AcpImageContent, type AcpPermissionOption, type AcpPermissionResponse, type AcpUpdate } from './types.ts';
33
+ /** How the client answers one `session/request_permission`. */
34
+ export type AcpPermissionHandler = (request: AcpFrame) => boolean | Promise<boolean>;
35
+ /**
36
+ * The answerable options of one `session/request_permission` frame. The wire is
37
+ * untrusted, so entries without a usable `optionId` are dropped rather than
38
+ * echoed back.
39
+ * @param frame - the reverse-RPC request frame.
40
+ * @returns the options the client may answer with.
41
+ */
42
+ export declare function permissionOptionsOf(frame: AcpFrame): readonly AcpPermissionOption[];
43
+ /**
44
+ * Encode one approval decision as the ACP `RequestPermissionResponse` the agent
45
+ * correlates against the options it advertised. The agent reads a terminal
46
+ * *option*, never a boolean: an outcome it cannot resolve (or a response that
47
+ * fails to parse at all) is reported to the model as a user rejection, so a
48
+ * decision that no single option expresses becomes `cancelled` — the honest
49
+ * "this client has no answer". Kimi re-uses this RPC for its question and
50
+ * plan-review bridges, which offer one `allow_once` option per choice; picking
51
+ * one of those would answer a question no human was asked, so any ambiguous
52
+ * set (zero or several `allow_once`/`reject_once` candidates) cancels instead.
53
+ * `allow_once` is preferred over `allow_always` because the decision is re-read
54
+ * from the session knobs on every request: letting the agent cache a session
55
+ * grant would outlive a mid-session switch back to `ask`.
56
+ * @param approved - whether the driver approves the request.
57
+ * @param options - the options the agent advertised for this request.
58
+ * @returns the result payload to send back.
59
+ */
60
+ export declare function permissionResponse(approved: boolean, options: readonly AcpPermissionOption[]): AcpPermissionResponse;
61
+ /** Callback receiving every non-response event line. */
62
+ export type AcpUpdateHandler = (update: AcpUpdate) => void;
63
+ /**
64
+ * Per-engine facts the shared client needs, all of them data.
65
+ *
66
+ * Defaulted rather than required, so `new AcpClient(process)` keeps meaning
67
+ * "kimi, protocol version 1" — which is what the existing callers and tests
68
+ * construct.
69
+ */
70
+ export interface AcpClientOptions {
71
+ /**
72
+ * The ACP protocol version this client announces at `initialize`.
73
+ *
74
+ * From the engine's registry row (`capabilities.acpProtocolVersion`), whose
75
+ * documented default is 1. A caller that pins nothing gets 1 — the version
76
+ * every engine on this fork's reference host was verified against.
77
+ */
78
+ readonly protocolVersion?: number;
79
+ /** The engine's name in diagnostics (`kimi`, `grok`, `minimaxcode`). */
80
+ readonly label?: string;
81
+ /**
82
+ * The reverse-RPC methods this client can answer, and how.
83
+ *
84
+ * Absent means "none": the client announces no client capabilities and answers
85
+ * every reverse request with `methodNotFound`, which is what the kimi driver has
86
+ * always done and remains a supported configuration. A driver that supplies
87
+ * `spawnTerminal` gets the `terminal` capability announced for it — the
88
+ * declaration is DERIVED from the handlers so the two cannot drift.
89
+ */
90
+ readonly handlers?: AcpReverseHandlers;
91
+ }
92
+ /**
93
+ * ACP client over one agent child. Created once per driver scope and reused
94
+ * across steps, matching the Pi RPC client's lifecycle.
95
+ */
96
+ export declare class AcpClient {
97
+ private readonly process;
98
+ private readonly pending;
99
+ private readonly updateBuffer;
100
+ private updateWake;
101
+ private updateHandler;
102
+ private permissionHandler;
103
+ private sealed;
104
+ private nextId;
105
+ private readonly decoder;
106
+ private buffer;
107
+ /** The protocol version this client announces (registry-declared, default 1). */
108
+ private readonly protocolVersion;
109
+ /** The engine's name in diagnostics. */
110
+ private readonly label;
111
+ /** What this client can answer, and how (see {@link AcpClientOptions.handlers}). */
112
+ private readonly handlers;
113
+ /** Every terminal this client owns, so a disposed client cannot leak a process. */
114
+ private readonly terminals;
115
+ /** Monotonic id source for the terminals the agent creates. */
116
+ private nextTerminalId;
117
+ /** Whether this client was sealed or its process exited. */
118
+ get closed(): boolean;
119
+ /** Mount a client over an already-spawned ACP agent process. */
120
+ constructor(process: AcpProcess, options?: AcpClientOptions);
121
+ /**
122
+ * Create a client, spawning the ACP child through the supplied capability (or
123
+ * the default node spawn when none is given).
124
+ * @param spec - the argv/cwd/env the child should run with.
125
+ * @param spawn - optional process-spawn capability (the subprocess seam).
126
+ * @param options - the engine's declared protocol version and diagnostic label.
127
+ * @returns the connected client.
128
+ */
129
+ static create(spec: AcpSpawnSpec, spawn?: AcpSpawnCapability, options?: AcpClientOptions): AcpClient;
130
+ /** Register the event dispatch handler. */
131
+ onUpdate(handler: AcpUpdateHandler): void;
132
+ /** Register the permission-approval handler (reverse-RPC answers). */
133
+ onPermission(handler: AcpPermissionHandler): void;
134
+ /** Send one request and await the correlated response. */
135
+ request(method: string, params: unknown): Promise<unknown>;
136
+ /** Send a notification (no correlated response awaited). */
137
+ notify(method: string, params: unknown): void;
138
+ /**
139
+ * The client capabilities to announce, DERIVED from what this client can
140
+ * actually answer.
141
+ *
142
+ * Declaring a capability is a promise an agent plans around, so this never
143
+ * announces more than the handlers implement: no `spawnTerminal` means no
144
+ * `terminal: true`, and no `readTextFile` means no `fs.readTextFile`. A client
145
+ * built with no handlers announces nothing, which is the pre-bridge behavior.
146
+ * @returns the capability block for `initialize`.
147
+ */
148
+ clientCapabilities(): AcpClientCapabilities;
149
+ /**
150
+ * Open the protocol handshake, announcing the engine's DECLARED protocol
151
+ * version and the capabilities this client can honour.
152
+ * @returns the agent's `initialize` result.
153
+ */
154
+ initialize(): Promise<unknown>;
155
+ /**
156
+ * Authenticate with one of the methods the agent advertised at `initialize`.
157
+ *
158
+ * Part of the ACP flow rather than an engine extension: an agent that requires
159
+ * authentication refuses `session/new` until the client answers with the method
160
+ * id it published (`grok agent stdio` does exactly that — measured on this
161
+ * host; reproduce it with `scripts/probe/acp-handshake.mjs`).
162
+ * @param methodId - one `authMethods[].id` from the initialize result.
163
+ * @returns the agent's response to `authenticate`.
164
+ */
165
+ authenticate(methodId: string): Promise<unknown>;
166
+ /**
167
+ * Start a fresh ACP session and resolve to its session id.
168
+ * @param cwd - the session's working directory.
169
+ * @param extra - engine-specific `session/new` params (grok's `_meta`, for
170
+ * example), merged over the two every engine takes.
171
+ * @returns the new session id.
172
+ */
173
+ newSession(cwd: string, extra?: Record<string, unknown>): Promise<string>;
174
+ /**
175
+ * Load (resume) an existing ACP session by id.
176
+ *
177
+ * Measured: `session/load` is accepted by MiniMax Code and advertised by grok
178
+ * (both answer `loadSession: true`). The driver itself replays the durable
179
+ * transcript and opens a fresh ACP session per step, so this exists for the
180
+ * probe and for a deployment that later wants engine-side session resume.
181
+ * @param sessionId - the session to load.
182
+ * @param cwd - the session's working directory.
183
+ * @returns the agent's response to `session/load`.
184
+ */
185
+ loadSession(sessionId: string, cwd: string): Promise<unknown>;
186
+ /**
187
+ * Select a session config option with the BARE value ACP's second-generation
188
+ * schema takes (`session/set_config_option` with `value: 'x'`).
189
+ *
190
+ * Measured on MiniMax Code 0.6.12: both `model` and `permissionMode` accept
191
+ * this spelling and answer `-32602 Invalid params` to the `{ value }` wrapper.
192
+ * @param sessionId - the ACP session the option applies to.
193
+ * @param configId - the option's id, as `session/new` advertised it.
194
+ * @param value - the new value (a string id, or a boolean for a boolean option).
195
+ * @returns the agent's response, which carries the updated option list.
196
+ */
197
+ setConfigOption(sessionId: string, configId: string, value: string | boolean): Promise<unknown>;
198
+ /**
199
+ * Select a session config option with the `{ value }` WRAPPER spelling, which
200
+ * Grok's own documentation shows.
201
+ *
202
+ * Its own method because the two spellings are mutually exclusive on the wire:
203
+ * an engine accepts one and rejects the other with `-32602 Invalid params`, so
204
+ * a driver tries the documented one and falls back — never a guess baked into
205
+ * a single call.
206
+ * @param sessionId - the ACP session the option applies to.
207
+ * @param configId - the option's id.
208
+ * @param value - the new string value.
209
+ * @returns the agent's response.
210
+ */
211
+ setConfigOptionValue(sessionId: string, configId: string, value: string): Promise<unknown>;
212
+ /**
213
+ * Switch the session's ACP MODE (`session/new` answers with `modes`).
214
+ *
215
+ * MiniMax Code advertises `default` and `plan` and accepts this call
216
+ * (measured). It is NOT the tool-permission switch — that is the engine's
217
+ * `permissionMode` config option — so the driver keeps the two apart.
218
+ * @param sessionId - the ACP session.
219
+ * @param modeId - one of the advertised mode ids.
220
+ * @returns the agent's response to `session/set_mode`.
221
+ */
222
+ setMode(sessionId: string, modeId: string): Promise<unknown>;
223
+ /**
224
+ * Select the model for one ACP session. The agent answers with an error frame
225
+ * when it cannot serve the id, and {@link request} rejects on that frame — so
226
+ * an engine that refuses the model fails the step loud rather than silently
227
+ * running its own default.
228
+ * @param sessionId - the ACP session the model applies to.
229
+ * @param modelId - the model id to select.
230
+ * @returns the agent's response to `session/set_model`.
231
+ */
232
+ setModel(sessionId: string, modelId: string): Promise<unknown>;
233
+ /**
234
+ * Prompt the agent in a session and resolve when the turn completes.
235
+ * @param sessionId - the ACP session to prompt.
236
+ * @param text - the serialized transcript, or a bare slash command.
237
+ * @param images - image blocks to carry after the text block; omitted or
238
+ * empty leaves the request exactly the text-only shape.
239
+ * @returns the agent's response to `session/prompt`.
240
+ */
241
+ prompt(sessionId: string, text: string, images?: readonly AcpImageContent[]): Promise<unknown>;
242
+ /** Cancel the active turn in a session (fire-and-forget). */
243
+ cancel(sessionId: string): void;
244
+ /**
245
+ * Answer a pending `session/request_permission`.
246
+ * @param id - the reverse-RPC request id.
247
+ * @param response - the ACP outcome to answer with.
248
+ */
249
+ respondPermission(id: number, response: AcpPermissionResponse): void;
250
+ /** Consume every buffered update as an async generator. */
251
+ updates(): AsyncGenerator<AcpUpdate, void, void>;
252
+ /** Seal the client and request child termination. */
253
+ dispose(): void;
254
+ private feed;
255
+ /** Dispatch one parsed line: a response, an update notification, or a reverse-RPC request. */
256
+ private dispatch;
257
+ private settle;
258
+ private handlePermission;
259
+ /**
260
+ * Answer one client-side capability request (`fs/read_text_file`, `terminal/*`).
261
+ *
262
+ * A capability this client did not announce is still answered `methodNotFound`
263
+ * rather than guessed at: an agent that calls one anyway gets the same honest
264
+ * refusal it would get from a client that never claimed it.
265
+ * @param id - the reverse-RPC request id.
266
+ * @param method - the ACP method name.
267
+ * @param params - the request params.
268
+ */
269
+ private handleCapability;
270
+ /**
271
+ * Perform one capability request and return its ACP result payload.
272
+ * @param method - the ACP method name.
273
+ * @param params - the request params.
274
+ * @returns the result object to send back.
275
+ */
276
+ private capabilityResult;
277
+ /**
278
+ * The terminal id one capability frame names.
279
+ * @param params - the request params.
280
+ * @returns the id.
281
+ */
282
+ private terminalIdOf;
283
+ /**
284
+ * The live terminal one capability frame names.
285
+ * @param params - the request params.
286
+ * @returns the terminal.
287
+ */
288
+ private terminalOf;
289
+ /**
290
+ * Write one reverse-RPC answer (result or error).
291
+ * @param id - the request id being answered.
292
+ * @param result - the result payload.
293
+ * @param error - the error payload, when the request failed.
294
+ */
295
+ private writeResult;
296
+ }
297
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Finding an external CLI and launching it correctly, shared by the ACP engines.
3
+ *
4
+ * Two Windows-specific facts make "just spawn the name" wrong, and both were
5
+ * measured on this fork's reference host rather than assumed:
6
+ *
7
+ * - an npm-installed CLI is a `mcode.cmd` / `grok.cmd` SHIM, and node's spawn
8
+ * cannot execute a `.cmd` — `spawn('mcode', …)` fails with `ENOENT` while
9
+ * `mcode --version` works in a shell. The shim has to go through
10
+ * `cmd.exe /c`, or the package's own JS entrypoint has to be spawned under
11
+ * `process.execPath`;
12
+ * - a PATH lookup therefore has to consider `PATHEXT`, not just the bare name,
13
+ * or it finds the extension-less shell script npm also writes (which the OS
14
+ * cannot execute either).
15
+ *
16
+ * @module dsh-loop-engine-allinone/driver-acp/executable
17
+ */
18
+ /**
19
+ * The argv prefix that launches one executable, accounting for what the resolved
20
+ * path actually IS.
21
+ *
22
+ * A `.js`/`.cjs`/`.mjs` file is a package entrypoint and runs under the CURRENT
23
+ * node (`process.execPath`), never directly (Windows answers `EFTYPE`/`ENOENT`);
24
+ * a `.cmd`/`.bat` shim goes through the command interpreter; anything else is a
25
+ * real executable and is spawned as itself.
26
+ * @param bin - the resolved executable or script path.
27
+ * @returns the argv prefix, ending in the file to run.
28
+ */
29
+ export declare function execArgvPrefix(bin: string): string[];
30
+ /**
31
+ * Resolve a bare command name against `PATH`, honouring `PATHEXT` on Windows.
32
+ *
33
+ * Written by hand rather than shelled out (`where`/`which`) on purpose: this runs
34
+ * inside the plugin's own process, where spawning a helper to answer a question
35
+ * about spawning would be its own failure mode.
36
+ * @param name - the command name, without an extension.
37
+ * @param env - the environment to read `PATH`/`PATHEXT` from.
38
+ * @returns the first existing match, or undefined when nothing matches.
39
+ */
40
+ export declare function resolveOnPath(name: string, env?: NodeJS.ProcessEnv): string | undefined;
41
+ /**
42
+ * Find one npm package's entrypoint under a global npm prefix.
43
+ *
44
+ * Both npm layouts are probed (the Windows prefix puts `node_modules` directly
45
+ * under it; a POSIX prefix keeps it under `lib`), because the plugin may be
46
+ * running under either and a wrong guess only costs one `existsSync`.
47
+ * @param prefix - an npm prefix, or the directory holding `node_modules`.
48
+ * @param pkg - the package name, scope included (`@minimax-ai/code`).
49
+ * @param entry - the file inside the package that starts the CLI (`cli.js`).
50
+ * @returns the entrypoint path when it exists.
51
+ */
52
+ export declare function npmPackageEntry(prefix: string, pkg: string, entry: string): string | undefined;
53
+ //# sourceMappingURL=executable.d.ts.map
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Maps ACP `session/update` events to dsh session-log projections.
3
+ *
4
+ * Every ACP engine streams the same event vocabulary: incremental assistant text
5
+ * (`agent_message_chunk`), incremental thinking (`agent_thought_chunk`), a
6
+ * tool-call announcement (`tool_call`) and its progress/result updates
7
+ * (`tool_call_update`). Assistant text and thinking are Deltas; a tool update's
8
+ * content is a whole Snapshot that replaces the previous one. A tool call's
9
+ * identity arrives on the announcement but its input (`rawInput`) does not —
10
+ * only a later update carries it.
11
+ *
12
+ * This module is pure and engine-neutral: it classifies an update, extracts chunk
13
+ * deltas, and projects the tool-call identity/input/content/result so the agent
14
+ * can fold them into the durable log. The one shape it reads is the content-block
15
+ * nesting measured on the wire — `{ type: 'content', content: { type: 'text',
16
+ * text } }` for a tool card, `{ type: 'text', text }` for a message chunk — and a
17
+ * block type this build does not know is ignored rather than guessed at.
18
+ *
19
+ * @module dsh-loop-engine-allinone/driver-acp/mapping
20
+ */
21
+ import type { ToolResultMessage } from '@deepseek-ai/dsh-llm';
22
+ import type { AcpContentBlock, AcpToolCallExt, AcpToolCallStreamExt, AcpUpdate } from './types.ts';
23
+ /** Whether the update is an incremental assistant text chunk. */
24
+ export declare function isTextChunk(update: AcpUpdate): update is AcpUpdate & {
25
+ readonly sessionUpdate: 'agent_message_chunk';
26
+ readonly content: AcpContentBlock;
27
+ };
28
+ /** Whether the update is an incremental thinking chunk. */
29
+ export declare function isThoughtChunk(update: AcpUpdate): update is AcpUpdate & {
30
+ readonly sessionUpdate: 'agent_thought_chunk';
31
+ readonly content: AcpContentBlock;
32
+ };
33
+ /** Whether the update announces a tool call. */
34
+ export declare function isToolCall(update: AcpUpdate): update is AcpToolCallExt;
35
+ /** Whether the update streams a tool call's progress/result. */
36
+ export declare function isToolCallUpdate(update: AcpUpdate): update is AcpToolCallStreamExt;
37
+ /** The delta text of a text/thinking chunk. */
38
+ export declare function chunkDelta(update: AcpUpdate): string;
39
+ /** The raw tool-call id (+ content index) as the wire carries it. */
40
+ export declare function toolCallIdOf(update: AcpUpdate): string;
41
+ /** The tool display name (`title`). */
42
+ export declare function toolCallName(update: AcpUpdate): string;
43
+ /**
44
+ * The tool call's real input as the JSON `arguments` string the durable
45
+ * `tool/call` carries, when the frame supplies it.
46
+ *
47
+ * The `tool_call` announcement never carries `rawInput`; a later
48
+ * `tool_call_update` does (measured against kimi 0.28.x: the execution-start
49
+ * frame, `status: 'in_progress'`). A call's arguments are therefore unknowable
50
+ * at announce time, and the driver logs the call only once an update supplies
51
+ * them — or when the call settles, whichever comes first.
52
+ * @param update - one tool-call announcement or update.
53
+ * @returns the arguments string, or `undefined` when the frame omits the field.
54
+ */
55
+ export declare function toolRawInput(update: AcpToolCallExt | AcpToolCallStreamExt): string | undefined;
56
+ /** Whether a tool stream status is settled (no longer streaming). */
57
+ export declare function isToolSettledStatus(status: string): boolean;
58
+ /** Whether a tool stream status denotes a failure. */
59
+ export declare function isToolErrorStatus(status: string): boolean;
60
+ /**
61
+ * The tool call's content as ONE update carries it: the joined text of its
62
+ * observed `{ type: 'content', content: { type: 'text', text } }` blocks.
63
+ *
64
+ * Kimi re-sends the call's whole content on every `tool_call_update` rather than
65
+ * streaming deltas (measured against 0.28.1: the string grows from the tool
66
+ * input's rendering to the final output), so this is a *snapshot* — callers
67
+ * replace with it, never append. `undefined` means the update carried no
68
+ * content field at all (nothing to replace), which is distinct from a present
69
+ * but empty one.
70
+ * @param update - one tool-call announcement or update.
71
+ * @returns the content snapshot, or `undefined` when the field is absent.
72
+ */
73
+ export declare function toolContentText(update: AcpToolCallExt | AcpToolCallStreamExt): string | undefined;
74
+ /** Project a completed tool call to a durable tool/result message. */
75
+ export declare function toolResult(callId: string, text: string, isError: boolean): ToolResultMessage;
76
+ //# sourceMappingURL=mapping.d.ts.map
@@ -0,0 +1,126 @@
1
+ /**
2
+ * The engines' side of the shared ACP driver, as data plus four small hooks.
3
+ *
4
+ * `driver-acp/agent.ts` holds the whole turn/step machine, and this module is
5
+ * everything that varies between the engines that run on it. The split is the
6
+ * same one the registry makes for the driver TABLE (one row per engine, and a
7
+ * new engine adds no branch to shared code): a new ACP engine is a profile, not
8
+ * a copy of a 900-line driver.
9
+ *
10
+ * ## What is a hook here, and why
11
+ *
12
+ * Four engine facts are CALLS rather than data, because each is a conversation
13
+ * with the agent rather than a constant:
14
+ *
15
+ * - {@link AcpEngineProfile.openSession} — grok refuses `session/new` until the
16
+ * client authenticates, MiniMax Code does not;
17
+ * - {@link AcpEngineProfile.selectModel} — kimi takes `session/set_model`,
18
+ * both new engines take `session/set_config_option` (and the two do not even
19
+ * agree on that call's parameter SHAPE);
20
+ * - {@link AcpEngineProfile.handoverEnv} — only kimi can translate a dsh
21
+ * endpoint into its own environment variables;
22
+ * - {@link AcpEngineProfile.approve} — the approval fold is a policy, and an
23
+ * engine whose own permission switch already bounds the tool may answer
24
+ * differently.
25
+ *
26
+ * `protocolVersion` is deliberately DATA and comes from the engine's registry
27
+ * row (`capabilities.acpProtocolVersion`): the value announced at `initialize`
28
+ * used to be hardcoded in the shared client, which is exactly the protocol-drift
29
+ * risk three engines on one skeleton must not inherit.
30
+ *
31
+ * @module dsh-loop-engine-allinone/driver-acp/profile
32
+ */
33
+ import type { Session } from '@deepseek-ai/dsh-session';
34
+ import type { DshModelHandover } from '../driver-core/model-handover.ts';
35
+ import type { HostedEngineId } from '../engine-registry.ts';
36
+ import type { AcpClient } from './client.ts';
37
+ /**
38
+ * One ACP driver's configuration after defaults and load-time validation.
39
+ *
40
+ * Shared because every ACP engine resolves the same four facts; the engines'
41
+ * own `process.ts` modules own the EXECUTABLE, which is what actually differs and
42
+ * what the profile's `argv` consumes.
43
+ */
44
+ export interface AcpResolvedConfig {
45
+ /** Model the session selects when it has none of its own; the engine decides when omitted. */
46
+ readonly model: string | undefined;
47
+ /** Explicit environment entries layered over the credential-scrubbed parent environment. */
48
+ readonly env: Record<string, string>;
49
+ /** The engine's CLI executable (or, for an npm-installed CLI, its entry path). */
50
+ readonly bin: string;
51
+ /**
52
+ * How long an idle session keeps its ACP child, in milliseconds; zero or less
53
+ * keeps it for the session's whole life. See `driver-core/idle-child.ts` for
54
+ * why the child, and not the agent, is what gets released.
55
+ */
56
+ readonly childIdleMs: number;
57
+ }
58
+ /** One ACP engine's protocol dialect, as the shared driver reads it. */
59
+ export interface AcpEngineProfile {
60
+ /** The registry id, used for the engine's own tool-name vocabulary. */
61
+ readonly engine: HostedEngineId;
62
+ /** The engine's name in diagnostics and error messages (`kimi`, `grok`, `minimaxcode`). */
63
+ readonly label: string;
64
+ /** The `LlmError` code a step with no assistant output fails with. */
65
+ readonly errorCode: string;
66
+ /**
67
+ * The ACP protocol version announced at `initialize`.
68
+ *
69
+ * From the registry row's `capabilities.acpProtocolVersion`; every engine on
70
+ * this fork's reference host answered protocol version 1 to a client that
71
+ * announced 1, which is also the documented default.
72
+ */
73
+ readonly protocolVersion: number;
74
+ /** The argv that launches this engine's ACP server, `argv[0]` being the executable. */
75
+ readonly argv: (bin: string) => string[];
76
+ /** Whether the engine accepts image blocks in a prompt (measured per engine). */
77
+ readonly images: boolean;
78
+ /**
79
+ * Whether the session's dsh approval knobs approve a reverse-RPC permission
80
+ * request. Absent means the ACP default: approve everything except under an
81
+ * `ask` policy, which the unattended runtime answers with a denial.
82
+ */
83
+ readonly approve?: (session: Session) => boolean;
84
+ /**
85
+ * Select the model for one ACP session, in this engine's own dialect.
86
+ *
87
+ * Absent means the engine has no model selection on this surface at all, and
88
+ * the deployment's `model`/the session's pick is dropped rather than sent as a
89
+ * call the agent would reject.
90
+ */
91
+ readonly selectModel?: (client: AcpClient, sessionId: string, model: string) => Promise<void>;
92
+ /**
93
+ * Open one ACP session, including whatever handshake the engine requires first.
94
+ *
95
+ * Absent means the plain `session/new` every ACP engine answers.
96
+ */
97
+ readonly openSession?: (client: AcpClient, cwd: string, session: Session, initializeResult: unknown) => Promise<string>;
98
+ /**
99
+ * Translate a dsh endpoint handover into this engine's own environment.
100
+ *
101
+ * Absent means the engine owns its provider credential and there is nothing to
102
+ * hand over — the shared driver then never resolves a dsh endpoint for it.
103
+ */
104
+ readonly handoverEnv?: (handover: DshModelHandover) => Record<string, string>;
105
+ /**
106
+ * Whether this engine drives its tools THROUGH the client, and so needs the
107
+ * client-side capability bridges.
108
+ *
109
+ * Measured, and it is the whole reason this field exists: MiniMax Code runs its
110
+ * own tools and reports results (`rawOutput.details.execution.exitCode`), so it
111
+ * needs nothing from us. Grok Build asks the CLIENT to read files
112
+ * (`fs/read_text_file`) and run commands (`terminal/create`), so without these
113
+ * bridges every one of its tools fails. An engine that omits this gets no
114
+ * bridges and announces no capabilities — exactly the pre-bridge behavior.
115
+ */
116
+ readonly clientBridges?: readonly AcpClientBridge[];
117
+ }
118
+ /**
119
+ * One client-side capability bridge an engine needs.
120
+ *
121
+ * Declared as a name rather than a flag per capability so the set is explicit at
122
+ * the engine's own row, and so `tests/driver-acp/capabilities.spec.ts` can assert
123
+ * that a declared bridge is really implemented and announced.
124
+ */
125
+ export type AcpClientBridge = 'readTextFile' | 'terminal';
126
+ //# sourceMappingURL=profile.d.ts.map
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The runtime half every ACP engine shares: one persistent child, one driver.
3
+ *
4
+ * Extracted from the kimi engine when two more ACP engines landed. It is the
5
+ * same machinery for all of them — hand the driver a spawn capability projected
6
+ * through the dsh subprocess seam (the only privilege boundary available) and
7
+ * let it construct the engine's agent per session. What differs per engine is
8
+ * the profile (the dialect) and the executable resolver, both of which that
9
+ * engine's own `process.ts`/`agent.ts` own.
10
+ *
11
+ * @module dsh-loop-engine-allinone/driver-acp/runtime
12
+ */
13
+ import type { Context } from '@deepseek-ai/cordis';
14
+ import type { AgentOptions } from '@deepseek-ai/dsh-agent';
15
+ import type { Session, SessionId } from '@deepseek-ai/dsh-session';
16
+ import { HostedEngineRuntime } from '../driver-core/hosted-engine-runtime.ts';
17
+ import { AcpEngineAgent } from './agent.ts';
18
+ import type { AcpEngineProfile, AcpResolvedConfig } from './profile.ts';
19
+ import type { AcpSpawnCapability } from './transport.ts';
20
+ export { acpSubprocessSpec, fromSubprocess } from './subprocess.ts';
21
+ /**
22
+ * Creation/resume machinery for one ACP engine.
23
+ *
24
+ * A plain class, not a Cordis plugin: the process-wide AgentFactory slot belongs
25
+ * to the router, which delegates each session to the engine its preset names.
26
+ * The generic agent parameter is what lets an engine with its own driver class
27
+ * (kimi's `KimiAgent`) keep it while an engine that needs nothing beyond the
28
+ * shared body uses {@link AcpEngineAgent} directly.
29
+ */
30
+ export declare abstract class AcpEngineRuntime<TAgent extends AcpEngineAgent = AcpEngineAgent> extends HostedEngineRuntime<AcpResolvedConfig, TAgent> {
31
+ protected readonly profile: AcpEngineProfile;
32
+ /** One-shot spawn capability handed to every agent, sandboxed by the subprocess seam. */
33
+ readonly spawn: AcpSpawnCapability;
34
+ /**
35
+ * @param ctx - the owning context; its fiber's unload tears every live agent down.
36
+ * @param label - effect-label prefix, e.g. `agentLoopKimi`.
37
+ * @param config - this engine's already-resolved configuration.
38
+ * @param profile - this engine's ACP dialect.
39
+ * @param disposeGraceMs - grace for process-tree termination through the seam.
40
+ */
41
+ constructor(ctx: Context, label: string, config: AcpResolvedConfig, profile: AcpEngineProfile, disposeGraceMs: number);
42
+ /** Construct the driver for one prepared session. */
43
+ protected abstract buildAgent(loopCtx: Context, id: SessionId, options: AgentOptions, session: Session): TAgent;
44
+ }
45
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Projection of one ACP spawn request onto the dsh subprocess seam.
3
+ *
4
+ * Its own module, apart from `./runtime.ts`, for a concrete reason: the seam types
5
+ * are type-only, so this file imports NO host service, and an engine's
6
+ * `process.ts` (argv + executable resolution) can therefore stay importable
7
+ * without the driver class — which is what lets `scripts/probe/smoke-acp.ts`
8
+ * exercise a real dialect against a real CLI in a process that has no dsh
9
+ * composition at all.
10
+ *
11
+ * @module dsh-loop-engine-allinone/driver-acp/subprocess
12
+ */
13
+ import type { SubprocessHandle, SubprocessSpawnSpec } from '@deepseek-ai/dsh-subprocess';
14
+ import type { AcpProcess, AcpSpawnSpec } from './transport.ts';
15
+ /** Project one driver spawn request onto the dsh subprocess seam. */
16
+ export declare function acpSubprocessSpec(spec: AcpSpawnSpec, graceMs: number): SubprocessSpawnSpec;
17
+ /** Project a dsh subprocess handle onto the ACP process transport. */
18
+ export declare function fromSubprocess(handle: SubprocessHandle): AcpProcess;
19
+ //# sourceMappingURL=subprocess.d.ts.map