@rynx-ai/runtime 0.1.11-beta.2 → 0.1.11-beta.20

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.
@@ -15,8 +15,8 @@
15
15
  * transport drops in here later without touching `ConversationRuntime` or any
16
16
  * channel.
17
17
  */
18
- import { spawn as nodeSpawn } from "node:child_process";
19
- import { type AgentCapabilities, type AgentRuntimeId, type AppConfig, type CapabilityResult, type ModelListResponse, type ResolvedExecutionSnapshot, type RuntimeUserInput, type SessionInteractionResolution, type SessionEvent, type SessionWorkspaceSnapshot, type ThreadGoal } from "@rynx-ai/core";
18
+ import { spawn as nodeSpawn, type ChildProcess } from "node:child_process";
19
+ import { type AdmissionReservation, type AgentCapabilities, type AgentRuntimeId, type AppConfig, type CapabilityResult, type ModelListResponse, type ResolvedExecutionSnapshot, type RuntimeUserInput, type SessionInteractionResolution, type SessionEvent, type SessionWorkspaceSnapshot, type ThreadGoal } from "@rynx-ai/core";
20
20
  import { type CodexSessionStore } from "../host.js";
21
21
  import type { ResolveInteractionResult } from "../interactions.js";
22
22
  import { type InjectOutcome, type TerminalOpenErrorCode, type TerminalRole } from "./protocol.js";
@@ -43,6 +43,9 @@ export interface RunnerManagerOptions {
43
43
  runnerEntry?: string;
44
44
  /** Idle TTL (ms) after which an unused runner is reaped. */
45
45
  idleTtlMs?: number;
46
+ /** Maximum time without user/control activity that an active response may
47
+ * protect a detached runner from idle reaping. */
48
+ staleActiveTtlMs?: number;
46
49
  /** Background reap sweep interval (ms); `0` disables the timer (tests). */
47
50
  reapIntervalMs?: number;
48
51
  /** Grace period between SIGTERM and SIGKILL during runner shutdown. */
@@ -53,8 +56,25 @@ export interface RunnerManagerOptions {
53
56
  liveStartTimeoutMs?: number;
54
57
  /** Max wait for a Provider-native thread to become ready. */
55
58
  liveReadyTimeoutMs?: number;
59
+ /** Claude SessionStart deadline. Codex/Traex use `liveStartTimeoutMs` for the
60
+ * pane/observer acknowledgement; their thread discovery is asynchronous. */
61
+ nativeLiveStartTimeoutMs?: number;
62
+ /** Max wait for a native interrupt acknowledgement before reporting it
63
+ * unproven. Callers may then use the explicit force-stop path. */
64
+ liveInterruptTimeoutMs?: number;
65
+ /** Max wait for an accepted owner TUI submission to become observable as a
66
+ * mirrored response or a published native rotation. */
67
+ terminalInputHandoffTimeoutMs?: number;
68
+ /** Initial exponential backoff for retrying unproven terminal cleanup. */
69
+ terminalInputCleanupRetryMs?: number;
56
70
  /** Injected for tests. */
57
71
  spawn?: typeof nodeSpawn;
72
+ /** Injected for tests. Defaults to signaling the whole POSIX process group
73
+ * created for the runner child, with direct-child fallback. */
74
+ signalChild?: (child: ChildProcess, signal: NodeJS.Signals, processGroup: boolean) => void;
75
+ /** Injected for tests. Kills and verifies the deterministic private tmux
76
+ * server owned by a Session runner. */
77
+ terminateTerminalServer?: (terminalName: string) => boolean | Promise<boolean>;
58
78
  now?: () => number;
59
79
  /** Extra env merged into every spawned runner child — e.g. the control-plane
60
80
  * URL + token so a claude-native PermissionRequest hook can POST back. */
@@ -62,6 +82,13 @@ export interface RunnerManagerOptions {
62
82
  /** Optional lifecycle context for Session runners. The shared `__cap__`
63
83
  * runner never opens one. */
64
84
  sessionContextProvider?: RunnerSessionContextProvider;
85
+ /** Dynamic process-wide admission fence. Existing cancellation and read-only
86
+ * inspection remain available; every path that may spawn or attach execution
87
+ * checks this immediately before admission. */
88
+ admissionOpen?: () => boolean;
89
+ /** Atomically reserves one work-producing admission while it crosses the
90
+ * asynchronous boundary into an observable live runner/turn. */
91
+ admissionReserve?: () => AdmissionReservation | undefined;
65
92
  }
66
93
  /** A session rotation reported by a runner child (claude `/clear`·`/fork`): the
67
94
  * new session `to` is now aliased to `from`'s runner; carries meta to carry over. */
@@ -115,9 +142,12 @@ export declare class RunnerManager implements AgentCapabilities {
115
142
  private readonly sessionStore;
116
143
  private readonly runnerEntry;
117
144
  private readonly idleTtlMs;
145
+ private readonly staleActiveTtlMs;
118
146
  private readonly spawn;
119
147
  private readonly childEnv;
120
148
  private readonly sessionContextProvider;
149
+ private readonly admissionOpen;
150
+ private readonly admissionReserve;
121
151
  private readonly now;
122
152
  private readonly defaultRuntime;
123
153
  private readonly handles;
@@ -127,8 +157,14 @@ export declare class RunnerManager implements AgentCapabilities {
127
157
  private readonly reapTimer;
128
158
  private readonly shutdownGraceMs;
129
159
  private readonly shutdownKillGraceMs;
160
+ private readonly signalChild;
161
+ private readonly terminateTerminalServer;
130
162
  private readonly liveStartTimeoutMs;
131
163
  private readonly liveReadyTimeoutMs;
164
+ private readonly nativeLiveStartTimeoutMs;
165
+ private readonly liveInterruptTimeoutMs;
166
+ private readonly terminalInputHandoffTimeoutMs;
167
+ private readonly terminalInputCleanupRetryMs;
132
168
  private stopping;
133
169
  private stopPromise;
134
170
  /** Sink for mirrored {@link SessionEvent}s from every session's forwarder. */
@@ -154,6 +190,9 @@ export declare class RunnerManager implements AgentCapabilities {
154
190
  private readonly forkOperations;
155
191
  private readonly forkBufferedMessages;
156
192
  private readonly forkBufferedTerminalInputs;
193
+ /** Owner TUI submissions accepted by the parent but not yet represented by a
194
+ * mirrored response or a durably published native rotation. */
195
+ private readonly terminalInputHandoffs;
157
196
  constructor(opts: RunnerManagerOptions);
158
197
  /**
159
198
  * Open a live terminal on the session's runner child (spawning it if needed).
@@ -181,11 +220,24 @@ export declare class RunnerManager implements AgentCapabilities {
181
220
  /** Register the sink for session rotations (claude `/clear`·`/fork`): the server
182
221
  * records the new session's meta (carry-over agent/model/title). */
183
222
  onRotate(listener: (rotation: RotateInfo) => void | Promise<void>): void;
223
+ /** Accepted TUI submissions that have not crossed into an observable runtime
224
+ * state. The daemon folds this into runningTurns after closing admission. */
225
+ pendingTerminalInputCount(): number;
226
+ private beginTerminalInputHandoffs;
227
+ private settleTerminalInputHandoff;
228
+ private settleTerminalRotationHandoff;
229
+ private currentTerminalSessionId;
230
+ private finishTerminalInputHandoff;
231
+ private finishAllTerminalInputHandoffs;
232
+ private preserveTerminalInputHandoffsAsActivity;
233
+ private scheduleTerminalInputCleanupRetry;
234
+ private expireTerminalInputHandoffs;
184
235
  /**
185
236
  * Eagerly bring up a session's codex-native live view (persistent forwarder +
186
237
  * detached `codex --remote` TUI) in its runner child, spawning the runner if
187
- * needed. Idempotent. Resolves true once the codex thread is bound; false for a
188
- * non-codex / non-live session (the caller then uses the normal run path).
238
+ * needed. Idempotent. For Codex-lineage fresh sessions, resolves after the
239
+ * app-server/observer and pane are launched; thread discovery continues in
240
+ * parallel with injection. Other providers retain their readiness gate.
189
241
  */
190
242
  ensureLiveSession(localThreadId: string, opts: {
191
243
  workspace: SessionWorkspaceSnapshot;
@@ -211,6 +263,7 @@ export declare class RunnerManager implements AgentCapabilities {
211
263
  * the session has no live forwarder (caller falls back to the run path).
212
264
  */
213
265
  injectMessage(localThreadId: string, input: RuntimeUserInput | string): Promise<InjectOutcome>;
266
+ private injectMessageAdmitted;
214
267
  /**
215
268
  * Interrupt a session's active live turn — the web Stop button (codex
216
269
  * `turn/interrupt`, claude Escape). Best-effort: resolves false with NO spawn
@@ -243,13 +296,19 @@ export declare class RunnerManager implements AgentCapabilities {
243
296
  }): Promise<import("../host.js").CodexRuntimeStatus>;
244
297
  /** Stop the runner bound to one session (if any), rejecting its in-flight work. */
245
298
  stopRunner(localThreadId: string): void;
299
+ /** Force-stop and join the runner bound to one Session. Unlike stopRunner,
300
+ * completion proves that the child process has exited. */
301
+ terminateLiveSession(localThreadId: string): Promise<boolean>;
246
302
  /** Stop every runner and join all child exits. Idempotent across concurrent calls. */
247
303
  stop(): Promise<void>;
304
+ private handleForCleanup;
248
305
  /** Forward a capability to a runner child. Session-less caps (listModels/status)
249
306
  * use the shared `CAP_KEY` child; per-thread caps pass the session's key so they
250
307
  * run on that session's child (which owns its private CODEX_HOME). */
251
308
  private forwardCap;
252
309
  private getOrSpawn;
310
+ private assertAdmissionOpen;
311
+ private reserveAdmission;
253
312
  private performManagedFork;
254
313
  private performClaudeManagedFork;
255
314
  private bufferForkTargetMessage;
@@ -262,5 +321,14 @@ export declare class RunnerManager implements AgentCapabilities {
262
321
  private failHandle;
263
322
  private terminateHandle;
264
323
  private reapIdle;
324
+ /** Close server-side runtime state before fencing a Provider that stayed
325
+ * active past its hard inactivity deadline. The child transport is closed by
326
+ * terminateHandle immediately afterwards, so these are the final events for
327
+ * the abandoned responses. */
328
+ private failStaleActiveResponses;
329
+ private failActiveResponses;
330
+ /** Track only response lifecycle, not output volume. Output deltas from a
331
+ * runaway TUI/Provider must not refresh the stale-active deadline. */
332
+ private observeHandleRuntimeEvent;
265
333
  private openSessionContext;
266
334
  }