ai-sdk-provider-codex-cli 2.1.0 → 2.1.1

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.
Files changed (2) hide show
  1. package/dist/index.js +89 -21
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4827,6 +4827,7 @@ var AppServerRpcClient = class extends EventEmitter {
4827
4827
  activeRequestContextsByTurn = /* @__PURE__ */ new Map();
4828
4828
  completedTurnIds = /* @__PURE__ */ new Set();
4829
4829
  lastStderr = "";
4830
+ lastCrashHadStderr = false;
4830
4831
  idleTimer;
4831
4832
  serverCapabilities;
4832
4833
  expectedExitSignal;
@@ -5033,6 +5034,7 @@ var AppServerRpcClient = class extends EventEmitter {
5033
5034
  const base = resolveCodexPath2(this.settings.codexPath);
5034
5035
  const args = [...base.args, "app-server", "--listen", "stdio://"];
5035
5036
  this.lastStderr = "";
5037
+ this.lastCrashHadStderr = false;
5036
5038
  this.expectedExitSignal = void 0;
5037
5039
  this.child = spawn(base.cmd, args, {
5038
5040
  stdio: ["pipe", "pipe", "pipe"],
@@ -5043,18 +5045,23 @@ var AppServerRpcClient = class extends EventEmitter {
5043
5045
  },
5044
5046
  cwd: this.settings.cwd
5045
5047
  });
5046
- this.child.stderr.setEncoding("utf8");
5047
- this.child.stderr.on("data", (chunk) => {
5048
- this.lastStderr += String(chunk);
5049
- if (this.lastStderr.length > 4e3) {
5050
- this.lastStderr = this.lastStderr.slice(-4e3);
5048
+ const child = this.child;
5049
+ let stderrBuf = "";
5050
+ child.stderr.setEncoding("utf8");
5051
+ child.stderr.on("data", (chunk) => {
5052
+ stderrBuf = (stderrBuf + String(chunk)).slice(-4e3);
5053
+ if (this.child === child) {
5054
+ this.lastStderr = stderrBuf;
5051
5055
  }
5052
5056
  });
5053
- this.child.on("error", (error) => {
5057
+ child.on("error", (error) => {
5054
5058
  this.logger.error(`[codex-app-server] process error: ${String(error)}`);
5055
- this.handleCrash(error);
5059
+ const base2 = String(error);
5060
+ const message = this.withStderrTail(base2, stderrBuf);
5061
+ this.lastCrashHadStderr = message !== base2;
5062
+ this.handleCrash(new Error(message));
5056
5063
  });
5057
- this.child.on("exit", (code, signal) => {
5064
+ child.on("exit", (code, signal) => {
5058
5065
  const message = `codex app-server exited (code=${String(code)}, signal=${String(signal)})`;
5059
5066
  const expected = this.state === "closed" || signal !== null && signal === this.expectedExitSignal;
5060
5067
  this.expectedExitSignal = void 0;
@@ -5062,11 +5069,29 @@ var AppServerRpcClient = class extends EventEmitter {
5062
5069
  this.logger.info(`[codex-app-server] ${message}`);
5063
5070
  return;
5064
5071
  }
5065
- this.logger.warn(`[codex-app-server] ${message}`);
5066
- this.handleCrash(new Error(message));
5072
+ const crashedPending = this.markCrashed();
5073
+ if (!crashedPending) return;
5074
+ let settled = false;
5075
+ const finish = () => {
5076
+ if (settled) return;
5077
+ settled = true;
5078
+ child.off("close", finish);
5079
+ clearTimeout(timer);
5080
+ const base2 = `codex app-server exited (code=${String(code)}, signal=${String(signal)})`;
5081
+ const crashMessage = this.withStderrTail(base2, stderrBuf);
5082
+ if (this.child === void 0) {
5083
+ this.lastStderr = stderrBuf;
5084
+ this.lastCrashHadStderr = crashMessage !== base2;
5085
+ }
5086
+ this.logger.warn(`[codex-app-server] ${crashMessage}`);
5087
+ this.rejectCrashedPending(crashedPending, new Error(crashMessage));
5088
+ };
5089
+ child.once("close", finish);
5090
+ const timer = setTimeout(finish, 120);
5091
+ timer.unref?.();
5067
5092
  });
5068
5093
  this.stdoutReader = readline.createInterface({
5069
- input: this.child.stdout,
5094
+ input: child.stdout,
5070
5095
  crlfDelay: Infinity
5071
5096
  });
5072
5097
  this.stdoutReader.on("line", (line) => this.handleLine(line));
@@ -5088,12 +5113,22 @@ var AppServerRpcClient = class extends EventEmitter {
5088
5113
  this.settings.connectionTimeoutMs ?? this.requestTimeoutMs
5089
5114
  );
5090
5115
  } catch (error) {
5091
- const message = String(error?.message ?? error);
5092
- if (message.includes("ENOENT") || message.includes("unknown subcommand")) {
5116
+ const raw = String(error?.message ?? error);
5117
+ if (raw.includes("unknown subcommand") || this.lastStderr.includes("unknown subcommand")) {
5118
+ throw new Error(
5119
+ this.withStderrTail(
5120
+ "codex app-server requires codex CLI >= 0.144.0. Run 'codex --version' to check."
5121
+ )
5122
+ );
5123
+ }
5124
+ if (raw.includes("ENOENT") || this.lastStderr.includes("ENOENT")) {
5093
5125
  throw new Error(
5094
- "codex app-server requires codex CLI >= 0.144.0. Run 'codex --version' to check."
5126
+ this.withStderrTail(
5127
+ "codex app-server failed to start: codex executable not found (ENOENT). Check that the codex CLI is installed and its native binary is intact \u2014 a corrupted @openai/codex npm install can cause this. Run 'codex --version' to verify."
5128
+ )
5095
5129
  );
5096
5130
  }
5131
+ const message = this.lastCrashHadStderr ? raw : this.withStderrTail(raw);
5097
5132
  throw createAPICallError({
5098
5133
  message: `Failed to initialize codex app-server: ${message}`,
5099
5134
  stderr: this.lastStderr,
@@ -5155,8 +5190,8 @@ var AppServerRpcClient = class extends EventEmitter {
5155
5190
  }
5156
5191
  this.writeQueue = Promise.resolve();
5157
5192
  }
5158
- handleCrash(error) {
5159
- if (this.state === "closed") return;
5193
+ markCrashed() {
5194
+ if (this.state === "closed" || this.state === "error") return void 0;
5160
5195
  this.state = "error";
5161
5196
  this.clearIdleTimer();
5162
5197
  this.stdoutReader?.close();
@@ -5166,11 +5201,9 @@ var AppServerRpcClient = class extends EventEmitter {
5166
5201
  this.child.kill("SIGTERM");
5167
5202
  this.child = void 0;
5168
5203
  }
5169
- for (const [id, pending] of this.pending.entries()) {
5170
- clearTimeout(pending.timer);
5171
- pending.reject(
5172
- new Error(`Request ${String(id)} failed after app-server crash: ${String(error)}`)
5173
- );
5204
+ const pending = new Map(this.pending);
5205
+ for (const [, entry] of pending) {
5206
+ clearTimeout(entry.timer);
5174
5207
  }
5175
5208
  this.pending.clear();
5176
5209
  this.threadLocks.clear();
@@ -5180,6 +5213,41 @@ var AppServerRpcClient = class extends EventEmitter {
5180
5213
  this.completedTurnIds.clear();
5181
5214
  this.serverCapabilities = void 0;
5182
5215
  this.writeQueue = Promise.resolve();
5216
+ return pending;
5217
+ }
5218
+ rejectCrashedPending(pending, error) {
5219
+ for (const [id, entry] of pending) {
5220
+ entry.reject(
5221
+ new Error(`Request ${String(id)} failed after app-server crash: ${String(error)}`)
5222
+ );
5223
+ }
5224
+ }
5225
+ handleCrash(error) {
5226
+ const pending = this.markCrashed();
5227
+ if (!pending) return;
5228
+ this.rejectCrashedPending(pending, error);
5229
+ }
5230
+ stderrExcerpt(raw) {
5231
+ if (!raw) return "";
5232
+ const escape = String.fromCharCode(27);
5233
+ const ansiEscapeSequence = new RegExp(
5234
+ `${escape}(?:\\[[0-?]*[ -/]*[@-~]|\\][^\\u0007]*(?:\\u0007|${escape}\\\\))`,
5235
+ "g"
5236
+ );
5237
+ const withoutAnsi = raw.replace(ansiEscapeSequence, "");
5238
+ const withoutControls = Array.from(withoutAnsi).filter((character) => {
5239
+ const code = character.charCodeAt(0);
5240
+ return character === "\n" || code >= 32 && (code < 127 || code > 159);
5241
+ }).join("");
5242
+ const excerpt = withoutControls.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).slice(-5).join("; ");
5243
+ if (excerpt.length > 600) {
5244
+ return `\u2026${excerpt.slice(-600)}`;
5245
+ }
5246
+ return excerpt;
5247
+ }
5248
+ withStderrTail(message, raw = this.lastStderr) {
5249
+ const excerpt = this.stderrExcerpt(raw);
5250
+ return excerpt ? `${message} | stderr (tail): ${excerpt}` : message;
5183
5251
  }
5184
5252
  handleLine(line) {
5185
5253
  const trimmed = line.trim();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-sdk-provider-codex-cli",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "description": "AI SDK v7 provider for OpenAI Codex CLI (use ChatGPT Plus/Pro subscription)",
5
5
  "keywords": [
6
6
  "ai-sdk",