






















@@ -20,6 +20,10 @@ function setRawArgs(command: Command, rawArgs: string[]): void {
2020(command as Command & { rawArgs: string[] }).rawArgs = rawArgs;
2121}
222223+function deleteRawArgs(command: Command): void {
24+delete (command as Command & { rawArgs?: string[] }).rawArgs;
25+}
26+2327describe("reparseProgramFromActionArgs", () => {
2428beforeEach(() => {
2529vi.clearAllMocks();
@@ -104,12 +108,33 @@ describe("reparseProgramFromActionArgs", () => {
104108expect(buildParseArgvMock).toHaveBeenCalledWith({
105109programName: "openclaw",
106110rawArgs: ["node", "openclaw", "workspaces", "audit", "export", "--since", "1"],
107-fallbackArgv: ["export", "--since", "1"],
111+fallbackArgv: ["workspaces", "audit", "export", "--since", "1"],
108112});
109113expect(parseAsync).toHaveBeenCalledWith(["node", "openclaw", "status"]);
110114expect(auditParseAsync).not.toHaveBeenCalled();
111115});
112116117+it("reconstructs the full nested command path when Commander rawArgs is missing", async () => {
118+// #83893: nested lazy commands still need their ancestor path if
119+// Commander stops exposing root rawArgs at runtime.
120+const root = new Command().name("openclaw");
121+const workspaces = root.command("workspaces");
122+const audit = workspaces.command("audit");
123+const exportCommand = audit.command("export");
124+deleteRawArgs(root);
125+const parseAsync = vi.spyOn(root, "parseAsync").mockResolvedValue(root);
126+resolveActionArgsMock.mockReturnValue(["--since", "1"]);
127+128+await reparseProgramFromActionArgs(audit, [exportCommand]);
129+130+expect(buildParseArgvMock).toHaveBeenCalledWith({
131+programName: "openclaw",
132+rawArgs: undefined,
133+fallbackArgv: ["workspaces", "audit", "export", "--since", "1"],
134+});
135+expect(parseAsync).toHaveBeenCalledWith(["node", "openclaw", "status"]);
136+});
137+113138it("uses program root when action command is missing", async () => {
114139const program = new Command().name("openclaw");
115140const parseAsync = vi.spyOn(program, "parseAsync").mockResolvedValue(program);
@@ -124,4 +149,23 @@ describe("reparseProgramFromActionArgs", () => {
124149});
125150expect(parseAsync).toHaveBeenCalledWith(["node", "openclaw", "status"]);
126151});
152+153+it("falls back to fallbackArgv when Commander rawArgs is missing from the root command", async () => {
154+// #83893: rawArgs is a Commander runtime field, so the root command must
155+// still reparse from reconstructed argv if Commander stops exposing it.
156+const root = new Command().name("openclaw");
157+const configCommand = root.command("config");
158+deleteRawArgs(root);
159+const parseAsync = vi.spyOn(root, "parseAsync").mockResolvedValue(root);
160+resolveActionArgsMock.mockReturnValue(["set", "key", "value"]);
161+162+await reparseProgramFromActionArgs(root, [configCommand]);
163+164+expect(buildParseArgvMock).toHaveBeenCalledWith({
165+programName: "openclaw",
166+rawArgs: undefined,
167+fallbackArgv: ["config", "set", "key", "value"],
168+});
169+expect(parseAsync).toHaveBeenCalled();
170+});
127171});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。