@rynx-ai/runtime 0.1.11-beta.4 → 0.1.11-beta.40

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 (65) hide show
  1. package/dist/claude/executor.d.ts +19 -5
  2. package/dist/claude/executor.js +56 -12
  3. package/dist/claude/models.d.ts +0 -5
  4. package/dist/claude/models.js +1 -7
  5. package/dist/claude/native-bridge.d.ts +103 -1
  6. package/dist/claude/native-bridge.js +445 -30
  7. package/dist/claude/native-hook-main.js +81 -1
  8. package/dist/claude/native-hooks.js +7 -0
  9. package/dist/claude/native-integration.d.ts +178 -26
  10. package/dist/claude/native-integration.js +1528 -170
  11. package/dist/claude/session-status.d.ts +39 -0
  12. package/dist/claude/session-status.js +163 -0
  13. package/dist/claude/transcript-clone.d.ts +18 -0
  14. package/dist/claude/transcript-clone.js +497 -0
  15. package/dist/claude/transcript.d.ts +27 -4
  16. package/dist/claude/transcript.js +158 -47
  17. package/dist/codex-app-server/client.d.ts +10 -6
  18. package/dist/codex-app-server/client.js +67 -15
  19. package/dist/codex-app-server/forwarder.d.ts +92 -3
  20. package/dist/codex-app-server/forwarder.js +532 -57
  21. package/dist/codex-app-server/mapping.d.ts +3 -6
  22. package/dist/codex-app-server/mapping.js +206 -36
  23. package/dist/codex-app-server/mcp-startup.d.ts +13 -0
  24. package/dist/codex-app-server/mcp-startup.js +63 -0
  25. package/dist/codex-app-server/process-registry.d.ts +36 -0
  26. package/dist/codex-app-server/process-registry.js +320 -0
  27. package/dist/codex-app-server/protocol.d.ts +64 -7
  28. package/dist/codex-app-server/ws-channel.d.ts +7 -0
  29. package/dist/codex-app-server/ws-channel.js +104 -28
  30. package/dist/codex-home.d.ts +35 -3
  31. package/dist/codex-home.js +323 -18
  32. package/dist/codex-session-store.d.ts +23 -0
  33. package/dist/codex-session-store.js +21 -0
  34. package/dist/host.d.ts +103 -46
  35. package/dist/host.js +1988 -634
  36. package/dist/index.d.ts +3 -3
  37. package/dist/index.js +1 -1
  38. package/dist/input-resources.d.ts +4 -0
  39. package/dist/input-resources.js +21 -5
  40. package/dist/models-catalog.d.ts +2 -1
  41. package/dist/models-catalog.js +94 -6
  42. package/dist/runner/child.d.ts +97 -28
  43. package/dist/runner/child.js +1486 -100
  44. package/dist/runner/manager.d.ts +110 -29
  45. package/dist/runner/manager.js +1481 -246
  46. package/dist/runner/protocol.d.ts +212 -24
  47. package/dist/runner/protocol.js +5 -0
  48. package/dist/runner/startup-policy.d.ts +7 -0
  49. package/dist/runner/startup-policy.js +10 -0
  50. package/dist/runner/transport.d.ts +18 -2
  51. package/dist/runner/transport.js +82 -3
  52. package/dist/runner-main.js +8 -3
  53. package/dist/terminal/claude-tui.d.ts +3 -1
  54. package/dist/terminal/claude-tui.js +3 -1
  55. package/dist/terminal/codex-tui.d.ts +4 -0
  56. package/dist/terminal/codex-tui.js +5 -0
  57. package/dist/terminal/control-parser.d.ts +39 -0
  58. package/dist/terminal/control-parser.js +172 -0
  59. package/dist/terminal/registry.d.ts +18 -15
  60. package/dist/terminal/registry.js +44 -23
  61. package/dist/terminal/spool.d.ts +47 -0
  62. package/dist/terminal/spool.js +231 -0
  63. package/dist/terminal/tmux.d.ts +126 -74
  64. package/dist/terminal/tmux.js +807 -211
  65. package/package.json +4 -4
@@ -0,0 +1,320 @@
1
+ import { mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync, } from "node:fs";
2
+ import { basename, dirname, join } from "node:path";
3
+ import { execFileSync } from "node:child_process";
4
+ import { randomUUID } from "node:crypto";
5
+ import { rynxRuntimeDir } from "@rynx-ai/core";
6
+ const REGISTRY_FILE = "process-registry.json";
7
+ const TAG_PREFIX = "rynx_crash_teardown_tag=";
8
+ const STATE_PREFIX = "rynx_crash_teardown_state_dir=";
9
+ export function runtimeProcessRegistryPath() {
10
+ return join(rynxRuntimeDir(), REGISTRY_FILE);
11
+ }
12
+ export function runtimeProcessTagArg(sessionTag) {
13
+ if (!sessionTag)
14
+ throw new Error("sessionTag must be non-empty");
15
+ return `${TAG_PREFIX}${sessionTag}`;
16
+ }
17
+ export function runtimeProcessArgv0(cliPath, sessionTag) {
18
+ return `${basename(cliPath)} ${runtimeProcessTagArg(sessionTag)}`;
19
+ }
20
+ export function withRuntimeProcessStateArg(baseArgs, stateDir) {
21
+ const args = [...baseArgs];
22
+ const marker = ["-c", `${STATE_PREFIX}${JSON.stringify(stateDir)}`];
23
+ const subcommand = args.indexOf("app-server");
24
+ args.splice(subcommand >= 0 ? subcommand : 0, 0, ...marker);
25
+ return args;
26
+ }
27
+ export function registerRuntimeProcess(entry, registryPath = runtimeProcessRegistryPath()) {
28
+ if (!validEntry(entry))
29
+ return;
30
+ mutateRegistry(registryPath, (entries) => [
31
+ ...entries.filter((candidate) => candidate.sessionTag !== entry.sessionTag),
32
+ entry,
33
+ ]);
34
+ }
35
+ export function unregisterRuntimeProcess(sessionTag, registryPath = runtimeProcessRegistryPath()) {
36
+ if (!sessionTag)
37
+ return;
38
+ mutateRegistry(registryPath, (entries) => entries.filter((entry) => entry.sessionTag !== sessionTag));
39
+ }
40
+ export function reconcileRuntimeProcesses(opts = {}) {
41
+ return reconcileEntries(undefined, opts);
42
+ }
43
+ export function reapRuntimeProcessesForStateDir(stateDir, opts = {}) {
44
+ if (process.platform === "win32" && !opts.processListing)
45
+ return 0;
46
+ const listing = opts.processListing?.() ?? listProcesses();
47
+ if (!listing)
48
+ return 0;
49
+ const currentPgid = opts.currentPgid?.() ?? processGroupId(process.pid);
50
+ const signalGroup = opts.signalGroup ?? signalProcessGroup;
51
+ const childAlive = opts.childAlive ?? isProcessAlive;
52
+ const graceMs = opts.graceMs ?? 1_500;
53
+ const victims = new Map();
54
+ for (const line of listing.split("\n")) {
55
+ const match = /^\s*(\d+)\s+(\d+)\s+([\s\S]+)$/.exec(line);
56
+ if (!match)
57
+ continue;
58
+ const pid = Number.parseInt(match[1], 10);
59
+ const pgid = Number.parseInt(match[2], 10);
60
+ const command = match[3];
61
+ if (!command.includes(stateDir) || !command.includes("app-server"))
62
+ continue;
63
+ if (pid === process.pid || pgid <= 0 || pgid === currentPgid)
64
+ continue;
65
+ victims.set(pid, pgid);
66
+ }
67
+ if (victims.size === 0)
68
+ return 0;
69
+ for (const pgid of new Set(victims.values()))
70
+ signalGroup(pgid, "SIGTERM");
71
+ const deadline = Date.now() + graceMs;
72
+ while (Date.now() < deadline && [...victims.keys()].some(childAlive)) {
73
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 50);
74
+ }
75
+ for (const [pid, pgid] of victims) {
76
+ if (childAlive(pid))
77
+ signalGroup(pgid, "SIGKILL");
78
+ }
79
+ return victims.size;
80
+ }
81
+ function reconcileEntries(stateDir, opts) {
82
+ const registryPath = opts.registryPath ?? runtimeProcessRegistryPath();
83
+ const ownerAlive = opts.ownerAlive ?? isProcessAlive;
84
+ const ownerIdentity = opts.ownerIdentity ?? runtimeProcessOwnerIdentity;
85
+ const childAlive = opts.childAlive ?? isProcessAlive;
86
+ const commandLine = opts.commandLine ?? processCommandLine;
87
+ const terminateGroup = opts.terminateGroup ?? terminateProcessGroup;
88
+ let reaped = 0;
89
+ mutateRegistry(registryPath, (entries) => {
90
+ const survivors = [];
91
+ for (const entry of entries) {
92
+ if (stateDir !== undefined && entry.stateDir !== stateDir) {
93
+ survivors.push(entry);
94
+ continue;
95
+ }
96
+ if (ownerAlive(entry.ownerPid)) {
97
+ const currentOwnerIdentity = ownerIdentity(entry.ownerPid);
98
+ // Old registry entries have no start identity. Keep the conservative
99
+ // PID-only behavior for those entries; every newly registered process
100
+ // is protected against PID reuse.
101
+ if (!entry.ownerIdentity ||
102
+ !currentOwnerIdentity ||
103
+ currentOwnerIdentity === entry.ownerIdentity) {
104
+ survivors.push(entry);
105
+ continue;
106
+ }
107
+ }
108
+ if (!childAlive(entry.pid))
109
+ continue;
110
+ if (!commandLine(entry.pid).includes(runtimeProcessTagArg(entry.sessionTag)))
111
+ continue;
112
+ if (!terminateGroup(entry.pgid)) {
113
+ survivors.push(entry);
114
+ continue;
115
+ }
116
+ reaped += 1;
117
+ }
118
+ return survivors;
119
+ });
120
+ return reaped;
121
+ }
122
+ function validEntry(entry) {
123
+ return Number.isSafeInteger(entry.pid) && entry.pid > 0 &&
124
+ Number.isSafeInteger(entry.pgid) && entry.pgid > 0 &&
125
+ Number.isSafeInteger(entry.ownerPid) && entry.ownerPid > 0 &&
126
+ (entry.ownerIdentity === undefined ||
127
+ (typeof entry.ownerIdentity === "string" && entry.ownerIdentity.length > 0)) &&
128
+ Boolean(entry.sessionTag) && Boolean(entry.stateDir);
129
+ }
130
+ function readRegistry(path) {
131
+ let value;
132
+ try {
133
+ value = JSON.parse(readFileSync(path, "utf8"));
134
+ }
135
+ catch {
136
+ return [];
137
+ }
138
+ if (!Array.isArray(value))
139
+ return [];
140
+ return value.filter((entry) => typeof entry === "object" && entry !== null && validEntry(entry));
141
+ }
142
+ function mutateRegistry(path, mutation) {
143
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
144
+ const lockDir = `${path}.lock`;
145
+ const deadline = Date.now() + 2_000;
146
+ while (true) {
147
+ try {
148
+ mkdirSync(lockDir, { mode: 0o700 });
149
+ writeFileSync(join(lockDir, "owner.pid"), JSON.stringify({
150
+ pid: process.pid,
151
+ identity: runtimeProcessOwnerIdentity(process.pid),
152
+ }), { mode: 0o600 });
153
+ break;
154
+ }
155
+ catch (error) {
156
+ if (error.code !== "EEXIST")
157
+ return;
158
+ let ownerPid = 0;
159
+ let ownerIdentity = "";
160
+ try {
161
+ const rawOwner = readFileSync(join(lockDir, "owner.pid"), "utf8");
162
+ try {
163
+ const parsed = JSON.parse(rawOwner);
164
+ ownerPid = typeof parsed.pid === "number" ? parsed.pid : 0;
165
+ ownerIdentity = typeof parsed.identity === "string" ? parsed.identity : "";
166
+ }
167
+ catch {
168
+ // Backward-compatible recovery for a lock written by the earlier
169
+ // PID-only implementation.
170
+ ownerPid = Number.parseInt(rawOwner, 10);
171
+ }
172
+ }
173
+ catch {
174
+ // A creator may be between mkdir and marker write; the bounded retry handles it.
175
+ }
176
+ const currentOwnerIdentity = ownerPid > 0
177
+ ? runtimeProcessOwnerIdentity(ownerPid)
178
+ : "";
179
+ const staleKnownOwner = ownerPid > 0 && (!isProcessAlive(ownerPid) ||
180
+ Boolean(ownerIdentity && currentOwnerIdentity && ownerIdentity !== currentOwnerIdentity));
181
+ let staleUnownedLock = false;
182
+ if (ownerPid <= 0) {
183
+ try {
184
+ staleUnownedLock = Date.now() - statSync(lockDir).mtimeMs >= 1_000;
185
+ }
186
+ catch {
187
+ staleUnownedLock = true;
188
+ }
189
+ }
190
+ if (staleKnownOwner || staleUnownedLock) {
191
+ rmSync(lockDir, { recursive: true, force: true });
192
+ continue;
193
+ }
194
+ if (Date.now() >= deadline)
195
+ return;
196
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 10);
197
+ }
198
+ }
199
+ try {
200
+ const entries = mutation(readRegistry(path));
201
+ const temp = `${path}.${process.pid}.${randomUUID()}.tmp`;
202
+ writeFileSync(temp, `${JSON.stringify(entries)}\n`, { mode: 0o600 });
203
+ renameSync(temp, path);
204
+ }
205
+ finally {
206
+ rmSync(lockDir, { recursive: true, force: true });
207
+ }
208
+ }
209
+ function isProcessAlive(pid) {
210
+ try {
211
+ process.kill(pid, 0);
212
+ return true;
213
+ }
214
+ catch (error) {
215
+ return error.code === "EPERM";
216
+ }
217
+ }
218
+ /** Return an OS process-start identity used to distinguish PID reuse. */
219
+ export function runtimeProcessOwnerIdentity(pid) {
220
+ if (!Number.isSafeInteger(pid) || pid <= 0)
221
+ return "";
222
+ if (process.platform === "linux") {
223
+ try {
224
+ const stat = readFileSync(`/proc/${pid}/stat`, "utf8");
225
+ const commandEnd = stat.lastIndexOf(")");
226
+ if (commandEnd >= 0) {
227
+ // Fields after ')' begin at proc field 3; starttime is field 22.
228
+ const startTicks = stat.slice(commandEnd + 2).trim().split(/\s+/)[19];
229
+ if (startTicks)
230
+ return `linux:${startTicks}`;
231
+ }
232
+ }
233
+ catch {
234
+ return "";
235
+ }
236
+ }
237
+ try {
238
+ const startedAt = execFileSync("ps", ["-p", String(pid), "-ww", "-o", "lstart="], {
239
+ encoding: "utf8",
240
+ timeout: 2_000,
241
+ stdio: ["ignore", "pipe", "ignore"],
242
+ }).trim();
243
+ return startedAt ? `${process.platform}:${startedAt}` : "";
244
+ }
245
+ catch {
246
+ return "";
247
+ }
248
+ }
249
+ function processCommandLine(pid) {
250
+ if (process.platform === "linux") {
251
+ try {
252
+ return readFileSync(`/proc/${pid}/cmdline`)
253
+ .toString("utf8")
254
+ .replaceAll("\0", " ");
255
+ }
256
+ catch {
257
+ // Fall through to ps for macOS and restricted procfs environments.
258
+ }
259
+ }
260
+ try {
261
+ return execFileSync("ps", ["-p", String(pid), "-ww", "-o", "command="], {
262
+ encoding: "utf8",
263
+ timeout: 2_000,
264
+ stdio: ["ignore", "pipe", "ignore"],
265
+ }).trim();
266
+ }
267
+ catch {
268
+ return "";
269
+ }
270
+ }
271
+ function listProcesses() {
272
+ try {
273
+ return execFileSync("ps", ["-axww", "-o", "pid=,pgid=,command="], {
274
+ encoding: "utf8",
275
+ timeout: 5_000,
276
+ stdio: ["ignore", "pipe", "ignore"],
277
+ });
278
+ }
279
+ catch {
280
+ return "";
281
+ }
282
+ }
283
+ function processGroupId(pid) {
284
+ try {
285
+ const value = execFileSync("ps", ["-p", String(pid), "-o", "pgid="], {
286
+ encoding: "utf8",
287
+ timeout: 2_000,
288
+ stdio: ["ignore", "pipe", "ignore"],
289
+ });
290
+ return Number.parseInt(value.trim(), 10) || -1;
291
+ }
292
+ catch {
293
+ return -1;
294
+ }
295
+ }
296
+ function signalProcessGroup(pgid, signal) {
297
+ if (process.platform === "win32")
298
+ return false;
299
+ try {
300
+ process.kill(-pgid, signal);
301
+ return true;
302
+ }
303
+ catch (error) {
304
+ return error.code === "ESRCH";
305
+ }
306
+ }
307
+ function terminateProcessGroup(pgid) {
308
+ if (process.platform === "win32")
309
+ return false;
310
+ try {
311
+ process.kill(-pgid, "SIGTERM");
312
+ return true;
313
+ }
314
+ catch (error) {
315
+ return error.code === "ESRCH";
316
+ }
317
+ }
318
+ export function newRuntimeProcessTag() {
319
+ return `native-${randomUUID().replaceAll("-", "")}`;
320
+ }
@@ -56,6 +56,21 @@ export interface GetAuthStatusResponse {
56
56
  authToken: string | null;
57
57
  requiresOpenaiAuth: boolean;
58
58
  }
59
+ /** Read the Provider's effective configuration through the app-server rather
60
+ * than parsing a runtime-specific config file (Traex has used both YAML and
61
+ * TOML across releases). `cwd` includes project-scoped configuration layers. */
62
+ export interface ConfigReadParams {
63
+ includeLayers: boolean;
64
+ cwd?: string | null;
65
+ }
66
+ export interface ConfigReadResponse {
67
+ config: {
68
+ model: string | null;
69
+ model_reasoning_effort: ReasoningEffort | null;
70
+ [key: string]: unknown;
71
+ };
72
+ [key: string]: unknown;
73
+ }
59
74
  export type AskForApproval = "untrusted" | "on-failure" | "on-request" | "never";
60
75
  export type SandboxMode = "read-only" | "workspace-write" | "danger-full-access";
61
76
  export type SandboxPolicy = {
@@ -87,6 +102,16 @@ export interface PermissionProfileModificationParams {
87
102
  export type PermissionSelection = string | PermissionProfileSelectionParams;
88
103
  /** Open since Codex App Server 0.144; values are advertised by `model/list`. */
89
104
  export type ReasoningEffort = string;
105
+ export type CollaborationModeKind = "plan" | "default";
106
+ /** Full Codex-lineage mode snapshot required by the App Server wire protocol. */
107
+ export interface CollaborationMode {
108
+ mode: CollaborationModeKind;
109
+ settings: {
110
+ model: string;
111
+ reasoning_effort: ReasoningEffort | null;
112
+ developer_instructions: string | null;
113
+ };
114
+ }
90
115
  export interface ThreadStartParams {
91
116
  model?: string | null;
92
117
  modelProvider?: string | null;
@@ -102,14 +127,18 @@ export interface ThreadStartParams {
102
127
  baseInstructions?: string | null;
103
128
  developerInstructions?: string | null;
104
129
  ephemeral?: boolean | null;
130
+ /** Native UI intent for a context-clearing fresh thread. */
131
+ sessionStartSource?: "clear" | string;
105
132
  }
106
133
  export interface ThreadResumeParams extends ThreadStartParams {
107
134
  threadId: string;
108
- /** When true, the resume response omits the thread's `turns` backlog (used to
109
- * SUBSCRIBE without re-replaying history). When false/absent, the response
110
- * carries `thread.turns[].items[]` — the backfill the forwarder replays for a
111
- * fresh thread's first turn (reference implementation's `_replay_resume_response`). */
135
+ /** Suppress rollout history when the caller only needs to load/subscribe. */
112
136
  excludeTurns?: boolean;
137
+ initialTurnsPage?: {
138
+ limit?: number | null;
139
+ sortDirection?: "asc" | "desc" | null;
140
+ itemsView?: "notLoaded" | "summary" | "full" | null;
141
+ } | null;
113
142
  }
114
143
  /** One turn in a resumed thread's backlog (`thread/resume` response). */
115
144
  export interface ResumedTurn {
@@ -125,6 +154,13 @@ export interface ResumedThread {
125
154
  turns?: ResumedTurn[];
126
155
  [key: string]: unknown;
127
156
  }
157
+ /** Settings selected by the Provider while starting or resuming a thread.
158
+ * Older app-server builds may omit them, so the bridge treats them as optional
159
+ * and falls back to `config/read` only for a fresh, not-yet-created thread. */
160
+ export interface ThreadRuntimeSettings {
161
+ model?: string;
162
+ reasoningEffort?: ReasoningEffort | null;
163
+ }
128
164
  export interface ThreadDescriptor {
129
165
  id: string;
130
166
  cwd: string;
@@ -155,6 +191,7 @@ export interface TurnStartParams {
155
191
  permissions?: PermissionSelection | null;
156
192
  model?: string | null;
157
193
  effort?: ReasoningEffort | null;
194
+ collaborationMode?: CollaborationMode | null;
158
195
  }
159
196
  export interface TurnInterruptParams {
160
197
  threadId: string;
@@ -169,7 +206,7 @@ export interface TurnSteerParams {
169
206
  expectedTurnId: string;
170
207
  input: UserInput[];
171
208
  }
172
- export type TurnStatus = "completed" | "interrupted" | "failed" | "inProgress";
209
+ export type TurnStatus = "completed" | "interrupted" | "cancelled" | "canceled" | "failed" | "errored" | "inProgress";
173
210
  export interface TurnPlanStep {
174
211
  step: string;
175
212
  status: "pending" | "inProgress" | "completed";
@@ -252,7 +289,16 @@ export interface WebSearchItem extends ThreadItemBase {
252
289
  type: "other";
253
290
  } | null;
254
291
  }
255
- export type ThreadItem = UserMessageItem | AgentMessageItem | ReasoningItem | PlanItem | CommandExecutionItem | FileChangeItem | McpToolCallItem | DynamicToolCallItem | WebSearchItem | (ThreadItemBase & Record<string, unknown>);
292
+ export interface ImageGenerationItem extends ThreadItemBase {
293
+ type: "imageGeneration";
294
+ status: string;
295
+ revisedPrompt: string | null;
296
+ /** Base64 image bytes supplied when no durable saved path is available. */
297
+ result: string;
298
+ /** Codex App Server guarantees this is absolute when present. */
299
+ savedPath?: string;
300
+ }
301
+ export type ThreadItem = UserMessageItem | AgentMessageItem | ReasoningItem | PlanItem | CommandExecutionItem | FileChangeItem | McpToolCallItem | DynamicToolCallItem | WebSearchItem | ImageGenerationItem | (ThreadItemBase & Record<string, unknown>);
256
302
  export interface ThreadSummary {
257
303
  id?: string;
258
304
  threadId?: string;
@@ -302,7 +348,7 @@ export interface ThreadSettingsUpdateParams {
302
348
  serviceTier?: string | null;
303
349
  effort?: ReasoningEffort | null;
304
350
  summary?: string | null;
305
- collaborationMode?: Record<string, unknown> | null;
351
+ collaborationMode?: CollaborationMode | null;
306
352
  personality?: string | null;
307
353
  }
308
354
  export interface ModelListParams {
@@ -476,6 +522,14 @@ export interface QueueStatusNotificationParams {
476
522
  export type ServerNotification = {
477
523
  method: "thread/started";
478
524
  params: ThreadStartedNotificationParams;
525
+ } | {
526
+ method: "thread/settings/updated";
527
+ params: {
528
+ threadId: string;
529
+ threadSettings: {
530
+ collaborationMode?: CollaborationMode | null;
531
+ } & Record<string, unknown>;
532
+ };
479
533
  } | {
480
534
  method: "turn/started";
481
535
  params: TurnStartedNotificationParams;
@@ -497,6 +551,9 @@ export type ServerNotification = {
497
551
  } | {
498
552
  method: "item/agentMessage/delta";
499
553
  params: AgentMessageDeltaNotificationParams;
554
+ } | {
555
+ method: "item/plan/delta";
556
+ params: AgentMessageDeltaNotificationParams;
500
557
  } | {
501
558
  method: "item/reasoning/summaryTextDelta";
502
559
  params: ReasoningSummaryTextDeltaNotificationParams;
@@ -8,6 +8,8 @@ export interface WsRpcChannelOptions {
8
8
  logger?: TransportLogger;
9
9
  /** Ms to wait for the app-server to accept a connection. */
10
10
  readyTimeoutMs?: number;
11
+ /** Durable per-session runtime state used for targeted crash reconciliation. */
12
+ stateDir?: string;
11
13
  }
12
14
  export declare class WsRpcChannel implements RpcChannel {
13
15
  private readonly opts;
@@ -16,6 +18,8 @@ export declare class WsRpcChannel implements RpcChannel {
16
18
  private lineCb;
17
19
  private closeCb;
18
20
  private closedEmitted;
21
+ private processTag;
22
+ private stopTask;
19
23
  private readonly readyTimeoutMs;
20
24
  /** The `ws://IP:PORT` the app-server listens on — pass to the TUI's `--remote`. */
21
25
  url: string;
@@ -30,6 +34,9 @@ export declare class WsRpcChannel implements RpcChannel {
30
34
  start(): Promise<void>;
31
35
  send(line: string): Promise<void>;
32
36
  stop(signal?: NodeJS.Signals): Promise<void>;
37
+ private stopOwnedProcess;
38
+ private signalChild;
39
+ private unregisterProcess;
33
40
  private emitClose;
34
41
  private connectWithRetry;
35
42
  private tryConnect;