@rynx-ai/runtime 0.1.11-beta.4 → 0.1.11-beta.41
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.
- package/dist/claude/executor.d.ts +19 -5
- package/dist/claude/executor.js +56 -12
- package/dist/claude/models.d.ts +0 -5
- package/dist/claude/models.js +1 -7
- package/dist/claude/native-bridge.d.ts +103 -1
- package/dist/claude/native-bridge.js +445 -30
- package/dist/claude/native-hook-main.js +81 -1
- package/dist/claude/native-hooks.js +7 -0
- package/dist/claude/native-integration.d.ts +178 -26
- package/dist/claude/native-integration.js +1528 -170
- package/dist/claude/session-status.d.ts +39 -0
- package/dist/claude/session-status.js +163 -0
- package/dist/claude/transcript-clone.d.ts +18 -0
- package/dist/claude/transcript-clone.js +497 -0
- package/dist/claude/transcript.d.ts +27 -4
- package/dist/claude/transcript.js +158 -47
- package/dist/codex-app-server/client.d.ts +10 -6
- package/dist/codex-app-server/client.js +67 -15
- package/dist/codex-app-server/forwarder.d.ts +92 -3
- package/dist/codex-app-server/forwarder.js +532 -57
- package/dist/codex-app-server/mapping.d.ts +3 -6
- package/dist/codex-app-server/mapping.js +206 -36
- package/dist/codex-app-server/mcp-startup.d.ts +13 -0
- package/dist/codex-app-server/mcp-startup.js +63 -0
- package/dist/codex-app-server/process-registry.d.ts +36 -0
- package/dist/codex-app-server/process-registry.js +320 -0
- package/dist/codex-app-server/protocol.d.ts +64 -7
- package/dist/codex-app-server/ws-channel.d.ts +7 -0
- package/dist/codex-app-server/ws-channel.js +104 -28
- package/dist/codex-home.d.ts +35 -3
- package/dist/codex-home.js +323 -18
- package/dist/codex-session-store.d.ts +23 -0
- package/dist/codex-session-store.js +21 -0
- package/dist/host.d.ts +103 -46
- package/dist/host.js +1988 -634
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/input-resources.d.ts +4 -0
- package/dist/input-resources.js +21 -5
- package/dist/models-catalog.d.ts +2 -1
- package/dist/models-catalog.js +94 -6
- package/dist/runner/child.d.ts +97 -28
- package/dist/runner/child.js +1486 -100
- package/dist/runner/manager.d.ts +110 -29
- package/dist/runner/manager.js +1481 -246
- package/dist/runner/protocol.d.ts +212 -24
- package/dist/runner/protocol.js +5 -0
- package/dist/runner/startup-policy.d.ts +7 -0
- package/dist/runner/startup-policy.js +10 -0
- package/dist/runner/transport.d.ts +18 -2
- package/dist/runner/transport.js +82 -3
- package/dist/runner-main.js +8 -3
- package/dist/terminal/claude-tui.d.ts +3 -1
- package/dist/terminal/claude-tui.js +3 -1
- package/dist/terminal/codex-tui.d.ts +4 -0
- package/dist/terminal/codex-tui.js +5 -0
- package/dist/terminal/control-parser.d.ts +39 -0
- package/dist/terminal/control-parser.js +172 -0
- package/dist/terminal/registry.d.ts +18 -15
- package/dist/terminal/registry.js +44 -23
- package/dist/terminal/spool.d.ts +47 -0
- package/dist/terminal/spool.js +231 -0
- package/dist/terminal/tmux.d.ts +126 -74
- package/dist/terminal/tmux.js +807 -211
- package/package.json +4 -4
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* (`live.ensure` / `inject` / `live.interrupt`) plus per-thread capabilities and
|
|
7
7
|
* terminal attachment; the reply channels mirror each request's `reqId`.
|
|
8
8
|
*/
|
|
9
|
-
import { AgentRuntimeError, type ResolvedExecutionSnapshot, type RuntimeUserInput, type SessionInteractionResolution, type SessionEvent, type SessionWorkspaceSnapshot } from "@rynx-ai/core";
|
|
9
|
+
import { AgentRuntimeError, type InjectResult, type ResolvedExecutionSnapshot, type RuntimeTurnOptions, type RuntimeUserInput, type SessionCollaborationMode, type SessionInteractionResolution, type SessionEvent, type SessionWorkspaceSnapshot } from "@rynx-ai/core";
|
|
10
|
+
export type { InjectOutcome, InjectResult } from "@rynx-ai/core";
|
|
10
11
|
import type { ResolveInteractionResult } from "../interactions.js";
|
|
11
12
|
/** A runtime error flattened for the wire; rebuilt parent-side as `AgentRuntimeError`. */
|
|
12
13
|
export interface WireError {
|
|
@@ -15,6 +16,10 @@ export interface WireError {
|
|
|
15
16
|
code: string;
|
|
16
17
|
statusCode: number;
|
|
17
18
|
}
|
|
19
|
+
/** Parent classification for a mirror write. `ambiguous` means persistence
|
|
20
|
+
* crossed the bounded response deadline: the
|
|
21
|
+
* operation may still commit, so retrying it would risk a duplicate. */
|
|
22
|
+
export type MirrorNackClassification = "transient" | "permanent" | "ambiguous";
|
|
18
23
|
/** Capabilities forwarded to a runner (parent serves status/listModels itself). */
|
|
19
24
|
export type CapName = "getGoal" | "setGoal" | "clearGoal" | "forkSession";
|
|
20
25
|
/** A live terminal role: `owner` is read-write, `read-only` a viewer. */
|
|
@@ -22,16 +27,50 @@ export type TerminalRole = "owner" | "read-only";
|
|
|
22
27
|
/** Stable reason for a terminal attach failure. `terminal_not_live` is an
|
|
23
28
|
* expected, retryable absence; `terminal_open_failed` is an infrastructure error. */
|
|
24
29
|
export type TerminalOpenErrorCode = "terminal_not_live" | "terminal_open_failed";
|
|
25
|
-
/**
|
|
26
|
-
* `notLive` = no live forwarder for this session (caller may use the run path).
|
|
27
|
-
* `notReady` = live but not ready within the park window; `failed` = injection
|
|
28
|
-
* threw. For BOTH notReady and failed the caller reports an error and MUST NOT
|
|
29
|
-
* re-run the turn (re-running would double-write alongside the forwarder).
|
|
30
|
-
* Mirrors reference implementation's "inject failure ⇒ response.failed, never re-run locally". */
|
|
31
|
-
export type InjectOutcome = "injected" | "notLive" | "notReady" | "failed";
|
|
32
|
-
/** Parent → child. Terminal PTY bytes ride `term.input` base64-encoded so the
|
|
30
|
+
/** Parent → child. Raw terminal bytes ride `term.input` base64-encoded so the
|
|
33
31
|
* NDJSON line framing stays intact (raw bytes contain newlines). */
|
|
34
32
|
export type ToChild = {
|
|
33
|
+
t: "mirror.ack";
|
|
34
|
+
deliveryId: string;
|
|
35
|
+
generation: number;
|
|
36
|
+
} | {
|
|
37
|
+
t: "mirror.nack";
|
|
38
|
+
deliveryId: string;
|
|
39
|
+
generation: number;
|
|
40
|
+
classification: MirrorNackClassification;
|
|
41
|
+
message: string;
|
|
42
|
+
} | {
|
|
43
|
+
t: "mirror.image.ack";
|
|
44
|
+
transferId: string;
|
|
45
|
+
seq: number;
|
|
46
|
+
generation: number;
|
|
47
|
+
} | {
|
|
48
|
+
t: "mirror.image.hold";
|
|
49
|
+
transferId: string;
|
|
50
|
+
seq: number;
|
|
51
|
+
generation: number;
|
|
52
|
+
} | {
|
|
53
|
+
t: "mirror.image.nack";
|
|
54
|
+
transferId: string;
|
|
55
|
+
seq: number;
|
|
56
|
+
generation: number;
|
|
57
|
+
classification: MirrorNackClassification;
|
|
58
|
+
message: string;
|
|
59
|
+
} | {
|
|
60
|
+
t: "rotate.ack";
|
|
61
|
+
rotationId: string;
|
|
62
|
+
generation: number;
|
|
63
|
+
} | {
|
|
64
|
+
t: "rotate.nack";
|
|
65
|
+
rotationId: string;
|
|
66
|
+
generation: number;
|
|
67
|
+
classification: MirrorNackClassification;
|
|
68
|
+
message: string;
|
|
69
|
+
} | {
|
|
70
|
+
t: "rotate.applied.ack";
|
|
71
|
+
rotationId: string;
|
|
72
|
+
generation: number;
|
|
73
|
+
} | {
|
|
35
74
|
t: "cap";
|
|
36
75
|
capId: string;
|
|
37
76
|
name: CapName;
|
|
@@ -49,13 +88,31 @@ export type ToChild = {
|
|
|
49
88
|
rows: number;
|
|
50
89
|
command?: string;
|
|
51
90
|
args?: string[];
|
|
91
|
+
} | {
|
|
92
|
+
t: "term.seed.read";
|
|
93
|
+
attachId: string;
|
|
94
|
+
reqId: string;
|
|
95
|
+
offset: number;
|
|
96
|
+
maxBytes: number;
|
|
97
|
+
} | {
|
|
98
|
+
t: "term.start";
|
|
99
|
+
attachId: string;
|
|
100
|
+
reqId: string;
|
|
101
|
+
} | {
|
|
102
|
+
t: "term.read";
|
|
103
|
+
attachId: string;
|
|
104
|
+
reqId: string;
|
|
105
|
+
offset: number;
|
|
106
|
+
maxBytes: number;
|
|
52
107
|
} | {
|
|
53
108
|
t: "term.input";
|
|
54
109
|
attachId: string;
|
|
110
|
+
reqId: string;
|
|
55
111
|
dataB64: string;
|
|
56
112
|
} | {
|
|
57
113
|
t: "term.resize";
|
|
58
114
|
attachId: string;
|
|
115
|
+
reqId: string;
|
|
59
116
|
cols: number;
|
|
60
117
|
rows: number;
|
|
61
118
|
} | {
|
|
@@ -70,8 +127,9 @@ export type ToChild = {
|
|
|
70
127
|
}
|
|
71
128
|
/** Eagerly bring up a session's live codex TUI + forwarder (codex-native), so
|
|
72
129
|
* its turns mirror to the bus regardless of whether the web has attached the
|
|
73
|
-
* terminal.
|
|
74
|
-
* the
|
|
130
|
+
* terminal. Fresh sessions connect the discovery listener before TUI launch;
|
|
131
|
+
* known-thread resumes launch the TUI after backend preload and attach their
|
|
132
|
+
* observer in the background. */
|
|
75
133
|
| {
|
|
76
134
|
t: "live.ensure";
|
|
77
135
|
reqId: string;
|
|
@@ -93,6 +151,7 @@ export type ToChild = {
|
|
|
93
151
|
t: "inject";
|
|
94
152
|
reqId: string;
|
|
95
153
|
localThreadId: string;
|
|
154
|
+
options?: RuntimeTurnOptions;
|
|
96
155
|
} & ({
|
|
97
156
|
input: RuntimeUserInput;
|
|
98
157
|
text?: never;
|
|
@@ -100,6 +159,14 @@ export type ToChild = {
|
|
|
100
159
|
text: string;
|
|
101
160
|
input?: never;
|
|
102
161
|
}))
|
|
162
|
+
/** Apply a Codex-lineage collaboration mode to an already-loaded native
|
|
163
|
+
* thread. This control path never starts a runner or waits for a new Turn. */
|
|
164
|
+
| {
|
|
165
|
+
t: "collaboration.update";
|
|
166
|
+
reqId: string;
|
|
167
|
+
localThreadId: string;
|
|
168
|
+
mode: SessionCollaborationMode;
|
|
169
|
+
}
|
|
103
170
|
/** Interrupt the session's active turn — the web Stop button. codex: app-server
|
|
104
171
|
* `turn/interrupt`; claude: an Escape keystroke to the pane. The child replies
|
|
105
172
|
* `interrupted` (echoing `reqId`). */
|
|
@@ -107,10 +174,18 @@ export type ToChild = {
|
|
|
107
174
|
t: "live.interrupt";
|
|
108
175
|
reqId: string;
|
|
109
176
|
localThreadId: string;
|
|
177
|
+
}
|
|
178
|
+
/** Pane-scoped idle cleanup. The child removes the terminal resource and
|
|
179
|
+
* performs the lifecycle adapter's explicit cleanup before acknowledging. */
|
|
180
|
+
| {
|
|
181
|
+
t: "terminal.reap";
|
|
182
|
+
reqId: string;
|
|
183
|
+
localThreadId: string;
|
|
184
|
+
terminalId: string;
|
|
110
185
|
} | {
|
|
111
186
|
t: "shutdown";
|
|
112
187
|
};
|
|
113
|
-
/** Child → parent. `term.data` carries
|
|
188
|
+
/** Child → parent. `term.data` carries raw pane output as base64 (line-safe NDJSON). */
|
|
114
189
|
export type FromChild = {
|
|
115
190
|
t: "ready";
|
|
116
191
|
} | {
|
|
@@ -124,20 +199,52 @@ export type FromChild = {
|
|
|
124
199
|
ok: false;
|
|
125
200
|
error: WireError;
|
|
126
201
|
} | {
|
|
127
|
-
t: "term.
|
|
202
|
+
t: "term.prepared";
|
|
128
203
|
attachId: string;
|
|
129
204
|
role: TerminalRole;
|
|
205
|
+
seedBytes: number;
|
|
206
|
+
cols?: number;
|
|
207
|
+
rows?: number;
|
|
130
208
|
} | {
|
|
131
|
-
t: "term.
|
|
209
|
+
t: "term.seed.chunk";
|
|
132
210
|
attachId: string;
|
|
211
|
+
reqId: string;
|
|
133
212
|
dataB64: string;
|
|
213
|
+
nextOffset: number;
|
|
214
|
+
done: boolean;
|
|
215
|
+
finalOffset?: number;
|
|
216
|
+
} | {
|
|
217
|
+
t: "term.started";
|
|
218
|
+
attachId: string;
|
|
219
|
+
reqId: string;
|
|
134
220
|
} | {
|
|
135
|
-
t: "term.
|
|
221
|
+
t: "term.chunk";
|
|
136
222
|
attachId: string;
|
|
223
|
+
reqId: string;
|
|
224
|
+
dataB64: string;
|
|
225
|
+
nextOffset: number;
|
|
226
|
+
done: boolean;
|
|
227
|
+
finalOffset?: number;
|
|
228
|
+
} | {
|
|
229
|
+
t: "term.reader.done";
|
|
230
|
+
attachId: string;
|
|
231
|
+
finalOffset: number;
|
|
232
|
+
reason: "terminal_exited" | "client_closed" | "backpressure" | "internal";
|
|
137
233
|
exitCode: number;
|
|
234
|
+
} | {
|
|
235
|
+
t: "term.ack";
|
|
236
|
+
attachId: string;
|
|
237
|
+
reqId: string;
|
|
238
|
+
operation: "input" | "resize";
|
|
239
|
+
} | {
|
|
240
|
+
t: "term.dimensions";
|
|
241
|
+
attachId: string;
|
|
242
|
+
cols: number;
|
|
243
|
+
rows: number;
|
|
138
244
|
} | {
|
|
139
245
|
t: "term.error";
|
|
140
246
|
attachId: string;
|
|
247
|
+
reqId?: string;
|
|
141
248
|
code: TerminalOpenErrorCode;
|
|
142
249
|
message: string;
|
|
143
250
|
}
|
|
@@ -147,6 +254,62 @@ export type FromChild = {
|
|
|
147
254
|
t: "mirror";
|
|
148
255
|
sessionId: string;
|
|
149
256
|
event: SessionEvent;
|
|
257
|
+
/** Correlates the event with the parent's post-persistence ACK. */
|
|
258
|
+
deliveryId: string;
|
|
259
|
+
/** Logical mirror generation. A clear/fork supersedes every pending
|
|
260
|
+
* delivery from an older generation. */
|
|
261
|
+
generation: number;
|
|
262
|
+
/** One-based attempt for the same logical ordinary delivery. Lets the
|
|
263
|
+
* parent settle process-local projections exactly when the permanent
|
|
264
|
+
* retry budget is exhausted. */
|
|
265
|
+
attempt: number;
|
|
266
|
+
}
|
|
267
|
+
/** The child stopped waiting for an ordinary delivery after an ambiguous
|
|
268
|
+
* outcome or an exhausted permanent budget. The parent keeps the exact
|
|
269
|
+
* delivery-to-projection association until the listener settles, so a late
|
|
270
|
+
* persistence failure can retire only the matching optimistic input. */
|
|
271
|
+
| {
|
|
272
|
+
t: "mirror.abandon";
|
|
273
|
+
deliveryId: string;
|
|
274
|
+
generation: number;
|
|
275
|
+
} | {
|
|
276
|
+
t: "mirror.image.begin";
|
|
277
|
+
transferId: string;
|
|
278
|
+
sessionId: string;
|
|
279
|
+
event: SessionEvent;
|
|
280
|
+
totalChars: number;
|
|
281
|
+
generation: number;
|
|
282
|
+
} | {
|
|
283
|
+
t: "mirror.image.chunk";
|
|
284
|
+
transferId: string;
|
|
285
|
+
seq: number;
|
|
286
|
+
data: string;
|
|
287
|
+
generation: number;
|
|
288
|
+
} | {
|
|
289
|
+
t: "mirror.image.commit";
|
|
290
|
+
transferId: string;
|
|
291
|
+
seq: number;
|
|
292
|
+
generation: number;
|
|
293
|
+
}
|
|
294
|
+
/** Child no longer waits for this transfer (ambiguous handled, permanent
|
|
295
|
+
* budget exhausted, or generation superseded); parent may release chunks. */
|
|
296
|
+
| {
|
|
297
|
+
t: "mirror.image.abandon";
|
|
298
|
+
transferId: string;
|
|
299
|
+
generation: number;
|
|
300
|
+
} | {
|
|
301
|
+
t: "terminal.lifecycle.ended";
|
|
302
|
+
localThreadId: string;
|
|
303
|
+
terminalId: string;
|
|
304
|
+
lifecycle: "required" | "auxiliary";
|
|
305
|
+
status: "idle" | "running" | "failed" | "unknown";
|
|
306
|
+
} | {
|
|
307
|
+
t: "terminal.reaped";
|
|
308
|
+
reqId: string;
|
|
309
|
+
localThreadId: string;
|
|
310
|
+
terminalId: string;
|
|
311
|
+
ok: boolean;
|
|
312
|
+
error?: WireError;
|
|
150
313
|
}
|
|
151
314
|
/** The session rotated to a fresh machine-session (claude `/clear`·`/fork`): the
|
|
152
315
|
* child re-pointed its mirror to `to` and asks the daemon to alias the runner
|
|
@@ -155,29 +318,43 @@ export type FromChild = {
|
|
|
155
318
|
t: "rotate";
|
|
156
319
|
from: string;
|
|
157
320
|
to: string;
|
|
321
|
+
rotationId: string;
|
|
322
|
+
generation: number;
|
|
158
323
|
kind: "clear" | "fork";
|
|
159
324
|
workspace: SessionWorkspaceSnapshot;
|
|
160
325
|
execution: ResolvedExecutionSnapshot;
|
|
161
326
|
parentSessionId?: string;
|
|
162
327
|
}
|
|
163
|
-
/**
|
|
164
|
-
*
|
|
328
|
+
/** Child-side terminal/runtime ownership has moved to the durable target.
|
|
329
|
+
* The parent must not expose the target routing alias before this frame. */
|
|
330
|
+
| {
|
|
331
|
+
t: "rotate.applied";
|
|
332
|
+
rotationId: string;
|
|
333
|
+
generation: number;
|
|
334
|
+
from: string;
|
|
335
|
+
to: string;
|
|
336
|
+
}
|
|
337
|
+
/** Result of a `live.ensure`: for Codex-lineage sessions `ok` means backend
|
|
338
|
+
* preload and pane launch completed. A resume observer and fresh-thread
|
|
339
|
+
* discovery may continue in the background. Other Providers retain their
|
|
340
|
+
* own readiness gate. */
|
|
165
341
|
| {
|
|
166
342
|
t: "live.ready";
|
|
167
343
|
reqId: string;
|
|
168
344
|
localThreadId: string;
|
|
169
345
|
ok: boolean;
|
|
170
|
-
error?:
|
|
346
|
+
error?: WireError;
|
|
171
347
|
}
|
|
172
|
-
/** Result of an `inject`: `outcome` distinguishes
|
|
173
|
-
*
|
|
174
|
-
*
|
|
348
|
+
/** Result of an `inject`: `result.outcome` distinguishes a new turn, an
|
|
349
|
+
* active-turn steer, and failures. RPC-backed success carries the canonical
|
|
350
|
+
* Response identity immediately; transcript-backed success may publish it on
|
|
351
|
+
* the mirrored user record shortly afterward. Echoes the request `reqId`. */
|
|
175
352
|
| {
|
|
176
353
|
t: "injected";
|
|
177
354
|
reqId: string;
|
|
178
355
|
localThreadId: string;
|
|
179
|
-
|
|
180
|
-
error?:
|
|
356
|
+
result: InjectResult;
|
|
357
|
+
error?: WireError;
|
|
181
358
|
}
|
|
182
359
|
/** Result of a `live.interrupt`: `ok` when an active turn was interrupted (false
|
|
183
360
|
* when there was none). Echoes the request `reqId`. */
|
|
@@ -186,13 +363,24 @@ export type FromChild = {
|
|
|
186
363
|
reqId: string;
|
|
187
364
|
localThreadId: string;
|
|
188
365
|
ok: boolean;
|
|
189
|
-
error?:
|
|
366
|
+
error?: WireError;
|
|
367
|
+
} | {
|
|
368
|
+
t: "collaboration.updated";
|
|
369
|
+
reqId: string;
|
|
370
|
+
localThreadId: string;
|
|
371
|
+
ok: boolean;
|
|
372
|
+
error?: WireError;
|
|
190
373
|
} | {
|
|
191
374
|
t: "interaction.resolved";
|
|
192
375
|
reqId: string;
|
|
193
376
|
localThreadId: string;
|
|
194
377
|
result: ResolveInteractionResult;
|
|
195
378
|
};
|
|
379
|
+
/** Internal runner wire bounds. Generated images are already subject to the
|
|
380
|
+
* Session image byte limit; chunks keep the NDJSON pipe and parser bounded and
|
|
381
|
+
* each chunk is acknowledged before the next is sent. */
|
|
382
|
+
export declare const RUNNER_IMAGE_CHUNK_CHARS: number;
|
|
383
|
+
export declare const RUNNER_IMAGE_MAX_RESULT_CHARS: number;
|
|
196
384
|
/** Encode a message as a single NDJSON line (newline included). */
|
|
197
385
|
export declare function encodeMessage(msg: ToChild | FromChild): string;
|
|
198
386
|
/** Parse one NDJSON line; returns `null` for blank lines or malformed JSON. */
|
package/dist/runner/protocol.js
CHANGED
|
@@ -7,6 +7,11 @@
|
|
|
7
7
|
* terminal attachment; the reply channels mirror each request's `reqId`.
|
|
8
8
|
*/
|
|
9
9
|
import { AgentRuntimeError, } from "@rynx-ai/core";
|
|
10
|
+
/** Internal runner wire bounds. Generated images are already subject to the
|
|
11
|
+
* Session image byte limit; chunks keep the NDJSON pipe and parser bounded and
|
|
12
|
+
* each chunk is acknowledged before the next is sent. */
|
|
13
|
+
export const RUNNER_IMAGE_CHUNK_CHARS = 32 * 1024;
|
|
14
|
+
export const RUNNER_IMAGE_MAX_RESULT_CHARS = 8 * 1024 * 1024;
|
|
10
15
|
/** Encode a message as a single NDJSON line (newline included). */
|
|
11
16
|
export function encodeMessage(msg) {
|
|
12
17
|
return `${JSON.stringify(msg)}\n`;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AgentRuntimeId } from "@rynx-ai/core";
|
|
2
|
+
/** Current live providers are native CLI sessions. Keep this explicit so a
|
|
3
|
+
* future non-native provider does not silently inherit their startup budget. */
|
|
4
|
+
export declare function isManagedNativeProvider(provider: AgentRuntimeId | undefined): provider is AgentRuntimeId;
|
|
5
|
+
/** Codex-lineage providers own app-server, thread-discovery, and injection
|
|
6
|
+
* phase errors. Claude instead retains its parent-owned SessionStart gate. */
|
|
7
|
+
export declare function isCodexLineageProvider(provider: AgentRuntimeId | undefined): provider is Exclude<AgentRuntimeId, "claude">;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Current live providers are native CLI sessions. Keep this explicit so a
|
|
2
|
+
* future non-native provider does not silently inherit their startup budget. */
|
|
3
|
+
export function isManagedNativeProvider(provider) {
|
|
4
|
+
return provider === "codex" || provider === "traex" || provider === "claude";
|
|
5
|
+
}
|
|
6
|
+
/** Codex-lineage providers own app-server, thread-discovery, and injection
|
|
7
|
+
* phase errors. Claude instead retains its parent-owned SessionStart gate. */
|
|
8
|
+
export function isCodexLineageProvider(provider) {
|
|
9
|
+
return provider === "codex" || provider === "traex";
|
|
10
|
+
}
|
|
@@ -3,9 +3,13 @@ import { type FromChild, type ToChild } from "./protocol.js";
|
|
|
3
3
|
export interface RunnerTransport<TSend, TRecv> {
|
|
4
4
|
/** Send one message. Best-effort: a dead peer is surfaced via {@link onClose}. */
|
|
5
5
|
send(msg: TSend): void;
|
|
6
|
+
/** Send one bounded message and resolve only after the writable accepts and
|
|
7
|
+
* drains it. Terminal pull responses use this to keep stdio end-to-end
|
|
8
|
+
* demand-driven. */
|
|
9
|
+
sendAndDrain(msg: TSend): Promise<void>;
|
|
6
10
|
/** Register the single message handler. */
|
|
7
11
|
onMessage(cb: (msg: TRecv) => void): void;
|
|
8
|
-
/** Register a close/error
|
|
12
|
+
/** Register a close/error observer (peer stream ended). */
|
|
9
13
|
onClose(cb: (error?: Error) => void): void;
|
|
10
14
|
/** Stop reading and release the readline interface. */
|
|
11
15
|
close(): void;
|
|
@@ -14,6 +18,15 @@ export interface RunnerTransport<TSend, TRecv> {
|
|
|
14
18
|
export type ParentTransport = RunnerTransport<ToChild, FromChild>;
|
|
15
19
|
/** Child-side transport: sends {@link FromChild}, receives {@link ToChild}. */
|
|
16
20
|
export type ChildTransport = RunnerTransport<FromChild, ToChild>;
|
|
21
|
+
/** Structured write failure used by delivery code to distinguish a frame that
|
|
22
|
+
* definitely never entered the pipe from one whose post-write result is
|
|
23
|
+
* uncertain. */
|
|
24
|
+
export declare class RunnerTransportWriteError extends Error {
|
|
25
|
+
readonly delivery: "not-sent" | "ambiguous";
|
|
26
|
+
constructor(message: string, delivery: "not-sent" | "ambiguous", options?: {
|
|
27
|
+
cause?: unknown;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
17
30
|
/**
|
|
18
31
|
* NDJSON-over-streams transport. `input` is line-read for inbound messages;
|
|
19
32
|
* `output` receives one JSON line per {@link send}. Used on both ends:
|
|
@@ -25,12 +38,15 @@ export declare class StdioRunnerTransport<TSend, TRecv> implements RunnerTranspo
|
|
|
25
38
|
private readonly output;
|
|
26
39
|
private readonly rl;
|
|
27
40
|
private messageHandler;
|
|
28
|
-
private
|
|
41
|
+
private readonly closeHandlers;
|
|
29
42
|
private closed;
|
|
43
|
+
private writeTail;
|
|
30
44
|
constructor(input: Readable, output: Writable);
|
|
31
45
|
send(msg: TSend): void;
|
|
46
|
+
sendAndDrain(msg: TSend): Promise<void>;
|
|
32
47
|
onMessage(cb: (msg: TRecv) => void): void;
|
|
33
48
|
onClose(cb: (error?: Error) => void): void;
|
|
34
49
|
close(): void;
|
|
35
50
|
private handleClose;
|
|
51
|
+
private writeMessage;
|
|
36
52
|
}
|
package/dist/runner/transport.js
CHANGED
|
@@ -11,6 +11,17 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import readline from "node:readline";
|
|
13
13
|
import { decodeMessage, encodeMessage } from "./protocol.js";
|
|
14
|
+
/** Structured write failure used by delivery code to distinguish a frame that
|
|
15
|
+
* definitely never entered the pipe from one whose post-write result is
|
|
16
|
+
* uncertain. */
|
|
17
|
+
export class RunnerTransportWriteError extends Error {
|
|
18
|
+
delivery;
|
|
19
|
+
constructor(message, delivery, options) {
|
|
20
|
+
super(message, options);
|
|
21
|
+
this.delivery = delivery;
|
|
22
|
+
this.name = "RunnerTransportWriteError";
|
|
23
|
+
}
|
|
24
|
+
}
|
|
14
25
|
/**
|
|
15
26
|
* NDJSON-over-streams transport. `input` is line-read for inbound messages;
|
|
16
27
|
* `output` receives one JSON line per {@link send}. Used on both ends:
|
|
@@ -22,8 +33,9 @@ export class StdioRunnerTransport {
|
|
|
22
33
|
output;
|
|
23
34
|
rl;
|
|
24
35
|
messageHandler = null;
|
|
25
|
-
|
|
36
|
+
closeHandlers = new Set();
|
|
26
37
|
closed = false;
|
|
38
|
+
writeTail = Promise.resolve();
|
|
27
39
|
constructor(input, output) {
|
|
28
40
|
this.input = input;
|
|
29
41
|
this.output = output;
|
|
@@ -52,11 +64,16 @@ export class StdioRunnerTransport {
|
|
|
52
64
|
}
|
|
53
65
|
this.output.write(encodeMessage(msg));
|
|
54
66
|
}
|
|
67
|
+
sendAndDrain(msg) {
|
|
68
|
+
const operation = this.writeTail.then(() => this.writeMessage(msg));
|
|
69
|
+
this.writeTail = operation.catch(() => undefined);
|
|
70
|
+
return operation;
|
|
71
|
+
}
|
|
55
72
|
onMessage(cb) {
|
|
56
73
|
this.messageHandler = cb;
|
|
57
74
|
}
|
|
58
75
|
onClose(cb) {
|
|
59
|
-
this.
|
|
76
|
+
this.closeHandlers.add(cb);
|
|
60
77
|
}
|
|
61
78
|
close() {
|
|
62
79
|
this.closed = true;
|
|
@@ -67,6 +84,68 @@ export class StdioRunnerTransport {
|
|
|
67
84
|
return;
|
|
68
85
|
}
|
|
69
86
|
this.closed = true;
|
|
70
|
-
this.
|
|
87
|
+
for (const handler of this.closeHandlers)
|
|
88
|
+
handler(error);
|
|
89
|
+
}
|
|
90
|
+
writeMessage(msg) {
|
|
91
|
+
if (this.closed) {
|
|
92
|
+
return Promise.reject(new RunnerTransportWriteError("runner transport is closed before write", "not-sent"));
|
|
93
|
+
}
|
|
94
|
+
let encoded;
|
|
95
|
+
try {
|
|
96
|
+
encoded = encodeMessage(msg);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
return Promise.reject(new RunnerTransportWriteError("runner transport frame could not be encoded", "not-sent", { cause: error }));
|
|
100
|
+
}
|
|
101
|
+
return new Promise((resolve, reject) => {
|
|
102
|
+
let callbackDone = false;
|
|
103
|
+
let drainDone = false;
|
|
104
|
+
let settled = false;
|
|
105
|
+
const cleanup = () => {
|
|
106
|
+
this.output.off("drain", onDrain);
|
|
107
|
+
this.output.off("error", onError);
|
|
108
|
+
};
|
|
109
|
+
const finish = () => {
|
|
110
|
+
if (settled || !callbackDone || !drainDone)
|
|
111
|
+
return;
|
|
112
|
+
settled = true;
|
|
113
|
+
cleanup();
|
|
114
|
+
resolve();
|
|
115
|
+
};
|
|
116
|
+
const onDrain = () => {
|
|
117
|
+
drainDone = true;
|
|
118
|
+
finish();
|
|
119
|
+
};
|
|
120
|
+
const onError = (error) => {
|
|
121
|
+
if (settled)
|
|
122
|
+
return;
|
|
123
|
+
settled = true;
|
|
124
|
+
cleanup();
|
|
125
|
+
reject(new RunnerTransportWriteError("runner transport write result is uncertain", "ambiguous", { cause: error }));
|
|
126
|
+
};
|
|
127
|
+
this.output.once("error", onError);
|
|
128
|
+
let accepted;
|
|
129
|
+
try {
|
|
130
|
+
accepted = this.output.write(encoded, (error) => {
|
|
131
|
+
if (error) {
|
|
132
|
+
onError(error);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
callbackDone = true;
|
|
136
|
+
finish();
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
settled = true;
|
|
141
|
+
cleanup();
|
|
142
|
+
reject(new RunnerTransportWriteError("runner transport rejected the frame before write", "not-sent", { cause: error }));
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
drainDone = accepted;
|
|
146
|
+
if (!accepted)
|
|
147
|
+
this.output.once("drain", onDrain);
|
|
148
|
+
finish();
|
|
149
|
+
});
|
|
71
150
|
}
|
|
72
151
|
}
|
package/dist/runner-main.js
CHANGED
|
@@ -20,6 +20,8 @@ import { loadConfig } from "@rynx-ai/core";
|
|
|
20
20
|
import { FileCodexSessionStore, LocalAgentHost, resolveCodexSessionStorePath, } from "./host.js";
|
|
21
21
|
import { RunnerSession } from "./runner/child.js";
|
|
22
22
|
import { StdioRunnerTransport } from "./runner/transport.js";
|
|
23
|
+
import { reapOrphanedTerminals } from "./terminal/tmux.js";
|
|
24
|
+
import { reconcileRuntimeProcesses } from "./codex-app-server/process-registry.js";
|
|
23
25
|
// stdout is the protocol channel — keep all logging on stderr.
|
|
24
26
|
console.log = console.error.bind(console);
|
|
25
27
|
console.info = console.error.bind(console);
|
|
@@ -34,6 +36,8 @@ for (const stream of [process.stdout, process.stderr]) {
|
|
|
34
36
|
});
|
|
35
37
|
}
|
|
36
38
|
async function main() {
|
|
39
|
+
reapOrphanedTerminals();
|
|
40
|
+
reconcileRuntimeProcesses();
|
|
37
41
|
const config = loadConfig();
|
|
38
42
|
const sessionStore = new FileCodexSessionStore(resolveCodexSessionStorePath(config));
|
|
39
43
|
const sessionId = process.env.RYNX_RUNNER_SESSION;
|
|
@@ -51,8 +55,7 @@ async function main() {
|
|
|
51
55
|
const transport = new StdioRunnerTransport(process.stdin, process.stdout);
|
|
52
56
|
let runner;
|
|
53
57
|
transport.onClose(() => {
|
|
54
|
-
runner?.shutdown();
|
|
55
|
-
process.exit(0);
|
|
58
|
+
void runner?.shutdown().finally(() => process.exit(0));
|
|
56
59
|
});
|
|
57
60
|
runner = new RunnerSession({
|
|
58
61
|
transport,
|
|
@@ -64,7 +67,9 @@ async function main() {
|
|
|
64
67
|
});
|
|
65
68
|
// A parent SIGTERM (idle reap / shutdown) uses the same ordered cleanup path
|
|
66
69
|
// as the protocol shutdown before ending the process.
|
|
67
|
-
process.on("SIGTERM", () =>
|
|
70
|
+
process.on("SIGTERM", () => {
|
|
71
|
+
void runner?.shutdown();
|
|
72
|
+
});
|
|
68
73
|
}
|
|
69
74
|
void main().catch((error) => {
|
|
70
75
|
console.error(error);
|
|
@@ -18,6 +18,8 @@ export interface ClaudeTuiArgs {
|
|
|
18
18
|
settingSources?: string;
|
|
19
19
|
/** Launch model (`--model`); omit to use claude's default. */
|
|
20
20
|
model?: string;
|
|
21
|
+
/** Native Claude Code effort (`--effort`); omit to use its default. */
|
|
22
|
+
reasoningEffort?: string;
|
|
21
23
|
/** Agent instructions appended to Claude Code's native system prompt. */
|
|
22
24
|
appendSystemPrompt?: string;
|
|
23
25
|
/** Resume a specific prior claude session (`--resume <id>`). */
|
|
@@ -36,4 +38,4 @@ export interface ClaudeTuiArgs {
|
|
|
36
38
|
* Build the `claude` argv for an interactive, co-drivable TUI:
|
|
37
39
|
* `[..extra] [--resume <id>] [--model <m>] [--append-system-prompt <text>] --settings <json>`.
|
|
38
40
|
*/
|
|
39
|
-
export declare function buildClaudeTuiArgs({ settingsJson, settingSources, model, appendSystemPrompt, resume, forkSession, sessionId, additionalDirs, extraArgs, }: ClaudeTuiArgs): string[];
|
|
41
|
+
export declare function buildClaudeTuiArgs({ settingsJson, settingSources, model, reasoningEffort, appendSystemPrompt, resume, forkSession, sessionId, additionalDirs, extraArgs, }: ClaudeTuiArgs): string[];
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Build the `claude` argv for an interactive, co-drivable TUI:
|
|
3
3
|
* `[..extra] [--resume <id>] [--model <m>] [--append-system-prompt <text>] --settings <json>`.
|
|
4
4
|
*/
|
|
5
|
-
export function buildClaudeTuiArgs({ settingsJson, settingSources, model, appendSystemPrompt, resume, forkSession = false, sessionId, additionalDirs = [], extraArgs = [], }) {
|
|
5
|
+
export function buildClaudeTuiArgs({ settingsJson, settingSources, model, reasoningEffort, appendSystemPrompt, resume, forkSession = false, sessionId, additionalDirs = [], extraArgs = [], }) {
|
|
6
6
|
const args = [...extraArgs];
|
|
7
7
|
if (additionalDirs.length > 0)
|
|
8
8
|
args.push("--add-dir", ...additionalDirs);
|
|
@@ -16,6 +16,8 @@ export function buildClaudeTuiArgs({ settingsJson, settingSources, model, append
|
|
|
16
16
|
args.push("--session-id", sessionId);
|
|
17
17
|
if (model)
|
|
18
18
|
args.push("--model", model);
|
|
19
|
+
if (reasoningEffort)
|
|
20
|
+
args.push("--effort", reasoningEffort);
|
|
19
21
|
if (appendSystemPrompt)
|
|
20
22
|
args.push("--append-system-prompt", appendSystemPrompt);
|
|
21
23
|
args.push("--settings", settingsJson);
|
|
@@ -49,6 +49,10 @@ export interface LaunchCodexTuiOptions extends CodexRemoteArgs {
|
|
|
49
49
|
env?: Record<string, string>;
|
|
50
50
|
cols?: number;
|
|
51
51
|
rows?: number;
|
|
52
|
+
scrollback?: number;
|
|
53
|
+
tmuxAllowPassthrough?: boolean;
|
|
54
|
+
tmuxStartOnAttach?: boolean;
|
|
55
|
+
keepAliveAfterExit?: boolean;
|
|
52
56
|
}
|
|
53
57
|
/**
|
|
54
58
|
* Create (idempotently) the codex TUI terminal in the registry, running the real
|
|
@@ -25,11 +25,16 @@ export function buildCodexRemoteArgs({ remoteUrl, threadId, configOverrides = []
|
|
|
25
25
|
*/
|
|
26
26
|
export function launchCodexTui(opts) {
|
|
27
27
|
opts.registry.getOrCreate(opts.terminalId, {
|
|
28
|
+
lifecycle: "auxiliary",
|
|
28
29
|
cwd: opts.cwd,
|
|
29
30
|
command: opts.codexBin,
|
|
30
31
|
args: buildCodexRemoteArgs(opts),
|
|
31
32
|
env: opts.env,
|
|
32
33
|
cols: opts.cols,
|
|
33
34
|
rows: opts.rows,
|
|
35
|
+
scrollback: opts.scrollback ?? 100_000,
|
|
36
|
+
tmuxAllowPassthrough: opts.tmuxAllowPassthrough ?? true,
|
|
37
|
+
tmuxStartOnAttach: opts.tmuxStartOnAttach ?? false,
|
|
38
|
+
keepAliveAfterExit: opts.keepAliveAfterExit ?? false,
|
|
34
39
|
});
|
|
35
40
|
}
|