feat(maestro): sort dormant sessions after live ones in the sidebar

docs/SIDEBAR.md: a dormant session takes the lowest precedence in the
sidebar tree, so a rebooted host's live work never sorts under a pile
of dormant cards.
This commit is contained in:
Miguel Palhas
2026-09-04 09:19:03 +01:00
parent a793727bb9
commit 8269bcabcc
2 changed files with 45 additions and 1 deletions
+37 -1
View File
@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest";
import { buildTree, mergeLinear, type TreeFolder, type TreeNode } from "./tree.js";
import { buildTree, compareNodes, mergeLinear, type TreeFolder, type TreeNode } from "./tree.js";
import type { Session } from "./types.js";
function session(id: string, cwd: string, command = "bash"): Session {
@@ -67,6 +67,42 @@ describe("buildTree", () => {
expect(root.children[0].kind).toBe("folder");
expect(root.children[1].kind).toBe("leaf");
});
// #168, docs/SIDEBAR.md: a dormant session takes the lowest precedence in
// the ordering, so live work always sorts above it, even a name that would
// otherwise sort first.
it("sorts a dormant session after live ones in the same folder, name notwithstanding", () => {
const dormant = { ...session("aaa-dormant", "/home/n/work"), status: "Dormant" } as Session;
const live = session("zzz-live", "/home/n/work");
const root = buildTree([dormant, live], "/home/n") as TreeFolder;
const folder = root.children[0] as TreeFolder;
const ids = folder.children.map((c) => (c.kind === "leaf" ? c.session.id : c.name));
expect(ids).toEqual(["zzz-live", "aaa-dormant"]);
});
it("still sorts dormant sessions by name against each other", () => {
const a = {
...session("a", "/home/n/work"),
status: "Dormant",
metadata: { name: "a" },
} as Session;
const b = {
...session("b", "/home/n/work"),
status: "Dormant",
metadata: { name: "b" },
} as Session;
const root = buildTree([b, a], "/home/n") as TreeFolder;
const folder = root.children[0] as TreeFolder;
const ids = folder.children.map((c) => (c.kind === "leaf" ? c.session.id : c.name));
expect(ids).toEqual(["a", "b"]);
});
it("exposes the leaf/name precedence directly via compareNodes", () => {
const dormant: TreeNode = { kind: "leaf", session: { ...session("a", "/x"), status: "Dormant" } };
const live: TreeNode = { kind: "leaf", session: session("b", "/x") };
expect(compareNodes(dormant, live)).toBeGreaterThan(0);
expect(compareNodes(live, dormant)).toBeLessThan(0);
});
});
describe("mergeLinear", () => {
+8
View File
@@ -18,8 +18,16 @@ export interface TreeLeaf {
export type TreeNode = TreeFolder | TreeLeaf;
/** docs/SIDEBAR.md: a dormant session takes the lowest precedence in the
* ordering, so live work always sorts above it regardless of name. */
function dormantRank(node: TreeNode): number {
return node.kind === "leaf" && node.session.status === "Dormant" ? 1 : 0;
}
export function compareNodes(a: TreeNode, b: TreeNode): number {
if (a.kind !== b.kind) return a.kind === "folder" ? -1 : 1;
const rank = dormantRank(a) - dormantRank(b);
if (rank !== 0) return rank;
const an = a.kind === "folder" ? a.name : sessionName(a.session);
const bn = b.kind === "folder" ? b.name : sessionName(b.session);
return an.localeCompare(bn);