@rynx-ai/runtime 0.1.11-beta.32 → 0.1.11-beta.34
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/native-bridge.d.ts +16 -1
- package/dist/claude/native-bridge.js +91 -17
- package/dist/claude/native-integration.d.ts +10 -0
- package/dist/claude/native-integration.js +100 -6
- package/dist/codex-app-server/forwarder.js +17 -1
- 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/ws-channel.d.ts +7 -0
- package/dist/codex-app-server/ws-channel.js +85 -9
- package/dist/host.d.ts +9 -1
- package/dist/host.js +48 -14
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/runner/child.d.ts +24 -3
- package/dist/runner/child.js +327 -58
- package/dist/runner/manager.d.ts +33 -18
- package/dist/runner/manager.js +229 -49
- package/dist/runner/protocol.d.ts +79 -7
- package/dist/runner/transport.d.ts +9 -2
- package/dist/runner/transport.js +55 -3
- package/dist/runner-main.js +8 -3
- 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 +15 -13
- package/dist/terminal/registry.js +38 -20
- package/dist/terminal/spool.d.ts +47 -0
- package/dist/terminal/spool.js +231 -0
- package/dist/terminal/tmux.d.ts +93 -84
- package/dist/terminal/tmux.js +666 -199
- package/package.json +3 -4
package/dist/host.js
CHANGED
|
@@ -15,8 +15,10 @@ import { validateInteractionResolution } from "./interactions.js";
|
|
|
15
15
|
import { CodexAppServerClient, buildRuntimeUserInput, } from "./codex-app-server/client.js";
|
|
16
16
|
import { buildAppServerBaseArgs, CodexTransportError, } from "./codex-app-server/transport.js";
|
|
17
17
|
import { WsRpcChannel, ExternalWsChannel } from "./codex-app-server/ws-channel.js";
|
|
18
|
+
import { reapRuntimeProcessesForStateDir } from "./codex-app-server/process-registry.js";
|
|
18
19
|
import { CodexSessionForwarder } from "./codex-app-server/forwarder.js";
|
|
19
20
|
import { readMcpStartupPlan } from "./codex-app-server/mcp-startup.js";
|
|
21
|
+
import { runtimeSessionStateDir } from "./runtime-state-paths.js";
|
|
20
22
|
import { buildCodexRemoteArgs } from "./terminal/codex-tui.js";
|
|
21
23
|
import { buildClaudeTuiArgs } from "./terminal/claude-tui.js";
|
|
22
24
|
import { providerAdditionalDirs, threadWorkspaceParams, turnWorkspaceParams, } from "./provider-workspace.js";
|
|
@@ -361,6 +363,7 @@ export class LocalAgentHost {
|
|
|
361
363
|
/** Claude forwarders stopped before their terminal is killed. Runner shutdown
|
|
362
364
|
* finalizes these synchronously afterwards to scrub raw interaction answers. */
|
|
363
365
|
pendingClaudeFinalizers = new Set();
|
|
366
|
+
pendingCleanupTasks = new Set();
|
|
364
367
|
// In-flight `ensureLiveCodexSession` calls, so concurrent triggers (a web
|
|
365
368
|
// `live.ensure` racing a `term.open`) share ONE forwarder — never two.
|
|
366
369
|
liveEnsuring = new Map();
|
|
@@ -477,6 +480,7 @@ export class LocalAgentHost {
|
|
|
477
480
|
const channel = new WsRpcChannel({
|
|
478
481
|
cliPath,
|
|
479
482
|
baseArgs: buildAppServerBaseArgs(sandbox),
|
|
483
|
+
stateDir: runtimeSessionStateDir(this.runtimeHomeSessionId),
|
|
480
484
|
extraEnv: {
|
|
481
485
|
...(extraEnv ?? {}),
|
|
482
486
|
[profile.homeEnvVar]: this.runtimeHome(runtime),
|
|
@@ -639,6 +643,7 @@ export class LocalAgentHost {
|
|
|
639
643
|
const profile = getRuntimeProfile(runtime);
|
|
640
644
|
const activeThreadId = live?.threadId ?? record?.codexSessionId;
|
|
641
645
|
return {
|
|
646
|
+
lifecycle: "auxiliary",
|
|
642
647
|
command: resolveRuntimeBinary(runtime),
|
|
643
648
|
args: buildCodexRemoteArgs({
|
|
644
649
|
remoteUrl,
|
|
@@ -648,6 +653,10 @@ export class LocalAgentHost {
|
|
|
648
653
|
additionalDirs: providerAdditionalDirs(live.workspace),
|
|
649
654
|
}),
|
|
650
655
|
cwd: live.workspace.cwd,
|
|
656
|
+
scrollback: 100_000,
|
|
657
|
+
tmuxAllowPassthrough: true,
|
|
658
|
+
tmuxStartOnAttach: false,
|
|
659
|
+
keepAliveAfterExit: false,
|
|
651
660
|
...(runtime === "traex" ? { skipTraexStartupPrompts: true } : {}),
|
|
652
661
|
// Share the app-server's private CODEX_HOME so the TUI inherits the same
|
|
653
662
|
// login/settings and skips the real home's update/NUX prompt. RYNX_SESSION_ID
|
|
@@ -765,6 +774,7 @@ export class LocalAgentHost {
|
|
|
765
774
|
void snapshotSkills.skillsCleanup();
|
|
766
775
|
return false;
|
|
767
776
|
};
|
|
777
|
+
reapRuntimeProcessesForStateDir(runtimeSessionStateDir(this.runtimeHomeSessionId));
|
|
768
778
|
const appServerOwner = this.getBackend(runtime, execution.budget ?? undefined).appServerClient;
|
|
769
779
|
if (!appServerOwner) {
|
|
770
780
|
this.liveStartupErrors.set(localThreadId, nativeLiveFailure(runtime, "native_app_server_unavailable", "app-server is unavailable for this Session"));
|
|
@@ -1418,6 +1428,7 @@ export class LocalAgentHost {
|
|
|
1418
1428
|
kind,
|
|
1419
1429
|
});
|
|
1420
1430
|
this.liveSessions.set(newSessionId, live);
|
|
1431
|
+
this.liveSessions.delete(previousSessionId);
|
|
1421
1432
|
retargetMirror?.(newSessionId, {
|
|
1422
1433
|
kind,
|
|
1423
1434
|
workspace: structuredClone(live.workspace),
|
|
@@ -1843,7 +1854,8 @@ export class LocalAgentHost {
|
|
|
1843
1854
|
claude.pendingImageInputs.delete(token);
|
|
1844
1855
|
}
|
|
1845
1856
|
else {
|
|
1846
|
-
|
|
1857
|
+
if (result.responseId)
|
|
1858
|
+
pendingInput.responseId = result.responseId;
|
|
1847
1859
|
if (pendingInput.observed)
|
|
1848
1860
|
forgetPendingInput();
|
|
1849
1861
|
else
|
|
@@ -2088,6 +2100,7 @@ export class LocalAgentHost {
|
|
|
2088
2100
|
this.liveClaudeSessions.delete(localThreadId);
|
|
2089
2101
|
claude.stopped = true;
|
|
2090
2102
|
claude.forwarder.stop();
|
|
2103
|
+
this.trackCleanup(claude.forwarder.waitForStop());
|
|
2091
2104
|
if (opts.deferClaudeInteractionCleanup) {
|
|
2092
2105
|
this.pendingClaudeFinalizers.add(claude.forwarder);
|
|
2093
2106
|
}
|
|
@@ -2118,9 +2131,10 @@ export class LocalAgentHost {
|
|
|
2118
2131
|
live.canonicalInteractions.clear();
|
|
2119
2132
|
live.settledInteractions.clear();
|
|
2120
2133
|
live.syntheticInteractions.clear();
|
|
2121
|
-
|
|
2134
|
+
this.trackCleanup(live.forwarderClient.stop().catch(() => undefined));
|
|
2122
2135
|
// Remove the session-scoped skills dir — the machine keeps zero task residue.
|
|
2123
|
-
|
|
2136
|
+
if (live.skillsCleanup)
|
|
2137
|
+
this.trackCleanup(live.skillsCleanup());
|
|
2124
2138
|
}
|
|
2125
2139
|
/** Tear down one codex-lineage native runtime without deleting its durable
|
|
2126
2140
|
* session-store binding. reference implementation couples its auxiliary Terminal, observer,
|
|
@@ -2138,14 +2152,19 @@ export class LocalAgentHost {
|
|
|
2138
2152
|
if (backend?.appServerClient === appServerOwner) {
|
|
2139
2153
|
this.backends.delete(backendKey);
|
|
2140
2154
|
}
|
|
2141
|
-
|
|
2155
|
+
this.trackCleanup(appServerOwner.stop().catch((stopError) => {
|
|
2142
2156
|
console.warn(`[codex-live] session=${localThreadId} runtime=${live.runtime} app-server teardown failed: ${stopError instanceof Error ? stopError.message : String(stopError)}`);
|
|
2143
|
-
});
|
|
2157
|
+
}));
|
|
2144
2158
|
return turnFailed;
|
|
2145
2159
|
}
|
|
2160
|
+
async teardownAuxiliaryTerminalRuntime(localThreadId) {
|
|
2161
|
+
const owner = this.liveSessions.get(localThreadId)?.appServerOwner;
|
|
2162
|
+
this.teardownLiveCodexSession(localThreadId);
|
|
2163
|
+
await owner?.stop().catch(() => undefined);
|
|
2164
|
+
}
|
|
2146
2165
|
/** Complete the second shutdown phase after the runner has killed all native
|
|
2147
2166
|
* terminals and hook subprocesses. Must run before the runner process exits. */
|
|
2148
|
-
finalizeStoppedLiveSessions() {
|
|
2167
|
+
async finalizeStoppedLiveSessions() {
|
|
2149
2168
|
for (const forwarder of this.pendingClaudeFinalizers)
|
|
2150
2169
|
forwarder.finalizeStop();
|
|
2151
2170
|
this.pendingClaudeFinalizers.clear();
|
|
@@ -2154,10 +2173,20 @@ export class LocalAgentHost {
|
|
|
2154
2173
|
// that can only reconnect to a dead session. `stop()` sends SIGTERM before
|
|
2155
2174
|
// its returned promise yields, so this remains safe in the synchronous
|
|
2156
2175
|
// runner shutdown path.
|
|
2157
|
-
|
|
2158
|
-
void backend.appServerClient?.stop().catch(() => undefined);
|
|
2159
|
-
}
|
|
2176
|
+
const backendStops = [...this.backends.values()].map((backend) => backend.appServerClient?.stop().catch(() => undefined));
|
|
2160
2177
|
this.backends.clear();
|
|
2178
|
+
await Promise.all([
|
|
2179
|
+
...backendStops,
|
|
2180
|
+
...this.pendingCleanupTasks,
|
|
2181
|
+
]);
|
|
2182
|
+
this.pendingCleanupTasks.clear();
|
|
2183
|
+
}
|
|
2184
|
+
trackCleanup(task) {
|
|
2185
|
+
const guarded = task.catch((error) => {
|
|
2186
|
+
console.warn(`[native-runtime] cleanup failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2187
|
+
});
|
|
2188
|
+
this.pendingCleanupTasks.add(guarded);
|
|
2189
|
+
void guarded.then(() => this.pendingCleanupTasks.delete(guarded));
|
|
2161
2190
|
}
|
|
2162
2191
|
// --- claude-native live session (parallel to the codex methods above) -----
|
|
2163
2192
|
/** The interactive `claude` TUI spec for a claude-native live session: the real
|
|
@@ -2216,9 +2245,14 @@ export class LocalAgentHost {
|
|
|
2216
2245
|
...(live.launchExtraArgs.length ? { extraArgs: live.launchExtraArgs } : {}),
|
|
2217
2246
|
});
|
|
2218
2247
|
return {
|
|
2248
|
+
lifecycle: "required",
|
|
2219
2249
|
command: resolveRuntimeBinary("claude"),
|
|
2220
2250
|
args,
|
|
2221
2251
|
cwd,
|
|
2252
|
+
scrollback: 50_000,
|
|
2253
|
+
tmuxAllowPassthrough: false,
|
|
2254
|
+
tmuxStartOnAttach: false,
|
|
2255
|
+
keepAliveAfterExit: true,
|
|
2222
2256
|
// Same env the pane would inherit by default, plus the session scope for
|
|
2223
2257
|
// agent-run CLIs (rynx-emulator resolves device-less commands via it).
|
|
2224
2258
|
env: { ...process.env, RYNX_SESSION_ID: localThreadId },
|
|
@@ -2598,6 +2632,7 @@ export class LocalAgentHost {
|
|
|
2598
2632
|
live.contextWarned = false;
|
|
2599
2633
|
pendingRotationEvents = [];
|
|
2600
2634
|
this.liveClaudeSessions.set(newSessionId, live);
|
|
2635
|
+
this.liveClaudeSessions.delete(previousSessionId);
|
|
2601
2636
|
void this.sessionStore
|
|
2602
2637
|
.set({
|
|
2603
2638
|
localThreadId: newSessionId,
|
|
@@ -2703,11 +2738,10 @@ export class LocalAgentHost {
|
|
|
2703
2738
|
if (!ok)
|
|
2704
2739
|
return { outcome: "failed" };
|
|
2705
2740
|
const responseId = pendingInput.responseId ?? live.currentResponseId();
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
}
|
|
2710
|
-
return { outcome: steered ? "steered" : "injected", responseId };
|
|
2741
|
+
return {
|
|
2742
|
+
outcome: steered ? "steered" : "injected",
|
|
2743
|
+
...(responseId ? { responseId } : {}),
|
|
2744
|
+
};
|
|
2711
2745
|
}
|
|
2712
2746
|
catch (error) {
|
|
2713
2747
|
live.error = error instanceof Error ? error.message : String(error);
|
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,6 @@ export type { InjectOutcome, InjectResult, TerminalOpenErrorCode, TerminalRole }
|
|
|
13
13
|
export type { ResolveInteractionResult, RuntimeInteractionEvent, RuntimeInteractionListener, } from "./interactions.js";
|
|
14
14
|
export { probeRuntimeStatus } from "./runtime-status.js";
|
|
15
15
|
export { listRuntimeModels } from "./models-catalog.js";
|
|
16
|
-
export { TmuxTerminal, isTmuxAvailable, terminateTmuxServer, tmuxSocketPath, } from "./terminal/tmux.js";
|
|
17
|
-
export type {
|
|
16
|
+
export { TmuxTerminal, isTmuxAvailable, resolveTmuxBin, terminateTmuxServer, tmuxSocketPath, } from "./terminal/tmux.js";
|
|
17
|
+
export type { PreparedTerminalAttachment, PullTerminalAttachment, TmuxTerminalOptions, } from "./terminal/tmux.js";
|
|
18
18
|
export { TerminalRegistry } from "./terminal/registry.js";
|
package/dist/index.js
CHANGED
|
@@ -12,5 +12,5 @@ export { RunnerManager, TerminalOpenError } from "./runner/manager.js";
|
|
|
12
12
|
export { probeRuntimeStatus } from "./runtime-status.js";
|
|
13
13
|
export { listRuntimeModels } from "./models-catalog.js";
|
|
14
14
|
// Live-terminal subsystem (Phase C): tmux-backed terminals + per-runner registry.
|
|
15
|
-
export { TmuxTerminal, isTmuxAvailable, terminateTmuxServer, tmuxSocketPath, } from "./terminal/tmux.js";
|
|
15
|
+
export { TmuxTerminal, isTmuxAvailable, resolveTmuxBin, terminateTmuxServer, tmuxSocketPath, } from "./terminal/tmux.js";
|
|
16
16
|
export { TerminalRegistry } from "./terminal/registry.js";
|
package/dist/runner/child.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type AgentCapabilities, type LiveSessionFailure, type ResolvedExecutionSnapshot, type RuntimeTurnOptions, type RuntimeUserInput, type SessionCollaborationMode, type SessionInteractionResolution, type SessionWorkspaceSnapshot } from "@rynx-ai/core";
|
|
2
2
|
import type { SessionEvent } from "@rynx-ai/core";
|
|
3
|
+
import { type TerminalLifecycle } from "../terminal/registry.js";
|
|
3
4
|
import type { TerminalInjector } from "../claude/native-integration.js";
|
|
4
5
|
import type { ResolveInteractionResult } from "../interactions.js";
|
|
5
6
|
import { type InjectResult } from "./protocol.js";
|
|
@@ -23,6 +24,11 @@ interface LiveCodexProvider {
|
|
|
23
24
|
cwd: string;
|
|
24
25
|
env?: Record<string, string>;
|
|
25
26
|
skipTraexStartupPrompts?: boolean;
|
|
27
|
+
scrollback?: number;
|
|
28
|
+
tmuxAllowPassthrough?: boolean;
|
|
29
|
+
tmuxStartOnAttach?: boolean;
|
|
30
|
+
keepAliveAfterExit?: boolean;
|
|
31
|
+
lifecycle: TerminalLifecycle;
|
|
26
32
|
} | null>;
|
|
27
33
|
ensureLiveCodexSession?(localThreadId: string, emit: (event: SessionEvent) => void, opts: {
|
|
28
34
|
workspace: SessionWorkspaceSnapshot;
|
|
@@ -45,13 +51,16 @@ interface LiveCodexProvider {
|
|
|
45
51
|
* observer/forwarder, and evict the owned app-server while preserving the
|
|
46
52
|
* durable native-session binding for a later cold resume. */
|
|
47
53
|
teardownLiveCodexSession?(localThreadId: string, error?: Error): boolean;
|
|
54
|
+
/** Cleanup coupled runtime resources after an auxiliary terminal is
|
|
55
|
+
* intentionally idle-reaped. Unexpected auxiliary exit does not call this. */
|
|
56
|
+
teardownAuxiliaryTerminalRuntime?(localThreadId: string): Promise<void>;
|
|
48
57
|
injectMessage?(localThreadId: string, input: RuntimeUserInput | string, options?: RuntimeTurnOptions): Promise<InjectResult>;
|
|
49
58
|
updateCollaborationMode?(localThreadId: string, mode: SessionCollaborationMode): Promise<void>;
|
|
50
59
|
interruptLive?(localThreadId: string): Promise<boolean>;
|
|
51
60
|
stopLiveCodexSession?(localThreadId: string, opts?: {
|
|
52
61
|
deferClaudeInteractionCleanup?: boolean;
|
|
53
62
|
}): void;
|
|
54
|
-
finalizeStoppedLiveSessions?(): void
|
|
63
|
+
finalizeStoppedLiveSessions?(): void | Promise<void>;
|
|
55
64
|
resolveInteraction?(localThreadId: string, interactionId: string, resolution: SessionInteractionResolution): Promise<ResolveInteractionResult>;
|
|
56
65
|
/** Hand the session's tmux pane injector to the host (which doesn't own
|
|
57
66
|
* tmux). Claude uses it for messages; Codex uses it only for TUI-local
|
|
@@ -77,8 +86,10 @@ export declare class RunnerSession {
|
|
|
77
86
|
private readonly onShutdown;
|
|
78
87
|
/** Live terminals hosted by this session, and per-attach client handles. */
|
|
79
88
|
private readonly terminals;
|
|
89
|
+
private readonly preparations;
|
|
80
90
|
private readonly attachments;
|
|
81
91
|
private readonly attachmentThreadIds;
|
|
92
|
+
private readonly attachmentRoles;
|
|
82
93
|
private readonly traexStartupWatchers;
|
|
83
94
|
private readonly traexStartupGates;
|
|
84
95
|
private readonly terminalWatchers;
|
|
@@ -91,7 +102,9 @@ export declare class RunnerSession {
|
|
|
91
102
|
private readonly mirrorImageAcks;
|
|
92
103
|
/** Provider name retained for asynchronous Terminal-exit diagnostics. */
|
|
93
104
|
private readonly liveRuntimes;
|
|
105
|
+
private readonly terminalStatuses;
|
|
94
106
|
private shuttingDown;
|
|
107
|
+
private shutdownPromise;
|
|
95
108
|
constructor({ transport, executor, onShutdown }: RunnerSessionDeps);
|
|
96
109
|
private handle;
|
|
97
110
|
private get liveProvider();
|
|
@@ -102,6 +115,7 @@ export declare class RunnerSession {
|
|
|
102
115
|
* new session AND tells the daemon to alias the runner (terminal transfer) so
|
|
103
116
|
* the new session stays injectable. */
|
|
104
117
|
private mirrorChannel;
|
|
118
|
+
private transferNativeSessionResources;
|
|
105
119
|
private enqueueMirror;
|
|
106
120
|
private sendMirroredEvent;
|
|
107
121
|
private sendMirrorImageFrame;
|
|
@@ -122,6 +136,7 @@ export declare class RunnerSession {
|
|
|
122
136
|
private inject;
|
|
123
137
|
private updateCollaborationMode;
|
|
124
138
|
private interruptLive;
|
|
139
|
+
private reapTerminal;
|
|
125
140
|
/** Launch (idempotently) the session's codex TUI pane from the executor's
|
|
126
141
|
* `codexTerminalSpec`. Shares the `${id}-main` terminal id with `term.open`,
|
|
127
142
|
* so the web attach reuses the same detached pane. */
|
|
@@ -132,10 +147,16 @@ export declare class RunnerSession {
|
|
|
132
147
|
private stopLive;
|
|
133
148
|
/** Stop event forwarding, kill native terminals/hooks, then synchronously
|
|
134
149
|
* scrub provider handoff files before the child process is allowed to exit. */
|
|
135
|
-
shutdown(): void
|
|
150
|
+
shutdown(): Promise<void>;
|
|
136
151
|
private openTerminal;
|
|
137
|
-
/**
|
|
152
|
+
/** Prepare captured history without starting the live control client. */
|
|
138
153
|
private attachExisting;
|
|
154
|
+
private readTerminalSeed;
|
|
155
|
+
private startTerminal;
|
|
156
|
+
private readTerminalOutput;
|
|
157
|
+
private writeTerminalInput;
|
|
158
|
+
private resizeTerminal;
|
|
159
|
+
private sendTerminalOperationError;
|
|
139
160
|
private runCap;
|
|
140
161
|
private dispatchCap;
|
|
141
162
|
}
|