Add review status tracking to sessions

The list command needs to show when a session is under active
review so users don't interrupt it. Wrapping the review body in
try/finally ensures the flag is always cleared on exit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Chris Wanstrath 2026-03-18 23:08:41 -07:00
parent 8172065928
commit 92dbad3cad
4 changed files with 30 additions and 15 deletions

View File

@ -2,7 +2,7 @@ import { homedir } from "os"
import * as git from "../git.ts"
import * as vm from "../vm.ts"
import * as state from "../state.ts"
import { reset, dim, bold, green, yellow, cyan, white, red } from "../fmt.ts"
import { reset, dim, bold, green, yellow, cyan, magenta, white, red } from "../fmt.ts"
export async function action(opts: { json?: boolean }) {
const root = await git.repoRoot()
@ -46,6 +46,7 @@ export async function action(opts: { json?: boolean }) {
// Determine status for each session in parallel
const statusEntries = await Promise.all(
sessions.map(async (s): Promise<[string, string]> => {
if (s.in_review) return [s.branch, "review"]
if (await vm.isClaudeActive(s.worktree, s.branch)) return [s.branch, "active"]
const dirty = await git.isDirty(s.worktree)
if (dirty) return [s.branch, "dirty"]
@ -61,8 +62,8 @@ export async function action(opts: { json?: boolean }) {
return
}
const icons: Record<string, string> = { idle: `${dim}${reset}`, active: `${cyan}${reset}`, dirty: `${yellow}${reset}`, saved: `${green}${reset}` }
const branchColors: Record<string, string> = { idle: dim, active: cyan, dirty: yellow, saved: green }
const icons: Record<string, string> = { idle: `${dim}${reset}`, active: `${cyan}${reset}`, dirty: `${yellow}${reset}`, saved: `${green}${reset}`, review: `${magenta}⦿${reset}` }
const branchColors: Record<string, string> = { idle: dim, active: cyan, dirty: yellow, saved: green, review: magenta }
const branchWidth = Math.max(6, ...sessions.map((s) => s.branch.length))
const cols = process.stdout.columns || 80
const prefixWidth = branchWidth + 4
@ -79,7 +80,7 @@ export async function action(opts: { json?: boolean }) {
console.log(`${icon} ${bc}${s.branch.padEnd(branchWidth)}${reset} ${dim}${truncated}${reset}`)
}
console.log(`\n${dim}◯ idle${reset} · ${cyan}◎ active${reset} · ${yellow}◐ unsaved${reset} · ${green}● saved${reset}`)
console.log(`\n${dim}◯ idle${reset} · ${cyan}◎ active${reset} · ${yellow}◐ unsaved${reset} · ${green}● saved${reset} · ${magenta}⦿ review${reset}`)
if ((await vm.status()) !== "running") {
console.log(`\n${red}VM is not running.${reset}`)

View File

@ -1,9 +1,15 @@
import * as git from "../git.ts"
import * as vm from "../vm.ts"
import * as state from "../state.ts"
import { spinner } from "../spinner.ts"
import { requireSession, saveChanges } from "./helpers.ts"
export async function action(branch: string, extra: string | undefined, opts: { print?: boolean }) {
const { session } = await requireSession(branch)
const { root, session } = await requireSession(branch)
// Mark session as in review
session.in_review = true
await state.setSession(root, session)
const spin = spinner("Starting container", branch)
await vm.ensure((msg) => { spin.text = msg })
@ -67,15 +73,21 @@ Your thoughts, in brief.
`
if (extra) prompt += "\n\n" + extra
if (opts.print) {
spin.text = "Running review…"
const result = await vm.claude(session.worktree, { print: prompt })
spin.stop()
if (result.output) process.stdout.write(result.output + "\n")
} else {
spin.succeed("Session ready")
await vm.claude(session.worktree, { prompt })
}
try {
if (opts.print) {
spin.text = "Running review…"
const result = await vm.claude(session.worktree, { print: prompt })
spin.stop()
if (result.output) process.stdout.write(result.output + "\n")
} else {
spin.succeed("Session ready")
await vm.claude(session.worktree, { prompt })
}
await saveChanges(session.worktree, session.branch)
await saveChanges(session.worktree, session.branch)
} finally {
// Clear review state
session.in_review = false
await state.setSession(root, session)
}
}

View File

@ -5,6 +5,7 @@ export const dim = "\x1b[2m"
export const green = "\x1b[32m"
export const yellow = "\x1b[33m"
export const red = "\x1b[31m"
export const magenta = "\x1b[35m"
export const cyan = "\x1b[36m"
// ── Formatted output ────────────────────────────────────────────────

View File

@ -7,6 +7,7 @@ export interface Session {
worktree: string
created_at: string
prompt?: string
in_review?: boolean
}
export interface State {