diff --git a/src/cli/profile.test.ts b/src/cli/profile.test.ts index 3ce82c2dd48..617eee78b41 100644 --- a/src/cli/profile.test.ts +++ b/src/cli/profile.test.ts @@ -69,6 +69,64 @@ describe("parseCliProfileArgs", () => { expect(res.argv).toEqual(["node", "openclaw", "status", "--deep"]); }); + it("preserves Matrix QA --profile for the command parser", () => { + const res = parseCliProfileArgs([ + "node", + "openclaw", + "qa", + "matrix", + "--profile", + "fast", + "--fail-fast", + ]); + if (!res.ok) { + throw new Error(res.error); + } + expect(res.profile).toBeNull(); + expect(res.argv).toEqual([ + "node", + "openclaw", + "qa", + "matrix", + "--profile", + "fast", + "--fail-fast", + ]); + }); + + it("preserves Matrix QA --profile after leading root options", () => { + const res = parseCliProfileArgs([ + "node", + "openclaw", + "--no-color", + "qa", + "matrix", + "--profile=fast", + ]); + if (!res.ok) { + throw new Error(res.error); + } + expect(res.profile).toBeNull(); + expect(res.argv).toEqual(["node", "openclaw", "--no-color", "qa", "matrix", "--profile=fast"]); + }); + + it("still parses root --profile before Matrix QA", () => { + const res = parseCliProfileArgs([ + "node", + "openclaw", + "--profile", + "work", + "qa", + "matrix", + "--fail-fast", + ]); + if (!res.ok) { + throw new Error(res.error); + } + expect(res.profile).toBe("work"); + expect(res.argv).toEqual(["node", "openclaw", "qa", "matrix", "--fail-fast"]); + }); + it("parses interleaved --dev after the command token", () => { const res = parseCliProfileArgs(["node", "openclaw", "status", "--dev"]); if (!res.ok) { diff --git a/src/cli/profile.ts b/src/cli/profile.ts index 894c2dcb6c0..be9b1140107 100644 --- a/src/cli/profile.ts +++ b/src/cli/profile.ts @@ -1,5 +1,6 @@ import os from "node:os"; import path from "node:path"; +import { isValueToken } from "../infra/cli-root-options.js"; import { resolveRequiredHomeDir } from "../infra/home-dir.js"; import { normalizeLowercaseStringOrEmpty, @@ -14,6 +15,11 @@ export type CliProfileParseResult = | { ok: true; profile: string | null; argv: string[] } | { ok: false; error: string }; +function isCommandLocalProfileOption(out: string[]): boolean { + const [primary, secondary] = resolveCliArgvInvocation(out).commandPath; + return primary === "qa" && secondary === "matrix"; +} + export function parseCliProfileArgs(argv: string[]): CliProfileParseResult { let profile: string | null = null; let sawDev = false; @@ -33,6 +39,14 @@ export function parseCliProfileArgs(argv: string[]): CliProfileParseResult { } if (arg === "--profile" || arg.startsWith("--profile=")) { + if (isCommandLocalProfileOption(out)) { + out.push(arg); + if (arg === "--profile" && isValueToken(args[index + 1])) { + out.push(args[index + 1]); + return { kind: "handled", consumedNext: true }; + } + return { kind: "handled" }; + } if (sawDev) { return { kind: "error", error: "Cannot combine --dev with --profile" }; }