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 <zheng.zuo0@gmail.com>
This commit is contained in:
Zee Zheng
2026-05-31 04:29:39 +08:00
committed by GitHub
parent b6891d284d
commit c80ec43325
7 changed files with 1014 additions and 81 deletions

View File

@@ -7,6 +7,7 @@ const mocks = vi.hoisted(() => ({
healthCommand: vi.fn(),
sessionsCommand: vi.fn(),
sessionsCleanupCommand: vi.fn(),
sessionsTailCommand: vi.fn(),
exportTrajectoryCommand: vi.fn(),
commitmentsListCommand: vi.fn(),
commitmentsDismissCommand: vi.fn(),
@@ -31,6 +32,7 @@ const statusCommand = mocks.statusCommand;
const healthCommand = mocks.healthCommand;
const sessionsCommand = mocks.sessionsCommand;
const sessionsCleanupCommand = mocks.sessionsCleanupCommand;
const sessionsTailCommand = mocks.sessionsTailCommand;
const exportTrajectoryCommand = mocks.exportTrajectoryCommand;
const commitmentsListCommand = mocks.commitmentsListCommand;
const commitmentsDismissCommand = mocks.commitmentsDismissCommand;
@@ -88,6 +90,10 @@ vi.mock("../../commands/sessions-cleanup.js", () => ({
sessionsCleanupCommand: mocks.sessionsCleanupCommand,
}));
vi.mock("../../commands/sessions-tail.js", () => ({
sessionsTailCommand: mocks.sessionsTailCommand,
}));
vi.mock("../../commands/export-trajectory.js", () => ({
exportTrajectoryCommand: mocks.exportTrajectoryCommand,
}));
@@ -134,6 +140,7 @@ describe("registerStatusHealthSessionsCommands", () => {
healthCommand.mockResolvedValue(undefined);
sessionsCommand.mockResolvedValue(undefined);
sessionsCleanupCommand.mockResolvedValue(undefined);
sessionsTailCommand.mockResolvedValue(undefined);
exportTrajectoryCommand.mockResolvedValue(undefined);
commitmentsListCommand.mockResolvedValue(undefined);
commitmentsDismissCommand.mockResolvedValue(undefined);
@@ -345,6 +352,31 @@ describe("registerStatusHealthSessionsCommands", () => {
});
});
it("runs sessions tail with forwarded progress options", async () => {
await runCli([
"sessions",
"--store",
"/tmp/sessions.json",
"--agent",
"work",
"tail",
"--session-key",
"agent:main:telegram:direct:owner",
"--tail",
"5",
"--follow",
]);
expectCommandOptions(sessionsTailCommand, {
sessionKey: "agent:main:telegram:direct:owner",
store: "/tmp/sessions.json",
agent: "work",
allAgents: false,
follow: true,
tail: "5",
});
});
it("runs sessions export-trajectory with owner-routable export options", async () => {
await runCli([
"sessions",

View File

@@ -286,6 +286,39 @@ export function registerStatusHealthSessionsCommands(program: Command) {
});
});
sessionsCmd
.command("tail")
.description("Tail human-readable session trajectory progress")
.option("--session-key <key>", "Session key to tail (default: active sessions or latest)")
.option("--tail <count>", "Number of existing trajectory events to show", "80")
.option("--follow", "Continue following for new trajectory events", false)
.option("--store <path>", "Path to session store (default: resolved from config)")
.option("--agent <id>", "Agent id to inspect (default: configured default agent)")
.option("--all-agents", "Aggregate sessions across all configured agents", false)
.action(async (opts, command) => {
const parentOpts = command.parent?.opts() as
| {
store?: string;
agent?: string;
allAgents?: boolean;
}
| undefined;
await runCommandWithRuntime(defaultRuntime, async () => {
const { sessionsTailCommand } = await import("../../commands/sessions-tail.js");
await sessionsTailCommand(
{
sessionKey: opts.sessionKey as string | undefined,
store: (opts.store as string | undefined) ?? parentOpts?.store,
agent: (opts.agent as string | undefined) ?? parentOpts?.agent,
allAgents: Boolean(opts.allAgents || parentOpts?.allAgents),
follow: Boolean(opts.follow),
tail: opts.tail as string | undefined,
},
defaultRuntime,
);
});
});
sessionsCmd
.command("export-trajectory")
.description("Export a redacted trajectory bundle for a stored session")