@rynx-ai/runtime 0.1.11-beta.2 → 0.1.11-beta.21
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/models.d.ts +0 -5
- package/dist/claude/models.js +1 -7
- package/dist/claude/native-integration.d.ts +35 -7
- package/dist/claude/native-integration.js +204 -32
- package/dist/claude/session-status.d.ts +39 -0
- package/dist/claude/session-status.js +163 -0
- package/dist/codex-app-server/forwarder.d.ts +66 -2
- package/dist/codex-app-server/forwarder.js +329 -11
- package/dist/codex-app-server/mapping.d.ts +2 -0
- package/dist/codex-app-server/mapping.js +97 -23
- 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/protocol.d.ts +8 -5
- package/dist/codex-app-server/ws-channel.js +19 -19
- package/dist/codex-home.js +2 -4
- package/dist/host.d.ts +28 -7
- package/dist/host.js +356 -92
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/models-catalog.d.ts +2 -1
- package/dist/models-catalog.js +82 -3
- package/dist/runner/child.d.ts +22 -6
- package/dist/runner/child.js +237 -30
- package/dist/runner/manager.d.ts +87 -4
- package/dist/runner/manager.js +610 -56
- package/dist/runner/protocol.d.ts +11 -15
- package/dist/runner/startup-policy.d.ts +4 -0
- package/dist/runner/startup-policy.js +5 -0
- package/dist/terminal/claude-tui.d.ts +3 -1
- package/dist/terminal/claude-tui.js +3 -1
- package/dist/terminal/tmux.d.ts +29 -2
- package/dist/terminal/tmux.js +122 -14
- package/package.json +4 -3
|
@@ -105,11 +105,14 @@ export interface ThreadStartParams {
|
|
|
105
105
|
}
|
|
106
106
|
export interface ThreadResumeParams extends ThreadStartParams {
|
|
107
107
|
threadId: string;
|
|
108
|
-
/**
|
|
109
|
-
*
|
|
110
|
-
* carries `thread.turns[].items[]` — the backfill the forwarder replays for a
|
|
111
|
-
* fresh thread's first turn (reference implementation's `_replay_resume_response`). */
|
|
108
|
+
/** Legacy whole-backlog suppression. New callers should prefer
|
|
109
|
+
* `initialTurnsPage` so recovery can fetch one summarized terminal status. */
|
|
112
110
|
excludeTurns?: boolean;
|
|
111
|
+
initialTurnsPage?: {
|
|
112
|
+
limit?: number | null;
|
|
113
|
+
sortDirection?: "asc" | "desc" | null;
|
|
114
|
+
itemsView?: "notLoaded" | "summary" | "full" | null;
|
|
115
|
+
} | null;
|
|
113
116
|
}
|
|
114
117
|
/** One turn in a resumed thread's backlog (`thread/resume` response). */
|
|
115
118
|
export interface ResumedTurn {
|
|
@@ -169,7 +172,7 @@ export interface TurnSteerParams {
|
|
|
169
172
|
expectedTurnId: string;
|
|
170
173
|
input: UserInput[];
|
|
171
174
|
}
|
|
172
|
-
export type TurnStatus = "completed" | "interrupted" | "failed" | "inProgress";
|
|
175
|
+
export type TurnStatus = "completed" | "interrupted" | "cancelled" | "canceled" | "failed" | "errored" | "inProgress";
|
|
173
176
|
export interface TurnPlanStep {
|
|
174
177
|
step: string;
|
|
175
178
|
status: "pending" | "inProgress" | "completed";
|
|
@@ -28,6 +28,7 @@ async function freeLoopbackPort() {
|
|
|
28
28
|
});
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
|
+
const DEFAULT_CONNECT_TIMEOUT_MS = 10_000;
|
|
31
32
|
export class WsRpcChannel {
|
|
32
33
|
opts;
|
|
33
34
|
child = null;
|
|
@@ -40,7 +41,7 @@ export class WsRpcChannel {
|
|
|
40
41
|
url = "";
|
|
41
42
|
constructor(opts) {
|
|
42
43
|
this.opts = opts;
|
|
43
|
-
this.readyTimeoutMs = opts.readyTimeoutMs ??
|
|
44
|
+
this.readyTimeoutMs = opts.readyTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS;
|
|
44
45
|
}
|
|
45
46
|
onLine(cb) {
|
|
46
47
|
this.lineCb = cb;
|
|
@@ -114,7 +115,7 @@ export class WsRpcChannel {
|
|
|
114
115
|
// eslint-disable-next-line no-constant-condition
|
|
115
116
|
while (Date.now() < deadline) {
|
|
116
117
|
try {
|
|
117
|
-
return await this.tryConnect(url);
|
|
118
|
+
return await this.tryConnect(url, Math.max(1, deadline - Date.now()));
|
|
118
119
|
}
|
|
119
120
|
catch (error) {
|
|
120
121
|
lastError = error;
|
|
@@ -123,9 +124,9 @@ export class WsRpcChannel {
|
|
|
123
124
|
}
|
|
124
125
|
throw new Error(`codex app-server ws did not become ready at ${url}: ${lastError?.message ?? "timeout"}`);
|
|
125
126
|
}
|
|
126
|
-
tryConnect(url) {
|
|
127
|
+
tryConnect(url, handshakeTimeout) {
|
|
127
128
|
return new Promise((resolve, reject) => {
|
|
128
|
-
const ws = new WebSocket(url);
|
|
129
|
+
const ws = new WebSocket(url, { handshakeTimeout });
|
|
129
130
|
const onOpen = () => {
|
|
130
131
|
ws.off("error", onError);
|
|
131
132
|
resolve(ws);
|
|
@@ -166,7 +167,7 @@ export class ExternalWsChannel {
|
|
|
166
167
|
/** The `ws://IP:PORT` of the already-running app-server to attach to. */
|
|
167
168
|
url, opts = {}) {
|
|
168
169
|
this.url = url;
|
|
169
|
-
this.readyTimeoutMs = opts.readyTimeoutMs ??
|
|
170
|
+
this.readyTimeoutMs = opts.readyTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS;
|
|
170
171
|
}
|
|
171
172
|
onLine(cb) {
|
|
172
173
|
this.lineCb = cb;
|
|
@@ -178,20 +179,16 @@ export class ExternalWsChannel {
|
|
|
178
179
|
return this.ws?.readyState === WebSocket.OPEN;
|
|
179
180
|
}
|
|
180
181
|
async start() {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
catch (error) {
|
|
189
|
-
lastError = error;
|
|
190
|
-
await new Promise((r) => setTimeout(r, 150));
|
|
191
|
-
}
|
|
182
|
+
// A channel instance is reusable after an observer disconnect. Do not let
|
|
183
|
+
// the prior closed socket make a failed reconnect look successful, and arm
|
|
184
|
+
// close delivery for the newly connected socket.
|
|
185
|
+
this.ws = null;
|
|
186
|
+
this.closedEmitted = false;
|
|
187
|
+
try {
|
|
188
|
+
this.ws = await this.connect(this.url);
|
|
192
189
|
}
|
|
193
|
-
|
|
194
|
-
throw new Error(`could not attach to app-server ws ${this.url}: ${
|
|
190
|
+
catch (error) {
|
|
191
|
+
throw new Error(`could not attach to app-server ws ${this.url}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
195
192
|
}
|
|
196
193
|
this.ws.on("message", (data) => this.lineCb?.(data.toString()));
|
|
197
194
|
this.ws.on("close", (code) => this.emitClose(code ?? null, null, null));
|
|
@@ -227,7 +224,10 @@ export class ExternalWsChannel {
|
|
|
227
224
|
}
|
|
228
225
|
connect(url) {
|
|
229
226
|
return new Promise((resolve, reject) => {
|
|
230
|
-
|
|
227
|
+
// The app-server owner has already completed its readiness probe. Use one
|
|
228
|
+
// bounded attach, then reuse this exact connection as the forwarder
|
|
229
|
+
// instead of running a second startup retry stage.
|
|
230
|
+
const ws = new WebSocket(url, { handshakeTimeout: this.readyTimeoutMs });
|
|
231
231
|
const onOpen = () => {
|
|
232
232
|
ws.off("error", onError);
|
|
233
233
|
resolve(ws);
|
package/dist/codex-home.js
CHANGED
|
@@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import { copyFileSync, cpSync, existsSync, mkdirSync, renameSync, rmSync, symlinkSync } from "node:fs";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
5
|
-
import { getRuntimeProfile, resolveRuntimeHome,
|
|
5
|
+
import { assertSkillPathComponent, getRuntimeProfile, resolveRuntimeHome, } from "@rynx-ai/core";
|
|
6
6
|
import { adoptLegacyRuntimeDirectory, legacyRuntimeStateRoot, runtimeSessionDigest, runtimeSessionStateDir, } from "./runtime-state-paths.js";
|
|
7
7
|
/** Inherit the user's LIVE login by symlink (stays in sync). */
|
|
8
8
|
const SYMLINK_FILES = ["auth.json"];
|
|
@@ -113,9 +113,7 @@ export function prepareRuntimeHome(sessionId, runtime, realHome = runtime === "c
|
|
|
113
113
|
export function populateCodexSkills(codexHome, skills) {
|
|
114
114
|
const skillsDir = join(codexHome, "skills");
|
|
115
115
|
for (const skill of skills) {
|
|
116
|
-
|
|
117
|
-
throw new Error(`unsafe skill name: ${skill.name}`);
|
|
118
|
-
}
|
|
116
|
+
assertSkillPathComponent(skill.name);
|
|
119
117
|
}
|
|
120
118
|
if (skills.length === 0)
|
|
121
119
|
return;
|
package/dist/host.d.ts
CHANGED
|
@@ -125,6 +125,7 @@ export declare class LocalAgentHost implements CodexCapabilities {
|
|
|
125
125
|
private readonly clock;
|
|
126
126
|
private readonly backendIdleTtlMs;
|
|
127
127
|
private readonly forwarderClientFactory;
|
|
128
|
+
private readonly observerReconnectTimeoutMs;
|
|
128
129
|
private readonly backends;
|
|
129
130
|
private readonly sessionId;
|
|
130
131
|
private readonly runtimeHomeSessionId;
|
|
@@ -133,6 +134,10 @@ export declare class LocalAgentHost implements CodexCapabilities {
|
|
|
133
134
|
private readonly runtimeHomes;
|
|
134
135
|
private readonly liveSessions;
|
|
135
136
|
private readonly liveClaudeSessions;
|
|
137
|
+
/** Exact pre-live startup failure, retained after the partial handle has been
|
|
138
|
+
* cleaned up so Core/plugin callers receive the failed phase, not a generic
|
|
139
|
+
* `live session unavailable` wrapper. */
|
|
140
|
+
private readonly liveStartupErrors;
|
|
136
141
|
/** Claude forwarders stopped before their terminal is killed. Runner shutdown
|
|
137
142
|
* finalizes these synchronously afterwards to scrub raw interaction answers. */
|
|
138
143
|
private readonly pendingClaudeFinalizers;
|
|
@@ -141,7 +146,7 @@ export declare class LocalAgentHost implements CodexCapabilities {
|
|
|
141
146
|
/** Short-lived dedupe for managed fork notifications delivered after the
|
|
142
147
|
* `thread/fork` response. Values are expected source Provider thread ids. */
|
|
143
148
|
private readonly managedForkThreadStarts;
|
|
144
|
-
constructor({ config, commandRunner, sessionStore, allowedRoots, appServerClient, now, backendIdleTtlMs, forwarderClientFactory, sessionId, runtimeHomeSessionId, }: {
|
|
149
|
+
constructor({ config, commandRunner, sessionStore, allowedRoots, appServerClient, now, backendIdleTtlMs, forwarderClientFactory, observerReconnectTimeoutMs, sessionId, runtimeHomeSessionId, }: {
|
|
145
150
|
config: AppConfig;
|
|
146
151
|
commandRunner?: CodexCommandRunner;
|
|
147
152
|
sessionStore?: CodexSessionStore;
|
|
@@ -153,6 +158,8 @@ export declare class LocalAgentHost implements CodexCapabilities {
|
|
|
153
158
|
backendIdleTtlMs?: number;
|
|
154
159
|
/** Override the live-session forwarder connection factory (tests inject a fake). */
|
|
155
160
|
forwarderClientFactory?: (appServerUrl: string) => CodexAppServerClient;
|
|
161
|
+
/** Grace window for observer reconnect before an active response is failed. */
|
|
162
|
+
observerReconnectTimeoutMs?: number;
|
|
156
163
|
/** The rynx session (localThreadId) this host serves — a per-session runner
|
|
157
164
|
* child sets it from `RYNX_RUNNER_SESSION` so the private CODEX_HOME is
|
|
158
165
|
* session-scoped. The shared `__cap__` child / tests fall back to a sentinel
|
|
@@ -191,6 +198,7 @@ export declare class LocalAgentHost implements CodexCapabilities {
|
|
|
191
198
|
args: string[];
|
|
192
199
|
cwd: string;
|
|
193
200
|
env?: Record<string, string>;
|
|
201
|
+
skipTraexStartupPrompts?: boolean;
|
|
194
202
|
} | null>;
|
|
195
203
|
/**
|
|
196
204
|
* Bring up (idempotently) a session's persistent codex forwarder and emit its
|
|
@@ -217,20 +225,31 @@ export declare class LocalAgentHost implements CodexCapabilities {
|
|
|
217
225
|
* Subscribe the forwarder connection to a thread (reference implementation's
|
|
218
226
|
* `_subscribe_until_ready`). A fresh TUI thread has no rollout until its first
|
|
219
227
|
* turn, so `thread/resume` is retried: park until the forwarder observes the
|
|
220
|
-
* thread active, then retry
|
|
221
|
-
*
|
|
222
|
-
*
|
|
228
|
+
* thread active, then retry. Resume only fetches the newest summarized Turn:
|
|
229
|
+
* recovery reconciles the exact active Turn or publishes the newest explicit
|
|
230
|
+
* terminal status without replaying historical items. Once resume succeeds,
|
|
231
|
+
* subsequent turns arrive live.
|
|
223
232
|
*/
|
|
224
233
|
private subscribeUntilReady;
|
|
225
|
-
/**
|
|
234
|
+
/** Restore the independent observer after an unexpected exit. The active turn
|
|
235
|
+
* remains open during the bounded grace so resume can reconcile its exact id. */
|
|
236
|
+
private reconnectForwarder;
|
|
237
|
+
private armObserverReconnectDeadline;
|
|
238
|
+
private clearObserverReconnectDeadline;
|
|
239
|
+
/** Await a live session's thread binding. `null` leaves the deadline to the
|
|
240
|
+
* caller; a number keeps the Provider-local bound. Returns false on timeout /
|
|
226
241
|
* no live session. Injection and the runner's `live.ready` gate on this. */
|
|
227
|
-
waitLiveReady(localThreadId: string, timeoutMs?: number): Promise<boolean>;
|
|
242
|
+
waitLiveReady(localThreadId: string, timeoutMs?: number | null): Promise<boolean>;
|
|
228
243
|
/** Await the stronger Terminal gate: another app-server connection has
|
|
229
244
|
* successfully resumed the thread, so the detached TUI cannot race rollout
|
|
230
245
|
* discovery or indexing. */
|
|
231
|
-
waitTerminalReady(localThreadId: string, timeoutMs?: number): Promise<boolean>;
|
|
246
|
+
waitTerminalReady(localThreadId: string, timeoutMs?: number | null): Promise<boolean>;
|
|
232
247
|
/** Diagnostic from the provider adapter when native discovery/resume failed. */
|
|
233
248
|
liveSessionError(localThreadId: string): string | undefined;
|
|
249
|
+
/** Publish the background TUI/thread discovery failure so an executor
|
|
250
|
+
* already waiting in the 60s bridge window exits immediately with the exact
|
|
251
|
+
* 30s discovery cause. */
|
|
252
|
+
failLiveStartup(localThreadId: string, error: Error): boolean;
|
|
234
253
|
/**
|
|
235
254
|
* Inject a user turn into a session's live codex thread — reference implementation's
|
|
236
255
|
* single-writer web send. `turn/steer` when a turn is open (mid-turn
|
|
@@ -290,6 +309,8 @@ export declare class LocalAgentHost implements CodexCapabilities {
|
|
|
290
309
|
* terminal registry — the host does not hold tmux). Ignored for codex sessions
|
|
291
310
|
* (they inject via the app-server). Idempotent. */
|
|
292
311
|
attachTerminalInjector(localThreadId: string, injector: TerminalInjector): void;
|
|
312
|
+
/** Close an active native response when its terminal or runner disappears. */
|
|
313
|
+
failLiveSession(localThreadId: string, error: Error): boolean;
|
|
293
314
|
/** List the models a runtime exposes (App Server for codex/traex; static for claude). */
|
|
294
315
|
listModels(runtime?: AgentRuntimeId): Promise<ModelListResponse | null>;
|
|
295
316
|
/**
|