Adds justfile with 8 grouped recipe sections covering build, jail management, skill catalog, agent ops, and system admin. Adds scripts for skill-list/add/sync, jail-status, system-health, agent-task/status/logs, harness-check, and hostd-cli. Fixes project root derivation to use import.meta.url instead of process.cwd() so scripts work regardless of invocation directory. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --- Build: pass | Tests: FAIL — Tests 40 failed | 766 passed (806)
82 lines
2.2 KiB
TypeScript
82 lines
2.2 KiB
TypeScript
#!/usr/bin/env npx tsx
|
|
/**
|
|
* scripts/agent-task.ts — Create a controlplane task via natural language.
|
|
* Usage: just agent-task "Restart the cms jail nginx service"
|
|
*/
|
|
import http from 'http';
|
|
|
|
const PORT = parseInt(process.env.CONTROLPLANE_PORT ?? '3100', 10);
|
|
const HOST = process.env.CONTROLPLANE_BIND_HOST ?? '127.0.0.1';
|
|
|
|
const description = process.argv[2];
|
|
|
|
if (!description) {
|
|
console.error('Usage: just agent-task "<description>"');
|
|
process.exit(1);
|
|
}
|
|
|
|
function post<T>(path: string, body: unknown): Promise<T> {
|
|
return new Promise((resolve, reject) => {
|
|
const payload = JSON.stringify(body);
|
|
const req = http.request(
|
|
{
|
|
hostname: HOST,
|
|
port: PORT,
|
|
path,
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) },
|
|
},
|
|
(res) => {
|
|
let buf = '';
|
|
res.on('data', (c: Buffer) => { buf += c.toString(); });
|
|
res.on('end', () => {
|
|
try { resolve(JSON.parse(buf) as T); }
|
|
catch { reject(new Error(`Non-JSON response (HTTP ${res.statusCode}): ${buf.slice(0, 100)}`)); }
|
|
});
|
|
},
|
|
);
|
|
req.on('error', reject);
|
|
req.write(payload);
|
|
req.end();
|
|
});
|
|
}
|
|
|
|
interface TaskResponse {
|
|
task?: { id: string; title: string; status: string };
|
|
error?: string;
|
|
}
|
|
|
|
async function main(): Promise<void> {
|
|
let resp: TaskResponse;
|
|
try {
|
|
resp = await post<TaskResponse>('/api/controlplane/tasks', {
|
|
title: description.slice(0, 100),
|
|
description,
|
|
priority: 'medium',
|
|
});
|
|
} catch (err) {
|
|
const msg = err instanceof Error ? err.message : String(err);
|
|
if (msg.includes('ECONNREFUSED')) {
|
|
console.error(`Controlplane not reachable at http://${HOST}:${PORT}`);
|
|
} else {
|
|
console.error(`Error: ${msg}`);
|
|
}
|
|
process.exit(1);
|
|
}
|
|
|
|
if (!resp.task) {
|
|
console.error(`Failed: ${resp.error ?? JSON.stringify(resp)}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(`\nTask created:`);
|
|
console.log(` ID: ${resp.task.id}`);
|
|
console.log(` Title: ${resp.task.title}`);
|
|
console.log(` Status: ${resp.task.status}`);
|
|
console.log('');
|
|
}
|
|
|
|
main().catch((err: Error) => {
|
|
console.error(err.message);
|
|
process.exit(1);
|
|
});
|