Skip to content

Commit c80ec43

Browse files
feat(cli): add sessions tail progress view
Adds `openclaw sessions tail` as an operator-facing progress view over session trajectory events, with conservative redaction for prompt text, tool arguments, and tool result bodies. The command supports explicit session keys, store/agent scope, follow mode, relocated trajectory pointer files, and cursor-safe follow across bounded trajectory window rewrites. Documents the new sessions tail CLI surface in `docs/cli/sessions.md`. Fixes #83441. Co-authored-by: zhengzuo0-ai <[email protected]>
1 parent b6891d2 commit c80ec43

7 files changed

Lines changed: 1014 additions & 81 deletions

File tree

docs/cli/sessions.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,20 @@ Scope selection:
4747
- `--store <path>`: explicit store path (cannot be combined with `--agent` or `--all-agents`)
4848
- `--limit <n|all>`: max rows to output (default `100`; `all` restores full output)
4949

50+
Tail human-readable trajectory progress for stored sessions:
51+
52+
```bash
53+
openclaw sessions tail
54+
openclaw sessions tail --follow
55+
openclaw sessions tail --session-key "agent:main:telegram:direct:123" --tail 25
56+
openclaw sessions --agent work tail --follow
57+
openclaw sessions --all-agents tail --follow
58+
```
59+
60+
`openclaw sessions tail` renders recent trajectory JSONL events as compact progress lines. Without `--session-key`, it tails running sessions first, then the latest stored session. `--tail <count>` controls how many existing events print before follow mode; the default is `80`, and `0` starts at the current end. `--follow` keeps watching the selected trajectory files, including relocated files referenced by `<session>.trajectory-path.json`.
61+
62+
The progress view is intentionally conservative: prompt text, tool arguments, and tool result bodies are not printed. Tool calls show the tool name with `{...redacted...}`; tool results show status such as `ok`, `error`, or `done`; model completion lines show provider/model and terminal status.
63+
5064
Export a trajectory bundle for a stored session:
5165

5266
```bash

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const mocks = vi.hoisted(() => ({
77
healthCommand: vi.fn(),
88
sessionsCommand: vi.fn(),
99
sessionsCleanupCommand: vi.fn(),
10+
sessionsTailCommand: vi.fn(),
1011
exportTrajectoryCommand: vi.fn(),
1112
commitmentsListCommand: vi.fn(),
1213
commitmentsDismissCommand: vi.fn(),
@@ -31,6 +32,7 @@ const statusCommand = mocks.statusCommand;
3132
const healthCommand = mocks.healthCommand;
3233
const sessionsCommand = mocks.sessionsCommand;
3334
const sessionsCleanupCommand = mocks.sessionsCleanupCommand;
35+
const sessionsTailCommand = mocks.sessionsTailCommand;
3436
const exportTrajectoryCommand = mocks.exportTrajectoryCommand;
3537
const commitmentsListCommand = mocks.commitmentsListCommand;
3638
const commitmentsDismissCommand = mocks.commitmentsDismissCommand;
@@ -88,6 +90,10 @@ vi.mock("../../commands/sessions-cleanup.js", () => ({
8890
sessionsCleanupCommand: mocks.sessionsCleanupCommand,
8991
}));
9092

93+
vi.mock("../../commands/sessions-tail.js", () => ({
94+
sessionsTailCommand: mocks.sessionsTailCommand,
95+
}));
96+
9197
vi.mock("../../commands/export-trajectory.js", () => ({
9298
exportTrajectoryCommand: mocks.exportTrajectoryCommand,
9399
}));
@@ -134,6 +140,7 @@ describe("registerStatusHealthSessionsCommands", () => {
134140
healthCommand.mockResolvedValue(undefined);
135141
sessionsCommand.mockResolvedValue(undefined);
136142
sessionsCleanupCommand.mockResolvedValue(undefined);
143+
sessionsTailCommand.mockResolvedValue(undefined);
137144
exportTrajectoryCommand.mockResolvedValue(undefined);
138145
commitmentsListCommand.mockResolvedValue(undefined);
139146
commitmentsDismissCommand.mockResolvedValue(undefined);
@@ -345,6 +352,31 @@ describe("registerStatusHealthSessionsCommands", () => {
345352
});
346353
});
347354

355+
it("runs sessions tail with forwarded progress options", async () => {
356+
await runCli([
357+
"sessions",
358+
"--store",
359+
"/tmp/sessions.json",
360+
"--agent",
361+
"work",
362+
"tail",
363+
"--session-key",
364+
"agent:main:telegram:direct:owner",
365+
"--tail",
366+
"5",
367+
"--follow",
368+
]);
369+
370+
expectCommandOptions(sessionsTailCommand, {
371+
sessionKey: "agent:main:telegram:direct:owner",
372+
store: "/tmp/sessions.json",
373+
agent: "work",
374+
allAgents: false,
375+
follow: true,
376+
tail: "5",
377+
});
378+
});
379+
348380
it("runs sessions export-trajectory with owner-routable export options", async () => {
349381
await runCli([
350382
"sessions",

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,39 @@ export function registerStatusHealthSessionsCommands(program: Command) {
286286
});
287287
});
288288

289+
sessionsCmd
290+
.command("tail")
291+
.description("Tail human-readable session trajectory progress")
292+
.option("--session-key <key>", "Session key to tail (default: active sessions or latest)")
293+
.option("--tail <count>", "Number of existing trajectory events to show", "80")
294+
.option("--follow", "Continue following for new trajectory events", false)
295+
.option("--store <path>", "Path to session store (default: resolved from config)")
296+
.option("--agent <id>", "Agent id to inspect (default: configured default agent)")
297+
.option("--all-agents", "Aggregate sessions across all configured agents", false)
298+
.action(async (opts, command) => {
299+
const parentOpts = command.parent?.opts() as
300+
| {
301+
store?: string;
302+
agent?: string;
303+
allAgents?: boolean;
304+
}
305+
| undefined;
306+
await runCommandWithRuntime(defaultRuntime, async () => {
307+
const { sessionsTailCommand } = await import("../../commands/sessions-tail.js");
308+
await sessionsTailCommand(
309+
{
310+
sessionKey: opts.sessionKey as string | undefined,
311+
store: (opts.store as string | undefined) ?? parentOpts?.store,
312+
agent: (opts.agent as string | undefined) ?? parentOpts?.agent,
313+
allAgents: Boolean(opts.allAgents || parentOpts?.allAgents),
314+
follow: Boolean(opts.follow),
315+
tail: opts.tail as string | undefined,
316+
},
317+
defaultRuntime,
318+
);
319+
});
320+
});
321+
289322
sessionsCmd
290323
.command("export-trajectory")
291324
.description("Export a redacted trajectory bundle for a stored session")

0 commit comments

Comments
 (0)