diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 10a4dfc56..8e6402af0 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -115,6 +115,7 @@ - Fixed prompt templates discovered from `cwd/.omp/prompts/` and the agent prompts directory not appearing in the slash-command autocomplete picker. `InteractiveMode.refreshSlashCommandState()` now feeds `session.promptTemplates` into the autocomplete provider alongside builtins and file-based slash commands; templates whose names collide with an existing command are skipped to mirror the runtime expansion order (`expandSlashCommand` precedes `expandPromptTemplate`) ([#2462](https://github.com/can1357/oh-my-pi/issues/2462)). - Fixed empty-Enter steering interrupts leaving the newest queued steer visible after aborting an auto-continued queued turn; queued turns now re-drain after every abort/settle cycle. - Added an agent-visible notice when the write tool auto-marks shebang files executable, so agents do not redundantly run `chmod +x`. +- 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"];