@pasko70/pibo 1.16.5 → 2.0.0
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/agent-runtime/auth.js +28 -0
- package/dist/agent-runtime/capabilities.js +221 -0
- package/dist/agent-runtime/context-build.js +313 -0
- package/dist/agent-runtime/contract.js +45 -0
- package/dist/agent-runtime/errors.js +57 -0
- package/dist/agent-runtime/events.js +1 -0
- package/dist/agent-runtime/history.js +1 -0
- package/dist/agent-runtime/profile-validation.js +109 -0
- package/dist/agent-runtime/registry.js +608 -0
- package/dist/agent-runtime/resource-files.js +87 -0
- package/dist/agent-runtime/resource-service.js +635 -0
- package/dist/agent-runtime/resources.js +1 -0
- package/dist/agent-runtime/routed-session.js +931 -0
- package/dist/agent-runtime/testing/contract.js +51 -0
- package/dist/agent-runtime/testing/fake-adapter.js +192 -0
- package/dist/agent-runtime/types.js +3 -0
- package/dist/agent-runtimes/codex-native/adapter.js +905 -0
- package/dist/agent-runtimes/codex-native/auth.js +476 -0
- package/dist/agent-runtimes/codex-native/client.js +734 -0
- package/dist/agent-runtimes/codex-native/config.js +152 -0
- package/dist/agent-runtimes/codex-native/history.js +283 -0
- package/dist/agent-runtimes/codex-native/mcp-stdio-launcher.js +89 -0
- package/dist/agent-runtimes/codex-native/models.js +581 -0
- package/dist/agent-runtimes/codex-native/process.js +459 -0
- package/dist/agent-runtimes/codex-native/protocol-types.js +1 -0
- package/dist/agent-runtimes/codex-native/protocol-version.js +7 -0
- package/dist/agent-runtimes/codex-native/redaction.js +31 -0
- package/dist/agent-runtimes/codex-native/requests.js +378 -0
- package/dist/agent-runtimes/codex-native/resource-delivery.js +445 -0
- package/dist/agent-runtimes/codex-native/thread.js +388 -0
- package/dist/agent-runtimes/codex-native/turn.js +849 -0
- package/dist/agent-runtimes/pi/adapter.js +653 -0
- package/dist/agent-runtimes/pi/auth.js +455 -0
- package/dist/agent-runtimes/pi/history.js +640 -0
- package/dist/agent-runtimes/pi/model-catalog.js +87 -0
- package/dist/agent-runtimes/pi/routed-session.js +1464 -0
- package/dist/agent-runtimes/pi/runtime.js +534 -0
- package/dist/agent-runtimes/pi/tool-compiler.js +69 -0
- package/dist/apps/chat/agent-profiles.js +40 -23
- package/dist/apps/chat/agent-store.js +111 -64
- package/dist/apps/chat/chat-api-routes.js +1 -1
- package/dist/apps/chat/chat-request-normalizers.js +47 -0
- package/dist/apps/chat/data/chat-data-mappers.js +25 -9
- package/dist/apps/chat/data/history-query-service.js +108 -0
- package/dist/apps/chat/data/session-query-service.js +24 -3
- package/dist/apps/chat/data/timeline-query-service.js +3 -3
- package/dist/apps/chat/model-catalog.js +1 -55
- package/dist/apps/chat/provider-auth-actions.js +171 -23
- package/dist/apps/chat/stream.js +12 -0
- package/dist/apps/chat/trace-v2.js +1 -0
- package/dist/apps/chat/trace.js +126 -415
- package/dist/apps/chat/web-app.js +582 -157
- package/dist/apps/chat-ui/assets/{dist-QXwINWYY.js → dist-9v2ZXT6V.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CvZNkkOi.js → dist-B1LVAytl.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-_SP-MjLq.js → dist-C6LPDFXU.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-Bad4Yz4P.js → dist-DVtXxfHc.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-xy-zomwl.js → dist-DW4Qrfbd.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-DI4i80O2.js → dist-DmbsHdMC.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-D17yAUqp.js → dist-DyvwuSFO.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-Bc3Vbgjh.js → dist-I26VB0QO.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-BzqH7w58.js → dist-RtHbJRPV.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CMDJ-WZm.js → dist-sZgJkWZb.js} +1 -1
- package/dist/apps/chat-ui/assets/index-BPbNvcZe.css +1 -0
- package/dist/apps/chat-ui/assets/index-CIOf2uL2.js +237 -0
- package/dist/apps/chat-ui/index.html +2 -2
- package/dist/apps/chat-vscode-web/assets/index-1ivRyjFs.js +41 -0
- package/dist/apps/chat-vscode-web/index.html +1 -1
- package/dist/apps/vscode-artifacts/latest.vsix +0 -0
- package/dist/apps/vscode-artifacts/pibo-vscode-ext-2.0.0.vsix +0 -0
- package/dist/auth/login-actions.js +5 -251
- package/dist/cli-session/localSessionSource.js +8 -1
- package/dist/core/context-build.js +124 -20
- package/dist/core/default-profile.js +8 -0
- package/dist/core/profiles.js +30 -3
- package/dist/core/routed-session.js +5 -1446
- package/dist/core/runtime.js +5 -561
- package/dist/core/session-router.js +637 -83
- package/dist/data/cli.js +20 -3
- package/dist/data/schema.js +104 -1
- package/dist/data/session-store.js +24 -1
- package/dist/debug/events.js +25 -10
- package/dist/debug/failures.js +23 -3
- package/dist/debug/index.js +24 -6
- package/dist/debug/messages.js +87 -7
- package/dist/debug/persisted-payloads.js +31 -0
- package/dist/debug/pty.js +7 -6
- package/dist/debug/runtime-binding.js +29 -0
- package/dist/debug/session.js +137 -0
- package/dist/debug/summary.js +12 -0
- package/dist/debug/telemetry.js +28 -0
- package/dist/debug/tools.js +12 -2
- package/dist/debug/trace.js +154 -76
- package/dist/gateway/server.js +87 -2
- package/dist/gateway/tool.js +5 -5
- package/dist/index.js +21 -2
- package/dist/loops/tools.js +13 -12
- package/dist/mcp/agent-context.js +13 -4
- package/dist/mcp/client.js +10 -6
- package/dist/mcp/config.js +5 -2
- package/dist/mcp/runtime-session.js +166 -0
- package/dist/plugins/builtin.js +191 -53
- package/dist/plugins/codex-native.js +29 -0
- package/dist/plugins/registry.js +66 -2
- package/dist/runs/tools.js +26 -25
- package/dist/session-ui/terminalRows.js +2 -2
- package/dist/sessions/pibo-data-store.js +125 -16
- package/dist/sessions/runtime-binding.js +107 -0
- package/dist/sessions/sqlite-store.js +239 -18
- package/dist/sessions/store.js +86 -7
- package/dist/shared/trace-engine.js +18 -9
- package/dist/shared/trace-event-projection.js +29 -11
- package/dist/shared/{trace-transcript.js → trace-history.js} +193 -195
- package/dist/shared/trace-order.js +9 -4
- package/dist/shared/trace-page-merge.js +1 -1
- package/dist/signals/projector.js +20 -2
- package/dist/signals/registry.js +11 -0
- package/dist/subagents/tool.js +8 -6
- package/dist/tools/codex-browser.js +20 -19
- package/dist/tools/codex-compat.js +10 -9
- package/dist/tools/codex-image-generation.js +8 -6
- package/dist/tools/contract.js +45 -0
- package/dist/tools/credential-registry.js +182 -0
- package/dist/tools/mcp-bridge.js +511 -0
- package/dist/tools/payload-writer.js +17 -0
- package/dist/tools/runtime/tool.js +10 -9
- package/dist/tools/schema.js +9 -0
- package/dist/tools/session-service.js +193 -0
- package/dist/tools/session-tool-set.js +85 -0
- package/dist/web-annotations/tools.js +17 -16
- package/docs/README.md +11 -0
- package/package.json +3 -2
- package/skills/builtin/pibo-agent-runtime-adapter/SKILL.md +183 -0
- package/skills/builtin/pibo-agent-runtime-adapter/evals/README.md +10 -0
- package/skills/builtin/pibo-agent-runtime-adapter/evals/evals.json +45 -0
- package/skills/builtin/pibo-agent-runtime-adapter/evals/fixtures/orion-full-harness.md +60 -0
- package/skills/builtin/pibo-agent-runtime-adapter/evals/fixtures/relay-partial-harness.md +52 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/capabilities-and-designer.md +194 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/history-debug-and-security.md +213 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/interfaces-and-registration.md +214 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/lifecycle-bindings-and-events.md +193 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/portable-delivery-and-native-behavior.md +226 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/testing-migration-and-validation.md +256 -0
- package/dist/apps/chat-ui/assets/index-C45B0rw7.js +0 -237
- package/dist/apps/chat-ui/assets/index-E0RmuCkY.css +0 -1
- package/dist/apps/chat-vscode-web/assets/index-D-tSsXLG.js +0 -41
- package/dist/apps/vscode-artifacts/pibo-vscode-ext-1.16.5.vsix +0 -0
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
3
|
+
import { chmod, lstat, mkdir, realpath, rm, rmdir, writeFile, } from "node:fs/promises";
|
|
4
|
+
import { isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
5
|
+
import { CodexAppServerClient } from "./client.js";
|
|
6
|
+
import { CODEX_APP_SERVER_PROTOCOL_NAME, CODEX_APP_SERVER_SUPPORTED_RANGE, CODEX_APP_SERVER_VERSION, } from "./protocol-version.js";
|
|
7
|
+
const MAX_VERSION_OUTPUT_BYTES = 64 * 1024;
|
|
8
|
+
const PRIVATE_DIRECTORY_MODE = 0o700;
|
|
9
|
+
const PRIVATE_FILE_MODE = 0o600;
|
|
10
|
+
const INSTANCE_CONFIG = [
|
|
11
|
+
"# Managed by Pibo for this configured Codex runtime instance.",
|
|
12
|
+
"# Session-specific settings are supplied through process-scoped official overrides.",
|
|
13
|
+
"[analytics]",
|
|
14
|
+
"enabled = false",
|
|
15
|
+
"",
|
|
16
|
+
].join("\n");
|
|
17
|
+
const RESOURCE_ENVIRONMENT_KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
18
|
+
const PROTECTED_RESOURCE_ENVIRONMENT_KEYS = new Set([
|
|
19
|
+
"CODEX_HOME",
|
|
20
|
+
"HOME",
|
|
21
|
+
"USERPROFILE",
|
|
22
|
+
"XDG_CACHE_HOME",
|
|
23
|
+
"XDG_CONFIG_HOME",
|
|
24
|
+
"XDG_DATA_HOME",
|
|
25
|
+
"XDG_STATE_HOME",
|
|
26
|
+
"TMP",
|
|
27
|
+
"TEMP",
|
|
28
|
+
"TMPDIR",
|
|
29
|
+
"PATH",
|
|
30
|
+
"PATHEXT",
|
|
31
|
+
"SYSTEMROOT",
|
|
32
|
+
"WINDIR",
|
|
33
|
+
"COMSPEC",
|
|
34
|
+
"NODE_OPTIONS",
|
|
35
|
+
"LD_PRELOAD",
|
|
36
|
+
"BASH_ENV",
|
|
37
|
+
"ENV",
|
|
38
|
+
"PYTHONHOME",
|
|
39
|
+
"PYTHONPATH",
|
|
40
|
+
"RUBYOPT",
|
|
41
|
+
"PERL5OPT",
|
|
42
|
+
"JAVA_TOOL_OPTIONS",
|
|
43
|
+
"_JAVA_OPTIONS",
|
|
44
|
+
]);
|
|
45
|
+
export class CodexNativeProcessError extends Error {
|
|
46
|
+
code;
|
|
47
|
+
constructor(code, message) {
|
|
48
|
+
super(message);
|
|
49
|
+
this.code = code;
|
|
50
|
+
this.name = "CodexNativeProcessError";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function safeSegment(value) {
|
|
54
|
+
const normalized = value.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 72) || "runtime";
|
|
55
|
+
const hash = createHash("sha256").update(value).digest("hex").slice(0, 12);
|
|
56
|
+
return `${normalized}-${hash}`;
|
|
57
|
+
}
|
|
58
|
+
function isInside(root, candidate) {
|
|
59
|
+
const child = relative(root, candidate);
|
|
60
|
+
return child === "" || (!child.startsWith(`..${sep}`) && child !== ".." && !isAbsolute(child));
|
|
61
|
+
}
|
|
62
|
+
async function ensurePrivateDirectory(path) {
|
|
63
|
+
await mkdir(path, { recursive: true, mode: PRIVATE_DIRECTORY_MODE });
|
|
64
|
+
const metadata = await lstat(path);
|
|
65
|
+
if (metadata.isSymbolicLink() || !metadata.isDirectory())
|
|
66
|
+
throw new Error("runtime path is not a private directory");
|
|
67
|
+
await chmod(path, PRIVATE_DIRECTORY_MODE);
|
|
68
|
+
}
|
|
69
|
+
async function ensurePrivateConfig(path) {
|
|
70
|
+
try {
|
|
71
|
+
await writeFile(path, INSTANCE_CONFIG, { encoding: "utf8", flag: "wx", mode: PRIVATE_FILE_MODE });
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
if (error.code !== "EEXIST")
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
const metadata = await lstat(path);
|
|
78
|
+
if (metadata.isSymbolicLink() || !metadata.isFile())
|
|
79
|
+
throw new Error("runtime config is not a private regular file");
|
|
80
|
+
await chmod(path, PRIVATE_FILE_MODE);
|
|
81
|
+
}
|
|
82
|
+
function nodeErrorCode(error) {
|
|
83
|
+
const code = error?.code;
|
|
84
|
+
return typeof code === "string" && /^[A-Z0-9_]+$/.test(code) ? code : undefined;
|
|
85
|
+
}
|
|
86
|
+
export async function prepareCodexNativeInstancePaths(config, runtimeInstanceId) {
|
|
87
|
+
if (!runtimeInstanceId.trim())
|
|
88
|
+
throw new CodexNativeProcessError("home_unavailable", "Codex runtime instance id is required.");
|
|
89
|
+
try {
|
|
90
|
+
await mkdir(config.homeRoot, { recursive: true, mode: PRIVATE_DIRECTORY_MODE });
|
|
91
|
+
const canonicalHomeRoot = await realpath(config.homeRoot);
|
|
92
|
+
const root = join(canonicalHomeRoot, safeSegment(runtimeInstanceId));
|
|
93
|
+
const codexHome = join(root, "codex-home");
|
|
94
|
+
const sessions = join(root, "sessions");
|
|
95
|
+
for (const path of [root, codexHome, sessions])
|
|
96
|
+
await ensurePrivateDirectory(path);
|
|
97
|
+
const canonicalRoot = await realpath(root);
|
|
98
|
+
for (const path of [codexHome, sessions]) {
|
|
99
|
+
const canonical = await realpath(path);
|
|
100
|
+
if (!isInside(canonicalRoot, canonical))
|
|
101
|
+
throw new Error("runtime path escaped its configured instance root");
|
|
102
|
+
}
|
|
103
|
+
const configFile = join(codexHome, "config.toml");
|
|
104
|
+
await ensurePrivateConfig(configFile);
|
|
105
|
+
return { root: canonicalRoot, codexHome: await realpath(codexHome), configFile, sessions: await realpath(sessions) };
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
throw new CodexNativeProcessError("home_unavailable", `Private Codex state could not be prepared for runtime instance "${runtimeInstanceId}".`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
export async function prepareCodexNativeSessionPaths(input) {
|
|
112
|
+
if (!input.piboSessionId.trim() || !input.sessionGeneration.trim()) {
|
|
113
|
+
throw new CodexNativeProcessError("home_unavailable", "Pibo session id and runtime generation are required.");
|
|
114
|
+
}
|
|
115
|
+
const instance = await prepareCodexNativeInstancePaths(input.config, input.runtimeInstanceId);
|
|
116
|
+
const sessionRoot = join(instance.sessions, safeSegment(input.piboSessionId));
|
|
117
|
+
const generationRoot = join(sessionRoot, safeSegment(input.sessionGeneration));
|
|
118
|
+
let sessionDirectoryReady = false;
|
|
119
|
+
try {
|
|
120
|
+
await ensurePrivateDirectory(sessionRoot);
|
|
121
|
+
sessionDirectoryReady = true;
|
|
122
|
+
const processHome = join(generationRoot, "home");
|
|
123
|
+
const temp = join(generationRoot, "tmp");
|
|
124
|
+
const xdgCache = join(processHome, ".cache");
|
|
125
|
+
const xdgConfig = join(processHome, ".config");
|
|
126
|
+
const xdgData = join(processHome, ".local", "share");
|
|
127
|
+
const xdgState = join(processHome, ".local", "state");
|
|
128
|
+
for (const path of [generationRoot, processHome, temp, xdgCache, xdgConfig, xdgData, xdgState]) {
|
|
129
|
+
await ensurePrivateDirectory(path);
|
|
130
|
+
}
|
|
131
|
+
const canonicalGenerationRoot = await realpath(generationRoot);
|
|
132
|
+
if (!isInside(instance.sessions, canonicalGenerationRoot))
|
|
133
|
+
throw new Error("runtime generation escaped its session root");
|
|
134
|
+
return {
|
|
135
|
+
...instance,
|
|
136
|
+
sessionRoot: await realpath(sessionRoot),
|
|
137
|
+
generationRoot: canonicalGenerationRoot,
|
|
138
|
+
processHome: await realpath(processHome),
|
|
139
|
+
temp: await realpath(temp),
|
|
140
|
+
xdgCache: await realpath(xdgCache),
|
|
141
|
+
xdgConfig: await realpath(xdgConfig),
|
|
142
|
+
xdgData: await realpath(xdgData),
|
|
143
|
+
xdgState: await realpath(xdgState),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
if (sessionDirectoryReady) {
|
|
148
|
+
await rm(generationRoot, { recursive: true, force: true }).catch(() => { });
|
|
149
|
+
await rmdir(sessionRoot).catch(() => { });
|
|
150
|
+
}
|
|
151
|
+
throw new CodexNativeProcessError("home_unavailable", `Private Codex process state could not be prepared for Pibo session "${input.piboSessionId}".`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
export async function disposeCodexNativeSessionPaths(paths) {
|
|
155
|
+
await rm(paths.generationRoot, { recursive: true, force: true });
|
|
156
|
+
await rmdir(paths.sessionRoot).catch((error) => {
|
|
157
|
+
if (error.code !== "ENOTEMPTY" && error.code !== "ENOENT")
|
|
158
|
+
throw error;
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
export async function removeCodexNativeInstanceState(paths) {
|
|
162
|
+
await rm(paths.root, { recursive: true, force: true });
|
|
163
|
+
}
|
|
164
|
+
function environmentLookup(environment) {
|
|
165
|
+
const lookup = new Map();
|
|
166
|
+
for (const [key, value] of Object.entries(environment)) {
|
|
167
|
+
if (typeof value === "string")
|
|
168
|
+
lookup.set(key.toUpperCase(), [key, value]);
|
|
169
|
+
}
|
|
170
|
+
return lookup;
|
|
171
|
+
}
|
|
172
|
+
function assertResourceEnvironmentKey(key) {
|
|
173
|
+
if (!RESOURCE_ENVIRONMENT_KEY_PATTERN.test(key)) {
|
|
174
|
+
throw new CodexNativeProcessError("environment_invalid", "Codex resource environment contains an invalid variable name.");
|
|
175
|
+
}
|
|
176
|
+
const canonical = key.toUpperCase();
|
|
177
|
+
if (PROTECTED_RESOURCE_ENVIRONMENT_KEYS.has(canonical) || canonical.startsWith("DYLD_")) {
|
|
178
|
+
throw new CodexNativeProcessError("environment_invalid", `Codex resource environment may not override protected variable "${key}".`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
export function buildCodexNativeProcessEnvironment(input) {
|
|
182
|
+
const base = input.baseEnvironment ?? process.env;
|
|
183
|
+
const lookup = environmentLookup(base);
|
|
184
|
+
const environment = {};
|
|
185
|
+
for (const configuredKey of input.config.environmentAllowlist) {
|
|
186
|
+
const selected = lookup.get(configuredKey.toUpperCase());
|
|
187
|
+
if (selected)
|
|
188
|
+
environment[selected[0]] = selected[1];
|
|
189
|
+
}
|
|
190
|
+
for (const [key, value] of Object.entries(input.resourceEnvironment ?? {})) {
|
|
191
|
+
if (value === undefined)
|
|
192
|
+
continue;
|
|
193
|
+
assertResourceEnvironmentKey(key);
|
|
194
|
+
environment[key] = value;
|
|
195
|
+
}
|
|
196
|
+
environment.CODEX_HOME = input.paths.codexHome;
|
|
197
|
+
environment.HOME = input.paths.processHome;
|
|
198
|
+
environment.USERPROFILE = input.paths.processHome;
|
|
199
|
+
environment.XDG_CACHE_HOME = input.paths.xdgCache;
|
|
200
|
+
environment.XDG_CONFIG_HOME = input.paths.xdgConfig;
|
|
201
|
+
environment.XDG_DATA_HOME = input.paths.xdgData;
|
|
202
|
+
environment.XDG_STATE_HOME = input.paths.xdgState;
|
|
203
|
+
environment.TMPDIR = input.paths.temp;
|
|
204
|
+
environment.TMP = input.paths.temp;
|
|
205
|
+
environment.TEMP = input.paths.temp;
|
|
206
|
+
return environment;
|
|
207
|
+
}
|
|
208
|
+
async function probeCodexVersion(config, environment) {
|
|
209
|
+
return await new Promise((resolveProbe) => {
|
|
210
|
+
let child;
|
|
211
|
+
try {
|
|
212
|
+
child = spawn(config.executable, ["--version"], { env: environment, stdio: ["ignore", "pipe", "pipe"] });
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
resolveProbe({ status: "failed", errorCode: nodeErrorCode(error) });
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
let settled = false;
|
|
219
|
+
let bytes = 0;
|
|
220
|
+
const chunks = [];
|
|
221
|
+
const settle = (result) => {
|
|
222
|
+
if (settled)
|
|
223
|
+
return;
|
|
224
|
+
settled = true;
|
|
225
|
+
clearTimeout(timer);
|
|
226
|
+
resolveProbe(result);
|
|
227
|
+
};
|
|
228
|
+
const collect = (chunk) => {
|
|
229
|
+
bytes += chunk.length;
|
|
230
|
+
if (bytes > MAX_VERSION_OUTPUT_BYTES) {
|
|
231
|
+
child.kill("SIGKILL");
|
|
232
|
+
settle({ status: "too_large" });
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
chunks.push(Buffer.from(chunk));
|
|
236
|
+
};
|
|
237
|
+
child.stdout.on("data", collect);
|
|
238
|
+
child.stderr.on("data", collect);
|
|
239
|
+
child.once("error", (error) => {
|
|
240
|
+
settle(error.code === "ENOENT" ? { status: "missing" } : { status: "failed", errorCode: nodeErrorCode(error) });
|
|
241
|
+
});
|
|
242
|
+
child.once("close", (code) => {
|
|
243
|
+
if (settled)
|
|
244
|
+
return;
|
|
245
|
+
if (code !== 0) {
|
|
246
|
+
settle({ status: "failed", exitCode: code });
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
settle({ status: "ok", output: Buffer.concat(chunks).toString("utf8") });
|
|
250
|
+
});
|
|
251
|
+
const timer = setTimeout(() => {
|
|
252
|
+
child.kill("SIGKILL");
|
|
253
|
+
settle({ status: "timeout" });
|
|
254
|
+
}, config.diagnosticTimeoutMs);
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
function parseCodexVersion(output) {
|
|
258
|
+
const match = output.match(/\bcodex-cli\s+v?(\d+)\.(\d+)\.(\d+)([-+][0-9A-Za-z.-]+)?\b/);
|
|
259
|
+
if (!match)
|
|
260
|
+
return undefined;
|
|
261
|
+
return {
|
|
262
|
+
version: `${match[1]}.${match[2]}.${match[3]}${match[4] ?? ""}`,
|
|
263
|
+
major: Number(match[1]),
|
|
264
|
+
minor: Number(match[2]),
|
|
265
|
+
patch: Number(match[3]),
|
|
266
|
+
prerelease: match[4]?.startsWith("-") === true,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
function versionSupported(version) {
|
|
270
|
+
return !version.prerelease && version.major === 0 && version.minor === 147 && version.patch >= 0;
|
|
271
|
+
}
|
|
272
|
+
export async function diagnoseCodexNativeRuntime(config, runtimeInstanceId, options = {}) {
|
|
273
|
+
const diagnostics = [];
|
|
274
|
+
let paths;
|
|
275
|
+
try {
|
|
276
|
+
paths = await prepareCodexNativeSessionPaths({
|
|
277
|
+
config,
|
|
278
|
+
runtimeInstanceId,
|
|
279
|
+
piboSessionId: "runtime-diagnostics",
|
|
280
|
+
sessionGeneration: `version-probe-${randomUUID()}`,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
const errorCode = nodeErrorCode(error);
|
|
285
|
+
diagnostics.push({
|
|
286
|
+
severity: "error",
|
|
287
|
+
code: "codex_native_home_unavailable",
|
|
288
|
+
message: `Private Codex state is unavailable for runtime instance "${runtimeInstanceId}".`,
|
|
289
|
+
path: "config.homeRoot",
|
|
290
|
+
...(errorCode ? { details: { errorCode } } : {}),
|
|
291
|
+
});
|
|
292
|
+
return diagnostics;
|
|
293
|
+
}
|
|
294
|
+
diagnostics.push({
|
|
295
|
+
severity: "info",
|
|
296
|
+
code: "codex_native_home_ready",
|
|
297
|
+
message: `Private Codex state is ready for runtime instance "${runtimeInstanceId}".`,
|
|
298
|
+
details: { scope: "configured-instance", private: true },
|
|
299
|
+
});
|
|
300
|
+
let probe;
|
|
301
|
+
try {
|
|
302
|
+
probe = await probeCodexVersion(config, buildCodexNativeProcessEnvironment({
|
|
303
|
+
config,
|
|
304
|
+
paths,
|
|
305
|
+
baseEnvironment: options.baseEnvironment ?? process.env,
|
|
306
|
+
}));
|
|
307
|
+
}
|
|
308
|
+
finally {
|
|
309
|
+
await disposeCodexNativeSessionPaths(paths);
|
|
310
|
+
}
|
|
311
|
+
if (probe.status === "missing") {
|
|
312
|
+
diagnostics.push({
|
|
313
|
+
severity: "error",
|
|
314
|
+
code: "codex_native_executable_not_found",
|
|
315
|
+
message: `Codex CLI is not available for runtime instance "${runtimeInstanceId}".`,
|
|
316
|
+
path: "config.executable",
|
|
317
|
+
});
|
|
318
|
+
return diagnostics;
|
|
319
|
+
}
|
|
320
|
+
if (probe.status === "timeout") {
|
|
321
|
+
diagnostics.push({
|
|
322
|
+
severity: "error",
|
|
323
|
+
code: "codex_native_version_probe_timeout",
|
|
324
|
+
message: `Codex CLI version inspection timed out for runtime instance "${runtimeInstanceId}".`,
|
|
325
|
+
path: "config.diagnosticTimeoutMs",
|
|
326
|
+
});
|
|
327
|
+
return diagnostics;
|
|
328
|
+
}
|
|
329
|
+
if (probe.status === "too_large") {
|
|
330
|
+
diagnostics.push({
|
|
331
|
+
severity: "error",
|
|
332
|
+
code: "codex_native_version_probe_too_large",
|
|
333
|
+
message: `Codex CLI version inspection produced too much output for runtime instance "${runtimeInstanceId}".`,
|
|
334
|
+
});
|
|
335
|
+
return diagnostics;
|
|
336
|
+
}
|
|
337
|
+
if (probe.status === "failed") {
|
|
338
|
+
diagnostics.push({
|
|
339
|
+
severity: "error",
|
|
340
|
+
code: "codex_native_version_probe_failed",
|
|
341
|
+
message: `Codex CLI version inspection failed for runtime instance "${runtimeInstanceId}".`,
|
|
342
|
+
...(probe.exitCode !== undefined || probe.errorCode
|
|
343
|
+
? { details: { ...(probe.exitCode !== undefined ? { exitCode: probe.exitCode } : {}), ...(probe.errorCode ? { errorCode: probe.errorCode } : {}) } }
|
|
344
|
+
: {}),
|
|
345
|
+
});
|
|
346
|
+
return diagnostics;
|
|
347
|
+
}
|
|
348
|
+
const parsed = parseCodexVersion(probe.output);
|
|
349
|
+
if (!parsed) {
|
|
350
|
+
diagnostics.push({
|
|
351
|
+
severity: "error",
|
|
352
|
+
code: "codex_native_version_unreadable",
|
|
353
|
+
message: `Codex CLI returned an unrecognized version for runtime instance "${runtimeInstanceId}".`,
|
|
354
|
+
});
|
|
355
|
+
return diagnostics;
|
|
356
|
+
}
|
|
357
|
+
if (!versionSupported(parsed)) {
|
|
358
|
+
diagnostics.push({
|
|
359
|
+
severity: "error",
|
|
360
|
+
code: "codex_native_version_unsupported",
|
|
361
|
+
message: `Codex CLI ${parsed.version} is outside the supported range for runtime instance "${runtimeInstanceId}".`,
|
|
362
|
+
details: { version: parsed.version, supportedRange: CODEX_APP_SERVER_SUPPORTED_RANGE },
|
|
363
|
+
});
|
|
364
|
+
return diagnostics;
|
|
365
|
+
}
|
|
366
|
+
diagnostics.push({
|
|
367
|
+
severity: parsed.version === CODEX_APP_SERVER_VERSION ? "info" : "warning",
|
|
368
|
+
code: parsed.version === CODEX_APP_SERVER_VERSION
|
|
369
|
+
? "codex_native_available"
|
|
370
|
+
: "codex_native_compatible_version",
|
|
371
|
+
message: parsed.version === CODEX_APP_SERVER_VERSION
|
|
372
|
+
? `Codex CLI ${parsed.version} is available for runtime instance "${runtimeInstanceId}".`
|
|
373
|
+
: `Codex CLI ${parsed.version} is compatible but differs from the validated checkpoint ${CODEX_APP_SERVER_VERSION}.`,
|
|
374
|
+
details: {
|
|
375
|
+
version: parsed.version,
|
|
376
|
+
validatedVersion: CODEX_APP_SERVER_VERSION,
|
|
377
|
+
supportedRange: CODEX_APP_SERVER_SUPPORTED_RANGE,
|
|
378
|
+
protocol: CODEX_APP_SERVER_PROTOCOL_NAME,
|
|
379
|
+
},
|
|
380
|
+
});
|
|
381
|
+
return diagnostics;
|
|
382
|
+
}
|
|
383
|
+
export class CodexNativeAppServerProcess {
|
|
384
|
+
client;
|
|
385
|
+
paths;
|
|
386
|
+
closePromise;
|
|
387
|
+
constructor(client, paths) {
|
|
388
|
+
this.client = client;
|
|
389
|
+
this.paths = paths;
|
|
390
|
+
}
|
|
391
|
+
async close() {
|
|
392
|
+
if (!this.closePromise) {
|
|
393
|
+
this.closePromise = (async () => {
|
|
394
|
+
try {
|
|
395
|
+
await this.client.close();
|
|
396
|
+
}
|
|
397
|
+
finally {
|
|
398
|
+
await disposeCodexNativeSessionPaths(this.paths);
|
|
399
|
+
}
|
|
400
|
+
})();
|
|
401
|
+
}
|
|
402
|
+
await this.closePromise;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
export async function startCodexNativeAppServer(input) {
|
|
406
|
+
if (!isAbsolute(input.workspace)) {
|
|
407
|
+
throw new CodexNativeProcessError("start_failed", "Codex runtime workspace must be an absolute path.");
|
|
408
|
+
}
|
|
409
|
+
if (!input.clientVersion.trim()) {
|
|
410
|
+
throw new CodexNativeProcessError("start_failed", "Codex App Server client version is required.");
|
|
411
|
+
}
|
|
412
|
+
const paths = await prepareCodexNativeSessionPaths(input);
|
|
413
|
+
let client;
|
|
414
|
+
try {
|
|
415
|
+
const capabilities = { experimentalApi: false };
|
|
416
|
+
client = await CodexAppServerClient.start({
|
|
417
|
+
command: input.config.executable,
|
|
418
|
+
fileCreationMask: 0o077,
|
|
419
|
+
args: [
|
|
420
|
+
"app-server",
|
|
421
|
+
"--stdio",
|
|
422
|
+
"--strict-config",
|
|
423
|
+
"-c",
|
|
424
|
+
`tools.experimental_request_user_input.enabled=${input.config.experimentalUserInput}`,
|
|
425
|
+
"-c",
|
|
426
|
+
`features.default_mode_request_user_input=${input.config.experimentalUserInput}`,
|
|
427
|
+
],
|
|
428
|
+
cwd: resolve(input.workspace),
|
|
429
|
+
env: buildCodexNativeProcessEnvironment({
|
|
430
|
+
config: input.config,
|
|
431
|
+
paths,
|
|
432
|
+
baseEnvironment: input.baseEnvironment,
|
|
433
|
+
resourceEnvironment: input.resourceEnvironment,
|
|
434
|
+
}),
|
|
435
|
+
clientInfo: { name: "pibo", title: "Pibo", version: input.clientVersion.trim() },
|
|
436
|
+
capabilities,
|
|
437
|
+
startupTimeoutMs: input.config.startupTimeoutMs,
|
|
438
|
+
requestTimeoutMs: input.config.requestTimeoutMs,
|
|
439
|
+
shutdownTimeoutMs: input.config.shutdownTimeoutMs,
|
|
440
|
+
killTimeoutMs: input.config.killTimeoutMs,
|
|
441
|
+
onDiagnostic: input.onDiagnostic,
|
|
442
|
+
});
|
|
443
|
+
const [reportedHome, expectedHome] = await Promise.all([
|
|
444
|
+
realpath(client.initializeResponse.codexHome).catch(() => resolve(client.initializeResponse.codexHome)),
|
|
445
|
+
realpath(paths.codexHome),
|
|
446
|
+
]);
|
|
447
|
+
if (reportedHome !== expectedHome) {
|
|
448
|
+
throw new CodexNativeProcessError("isolation_failed", `Codex App Server did not use the private home for runtime instance "${input.runtimeInstanceId}".`);
|
|
449
|
+
}
|
|
450
|
+
return new CodexNativeAppServerProcess(client, paths);
|
|
451
|
+
}
|
|
452
|
+
catch (error) {
|
|
453
|
+
await client?.close().catch(() => { });
|
|
454
|
+
await disposeCodexNativeSessionPaths(paths).catch(() => { });
|
|
455
|
+
if (error instanceof CodexNativeProcessError)
|
|
456
|
+
throw error;
|
|
457
|
+
throw new CodexNativeProcessError("start_failed", `Codex App Server failed to start for runtime instance "${input.runtimeInstanceId}".`);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const CODEX_APP_SERVER_VERSION = "0.147.0";
|
|
2
|
+
export const CODEX_APP_SERVER_SUPPORTED_RANGE = ">=0.147.0 <0.148.0";
|
|
3
|
+
export const CODEX_APP_SERVER_PROTOCOL_NAME = "codex-app-server-v2";
|
|
4
|
+
export const CODEX_APP_SERVER_SCHEMA_SHA256 = "f72b2caa3cbfa4298de9e85c62dda6dfbaf2266ffeb916fed30615ca69ff8c74";
|
|
5
|
+
export const CODEX_APP_SERVER_V2_SCHEMA_SHA256 = "f3dec1e031d99a420b137b903f02196d4325eece57620c925bb7130b25f168d2";
|
|
6
|
+
export const CODEX_APP_SERVER_GENERATED_TYPES_INDEX_SHA256 = "1cca50b4003a6661cd211dff7c655ecf03ecfe4c7bba8e72a5bbc9af33ee5086";
|
|
7
|
+
export const CODEX_APP_SERVER_GENERATED_BUNDLE_SHA256 = "ab890a36f19a6b48284c34dd46bb5154ccc34185c4c4d0f05c16e0bf113956a1";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const SENSITIVE_KEY_PATTERN = /(?:authorization|cookie|credential|access[_-]?token|refresh[_-]?token|id[_-]?token|api[_-]?key|token|secret|password)/i;
|
|
2
|
+
export function redactCodexNativeSensitiveText(value) {
|
|
3
|
+
return value
|
|
4
|
+
.replace(/Bearer\s+\S+/gi, "Bearer [redacted]")
|
|
5
|
+
.replace(/\b(?:sk|pk|ghp|github_pat|pibo)[-_][A-Za-z0-9_-]{8,}\b/g, "[redacted]")
|
|
6
|
+
.replace(/\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g, "[redacted]")
|
|
7
|
+
.replace(/\b(access[_-]?token|refresh[_-]?token|id[_-]?token|api[_-]?key|token|secret|password)\b(\s*["']?\s*[:=]\s*["']?)([^\s"'&,}]+)/gi, "$1$2[redacted]");
|
|
8
|
+
}
|
|
9
|
+
export function redactCodexNativeValue(value, key, depth = 0) {
|
|
10
|
+
if (key && SENSITIVE_KEY_PATTERN.test(key))
|
|
11
|
+
return "[redacted]";
|
|
12
|
+
if (depth > 32)
|
|
13
|
+
return "[maximum depth reached]";
|
|
14
|
+
if (value === null || typeof value === "boolean")
|
|
15
|
+
return value;
|
|
16
|
+
if (typeof value === "string")
|
|
17
|
+
return redactCodexNativeSensitiveText(value);
|
|
18
|
+
if (typeof value === "number")
|
|
19
|
+
return Number.isFinite(value) ? value : String(value);
|
|
20
|
+
if (Array.isArray(value))
|
|
21
|
+
return value.map((entry) => redactCodexNativeValue(entry, undefined, depth + 1));
|
|
22
|
+
if (value && typeof value === "object") {
|
|
23
|
+
const result = {};
|
|
24
|
+
for (const [entryKey, entryValue] of Object.entries(value)) {
|
|
25
|
+
if (entryValue !== undefined)
|
|
26
|
+
result[entryKey] = redactCodexNativeValue(entryValue, entryKey, depth + 1);
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
return String(value);
|
|
31
|
+
}
|