Track Claude activity state via hook-based marker files
This commit is contained in:
parent
0d059b8940
commit
86fd1e6c25
|
|
@ -233,10 +233,9 @@ program
|
|||
}
|
||||
|
||||
// Determine status for each session in parallel
|
||||
const activeWorktrees = await vm.activeWorktrees()
|
||||
const statusEntries = await Promise.all(
|
||||
sessions.map(async (s): Promise<[string, string]> => {
|
||||
if (activeWorktrees.includes(s.worktree)) return [s.branch, "active"]
|
||||
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"]
|
||||
const commits = await git.hasNewCommits(s.worktree)
|
||||
|
|
@ -362,6 +361,8 @@ const closeAction = async (branch: string) => {
|
|||
const session = await state.getSession(root, branch)
|
||||
const worktreeAbs = session?.worktree ?? join(homedir(), '.sandlot', basename(root), branch)
|
||||
|
||||
await vm.clearActivity(worktreeAbs, branch)
|
||||
|
||||
await git.removeWorktree(worktreeAbs, root)
|
||||
.catch((e) => console.warn(`⚠ Failed to remove worktree: ${e.message}`))
|
||||
|
||||
|
|
|
|||
39
src/vm.ts
39
src/vm.ts
|
|
@ -1,5 +1,6 @@
|
|||
import { $ } from "bun"
|
||||
import { homedir } from "os"
|
||||
import { dirname } from "path"
|
||||
|
||||
const CONTAINER_NAME = "sandlot"
|
||||
const USER = "ubuntu"
|
||||
|
|
@ -73,9 +74,13 @@ export async function ensure(log?: (msg: string) => void): Promise<void> {
|
|||
log?.("Warning: ANTHROPIC_API_KEY not found in ~/.env — claude will require manual login")
|
||||
}
|
||||
|
||||
const hooks = {
|
||||
UserPromptSubmit: [{ hooks: [{ type: "command", command: "sandlot-activity active" }] }],
|
||||
Stop: [{ hooks: [{ type: "command", command: "sandlot-activity idle" }] }],
|
||||
}
|
||||
const settingsJson = JSON.stringify(apiKey
|
||||
? { apiKeyHelper: "~/.claude/api-key-helper.sh", skipDangerousModePermissionPrompt: true }
|
||||
: { skipDangerousModePermissionPrompt: true })
|
||||
? { apiKeyHelper: "~/.claude/api-key-helper.sh", skipDangerousModePermissionPrompt: true, hooks }
|
||||
: { skipDangerousModePermissionPrompt: true, hooks })
|
||||
const claudeJson = JSON.stringify({ hasCompletedOnboarding: true, effortCalloutDismissed: true })
|
||||
|
||||
// Write the helper script to a temp file and copy it in so the key
|
||||
|
|
@ -88,6 +93,19 @@ export async function ensure(log?: (msg: string) => void): Promise<void> {
|
|||
await Bun.file(tmp).unlink()
|
||||
}
|
||||
|
||||
// Install activity tracking hook script
|
||||
const activityTmp = `${home}/.sandlot/.sandlot-activity.tmp`
|
||||
await Bun.write(activityTmp, [
|
||||
'#!/bin/bash',
|
||||
'DIR=$(dirname "$CLAUDE_PROJECT_DIR")',
|
||||
'BRANCH=$(basename "$CLAUDE_PROJECT_DIR")',
|
||||
'echo "$1" > "$DIR/.activity-$BRANCH"',
|
||||
'',
|
||||
].join('\n'))
|
||||
await $`chmod +x ${activityTmp}`.quiet()
|
||||
await $`container exec --user ${USER} ${CONTAINER_NAME} bash -c ${"cp /sandlot/.sandlot-activity.tmp ~/.local/bin/sandlot-activity"}`.quiet()
|
||||
await Bun.file(activityTmp).unlink()
|
||||
|
||||
await $`container exec --user ${USER} ${CONTAINER_NAME} bash -c ${`
|
||||
mkdir -p ~/.claude
|
||||
echo '${settingsJson}' > ~/.claude/settings.json
|
||||
|
|
@ -178,6 +196,23 @@ export async function activeWorktrees(): Promise<string[]> {
|
|||
})
|
||||
}
|
||||
|
||||
/** Check if Claude is actively working in the given worktree (based on activity hook). */
|
||||
export async function isClaudeActive(worktree: string, branch: string): Promise<boolean> {
|
||||
const file = `${dirname(worktree)}/.activity-${branch}`
|
||||
try {
|
||||
const content = await Bun.file(file).text()
|
||||
return content.trim() === "active"
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/** Remove the activity marker file for a worktree. */
|
||||
export async function clearActivity(worktree: string, branch: string): Promise<void> {
|
||||
const file = `${dirname(worktree)}/.activity-${branch}`
|
||||
await Bun.file(file).unlink().catch(() => {})
|
||||
}
|
||||
|
||||
/** Stop the container. */
|
||||
export async function stop(): Promise<void> {
|
||||
await $`container stop ${CONTAINER_NAME}`.nothrow().quiet()
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user