87 lines
3.1 KiB
JavaScript
87 lines
3.1 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Agent Runtime CLI — PR-35
|
|
*
|
|
* Usage:
|
|
* echo '{"task":{...},"context":{...}}' | node scripts/runtime.mjs
|
|
*
|
|
* stdin:
|
|
* { task, context: { baselineData?, candidateData?, ... }, options? }
|
|
*
|
|
* Output: JSON { success, taskResult, report }
|
|
* Exit: 0=passed, 1=failed/blocked/error
|
|
*/
|
|
|
|
import { readFileSync } from "node:fs";
|
|
import { createTask, createExecutionPlan } from "../src/agent-runtime/domain.mjs";
|
|
import { executePipeline, recoverTask } from "../src/agent-runtime/pipeline.mjs";
|
|
import { createRuntimeContext, autoGateAdapter, createCertificationAdapter } from "../src/agent-runtime/adapters.mjs";
|
|
import { generateRuntimeReport } from "../src/agent-runtime/reporting.mjs";
|
|
|
|
function readStdin() {
|
|
try {
|
|
const raw = readFileSync(0, "utf8").trim();
|
|
return raw ? JSON.parse(raw) : null;
|
|
} catch (e) {
|
|
return { _error: `Parse error: ${e.message}` };
|
|
}
|
|
}
|
|
|
|
function main() {
|
|
const input = readStdin();
|
|
if (!input) { console.error("Error: No stdin input."); process.exit(1); }
|
|
if (input._error) { console.error(input._error); process.exit(1); }
|
|
|
|
const { task: rawTask, context: rawCtx = {}, options = {}, action = "execute" } = input;
|
|
if (!rawTask) { console.error("Error: 'task' field required."); process.exit(1); }
|
|
|
|
// 反序列化 Task
|
|
const task = createTask({
|
|
id: rawTask.id, title: rawTask.title || rawTask.id,
|
|
description: rawTask.description, tags: rawTask.tags,
|
|
dependsOn: rawTask.dependsOn, parentTaskId: rawTask.parentTaskId,
|
|
metadata: rawTask.metadata,
|
|
});
|
|
task.executionPlan = createExecutionPlan({
|
|
taskId: task.id,
|
|
steps: (rawTask.steps || []).map(s => ({
|
|
id: s.id, name: s.name || s.id, action: s.action || s.name,
|
|
dependsOn: s.dependsOn, expectedArtifacts: s.expectedArtifacts, metadata: s.metadata,
|
|
})),
|
|
strategy: rawTask.strategy,
|
|
});
|
|
task.maxRetries = rawTask.maxRetries ?? 3;
|
|
|
|
// 构建 Runtime Context
|
|
const rctx = createRuntimeContext({
|
|
checklistAdapter: rawCtx.checklist ? (ctx) => ({ status: rawCtx.checklist === "pass" ? "pass" : "fail", blockers: [], warnings: [], confidence: 100 }) : null,
|
|
baselineAdapter: rawCtx.baseline ? (_ctx, b, c) => ({ status: "pass", changes: [], blockers: [], warnings: [] }) : null,
|
|
gateAdapter: rawCtx.gate ? autoGateAdapter : null,
|
|
certificationAdapter: createCertificationAdapter(),
|
|
baselineData: rawCtx.baselineData || null,
|
|
candidateData: rawCtx.candidateData || null,
|
|
pipelineOptions: options,
|
|
});
|
|
|
|
try {
|
|
let taskResult;
|
|
if (action === "recover") {
|
|
task.state = "failed";
|
|
task.retryCount = rawTask.retryCount || 0;
|
|
taskResult = recoverTask(task, rctx, options);
|
|
} else {
|
|
taskResult = executePipeline(task, rctx, options);
|
|
}
|
|
|
|
const report = generateRuntimeReport(task, taskResult);
|
|
const output = { success: taskResult.status === "passed", taskResult, report };
|
|
console.log(JSON.stringify(output, null, 2));
|
|
process.exit(taskResult.status === "passed" ? 0 : 1);
|
|
} catch (e) {
|
|
console.error(`Runtime error: ${e.message}`);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
main();
|