@rynx-ai/runtime 0.1.11-beta.5 → 0.1.11-beta.51
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 +460 -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 +1571 -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 +183 -46
- 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 +96 -3
- package/dist/codex-app-server/forwarder.js +542 -57
- package/dist/codex-app-server/mapping.d.ts +3 -6
- package/dist/codex-app-server/mapping.js +228 -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 +68 -7
- package/dist/codex-app-server/transport.d.ts +2 -2
- package/dist/codex-app-server/transport.js +4 -0
- package/dist/codex-app-server/ws-channel.d.ts +8 -1
- package/dist/codex-app-server/ws-channel.js +113 -28
- package/dist/codex-child-env.js +3 -32
- 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 +106 -48
- package/dist/host.js +2024 -640
- 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.js +12 -3
- package/dist/runner/child.d.ts +105 -28
- package/dist/runner/child.js +1625 -100
- package/dist/runner/manager.d.ts +114 -46
- package/dist/runner/manager.js +1523 -446
- 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/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
|
@@ -14,8 +14,11 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { spawn } from "node:child_process";
|
|
16
16
|
import { createServer } from "node:net";
|
|
17
|
+
import { join } from "node:path";
|
|
18
|
+
import { diagnosticEvents, teeDiagnosticStream } from "@rynx-ai/core";
|
|
17
19
|
import { WebSocket } from "ws";
|
|
18
20
|
import { createCodexChildEnv } from "../codex-child-env.js";
|
|
21
|
+
import { newRuntimeProcessTag, reconcileRuntimeProcesses, registerRuntimeProcess, runtimeProcessArgv0, runtimeProcessOwnerIdentity, unregisterRuntimeProcess, withRuntimeProcessStateArg, } from "./process-registry.js";
|
|
19
22
|
/** Reserve a free loopback TCP port (best-effort; racy but fine for local use). */
|
|
20
23
|
async function freeLoopbackPort() {
|
|
21
24
|
return await new Promise((resolve, reject) => {
|
|
@@ -28,6 +31,7 @@ async function freeLoopbackPort() {
|
|
|
28
31
|
});
|
|
29
32
|
});
|
|
30
33
|
}
|
|
34
|
+
const DEFAULT_CONNECT_TIMEOUT_MS = 10_000;
|
|
31
35
|
export class WsRpcChannel {
|
|
32
36
|
opts;
|
|
33
37
|
child = null;
|
|
@@ -35,12 +39,14 @@ export class WsRpcChannel {
|
|
|
35
39
|
lineCb = null;
|
|
36
40
|
closeCb = null;
|
|
37
41
|
closedEmitted = false;
|
|
42
|
+
processTag = null;
|
|
43
|
+
stopTask = null;
|
|
38
44
|
readyTimeoutMs;
|
|
39
45
|
/** The `ws://IP:PORT` the app-server listens on — pass to the TUI's `--remote`. */
|
|
40
46
|
url = "";
|
|
41
47
|
constructor(opts) {
|
|
42
48
|
this.opts = opts;
|
|
43
|
-
this.readyTimeoutMs = opts.readyTimeoutMs ??
|
|
49
|
+
this.readyTimeoutMs = opts.readyTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS;
|
|
44
50
|
}
|
|
45
51
|
onLine(cb) {
|
|
46
52
|
this.lineCb = cb;
|
|
@@ -52,16 +58,55 @@ export class WsRpcChannel {
|
|
|
52
58
|
return this.ws?.readyState === WebSocket.OPEN;
|
|
53
59
|
}
|
|
54
60
|
async start() {
|
|
61
|
+
this.stopTask = null;
|
|
62
|
+
this.closedEmitted = false;
|
|
63
|
+
if (this.opts.stateDir) {
|
|
64
|
+
reconcileRuntimeProcesses();
|
|
65
|
+
}
|
|
55
66
|
const port = await freeLoopbackPort();
|
|
56
67
|
this.url = `ws://127.0.0.1:${port}`;
|
|
57
|
-
const
|
|
68
|
+
const baseArgs = this.opts.stateDir
|
|
69
|
+
? withRuntimeProcessStateArg(this.opts.baseArgs, this.opts.stateDir)
|
|
70
|
+
: this.opts.baseArgs;
|
|
71
|
+
const args = [...baseArgs, "--listen", this.url];
|
|
72
|
+
const processTag = this.opts.stateDir ? newRuntimeProcessTag() : null;
|
|
73
|
+
this.processTag = processTag;
|
|
58
74
|
this.child = spawn(this.opts.cliPath, args, {
|
|
59
75
|
stdio: ["ignore", "ignore", "pipe"],
|
|
60
76
|
env: { ...createCodexChildEnv(process.env), ...(this.opts.extraEnv ?? {}) },
|
|
77
|
+
detached: process.platform !== "win32",
|
|
78
|
+
...(processTag ? { argv0: runtimeProcessArgv0(this.opts.cliPath, processTag) } : {}),
|
|
79
|
+
});
|
|
80
|
+
const childPid = this.child.pid;
|
|
81
|
+
if (process.env.RYNX_RUNTIME_LOG_DIR) {
|
|
82
|
+
const logDir = process.env.RYNX_RUNTIME_LOG_DIR;
|
|
83
|
+
teeDiagnosticStream(this.child.stderr, join(logDir, "app-server.stderr.log"));
|
|
84
|
+
const event = diagnosticEvents(join(logDir, "process-events.jsonl"));
|
|
85
|
+
event("app-server.spawn", { pid: childPid });
|
|
86
|
+
this.child.on("exit", (code, signal) => event("app-server.exit", { code, signal }));
|
|
87
|
+
}
|
|
88
|
+
if (processTag && this.opts.stateDir && childPid) {
|
|
89
|
+
registerRuntimeProcess({
|
|
90
|
+
pid: childPid,
|
|
91
|
+
pgid: childPid,
|
|
92
|
+
ownerPid: process.pid,
|
|
93
|
+
ownerIdentity: runtimeProcessOwnerIdentity(process.pid),
|
|
94
|
+
sessionTag: processTag,
|
|
95
|
+
stateDir: this.opts.stateDir,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
this.child.on("exit", (code, signal) => {
|
|
99
|
+
this.unregisterProcess();
|
|
100
|
+
this.emitClose(code, signal, null);
|
|
61
101
|
});
|
|
62
|
-
this.child.on("exit", (code, signal) => this.emitClose(code, signal, null));
|
|
63
102
|
this.child.on("error", (error) => this.emitClose(null, null, error));
|
|
64
|
-
|
|
103
|
+
try {
|
|
104
|
+
this.ws = await this.connectWithRetry(this.url);
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
await this.stop();
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
65
110
|
this.ws.on("message", (data) => {
|
|
66
111
|
// One JSON-RPC object per frame (codex ws framing).
|
|
67
112
|
this.lineCb?.(data.toString());
|
|
@@ -85,6 +130,12 @@ export class WsRpcChannel {
|
|
|
85
130
|
});
|
|
86
131
|
}
|
|
87
132
|
async stop(signal = "SIGTERM") {
|
|
133
|
+
if (this.stopTask)
|
|
134
|
+
return await this.stopTask;
|
|
135
|
+
this.stopTask = this.stopOwnedProcess(signal);
|
|
136
|
+
return await this.stopTask;
|
|
137
|
+
}
|
|
138
|
+
async stopOwnedProcess(signal) {
|
|
88
139
|
try {
|
|
89
140
|
this.ws?.close();
|
|
90
141
|
}
|
|
@@ -92,14 +143,33 @@ export class WsRpcChannel {
|
|
|
92
143
|
/* already closing */
|
|
93
144
|
}
|
|
94
145
|
const child = this.child;
|
|
95
|
-
if (child) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
/* already gone */
|
|
146
|
+
if (child && child.exitCode === null && child.signalCode === null) {
|
|
147
|
+
this.signalChild(child, signal);
|
|
148
|
+
if (!await waitForExit(child, 5_000)) {
|
|
149
|
+
this.signalChild(child, "SIGKILL");
|
|
150
|
+
await waitForExit(child, 2_000);
|
|
101
151
|
}
|
|
102
152
|
}
|
|
153
|
+
this.unregisterProcess();
|
|
154
|
+
this.child = null;
|
|
155
|
+
this.ws = null;
|
|
156
|
+
}
|
|
157
|
+
signalChild(child, signal) {
|
|
158
|
+
try {
|
|
159
|
+
if (process.platform !== "win32" && child.pid)
|
|
160
|
+
process.kill(-child.pid, signal);
|
|
161
|
+
else
|
|
162
|
+
child.kill(signal);
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
// Already gone.
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
unregisterProcess() {
|
|
169
|
+
const tag = this.processTag;
|
|
170
|
+
this.processTag = null;
|
|
171
|
+
if (tag)
|
|
172
|
+
unregisterRuntimeProcess(tag);
|
|
103
173
|
}
|
|
104
174
|
emitClose(code, signal, error) {
|
|
105
175
|
if (this.closedEmitted)
|
|
@@ -114,7 +184,7 @@ export class WsRpcChannel {
|
|
|
114
184
|
// eslint-disable-next-line no-constant-condition
|
|
115
185
|
while (Date.now() < deadline) {
|
|
116
186
|
try {
|
|
117
|
-
return await this.tryConnect(url);
|
|
187
|
+
return await this.tryConnect(url, Math.max(1, deadline - Date.now()));
|
|
118
188
|
}
|
|
119
189
|
catch (error) {
|
|
120
190
|
lastError = error;
|
|
@@ -123,9 +193,9 @@ export class WsRpcChannel {
|
|
|
123
193
|
}
|
|
124
194
|
throw new Error(`codex app-server ws did not become ready at ${url}: ${lastError?.message ?? "timeout"}`);
|
|
125
195
|
}
|
|
126
|
-
tryConnect(url) {
|
|
196
|
+
tryConnect(url, handshakeTimeout) {
|
|
127
197
|
return new Promise((resolve, reject) => {
|
|
128
|
-
const ws = new WebSocket(url);
|
|
198
|
+
const ws = new WebSocket(url, { handshakeTimeout });
|
|
129
199
|
const onOpen = () => {
|
|
130
200
|
ws.off("error", onError);
|
|
131
201
|
resolve(ws);
|
|
@@ -145,6 +215,22 @@ export class WsRpcChannel {
|
|
|
145
215
|
});
|
|
146
216
|
}
|
|
147
217
|
}
|
|
218
|
+
function waitForExit(child, timeoutMs) {
|
|
219
|
+
if (child.exitCode !== null || child.signalCode !== null)
|
|
220
|
+
return Promise.resolve(true);
|
|
221
|
+
return new Promise((resolve) => {
|
|
222
|
+
const timer = setTimeout(() => {
|
|
223
|
+
child.off("exit", onExit);
|
|
224
|
+
resolve(false);
|
|
225
|
+
}, timeoutMs);
|
|
226
|
+
timer.unref?.();
|
|
227
|
+
const onExit = () => {
|
|
228
|
+
clearTimeout(timer);
|
|
229
|
+
resolve(true);
|
|
230
|
+
};
|
|
231
|
+
child.once("exit", onExit);
|
|
232
|
+
});
|
|
233
|
+
}
|
|
148
234
|
/**
|
|
149
235
|
* Connect-only {@link RpcChannel}: attaches an ADDITIONAL client to an app-server
|
|
150
236
|
* someone else already started (a {@link WsRpcChannel}'s `url`) — no spawn. This
|
|
@@ -166,7 +252,7 @@ export class ExternalWsChannel {
|
|
|
166
252
|
/** The `ws://IP:PORT` of the already-running app-server to attach to. */
|
|
167
253
|
url, opts = {}) {
|
|
168
254
|
this.url = url;
|
|
169
|
-
this.readyTimeoutMs = opts.readyTimeoutMs ??
|
|
255
|
+
this.readyTimeoutMs = opts.readyTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS;
|
|
170
256
|
}
|
|
171
257
|
onLine(cb) {
|
|
172
258
|
this.lineCb = cb;
|
|
@@ -178,20 +264,16 @@ export class ExternalWsChannel {
|
|
|
178
264
|
return this.ws?.readyState === WebSocket.OPEN;
|
|
179
265
|
}
|
|
180
266
|
async start() {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
catch (error) {
|
|
189
|
-
lastError = error;
|
|
190
|
-
await new Promise((r) => setTimeout(r, 150));
|
|
191
|
-
}
|
|
267
|
+
// A channel instance is reusable after an observer disconnect. Do not let
|
|
268
|
+
// the prior closed socket make a failed reconnect look successful, and arm
|
|
269
|
+
// close delivery for the newly connected socket.
|
|
270
|
+
this.ws = null;
|
|
271
|
+
this.closedEmitted = false;
|
|
272
|
+
try {
|
|
273
|
+
this.ws = await this.connect(this.url);
|
|
192
274
|
}
|
|
193
|
-
|
|
194
|
-
throw new Error(`could not attach to app-server ws ${this.url}: ${
|
|
275
|
+
catch (error) {
|
|
276
|
+
throw new Error(`could not attach to app-server ws ${this.url}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
195
277
|
}
|
|
196
278
|
this.ws.on("message", (data) => this.lineCb?.(data.toString()));
|
|
197
279
|
this.ws.on("close", (code) => this.emitClose(code ?? null, null, null));
|
|
@@ -227,7 +309,10 @@ export class ExternalWsChannel {
|
|
|
227
309
|
}
|
|
228
310
|
connect(url) {
|
|
229
311
|
return new Promise((resolve, reject) => {
|
|
230
|
-
|
|
312
|
+
// The app-server owner has already completed its readiness probe. Use one
|
|
313
|
+
// bounded attach, then reuse this exact connection as the forwarder
|
|
314
|
+
// instead of running a second startup retry stage.
|
|
315
|
+
const ws = new WebSocket(url, { handshakeTimeout: this.readyTimeoutMs });
|
|
231
316
|
const onOpen = () => {
|
|
232
317
|
ws.off("error", onError);
|
|
233
318
|
resolve(ws);
|
package/dist/codex-child-env.js
CHANGED
|
@@ -1,28 +1,3 @@
|
|
|
1
|
-
const CODEX_CHILD_ENV_ALLOWLIST = [
|
|
2
|
-
"PATH",
|
|
3
|
-
"HOME",
|
|
4
|
-
"USER",
|
|
5
|
-
"SHELL",
|
|
6
|
-
"TMPDIR",
|
|
7
|
-
"CODEX_HOME",
|
|
8
|
-
"TRAE_HOME",
|
|
9
|
-
// Keep Runtime-local CLIs on the same resident daemon when its state root is
|
|
10
|
-
// configured outside the default ~/.rynx location.
|
|
11
|
-
"RYNX_HOME",
|
|
12
|
-
// RunnerManager supplies this rotation-safe handle for the exact managed
|
|
13
|
-
// Session. Codex command executions need it to call their own Runtime
|
|
14
|
-
// Browser; the raw Browser capability and internal runner key stay outside
|
|
15
|
-
// the allowlist.
|
|
16
|
-
"RYNX_BROWSER_CONTEXT_FILE",
|
|
17
|
-
"HTTP_PROXY",
|
|
18
|
-
"HTTPS_PROXY",
|
|
19
|
-
"ALL_PROXY",
|
|
20
|
-
"NO_PROXY",
|
|
21
|
-
"http_proxy",
|
|
22
|
-
"https_proxy",
|
|
23
|
-
"all_proxy",
|
|
24
|
-
"no_proxy",
|
|
25
|
-
];
|
|
26
1
|
const PROXY_ENV_KEYS = [
|
|
27
2
|
"HTTP_PROXY",
|
|
28
3
|
"HTTPS_PROXY",
|
|
@@ -42,13 +17,9 @@ function withLoopbackNoProxy(value) {
|
|
|
42
17
|
return entries.join(",");
|
|
43
18
|
}
|
|
44
19
|
export function createCodexChildEnv(env) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (typeof value === "string" && value.length > 0) {
|
|
49
|
-
childEnv[key] = value;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
20
|
+
// Managed Codex/TraeX processes need the same development environment as
|
|
21
|
+
// their runner, including workspace metadata and user-configured CLI keys.
|
|
22
|
+
const childEnv = { ...env };
|
|
52
23
|
if (childEnv.NO_PROXY || childEnv.no_proxy || PROXY_ENV_KEYS.some((key) => childEnv[key])) {
|
|
53
24
|
const upper = childEnv.NO_PROXY ?? childEnv.no_proxy;
|
|
54
25
|
const lower = childEnv.no_proxy ?? childEnv.NO_PROXY;
|
package/dist/codex-home.d.ts
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
|
-
import { type AgentRuntimeId } from "@rynx-ai/core";
|
|
1
|
+
import { type AgentRuntimeId, type ResolvedRetryPolicy } from "@rynx-ai/core";
|
|
2
2
|
export type CodexLineageRuntime = Exclude<AgentRuntimeId, "claude">;
|
|
3
|
+
export type CodexAuthMode = "chatgpt" | "apikey" | "pat";
|
|
4
|
+
export type CodexConfigAuth = "provider-ready" | "provider-auth-missing" | "codex-login";
|
|
5
|
+
/** Read the credential mode from Codex's optional-field auth.json shape. */
|
|
6
|
+
export declare function codexAuthEffectiveMode(authPath: string): CodexAuthMode | null;
|
|
7
|
+
/** Mirror Codex's provider-specific auth decision without spawning the CLI. */
|
|
8
|
+
export declare function codexConfigEffectiveAuth(configPath: string, env?: NodeJS.ProcessEnv): CodexConfigAuth;
|
|
9
|
+
/** True only when this exact launch would defer to an absent Codex login. */
|
|
10
|
+
export declare function codexLaunchRequiresLogin(codexHome: string, env?: NodeJS.ProcessEnv): boolean;
|
|
11
|
+
/** Resolve the user's auth/config source without nesting a parent Session's
|
|
12
|
+
* private CODEX_HOME into a child Session. */
|
|
13
|
+
export declare function resolveCodexHomeConfigSource(candidate: string, defaultHome?: string): string;
|
|
3
14
|
/**
|
|
4
15
|
* The deterministic private CODEX_HOME path for a rynx session. PER-SESSION,
|
|
5
16
|
* under the daemon-owned RYNX_HOME runtime tree,
|
|
@@ -22,8 +33,8 @@ export declare function legacyCodexHomePath(): string;
|
|
|
22
33
|
* `_CODEX_HOME_COPY_FILES`.
|
|
23
34
|
*
|
|
24
35
|
* PER-SESSION: one private home per rynx session (matching reference implementation), so concurrent
|
|
25
|
-
* agents never share a `skills/` dir. Idempotent:
|
|
26
|
-
*
|
|
36
|
+
* agents never share a `skills/` dir. Idempotent: existing Session-owned entries stay
|
|
37
|
+
* unchanged; live symlinks still observe source credential updates. Returns the private home dir.
|
|
27
38
|
*/
|
|
28
39
|
export declare function prepareCodexHome(sessionId: string, realHome?: string): string;
|
|
29
40
|
/**
|
|
@@ -32,6 +43,27 @@ export declare function prepareCodexHome(sessionId: string, realHome?: string):
|
|
|
32
43
|
* real home and cannot wedge a managed app-server/TUI pair.
|
|
33
44
|
*/
|
|
34
45
|
export declare function prepareRuntimeHome(sessionId: string, runtime: CodexLineageRuntime, realHome?: string): string;
|
|
46
|
+
/** Trust a runner-selected workspace only in the Session's private config so
|
|
47
|
+
* Codex cannot stop a detached TUI at its project-trust prompt. */
|
|
48
|
+
export declare function trustCodexProject(codexHome: string, cwd: string): void;
|
|
49
|
+
/** Apply the Session retry budget through Codex's supported provider settings.
|
|
50
|
+
* A config with no provider definitions is left untouched. */
|
|
51
|
+
export declare function applyCodexProviderRetryPolicy(codexHome: string, retry?: ResolvedRetryPolicy | null): void;
|
|
52
|
+
/** Preserve the user's private-home base instructions and append only the raw
|
|
53
|
+
* Agent-authored text. Repeated launches replace the managed suffix instead of
|
|
54
|
+
* accumulating it. Invalid user TOML is intentionally left untouched. */
|
|
55
|
+
export declare function syncCodexDeveloperInstructions(codexHome: string, instructions?: string | null): void;
|
|
56
|
+
export type CodexDeveloperInstructionsState = {
|
|
57
|
+
state: "present";
|
|
58
|
+
value: string;
|
|
59
|
+
} | {
|
|
60
|
+
state: "absent";
|
|
61
|
+
} | {
|
|
62
|
+
state: "unreadable";
|
|
63
|
+
};
|
|
64
|
+
/** Read the active private-home instructions without conflating a definite
|
|
65
|
+
* absence with malformed or temporarily unreadable config. */
|
|
66
|
+
export declare function readCodexDeveloperInstructionsState(codexHome: string): CodexDeveloperInstructionsState;
|
|
35
67
|
/** Persist immutable skill copies in a native Provider home. Fork descendants
|
|
36
68
|
* share that home, so entries must outlive every runner's temporary sources. */
|
|
37
69
|
export declare function populateCodexSkills(codexHome: string, skills: {
|