From 2da22b940abd45738c2f5c9ce3c9bb467db33652 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Thu, 19 Mar 2026 11:29:22 -0700 Subject: [PATCH] Fix list command to skip empty JSON output and batch stale-review cleanup Collapse redundant empty-session branch so --json falls through to the normal serialization path instead of printing "[]" separately. Replace per-branch load/save loop with a single state cycle to avoid racing concurrent writes. Co-Authored-By: Claude Opus 4.6 --- src/commands/list.ts | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/commands/list.ts b/src/commands/list.ts index 71413ce..59ba127 100644 --- a/src/commands/list.ts +++ b/src/commands/list.ts @@ -30,14 +30,10 @@ export async function action(opts: { json?: boolean }) { } catch {} } - if (sessions.length === 0) { - if (opts.json) { - console.log("[]") - } else { - console.log("◆ No active sessions.") - if ((await vm.status()) !== "running") { - console.log(`\n${red}VM is not running.${reset}`) - } + if (sessions.length === 0 && !opts.json) { + console.log("◆ No active sessions.") + if ((await vm.status()) !== "running") { + console.log(`\n${red}VM is not running.${reset}`) } return } @@ -61,13 +57,13 @@ export async function action(opts: { json?: boolean }) { ) const statuses = Object.fromEntries(statusEntries) - // Clear stale in_review flags via setSession to avoid clobbering concurrent writes - for (const branch of staleReviewBranches) { - const fresh = await state.getSession(root, branch) - if (fresh) { - fresh.in_review = false - await state.setSession(root, fresh).catch(() => {}) + // Clear stale in_review flags in a single load/save cycle + if (staleReviewBranches.length > 0) { + const fresh = await state.load(root) + for (const branch of staleReviewBranches) { + if (fresh.sessions[branch]) fresh.sessions[branch].in_review = false } + await state.save(root, fresh).catch(() => {}) } if (opts.json) { @@ -76,13 +72,13 @@ export async function action(opts: { json?: boolean }) { return } - const styles: Record = { - idle: { icon: `${dim}◯${reset}`, color: dim }, - active: { icon: `${cyan}◎${reset}`, color: cyan }, - dirty: { icon: `${yellow}◐${reset}`, color: yellow }, - saved: { icon: `${green}●${reset}`, color: green }, - review: { icon: `${magenta}⦿${reset}`, color: magenta }, - } + const styleDefs: [string, string, string][] = [ + ["idle", dim, "◯"], ["active", cyan, "◎"], ["dirty", yellow, "◐"], + ["saved", green, "●"], ["review", magenta, "⦿"], + ] + const styles = Object.fromEntries( + styleDefs.map(([k, c, ch]) => [k, { icon: `${c}${ch}${reset}`, color: c }]) + ) const branchWidth = Math.max(6, ...sessions.map((s) => s.branch.length)) const cols = process.stdout.columns || 80 const prefixWidth = branchWidth + 4