From cd87b82ac0551f7b657351fbc98e0f8db1b7ee54 Mon Sep 17 00:00:00 2001 From: roboomp Date: Sun, 14 Jun 2026 07:17:19 +0000 Subject: [PATCH] fix(cli): honored `--` as the POSIX positional separator in parseArgs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without an after-separator state, the new unknown-flag guard rejected flag-shaped prompts (`omp -p -- --explain-this`): the loop dropped the `--` token and then re-validated `--explain-this`, recorded it in `unrecognizedFlags`, and exited 2. parseArgs now flips a `sawSeparator` latch on `--` and short-circuits the remaining tokens straight into `messages` — no built-in dispatch, no extension match, no `@file` expansion. Two regression tests cover the flag-shaped and `@`-prefixed cases. Refs #2459 --- packages/coding-agent/CHANGELOG.md | 2 +- packages/coding-agent/src/cli/args.ts | 23 +++++++++++++++---- .../test/cli-unknown-flag.test.ts | 19 +++++++++++++++ 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 9faea0dc5..1511c0d25 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -4,7 +4,7 @@ ### Fixed -- Fixed unknown `--`-prefixed flags being silently consumed as prompt text, which let a stale or typoed flag start a real agent session (connecting to MCP servers, waiting on the model) instead of failing fast. `parseArgs` now tracks unrecognized flag-shaped tokens and `runRootCommand` calls `reportUnrecognizedFlags` immediately after the post-extension reparse, exiting `2` with `Error: unknown flag: --…` before any session, MCP, or initial-message work runs. Extension-registered flags still pass cleanly since the validation runs after the extension-aware reparse ([#2459](https://github.com/can1357/oh-my-pi/issues/2459)). +- Fixed unknown `--`-prefixed flags being silently consumed as prompt text, which let a stale or typoed flag start a real agent session (connecting to MCP servers, waiting on the model) instead of failing fast. `parseArgs` now tracks unrecognized flag-shaped tokens and `runRootCommand` calls `reportUnrecognizedFlags` immediately after the post-extension reparse, exiting `2` with `Error: unknown flag: --…` before any session, MCP, or initial-message work runs. Extension-registered flags still pass cleanly since the validation runs after the extension-aware reparse, and `--` is honored as a POSIX positional separator so flag-shaped prompts (`omp -p -- --explain-this`) survive the new guard ([#2459](https://github.com/can1357/oh-my-pi/issues/2459)). ## [15.12.4] - 2026-06-13 diff --git a/packages/coding-agent/src/cli/args.ts b/packages/coding-agent/src/cli/args.ts index 704a96740..ef0dffa72 100644 --- a/packages/coding-agent/src/cli/args.ts +++ b/packages/coding-agent/src/cli/args.ts @@ -81,10 +81,20 @@ export function parseArgs(inputArgs: string[], extensionFlags?: Map s.trim()); } else if (arg.startsWith("@")) { result.fileArgs.push(arg.slice(1)); // Remove @ prefix - } else if (!arg.startsWith("-") || arg === "-" || arg === "--") { - // Plain positional, lone `-` (stdin marker), or POSIX positional - // separator `--` — pass through as a message rather than flagging it. - if (arg !== "--") result.messages.push(arg); + } else if (!arg.startsWith("-") || arg === "-") { + // Plain positional or lone `-` (stdin marker) — pass through as a + // message rather than flagging it. + result.messages.push(arg); + } else if (arg === "--") { + // POSIX positional separator: drop the token and switch the loop + // into "everything from here is a positional" mode. The guard at + // the top of the loop body handles the remaining tokens. + sawSeparator = true; } else { // Flag-shaped (`-x`, `--name`) but unrecognized at this parse. Record // it so the post-extension reparse can decide whether to surface it diff --git a/packages/coding-agent/test/cli-unknown-flag.test.ts b/packages/coding-agent/test/cli-unknown-flag.test.ts index c5bf189d5..ba142dcf8 100644 --- a/packages/coding-agent/test/cli-unknown-flag.test.ts +++ b/packages/coding-agent/test/cli-unknown-flag.test.ts @@ -66,6 +66,25 @@ describe("parseArgs — unrecognized flag tracking (#2459)", () => { expect(ddash.messages).toEqual(["hello"]); }); + it("treats every token after `--` as a positional, even flag-shaped ones (#2461 review)", () => { + // `omp -p -- --explain-this` must forward `--explain-this` as the + // prompt body. Without after-separator semantics the unknown-flag guard + // trips on it and the CLI exits before any session work. + const parsed = parseArgs(["-p", "--", "--explain-this", "-x", "plain"]); + expect(parsed.print).toBe(true); + expect(parsed.unrecognizedFlags).toEqual([]); + expect(parsed.messages).toEqual(["--explain-this", "-x", "plain"]); + }); + + it("does not expand `@foo` after `--` into a fileArg (POSIX positional semantics)", () => { + // After `--`, application-level conventions like `@file` no longer + // apply — the token is a literal positional. Lets users include `@` + // strings (e.g. emails, handles) in prompts without file lookup. + const parsed = parseArgs(["--", "@notes.md", "hello"]); + expect(parsed.fileArgs).toEqual([]); + expect(parsed.messages).toEqual(["@notes.md", "hello"]); + }); + it("clears extension-registered flags from unrecognizedFlags on the post-extension reparse", () => { const argv = ["--spawn-peer", "reviewer", "review the diff"];