mission-control/src/app/api/local/terminal/route.ts

48 lines
1.6 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server'
import { existsSync, statSync } from 'node:fs'
import { resolve } from 'node:path'
import { requireRole } from '@/lib/auth'
import { runCommand } from '@/lib/command'
function isAllowedDirectory(input: string): boolean {
const cwd = resolve(input)
if (!cwd.startsWith('/')) return false
if (!(cwd.startsWith('/Users/') || cwd.startsWith('/tmp/') || cwd.startsWith('/var/folders/'))) {
return false
}
if (!existsSync(cwd)) return false
try {
return statSync(cwd).isDirectory()
} catch {
return false
}
}
/**
* POST /api/local/terminal
* Body: { cwd: string }
* Opens a new local Terminal window at the given working directory.
*/
export async function POST(request: NextRequest) {
const auth = requireRole(request, 'operator')
if ('error' in auth) return NextResponse.json({ error: auth.error }, { status: auth.status })
const body = await request.json().catch(() => ({}))
const cwd = typeof body?.cwd === 'string' ? body.cwd.trim() : ''
if (!cwd) {
return NextResponse.json({ error: 'cwd is required' }, { status: 400 })
}
if (!isAllowedDirectory(cwd)) {
return NextResponse.json({ error: 'cwd must be an existing safe local directory' }, { status: 400 })
}
try {
await runCommand('open', ['-a', 'Terminal', cwd], { timeoutMs: 10_000 })
return NextResponse.json({ ok: true, message: `Opened Terminal at ${cwd}` })
} catch (error: any) {
return NextResponse.json({ error: error?.message || 'Failed to open Terminal' }, { status: 500 })
}
}
export const dynamic = 'force-dynamic'