mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-04 22:32:56 +00:00
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:
@@ -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",
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user