Skip to content

Commit 9eff42f

Browse files
YB0yYB0y
authored andcommitted
fix(cli): add sessions list alias matching cron/commitments/devices/mcp convention (#81139)
openclaw sessions was the only list-style parent command that rejected a list subcommand. Every sibling (cron list, commitments list, devices list, mcp list, plugins list, agents list, tasks list) accepts the convention; sessions list errored with "Too many arguments for this command." and pointed users at openclaw sessions list --help, which silently dropped the list arg and showed help for bare sessions. The closed #60905 fix only addressed exit code, not the missing alias. Register sessionsCmd.command("list") that delegates to the same sessionsCommand handler the bare command already calls. With enablePositionalOptions on the parent, commander captures any option whose name matches the parent (--json, --verbose, --store, --agent, --all-agents, --active, --limit) onto the parent regardless of position, so the action merges its own opts with command.parent.opts(). Flags work both before and after list (sessions --json list and sessions list --json). Mirrors the parentOpts pattern already used by the sibling cleanup subcommand and by commitments list / tasks list elsewhere in this file. Verified: - pnpm test src/cli/program/register.status-health-sessions.test.ts (28 passed) - pnpm exec oxfmt --check --threads=1 src/cli/program/register.status-health-sessions.ts src/cli/program/register.status-health-sessions.test.ts (clean) - pnpm check:changed (exit 0) - pnpm build && node openclaw.mjs sessions list (lists sessions, exit 0) - pnpm build && node openclaw.mjs sessions list --json (JSON output, exit 0) - pnpm build && node openclaw.mjs sessions --json list (JSON output, exit 0) - pnpm build && node openclaw.mjs sessions list --agent work (forwards --agent, errors with "Unknown agent id 'work'") - pnpm build && node openclaw.mjs sessions --json (bare baseline unchanged, exit 0) - pnpm build && node openclaw.mjs sessions cleanup --dry-run (sibling subcommand unchanged, exit 0) Closes #81139
1 parent 046d6fc commit 9eff42f

2 files changed

Lines changed: 140 additions & 0 deletions

File tree

src/cli/program/register.status-health-sessions.test.ts

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,98 @@ describe("registerStatusHealthSessionsCommands", () => {
241241
});
242242
});
243243

244+
it("dispatches sessions list as an alias for bare sessions (regression for #81139)", async () => {
245+
await runCli(["sessions", "list"]);
246+
247+
expect(sessionsCommand).toHaveBeenCalledTimes(1);
248+
expectCommandOptions(sessionsCommand, {
249+
json: false,
250+
allAgents: false,
251+
agent: undefined,
252+
store: undefined,
253+
});
254+
});
255+
256+
it("forwards sessions parent options through the list alias (flags before list)", async () => {
257+
await runCli([
258+
"sessions",
259+
"--json",
260+
"--verbose",
261+
"--store",
262+
"/tmp/sessions.json",
263+
"--active",
264+
"120",
265+
"--limit",
266+
"25",
267+
"list",
268+
]);
269+
270+
expect(setVerbose).toHaveBeenCalledWith(true);
271+
expectCommandOptions(sessionsCommand, {
272+
json: true,
273+
store: "/tmp/sessions.json",
274+
active: "120",
275+
limit: "25",
276+
});
277+
});
278+
279+
it("forwards sessions list-side options (flags after list)", async () => {
280+
await runCli([
281+
"sessions",
282+
"list",
283+
"--json",
284+
"--verbose",
285+
"--store",
286+
"/tmp/sessions.json",
287+
"--active",
288+
"120",
289+
"--limit",
290+
"25",
291+
]);
292+
293+
expect(setVerbose).toHaveBeenCalledWith(true);
294+
expectCommandOptions(sessionsCommand, {
295+
json: true,
296+
store: "/tmp/sessions.json",
297+
active: "120",
298+
limit: "25",
299+
});
300+
});
301+
302+
it("forwards --agent through the list alias (flag before list)", async () => {
303+
await runCli(["sessions", "--agent", "work", "list"]);
304+
305+
expectCommandOptions(sessionsCommand, {
306+
agent: "work",
307+
allAgents: false,
308+
});
309+
});
310+
311+
it("forwards --agent through the list alias (flag after list)", async () => {
312+
await runCli(["sessions", "list", "--agent", "work"]);
313+
314+
expectCommandOptions(sessionsCommand, {
315+
agent: "work",
316+
allAgents: false,
317+
});
318+
});
319+
320+
it("forwards --all-agents through the list alias (flag before list)", async () => {
321+
await runCli(["sessions", "--all-agents", "list"]);
322+
323+
expectCommandOptions(sessionsCommand, {
324+
allAgents: true,
325+
});
326+
});
327+
328+
it("forwards --all-agents through the list alias (flag after list)", async () => {
329+
await runCli(["sessions", "list", "--all-agents"]);
330+
331+
expectCommandOptions(sessionsCommand, {
332+
allAgents: true,
333+
});
334+
});
335+
244336
it("runs sessions cleanup subcommand with forwarded options", async () => {
245337
await runCli([
246338
"sessions",

src/cli/program/register.status-health-sessions.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,54 @@ export function registerStatusHealthSessionsCommands(program: Command) {
169169
});
170170
sessionsCmd.enablePositionalOptions();
171171

172+
// Backward-compatible `sessions list` alias. Every other list-style parent
173+
// command (cron, commitments, devices, mcp, plugins, agents, tasks) accepts
174+
// a bare `list` subcommand; without this alias, `openclaw sessions list`
175+
// hits the generic parser's "Too many arguments" path and the recovery
176+
// suggestion (`sessions list --help`) silently drops the extra argument.
177+
// See #81139.
178+
//
179+
// The action merges its own `opts` with `command.parent.opts()` so flags
180+
// work both before and after `list` (e.g. `sessions --json list` and
181+
// `sessions list --json`). This matches the parentOpts pattern used by the
182+
// sibling `cleanup` subcommand below and by `commitments list` / `tasks
183+
// list` elsewhere in this file.
184+
sessionsCmd
185+
.command("list")
186+
.description("List stored conversation sessions (alias for `openclaw sessions`)")
187+
.option("--json", "Output as JSON", false)
188+
.option("--verbose", "Verbose logging", false)
189+
.option("--store <path>", "Path to session store (default: resolved from config)")
190+
.option("--agent <id>", "Agent id to inspect (default: configured default agent)")
191+
.option("--all-agents", "Aggregate sessions across all configured agents", false)
192+
.option("--active <minutes>", "Only show sessions updated within the past N minutes")
193+
.option("--limit <count>", 'Max sessions to show (default: 100; use "all" for full output)')
194+
.action(async (opts, command) => {
195+
const parentOpts = command.parent?.opts() as
196+
| {
197+
json?: boolean;
198+
verbose?: boolean;
199+
store?: string;
200+
agent?: string;
201+
allAgents?: boolean;
202+
active?: string;
203+
limit?: string;
204+
}
205+
| undefined;
206+
setVerbose(Boolean(opts.verbose || parentOpts?.verbose));
207+
await sessionsCommand(
208+
{
209+
json: Boolean(opts.json || parentOpts?.json),
210+
store: (opts.store as string | undefined) ?? parentOpts?.store,
211+
agent: (opts.agent as string | undefined) ?? parentOpts?.agent,
212+
allAgents: Boolean(opts.allAgents || parentOpts?.allAgents),
213+
active: (opts.active as string | undefined) ?? parentOpts?.active,
214+
limit: (opts.limit as string | undefined) ?? parentOpts?.limit,
215+
},
216+
defaultRuntime,
217+
);
218+
});
219+
172220
sessionsCmd
173221
.command("cleanup")
174222
.description("Run session-store maintenance now")

0 commit comments

Comments
 (0)