Initial commit
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import { tool } from '@opencode-ai/plugin';
|
||||
|
||||
export default tool({
|
||||
description:
|
||||
"Start, stop, or health-check the Next.js dev server for the generated clone project. Use action='health' to check if a server is already responding at url; action='start' to spawn `bun run dev` in project_dir; action='stop' to kill the pid from a prior start.",
|
||||
args: {
|
||||
action: tool.schema.enum(['health', 'start', 'stop']).describe('Which lifecycle action to perform'),
|
||||
project_dir: tool.schema.string().nullable().describe('Path to the generated Next.js project (required for start)'),
|
||||
url: tool.schema.string().nullable().describe('Base URL to health-check. Default http://localhost:3000'),
|
||||
port: tool.schema.number().nullable().describe('Port for `bun run dev` when starting. Default 3000.'),
|
||||
pid: tool.schema.number().nullable().describe('Pid to kill when action=stop'),
|
||||
},
|
||||
async execute(args, context) {
|
||||
const { spawn } = await import('node:child_process');
|
||||
const { resolve } = await import('node:path');
|
||||
const url = args.url ?? 'http://localhost:3000';
|
||||
|
||||
if (args.action === 'health') {
|
||||
try {
|
||||
const res = await fetch(url, { method: 'HEAD' });
|
||||
return JSON.stringify({ healthy: res.ok || res.status === 404, status: res.status, url });
|
||||
} catch {
|
||||
return JSON.stringify({ healthy: false, status: 0, url });
|
||||
}
|
||||
}
|
||||
|
||||
if (args.action === 'start') {
|
||||
if (!args.project_dir) throw new Error('project_dir is required for action=start');
|
||||
const cwd = resolve(context.worktree, args.project_dir);
|
||||
const port = args.port ?? 3000;
|
||||
const child = spawn('bun', ['run', 'dev', '--port', String(port)], {
|
||||
cwd,
|
||||
detached: true,
|
||||
stdio: 'ignore',
|
||||
});
|
||||
child.unref();
|
||||
|
||||
const deadline = Date.now() + 30_000;
|
||||
while (Date.now() < deadline) {
|
||||
try {
|
||||
const res = await fetch(url, { method: 'HEAD' });
|
||||
if (res.ok || res.status === 404) {
|
||||
return JSON.stringify({ status: 'started', url, pid: child.pid });
|
||||
}
|
||||
} catch {}
|
||||
await new Promise((r) => setTimeout(r, 1000));
|
||||
}
|
||||
return JSON.stringify({ status: 'timeout', url, pid: child.pid });
|
||||
}
|
||||
|
||||
if (args.action === 'stop') {
|
||||
if (args.pid == null) throw new Error('pid is required for action=stop');
|
||||
try {
|
||||
process.kill(args.pid, 'SIGTERM');
|
||||
return JSON.stringify({ status: 'stopped', pid: args.pid });
|
||||
} catch (err) {
|
||||
return JSON.stringify({ status: 'error', pid: args.pid, error: String(err) });
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`unknown action ${args.action}`);
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user