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:
parent
8172065928
commit
92dbad3cad
|
|
@ -2,7 +2,7 @@ import { homedir } from "os"
|
||||||
import * as git from "../git.ts"
|
import * as git from "../git.ts"
|
||||||
import * as vm from "../vm.ts"
|
import * as vm from "../vm.ts"
|
||||||
import * as state from "../state.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 }) {
|
export async function action(opts: { json?: boolean }) {
|
||||||
const root = await git.repoRoot()
|
const root = await git.repoRoot()
|
||||||
|
|
@ -46,6 +46,7 @@ export async function action(opts: { json?: boolean }) {
|
||||||
// Determine status for each session in parallel
|
// Determine status for each session in parallel
|
||||||
const statusEntries = await Promise.all(
|
const statusEntries = await Promise.all(
|
||||||
sessions.map(async (s): Promise<[string, string]> => {
|
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"]
|
if (await vm.isClaudeActive(s.worktree, s.branch)) return [s.branch, "active"]
|
||||||
const dirty = await git.isDirty(s.worktree)
|
const dirty = await git.isDirty(s.worktree)
|
||||||
if (dirty) return [s.branch, "dirty"]
|
if (dirty) return [s.branch, "dirty"]
|
||||||
|
|
@ -61,8 +62,8 @@ export async function action(opts: { json?: boolean }) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const icons: Record<string, string> = { idle: `${dim}◯${reset}`, active: `${cyan}◎${reset}`, dirty: `${yellow}◐${reset}`, saved: `${green}●${reset}` }
|
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 }
|
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 branchWidth = Math.max(6, ...sessions.map((s) => s.branch.length))
|
||||||
const cols = process.stdout.columns || 80
|
const cols = process.stdout.columns || 80
|
||||||
const prefixWidth = branchWidth + 4
|
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(`${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") {
|
if ((await vm.status()) !== "running") {
|
||||||
console.log(`\n${red}VM is not running.${reset}`)
|
console.log(`\n${red}VM is not running.${reset}`)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,15 @@
|
||||||
|
import * as git from "../git.ts"
|
||||||
import * as vm from "../vm.ts"
|
import * as vm from "../vm.ts"
|
||||||
|
import * as state from "../state.ts"
|
||||||
import { spinner } from "../spinner.ts"
|
import { spinner } from "../spinner.ts"
|
||||||
import { requireSession, saveChanges } from "./helpers.ts"
|
import { requireSession, saveChanges } from "./helpers.ts"
|
||||||
|
|
||||||
export async function action(branch: string, extra: string | undefined, opts: { print?: boolean }) {
|
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)
|
const spin = spinner("Starting container", branch)
|
||||||
await vm.ensure((msg) => { spin.text = msg })
|
await vm.ensure((msg) => { spin.text = msg })
|
||||||
|
|
@ -67,15 +73,21 @@ Your thoughts, in brief.
|
||||||
`
|
`
|
||||||
if (extra) prompt += "\n\n" + extra
|
if (extra) prompt += "\n\n" + extra
|
||||||
|
|
||||||
if (opts.print) {
|
try {
|
||||||
spin.text = "Running review…"
|
if (opts.print) {
|
||||||
const result = await vm.claude(session.worktree, { print: prompt })
|
spin.text = "Running review…"
|
||||||
spin.stop()
|
const result = await vm.claude(session.worktree, { print: prompt })
|
||||||
if (result.output) process.stdout.write(result.output + "\n")
|
spin.stop()
|
||||||
} else {
|
if (result.output) process.stdout.write(result.output + "\n")
|
||||||
spin.succeed("Session ready")
|
} else {
|
||||||
await vm.claude(session.worktree, { prompt })
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ export const dim = "\x1b[2m"
|
||||||
export const green = "\x1b[32m"
|
export const green = "\x1b[32m"
|
||||||
export const yellow = "\x1b[33m"
|
export const yellow = "\x1b[33m"
|
||||||
export const red = "\x1b[31m"
|
export const red = "\x1b[31m"
|
||||||
|
export const magenta = "\x1b[35m"
|
||||||
export const cyan = "\x1b[36m"
|
export const cyan = "\x1b[36m"
|
||||||
|
|
||||||
// ── Formatted output ────────────────────────────────────────────────
|
// ── Formatted output ────────────────────────────────────────────────
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ export interface Session {
|
||||||
worktree: string
|
worktree: string
|
||||||
created_at: string
|
created_at: string
|
||||||
prompt?: string
|
prompt?: string
|
||||||
|
in_review?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface State {
|
export interface State {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user