mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-13 18:52:18 +03:00
* feat(a2a): conductor bridge core — event mapping with canceled->cancelled
* feat(a2a): incremental SSE parser for conductor bridge
* feat(a2a): conductor bridge connection loop with persisted cursor and backoff
* feat(a2a): start conductor bridge at boot behind CONDUCTOR_HUB_URL
* fix(a2a): conductor bridge parses the hub's real SSE wire format (id/type in frame, data={ts,payload})
* docs(reference): document CONDUCTOR_HUB_URL/TOKEN in ENVIRONMENT.md (env-doc-sync gate)
* feat(a2a): fleet skills derived from the Conductor hub for the agent card
* feat(a2a): agent card announces Conductor fleet skills
* feat(dashboard): server-side hub proxy for the Conductor panel (whitelisted shapes, fail-open)
* feat(dashboard): /api/conductor proxy routes (fleet, task detail, cancel) behind management auth
* feat(dashboard): Conductor panel — fleet live view, task detail and cancel over /api/conductor proxy
---------
Co-authored-by: backryun <bakryun0718@proton.me>
141 lines
4.8 KiB
TypeScript
141 lines
4.8 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import {
|
|
getFleetSnapshot,
|
|
getConductorTaskDetail,
|
|
cancelConductorTask,
|
|
} from "../../src/lib/conductor/hubProxy.ts";
|
|
|
|
const RUNNERS = [
|
|
{
|
|
id: "r_1",
|
|
token: "NUNCA-VAZAR",
|
|
online: true,
|
|
draining: false,
|
|
capabilities: { name: "devbox", clis: [{ profile: "claude" }, { profile: "codex" }], skills: [] },
|
|
},
|
|
];
|
|
|
|
const TASKS = [
|
|
{
|
|
id: "t_1",
|
|
status: "completed",
|
|
mode: "solo",
|
|
from: "orchestrator",
|
|
repo: { url: "https://git.x/repo", base_ref: "main" },
|
|
spec: { prompt: "faz algo" },
|
|
assigned_runner: "r_1",
|
|
manifest: { summary: "feito", branch: "task/t_1", error: null },
|
|
council: null,
|
|
created_at: "2026-07-22T00:00:00Z",
|
|
updated_at: "2026-07-22T00:01:00Z",
|
|
},
|
|
{
|
|
id: "t_2",
|
|
status: "working",
|
|
mode: "council-3",
|
|
from: "orchestrator",
|
|
repo: { url: "https://git.x/repo", base_ref: "main" },
|
|
spec: { prompt: "outra" },
|
|
assigned_runner: null,
|
|
manifest: null,
|
|
council: { candidate_task_ids: ["t_2a", "t_2b"] },
|
|
created_at: "2026-07-22T00:02:00Z",
|
|
updated_at: "2026-07-22T00:02:30Z",
|
|
},
|
|
];
|
|
|
|
function fakeHub(routes: Record<string, { status: number; body: unknown }>) {
|
|
const calls: { url: string; method: string; auth: string | null }[] = [];
|
|
const impl = (async (url: string | URL | Request, init?: RequestInit) => {
|
|
const u = String(url);
|
|
calls.push({
|
|
url: u,
|
|
method: init?.method ?? "GET",
|
|
auth: (init?.headers as Record<string, string> | undefined)?.authorization ?? null,
|
|
});
|
|
const hit = Object.entries(routes).find(([path]) => u.includes(path));
|
|
if (!hit) return new Response("{}", { status: 404 });
|
|
return new Response(JSON.stringify(hit[1].body), { status: hit[1].status });
|
|
}) as typeof fetch;
|
|
return { impl, calls };
|
|
}
|
|
|
|
test.beforeEach(() => {
|
|
process.env.CONDUCTOR_HUB_URL = "http://hub.test:7910";
|
|
process.env.CONDUCTOR_HUB_TOKEN = "tok-secreto";
|
|
});
|
|
|
|
test.after(() => {
|
|
delete process.env.CONDUCTOR_HUB_URL;
|
|
delete process.env.CONDUCTOR_HUB_TOKEN;
|
|
});
|
|
|
|
test("snapshot: runners e tasks sanitizados (whitelist — token do runner NUNCA passa)", async () => {
|
|
const { impl, calls } = fakeHub({
|
|
"/v1/runners": { status: 200, body: RUNNERS },
|
|
"/v1/tasks": { status: 200, body: TASKS },
|
|
});
|
|
const snap = await getFleetSnapshot({ fetchImpl: impl });
|
|
assert.equal(snap.offline, false);
|
|
assert.deepEqual(snap.runners, [
|
|
{ id: "r_1", name: "devbox", clis: ["claude", "codex"], online: true, draining: false },
|
|
]);
|
|
assert.equal(snap.tasks.length, 2);
|
|
assert.deepEqual(snap.tasks[0], {
|
|
id: "t_1",
|
|
status: "completed",
|
|
mode: "solo",
|
|
repo: "https://git.x/repo",
|
|
runner: "r_1",
|
|
summary: "feito",
|
|
branch: "task/t_1",
|
|
error: null,
|
|
updated_at: "2026-07-22T00:01:00Z",
|
|
});
|
|
assert.ok(!JSON.stringify(snap).includes("NUNCA-VAZAR"), "token de runner não vaza");
|
|
assert.ok(!JSON.stringify(snap).includes("tok-secreto"), "token do hub não vaza");
|
|
assert.equal(calls.every((c) => c.auth === "Bearer tok-secreto"), true, "proxy autentica no hub");
|
|
});
|
|
|
|
test("snapshot: hub fora do ar → degradado {offline:true} sem lançar", async () => {
|
|
const failing = (async () => {
|
|
throw new Error("ECONNREFUSED");
|
|
}) as unknown as typeof fetch;
|
|
const snap = await getFleetSnapshot({ fetchImpl: failing });
|
|
assert.deepEqual(snap, { offline: true, runners: [], tasks: [] });
|
|
});
|
|
|
|
test("snapshot: env ausente → degradado sem fetch", async () => {
|
|
delete process.env.CONDUCTOR_HUB_URL;
|
|
const { impl, calls } = fakeHub({});
|
|
const snap = await getFleetSnapshot({ fetchImpl: impl });
|
|
assert.equal(snap.offline, true);
|
|
assert.equal(calls.length, 0);
|
|
});
|
|
|
|
test("detalhe: manifest e council passam; spec.prompt vem; campos fora da whitelist não", async () => {
|
|
const { impl } = fakeHub({ "/v1/tasks/t_2": { status: 200, body: TASKS[1] } });
|
|
const detail = await getConductorTaskDetail("t_2", { fetchImpl: impl });
|
|
assert.ok(detail);
|
|
assert.equal(detail!.id, "t_2");
|
|
assert.equal(detail!.prompt, "outra");
|
|
assert.deepEqual(detail!.council, { candidate_task_ids: ["t_2a", "t_2b"] });
|
|
assert.equal(detail!.base_ref, "main");
|
|
});
|
|
|
|
test("detalhe: 404 do hub → null", async () => {
|
|
const { impl } = fakeHub({});
|
|
assert.equal(await getConductorTaskDetail("t_x", { fetchImpl: impl }), null);
|
|
});
|
|
|
|
test("cancelar: POST no hub e repassa o status", async () => {
|
|
const { impl, calls } = fakeHub({ "/v1/tasks/t_1/cancel": { status: 200, body: { ok: true } } });
|
|
const r = await cancelConductorTask("t_1", { fetchImpl: impl });
|
|
assert.deepEqual(r, { ok: true, status: 200 });
|
|
assert.equal(calls[0].method, "POST");
|
|
const miss = await cancelConductorTask("t_zzz", { fetchImpl: fakeHub({}).impl });
|
|
assert.deepEqual(miss, { ok: false, status: 404 });
|
|
});
|