@ycodium-ai/agent-codex 0.2.3488 → 0.2.3502

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 +81 -116
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -2455,49 +2455,30 @@ async function spawnCodexAppServer(input) {
2455
2455
  }
2456
2456
 
2457
2457
  // src/cliVersion.ts
2458
+ import {
2459
+ runProcessOperation,
2460
+ isOperationCleanupError
2461
+ } from "@ycodium-ai/plugin-api/process-operation";
2458
2462
  var CODEX_VERSION_TIMEOUT_MS = 15e3;
2459
2463
  var VERSION_PATTERN = /(?<![\d.])(\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?)/;
2460
- async function collect(stream) {
2461
- const chunks = [];
2462
- for await (const chunk of stream) {
2463
- chunks.push(Buffer.from(chunk));
2464
- if (Buffer.concat(chunks).length > 64 * 1024) break;
2465
- }
2466
- return Buffer.concat(chunks).toString("utf8");
2467
- }
2468
2464
  async function readCodexCliVersion(input) {
2465
+ input.signal?.throwIfAborted();
2469
2466
  if (input.recipe.binaryPath.length === 0) return null;
2470
- let handle;
2471
2467
  try {
2472
- handle = await input.host.process.spawn({
2468
+ const { stdout, stderr, exitCode } = await runProcessOperation(input.host, {
2473
2469
  program: input.recipe.binaryPath,
2474
2470
  args: ["--version"],
2475
- owner: { bindingId: input.host.bindingId }
2471
+ owner: { bindingId: input.host.bindingId },
2472
+ signal: input.signal,
2473
+ timeoutMs: CODEX_VERSION_TIMEOUT_MS,
2474
+ maxOutputBytes: 64 * 1024
2476
2475
  });
2477
- } catch {
2478
- return null;
2479
- }
2480
- const collected = Promise.all([collect(handle.stdout), collect(handle.stderr), handle.exited]);
2481
- let timer;
2482
- const timeout = new Promise((resolve4) => {
2483
- timer = setTimeout(() => resolve4("timeout"), CODEX_VERSION_TIMEOUT_MS);
2484
- timer.unref?.();
2485
- });
2486
- try {
2487
- const settled = await Promise.race([collected, timeout]);
2488
- if (settled === "timeout") {
2489
- collected.catch(() => void 0);
2490
- return null;
2491
- }
2492
- const [stdout, stderr, exitCode] = settled;
2493
2476
  if (exitCode !== 0) return null;
2494
- return VERSION_PATTERN.exec(`${stdout}
2495
- ${stderr}`)?.[1] ?? null;
2496
- } catch {
2477
+ return VERSION_PATTERN.exec(stdout + "\n" + stderr)?.[1] ?? null;
2478
+ } catch (error) {
2479
+ if (isOperationCleanupError(error)) throw error;
2480
+ input.signal?.throwIfAborted();
2497
2481
  return null;
2498
- } finally {
2499
- if (timer !== void 0) clearTimeout(timer);
2500
- await handle.kill("SIGTERM").catch(() => void 0);
2501
2482
  }
2502
2483
  }
2503
2484
 
@@ -6392,6 +6373,10 @@ import * as NodePath9 from "node:path";
6392
6373
  import {
6393
6374
  mergeLaunchEnv as mergeLaunchEnv2
6394
6375
  } from "@ycodium-ai/plugin-api/executor";
6376
+ import {
6377
+ OperationCleanupError,
6378
+ runProcessOperation as runProcessOperation2
6379
+ } from "@ycodium-ai/plugin-api/process-operation";
6395
6380
  var CODEX_TIMEOUT_MS = 18e4;
6396
6381
  var EARLIER_CONTENT_TRUNCATION_MARKER = "[Earlier content truncated]\n\n";
6397
6382
  function limitSection(value, maxChars) {
@@ -6544,98 +6529,78 @@ function absoluteImagePaths(attachments) {
6544
6529
  }
6545
6530
  return paths;
6546
6531
  }
6547
- async function collectStream(stream) {
6548
- const decoder = new TextDecoder();
6549
- let out = "";
6550
- for await (const chunk of stream) out += decoder.decode(chunk, { stream: true });
6551
- return out;
6552
- }
6553
6532
  function createCodexTextGeneration(input) {
6554
6533
  const run = async (operation, cwd, prompt, schema, modelSelection, imagePaths, signal) => {
6555
6534
  if (input.recipe.binaryPath.length === 0) {
6556
6535
  throw new Error("Codex CLI is required but not available on PATH.");
6557
6536
  }
6537
+ signal?.throwIfAborted();
6558
6538
  const tmp = await NodeFSP5.mkdtemp(NodePath9.join(NodeOS3.tmpdir(), "ycodium-codex-tg-"));
6559
- const schemaPath = NodePath9.join(tmp, "schema.json");
6560
- const outputPath = NodePath9.join(tmp, "output.json");
6561
- await NodeFSP5.writeFile(schemaPath, JSON.stringify(schema));
6562
- await NodeFSP5.writeFile(outputPath, "");
6563
- const reasoningEffort = modelSelectionStringOption(modelSelection, "reasoningEffort") ?? DEFAULT_TEXT_GENERATION_REASONING_EFFORT;
6564
- const serviceTier = modelSelectionStringOption(modelSelection, "serviceTier");
6565
- const model = modelIdFromSelection(modelSelection) ?? "gpt-5.6-luna";
6566
- const env = mergeLaunchEnv2({
6567
- accountHome: input.layout.effectiveHomePath ? { CODEX_HOME: input.layout.effectiveHomePath } : input.recipe.homePath.trim() ? { CODEX_HOME: expandHomePath(input.recipe.homePath) } : {},
6568
- instanceTable: input.recipe.environment
6569
- });
6570
- const args = [
6571
- "exec",
6572
- ...codexExecLaunchArgs(input.recipe.launchArgs),
6573
- "--ephemeral",
6574
- "--skip-git-repo-check",
6575
- "-s",
6576
- "read-only",
6577
- "--model",
6578
- model,
6579
- "--config",
6580
- `model_reasoning_effort="${reasoningEffort}"`,
6581
- ...serviceTier ? ["--config", `service_tier="${serviceTier}"`] : [],
6582
- "--output-schema",
6583
- schemaPath,
6584
- "--output-last-message",
6585
- outputPath,
6586
- ...imagePaths.flatMap((imagePath) => ["--image", imagePath]),
6587
- "-"
6588
- ];
6589
- const handle = await input.host.process.spawn({
6590
- program: input.recipe.binaryPath,
6591
- args,
6592
- cwd: operation === "summarizeTurn" ? tmp : cwd,
6593
- env,
6594
- owner: { bindingId: input.host.bindingId }
6595
- });
6596
- const onAbort = () => {
6597
- void handle.kill("SIGTERM").catch(() => void 0);
6598
- };
6599
- signal?.addEventListener("abort", onAbort);
6600
- let timer;
6539
+ let safeToRemove = true;
6601
6540
  try {
6602
- await handle.writeStdin(prompt);
6603
- await handle.closeStdin();
6604
- const timedOut = await Promise.race([
6605
- handle.exited.then(() => false),
6606
- new Promise((resolve4) => {
6607
- timer = setTimeout(() => resolve4(true), CODEX_TIMEOUT_MS);
6608
- })
6609
- ]);
6610
- if (timedOut) {
6611
- await handle.kill("SIGTERM").catch(() => void 0);
6612
- throw new Error("Codex CLI request timed out.");
6613
- }
6614
- const [stdout, stderr, exitCode] = await Promise.all([
6615
- collectStream(handle.stdout),
6616
- collectStream(handle.stderr),
6617
- handle.exited
6618
- ]);
6619
- if (exitCode !== 0) {
6620
- const detail = stderr.trim() || stdout.trim();
6621
- throw new Error(
6622
- detail.length > 0 ? `Codex CLI command failed: ${detail}` : `Codex CLI command failed with code ${String(exitCode)}.`
6623
- );
6624
- }
6625
- const raw = await NodeFSP5.readFile(outputPath, "utf8");
6626
- let parsed;
6541
+ const schemaPath = NodePath9.join(tmp, "schema.json");
6542
+ const outputPath = NodePath9.join(tmp, "output.json");
6543
+ await NodeFSP5.writeFile(schemaPath, JSON.stringify(schema));
6544
+ await NodeFSP5.writeFile(outputPath, "");
6545
+ const reasoningEffort = modelSelectionStringOption(modelSelection, "reasoningEffort") ?? DEFAULT_TEXT_GENERATION_REASONING_EFFORT;
6546
+ const serviceTier = modelSelectionStringOption(modelSelection, "serviceTier");
6547
+ const model = modelIdFromSelection(modelSelection) ?? "gpt-5.6-luna";
6548
+ const env = mergeLaunchEnv2({
6549
+ accountHome: input.layout.effectiveHomePath ? { CODEX_HOME: input.layout.effectiveHomePath } : input.recipe.homePath.trim() ? { CODEX_HOME: expandHomePath(input.recipe.homePath) } : {},
6550
+ instanceTable: input.recipe.environment
6551
+ });
6552
+ const args = [
6553
+ "exec",
6554
+ ...codexExecLaunchArgs(input.recipe.launchArgs),
6555
+ "--ephemeral",
6556
+ "--skip-git-repo-check",
6557
+ "-s",
6558
+ "read-only",
6559
+ "--model",
6560
+ model,
6561
+ "--config",
6562
+ `model_reasoning_effort="${reasoningEffort}"`,
6563
+ ...serviceTier ? ["--config", `service_tier="${serviceTier}"`] : [],
6564
+ "--output-schema",
6565
+ schemaPath,
6566
+ "--output-last-message",
6567
+ outputPath,
6568
+ ...imagePaths.flatMap((imagePath) => ["--image", imagePath]),
6569
+ "-"
6570
+ ];
6627
6571
  try {
6628
- parsed = JSON.parse(raw);
6572
+ const { stdout, stderr, exitCode } = await runProcessOperation2(input.host, {
6573
+ program: input.recipe.binaryPath,
6574
+ args,
6575
+ cwd: operation === "summarizeTurn" ? tmp : cwd,
6576
+ env,
6577
+ owner: { bindingId: input.host.bindingId },
6578
+ signal,
6579
+ timeoutMs: CODEX_TIMEOUT_MS,
6580
+ input: prompt
6581
+ });
6582
+ if (exitCode !== 0) {
6583
+ const detail = stderr.trim() || stdout.trim();
6584
+ throw new Error(
6585
+ detail.length > 0 ? `Codex CLI command failed: ${detail}` : `Codex CLI command failed with code ${String(exitCode)}.`
6586
+ );
6587
+ }
6588
+ const raw = await NodeFSP5.readFile(outputPath, "utf8");
6589
+ let parsed;
6590
+ try {
6591
+ parsed = JSON.parse(raw);
6592
+ } catch (cause) {
6593
+ throw new Error("Codex returned invalid structured output.", { cause });
6594
+ }
6595
+ if (!isRecord2(parsed)) throw new Error("Codex returned invalid structured output.");
6596
+ return parsed;
6629
6597
  } catch (cause) {
6630
- throw new Error("Codex returned invalid structured output.", { cause });
6598
+ if (cause instanceof OperationCleanupError) safeToRemove = false;
6599
+ throw cause;
6631
6600
  }
6632
- if (!isRecord2(parsed)) throw new Error("Codex returned invalid structured output.");
6633
- return parsed;
6634
6601
  } finally {
6635
- if (timer !== void 0) clearTimeout(timer);
6636
- signal?.removeEventListener("abort", onAbort);
6637
- await NodeFSP5.rm(tmp, { recursive: true, force: true }).catch(() => void 0);
6638
- void operation;
6602
+ if (safeToRemove)
6603
+ await NodeFSP5.rm(tmp, { recursive: true, force: true }).catch(() => void 0);
6639
6604
  }
6640
6605
  };
6641
6606
  return {
@@ -7637,7 +7602,7 @@ var createCodexInstance = (config, host, attachments, cache) => {
7637
7602
  ...CODEX_NATIVE_MODE_REPORT
7638
7603
  };
7639
7604
  },
7640
- readCliVersion: () => readCodexCliVersion({ recipe, host }),
7605
+ readCliVersion: (signal) => readCodexCliVersion({ recipe, host, ...signal ? { signal } : {} }),
7641
7606
  // 有意不处理 input.readOnlyDirectories:codex 的沙箱只限制写入,读不受限,
7642
7607
  // 附件目录本来就能读,无需放行。
7643
7608
  startSession: async (input, signal) => {
@@ -7955,7 +7920,7 @@ var executors = [
7955
7920
  ];
7956
7921
  var index_default = definePlugin({
7957
7922
  id: "agent-codex",
7958
- apiVersion: 39,
7923
+ apiVersion: 41,
7959
7924
  executors,
7960
7925
  activate(ctx) {
7961
7926
  capturedAttachments = ctx.attachments;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ycodium-ai/agent-codex",
3
- "version": "0.2.3488",
3
+ "version": "0.2.3502",
4
4
  "description": "Codex executor: Codex CLI over the app-server JSON-RPC protocol.",
5
5
  "keywords": [
6
6
  "ycodium",
@@ -29,9 +29,9 @@
29
29
  "tailwindcss": "^4.0.0",
30
30
  "typescript": "~6.0.3",
31
31
  "vite-plus": "0.2.2",
32
- "@ycodium-ai/plugin-api": "0.2.3488",
33
32
  "ycodium-jsonl-stream": "0.0.0",
34
- "ycodium-executor-testing": "0.0.0"
33
+ "ycodium-executor-testing": "0.0.0",
34
+ "@ycodium-ai/plugin-api": "0.2.3502"
35
35
  },
36
36
  "ycodium": {
37
37
  "plugin": "./dist/index.js",