@ag-eco/agentplate-cli 0.15.1 → 0.15.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ag-eco/agentplate-cli",
3
- "version": "0.15.1",
3
+ "version": "0.15.2",
4
4
  "description": "Multi-agent orchestration for AI coding agents — spawn workers in git worktrees via tmux, coordinate through SQLite mail, merge with tiered conflict resolution. Pluggable runtime adapters for Claude Code, Pi, and more.",
5
5
  "author": "Jaymin West",
6
6
  "license": "MIT",
@@ -20,7 +20,7 @@ describe("CodexRuntime", () => {
20
20
  });
21
21
 
22
22
  describe("buildSpawnCommand", () => {
23
- test("basic command uses interactive codex with --full-auto", () => {
23
+ test("basic command uses interactive codex with workspace-write sandbox + no approvals", () => {
24
24
  const opts: SpawnOpts = {
25
25
  model: "gpt-5-codex",
26
26
  permissionMode: "bypass",
@@ -28,7 +28,7 @@ describe("CodexRuntime", () => {
28
28
  env: {},
29
29
  };
30
30
  const cmd = runtime.buildSpawnCommand(opts);
31
- expect(cmd).toContain("codex --full-auto");
31
+ expect(cmd).toContain("codex --sandbox workspace-write --ask-for-approval never");
32
32
  expect(cmd).toContain("--model gpt-5-codex");
33
33
  expect(cmd).toContain("Read AGENTS.md");
34
34
  });
@@ -42,7 +42,7 @@ describe("CodexRuntime", () => {
42
42
  env: {},
43
43
  };
44
44
  const cmd = runtime.buildSpawnCommand(opts);
45
- expect(cmd).toContain("codex --full-auto");
45
+ expect(cmd).toContain("codex --sandbox workspace-write --ask-for-approval never");
46
46
  expect(cmd).not.toContain(" --model ");
47
47
  }
48
48
  });
@@ -173,7 +173,7 @@ describe("CodexRuntime", () => {
173
173
  };
174
174
  const cmd = runtime.buildSpawnCommand(opts);
175
175
  expect(cmd).toBe(
176
- "codex --full-auto --model gpt-5-codex 'Read AGENTS.md for your task assignment and begin immediately.'",
176
+ "codex --sandbox workspace-write --ask-for-approval never --model gpt-5-codex 'Read AGENTS.md for your task assignment and begin immediately.'",
177
177
  );
178
178
  });
179
179
 
@@ -256,7 +256,14 @@ describe("CodexRuntime", () => {
256
256
  describe("buildPrintCommand", () => {
257
257
  test("basic command without model", () => {
258
258
  const argv = runtime.buildPrintCommand("Summarize this diff");
259
- expect(argv).toEqual(["codex", "exec", "--full-auto", "--ephemeral", "Summarize this diff"]);
259
+ expect(argv).toEqual([
260
+ "codex",
261
+ "exec",
262
+ "--sandbox",
263
+ "workspace-write",
264
+ "--ephemeral",
265
+ "Summarize this diff",
266
+ ]);
260
267
  });
261
268
 
262
269
  test("command with model override", () => {
@@ -264,7 +271,8 @@ describe("CodexRuntime", () => {
264
271
  expect(argv).toEqual([
265
272
  "codex",
266
273
  "exec",
267
- "--full-auto",
274
+ "--sandbox",
275
+ "workspace-write",
268
276
  "--ephemeral",
269
277
  "--model",
270
278
  "gpt-5-codex",
@@ -277,7 +285,8 @@ describe("CodexRuntime", () => {
277
285
  expect(argv).toEqual([
278
286
  "codex",
279
287
  "exec",
280
- "--full-auto",
288
+ "--sandbox",
289
+ "workspace-write",
281
290
  "--ephemeral",
282
291
  "--model",
283
292
  "gpt-5.4",
@@ -296,14 +305,14 @@ describe("CodexRuntime", () => {
296
305
  expect(argv[argv.length - 1]).toBe(prompt);
297
306
  });
298
307
 
299
- test("without model, argv has exactly 5 elements", () => {
308
+ test("without model, argv has exactly 6 elements", () => {
300
309
  const argv = runtime.buildPrintCommand("prompt text");
301
- expect(argv.length).toBe(5);
310
+ expect(argv.length).toBe(6);
302
311
  });
303
312
 
304
- test("with model, argv has exactly 7 elements", () => {
313
+ test("with model, argv has exactly 8 elements", () => {
305
314
  const argv = runtime.buildPrintCommand("prompt text", "gpt-5-codex");
306
- expect(argv.length).toBe(7);
315
+ expect(argv.length).toBe(8);
307
316
  });
308
317
 
309
318
  test("does not include --json (print expects plain text stdout)", () => {
@@ -318,27 +327,53 @@ describe("CodexRuntime", () => {
318
327
  });
319
328
 
320
329
  describe("detectReady", () => {
321
- test("returns ready for empty pane", () => {
322
- const state = runtime.detectReady("");
323
- expect(state).toEqual({ phase: "ready" });
324
- });
325
-
326
- test("returns ready for any pane content", () => {
327
- const state = runtime.detectReady("Loading Codex...\nPlease wait");
328
- expect(state).toEqual({ phase: "ready" });
329
- });
330
-
331
- test("returns ready for NDJSON output", () => {
332
- const state = runtime.detectReady(
333
- '{"type":"thread.started","thread_id":"abc"}\n{"type":"turn.started"}',
334
- );
335
- expect(state).toEqual({ phase: "ready" });
336
- });
337
-
338
- test("no dialog phase — Codex has no trust dialog", () => {
339
- const state = runtime.detectReady("trust this folder");
340
- expect(state.phase).not.toBe("dialog");
341
- expect(state.phase).toBe("ready");
330
+ test("returns loading for empty / pre-header pane", () => {
331
+ expect(runtime.detectReady("")).toEqual({ phase: "loading" });
332
+ expect(runtime.detectReady("Loading Codex...\nPlease wait")).toEqual({ phase: "loading" });
333
+ });
334
+
335
+ test("returns ready once the Codex header box renders", () => {
336
+ const pane = [
337
+ "╭──────────────────────────────────────╮",
338
+ "│ >_ OpenAI Codex (v0.128.0) │",
339
+ "│ model: gpt-5.5 high /model to change│",
340
+ "╰──────────────────────────────────────╯",
341
+ "› Explain this codebase",
342
+ ].join("\n");
343
+ expect(runtime.detectReady(pane)).toEqual({ phase: "ready" });
344
+ });
345
+
346
+ test("skips the blocking 'Update available' modal via type:2", () => {
347
+ const pane = [
348
+ "✨ Update available! 0.128.0 -> 0.131.0",
349
+ "› 1. Update now (runs `npm install -g @openai/codex`)",
350
+ " 2. Skip",
351
+ " 3. Skip until next version",
352
+ " Press enter to continue",
353
+ ].join("\n");
354
+ expect(runtime.detectReady(pane)).toEqual({ phase: "dialog", action: "type:2" });
355
+ });
356
+
357
+ test("passive post-skip update banner is not treated as a modal", () => {
358
+ // The non-blocking banner says "Run npm install" and has no numbered options.
359
+ const pane = [
360
+ "╭───────────────────────────────────────────╮",
361
+ "│ ✨ Update available! 0.128.0 -> 0.135.0 │",
362
+ "│ Run npm install -g @openai/codex to update. │",
363
+ "╰───────────────────────────────────────────╯",
364
+ "│ >_ OpenAI Codex (v0.128.0) │",
365
+ ].join("\n");
366
+ expect(runtime.detectReady(pane)).toEqual({ phase: "ready" });
367
+ });
368
+
369
+ test("confirms the trust-directory prompt via retryable type:1", () => {
370
+ const pane = [
371
+ "Do you trust the contents of this directory?",
372
+ "› 1. Yes, continue",
373
+ " 2. No, quit",
374
+ " Press enter to continue",
375
+ ].join("\n");
376
+ expect(runtime.detectReady(pane)).toEqual({ phase: "dialog", action: "type:1" });
342
377
  });
343
378
  });
344
379
 
@@ -728,7 +763,7 @@ describe("CodexRuntime integration: spawn command structure", () => {
728
763
  env: { AGENTPLATE_AGENT_NAME: "builder-1" },
729
764
  });
730
765
  expect(cmd).toBe(
731
- "codex --full-auto --model gpt-5-codex 'Read AGENTS.md for your task assignment and begin immediately.'",
766
+ "codex --sandbox workspace-write --ask-for-approval never --model gpt-5-codex 'Read AGENTS.md for your task assignment and begin immediately.'",
732
767
  );
733
768
  });
734
769
 
@@ -741,7 +776,9 @@ describe("CodexRuntime integration: spawn command structure", () => {
741
776
  appendSystemPrompt: baseDefinition,
742
777
  env: { AGENTPLATE_AGENT_NAME: "coordinator" },
743
778
  });
744
- expect(cmd).toContain("codex --full-auto --model gpt-5-codex");
779
+ expect(cmd).toContain(
780
+ "codex --sandbox workspace-write --ask-for-approval never --model gpt-5-codex",
781
+ );
745
782
  expect(cmd).toContain("# Coordinator");
746
783
  expect(cmd).toContain("You are the coordinator agent.");
747
784
  expect(cmd).toContain("Read AGENTS.md");
@@ -755,7 +792,9 @@ describe("CodexRuntime integration: spawn command structure", () => {
755
792
  appendSystemPromptFile: "/project/.agentplate/agent-defs/coordinator.md",
756
793
  env: { AGENTPLATE_AGENT_NAME: "coordinator" },
757
794
  });
758
- expect(cmd).toContain("codex --full-auto --model gpt-5-codex");
795
+ expect(cmd).toContain(
796
+ "codex --sandbox workspace-write --ask-for-approval never --model gpt-5-codex",
797
+ );
759
798
  expect(cmd).toContain("$(cat '/project/.agentplate/agent-defs/coordinator.md')");
760
799
  expect(cmd).toContain("Read AGENTS.md");
761
800
  });
@@ -95,7 +95,10 @@ export class CodexRuntime implements AgentRuntime {
95
95
  const bareModel = CodexRuntime.stripProviderPrefix(opts.model);
96
96
  // When model comes from default manifest aliases (sonnet/opus/haiku),
97
97
  // omit --model so Codex uses the user's configured default model.
98
- let cmd = "codex --full-auto";
98
+ // `--full-auto` was removed in modern codex-cli; the equivalent (write to
99
+ // the workspace without per-command approval prompts) is
100
+ // `--sandbox workspace-write --ask-for-approval never`.
101
+ let cmd = "codex --sandbox workspace-write --ask-for-approval never";
99
102
  if (!CodexRuntime.MANIFEST_ALIASES.has(bareModel)) {
100
103
  cmd += ` --model ${bareModel}`;
101
104
  }
@@ -135,7 +138,9 @@ export class CodexRuntime implements AgentRuntime {
135
138
  * @returns Argv array for Bun.spawn
136
139
  */
137
140
  buildPrintCommand(prompt: string, model?: string): string[] {
138
- const cmd = ["codex", "exec", "--full-auto", "--ephemeral"];
141
+ // `--full-auto` is deprecated in `codex exec` (still works, warns); the
142
+ // non-deprecated form is `--sandbox workspace-write`.
143
+ const cmd = ["codex", "exec", "--sandbox", "workspace-write", "--ephemeral"];
139
144
  if (model !== undefined) {
140
145
  // Strip provider prefix — Codex CLI expects bare model names.
141
146
  cmd.push("--model", CodexRuntime.stripProviderPrefix(model));
@@ -174,13 +179,37 @@ export class CodexRuntime implements AgentRuntime {
174
179
  }
175
180
 
176
181
  /**
177
- * Codex interactive startup is treated as ready once a pane exists.
182
+ * Detect Codex TUI readiness from a tmux pane content snapshot.
178
183
  *
179
- * @param _paneContent - Captured tmux pane content (unused)
180
- * @returns Always `{ phase: "ready" }`
184
+ * Observed against codex-cli 0.128.x, the interactive TUI can show up to two
185
+ * blocking dialogs before it is usable, which we clear via dialog actions:
186
+ * - "Update available" modal (outdated install): "1. Update now / 2. Skip …".
187
+ * Selected via `type:2` (Skip). Distinguished from the passive post-skip
188
+ * "Run npm install …" banner by the "Update now" option text.
189
+ * - "Do you trust the contents of this directory?" prompt: confirm the default
190
+ * "Yes, continue" with Enter.
191
+ * Ready once the Codex header box ("OpenAI Codex") renders.
192
+ *
193
+ * @param paneContent - Captured tmux pane content
194
+ * @returns Current readiness phase
181
195
  */
182
- detectReady(_paneContent: string): ReadyState {
183
- return { phase: "ready" };
196
+ detectReady(paneContent: string): ReadyState {
197
+ // Blocking update modal (numbered options) — skip it. The passive banner
198
+ // shown afterwards says "Run npm install" and lacks the "Update now" option.
199
+ if (paneContent.includes("Update now") && paneContent.includes("Skip")) {
200
+ return { phase: "dialog", action: "type:2" };
201
+ }
202
+ // Trust-directory prompt → select "1. Yes, continue". Use a `type:` action
203
+ // (not bare Enter) so the readiness loop re-fires it until the dialog clears
204
+ // — non-type dialog actions are sent only once (see waitForTuiReady).
205
+ if (paneContent.includes("Do you trust")) {
206
+ return { phase: "dialog", action: "type:1" };
207
+ }
208
+ // Ready: the Codex header box has rendered.
209
+ if (paneContent.includes("OpenAI Codex")) {
210
+ return { phase: "ready" };
211
+ }
212
+ return { phase: "loading" };
184
213
  }
185
214
 
186
215
  /**
package/src/version.ts CHANGED
@@ -2,4 +2,4 @@
2
2
  * Single source of truth for the package version, shared by every bundled bin
3
3
  * (ap/agentplate, lm/loam, sr, tl). Updated by scripts/version-bump.ts.
4
4
  */
5
- export const VERSION = "0.15.1";
5
+ export const VERSION = "0.15.2";