← back to Letsbegin
app/api/ralph/stop/route.ts
84 lines
import { NextResponse } from 'next/server'
import * as fs from 'fs'
const STATE_FILE = '/tmp/ralph-state.json'
interface RalphState {
running: boolean
pid?: number
logs: string[]
[key: string]: any
}
function getState(): RalphState {
if (fs.existsSync(STATE_FILE)) {
return JSON.parse(fs.readFileSync(STATE_FILE, 'utf-8'))
}
return { running: false, logs: [] }
}
function saveState(state: RalphState) {
fs.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2))
}
export async function POST() {
try {
const state = getState()
const { execSync } = require('child_process')
const killed: string[] = []
// Kill stored PID if exists
if (state.pid) {
try {
process.kill(-state.pid, 'SIGKILL')
killed.push(`pid ${state.pid}`)
} catch {
try {
process.kill(state.pid, 'SIGKILL')
killed.push(`pid ${state.pid}`)
} catch {}
}
}
// Kill ralph-runner script
try {
execSync('pkill -9 -f "ralph-runner" || true', { stdio: 'pipe' })
killed.push('ralph-runner')
} catch {}
// Kill any claude processes run by ralph user with dangerously-skip-permissions
try {
execSync('pkill -9 -f "claude.*dangerously-skip-permissions" || true', { stdio: 'pipe' })
killed.push('claude processes')
} catch {}
// Kill any bash processes running ralph scripts
try {
execSync('pkill -9 -f "ralph-story" || true', { stdio: 'pipe' })
killed.push('ralph-story')
} catch {}
// Kill sudo processes running ralph
try {
execSync('pkill -9 -f "sudo.*ralph" || true', { stdio: 'pipe' })
killed.push('sudo ralph')
} catch {}
// Update state
state.running = false
state.paused = false
state.pid = undefined
state.logs.push(`> STOPPED by user (killed: ${killed.join(', ')})`)
saveState(state)
return NextResponse.json({
success: true,
message: `Ralph stopped. Killed: ${killed.join(', ')}`
})
} catch (error: any) {
console.error('Ralph stop error:', error)
return NextResponse.json({ error: error.message }, { status: 500 })
}
}