Replace Claude with Pi throughout codebase

This commit is contained in:
Chris Wanstrath 2026-04-11 23:56:48 -07:00
parent 9eded80a0e
commit e64564a045
9 changed files with 26 additions and 26 deletions

View File

@ -35,7 +35,7 @@ const program = new Command()
program program
.name("sandlot") .name("sandlot")
.description("Sandboxed development with Claude.") .description("Sandboxed development with Pi.")
.configureHelp({ styleTitle: (str) => `${yellow}${str}${reset}` }) .configureHelp({ styleTitle: (str) => `${yellow}${str}${reset}` })
.helpOption(false) .helpOption(false)
.addOption(new Option("-h, --help").hideHelp()) .addOption(new Option("-h, --help").hideHelp())
@ -59,19 +59,19 @@ program
program program
.command("new") .command("new")
.argument("[branch]", "branch name or prompt (if it contains spaces)") .argument("[branch]", "branch name or prompt (if it contains spaces)")
.argument("[prompt]", "initial prompt for Claude") .argument("[prompt]", "initial prompt for Pi")
.option("-p, --print <prompt>", "run Claude in non-interactive mode with -p") .option("-p, --print <prompt>", "run Pi in non-interactive mode with -p")
.option("-n, --no-save", "skip auto-save after Claude exits") .option("-n, --no-save", "skip auto-save after Pi exits")
.description("Create a new session and launch Claude") .description("Create a new session and launch Pi")
.action(newAction) .action(newAction)
program program
.command("open") .command("open")
.argument("<branch>", "branch name") .argument("<branch>", "branch name")
.argument("[prompt]", "initial prompt for Claude") .argument("[prompt]", "initial prompt for Pi")
.option("-p, --print <prompt>", "run Claude in non-interactive mode with -p") .option("-p, --print <prompt>", "run Pi in non-interactive mode with -p")
.option("-n, --no-save", "skip auto-save after Claude exits") .option("-n, --no-save", "skip auto-save after Pi exits")
.description("Open an existing Claude session") .description("Open an existing Pi session")
.action(openAction) .action(openAction)
program program

View File

@ -104,7 +104,7 @@ const SKIP_RESOLVE = new Set([
"yarn.lock", "yarn.lock",
]) ])
/** Resolve conflict markers in files using Claude, then stage them. */ /** Resolve conflict markers in files using Pi, then stage them. */
export async function resolveConflicts( export async function resolveConflicts(
files: string[], files: string[],
cwd: string, cwd: string,
@ -124,13 +124,13 @@ export async function resolveConflicts(
throw new Error(`Failed to read conflicted file: ${file}`) throw new Error(`Failed to read conflicted file: ${file}`)
}) })
const resolved = await vm.claudePipe( const resolved = await vm.piPipe(
content, content,
"resolve this merge conflict. output ONLY the resolved file content with no markdown fences, no explanation, no surrounding text.", "resolve this merge conflict. output ONLY the resolved file content with no markdown fences, no explanation, no surrounding text.",
) )
if (resolved.exitCode !== 0 || !resolved.stdout.trim()) { if (resolved.exitCode !== 0 || !resolved.stdout.trim()) {
throw new Error(`Claude failed to resolve ${file}: ${resolved.stderr.trim() || "(no output)"}`) throw new Error(`Pi failed to resolve ${file}: ${resolved.stderr.trim() || "(no output)"}`)
} }
await Bun.write(join(cwd, file), resolved.stdout.trimEnd() + "\n") await Bun.write(join(cwd, file), resolved.stdout.trimEnd() + "\n")
@ -162,7 +162,7 @@ export async function mergeAndClose(branch: string, opts?: { force?: boolean }):
return return
} }
// Resolve conflicts with Claude // Resolve conflicts with Pi
spin.text = `Resolving ${conflicts.length} conflict(s)` spin.text = `Resolving ${conflicts.length} conflict(s)`
try { try {
@ -210,7 +210,7 @@ export async function saveChanges(worktree: string, branch: string, message?: st
spin.text = "Generating commit message" spin.text = "Generating commit message"
const diff = await $`git -C ${worktree} diff --staged`.nothrow().quiet().text() const diff = await $`git -C ${worktree} diff --staged`.nothrow().quiet().text()
const gen = await vm.claudePipe( const gen = await vm.piPipe(
diff, diff,
"Write a commit message for this diff. Subject line: imperative mood, max 72 characters, no period. If the changes warrant it, add a blank line then a brief body explaining why, not what. Output only the raw commit message, no quotes or markdown.", "Write a commit message for this diff. Subject line: imperative mood, max 72 characters, no period. If the changes warrant it, add a blank line then a brief body explaining why, not what. Output only the raw commit message, no quotes or markdown.",
) )

View File

@ -44,7 +44,7 @@ async function resolveStatus(
): Promise<string> { ): Promise<string> {
try { await stat(s.worktree) } catch { return "idle" } try { await stat(s.worktree) } catch { return "idle" }
if (vmRunning) { if (vmRunning) {
const active = await vm.isClaudeActive(s.worktree, s.branch).catch(() => false) const active = await vm.isPiActive(s.worktree, s.branch).catch(() => false)
if (active && s.in_review) return "review" if (active && s.in_review) return "review"
if (active) return "active" if (active) return "active"
} }
@ -58,7 +58,7 @@ async function resolveStatus(
} }
} }
/** Clear in_review flags for sessions where Claude is no longer active. */ /** Clear in_review flags for sessions where Pi is no longer active. */
async function clearStaleReviews( async function clearStaleReviews(
sessions: state.GlobalSession[], sessions: state.GlobalSession[],
statusMap: Map<state.GlobalSession, string>, statusMap: Map<state.GlobalSession, string>,
@ -79,7 +79,7 @@ async function backfillPrompts(sessions: { worktree: string; prompt?: string }[]
if (!vmRunning) return if (!vmRunning) return
const needsPrompt = sessions.filter(s => !s.prompt) const needsPrompt = sessions.filter(s => !s.prompt)
if (needsPrompt.length === 0) return if (needsPrompt.length === 0) return
const result = await vm.exec(homedir() + "/.sandlot", "cat /home/ubuntu/.claude/history.jsonl 2>/dev/null").catch(() => null) const result = await vm.exec(homedir() + "/.sandlot", "cat /home/ubuntu/.pi/history.jsonl 2>/dev/null").catch(() => null)
if (!result || result.exitCode !== 0 || !result.stdout) return if (!result || result.exitCode !== 0 || !result.stdout) return
const byProject = new Map<string, string>() const byProject = new Map<string, string>()

View File

@ -126,7 +126,7 @@ export async function action(
if (opts.print) { if (opts.print) {
spin.text = "Running prompt…" spin.text = "Running prompt…"
const result = await vm.claude(worktreeAbs, { prompt, print: opts.print }) const result = await vm.pi(worktreeAbs, { prompt, print: opts.print })
if (result.output) { if (result.output) {
spin.stop() spin.stop()
process.stdout.write(renderMarkdown(result.output) + "\n") process.stdout.write(renderMarkdown(result.output) + "\n")
@ -134,7 +134,7 @@ export async function action(
spin.succeed("Done") spin.succeed("Done")
} }
} else { } else {
await vm.claude(worktreeAbs, { prompt, print: opts.print }) await vm.pi(worktreeAbs, { prompt, print: opts.print })
} }
await vm.clearActivity(worktreeAbs, branch) await vm.clearActivity(worktreeAbs, branch)

View File

@ -21,7 +21,7 @@ export async function action(
if (opts.print) { if (opts.print) {
spin.text = "Running prompt…" spin.text = "Running prompt…"
const result = await vm.claude(session.worktree, { prompt, print: opts.print, continue: true }) const result = await vm.pi(session.worktree, { prompt, print: opts.print, continue: true })
if (result.output) { if (result.output) {
spin.stop() spin.stop()
process.stdout.write(renderMarkdown(result.output) + "\n") process.stdout.write(renderMarkdown(result.output) + "\n")
@ -30,7 +30,7 @@ export async function action(
} }
} else { } else {
spin.succeed("Session ready") spin.succeed("Session ready")
await vm.claude(session.worktree, { prompt, print: opts.print, continue: true }) await vm.pi(session.worktree, { prompt, print: opts.print, continue: true })
} }
await vm.clearActivity(session.worktree, branch) await vm.clearActivity(session.worktree, branch)

View File

@ -34,7 +34,7 @@ export async function action(branch: string) {
} }
fetchSpin.stop() fetchSpin.stop()
console.log(`◆ Rebase conflicts in ${conflicts.length} file(s). Resolving with Claude...`) console.log(`◆ Rebase conflicts in ${conflicts.length} file(s). Resolving with Pi...`)
const resolveSpin = spinner("Starting container", branch) const resolveSpin = spinner("Starting container", branch)
try { try {

View File

@ -74,11 +74,11 @@ Your thoughts, in brief.
try { try {
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.pi(session.worktree, { print: prompt })
if (result.output) process.stdout.write(result.output + "\n") if (result.output) process.stdout.write(result.output + "\n")
} else { } else {
spin.succeed("Session ready") spin.succeed("Session ready")
await vm.claude(session.worktree, { prompt }) await vm.pi(session.worktree, { prompt })
} }
} finally { } finally {
spin.stop() spin.stop()

View File

@ -40,7 +40,7 @@ export async function action(branch: string) {
process.exit(1) process.exit(1)
} }
const gen = await vm.claudePipe( const gen = await vm.piPipe(
diff, diff,
"Write a commit message summarizing all changes. Subject line: imperative mood, max 72 characters, no period. Add a blank line then a concise body with the key changes as bullet points. Output only the raw commit message, no quotes or markdown.", "Write a commit message summarizing all changes. Subject line: imperative mood, max 72 characters, no period. Add a blank line then a concise body with the key changes as bullet points. Output only the raw commit message, no quotes or markdown.",
) )

View File

@ -70,7 +70,7 @@ export function register(program: Command) {
sessions.map(async (sess): Promise<[string, string]> => { sessions.map(async (sess): Promise<[string, string]> => {
const key = `${basename(sess.repoRoot)}/${sess.branch}` const key = `${basename(sess.repoRoot)}/${sess.branch}`
try { try {
if (await vm.isClaudeActive(sess.worktree, sess.branch)) return [key, "active"] if (await vm.isPiActive(sess.worktree, sess.branch)) return [key, "active"]
if (await git.isDirty(sess.worktree)) return [key, "dirty"] if (await git.isDirty(sess.worktree)) return [key, "dirty"]
if (await git.hasNewCommits(sess.worktree)) return [key, "saved"] if (await git.hasNewCommits(sess.worktree)) return [key, "saved"]
} catch {} } catch {}