Move ListSession interface to module scope and harden error paths

Simplify stale-lock recovery to just retry the loop instead of
nesting a second mkdir, and surface lock failures in actionRemove
rather than letting them propagate as unhandled exceptions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Chris Wanstrath 2026-03-19 14:57:38 -07:00
parent ac168d3019
commit 3d07643547
2 changed files with 15 additions and 14 deletions

View File

@ -6,6 +6,11 @@ import * as vm from "../vm.ts"
import * as state from "../state.ts"
import { die, reset, dim, green, yellow, cyan, magenta, red } from "../fmt.ts"
interface ListSession extends state.Session {
repoRoot: string
repo?: string
}
// ── Shared rendering ─────────────────────────────────────────────────
const styleDefs: [string, string, string][] = [
@ -17,9 +22,9 @@ const styles = Object.fromEntries(
)
function renderSessions(
sessions: { branch: string; prompt?: string }[],
sessions: ListSession[],
statuses: Record<string, string>,
keyFn: (s: { branch: string }) => string,
keyFn: (s: ListSession) => string,
) {
const branchWidth = Math.max(6, ...sessions.map(s => s.branch.length))
const cols = process.stdout.columns || 80
@ -49,7 +54,7 @@ async function resolveStatus(
): Promise<string> {
try { await stat(s.worktree) } catch { return "idle" }
if (vmRunning) {
const active = await vm.isClaudeActive(s.worktree, s.branch)
const active = await vm.isClaudeActive(s.worktree, s.branch).catch(() => false)
if (active && s.in_review) return "review"
if (active) return "active"
}
@ -120,11 +125,6 @@ async function backfillPrompts(sessions: { worktree: string; prompt?: string }[]
// ── Commands ─────────────────────────────────────────────────────────
interface ListSession extends state.Session {
repoRoot: string
repo?: string
}
export async function action(opts: { json?: boolean; all?: boolean; add?: string; remove?: string }) {
if (opts.add) return actionAdd(opts.add)
if (opts.remove) return actionRemove(opts.remove)
@ -185,7 +185,12 @@ async function actionAdd(dir: string) {
}
async function actionRemove(dir: string) {
const removed = await state.unregisterProject(dir)
let removed: boolean
try {
removed = await state.unregisterProject(dir)
} catch {
die("Could not acquire registry lock")
}
if (removed) {
console.log(`${red}-${reset} ${dir}`)
} else {

View File

@ -76,11 +76,7 @@ async function withGlobalLock<T>(fn: () => Promise<T>): Promise<T> {
const info = await stat(lockPath)
if (Date.now() - info.mtimeMs > 300_000) {
await rmdir(lockPath).catch(() => {})
// Retry mkdir immediately instead of continuing the loop
try {
await mkdir(lockPath)
break
} catch {}
continue
}
} catch {}
if (i === 19) throw new Error("Could not acquire registry lock")