Fix stale in_review flag handling and review lifecycle
Move in_review flag set inside try block so finally always clears it, and actively clear stale flags in list when Claude is no longer active. Previously a crash between setting the flag and entering try would leave the session stuck in review state. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
bc102e416c
commit
3ba550d80a
|
|
@ -151,7 +151,7 @@ Always use `.nothrow()` for commands that may fail non-fatally. Use `.quiet()` t
|
||||||
- `sandlot merge` and `sandlot squash` both delegate to `mergeAndClose()` in `helpers.ts`, which merges, resolves conflicts, commits, and then calls `closeAction()` to clean up
|
- `sandlot merge` and `sandlot squash` both delegate to `mergeAndClose()` in `helpers.ts`, which merges, resolves conflicts, commits, and then calls `closeAction()` to clean up
|
||||||
- `sandlot list` discovers missing session prompts by parsing Claude's `history.jsonl` from inside the container
|
- `sandlot list` discovers missing session prompts by parsing Claude's `history.jsonl` from inside the container
|
||||||
- `sandlot list` shows five status icons: idle (dim `◯`), active (cyan `◎`), dirty/unsaved (yellow `◐`), saved (green `●`), review (magenta `⦿`)
|
- `sandlot list` shows five status icons: idle (dim `◯`), active (cyan `◎`), dirty/unsaved (yellow `◐`), saved (green `●`), review (magenta `⦿`)
|
||||||
- `sandlot review` sets `in_review` on the session during the review and clears it in a `finally` block on exit; `list` only shows review status if Claude is also active (self-heals stale flags)
|
- `sandlot review` sets `in_review` on the session during the review and clears it in a `finally` block on exit; `list` detects stale `in_review` flags (Claude not active) and clears them from state
|
||||||
- `sandlot new` and `sandlot open` auto-save changes when Claude exits (disable with `--no-save`)
|
- `sandlot new` and `sandlot open` auto-save changes when Claude exits (disable with `--no-save`)
|
||||||
- `sandlot close` has a hidden `rm` alias
|
- `sandlot close` has a hidden `rm` alias
|
||||||
- Default behavior (no subcommand): always runs `list` (which prints "No active sessions." if empty)
|
- Default behavior (no subcommand): always runs `list` (which prints "No active sessions." if empty)
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,11 @@ export async function action(opts: { json?: boolean }) {
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opts.json) {
|
|
||||||
console.log(JSON.stringify(sessions, null, 2))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sessions.length === 0) {
|
if (sessions.length === 0) {
|
||||||
|
if (opts.json) {
|
||||||
|
console.log("[]")
|
||||||
|
return
|
||||||
|
}
|
||||||
console.log("◆ No active sessions.")
|
console.log("◆ No active sessions.")
|
||||||
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}`)
|
||||||
|
|
@ -48,6 +47,11 @@ export async function action(opts: { json?: boolean }) {
|
||||||
sessions.map(async (s): Promise<[string, string]> => {
|
sessions.map(async (s): Promise<[string, string]> => {
|
||||||
const active = await vm.isClaudeActive(s.worktree, s.branch)
|
const active = await vm.isClaudeActive(s.worktree, s.branch)
|
||||||
if (active && s.in_review) return [s.branch, "review"]
|
if (active && s.in_review) return [s.branch, "review"]
|
||||||
|
// Self-heal: clear stale in_review flag if Claude is not active
|
||||||
|
if (!active && s.in_review) {
|
||||||
|
s.in_review = false
|
||||||
|
await state.setSession(root, s).catch(() => {})
|
||||||
|
}
|
||||||
if (active) return [s.branch, "active"]
|
if (active) 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"]
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,6 @@ export async function action(branch: string, extra: string | undefined, opts: {
|
||||||
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 })
|
||||||
|
|
||||||
// Mark session as in review only after container is confirmed running
|
|
||||||
session.in_review = true
|
|
||||||
await state.setSession(root, session)
|
|
||||||
|
|
||||||
let prompt = `
|
let prompt = `
|
||||||
You're a grumpy old senior software engineer. You need to review some code my co-worker wrote.
|
You're a grumpy old senior software engineer. You need to review some code my co-worker wrote.
|
||||||
|
|
||||||
|
|
@ -73,6 +69,10 @@ Your thoughts, in brief.
|
||||||
if (extra) prompt += "\n\n" + extra
|
if (extra) prompt += "\n\n" + extra
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Mark session as in review inside try so finally always clears it
|
||||||
|
session.in_review = true
|
||||||
|
await state.setSession(root, session)
|
||||||
|
|
||||||
if (opts.print) {
|
if (opts.print) {
|
||||||
spin.text = "Running review…"
|
spin.text = "Running review…"
|
||||||
const result = await vm.claude(session.worktree, { print: prompt })
|
const result = await vm.claude(session.worktree, { print: prompt })
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user