@rynx-ai/runtime 0.1.11-beta.23 → 0.1.11-beta.25

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.
@@ -7,7 +7,7 @@
7
7
  * per-thread capabilities, answered against the same backend so the parent never
8
8
  * needs an app-server of its own.
9
9
  */
10
- import { type AgentCapabilities, type LiveSessionFailure, type ResolvedExecutionSnapshot, type RuntimeUserInput, type SessionInteractionResolution, type SessionWorkspaceSnapshot } from "@rynx-ai/core";
10
+ import { type AgentCapabilities, type LiveSessionFailure, type ResolvedExecutionSnapshot, type RuntimeTurnOptions, type RuntimeUserInput, type SessionCollaborationMode, type SessionInteractionResolution, type SessionWorkspaceSnapshot } from "@rynx-ai/core";
11
11
  import type { SessionEvent } from "@rynx-ai/core";
12
12
  import type { TerminalInjector } from "../claude/native-integration.js";
13
13
  import type { ResolveInteractionResult } from "../interactions.js";
@@ -54,15 +54,17 @@ interface LiveCodexProvider {
54
54
  * observer/forwarder, and evict the owned app-server while preserving the
55
55
  * durable native-session binding for a later cold resume. */
56
56
  teardownLiveCodexSession?(localThreadId: string, error?: Error): boolean;
57
- injectMessage?(localThreadId: string, input: RuntimeUserInput | string): Promise<InjectResult>;
57
+ injectMessage?(localThreadId: string, input: RuntimeUserInput | string, options?: RuntimeTurnOptions): Promise<InjectResult>;
58
+ updateCollaborationMode?(localThreadId: string, mode: SessionCollaborationMode): Promise<void>;
58
59
  interruptLive?(localThreadId: string): Promise<boolean>;
59
60
  stopLiveCodexSession?(localThreadId: string, opts?: {
60
61
  deferClaudeInteractionCleanup?: boolean;
61
62
  }): void;
62
63
  finalizeStoppedLiveSessions?(): void;
63
64
  resolveInteraction?(localThreadId: string, interactionId: string, resolution: SessionInteractionResolution): Promise<ResolveInteractionResult>;
64
- /** claude-native: hand the session's tmux pane injector to the host (which
65
- * doesn't own tmux). No-op for codex sessions (they inject via app-server). */
65
+ /** Hand the session's tmux pane injector to the host (which doesn't own
66
+ * tmux). Claude uses it for messages; Codex uses it only for TUI-local
67
+ * controls that the app-server cannot resolve, such as the final Plan picker. */
66
68
  attachTerminalInjector?(localThreadId: string, injector: TerminalInjector): void;
67
69
  /** Internal Provider operation used only by MachineSessionService through
68
70
  * RunnerManager. It is deliberately absent from public AgentCapabilities. */
@@ -120,6 +122,7 @@ export declare class RunnerSession {
120
122
  * already-rejected readiness promise. */
121
123
  private failCodexThreadStartup;
122
124
  private inject;
125
+ private updateCollaborationMode;
123
126
  private interruptLive;
124
127
  /** Launch (idempotently) the session's codex TUI pane from the executor's
125
128
  * `codexTerminalSpec`. Shares the `${id}-main` terminal id with `term.open`,
@@ -149,6 +149,9 @@ export class RunnerSession {
149
149
  case "inject":
150
150
  void this.inject(msg);
151
151
  return;
152
+ case "collaboration.update":
153
+ void this.updateCollaborationMode(msg);
154
+ return;
152
155
  case "live.interrupt":
153
156
  void this.interruptLive(msg);
154
157
  return;
@@ -274,7 +277,7 @@ export class RunnerSession {
274
277
  : nativePhaseError(runtime, "native_terminal_launch_failed", "Terminal failed to launch", error);
275
278
  }
276
279
  }
277
- // Omnigent's known-thread path launches `codex --remote resume` first,
280
+ // reference implementation's known-thread path launches `codex --remote resume` first,
278
281
  // then creates `_codex_forward_known_thread` as background work. Keep the
279
282
  // ordering explicit here: observer connection failure cannot delay or
280
283
  // reject cold-resume admission.
@@ -377,7 +380,7 @@ export class RunnerSession {
377
380
  const provider = this.liveProvider;
378
381
  try {
379
382
  const input = msg.input ?? msg.text;
380
- const result = (await provider.injectMessage?.(msg.localThreadId, input))
383
+ const result = (await provider.injectMessage?.(msg.localThreadId, input, msg.options))
381
384
  ?? { outcome: "notLive" };
382
385
  // App-server injection is independent of the Terminal TUI startup, so it
383
386
  // must not cancel prompt handling for the pane that is still starting.
@@ -413,6 +416,29 @@ export class RunnerSession {
413
416
  });
414
417
  }
415
418
  }
419
+ async updateCollaborationMode(msg) {
420
+ try {
421
+ if (!this.liveProvider.updateCollaborationMode) {
422
+ throw new AgentRuntimeError("Native collaboration mode is unavailable", 409, "collaboration_mode_unavailable");
423
+ }
424
+ await this.liveProvider.updateCollaborationMode(msg.localThreadId, msg.mode);
425
+ this.transport.send({
426
+ t: "collaboration.updated",
427
+ reqId: msg.reqId,
428
+ localThreadId: msg.localThreadId,
429
+ ok: true,
430
+ });
431
+ }
432
+ catch (error) {
433
+ this.transport.send({
434
+ t: "collaboration.updated",
435
+ reqId: msg.reqId,
436
+ localThreadId: msg.localThreadId,
437
+ ok: false,
438
+ error: toWireError(error),
439
+ });
440
+ }
441
+ }
416
442
  async interruptLive(msg) {
417
443
  const provider = this.liveProvider;
418
444
  let ok = false;
@@ -472,7 +498,7 @@ export class RunnerSession {
472
498
  ? terminal.isAliveAsync().then((alive) => alive ? "alive" : "dead")
473
499
  : Promise.resolve(terminal.isAlive() ? "alive" : "dead");
474
500
  void probe.then((liveness) => {
475
- // A failed pane probe is inconclusive. Only Omnigent's lifecycle
501
+ // A failed pane probe is inconclusive. Only reference implementation's lifecycle
476
502
  // evidence — capture target gone or explicit pane_dead — may fail it.
477
503
  if (liveness !== "dead" ||
478
504
  this.shuttingDown ||
@@ -16,7 +16,7 @@
16
16
  * channel.
17
17
  */
18
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 LiveSessionFailure, type InjectResult, type ResolvedExecutionSnapshot, type RuntimeUserInput, type SessionInteractionResolution, type SessionEvent, type SessionWorkspaceSnapshot, type ThreadGoal } from "@rynx-ai/core";
19
+ import { type AdmissionReservation, type AgentCapabilities, type AgentRuntimeId, type AppConfig, type CapabilityResult, type ModelListResponse, type LiveSessionFailure, type InjectResult, type ResolvedExecutionSnapshot, type RuntimeTurnOptions, type RuntimeUserInput, type SessionCollaborationMode, 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 TerminalOpenErrorCode, type TerminalRole } from "./protocol.js";
@@ -73,7 +73,7 @@ export interface RunnerManagerOptions {
73
73
  * created for the runner child, with direct-child fallback. */
74
74
  signalChild?: (child: ChildProcess, signal: NodeJS.Signals, processGroup: boolean) => void;
75
75
  /** Injected for tests. Best-effort close of the deterministic private tmux
76
- * server owned by a Session runner; Omnigent does not verify/retry close. */
76
+ * server owned by a Session runner; reference implementation does not verify/retry close. */
77
77
  terminateTerminalServer?: (terminalName: string) => boolean | Promise<boolean>;
78
78
  /** Injected tmux `#{window_activity}` reader. Returns epoch seconds. */
79
79
  terminalWindowActivityAt?: (terminalName: string) => number | null | Promise<number | null>;
@@ -179,6 +179,9 @@ export declare class RunnerManager implements AgentCapabilities {
179
179
  private stopPromise;
180
180
  /** Sink for mirrored {@link SessionEvent}s from every session's forwarder. */
181
181
  private mirrorListener;
182
+ /** Synchronous persistence hook for native collaboration-mode reflection.
183
+ * It runs before the event reaches the Session bus. */
184
+ private collaborationModeListener;
182
185
  /** Sink for session rotations (claude `/clear`·`/fork`) — server records meta. */
183
186
  private rotateListener;
184
187
  /** Session keys with a live codex forwarder — never reaped while present. */
@@ -227,6 +230,7 @@ export declare class RunnerManager implements AgentCapabilities {
227
230
  * server wires this to `persistSessionEvent` (bus + canonical log).
228
231
  */
229
232
  onMirror(listener: (sessionId: string, event: SessionEvent) => void): void;
233
+ onCollaborationMode(listener: (sessionId: string, mode: SessionCollaborationMode) => void): void;
230
234
  /** Register the sink for session rotations (claude `/clear`·`/fork`): the server
231
235
  * records the new session's meta (carry-over agent/model/title). */
232
236
  onRotate(listener: (rotation: RotateInfo) => void | Promise<void>): void;
@@ -273,7 +277,7 @@ export declare class RunnerManager implements AgentCapabilities {
273
277
  * all output. Resolves true when the app-server accepted the turn, false when
274
278
  * the session has no live forwarder (caller falls back to the run path).
275
279
  */
276
- injectMessage(localThreadId: string, input: RuntimeUserInput | string): Promise<InjectResult>;
280
+ injectMessage(localThreadId: string, input: RuntimeUserInput | string, options?: RuntimeTurnOptions): Promise<InjectResult>;
277
281
  private injectMessageAdmitted;
278
282
  /**
279
283
  * Interrupt a session's active live turn — the web Stop button (codex
@@ -283,6 +287,8 @@ export declare class RunnerManager implements AgentCapabilities {
283
287
  interruptLiveSession(localThreadId: string): Promise<boolean>;
284
288
  /** Resolve a native question/approval without ever spawning a new runner. */
285
289
  resolveInteraction(localThreadId: string, interactionId: string, resolution: SessionInteractionResolution): Promise<ResolveInteractionResult>;
290
+ /** Update a loaded Codex-lineage native thread without spawning a runner. */
291
+ updateCollaborationMode(localThreadId: string, mode: SessionCollaborationMode): Promise<void>;
286
292
  listModels(runtime?: AgentRuntimeId): Promise<ModelListResponse | null>;
287
293
  getGoal(localThreadId: string): Promise<CapabilityResult<ThreadGoal | null>>;
288
294
  setGoal(localThreadId: string, objective: string): Promise<CapabilityResult>;
@@ -340,6 +346,7 @@ export declare class RunnerManager implements AgentCapabilities {
340
346
  private isNativePaneBusy;
341
347
  private isManagedNativeHandle;
342
348
  private failActiveResponses;
349
+ private interruptActiveResponses;
343
350
  /** Track the provider-authoritative response lifecycle. Native-pane busy
344
351
  * classification consumes this level directly; output volume is separately
345
352
  * grounded in tmux's own activity clock. */
@@ -182,6 +182,9 @@ export class RunnerManager {
182
182
  stopPromise;
183
183
  /** Sink for mirrored {@link SessionEvent}s from every session's forwarder. */
184
184
  mirrorListener = null;
185
+ /** Synchronous persistence hook for native collaboration-mode reflection.
186
+ * It runs before the event reaches the Session bus. */
187
+ collaborationModeListener = null;
185
188
  /** Sink for session rotations (claude `/clear`·`/fork`) — server records meta. */
186
189
  rotateListener = null;
187
190
  /** Session keys with a live codex forwarder — never reaped while present. */
@@ -349,6 +352,9 @@ export class RunnerManager {
349
352
  onMirror(listener) {
350
353
  this.mirrorListener = listener;
351
354
  }
355
+ onCollaborationMode(listener) {
356
+ this.collaborationModeListener = listener;
357
+ }
352
358
  /** Register the sink for session rotations (claude `/clear`·`/fork`): the server
353
359
  * records the new session's meta (carry-over agent/model/title). */
354
360
  onRotate(listener) {
@@ -623,19 +629,19 @@ export class RunnerManager {
623
629
  * all output. Resolves true when the app-server accepted the turn, false when
624
630
  * the session has no live forwarder (caller falls back to the run path).
625
631
  */
626
- injectMessage(localThreadId, input) {
632
+ injectMessage(localThreadId, input, options) {
627
633
  const admission = this.reserveAdmission();
628
- return this.injectMessageAdmitted(localThreadId, input)
634
+ return this.injectMessageAdmitted(localThreadId, input, options)
629
635
  .finally(() => admission.release());
630
636
  }
631
- injectMessageAdmitted(localThreadId, input) {
637
+ injectMessageAdmitted(localThreadId, input, options) {
632
638
  const sourceReservation = this.sourceForkReservations.get(localThreadId);
633
639
  if (sourceReservation) {
634
- return sourceReservation.then(() => this.injectMessageAdmitted(localThreadId, input));
640
+ return sourceReservation.then(() => this.injectMessageAdmitted(localThreadId, input, options));
635
641
  }
636
642
  const reservation = this.forkReservations.get(localThreadId);
637
643
  if (reservation) {
638
- return reservation.then(() => this.injectMessageAdmitted(localThreadId, input));
644
+ return reservation.then(() => this.injectMessageAdmitted(localThreadId, input, options));
639
645
  }
640
646
  const handle = this.getOrSpawn(localThreadId);
641
647
  handle.lastUsedAt = this.now();
@@ -670,8 +676,8 @@ export class RunnerManager {
670
676
  resolve(finish());
671
677
  });
672
678
  handle.transport.send(typeof input === "string"
673
- ? { t: "inject", reqId, localThreadId, text: input }
674
- : { t: "inject", reqId, localThreadId, input });
679
+ ? { t: "inject", reqId, localThreadId, text: input, ...(options ? { options } : {}) }
680
+ : { t: "inject", reqId, localThreadId, input, ...(options ? { options } : {}) });
675
681
  });
676
682
  }
677
683
  /**
@@ -723,6 +729,34 @@ export class RunnerManager {
723
729
  });
724
730
  });
725
731
  }
732
+ /** Update a loaded Codex-lineage native thread without spawning a runner. */
733
+ updateCollaborationMode(localThreadId, mode) {
734
+ const handle = this.handles.get(localThreadId);
735
+ if (!handle || handle.dead || !this.liveSessionKeys.has(localThreadId)) {
736
+ return Promise.reject(new AgentRuntimeError("Native Session is not live", 409, "native_session_not_live"));
737
+ }
738
+ handle.lastUsedAt = this.now();
739
+ const reqId = randomUUID();
740
+ return new Promise((resolve, reject) => {
741
+ handle.live.set(reqId, (reply) => {
742
+ if (reply.collaborationUpdated) {
743
+ resolve();
744
+ return;
745
+ }
746
+ reject(fromWireError(reply.error ?? {
747
+ message: "Native collaboration mode update failed",
748
+ code: "collaboration_mode_update_failed",
749
+ statusCode: 503,
750
+ }));
751
+ });
752
+ handle.transport.send({
753
+ t: "collaboration.update",
754
+ reqId,
755
+ localThreadId,
756
+ mode,
757
+ });
758
+ });
759
+ }
726
760
  // ── AgentCapabilities ──────────────────────────────────────────────────────
727
761
  async listModels(runtime) {
728
762
  return listRuntimeModels(this.config, runtime ?? this.defaultRuntime);
@@ -1248,6 +1282,9 @@ export class RunnerManager {
1248
1282
  return;
1249
1283
  if (this.bufferForkTargetMessage(handle, msg))
1250
1284
  return;
1285
+ if (msg.event.type === "session.collaboration_mode") {
1286
+ this.collaborationModeListener?.(msg.sessionId, msg.event.mode);
1287
+ }
1251
1288
  this.observeHandleRuntimeEvent(handle, msg.event);
1252
1289
  this.mirrorListener?.(msg.sessionId, msg.event);
1253
1290
  if (msg.event.type === "response.created") {
@@ -1275,6 +1312,15 @@ export class RunnerManager {
1275
1312
  : { ok: msg.ok, error: msg.error });
1276
1313
  return;
1277
1314
  }
1315
+ case "collaboration.updated": {
1316
+ const resolve = handle.live.get(msg.reqId);
1317
+ handle.live.delete(msg.reqId);
1318
+ resolve?.({
1319
+ collaborationUpdated: msg.ok,
1320
+ ...(msg.error ? { error: msg.error } : {}),
1321
+ });
1322
+ return;
1323
+ }
1278
1324
  case "interaction.resolved": {
1279
1325
  const resolve = handle.live.get(msg.reqId);
1280
1326
  handle.live.delete(msg.reqId);
@@ -1335,6 +1381,7 @@ export class RunnerManager {
1335
1381
  catch {
1336
1382
  // The process signal below remains the authoritative shutdown path.
1337
1383
  }
1384
+ this.interruptActiveResponses(handle);
1338
1385
  this.failHandle(handle, reason, { failActiveResponses: false });
1339
1386
  }
1340
1387
  this.signalChild(handle.child, "SIGTERM", handle.processGroup);
@@ -1477,6 +1524,18 @@ export class RunnerManager {
1477
1524
  });
1478
1525
  }
1479
1526
  }
1527
+ interruptActiveResponses(handle) {
1528
+ const responseIds = [...handle.activeResponseIds];
1529
+ handle.activeResponseIds.clear();
1530
+ const sessionId = this.currentTerminalSessionId(handle, handle.key);
1531
+ for (const responseId of responseIds) {
1532
+ this.mirrorListener?.(sessionId, {
1533
+ type: "session.interrupted",
1534
+ sessionId,
1535
+ responseId,
1536
+ });
1537
+ }
1538
+ }
1480
1539
  /** Track the provider-authoritative response lifecycle. Native-pane busy
1481
1540
  * classification consumes this level directly; output volume is separately
1482
1541
  * grounded in tmux's own activity clock. */
@@ -6,7 +6,7 @@
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 InjectResult, 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
10
  export type { InjectOutcome, InjectResult } from "@rynx-ai/core";
11
11
  import type { ResolveInteractionResult } from "../interactions.js";
12
12
  /** A runtime error flattened for the wire; rebuilt parent-side as `AgentRuntimeError`. */
@@ -88,6 +88,7 @@ export type ToChild = {
88
88
  t: "inject";
89
89
  reqId: string;
90
90
  localThreadId: string;
91
+ options?: RuntimeTurnOptions;
91
92
  } & ({
92
93
  input: RuntimeUserInput;
93
94
  text?: never;
@@ -95,6 +96,14 @@ export type ToChild = {
95
96
  text: string;
96
97
  input?: never;
97
98
  }))
99
+ /** Apply a Codex-lineage collaboration mode to an already-loaded native
100
+ * thread. This control path never starts a runner or waits for a new Turn. */
101
+ | {
102
+ t: "collaboration.update";
103
+ reqId: string;
104
+ localThreadId: string;
105
+ mode: SessionCollaborationMode;
106
+ }
98
107
  /** Interrupt the session's active turn — the web Stop button. codex: app-server
99
108
  * `turn/interrupt`; claude: an Escape keystroke to the pane. The child replies
100
109
  * `interrupted` (echoing `reqId`). */
@@ -184,6 +193,12 @@ export type FromChild = {
184
193
  localThreadId: string;
185
194
  ok: boolean;
186
195
  error?: WireError;
196
+ } | {
197
+ t: "collaboration.updated";
198
+ reqId: string;
199
+ localThreadId: string;
200
+ ok: boolean;
201
+ error?: WireError;
187
202
  } | {
188
203
  t: "interaction.resolved";
189
204
  reqId: string;
@@ -59,7 +59,7 @@ export class TerminalRegistry {
59
59
  const terminal = this.terminals.get(id);
60
60
  if (!terminal)
61
61
  return;
62
- // Omnigent removes the resource from its registry before best-effort close.
62
+ // reference implementation removes the resource from its registry before best-effort close.
63
63
  this.terminals.delete(id);
64
64
  terminal.kill();
65
65
  }
@@ -14,7 +14,7 @@ export interface TerminalAttachment {
14
14
  /** Result of probing the inner tmux pane. `unknown` is deliberately distinct
15
15
  * from `dead`: a timed-out/unexecutable control command is inconclusive;
16
16
  * `dead` requires an explicit dead pane. The lifecycle watcher separately
17
- * mirrors Omnigent's capture failure path for a vanished server/session. */
17
+ * mirrors reference implementation's capture failure path for a vanished server/session. */
18
18
  export type TerminalLiveness = "alive" | "dead" | "unknown";
19
19
  /** Minimal node-pty surface (kept local so this module has no type dep on it). */
20
20
  interface PtyProcess {
@@ -67,7 +67,7 @@ export declare function tmuxWindowActivityAt(name: string, tmuxBin?: string): Pr
67
67
  * This remains authoritative if a parent-side attachment bookkeeping edge was
68
68
  * missed during a transport failure. */
69
69
  export declare function tmuxHasAttachedClient(name: string, tmuxBin?: string): Promise<boolean>;
70
- /** Best-effort close of one private tmux server. Mirrors Omnigent's bounded
70
+ /** Best-effort close of one private tmux server. Mirrors reference implementation's bounded
71
71
  * `TerminalInstance.close`: attempt `kill-server`, then retire the private
72
72
  * socket regardless of command outcome. The registry has already forgotten
73
73
  * the resource, so cleanup failure is diagnostic rather than a second
@@ -93,7 +93,7 @@ export declare class TmuxTerminal {
93
93
  * out once per attached client. */
94
94
  private paneLivenessFlight?;
95
95
  /** Shared by lifecycle callers so capture + pane-dead remains one ordered
96
- * Omnigent-style observation per Terminal. */
96
+ * reference implementation-style observation per Terminal. */
97
97
  private lifecycleLivenessFlight?;
98
98
  constructor(opts: TmuxTerminalOptions);
99
99
  /** tmux argv prefix targeting this terminal's private server. */
@@ -138,10 +138,10 @@ export declare class TmuxTerminal {
138
138
  /** Async pane-liveness probe — MUST NOT block the event loop. The attach
139
139
  * pane-death watcher polls this on an interval; a synchronous `execFileSync`
140
140
  * there stalls the runner child's event loop (freezing the PTY stream → the
141
- * terminal appears "stuck"). Exactly like Omnigent's definitive pane probe,
141
+ * terminal appears "stuck"). Exactly like reference implementation's definitive pane probe,
142
142
  * every command error is `unknown`; only `#{pane_dead}=1` is `dead`. */
143
143
  livenessAsync(): Promise<TerminalLiveness>;
144
- /** Omnigent's always-on terminal lifecycle watcher first captures the pane:
144
+ /** reference implementation's always-on terminal lifecycle watcher first captures the pane:
145
145
  * a control command that ran and reports the target missing is terminal exit;
146
146
  * a probe that cannot spawn is inconclusive. If capture succeeds, the normal
147
147
  * definitive `pane_dead` probe distinguishes live from exited. */
@@ -79,7 +79,7 @@ export function tmuxHasAttachedClient(name, tmuxBin = resolveTmuxBin()) {
79
79
  });
80
80
  });
81
81
  }
82
- /** Best-effort close of one private tmux server. Mirrors Omnigent's bounded
82
+ /** Best-effort close of one private tmux server. Mirrors reference implementation's bounded
83
83
  * `TerminalInstance.close`: attempt `kill-server`, then retire the private
84
84
  * socket regardless of command outcome. The registry has already forgotten
85
85
  * the resource, so cleanup failure is diagnostic rather than a second
@@ -96,7 +96,7 @@ export function terminateTmuxServer(name, tmuxBin = resolveTmuxBin()) {
96
96
  });
97
97
  }
98
98
  catch {
99
- // Omnigent treats close as best-effort and still retires the resource.
99
+ // reference implementation treats close as best-effort and still retires the resource.
100
100
  }
101
101
  try {
102
102
  unlinkSync(socketPath);
@@ -146,7 +146,7 @@ export class TmuxTerminal {
146
146
  * out once per attached client. */
147
147
  paneLivenessFlight;
148
148
  /** Shared by lifecycle callers so capture + pane-dead remains one ordered
149
- * Omnigent-style observation per Terminal. */
149
+ * reference implementation-style observation per Terminal. */
150
150
  lifecycleLivenessFlight;
151
151
  constructor(opts) {
152
152
  this.name = opts.name;
@@ -285,7 +285,7 @@ export class TmuxTerminal {
285
285
  /** Async pane-liveness probe — MUST NOT block the event loop. The attach
286
286
  * pane-death watcher polls this on an interval; a synchronous `execFileSync`
287
287
  * there stalls the runner child's event loop (freezing the PTY stream → the
288
- * terminal appears "stuck"). Exactly like Omnigent's definitive pane probe,
288
+ * terminal appears "stuck"). Exactly like reference implementation's definitive pane probe,
289
289
  * every command error is `unknown`; only `#{pane_dead}=1` is `dead`. */
290
290
  livenessAsync() {
291
291
  if (!this.started)
@@ -320,7 +320,7 @@ export class TmuxTerminal {
320
320
  });
321
321
  return flight;
322
322
  }
323
- /** Omnigent's always-on terminal lifecycle watcher first captures the pane:
323
+ /** reference implementation's always-on terminal lifecycle watcher first captures the pane:
324
324
  * a control command that ran and reports the target missing is terminal exit;
325
325
  * a probe that cannot spawn is inconclusive. If capture succeeds, the normal
326
326
  * definitive `pane_dead` probe distinguishes live from exited. */
@@ -340,7 +340,7 @@ export class TmuxTerminal {
340
340
  }
341
341
  this.lastPaneSnapshot = stdout.toString();
342
342
  void this.livenessAsync().then((liveness) => {
343
- // A successful capture proves the target exists. Omnigent treats a
343
+ // A successful capture proves the target exists. reference implementation treats a
344
344
  // subsequent pane-dead probe failure as non-dead for this tick.
345
345
  resolve(liveness === "dead" ? "dead" : "alive");
346
346
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rynx-ai/runtime",
3
- "version": "0.1.11-beta.23",
3
+ "version": "0.1.11-beta.25",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/rynx-ai/rynx.git",
@@ -27,7 +27,7 @@
27
27
  "node-pty": "1.2.0-beta.15",
28
28
  "smol-toml": "1.7.1",
29
29
  "ws": "^8.21.0",
30
- "@rynx-ai/core": "0.1.11-beta.23"
30
+ "@rynx-ai/core": "0.1.11-beta.25"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/ws": "^8.18.1"