feat(cli): hide terminal sessions in `ao session ls` by default (#1319)
* feat(cli): hide terminal session rows by default in session ls - Filter with TERMINAL_STATUSES unless --include-terminated - Hint when completed sessions are hidden; docs/CLI.md updated Made-with: Cursor * fix(cli): keep session ls JSON inventory stable Address review concerns by preserving terminal sessions in `ao session ls --json` output while keeping terminal rows hidden by default in text output. Use the core terminal-session predicate, improve hidden-row messaging, and add regression tests for mixed/hinted and JSON behavior. Made-with: Cursor * fix(cli): resolve rebase conflicts with latest session ls behavior Align session command and CLI docs with the current mainline JSON contract (`data` + `meta.hiddenTerminatedCount`) while preserving terminal-filter defaults and updated regression coverage. Made-with: Cursor
This commit is contained in:
parent
e518562a62
commit
f09cc72dc8
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"@aoagents/ao-cli": patch
|
||||
---
|
||||
|
||||
`ao session ls` hides terminal sessions in text output by default; use `--include-terminated` for the full text list.
|
||||
|
|
@ -370,6 +370,23 @@ describe("session ls", () => {
|
|||
});
|
||||
});
|
||||
|
||||
it("filters terminal sessions from JSON by default and reports hidden count", async () => {
|
||||
writeFileSync(join(sessionsDir, "app-1"), "branch=main\nstatus=working\n");
|
||||
writeFileSync(join(sessionsDir, "app-done"), "branch=main\nstatus=merged\nactivity=exited\n");
|
||||
|
||||
mockTmux.mockResolvedValue(null);
|
||||
mockGit.mockResolvedValue(null);
|
||||
|
||||
await program.parseAsync(["node", "test", "session", "ls", "--json"]);
|
||||
|
||||
const parsed = JSON.parse(String(consoleSpy.mock.calls[0][0])) as {
|
||||
data: Array<{ id: string }>;
|
||||
meta: { hiddenTerminatedCount: number };
|
||||
};
|
||||
expect(parsed.data.map((entry) => entry.id)).toEqual(["app-1"]);
|
||||
expect(parsed.meta.hiddenTerminatedCount).toBe(1);
|
||||
});
|
||||
|
||||
it("marks metadata-based orchestrators correctly in JSON output", async () => {
|
||||
writeFileSync(
|
||||
join(sessionsDir, "app-control"),
|
||||
|
|
@ -573,6 +590,71 @@ describe("session ls", () => {
|
|||
expect(parsed.data.map((e: { id: string }) => e.id)).toEqual(["app-1"]);
|
||||
expect(parsed.meta.hiddenTerminatedCount).toBe(3);
|
||||
});
|
||||
|
||||
it("hides terminal-status sessions by default", async () => {
|
||||
writeFileSync(join(sessionsDir, "app-1"), "branch=main\nstatus=working\n");
|
||||
writeFileSync(join(sessionsDir, "app-done"), "branch=main\nstatus=merged\n");
|
||||
|
||||
mockTmux.mockImplementation(async (...args: string[]) => {
|
||||
if (args[0] === "list-sessions") return "app-1\napp-done";
|
||||
if (args[0] === "display-message") {
|
||||
return String(Math.floor(Date.now() / 1000) - 60);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
mockGit.mockResolvedValue(null);
|
||||
|
||||
await program.parseAsync(["node", "test", "session", "ls"]);
|
||||
|
||||
const output = consoleSpy.mock.calls.map((c) => String(c[0])).join("\n");
|
||||
expect(output).toContain("app-1");
|
||||
expect(output).not.toContain("app-done");
|
||||
});
|
||||
|
||||
it("lists terminal sessions when --include-terminated is set", async () => {
|
||||
writeFileSync(join(sessionsDir, "app-done"), "branch=main\nstatus=merged\n");
|
||||
|
||||
mockTmux.mockImplementation(async (...args: string[]) => {
|
||||
if (args[0] === "list-sessions") return "app-done";
|
||||
return null;
|
||||
});
|
||||
mockGit.mockResolvedValue(null);
|
||||
|
||||
await program.parseAsync(["node", "test", "session", "ls", "--include-terminated"]);
|
||||
|
||||
const output = consoleSpy.mock.calls.map((c) => String(c[0])).join("\n");
|
||||
expect(output).toContain("app-done");
|
||||
});
|
||||
|
||||
it("prints a hint when only terminal sessions exist", async () => {
|
||||
writeFileSync(join(sessionsDir, "app-done"), "branch=main\nstatus=merged\n");
|
||||
|
||||
mockTmux.mockImplementation(async (...args: string[]) => {
|
||||
if (args[0] === "list-sessions") return "app-done";
|
||||
return null;
|
||||
});
|
||||
|
||||
await program.parseAsync(["node", "test", "session", "ls"]);
|
||||
|
||||
const output = consoleSpy.mock.calls.map((c) => String(c[0])).join("\n");
|
||||
expect(output).toContain("--include-terminated");
|
||||
expect(output).not.toContain("app-done");
|
||||
});
|
||||
|
||||
it("prints a hint when terminal sessions are hidden alongside active ones", async () => {
|
||||
writeFileSync(join(sessionsDir, "app-1"), "branch=main\nstatus=working\n");
|
||||
writeFileSync(join(sessionsDir, "app-done"), "branch=main\nstatus=merged\n");
|
||||
|
||||
mockTmux.mockResolvedValue(null);
|
||||
mockGit.mockResolvedValue(null);
|
||||
|
||||
await program.parseAsync(["node", "test", "session", "ls"]);
|
||||
|
||||
const output = consoleSpy.mock.calls.map((c) => String(c[0])).join("\n");
|
||||
expect(output).toContain("app-1");
|
||||
expect(output).toContain("terminated session");
|
||||
expect(output).toContain("--include-terminated");
|
||||
});
|
||||
});
|
||||
|
||||
describe("session kill", () => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue