← back to Letsbegin
app/api/processes/stop/route.ts
72 lines
import { NextRequest, NextResponse } from 'next/server'
import { execSync } from 'child_process'
import * as fs from 'fs'
import * as path from 'path'
const STATE_FILE = '/tmp/ralph-state.json'
export async function POST(request: NextRequest) {
try {
const { projectPath, project, pid } = await request.json()
if (!projectPath || !project) {
return NextResponse.json({ error: 'Missing projectPath or project' }, { status: 400 })
}
// Kill the process if PID provided
if (pid && pid > 0) {
try {
// Try to kill the process group first
process.kill(-pid, 'SIGTERM')
} catch (e) {
try {
// Fallback to killing just the process
process.kill(pid, 'SIGTERM')
} catch {}
}
}
// Kill any claude processes running for this project
try {
execSync(`pkill -f "claude.*${project}" || true`, { stdio: 'pipe' })
} catch {}
// Kill any ralph-runner processes
try {
execSync(`pkill -f "ralph-runner.*${project}" || true`, { stdio: 'pipe' })
} catch {}
// Update state file
if (fs.existsSync(STATE_FILE)) {
try {
const state = JSON.parse(fs.readFileSync(STATE_FILE, 'utf-8'))
if (state.project === project || state.projectPath === projectPath) {
state.running = false
state.logs = state.logs || []
state.logs.push(`> Stopped by user at ${new Date().toLocaleTimeString()}`)
fs.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2))
}
} catch {}
}
// Update progress.txt to mark as stopped
const progressFile = path.join(projectPath, 'scripts', 'ralph', 'progress.txt')
if (fs.existsSync(progressFile)) {
let content = fs.readFileSync(progressFile, 'utf-8')
// Replace any RUNNING status with STOPPED
content = content.replace(/: RUNNING/g, ': STOPPED')
content += `\n\nStopped by user at ${new Date().toISOString()}`
fs.writeFileSync(progressFile, content)
}
return NextResponse.json({
success: true,
message: `Stopped Ralph for ${project}`
})
} catch (error: any) {
console.error('Stop process error:', error)
return NextResponse.json({ error: error.message }, { status: 500 })
}
}