@parall/codex-agent 1.31.0 → 1.32.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.
@@ -14,28 +14,28 @@ export class JsonRpcStdioClient {
14
14
  killProcess;
15
15
  nextId = 1;
16
16
  pending = new Map();
17
- buffer = "";
17
+ buffer = '';
18
18
  onNotification = null;
19
19
  disposed = false;
20
20
  constructor(proc, requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS, killProcess) {
21
21
  this.proc = proc;
22
22
  this.requestTimeoutMs = requestTimeoutMs;
23
23
  this.killProcess = killProcess;
24
- proc.stdout.setEncoding("utf8");
25
- proc.stdout.on("data", (chunk) => this.ingest(chunk));
26
- proc.once("close", () => this.dispose(new Error("app-server subprocess closed")));
27
- proc.once("error", (err) => this.dispose(err));
28
- proc.stdin.on("error", (err) => this.killUnhealthy(err));
24
+ proc.stdout.setEncoding('utf8');
25
+ proc.stdout.on('data', (chunk) => this.ingest(chunk));
26
+ proc.once('close', () => this.dispose(new Error('app-server subprocess closed')));
27
+ proc.once('error', (err) => this.dispose(err));
28
+ proc.stdin.on('error', (err) => this.killUnhealthy(err));
29
29
  }
30
30
  setNotificationHandler(handler) {
31
31
  this.onNotification = handler;
32
32
  }
33
33
  sendRequest(method, params) {
34
34
  if (this.disposed) {
35
- return Promise.reject(new Error("JSON-RPC client disposed"));
35
+ return Promise.reject(new Error('JSON-RPC client disposed'));
36
36
  }
37
37
  const id = this.nextId++;
38
- const request = { jsonrpc: "2.0", id, method, params };
38
+ const request = { jsonrpc: '2.0', id, method, params };
39
39
  const promise = new Promise((resolve, reject) => {
40
40
  const timer = setTimeout(() => {
41
41
  const pending = this.pending.get(id);
@@ -53,7 +53,7 @@ export class JsonRpcStdioClient {
53
53
  sendNotification(method, params) {
54
54
  if (this.disposed)
55
55
  return;
56
- const notification = { jsonrpc: "2.0", method, params };
56
+ const notification = { jsonrpc: '2.0', method, params };
57
57
  this.writeFrame(notification);
58
58
  }
59
59
  isDisposed() {
@@ -84,19 +84,19 @@ export class JsonRpcStdioClient {
84
84
  this.killProcess(this.proc);
85
85
  }
86
86
  else {
87
- this.proc.kill("SIGTERM");
87
+ this.proc.kill('SIGTERM');
88
88
  }
89
89
  }
90
90
  }
91
91
  ingest(chunk) {
92
92
  this.buffer += chunk;
93
- let newlineIndex = this.buffer.indexOf("\n");
93
+ let newlineIndex = this.buffer.indexOf('\n');
94
94
  while (newlineIndex >= 0) {
95
95
  const line = this.buffer.slice(0, newlineIndex).trim();
96
96
  this.buffer = this.buffer.slice(newlineIndex + 1);
97
97
  if (line)
98
98
  this.handleLine(line);
99
- newlineIndex = this.buffer.indexOf("\n");
99
+ newlineIndex = this.buffer.indexOf('\n');
100
100
  }
101
101
  }
102
102
  handleLine(line) {
@@ -114,7 +114,7 @@ export class JsonRpcStdioClient {
114
114
  this.pending.delete(message.id);
115
115
  clearTimeout(pending.timer);
116
116
  if (message.error) {
117
- pending.reject(new Error(message.error.message || "JSON-RPC error"));
117
+ pending.reject(new Error(message.error.message || 'JSON-RPC error'));
118
118
  }
119
119
  else {
120
120
  pending.resolve(message.result);
@@ -127,8 +127,8 @@ export class JsonRpcStdioClient {
127
127
  }
128
128
  }
129
129
  function isResponse(m) {
130
- return !!m && typeof m === "object" && "id" in m && ("result" in m || "error" in m);
130
+ return !!m && typeof m === 'object' && 'id' in m && ('result' in m || 'error' in m);
131
131
  }
132
132
  function isNotification(m) {
133
- return !!m && typeof m === "object" && "method" in m && !("id" in m);
133
+ return !!m && typeof m === 'object' && 'method' in m && !('id' in m);
134
134
  }
@@ -1,4 +1,4 @@
1
- import type { ForkSessionHandle } from "@parall/agent-core";
1
+ import type { ForkSessionHandle } from '@parall/agent-core';
2
2
  type Logger = {
3
3
  warn(message: string): void;
4
4
  };
@@ -1 +1 @@
1
- {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../src/session-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAO5D,KAAK,MAAM,GAAG;IAAE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAE9C;;;;;GAKG;AACH,qBAAa,mBAAmB;IAI5B,QAAQ,CAAC,cAAc,EAAE,MAAM;IAC/B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAL1B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA6B;gBAG5C,cAAc,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,MAAM,CAAC,EAAE,MAAM,YAAA;IAKlC,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAInC,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAInD,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IAOnD,oBAAoB,IAAI,iBAAiB;IAOzC,WAAW,CAAC,UAAU,EAAE,MAAM;IAI9B,6EAA6E;IAC7E,eAAe;IAWf,OAAO,CAAC,OAAO;IAgBf,OAAO,CAAC,OAAO;CAqBhB"}
1
+ {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../src/session-manager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAO5D,KAAK,MAAM,GAAG;IAAE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAE9C;;;;;GAKG;AACH,qBAAa,mBAAmB;IAI5B,QAAQ,CAAC,cAAc,EAAE,MAAM;IAC/B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAL1B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA6B;gBAG5C,cAAc,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,MAAM,CAAC,EAAE,MAAM,YAAA;IAKlC,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAInC,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAInD,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IAOnD,oBAAoB,IAAI,iBAAiB;IAOzC,WAAW,CAAC,UAAU,EAAE,MAAM;IAI9B,6EAA6E;IAC7E,eAAe;IAWf,OAAO,CAAC,OAAO;IAoBf,OAAO,CAAC,OAAO;CAqBhB"}
@@ -1,5 +1,5 @@
1
- import * as fs from "node:fs";
2
- import * as path from "node:path";
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
3
  /**
4
4
  * Persists the app-server `threadId` for the main Parall session so the
5
5
  * bridge can resume across restarts via `thread/resume`. Fork sessions
@@ -50,14 +50,16 @@ export class CodexSessionManager {
50
50
  }
51
51
  restore() {
52
52
  try {
53
- const raw = fs.readFileSync(this.stateFilePath, "utf8");
53
+ const raw = fs.readFileSync(this.stateFilePath, 'utf8');
54
54
  const parsed = JSON.parse(raw);
55
- if (parsed.runtimeKey === this.mainSessionKey && typeof parsed.threadId === "string" && parsed.threadId.trim()) {
55
+ if (parsed.runtimeKey === this.mainSessionKey &&
56
+ typeof parsed.threadId === 'string' &&
57
+ parsed.threadId.trim()) {
56
58
  this.threadIds.set(this.mainSessionKey, parsed.threadId.trim());
57
59
  }
58
60
  }
59
61
  catch (error) {
60
- if (error?.code !== "ENOENT") {
62
+ if (error?.code !== 'ENOENT') {
61
63
  this.logger?.warn(`codex-agent: could not restore main thread state from ${this.stateFilePath}: ${String(error)}`);
62
64
  }
63
65
  }
@@ -1,4 +1,4 @@
1
- import type { AgentIdentity } from "@parall/agent-core";
1
+ import type { AgentIdentity } from '@parall/agent-core';
2
2
  /**
3
3
  * Ensure the workspace directory is marked as trusted in the global Codex
4
4
  * config so that project-level `developer_instructions` are loaded at
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,GAAG,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GACpC,IAAI,CAyEN;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAK/E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,GAAG,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GACpC,IAAI,CA6CN;AASD,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,MAAM,EACpB,GAAG,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,EACrC,aAAa,CAAC,EAAE,aAAa,GAC5B,IAAI,CAqBN"}
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,GAAG,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GACpC,IAAI,CAgFN;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAK/E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,GAAG,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,GACpC,IAAI,CA6CN;AASD,wBAAgB,oBAAoB,CAClC,YAAY,EAAE,MAAM,EACpB,GAAG,CAAC,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,EACrC,aAAa,CAAC,EAAE,aAAa,GAC5B,IAAI,CAqBN"}
package/dist/workspace.js CHANGED
@@ -1,7 +1,7 @@
1
- import * as fs from "node:fs";
2
- import * as path from "node:path";
3
- import { parse as parseToml } from "smol-toml";
4
- import { BRIDGE_WORKSPACE_INSTRUCTIONS, PRLL_BEHAVIOR, PRLL_REFERENCE_GUIDE, buildIdentity, buildSkillReferences, writeSkillFiles, } from "@parall/agent-core";
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { parse as parseToml } from 'smol-toml';
4
+ import { BRIDGE_WORKSPACE_INSTRUCTIONS, PRLL_BEHAVIOR, PRLL_REFERENCE_GUIDE, buildIdentity, buildSkillReferences, writeSkillFiles, } from '@parall/agent-core';
5
5
  /**
6
6
  * Ensure the workspace directory is marked as trusted in the global Codex
7
7
  * config so that project-level `developer_instructions` are loaded at
@@ -13,15 +13,15 @@ import { BRIDGE_WORKSPACE_INSTRUCTIONS, PRLL_BEHAVIOR, PRLL_REFERENCE_GUIDE, bui
13
13
  * the bridge from starting.
14
14
  */
15
15
  export function ensureWorkspaceTrusted(codexHome, workspaceDir, log) {
16
- const configPath = path.join(codexHome, "config.toml");
16
+ const configPath = path.join(codexHome, 'config.toml');
17
17
  const normalizedPath = path.resolve(workspaceDir);
18
18
  try {
19
- let content = "";
19
+ let content = '';
20
20
  try {
21
- content = fs.readFileSync(configPath, "utf8");
21
+ content = fs.readFileSync(configPath, 'utf8');
22
22
  }
23
23
  catch (err) {
24
- if (err.code !== "ENOENT")
24
+ if (err.code !== 'ENOENT')
25
25
  throw err;
26
26
  }
27
27
  // Structured read — know exactly what state we're in.
@@ -37,10 +37,10 @@ export function ensureWorkspaceTrusted(codexHome, workspaceDir, log) {
37
37
  }
38
38
  }
39
39
  const projects = parsed?.projects;
40
- if (projects?.[normalizedPath]?.trust_level === "trusted")
40
+ if (projects?.[normalizedPath]?.trust_level === 'trusted')
41
41
  return;
42
42
  // TOML basic-string keys require backslash and double-quote escaping.
43
- const escapedPath = normalizedPath.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
43
+ const escapedPath = normalizedPath.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
44
44
  const sectionHeader = `[projects."${escapedPath}"]`;
45
45
  const trustLine = 'trust_level = "trusted"';
46
46
  const headerIdx = content.indexOf(sectionHeader);
@@ -49,7 +49,7 @@ export function ensureWorkspaceTrusted(codexHome, workspaceDir, log) {
49
49
  // within the section (up to the next `[` header or EOF) for an
50
50
  // existing trust_level key — it may not be the first line after
51
51
  // the header if the user added comments or other keys.
52
- const headerLineEnd = content.indexOf("\n", headerIdx);
52
+ const headerLineEnd = content.indexOf('\n', headerIdx);
53
53
  if (headerLineEnd === -1) {
54
54
  content = `${content}\n${trustLine}\n`;
55
55
  }
@@ -64,10 +64,11 @@ export function ensureWorkspaceTrusted(codexHome, workspaceDir, log) {
64
64
  content = content.substring(0, matchStart) + trustLine + content.substring(matchEnd);
65
65
  }
66
66
  else {
67
- content = content.substring(0, afterHeader) + trustLine + "\n" + content.substring(afterHeader);
67
+ content =
68
+ content.substring(0, afterHeader) + trustLine + '\n' + content.substring(afterHeader);
68
69
  }
69
70
  }
70
- fs.writeFileSync(configPath, content, "utf8");
71
+ fs.writeFileSync(configPath, content, 'utf8');
71
72
  }
72
73
  else if (projects?.[normalizedPath] !== undefined) {
73
74
  // smol-toml found the section but indexOf missed it — the header
@@ -75,7 +76,7 @@ export function ensureWorkspaceTrusted(codexHome, workspaceDir, log) {
75
76
  // duplicate table. Skip rather than corrupt the file.
76
77
  log?.warn(`Codex config.toml has non-canonical header for ${normalizedPath}; skipping trust write`);
77
78
  }
78
- else if (projects && !content.includes("[projects.")) {
79
+ else if (projects && !content.includes('[projects.')) {
79
80
  // `projects` exists in parsed output but no `[projects.` table
80
81
  // headers in the raw text — it's an inline table. Appending a
81
82
  // standard table header would produce invalid TOML.
@@ -84,7 +85,7 @@ export function ensureWorkspaceTrusted(codexHome, workspaceDir, log) {
84
85
  else {
85
86
  // Section doesn't exist — append.
86
87
  fs.mkdirSync(codexHome, { recursive: true });
87
- fs.appendFileSync(configPath, `\n${sectionHeader}\n${trustLine}\n`, "utf8");
88
+ fs.appendFileSync(configPath, `\n${sectionHeader}\n${trustLine}\n`, 'utf8');
88
89
  }
89
90
  }
90
91
  catch (err) {
@@ -97,8 +98,8 @@ export function ensureWorkspaceTrusted(codexHome, workspaceDir, log) {
97
98
  * whether OPENAI_BASE_URL points to the Parall API.
98
99
  */
99
100
  export function isParallProxyMode(env = process.env) {
100
- const baseUrl = env.OPENAI_BASE_URL?.trim()?.replace(/\/+$/, "");
101
- const apiUrl = env.PRLL_API_URL?.trim()?.replace(/\/+$/, "");
101
+ const baseUrl = env.OPENAI_BASE_URL?.trim()?.replace(/\/+$/, '');
102
+ const apiUrl = env.PRLL_API_URL?.trim()?.replace(/\/+$/, '');
102
103
  if (!baseUrl || !apiUrl)
103
104
  return false;
104
105
  return baseUrl === apiUrl || baseUrl.startsWith(`${apiUrl}/`);
@@ -118,46 +119,46 @@ export function isParallProxyMode(env = process.env) {
118
119
  * Provider-managed: overwritten on every boot (env vars are the SSOT).
119
120
  */
120
121
  export function ensureParallProvider(codexHome, apiUrl, log) {
121
- const configPath = path.join(codexHome, "config.toml");
122
- const baseUrl = apiUrl.replace(/\/$/, "") + "/api/llm/v1";
122
+ const configPath = path.join(codexHome, 'config.toml');
123
+ const baseUrl = apiUrl.replace(/\/$/, '') + '/api/llm/v1';
123
124
  try {
124
- let content = "";
125
+ let content = '';
125
126
  try {
126
- content = fs.readFileSync(configPath, "utf8");
127
+ content = fs.readFileSync(configPath, 'utf8');
127
128
  }
128
129
  catch (err) {
129
- if (err.code !== "ENOENT")
130
+ if (err.code !== 'ENOENT')
130
131
  throw err;
131
132
  }
132
- const sectionHeader = "[model_providers.parall]";
133
- const authHeader = "[model_providers.parall.auth]";
133
+ const sectionHeader = '[model_providers.parall]';
134
+ const authHeader = '[model_providers.parall.auth]';
134
135
  const providerBlock = [
135
136
  sectionHeader,
136
137
  'name = "Parall Proxy"',
137
138
  `base_url = "${baseUrl}"`,
138
139
  'wire_api = "responses"',
139
- "supports_websockets = false",
140
- "requires_openai_auth = false",
141
- "",
140
+ 'supports_websockets = false',
141
+ 'requires_openai_auth = false',
142
+ '',
142
143
  authHeader,
143
144
  'command = "printenv"',
144
145
  'args = ["OPENAI_API_KEY"]',
145
- ].join("\n");
146
+ ].join('\n');
146
147
  const headerIdx = content.indexOf(sectionHeader);
147
148
  if (headerIdx !== -1) {
148
149
  let blockEnd = findSectionEnd(content, headerIdx + sectionHeader.length + 1);
149
150
  let authIdx = content.indexOf(authHeader, blockEnd);
150
- while (authIdx !== -1 && content.substring(blockEnd, authIdx).trim() === "") {
151
+ while (authIdx !== -1 && content.substring(blockEnd, authIdx).trim() === '') {
151
152
  blockEnd = findSectionEnd(content, authIdx + authHeader.length + 1);
152
153
  authIdx = content.indexOf(authHeader, blockEnd);
153
154
  }
154
155
  content = content.substring(0, headerIdx) + providerBlock + content.substring(blockEnd);
155
156
  }
156
157
  else {
157
- content = content.trimEnd() + "\n\n" + providerBlock + "\n";
158
+ content = content.trimEnd() + '\n\n' + providerBlock + '\n';
158
159
  }
159
160
  fs.mkdirSync(codexHome, { recursive: true });
160
- fs.writeFileSync(configPath, content, "utf8");
161
+ fs.writeFileSync(configPath, content, 'utf8');
161
162
  }
162
163
  catch (err) {
163
164
  throw new Error(`failed to write Parall provider config: ${String(err)}`);
@@ -166,7 +167,7 @@ export function ensureParallProvider(codexHome, apiUrl, log) {
166
167
  function findSectionEnd(content, fromIndex) {
167
168
  // A TOML section ends at the next `[` that starts a new table header.
168
169
  // Match `[` at the beginning of a line (not inside a value).
169
- const nextHeader = content.indexOf("\n[", fromIndex);
170
+ const nextHeader = content.indexOf('\n[', fromIndex);
170
171
  return nextHeader === -1 ? content.length : nextHeader;
171
172
  }
172
173
  export function ensureCodexWorkspace(workspaceDir, log, agentIdentity) {
@@ -176,14 +177,14 @@ export function ensureCodexWorkspace(workspaceDir, log, agentIdentity) {
176
177
  PRLL_BEHAVIOR,
177
178
  PRLL_REFERENCE_GUIDE,
178
179
  buildSkillReferences(workspaceDir),
179
- ].join("\n\n");
180
+ ].join('\n\n');
180
181
  fs.mkdirSync(workspaceDir, { recursive: true });
181
- const parallDir = path.join(workspaceDir, ".parall");
182
+ const parallDir = path.join(workspaceDir, '.parall');
182
183
  fs.mkdirSync(parallDir, { recursive: true });
183
- fs.writeFileSync(path.join(parallDir, "system-prompt.md"), systemPrompt, "utf8");
184
- writeSkillFiles(path.join(parallDir, "skills"));
185
- const codexConfigDir = path.join(workspaceDir, ".codex");
184
+ fs.writeFileSync(path.join(parallDir, 'system-prompt.md'), systemPrompt, 'utf8');
185
+ writeSkillFiles(path.join(parallDir, 'skills'));
186
+ const codexConfigDir = path.join(workspaceDir, '.codex');
186
187
  fs.mkdirSync(codexConfigDir, { recursive: true });
187
- const toml = `developer_instructions = """\n${systemPrompt.replace(/\\/g, "\\\\").replace(/"""/g, '\\"""')}\n"""\n`;
188
- fs.writeFileSync(path.join(codexConfigDir, "config.toml"), toml, "utf8");
188
+ const toml = `developer_instructions = """\n${systemPrompt.replace(/\\/g, '\\\\').replace(/"""/g, '\\"""')}\n"""\n`;
189
+ fs.writeFileSync(path.join(codexConfigDir, 'config.toml'), toml, 'utf8');
189
190
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parall/codex-agent",
3
- "version": "1.31.0",
3
+ "version": "1.32.0",
4
4
  "description": "Codex CLI bridge runtime for self-hosted Parall agents",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -26,9 +26,9 @@
26
26
  ],
27
27
  "dependencies": {
28
28
  "smol-toml": "^1.6.1",
29
- "@parall/cli": "1.31.0",
30
- "@parall/agent-core": "1.31.0",
31
- "@parall/sdk": "1.31.0"
29
+ "@parall/agent-core": "1.32.0",
30
+ "@parall/cli": "1.32.0",
31
+ "@parall/sdk": "1.32.0"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/node": "^22.0.0",
package/src/config.ts CHANGED
@@ -1,5 +1,5 @@
1
- import * as os from "node:os";
2
- import * as path from "node:path";
1
+ import * as os from 'node:os';
2
+ import * as path from 'node:path';
3
3
 
4
4
  export type CodexAgentConfig = {
5
5
  apiUrl: string;
@@ -45,9 +45,9 @@ function resolvePath(value: string): string {
45
45
  }
46
46
 
47
47
  export function resolveCodexAgentConfig(env: NodeJS.ProcessEnv = process.env): CodexAgentConfig {
48
- const apiUrl = requireEnv(env, "PRLL_API_URL");
49
- const apiKey = requireEnv(env, "PRLL_API_KEY");
50
- const orgId = requireEnv(env, "PRLL_ORG_ID");
48
+ const apiUrl = requireEnv(env, 'PRLL_API_URL');
49
+ const apiKey = requireEnv(env, 'PRLL_API_KEY');
50
+ const orgId = requireEnv(env, 'PRLL_ORG_ID');
51
51
  // CODEX_HOME is where codex looks for `auth.json` / `config.toml`. Its
52
52
  // own default is `$HOME/.codex`; falling back to `$HOME` here was wrong
53
53
  // — it made the spawned app-server subprocess look for
@@ -56,17 +56,18 @@ export function resolveCodexAgentConfig(env: NodeJS.ProcessEnv = process.env): C
56
56
  // WebSocket endpoint. Default to `$HOME/.codex` so `codex login`'s
57
57
  // credentials are picked up transparently.
58
58
  const codexHome = resolvePath(
59
- env.PRLL_CODEX_HOME?.trim()
60
- || env.CODEX_HOME?.trim()
61
- || path.join(env.HOME || os.homedir(), ".codex"),
59
+ env.PRLL_CODEX_HOME?.trim() ||
60
+ env.CODEX_HOME?.trim() ||
61
+ path.join(env.HOME || os.homedir(), '.codex'),
62
62
  );
63
63
  // Bridge state lives outside CODEX_HOME to avoid polluting codex's own
64
64
  // directory with non-codex files.
65
65
  const stateDir = resolvePath(
66
- env.PRLL_STATE_DIR?.trim()
67
- || path.join(env.HOME || os.homedir(), ".parall-agent"),
66
+ env.PRLL_STATE_DIR?.trim() || path.join(env.HOME || os.homedir(), '.parall-agent'),
67
+ );
68
+ const workspaceDir = resolvePath(
69
+ env.PRLL_WORKSPACE_DIR?.trim() || path.join(stateDir, 'workspace'),
68
70
  );
69
- const workspaceDir = resolvePath(env.PRLL_WORKSPACE_DIR?.trim() || path.join(stateDir, "workspace"));
70
71
 
71
72
  return {
72
73
  apiUrl,
@@ -74,14 +75,14 @@ export function resolveCodexAgentConfig(env: NodeJS.ProcessEnv = process.env): C
74
75
  orgId,
75
76
  wsUrl: env.PRLL_WS_URL?.trim() || undefined,
76
77
  swimlaneName: env.PRLL_SWIMLANE_NAME?.trim() || undefined,
77
- codexBin: env.PRLL_CODEX_BIN?.trim() || "codex",
78
+ codexBin: env.PRLL_CODEX_BIN?.trim() || 'codex',
78
79
  codexHome,
79
80
  stateDir,
80
81
  workspaceDir,
81
82
  model: env.PRLL_CODEX_MODEL?.trim() || undefined,
82
83
  reasoningEffort: env.PRLL_CODEX_REASONING_EFFORT?.trim() || undefined,
83
- sandbox: env.PRLL_CODEX_SANDBOX?.trim() || "danger-full-access",
84
- approvalPolicy: env.PRLL_CODEX_APPROVAL?.trim() || "never",
84
+ sandbox: env.PRLL_CODEX_SANDBOX?.trim() || 'danger-full-access',
85
+ approvalPolicy: env.PRLL_CODEX_APPROVAL?.trim() || 'never',
85
86
  runtimeKey: env.PRLL_CODEX_RUNTIME_KEY?.trim() || undefined,
86
87
  };
87
88
  }
@@ -99,12 +100,12 @@ export function resolveCodexAgentConfig(env: NodeJS.ProcessEnv = process.env): C
99
100
  */
100
101
  export function normalizeSandbox(value: string): string {
101
102
  const map: Record<string, string> = {
102
- "workspace-write": "workspace-write",
103
- "workspacewrite": "workspace-write",
104
- "danger-full-access": "danger-full-access",
105
- "dangerfullaccess": "danger-full-access",
106
- "read-only": "read-only",
107
- "readonly": "read-only",
103
+ 'workspace-write': 'workspace-write',
104
+ workspacewrite: 'workspace-write',
105
+ 'danger-full-access': 'danger-full-access',
106
+ dangerfullaccess: 'danger-full-access',
107
+ 'read-only': 'read-only',
108
+ readonly: 'read-only',
108
109
  };
109
110
  return map[value.toLowerCase()] ?? value;
110
111
  }
@@ -117,22 +118,26 @@ export function normalizeSandbox(value: string): string {
117
118
  */
118
119
  export function normalizeApprovalPolicy(value: string): string {
119
120
  const map: Record<string, string> = {
120
- "never": "never",
121
- "on-request": "on-request",
122
- "onrequest": "on-request",
123
- "unless-trusted": "unless-trusted",
124
- "unlesstrusted": "unless-trusted",
125
- "on-failure": "on-failure",
126
- "onfailure": "on-failure",
121
+ never: 'never',
122
+ 'on-request': 'on-request',
123
+ onrequest: 'on-request',
124
+ 'unless-trusted': 'unless-trusted',
125
+ unlesstrusted: 'unless-trusted',
126
+ 'on-failure': 'on-failure',
127
+ onfailure: 'on-failure',
127
128
  };
128
129
  return map[value.toLowerCase()] ?? value;
129
130
  }
130
131
 
131
- export function resolveWsUrl(apiUrl: string, explicitWsUrl?: string, swimlaneName?: string): string {
132
- const base = explicitWsUrl || `${apiUrl.replace(/\/$/, "").replace(/^http/, "ws")}/ws`;
132
+ export function resolveWsUrl(
133
+ apiUrl: string,
134
+ explicitWsUrl?: string,
135
+ swimlaneName?: string,
136
+ ): string {
137
+ const base = explicitWsUrl || `${apiUrl.replace(/\/$/, '').replace(/^http/, 'ws')}/ws`;
133
138
  if (!swimlaneName) return base;
134
139
  const url = new URL(base);
135
- url.searchParams.set("swimlane", swimlaneName);
140
+ url.searchParams.set('swimlane', swimlaneName);
136
141
  return url.toString();
137
142
  }
138
143
 
@@ -141,16 +146,16 @@ export function buildCodexRuntimeKey(agentUserId: string): string {
141
146
  }
142
147
 
143
148
  export function sessionStateFilePathForRuntime(stateDir: string, runtimeKey: string): string {
144
- const fileName = Buffer.from(runtimeKey).toString("base64url");
145
- return path.join(stateDir, "threads", `${fileName}.json`);
149
+ const fileName = Buffer.from(runtimeKey).toString('base64url');
150
+ return path.join(stateDir, 'threads', `${fileName}.json`);
146
151
  }
147
152
 
148
153
  export function contextFilePathForSession(stateDir: string, sessionKey: string): string {
149
- const fileName = Buffer.from(sessionKey).toString("base64url");
150
- return path.join(stateDir, "dispatch-context", `${fileName}.json`);
154
+ const fileName = Buffer.from(sessionKey).toString('base64url');
155
+ return path.join(stateDir, 'dispatch-context', `${fileName}.json`);
151
156
  }
152
157
 
153
158
  export function stepIdFilePathForSession(stateDir: string, sessionKey: string): string {
154
- const fileName = Buffer.from(sessionKey).toString("base64url");
155
- return path.join(stateDir, "step-ids", `${fileName}.txt`);
159
+ const fileName = Buffer.from(sessionKey).toString('base64url');
160
+ return path.join(stateDir, 'step-ids', `${fileName}.txt`);
156
161
  }