negotium 0.18.2 → 0.19.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/bin/codex-sdk-window-hide.mjs +40 -0
- package/bin/negotium.mjs +4 -0
- package/dist/agent-helpers.js +432 -152
- package/dist/agent-helpers.js.map +7 -6
- package/dist/canonical-mcp-bridge.js +3 -2
- package/dist/canonical-mcp-bridge.js.map +1 -1
- package/dist/chunk-22mtr8np.js +200 -0
- package/dist/chunk-22mtr8np.js.map +9 -0
- package/dist/chunk-2mx7fq49.js +6 -0
- package/dist/chunk-2mx7fq49.js.map +9 -0
- package/dist/{chunk-44ajn328.js → chunk-4bzehg8t.js} +2 -2
- package/dist/chunk-4bzehg8t.js.map +12 -0
- package/dist/{chunk-r0xs3t81.js → chunk-f7p0h1gs.js} +2 -4
- package/dist/{chunk-r0xs3t81.js.map → chunk-f7p0h1gs.js.map} +2 -2
- package/dist/chunk-y8rtedjb.js +374 -0
- package/dist/chunk-y8rtedjb.js.map +13 -0
- package/dist/hosted-agent.js +355 -476
- package/dist/hosted-agent.js.map +7 -10
- package/dist/main.js +773 -473
- package/dist/main.js.map +8 -7
- package/dist/mcp-factories.js +407 -127
- package/dist/mcp-factories.js.map +7 -6
- package/dist/registry.js +1 -1
- package/dist/runtime/src/agents/codex-native-multi-agent.ts +45 -3
- package/dist/runtime/src/agents/codex-vault-hook-bridge.ts +36 -23
- package/dist/runtime/src/agents/codex-windows-wrapper.ts +174 -0
- package/dist/runtime/src/prompts/sessions/_shared-tools.md +19 -0
- package/dist/runtime/src/version.ts +1 -1
- package/dist/types/packages/core/src/agents/codex-windows-wrapper.d.ts +30 -0
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chunk-44ajn328.js.map +0 -12
package/dist/registry.js
CHANGED
|
@@ -132,7 +132,7 @@ var codexRegistryOperations = {
|
|
|
132
132
|
return { sessionId: threadId, rolloutPath };
|
|
133
133
|
},
|
|
134
134
|
async forkSession({ parentSessionId }) {
|
|
135
|
-
const { forkCodexSession } = await import("./chunk-
|
|
135
|
+
const { forkCodexSession } = await import("./chunk-4bzehg8t.js");
|
|
136
136
|
return await forkCodexSession(parentSessionId);
|
|
137
137
|
},
|
|
138
138
|
async cleanupRollouts({ sessionIds }) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
1
|
+
import { type ChildProcess, spawn } from "node:child_process";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import {
|
|
4
4
|
chmodSync,
|
|
@@ -111,7 +111,7 @@ async function bootstrapCodexModelCache(codexHome: string, cachePath: string): P
|
|
|
111
111
|
windowsHide: true,
|
|
112
112
|
});
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
const refreshed = new Promise<void>((resolve, reject) => {
|
|
115
115
|
let settled = false;
|
|
116
116
|
let stdoutBuffer = "";
|
|
117
117
|
let stderr = "";
|
|
@@ -192,6 +192,48 @@ async function bootstrapCodexModelCache(codexHome: string, cachePath: string): P
|
|
|
192
192
|
},
|
|
193
193
|
});
|
|
194
194
|
});
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
await refreshed;
|
|
198
|
+
} finally {
|
|
199
|
+
// `child.kill()` only signals. The caller deletes CODEX_HOME right after we
|
|
200
|
+
// return, and Windows cannot delete a directory the child still holds open
|
|
201
|
+
// (EBUSY), so wait for the process to actually exit first.
|
|
202
|
+
await waitForChildExit(child, CODEX_BOOTSTRAP_EXIT_WAIT_MS);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const CODEX_BOOTSTRAP_EXIT_WAIT_MS = 3_000;
|
|
207
|
+
|
|
208
|
+
function waitForChildExit(child: ChildProcess, timeoutMs: number): Promise<void> {
|
|
209
|
+
if (child.exitCode !== null || child.signalCode !== null) return Promise.resolve();
|
|
210
|
+
return new Promise((resolve) => {
|
|
211
|
+
const timer = setTimeout(resolve, timeoutMs);
|
|
212
|
+
timer.unref?.();
|
|
213
|
+
child.once("exit", () => {
|
|
214
|
+
clearTimeout(timer);
|
|
215
|
+
resolve();
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Remove the temporary CODEX_HOME. On Windows a just-exited child (or an
|
|
222
|
+
* antivirus scan of the files it wrote) can keep the directory busy for a
|
|
223
|
+
* moment, so retry, and never let cleanup of a throwaway directory fail a turn
|
|
224
|
+
* whose result was already read. POSIX keeps the original behaviour: unlinking
|
|
225
|
+
* open files works there, and a genuine failure still surfaces.
|
|
226
|
+
*/
|
|
227
|
+
function removeIsolatedCodexHome(dir: string): void {
|
|
228
|
+
if (process.platform !== "win32") {
|
|
229
|
+
rmSync(dir, { recursive: true, force: true });
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
try {
|
|
233
|
+
rmSync(dir, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 });
|
|
234
|
+
} catch {
|
|
235
|
+
// Best effort: the OS temp cleaner will reclaim it.
|
|
236
|
+
}
|
|
195
237
|
}
|
|
196
238
|
|
|
197
239
|
async function bootstrapIsolatedCodexModelCache(
|
|
@@ -219,7 +261,7 @@ async function bootstrapIsolatedCodexModelCache(
|
|
|
219
261
|
await bootstrap(isolatedHome, isolatedCachePath);
|
|
220
262
|
return readCompatibleCodexModelCache(isolatedCachePath).contents;
|
|
221
263
|
} finally {
|
|
222
|
-
|
|
264
|
+
removeIsolatedCodexHome(isolatedHome);
|
|
223
265
|
}
|
|
224
266
|
}
|
|
225
267
|
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
|
-
import { chmod, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import { chmod, copyFile, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
4
4
|
import type { Socket } from "node:net";
|
|
5
5
|
import { createServer } from "node:net";
|
|
6
6
|
import { tmpdir } from "node:os";
|
|
7
7
|
import { dirname, join, resolve } from "node:path";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
9
|
import { codexCliScriptPath } from "#agents/codex-native-multi-agent";
|
|
10
|
+
import { ensureCodexWindowsWrapperExe } from "#agents/codex-windows-wrapper";
|
|
10
11
|
import { deepMapStrings } from "#agents/deep-map";
|
|
11
12
|
import { referencesHostedSecretStorage, substituteHostedSecrets } from "#agents/execution-host";
|
|
12
13
|
import { shouldSubstituteVaultToolInput } from "#agents/vault-tool-policy";
|
|
@@ -104,38 +105,36 @@ export interface CodexVaultHookBridge {
|
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
/**
|
|
107
|
-
* Why
|
|
108
|
+
* Why the Windows wrapper is an `.exe`, not a script.
|
|
108
109
|
*
|
|
109
110
|
* The hook only runs if codex is invoked with `--dangerously-bypass-hook-trust`
|
|
110
|
-
*
|
|
111
|
+
* -- an argv-only flag with no config-file or environment equivalent -- and the
|
|
111
112
|
* SDK builds its own argv, so the flag can only be injected by a wrapper
|
|
112
113
|
* standing in for the codex executable. On POSIX that wrapper is the
|
|
113
|
-
* `#!/bin/sh` script
|
|
114
|
-
* `codexPathOverride` through `child_process.spawn` with no `shell`
|
|
115
|
-
* Node refuses to spawn a `.cmd`/`.bat` that way (EINVAL)
|
|
116
|
-
* executable
|
|
114
|
+
* `#!/bin/sh` script above. Windows cannot use a script: `@openai/codex-sdk`
|
|
115
|
+
* spawns `codexPathOverride` through `child_process.spawn` with no `shell`
|
|
116
|
+
* option, and Node refuses to spawn a `.cmd`/`.bat` that way (EINVAL). So on
|
|
117
|
+
* Windows the wrapper is a small compiled executable (see
|
|
118
|
+
* `codex-windows-wrapper.ts`) that reads a private per-bridge config file.
|
|
117
119
|
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
* substitution and sensitive-storage denial silently absent. The alternative —
|
|
122
|
-
* dropping the wrapper and letting the turn proceed — would leave those two
|
|
123
|
-
* protections off while everything downstream assumed they were on.
|
|
120
|
+
* A bridge failure is still fatal for the turn (`codexProvider`), so a Codex
|
|
121
|
+
* turn never runs with the Vault substitution and sensitive-storage denial
|
|
122
|
+
* silently absent.
|
|
124
123
|
*/
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
".
|
|
124
|
+
const IS_WINDOWS = process.platform === "win32";
|
|
125
|
+
|
|
126
|
+
function windowsQuote(value: string): string {
|
|
127
|
+
return `"${value.replaceAll('"', '\\"')}"`;
|
|
128
|
+
}
|
|
129
129
|
|
|
130
130
|
export async function createCodexVaultHookBridge(userId: string): Promise<CodexVaultHookBridge> {
|
|
131
|
-
if (process.platform === "win32") throw new Error(WINDOWS_BRIDGE_UNSUPPORTED);
|
|
132
131
|
const root = await mkdtemp(join(tmpdir(), "negotium-codex-vault-"));
|
|
133
132
|
await chmod(root, 0o700);
|
|
134
133
|
// Windows listens on a named pipe instead; the digest in `ipcEndpoint` is
|
|
135
134
|
// taken over this whole path, so the per-bridge mkdtemp above still supplies
|
|
136
135
|
// the uniqueness that the constant basename does not.
|
|
137
136
|
const socketPath = ipcEndpoint(join(root, "hook.sock"));
|
|
138
|
-
const wrapperPath = join(root, "codex-with-hooks");
|
|
137
|
+
const wrapperPath = join(root, IS_WINDOWS ? "codex-with-hooks.exe" : "codex-with-hooks");
|
|
139
138
|
const token = randomBytes(32).toString("hex");
|
|
140
139
|
const connections = new Set<Socket>();
|
|
141
140
|
const server = createServer((socket) => {
|
|
@@ -187,14 +186,28 @@ export async function createCodexVaultHookBridge(userId: string): Promise<CodexV
|
|
|
187
186
|
});
|
|
188
187
|
});
|
|
189
188
|
restrictIpcEndpoint(socketPath);
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
189
|
+
if (IS_WINDOWS) {
|
|
190
|
+
const { BINARIES_DIR } = await import("#platform/config");
|
|
191
|
+
const cached = await ensureCodexWindowsWrapperExe(join(BINARIES_DIR, "codex-hook-wrapper"));
|
|
192
|
+
await copyFile(cached, wrapperPath);
|
|
193
|
+
// Same private per-bridge dir as the POSIX wrapper; the exe reads this
|
|
194
|
+
// file (runtime, codex script, hook socket, hook token, one per line).
|
|
195
|
+
await writeFile(
|
|
196
|
+
join(root, "codex-with-hooks.cfg"),
|
|
197
|
+
[process.execPath, codexCliScriptPath(), socketPath, token].join("\n"),
|
|
198
|
+
{ encoding: "utf8", mode: 0o600 },
|
|
199
|
+
);
|
|
200
|
+
} else {
|
|
201
|
+
await writeFile(wrapperPath, privateCodexWrapper(codexCliScriptPath(), socketPath, token), {
|
|
202
|
+
mode: 0o700,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
193
205
|
|
|
194
206
|
// Keep the capability out of the process list and reviewed hook command.
|
|
195
207
|
// The private wrapper explicitly authorizes this runtime-owned hook for
|
|
196
208
|
// headless Codex turns.
|
|
197
|
-
const
|
|
209
|
+
const quote = IS_WINDOWS ? windowsQuote : shellQuote;
|
|
210
|
+
const command = [quote(process.execPath), quote(hookClientPath())].join(" ");
|
|
198
211
|
return {
|
|
199
212
|
codexPathOverride: wrapperPath,
|
|
200
213
|
environment: { [HOOK_SOCKET_ENV]: socketPath, [HOOK_TOKEN_ENV]: token },
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { mkdir, rename, rm, writeFile } from "node:fs/promises";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { promisify } from "node:util";
|
|
7
|
+
|
|
8
|
+
const execFileAsync = promisify(execFile);
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The Windows stand-in for the POSIX `#!/bin/sh` codex wrapper.
|
|
12
|
+
*
|
|
13
|
+
* `@openai/codex-sdk` spawns `codexPathOverride` with no `shell`, and Node
|
|
14
|
+
* refuses to spawn a `.cmd`/`.bat` that way (EINVAL), so the wrapper has to be
|
|
15
|
+
* a real executable. It is a ~40-line C# program compiled once with the
|
|
16
|
+
* `csc.exe` that ships with every Windows (.NET Framework 4), cached by source
|
|
17
|
+
* hash, and copied next to a per-bridge config file for each bridge.
|
|
18
|
+
*
|
|
19
|
+
* It is a plain console exe (`Process.Start` with inherited stdio). A GUI-subsystem
|
|
20
|
+
* variant that hides the child via CreateProcess(CREATE_NO_WINDOW) was tried and
|
|
21
|
+
* rejected: antivirus flagged it as malware. The SDK spawns this without
|
|
22
|
+
* windowsHide, so a console window may briefly appear per Codex turn.
|
|
23
|
+
*
|
|
24
|
+
* Behaviour mirrors the sh wrapper: read the private config (runtime, codex
|
|
25
|
+
* script, hook socket, hook token), export the socket/token to the child, run
|
|
26
|
+
* `<runtime> <codex script> [exec --dangerously-bypass-hook-trust] <args...>`
|
|
27
|
+
* with inherited stdio, and return the child's exit code. Unlike `exec` on
|
|
28
|
+
* POSIX there is a second process here, so the child is placed in a job object
|
|
29
|
+
* with kill-on-close: when the SDK terminates the wrapper on abort the whole
|
|
30
|
+
* codex tree goes with it instead of being orphaned.
|
|
31
|
+
*/
|
|
32
|
+
export const CODEX_WINDOWS_WRAPPER_SOURCE = String.raw`
|
|
33
|
+
using System;
|
|
34
|
+
using System.Diagnostics;
|
|
35
|
+
using System.IO;
|
|
36
|
+
using System.Runtime.InteropServices;
|
|
37
|
+
using System.Text;
|
|
38
|
+
|
|
39
|
+
static class CodexHookWrapper {
|
|
40
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
41
|
+
struct IO_COUNTERS { public ulong a, b, c, d, e, f; }
|
|
42
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
43
|
+
struct BASIC {
|
|
44
|
+
public long PerProcessUserTimeLimit, PerJobUserTimeLimit;
|
|
45
|
+
public uint LimitFlags;
|
|
46
|
+
public UIntPtr MinimumWorkingSetSize, MaximumWorkingSetSize;
|
|
47
|
+
public uint ActiveProcessLimit;
|
|
48
|
+
public UIntPtr Affinity;
|
|
49
|
+
public uint PriorityClass, SchedulingClass;
|
|
50
|
+
}
|
|
51
|
+
[StructLayout(LayoutKind.Sequential)]
|
|
52
|
+
struct EXTENDED {
|
|
53
|
+
public BASIC Basic;
|
|
54
|
+
public IO_COUNTERS Io;
|
|
55
|
+
public UIntPtr ProcessMemoryLimit, JobMemoryLimit, PeakProcessMemoryUsed, PeakJobMemoryUsed;
|
|
56
|
+
}
|
|
57
|
+
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
|
58
|
+
static extern IntPtr CreateJobObject(IntPtr attrs, string name);
|
|
59
|
+
[DllImport("kernel32.dll")]
|
|
60
|
+
static extern bool SetInformationJobObject(IntPtr job, int cls, IntPtr info, uint len);
|
|
61
|
+
[DllImport("kernel32.dll")]
|
|
62
|
+
static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);
|
|
63
|
+
|
|
64
|
+
static string Quote(string a) {
|
|
65
|
+
if (a.Length > 0 && a.IndexOfAny(new[] { ' ', '\t', '\n', '\v', '"' }) < 0) return a;
|
|
66
|
+
var sb = new StringBuilder("\"");
|
|
67
|
+
int bs = 0;
|
|
68
|
+
foreach (char c in a) {
|
|
69
|
+
if (c == '\\') { bs++; }
|
|
70
|
+
else if (c == '"') { sb.Append('\\', bs * 2 + 1); sb.Append('"'); bs = 0; }
|
|
71
|
+
else { sb.Append('\\', bs); bs = 0; sb.Append(c); }
|
|
72
|
+
}
|
|
73
|
+
sb.Append('\\', bs * 2);
|
|
74
|
+
sb.Append('"');
|
|
75
|
+
return sb.ToString();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
static IntPtr KillOnCloseJob() {
|
|
79
|
+
IntPtr job = CreateJobObject(IntPtr.Zero, null);
|
|
80
|
+
if (job == IntPtr.Zero) return IntPtr.Zero;
|
|
81
|
+
var info = new EXTENDED();
|
|
82
|
+
info.Basic.LimitFlags = 0x2000; // JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
|
|
83
|
+
int size = Marshal.SizeOf(typeof(EXTENDED));
|
|
84
|
+
IntPtr mem = Marshal.AllocHGlobal(size);
|
|
85
|
+
try {
|
|
86
|
+
Marshal.StructureToPtr(info, mem, false);
|
|
87
|
+
if (!SetInformationJobObject(job, 9, mem, (uint)size)) return IntPtr.Zero;
|
|
88
|
+
} finally { Marshal.FreeHGlobal(mem); }
|
|
89
|
+
return job;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
static int Main(string[] args) {
|
|
93
|
+
string self = Process.GetCurrentProcess().MainModule.FileName;
|
|
94
|
+
string[] cfg = File.ReadAllLines(Path.ChangeExtension(self, ".cfg"), Encoding.UTF8);
|
|
95
|
+
if (cfg.Length < 4) { Console.Error.WriteLine("codex hook wrapper: bad config"); return 70; }
|
|
96
|
+
var sb = new StringBuilder(Quote(cfg[1]));
|
|
97
|
+
int i = 0;
|
|
98
|
+
if (args.Length > 0 && args[0] == "exec") {
|
|
99
|
+
sb.Append(" exec --dangerously-bypass-hook-trust");
|
|
100
|
+
i = 1;
|
|
101
|
+
}
|
|
102
|
+
for (; i < args.Length; i++) sb.Append(' ').Append(Quote(args[i]));
|
|
103
|
+
|
|
104
|
+
// No CreateNoWindow: with it the child stops inheriting our stdio handles.
|
|
105
|
+
var psi = new ProcessStartInfo(cfg[0], sb.ToString());
|
|
106
|
+
psi.UseShellExecute = false;
|
|
107
|
+
psi.EnvironmentVariables["NEGOTIUM_CODEX_VAULT_HOOK_SOCKET"] = cfg[2];
|
|
108
|
+
psi.EnvironmentVariables["NEGOTIUM_CODEX_VAULT_HOOK_TOKEN"] = cfg[3];
|
|
109
|
+
IntPtr job = KillOnCloseJob();
|
|
110
|
+
using (Process p = Process.Start(psi)) {
|
|
111
|
+
if (job != IntPtr.Zero) AssignProcessToJobObject(job, p.Handle);
|
|
112
|
+
p.WaitForExit();
|
|
113
|
+
return p.ExitCode;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
`;
|
|
118
|
+
|
|
119
|
+
function cscPath(): string {
|
|
120
|
+
const windir = process.env.WINDIR ?? process.env.SystemRoot ?? "C:\\Windows";
|
|
121
|
+
for (const framework of ["Framework64", "Framework"]) {
|
|
122
|
+
const candidate = join(windir, "Microsoft.NET", framework, "v4.0.30319", "csc.exe");
|
|
123
|
+
if (existsSync(candidate)) return candidate;
|
|
124
|
+
}
|
|
125
|
+
throw new Error(
|
|
126
|
+
"csc.exe (.NET Framework 4) was not found, so the Codex hook wrapper cannot be built",
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Path to the compiled wrapper, building it on first use. The cache key is the
|
|
132
|
+
* source hash, so a changed wrapper is rebuilt and old copies are just ignored.
|
|
133
|
+
* Compilation writes to a temp name and renames, so concurrent turns never see
|
|
134
|
+
* a half-written exe.
|
|
135
|
+
*/
|
|
136
|
+
export async function ensureCodexWindowsWrapperExe(cacheDir: string): Promise<string> {
|
|
137
|
+
const digest = createHash("sha256")
|
|
138
|
+
.update(CODEX_WINDOWS_WRAPPER_SOURCE)
|
|
139
|
+
.digest("hex")
|
|
140
|
+
.slice(0, 12);
|
|
141
|
+
const exePath = join(cacheDir, `codex-hook-wrapper-${digest}.exe`);
|
|
142
|
+
if (existsSync(exePath)) return exePath;
|
|
143
|
+
|
|
144
|
+
await mkdir(cacheDir, { recursive: true });
|
|
145
|
+
const stamp = randomUUID();
|
|
146
|
+
const sourcePath = join(cacheDir, `wrapper-${stamp}.cs`);
|
|
147
|
+
const tempExe = join(cacheDir, `wrapper-${stamp}.exe`);
|
|
148
|
+
try {
|
|
149
|
+
await writeFile(sourcePath, CODEX_WINDOWS_WRAPPER_SOURCE, "utf8");
|
|
150
|
+
await execFileAsync(
|
|
151
|
+
cscPath(),
|
|
152
|
+
["/nologo", "/target:exe", "/optimize+", `/out:${tempExe}`, sourcePath],
|
|
153
|
+
{ windowsHide: true, timeout: 60_000 },
|
|
154
|
+
);
|
|
155
|
+
try {
|
|
156
|
+
await rename(tempExe, exePath);
|
|
157
|
+
} catch (error) {
|
|
158
|
+
// Another turn finished the same build first; its exe is equivalent.
|
|
159
|
+
if (!existsSync(exePath)) throw error;
|
|
160
|
+
}
|
|
161
|
+
return exePath;
|
|
162
|
+
} catch (error) {
|
|
163
|
+
const detail =
|
|
164
|
+
error && typeof error === "object" && "stdout" in error
|
|
165
|
+
? String((error as { stdout?: unknown }).stdout ?? "").trim()
|
|
166
|
+
: "";
|
|
167
|
+
throw new Error(
|
|
168
|
+
`Failed to build the Codex hook wrapper: ${error instanceof Error ? error.message : String(error)}${detail ? `\n${detail}` : ""}`,
|
|
169
|
+
);
|
|
170
|
+
} finally {
|
|
171
|
+
await rm(sourcePath, { force: true });
|
|
172
|
+
await rm(tempExe, { force: true });
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -17,3 +17,22 @@ Use a tool only when it is actually available; otherwise say so instead of prete
|
|
|
17
17
|
- Scheduled tasks: manage with `cron-manager` tools; scripts must already exist (`cron_list_scripts`). Jobs in one topic share a Cron conversation, so `cron_reset` clears the topic's whole Cron context, not one job.
|
|
18
18
|
- Heavy work (large files, video encode, big crawls, browser automation): check `get_system_health` first and back off under resource pressure.
|
|
19
19
|
- Computer Use: if unavailable, check `get_mcp_config` for optional `cua-rs`; MCP changes apply next session.
|
|
20
|
+
|
|
21
|
+
## Browser
|
|
22
|
+
Reading pages:
|
|
23
|
+
- Escalate in this order: `browser_snapshot` (interactive elements only) → full snapshot → wait briefly and re-snapshot if the page is still changing → screenshot as a last resort. Never make a screenshot the first move.
|
|
24
|
+
- Never truncate a snapshot. Refs are invalidated by every new snapshot, so re-snapshot after each action, and never mix a ref into a CSS selector.
|
|
25
|
+
|
|
26
|
+
Acting:
|
|
27
|
+
- Click and navigation tools already wait for the page to settle, so do not add a habitual wait right after them. Wait only when a fresh snapshot shows the page is still changing.
|
|
28
|
+
- Treat an action as unconfirmed until a fresh snapshot shows the expected state.
|
|
29
|
+
- When the next step does not depend on the new page state, batch the steps into one `browser_evaluate` call.
|
|
30
|
+
- Do not guess URLs except for well-known destinations; follow links instead.
|
|
31
|
+
|
|
32
|
+
When something fails:
|
|
33
|
+
- Dismiss popups and cookie banners first. If a click fails as obscured, inspect what actually covers the target before retrying.
|
|
34
|
+
- If the same approach fails 2-3 times, switch to a different path rather than retrying with another selector.
|
|
35
|
+
- If the page state is unexpected, suspect a missed or wrong-target action before inferring site-specific rules.
|
|
36
|
+
|
|
37
|
+
Coordinate input:
|
|
38
|
+
- Use `browser_pointer`, `browser_wheel`, and `browser_drag` only for things the accessibility tree cannot expose (canvases, drag handles, maps), and return to ref-based actions immediately afterward.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const NEGOTIUM_VERSION = "0.
|
|
1
|
+
export const NEGOTIUM_VERSION = "0.19.0";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Windows stand-in for the POSIX `#!/bin/sh` codex wrapper.
|
|
3
|
+
*
|
|
4
|
+
* `@openai/codex-sdk` spawns `codexPathOverride` with no `shell`, and Node
|
|
5
|
+
* refuses to spawn a `.cmd`/`.bat` that way (EINVAL), so the wrapper has to be
|
|
6
|
+
* a real executable. It is a ~40-line C# program compiled once with the
|
|
7
|
+
* `csc.exe` that ships with every Windows (.NET Framework 4), cached by source
|
|
8
|
+
* hash, and copied next to a per-bridge config file for each bridge.
|
|
9
|
+
*
|
|
10
|
+
* It is a plain console exe (`Process.Start` with inherited stdio). A GUI-subsystem
|
|
11
|
+
* variant that hides the child via CreateProcess(CREATE_NO_WINDOW) was tried and
|
|
12
|
+
* rejected: antivirus flagged it as malware. The SDK spawns this without
|
|
13
|
+
* windowsHide, so a console window may briefly appear per Codex turn.
|
|
14
|
+
*
|
|
15
|
+
* Behaviour mirrors the sh wrapper: read the private config (runtime, codex
|
|
16
|
+
* script, hook socket, hook token), export the socket/token to the child, run
|
|
17
|
+
* `<runtime> <codex script> [exec --dangerously-bypass-hook-trust] <args...>`
|
|
18
|
+
* with inherited stdio, and return the child's exit code. Unlike `exec` on
|
|
19
|
+
* POSIX there is a second process here, so the child is placed in a job object
|
|
20
|
+
* with kill-on-close: when the SDK terminates the wrapper on abort the whole
|
|
21
|
+
* codex tree goes with it instead of being orphaned.
|
|
22
|
+
*/
|
|
23
|
+
export declare const CODEX_WINDOWS_WRAPPER_SOURCE: string;
|
|
24
|
+
/**
|
|
25
|
+
* Path to the compiled wrapper, building it on first use. The cache key is the
|
|
26
|
+
* source hash, so a changed wrapper is rebuilt and old copies are just ignored.
|
|
27
|
+
* Compilation writes to a temp name and renames, so concurrent turns never see
|
|
28
|
+
* a half-written exe.
|
|
29
|
+
*/
|
|
30
|
+
export declare function ensureCodexWindowsWrapperExe(cacheDir: string): Promise<string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const NEGOTIUM_VERSION = "0.
|
|
1
|
+
export declare const NEGOTIUM_VERSION = "0.19.0";
|
package/package.json
CHANGED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../packages/core/src/agents/codex-app-server.ts", "../../../packages/core/src/agents/codex-native-multi-agent.ts", "../../../packages/core/src/version.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import { type ChildProcessWithoutNullStreams, spawn } from \"node:child_process\";\nimport { codexCliScriptPath } from \"#agents/codex-native-multi-agent\";\nimport { hostedCodexHomePath } from \"#agents/execution-host\";\nimport { latestCodexRolloutPath } from \"#agents/rollout/codex\";\nimport { NEGOTIUM_VERSION } from \"#version\";\n\ninterface CodexAppServerForkResult {\n forkId: string;\n rolloutPath: string;\n}\n\ninterface CodexAppServerForkHost {\n spawnServer(): ChildProcessWithoutNullStreams;\n findRolloutPath(threadId: string): string | undefined;\n timeoutMs: number;\n}\n\ntype JsonRpcResponse = {\n id?: number;\n result?: { thread?: { id?: unknown } };\n error?: { message?: unknown };\n};\n\nexport function createCodexAppServerForker(host: CodexAppServerForkHost) {\n return async (parentThreadId: string): Promise<CodexAppServerForkResult> => {\n const child = host.spawnServer();\n\n return await new Promise<CodexAppServerForkResult>((resolve, reject) => {\n let settled = false;\n let stdoutBuffer = \"\";\n let stderr = \"\";\n const timer = setTimeout(\n () => finish(new Error(\"Codex thread fork timed out\")),\n host.timeoutMs,\n );\n\n const finish = (error?: Error, result?: CodexAppServerForkResult) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n try {\n child.stdin.end();\n child.kill();\n } catch {\n // The app server may already have exited after stdin closed.\n }\n if (error) reject(error);\n else if (result) resolve(result);\n else reject(new Error(\"Codex thread fork returned no result\"));\n };\n\n const send = (message: Record<string, unknown>) => {\n child.stdin.write(`${JSON.stringify(message)}\\n`);\n };\n\n child.stderr.on(\"data\", (chunk) => {\n if (stderr.length < 8_192) stderr += String(chunk);\n });\n child.on(\"error\", (error) => finish(error));\n child.on(\"exit\", (code, signal) => {\n if (settled) return;\n const detail = signal ? `signal ${signal}` : `code ${code ?? 1}`;\n finish(\n new Error(\n `Codex app server exited with ${detail}${stderr.trim() ? `: ${stderr.trim()}` : \"\"}`,\n ),\n );\n });\n child.stdout.on(\"data\", (chunk) => {\n stdoutBuffer += String(chunk);\n for (;;) {\n const newline = stdoutBuffer.indexOf(\"\\n\");\n if (newline < 0) break;\n const line = stdoutBuffer.slice(0, newline);\n stdoutBuffer = stdoutBuffer.slice(newline + 1);\n let message: JsonRpcResponse;\n try {\n message = JSON.parse(line) as JsonRpcResponse;\n } catch {\n continue;\n }\n\n if (message.id === 1) {\n if (message.error) {\n finish(new Error(String(message.error.message || \"Codex initialization failed\")));\n return;\n }\n send({ method: \"initialized\" });\n send({ id: 2, method: \"thread/fork\", params: { threadId: parentThreadId } });\n continue;\n }\n if (message.id !== 2) continue;\n if (message.error) {\n finish(new Error(String(message.error.message || \"Codex thread fork failed\")));\n return;\n }\n const forkId = message.result?.thread?.id;\n if (typeof forkId !== \"string\" || !forkId) {\n finish(new Error(\"Codex thread fork returned no thread id\"));\n return;\n }\n const rolloutPath = host.findRolloutPath(forkId);\n if (!rolloutPath) {\n finish(new Error(`Codex thread fork rollout was not found for ${forkId}`));\n return;\n }\n finish(undefined, { forkId, rolloutPath });\n return;\n }\n });\n\n send({\n id: 1,\n method: \"initialize\",\n params: {\n clientInfo: { name: \"negotium\", version: NEGOTIUM_VERSION },\n },\n });\n });\n };\n}\n\nconst forkCodexThread = createCodexAppServerForker({\n spawnServer() {\n return spawn(process.execPath, [codexCliScriptPath(), \"app-server\", \"--stdio\"], {\n env: { ...process.env, CODEX_HOME: hostedCodexHomePath() },\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n // Background stdio server — no console window on Windows. Ignored on POSIX.\n windowsHide: true,\n });\n },\n findRolloutPath: latestCodexRolloutPath,\n timeoutMs: 15_000,\n});\n\nexport async function forkCodexSession(parentThreadId: string): Promise<CodexAppServerForkResult> {\n return await forkCodexThread(parentThreadId);\n}\n",
|
|
6
|
-
"import { spawn } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport {\n chmodSync,\n copyFileSync,\n existsSync,\n mkdtempSync,\n readFileSync,\n renameSync,\n rmSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { NEGOTIUM_VERSION } from \"#version\";\n\ntype CodexModel = Record<string, unknown>;\ntype CodexModelCache = {\n client_version?: unknown;\n models?: unknown;\n};\n\nconst moduleRequire = createRequire(import.meta.url);\nconst codexSdkPackagePath = moduleRequire.resolve(\"@openai/codex-sdk/package.json\");\nconst codexSdkRequire = createRequire(codexSdkPackagePath);\nconst bundledCodexPackagePath = codexSdkRequire.resolve(\"@openai/codex/package.json\");\n\nfunction readPackageVersion(packageJsonPath: string): string {\n const parsed = JSON.parse(readFileSync(packageJsonPath, \"utf8\")) as { version?: unknown };\n if (typeof parsed.version !== \"string\" || !parsed.version.trim()) {\n throw new Error(`Codex package has no valid version: ${packageJsonPath}`);\n }\n return parsed.version;\n}\n\nexport const BUNDLED_CODEX_VERSION = readPackageVersion(bundledCodexPackagePath);\nconst SAFE_BUNDLED_CODEX_VERSION = BUNDLED_CODEX_VERSION.replace(/[^a-zA-Z0-9._-]/g, \"_\");\nconst NEGOTIUM_MODEL_CACHE = `negotium-models-cache-${SAFE_BUNDLED_CODEX_VERSION}.json`;\nconst NEGOTIUM_MODEL_CATALOG = `negotium-model-catalog-${SAFE_BUNDLED_CODEX_VERSION}.json`;\n\nexport function codexCliScriptPath(): string {\n return join(dirname(bundledCodexPackagePath), \"bin\", \"codex.js\");\n}\n\nfunction parseCodexModelCache(contents: string, sourcePath: string): CodexModelCache {\n let parsed: CodexModelCache;\n try {\n parsed = JSON.parse(contents) as CodexModelCache;\n } catch (error) {\n throw new Error(`Codex model cache is invalid JSON: ${sourcePath}`, { cause: error });\n }\n if (!Array.isArray(parsed.models) || parsed.models.length === 0) {\n throw new Error(`Codex model cache has no models: ${sourcePath}`);\n }\n return parsed;\n}\n\nfunction readCodexModelCache(cachePath: string): {\n contents: string;\n parsed: CodexModelCache;\n} {\n const contents = readFileSync(cachePath, \"utf8\");\n return { contents, parsed: parseCodexModelCache(contents, cachePath) };\n}\n\nfunction readCompatibleCodexModelCache(cachePath: string): {\n contents: string;\n parsed: CodexModelCache;\n} {\n const cache = readCodexModelCache(cachePath);\n if (cache.parsed.client_version !== BUNDLED_CODEX_VERSION) {\n const found =\n typeof cache.parsed.client_version === \"string\"\n ? cache.parsed.client_version\n : \"missing or invalid\";\n throw new Error(\n `Codex model cache version ${found} does not match Negotium's bundled Codex ${BUNDLED_CODEX_VERSION}: ${cachePath}`,\n );\n }\n return cache;\n}\n\nfunction writePrivateFileAtomic(path: string, contents: string): void {\n if (existsSync(path) && readFileSync(path, \"utf8\") === contents) return;\n\n const tempPath = `${path}.${process.pid}.${randomUUID()}.tmp`;\n try {\n writeFileSync(tempPath, contents, { encoding: \"utf8\", mode: 0o600 });\n renameSync(tempPath, path);\n chmodSync(path, 0o600);\n } finally {\n try {\n unlinkSync(tempPath);\n } catch {\n // renameSync normally consumed the temporary file.\n }\n }\n}\n\nexport function bundledCodexModelCachePath(authFilePath: string): string {\n return join(dirname(authFilePath), NEGOTIUM_MODEL_CACHE);\n}\n\nasync function bootstrapCodexModelCache(codexHome: string, cachePath: string): Promise<void> {\n const child = spawn(process.execPath, [codexCliScriptPath(), \"app-server\", \"--stdio\"], {\n env: { ...process.env, CODEX_HOME: codexHome },\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n // Background stdio server — no console window on Windows. Ignored on POSIX.\n windowsHide: true,\n });\n\n await new Promise<void>((resolve, reject) => {\n let settled = false;\n let stdoutBuffer = \"\";\n let stderr = \"\";\n const timer = setTimeout(\n () => finish(new Error(\"timed out while refreshing the Codex model catalog\")),\n 15_000,\n );\n\n const finish = (error?: Error) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n try {\n child.stdin.end();\n child.kill();\n } catch {\n // The app server may already have exited after stdin closed.\n }\n if (error) reject(error);\n else if (!existsSync(cachePath)) reject(new Error(\"Codex did not create its model cache\"));\n else resolve();\n };\n\n const send = (message: Record<string, unknown>) => {\n child.stdin.write(`${JSON.stringify(message)}\\n`);\n };\n\n child.stderr.on(\"data\", (chunk) => {\n if (stderr.length < 4_096) stderr += String(chunk);\n });\n child.on(\"error\", (error) => finish(error));\n child.on(\"exit\", (code, signal) => {\n if (!settled) {\n finish(\n new Error(\n `Codex model catalog refresh exited with ${signal ? `signal ${signal}` : `code ${code ?? 1}`}${stderr.trim() ? `: ${stderr.trim()}` : \"\"}`,\n ),\n );\n }\n });\n child.stdout.on(\"data\", (chunk) => {\n stdoutBuffer += String(chunk);\n for (;;) {\n const newline = stdoutBuffer.indexOf(\"\\n\");\n if (newline < 0) break;\n const line = stdoutBuffer.slice(0, newline);\n stdoutBuffer = stdoutBuffer.slice(newline + 1);\n let message: { id?: number; error?: { message?: string } };\n try {\n message = JSON.parse(line) as typeof message;\n } catch {\n continue;\n }\n if (message.id === 1) {\n if (message.error) {\n finish(new Error(message.error.message || \"Codex initialization failed\"));\n return;\n }\n send({ method: \"initialized\" });\n send({ id: 2, method: \"model/list\", params: { includeHidden: true } });\n } else if (message.id === 2) {\n if (message.error) {\n finish(new Error(message.error.message || \"Codex model listing failed\"));\n } else {\n finish();\n }\n return;\n }\n }\n });\n\n send({\n id: 1,\n method: \"initialize\",\n params: {\n clientInfo: { name: \"negotium\", version: NEGOTIUM_VERSION },\n capabilities: { experimentalApi: true },\n },\n });\n });\n}\n\nasync function bootstrapIsolatedCodexModelCache(\n authFilePath: string,\n bootstrap: (codexHome: string, cachePath: string) => Promise<void>,\n): Promise<string> {\n const sourceHome = dirname(authFilePath);\n const isolatedHome = mkdtempSync(join(tmpdir(), \"negotium-codex-models-\"));\n const isolatedCachePath = join(isolatedHome, \"models_cache.json\");\n\n try {\n const isolatedAuthPath = join(isolatedHome, \"auth.json\");\n copyFileSync(authFilePath, isolatedAuthPath);\n chmodSync(isolatedAuthPath, 0o600);\n\n // Preserve custom provider configuration while keeping the bundled CLI's\n // cache write completely outside the user's shared CODEX_HOME.\n const sourceConfigPath = join(sourceHome, \"config.toml\");\n if (existsSync(sourceConfigPath)) {\n const isolatedConfigPath = join(isolatedHome, \"config.toml\");\n copyFileSync(sourceConfigPath, isolatedConfigPath);\n chmodSync(isolatedConfigPath, 0o600);\n }\n\n await bootstrap(isolatedHome, isolatedCachePath);\n return readCompatibleCodexModelCache(isolatedCachePath).contents;\n } finally {\n rmSync(isolatedHome, { recursive: true, force: true });\n }\n}\n\nexport async function ensureCodexModelCache(\n authFilePath: string,\n bootstrap: (codexHome: string, cachePath: string) => Promise<void> = bootstrapCodexModelCache,\n): Promise<string> {\n const codexHome = dirname(authFilePath);\n const configuredCachePath = process.env.NEGOTIUM_CODEX_MODELS_CACHE_FILE;\n if (configuredCachePath) {\n if (!existsSync(configuredCachePath)) {\n throw new Error(`Configured Codex model cache does not exist: ${configuredCachePath}`);\n }\n readCompatibleCodexModelCache(configuredCachePath);\n return configuredCachePath;\n }\n\n // The global Codex CLI owns models_cache.json and may update it to a schema\n // newer than the SDK bundled by Negotium. Snapshot a cache generated for our\n // exact bundled version so later global CLI updates cannot break turns.\n const bundledCachePath = bundledCodexModelCachePath(authFilePath);\n const sharedCachePath = join(codexHome, \"models_cache.json\");\n if (existsSync(sharedCachePath)) {\n try {\n const shared = readCompatibleCodexModelCache(sharedCachePath);\n // Keep model metadata fresh while the global CLI remains compatible.\n writePrivateFileAtomic(bundledCachePath, shared.contents);\n return bundledCachePath;\n } catch {\n // A compatible private snapshot is safer than failing because another\n // process briefly exposed an incomplete shared-cache write.\n }\n }\n\n if (existsSync(bundledCachePath)) {\n try {\n readCompatibleCodexModelCache(bundledCachePath);\n return bundledCachePath;\n } catch {\n // Re-bootstrap below instead of passing a corrupt or version-mismatched\n // private snapshot into this SDK version.\n }\n }\n\n const refreshedContents = await bootstrapIsolatedCodexModelCache(authFilePath, bootstrap);\n writePrivateFileAtomic(bundledCachePath, refreshedContents);\n return bundledCachePath;\n}\n\n/**\n * Codex can resolve model metadata before `features.multi_agent=false`, so a\n * model-advertised v1/v2 value may still register native collaboration tools.\n * Feed Codex an authoritative copy of its own catalog with only that field\n * disabled. Runtime MCP delegation remains available independently.\n */\nexport function writeCodexCatalogWithNativeMultiAgentDisabled(\n authFilePath: string,\n sourcePath: string,\n): string {\n const codexHome = dirname(authFilePath);\n const outputPath = join(codexHome, NEGOTIUM_MODEL_CATALOG);\n\n const parsed = readCodexModelCache(sourcePath).parsed;\n\n const models = (parsed.models as unknown[]).map((model, index): CodexModel => {\n if (!model || typeof model !== \"object\" || Array.isArray(model)) {\n throw new Error(`Codex model cache entry ${index} is invalid: ${sourcePath}`);\n }\n return { ...(model as CodexModel), multi_agent_version: \"disabled\" };\n });\n const contents = `${JSON.stringify({ models }, null, 2)}\\n`;\n writePrivateFileAtomic(outputPath, contents);\n return outputPath;\n}\n",
|
|
7
|
-
"export const NEGOTIUM_VERSION = \"0.18.2\";\n"
|
|
8
|
-
],
|
|
9
|
-
"mappings": "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",
|
|
10
|
-
"debugId": "BEFB3E8C582938DC64756E2164756E21",
|
|
11
|
-
"names": []
|
|
12
|
-
}
|