Skip to content

Commit 901f699

Browse files
fix(agent-manager): consume variadic codex -i/--image values in helper detection (#298) (#301)
Codex CLI 0.157.1 declares -i, --image <FILE>... (clap num_args = 1..), so the helper-subcommand check now skips image values until the next flag or known subcommand name, matching clap. Also treats the cloud-tasks alias of cloud as a helper.
1 parent 1e33f43 commit 901f699

2 files changed

Lines changed: 69 additions & 3 deletions

File tree

‎packages/agent-manager/src/__tests__/adapters/CodexAdapter.test.ts‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,42 @@ describe("CodexAdapter", () => {
295295
expect(agents.map((agent) => agent.pid)).toEqual([4321]);
296296
});
297297

298+
// Codex CLI 0.157.1 declares `-i, --image <FILE>...` (clap `num_args = 1..`,
299+
// `value_delimiter = ','`), its only variadic root flag. clap keeps taking
300+
// image values until a flag or a subcommand name, so a helper subcommand can
301+
// follow several images.
302+
describe("variadic -i/--image values (Codex CLI 0.157.1)", () => {
303+
const helperCommands = [
304+
"codex -i a.png b.png cloud",
305+
"codex --image a.png b.png app-server",
306+
"codex -i a.png -i b.png agents",
307+
"codex -i a.png b.png c.png --model o3 mcp list",
308+
"codex --image=a.png,b.png cloud",
309+
"codex -i a.png,b.png login",
310+
"codex -i a.png b.png a",
311+
"codex --image a.png b.png cloud-tasks list",
312+
];
313+
const agentCommands = [
314+
'codex -i a.png "fix the bug"',
315+
"codex -i a.png fix the bug",
316+
"codex -i a.png b.png",
317+
"codex -i a.png resume --last",
318+
"codex --image a.png b.png fork --last",
319+
"codex -i a.png b.png exec summarize the screenshots",
320+
"codex -i a.png b.png e -",
321+
"codex -i a.png b.png review",
322+
"codex -i a.png --model o3 describe this",
323+
];
324+
325+
it.each(helperCommands)("does not handle helper command %s", (command) => {
326+
expect(adapter.canHandle({ pid: 30, command, cwd: "/repo", tty: "??" })).toBe(false);
327+
});
328+
329+
it.each(agentCommands)("handles agent command %s", (command) => {
330+
expect(adapter.canHandle({ pid: 31, command, cwd: "/repo", tty: "ttys003" })).toBe(true);
331+
});
332+
});
333+
298334
it("still excludes helper subcommands when Codex lives under a path containing spaces", () => {
299335
const executable = path.join(
300336
tmpHome,

‎packages/agent-manager/src/providers/codex/CodexAdapter.ts‎

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ const CODEX_HELPER_SUBCOMMANDS = new Set([
4646
"a",
4747
"archive",
4848
"cloud",
49+
"cloud-tasks",
4950
"completion",
5051
"debug",
5152
"delete",
@@ -68,6 +69,21 @@ const CODEX_HELPER_SUBCOMMANDS = new Set([
6869
"update",
6970
]);
7071

72+
/**
73+
* Known root Codex subcommand names and aliases, including the hidden ones in
74+
* Codex CLI 0.157.1. A variadic flag's values stop at these, as clap stops there.
75+
*/
76+
const CODEX_SUBCOMMANDS = new Set([
77+
...CODEX_HELPER_SUBCOMMANDS,
78+
"e",
79+
"exec",
80+
"execpolicy",
81+
"fork",
82+
"resume",
83+
"review",
84+
"tcp-tunnel",
85+
]);
86+
7187
/** Global Codex flags that consume the following argument as their value. */
7288
const CODEX_VALUE_FLAGS = new Set([
7389
"-c",
@@ -82,8 +98,6 @@ const CODEX_VALUE_FLAGS = new Set([
8298
"--ask-for-approval",
8399
"-C",
84100
"--cd",
85-
"-i",
86-
"--image",
87101
"--add-dir",
88102
"--enable",
89103
"--disable",
@@ -92,6 +106,12 @@ const CODEX_VALUE_FLAGS = new Set([
92106
"--remote-auth-token-env",
93107
]);
94108

109+
/**
110+
* Global Codex flags that take one or more values (clap `num_args = 1..`).
111+
* `-i, --image <FILE>...` is the only one in Codex CLI 0.157.1.
112+
*/
113+
const CODEX_VARIADIC_VALUE_FLAGS = new Set(["-i", "--image"]);
114+
95115
const CODEX_APP_SERVER_DAEMON_DIR = "app-server-daemon";
96116

97117
function isCodexHelperCommand(command: string): boolean {
@@ -112,11 +132,21 @@ function firstPositionalArgument(args: string[]): string | undefined {
112132
const arg = args[index];
113133
if (arg === "--") return undefined;
114134
if (!arg.startsWith("-")) return arg;
115-
if (!arg.includes("=") && CODEX_VALUE_FLAGS.has(arg)) index++;
135+
if (arg.includes("=")) continue;
136+
if (CODEX_VALUE_FLAGS.has(arg)) {
137+
index++;
138+
} else if (CODEX_VARIADIC_VALUE_FLAGS.has(arg)) {
139+
// Like clap, take values until the next flag or subcommand name.
140+
while (index + 1 < args.length && isVariadicFlagValue(args[index + 1])) index++;
141+
}
116142
}
117143
return undefined;
118144
}
119145

146+
function isVariadicFlagValue(arg: string): boolean {
147+
return !arg.startsWith("-") && !CODEX_SUBCOMMANDS.has(arg);
148+
}
149+
120150
interface MappedAgentResult {
121151
agents: AgentInfo[];
122152
fallback: ProcessInfo[];

0 commit comments

Comments
 (0)