@rynx-ai/runtime 0.1.11-beta.4 → 0.1.11-beta.41
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/executor.d.ts +19 -5
- package/dist/claude/executor.js +56 -12
- package/dist/claude/models.d.ts +0 -5
- package/dist/claude/models.js +1 -7
- package/dist/claude/native-bridge.d.ts +103 -1
- package/dist/claude/native-bridge.js +445 -30
- package/dist/claude/native-hook-main.js +81 -1
- package/dist/claude/native-hooks.js +7 -0
- package/dist/claude/native-integration.d.ts +178 -26
- package/dist/claude/native-integration.js +1528 -170
- package/dist/claude/session-status.d.ts +39 -0
- package/dist/claude/session-status.js +163 -0
- package/dist/claude/transcript-clone.d.ts +18 -0
- package/dist/claude/transcript-clone.js +497 -0
- package/dist/claude/transcript.d.ts +27 -4
- package/dist/claude/transcript.js +158 -47
- package/dist/codex-app-server/client.d.ts +10 -6
- package/dist/codex-app-server/client.js +67 -15
- package/dist/codex-app-server/forwarder.d.ts +92 -3
- package/dist/codex-app-server/forwarder.js +532 -57
- package/dist/codex-app-server/mapping.d.ts +3 -6
- package/dist/codex-app-server/mapping.js +206 -36
- 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/process-registry.d.ts +36 -0
- package/dist/codex-app-server/process-registry.js +320 -0
- package/dist/codex-app-server/protocol.d.ts +64 -7
- package/dist/codex-app-server/ws-channel.d.ts +7 -0
- package/dist/codex-app-server/ws-channel.js +104 -28
- package/dist/codex-home.d.ts +35 -3
- package/dist/codex-home.js +323 -18
- package/dist/codex-session-store.d.ts +23 -0
- package/dist/codex-session-store.js +21 -0
- package/dist/host.d.ts +103 -46
- package/dist/host.js +1988 -634
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/input-resources.d.ts +4 -0
- package/dist/input-resources.js +21 -5
- package/dist/models-catalog.d.ts +2 -1
- package/dist/models-catalog.js +94 -6
- package/dist/runner/child.d.ts +97 -28
- package/dist/runner/child.js +1486 -100
- package/dist/runner/manager.d.ts +110 -29
- package/dist/runner/manager.js +1481 -246
- package/dist/runner/protocol.d.ts +212 -24
- package/dist/runner/protocol.js +5 -0
- package/dist/runner/startup-policy.d.ts +7 -0
- package/dist/runner/startup-policy.js +10 -0
- package/dist/runner/transport.d.ts +18 -2
- package/dist/runner/transport.js +82 -3
- package/dist/runner-main.js +8 -3
- package/dist/terminal/claude-tui.d.ts +3 -1
- package/dist/terminal/claude-tui.js +3 -1
- 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 +18 -15
- package/dist/terminal/registry.js +44 -23
- package/dist/terminal/spool.d.ts +47 -0
- package/dist/terminal/spool.js +231 -0
- package/dist/terminal/tmux.d.ts +126 -74
- package/dist/terminal/tmux.js +807 -211
- package/package.json +4 -4
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure codex app-server notification → {@link AgentEvent} mapping. Extracted from
|
|
3
|
-
* the executor so BOTH the per-turn executor and the persistent session
|
|
4
|
-
* forwarder (which mirrors every thread turn — web- AND TUI-initiated — into the
|
|
5
|
-
* canonical log, reference implementation's codex-native model) share one mapping.
|
|
6
|
-
*/
|
|
7
1
|
import type { AgentEvent } from "@rynx-ai/core";
|
|
8
2
|
import type { ThreadItem } from "./protocol.js";
|
|
9
3
|
export interface CodexMapResult {
|
|
@@ -11,8 +5,11 @@ export interface CodexMapResult {
|
|
|
11
5
|
finalText?: string;
|
|
12
6
|
usage?: Record<string, unknown>;
|
|
13
7
|
turnCompleted?: boolean;
|
|
8
|
+
turnInterrupted?: boolean;
|
|
14
9
|
fatalError?: Error;
|
|
15
10
|
}
|
|
11
|
+
export declare function codexTurnStatus(turn: unknown): string | undefined;
|
|
12
|
+
export declare function codexResumeTerminalStatus(turn: unknown): "idle" | "failed" | undefined;
|
|
16
13
|
/** Map one thread item (`item/started` | `item/completed`) to events. */
|
|
17
14
|
export declare function mapCodexItem(method: string, item: ThreadItem): CodexMapResult;
|
|
18
15
|
/** Map one codex app-server notification to events (+ turn/usage/error signals). */
|
|
@@ -1,12 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure codex app-server notification → {@link AgentEvent} mapping. Extracted from
|
|
3
|
+
* the executor so BOTH the per-turn executor and the persistent session
|
|
4
|
+
* forwarder (which mirrors every thread turn — web- AND TUI-initiated — into the
|
|
5
|
+
* canonical log, reference implementation's codex-native model) share one mapping.
|
|
6
|
+
*/
|
|
7
|
+
import { extname, isAbsolute } from "node:path";
|
|
8
|
+
function isRecord(value) {
|
|
9
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
10
|
+
}
|
|
11
|
+
const CODEX_AUTH_ERROR_FRAGMENTS = [
|
|
12
|
+
"401",
|
|
13
|
+
"403",
|
|
14
|
+
"unauthorized",
|
|
15
|
+
"authentication",
|
|
16
|
+
"not logged in",
|
|
17
|
+
"not authenticated",
|
|
18
|
+
"log in",
|
|
19
|
+
"login",
|
|
20
|
+
"sign in",
|
|
21
|
+
"re-authenticate",
|
|
22
|
+
"reauthenticate",
|
|
23
|
+
"credentials",
|
|
24
|
+
"access token",
|
|
25
|
+
"token expired",
|
|
26
|
+
"expired token",
|
|
27
|
+
"session expired",
|
|
28
|
+
"api key",
|
|
29
|
+
];
|
|
30
|
+
const CODEX_REAUTH_HINT = "Codex needs you to re-authenticate. Run `codex login` and retry.";
|
|
31
|
+
function codexErrorMessage(error) {
|
|
32
|
+
for (const key of ["message", "error", "text", "detail"]) {
|
|
33
|
+
const value = error[key];
|
|
34
|
+
if (typeof value === "string" && value.trim())
|
|
35
|
+
return value.trim();
|
|
36
|
+
}
|
|
37
|
+
return "Codex turn ended with an unspecified error.";
|
|
38
|
+
}
|
|
39
|
+
function codexErrorIsAuth(error, message) {
|
|
40
|
+
const info = error.codexErrorInfo;
|
|
41
|
+
let variant;
|
|
42
|
+
let httpStatusCode;
|
|
43
|
+
if (typeof info === "string") {
|
|
44
|
+
variant = info;
|
|
45
|
+
}
|
|
46
|
+
else if (isRecord(info)) {
|
|
47
|
+
variant = info.type ?? info.kind ?? info.variant;
|
|
48
|
+
httpStatusCode = info.httpStatusCode;
|
|
49
|
+
}
|
|
50
|
+
if (typeof variant === "string" && variant.toLowerCase() === "unauthorized")
|
|
51
|
+
return true;
|
|
52
|
+
if (httpStatusCode === 401 || httpStatusCode === 403)
|
|
53
|
+
return true;
|
|
54
|
+
const lowered = message.toLowerCase();
|
|
55
|
+
return CODEX_AUTH_ERROR_FRAGMENTS.some((fragment) => lowered.includes(fragment));
|
|
56
|
+
}
|
|
1
57
|
function turnError(error, fallback) {
|
|
2
|
-
if (
|
|
3
|
-
return new Error(
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
58
|
+
if (!error)
|
|
59
|
+
return new Error(fallback);
|
|
60
|
+
const message = codexErrorMessage(error);
|
|
61
|
+
return new Error(codexErrorIsAuth(error, message)
|
|
62
|
+
? `${message}\n\n${CODEX_REAUTH_HINT}`
|
|
63
|
+
: message);
|
|
64
|
+
}
|
|
65
|
+
export function codexTurnStatus(turn) {
|
|
66
|
+
if (!isRecord(turn))
|
|
67
|
+
return undefined;
|
|
68
|
+
const status = turn.status;
|
|
69
|
+
if (typeof status === "string")
|
|
70
|
+
return status;
|
|
71
|
+
if (!isRecord(status))
|
|
72
|
+
return undefined;
|
|
73
|
+
const value = status.type ?? status.status;
|
|
74
|
+
return typeof value === "string" ? value : undefined;
|
|
75
|
+
}
|
|
76
|
+
export function codexResumeTerminalStatus(turn) {
|
|
77
|
+
if (terminalTurnError(turn, "turn/completed"))
|
|
78
|
+
return "failed";
|
|
79
|
+
const status = codexTurnStatus(turn);
|
|
80
|
+
if (status === "completed" || status === "interrupted" ||
|
|
81
|
+
status === "cancelled" || status === "canceled") {
|
|
82
|
+
return "idle";
|
|
83
|
+
}
|
|
84
|
+
if (status === "failed" || status === "errored")
|
|
85
|
+
return "failed";
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
function terminalTurnError(turn, method) {
|
|
89
|
+
if (!isRecord(turn)) {
|
|
90
|
+
return method === "turn/failed" ? new Error("Codex turn failed") : undefined;
|
|
91
|
+
}
|
|
92
|
+
let error = turn.error;
|
|
93
|
+
if (!isRecord(error) && Array.isArray(turn.items)) {
|
|
94
|
+
error = turn.items.find((item) => isRecord(item) && item.type === "error");
|
|
95
|
+
}
|
|
96
|
+
if (isRecord(error))
|
|
97
|
+
return turnError(error, "Codex turn failed");
|
|
98
|
+
const status = codexTurnStatus(turn);
|
|
99
|
+
if (method === "turn/failed" || status === "failed" || status === "errored") {
|
|
100
|
+
return turnError(undefined, "Codex turn failed");
|
|
8
101
|
}
|
|
9
|
-
return
|
|
102
|
+
return undefined;
|
|
10
103
|
}
|
|
11
104
|
function webSearchInput(item) {
|
|
12
105
|
const action = item.action;
|
|
@@ -29,6 +122,25 @@ function webSearchInput(item) {
|
|
|
29
122
|
}
|
|
30
123
|
return { id: item.id, query: item.query };
|
|
31
124
|
}
|
|
125
|
+
function fileChangeSummary(changes) {
|
|
126
|
+
const lines = [];
|
|
127
|
+
for (const change of changes) {
|
|
128
|
+
if (!isRecord(change))
|
|
129
|
+
continue;
|
|
130
|
+
if (typeof change.path !== "string")
|
|
131
|
+
continue;
|
|
132
|
+
const kind = isRecord(change.kind) && typeof change.kind.type === "string" && change.kind.type
|
|
133
|
+
? change.kind.type
|
|
134
|
+
: "change";
|
|
135
|
+
lines.push(`${kind} ${change.path}`);
|
|
136
|
+
}
|
|
137
|
+
return lines.join("\n");
|
|
138
|
+
}
|
|
139
|
+
function isSupportedAbsoluteImagePath(path) {
|
|
140
|
+
if (!isAbsolute(path))
|
|
141
|
+
return false;
|
|
142
|
+
return [".png", ".jpg", ".jpeg", ".webp", ".gif", ".svg"].includes(extname(path).toLowerCase());
|
|
143
|
+
}
|
|
32
144
|
/** Map one thread item (`item/started` | `item/completed`) to events. */
|
|
33
145
|
export function mapCodexItem(method, item) {
|
|
34
146
|
const events = [];
|
|
@@ -37,20 +149,37 @@ export function mapCodexItem(method, item) {
|
|
|
37
149
|
switch (item.type) {
|
|
38
150
|
case "commandExecution": {
|
|
39
151
|
const commandItem = item;
|
|
152
|
+
const id = typeof commandItem.id === "string" ? commandItem.id : "";
|
|
153
|
+
const command = typeof commandItem.command === "string" ? commandItem.command : "";
|
|
154
|
+
if (!id || !command)
|
|
155
|
+
return { events };
|
|
156
|
+
const exitCode = typeof commandItem.exitCode === "number"
|
|
157
|
+
? commandItem.exitCode
|
|
158
|
+
: null;
|
|
159
|
+
const rawOutput = commandItem.aggregatedOutput ?? "";
|
|
160
|
+
const aggregatedOutput = exitCode !== null && exitCode !== 0
|
|
161
|
+
? `${rawOutput}${rawOutput ? "\n" : ""}[exit code: ${exitCode}]`
|
|
162
|
+
: rawOutput;
|
|
40
163
|
events.push({
|
|
41
164
|
type: "tool",
|
|
42
165
|
event: isStart ? "on_tool_start" : "on_tool_end",
|
|
43
|
-
name: "
|
|
44
|
-
input: isStart
|
|
45
|
-
? {
|
|
166
|
+
name: "shell",
|
|
167
|
+
input: isStart || isEnd
|
|
168
|
+
? {
|
|
169
|
+
id,
|
|
170
|
+
command,
|
|
171
|
+
...(typeof commandItem.cwd === "string" && commandItem.cwd
|
|
172
|
+
? { cwd: commandItem.cwd }
|
|
173
|
+
: {}),
|
|
174
|
+
}
|
|
46
175
|
: undefined,
|
|
47
176
|
output: isEnd
|
|
48
177
|
? {
|
|
49
|
-
id
|
|
50
|
-
command
|
|
178
|
+
id,
|
|
179
|
+
command,
|
|
51
180
|
status: commandItem.status,
|
|
52
|
-
aggregatedOutput
|
|
53
|
-
exitCode
|
|
181
|
+
aggregatedOutput,
|
|
182
|
+
exitCode,
|
|
54
183
|
}
|
|
55
184
|
: undefined,
|
|
56
185
|
data: { method, item },
|
|
@@ -58,16 +187,23 @@ export function mapCodexItem(method, item) {
|
|
|
58
187
|
return { events };
|
|
59
188
|
}
|
|
60
189
|
case "fileChange": {
|
|
190
|
+
const fileChange = item;
|
|
191
|
+
const changes = Array.isArray(fileChange.changes) ? fileChange.changes : [];
|
|
192
|
+
const id = typeof item.id === "string" ? item.id : "";
|
|
193
|
+
if (!id ||
|
|
194
|
+
changes.length === 0 ||
|
|
195
|
+
!changes.some((change) => isRecord(change) && typeof change.path === "string"))
|
|
196
|
+
return { events };
|
|
61
197
|
events.push({
|
|
62
198
|
type: "tool",
|
|
63
199
|
event: isStart ? "on_tool_start" : "on_tool_end",
|
|
64
|
-
name: "
|
|
65
|
-
input: isStart ? { id
|
|
200
|
+
name: "apply_patch",
|
|
201
|
+
input: isStart || isEnd ? { id, changes } : undefined,
|
|
66
202
|
output: isEnd
|
|
67
203
|
? {
|
|
68
|
-
id
|
|
69
|
-
|
|
70
|
-
|
|
204
|
+
id,
|
|
205
|
+
status: fileChange.status,
|
|
206
|
+
aggregatedOutput: fileChangeSummary(changes),
|
|
71
207
|
}
|
|
72
208
|
: undefined,
|
|
73
209
|
data: { method, item },
|
|
@@ -113,6 +249,30 @@ export function mapCodexItem(method, item) {
|
|
|
113
249
|
});
|
|
114
250
|
return { events };
|
|
115
251
|
}
|
|
252
|
+
case "imageGeneration": {
|
|
253
|
+
const image = item;
|
|
254
|
+
events.push({
|
|
255
|
+
type: "tool",
|
|
256
|
+
event: isStart ? "on_tool_start" : "on_tool_end",
|
|
257
|
+
name: "image_generation",
|
|
258
|
+
input: isStart ? { id: image.id } : undefined,
|
|
259
|
+
output: isEnd
|
|
260
|
+
? {
|
|
261
|
+
id: image.id,
|
|
262
|
+
status: image.status,
|
|
263
|
+
generatedImage: {
|
|
264
|
+
...(!image.savedPath || !isSupportedAbsoluteImagePath(image.savedPath)
|
|
265
|
+
? { result: image.result }
|
|
266
|
+
: {}),
|
|
267
|
+
revisedPrompt: image.revisedPrompt,
|
|
268
|
+
...(image.savedPath ? { savedPath: image.savedPath } : {}),
|
|
269
|
+
},
|
|
270
|
+
}
|
|
271
|
+
: undefined,
|
|
272
|
+
data: { method, item: { ...image, result: image.result ? "[image data omitted]" : "" } },
|
|
273
|
+
});
|
|
274
|
+
return { events };
|
|
275
|
+
}
|
|
116
276
|
case "agentMessage": {
|
|
117
277
|
const text = item.text?.trim() ?? "";
|
|
118
278
|
if (isEnd && text) {
|
|
@@ -122,7 +282,11 @@ export function mapCodexItem(method, item) {
|
|
|
122
282
|
return { events };
|
|
123
283
|
}
|
|
124
284
|
case "plan": {
|
|
125
|
-
|
|
285
|
+
const text = item.text?.trim() ?? "";
|
|
286
|
+
if (isEnd && text) {
|
|
287
|
+
events.push({ type: "message_completed", itemId: item.id, text });
|
|
288
|
+
return { events, finalText: text };
|
|
289
|
+
}
|
|
126
290
|
return { events };
|
|
127
291
|
}
|
|
128
292
|
case "reasoning": {
|
|
@@ -151,23 +315,18 @@ export function mapCodexNotification(method, params) {
|
|
|
151
315
|
return { events };
|
|
152
316
|
case "turn/started":
|
|
153
317
|
return { events };
|
|
154
|
-
case "turn/completed":
|
|
318
|
+
case "turn/completed":
|
|
319
|
+
case "turn/failed": {
|
|
155
320
|
const turnPayload = typed.params?.turn;
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
events,
|
|
166
|
-
fatalError: turnError(turnPayload.error, "Codex turn was interrupted"),
|
|
167
|
-
turnCompleted: true,
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
return { events, turnCompleted: true };
|
|
321
|
+
const fatalError = terminalTurnError(turnPayload, typed.method);
|
|
322
|
+
const turnInterrupted = typed.method === "turn/completed" &&
|
|
323
|
+
["interrupted", "cancelled", "canceled"].includes(codexTurnStatus(turnPayload) ?? "");
|
|
324
|
+
return {
|
|
325
|
+
events,
|
|
326
|
+
...(fatalError ? { fatalError } : {}),
|
|
327
|
+
turnCompleted: true,
|
|
328
|
+
...(turnInterrupted ? { turnInterrupted: true } : {}),
|
|
329
|
+
};
|
|
171
330
|
}
|
|
172
331
|
case "turn/plan/updated": {
|
|
173
332
|
const planParams = typed.params;
|
|
@@ -195,6 +354,17 @@ export function mapCodexNotification(method, params) {
|
|
|
195
354
|
}
|
|
196
355
|
return { events };
|
|
197
356
|
}
|
|
357
|
+
case "item/plan/delta": {
|
|
358
|
+
const delta = typed.params.delta ?? "";
|
|
359
|
+
if (delta) {
|
|
360
|
+
events.push({
|
|
361
|
+
type: "token",
|
|
362
|
+
text: delta,
|
|
363
|
+
metadata: { source: "app_server", itemId: typed.params.itemId },
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
return { events };
|
|
367
|
+
}
|
|
198
368
|
case "item/reasoning/summaryTextDelta":
|
|
199
369
|
case "item/reasoning/textDelta": {
|
|
200
370
|
const p = typed.params;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CodexLineageRuntime } from "../codex-home.js";
|
|
2
|
+
export interface McpStartupPlan {
|
|
3
|
+
servers: string[];
|
|
4
|
+
settleTimeoutMs: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Read the MCP table fields needed for startup tracking. Provider config stays
|
|
8
|
+
* authoritative: malformed TOML disables the synthesized status rather than
|
|
9
|
+
* preventing the native CLI from reporting its own startup error.
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseMcpStartupToml(input: string): McpStartupPlan | null;
|
|
12
|
+
/** Enabled Provider-configured MCP servers and their synthesized settle window. */
|
|
13
|
+
export declare function readMcpStartupPlan(runtimeHome: string, runtime: CodexLineageRuntime): McpStartupPlan | null;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { parse } from "smol-toml";
|
|
4
|
+
const DEFAULT_SERVER_TIMEOUT_MS = 10_000;
|
|
5
|
+
const SETTLE_GRACE_MS = 15_000;
|
|
6
|
+
const MAX_SETTLE_TIMEOUT_MS = 240_000;
|
|
7
|
+
function configNames(runtime) {
|
|
8
|
+
return runtime === "codex"
|
|
9
|
+
? ["config.toml"]
|
|
10
|
+
: ["traecli.toml"];
|
|
11
|
+
}
|
|
12
|
+
function isTomlTable(value) {
|
|
13
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Read the MCP table fields needed for startup tracking. Provider config stays
|
|
17
|
+
* authoritative: malformed TOML disables the synthesized status rather than
|
|
18
|
+
* preventing the native CLI from reporting its own startup error.
|
|
19
|
+
*/
|
|
20
|
+
export function parseMcpStartupToml(input) {
|
|
21
|
+
let config;
|
|
22
|
+
try {
|
|
23
|
+
config = parse(input);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const servers = config.mcp_servers;
|
|
29
|
+
if (!isTomlTable(servers))
|
|
30
|
+
return null;
|
|
31
|
+
const enabled = Object.entries(servers)
|
|
32
|
+
.filter(([name, server]) => Boolean(name) && isTomlTable(server) && server.enabled !== false)
|
|
33
|
+
.sort(([left], [right]) => left.localeCompare(right));
|
|
34
|
+
if (enabled.length === 0)
|
|
35
|
+
return null;
|
|
36
|
+
const slowest = Math.max(DEFAULT_SERVER_TIMEOUT_MS, ...enabled.map(([, server]) => {
|
|
37
|
+
if (!isTomlTable(server))
|
|
38
|
+
return DEFAULT_SERVER_TIMEOUT_MS;
|
|
39
|
+
const seconds = server.startup_timeout_sec;
|
|
40
|
+
return typeof seconds === "number" && Number.isFinite(seconds) && seconds > 0
|
|
41
|
+
? seconds * 1_000
|
|
42
|
+
: DEFAULT_SERVER_TIMEOUT_MS;
|
|
43
|
+
}));
|
|
44
|
+
return {
|
|
45
|
+
servers: enabled.map(([name]) => name),
|
|
46
|
+
settleTimeoutMs: Math.min(slowest + SETTLE_GRACE_MS, MAX_SETTLE_TIMEOUT_MS),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/** Enabled Provider-configured MCP servers and their synthesized settle window. */
|
|
50
|
+
export function readMcpStartupPlan(runtimeHome, runtime) {
|
|
51
|
+
for (const name of configNames(runtime)) {
|
|
52
|
+
try {
|
|
53
|
+
const plan = parseMcpStartupToml(readFileSync(join(runtimeHome, name), "utf8"));
|
|
54
|
+
if (plan)
|
|
55
|
+
return plan;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Missing/unreadable config: the Provider still owns startup; Rynx simply
|
|
59
|
+
// cannot synthesize per-server progress for this launch.
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface RuntimeProcessEntry {
|
|
2
|
+
pid: number;
|
|
3
|
+
pgid: number;
|
|
4
|
+
ownerPid: number;
|
|
5
|
+
/** OS process-start identity. Unlike a PID, this cannot silently refer to a
|
|
6
|
+
* later process after the launcher crashes and the PID is recycled. */
|
|
7
|
+
ownerIdentity?: string;
|
|
8
|
+
sessionTag: string;
|
|
9
|
+
stateDir: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function runtimeProcessRegistryPath(): string;
|
|
12
|
+
export declare function runtimeProcessTagArg(sessionTag: string): string;
|
|
13
|
+
export declare function runtimeProcessArgv0(cliPath: string, sessionTag: string): string;
|
|
14
|
+
export declare function withRuntimeProcessStateArg(baseArgs: string[], stateDir: string): string[];
|
|
15
|
+
export declare function registerRuntimeProcess(entry: RuntimeProcessEntry, registryPath?: string): void;
|
|
16
|
+
export declare function unregisterRuntimeProcess(sessionTag: string, registryPath?: string): void;
|
|
17
|
+
export interface RuntimeProcessReconcileOptions {
|
|
18
|
+
registryPath?: string;
|
|
19
|
+
ownerAlive?: (pid: number) => boolean;
|
|
20
|
+
ownerIdentity?: (pid: number) => string;
|
|
21
|
+
childAlive?: (pid: number) => boolean;
|
|
22
|
+
commandLine?: (pid: number) => string;
|
|
23
|
+
terminateGroup?: (pgid: number) => boolean;
|
|
24
|
+
}
|
|
25
|
+
export declare function reconcileRuntimeProcesses(opts?: RuntimeProcessReconcileOptions): number;
|
|
26
|
+
export declare function reapRuntimeProcessesForStateDir(stateDir: string, opts?: RuntimeProcessStateReapOptions): number;
|
|
27
|
+
export interface RuntimeProcessStateReapOptions {
|
|
28
|
+
processListing?: () => string;
|
|
29
|
+
currentPgid?: () => number;
|
|
30
|
+
childAlive?: (pid: number) => boolean;
|
|
31
|
+
signalGroup?: (pgid: number, signal: NodeJS.Signals) => boolean;
|
|
32
|
+
graceMs?: number;
|
|
33
|
+
}
|
|
34
|
+
/** Return an OS process-start identity used to distinguish PID reuse. */
|
|
35
|
+
export declare function runtimeProcessOwnerIdentity(pid: number): string;
|
|
36
|
+
export declare function newRuntimeProcessTag(): string;
|