Derive repo name from repoRoot instead of storing it separately
Remove the redundant `repo` field from GlobalSession and compute it via basename(repoRoot) at render time. Also fix prompt truncation when terminal is extremely narrow, and simplify backfillPrompts to avoid an intermediate array allocation.
This commit is contained in:
parent
99b0fc0f12
commit
d402a3f980
|
|
@ -31,7 +31,7 @@ function renderSessions(
|
|||
const status = statusMap.get(s) ?? "idle"
|
||||
const { icon, color: bc } = styles[status]
|
||||
const maxPrompt = cols - prefixWidth
|
||||
const truncated = prompt.length <= maxPrompt ? prompt : prompt.slice(0, maxPrompt - 3) + "..."
|
||||
const truncated = maxPrompt <= 3 ? "" : prompt.length <= maxPrompt ? prompt : prompt.slice(0, maxPrompt - 3) + "..."
|
||||
console.log(`${icon} ${bc}${s.branch.padEnd(branchWidth)}${reset} ${dim}${truncated}${reset}`)
|
||||
}
|
||||
}
|
||||
|
|
@ -61,9 +61,9 @@ async function resolveStatus(
|
|||
/** Clear in_review flags for sessions where Claude is no longer active. */
|
||||
async function clearStaleReviews(
|
||||
sessions: state.GlobalSession[],
|
||||
results: string[],
|
||||
statusMap: Map<state.GlobalSession, string>,
|
||||
) {
|
||||
const stale = sessions.filter((s, i) => s.in_review && results[i] !== "review")
|
||||
const stale = sessions.filter(s => s.in_review && statusMap.get(s) !== "review")
|
||||
if (stale.length === 0) return
|
||||
const byRepo = Map.groupBy(stale, s => s.repoRoot)
|
||||
for (const [repoRoot, staleSessions] of byRepo) {
|
||||
|
|
@ -82,13 +82,13 @@ async function backfillPrompts(sessions: { worktree: string; prompt?: string }[]
|
|||
const result = await vm.exec(homedir() + "/.sandlot", "cat /home/ubuntu/.claude/history.jsonl 2>/dev/null").catch(() => null)
|
||||
if (!result || result.exitCode !== 0 || !result.stdout) return
|
||||
|
||||
const entries = result.stdout.split("\n").filter(Boolean).map(line => {
|
||||
try { return JSON.parse(line) } catch { return null }
|
||||
}).filter(Boolean)
|
||||
|
||||
const byProject = new Map<string, string>()
|
||||
for (const e of entries) {
|
||||
for (const line of result.stdout.split("\n")) {
|
||||
if (!line) continue
|
||||
try {
|
||||
const e = JSON.parse(line)
|
||||
if (e.project && e.display) byProject.set(e.project, e.display)
|
||||
} catch {}
|
||||
}
|
||||
|
||||
for (const s of needsPrompt) {
|
||||
|
|
@ -106,7 +106,7 @@ export async function action(opts: { json?: boolean; all?: boolean }) {
|
|||
} else {
|
||||
const root = await git.repoRoot()
|
||||
const st = await state.load(root)
|
||||
sessions = Object.values(st.sessions).map(s => ({ ...s, repo: basename(root), repoRoot: root }))
|
||||
sessions = Object.values(st.sessions).map(s => ({ ...s, repoRoot: root }))
|
||||
}
|
||||
|
||||
const vmRunning = (await vm.status()) === "running"
|
||||
|
|
@ -120,7 +120,7 @@ export async function action(opts: { json?: boolean; all?: boolean }) {
|
|||
|
||||
const results = await Promise.all(sessions.map(s => resolveStatus(s, vmRunning)))
|
||||
const statusMap = new Map(sessions.map((s, i) => [s, results[i]]))
|
||||
await clearStaleReviews(sessions, results)
|
||||
await clearStaleReviews(sessions, statusMap)
|
||||
|
||||
if (opts.json) {
|
||||
const withStatus = sessions.map(s => ({ ...s, status: statusMap.get(s) ?? "idle" }))
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { basename } from "path"
|
||||
import type { Command } from "commander"
|
||||
import * as vm from "../vm.ts"
|
||||
import * as git from "../git.ts"
|
||||
|
|
@ -67,7 +68,7 @@ export function register(program: Command) {
|
|||
// Determine status for each session in parallel
|
||||
const statusEntries = await Promise.all(
|
||||
sessions.map(async (sess): Promise<[string, string]> => {
|
||||
const key = `${sess.repo}/${sess.branch}`
|
||||
const key = `${basename(sess.repoRoot)}/${sess.branch}`
|
||||
try {
|
||||
if (await vm.isClaudeActive(sess.worktree, sess.branch)) return [key, "active"]
|
||||
if (await git.isDirty(sess.worktree)) return [key, "dirty"]
|
||||
|
|
@ -81,7 +82,7 @@ export function register(program: Command) {
|
|||
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 repoWidth = Math.max(4, ...sessions.map(sess => sess.repo.length))
|
||||
const repoWidth = Math.max(4, ...sessions.map(sess => basename(sess.repoRoot).length))
|
||||
const branchWidth = Math.max(6, ...sessions.map(sess => sess.branch.length))
|
||||
const cols = process.stdout.columns || 80
|
||||
const prefixWidth = repoWidth + branchWidth + 6
|
||||
|
|
@ -90,13 +91,13 @@ export function register(program: Command) {
|
|||
|
||||
for (const sess of sessions) {
|
||||
const prompt = (sess.prompt ?? "").split("\n")[0]
|
||||
const key = `${sess.repo}/${sess.branch}`
|
||||
const key = `${basename(sess.repoRoot)}/${sess.branch}`
|
||||
const status = statuses[key]
|
||||
const icon = icons[status]
|
||||
const bc = branchColors[status]
|
||||
const maxPrompt = cols - prefixWidth
|
||||
const truncated = maxPrompt > 3 && prompt.length > maxPrompt ? prompt.slice(0, maxPrompt - 3) + "..." : prompt
|
||||
console.log(`${icon} ${dim}${sess.repo.padEnd(repoWidth)}${reset} ${bc}${sess.branch.padEnd(branchWidth)}${reset} ${dim}${truncated}${reset}`)
|
||||
console.log(`${icon} ${dim}${basename(sess.repoRoot).padEnd(repoWidth)}${reset} ${bc}${sess.branch.padEnd(branchWidth)}${reset} ${dim}${truncated}${reset}`)
|
||||
}
|
||||
|
||||
console.log(`\n${dim}◯ idle${reset} · ${cyan}◎ active${reset} · ${yellow}◐ unsaved${reset} · ${green}● saved${reset}`)
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ export async function removeSession(repoRoot: string, branch: string): Promise<v
|
|||
}
|
||||
|
||||
export interface GlobalSession extends Session {
|
||||
repo: string
|
||||
repoRoot: string
|
||||
}
|
||||
|
||||
|
|
@ -94,7 +93,7 @@ export async function loadAll(): Promise<GlobalSession[]> {
|
|||
try {
|
||||
const st = await load(repoRoot)
|
||||
for (const session of Object.values(st.sessions)) {
|
||||
all.push({ ...session, repo: entry.name, repoRoot })
|
||||
all.push({ ...session, repoRoot })
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user