feat(cli): fase 7 — context-eng/sessions/tags/openapi/combo-suggest/oneproxy/telemetry

- 7.1: context-eng (alias ctx) — caveman/rtk config/filters/test, analytics, combos
- 7.2: sessions list/show/expire/expire-all/current
- 7.3: tags list/add/remove/assign/unassign/resources
- 7.4: openapi dump/validate/try/endpoints/paths (YAML sem js-yaml via toYaml inline)
- 7.5: combo suggest via MCP omniroute_best_combo_for_task (extendComboSuggest)
- 7.6: oneproxy status/stats/fetch/rotate/config/pool via MCP + REST
- 7.7: telemetry summary/export com fmtMetric/fmtDelta
45 novos testes passando
This commit is contained in:
diegosouzapw
2026-05-15 02:47:49 -03:00
parent fc45ff1bdd
commit 2f2583a02f
17 changed files with 2021 additions and 16 deletions

View File

@@ -2,6 +2,8 @@ import { Option } from "commander";
import { printHeading } from "../io.mjs";
import { withRuntime } from "../runtime.mjs";
import { t } from "../i18n.mjs";
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
const VALID_STRATEGIES = [
"priority",
@@ -20,6 +22,79 @@ const VALID_STRATEGIES = [
"reset-aware",
];
const suggestSchema = [
{ key: "rank", header: "#" },
{ key: "name", header: "Combo", width: 24 },
{ key: "strategy", header: "Strategy", width: 16 },
{ key: "score", header: "Score", formatter: (v) => (v != null ? v.toFixed(3) : "-") },
{ key: "latencyP50Ms", header: "Latency P50", formatter: (v) => (v != null ? `${v}ms` : "-") },
{ key: "costPer1k", header: "Cost/1k", formatter: (v) => (v != null ? `$${v.toFixed(5)}` : "-") },
{
key: "rationale",
header: "Rationale",
width: 40,
formatter: (v) => {
if (!v) return "-";
const s = String(v);
return s.length > 40 ? s.slice(0, 39) + "…" : s;
},
},
];
export function extendComboSuggest(combo) {
combo
.command("suggest")
.description(t("combo.suggest.description"))
.requiredOption("--task <description>", t("combo.suggest.task"))
.option("--max-cost <usd>", t("combo.suggest.maxCost"), parseFloat)
.option("--max-latency-ms <ms>", t("combo.suggest.maxLatencyMs"), parseInt)
.option("--weights <json>", t("combo.suggest.weights"))
.option("--top <n>", t("combo.suggest.top"), parseInt, 5)
.option("--explain", t("combo.suggest.explain"))
.option("--switch", t("combo.suggest.switch"))
.action(async (opts, cmd) => {
const body = {
task: opts.task,
constraints: {
maxCostUsd: opts.maxCost,
maxLatencyMs: opts.maxLatencyMs,
},
weights: opts.weights ? JSON.parse(opts.weights) : undefined,
top: opts.top,
};
const res = await apiFetch("/api/mcp/tools/call", {
method: "POST",
body: { name: "omniroute_best_combo_for_task", arguments: body },
});
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
const data = await res.json();
const candidates = data.candidates ?? data;
const rows = (Array.isArray(candidates) ? candidates : []).map((c, i) => ({
rank: i + 1,
...c,
}));
emit(rows, cmd.optsWithGlobals(), suggestSchema);
if (opts.explain && !cmd.optsWithGlobals().quiet) {
process.stderr.write(`\nRationale:\n${data.rationale ?? "(no rationale)"}\n`);
}
if (opts.switch && rows[0]) {
const best = rows[0].name;
const switchRes = await apiFetch("/api/combos/switch", {
method: "POST",
body: { name: best },
});
if (!switchRes.ok) {
process.stderr.write(`Switch failed: ${switchRes.status}\n`);
process.exit(1);
}
process.stderr.write(`\nSwitched to: ${best}\n`);
}
});
}
export function registerCombo(program) {
const combo = program.command("combo").description(t("combo.title"));
@@ -68,6 +143,8 @@ export function registerCombo(program) {
const exitCode = await runComboDeleteCommand(name, { ...opts, output: globalOpts.output });
if (exitCode !== 0) process.exit(exitCode);
});
extendComboSuggest(combo);
}
export async function runComboListCommand(opts = {}) {

View File

@@ -0,0 +1,182 @@
import { readFileSync } from "node:fs";
import { createInterface } from "node:readline";
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { t } from "../i18n.mjs";
async function confirm(q) {
const rl = createInterface({ input: process.stdin, output: process.stdout });
return new Promise((resolve) => {
rl.question(`${q} [y/N] `, (a) => {
rl.close();
resolve(a.trim().toLowerCase() === "y");
});
});
}
export function registerContextEng(program) {
const ctx = program.command("context-eng").alias("ctx").description(t("context.description"));
ctx
.command("analytics")
.option("--period <p>", t("context.analytics.period"), "7d")
.action(async (opts, cmd) => {
const res = await apiFetch(`/api/context/analytics?period=${opts.period}`);
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
emit(await res.json(), cmd.optsWithGlobals());
});
const caveman = ctx.command("caveman").description(t("context.caveman.description"));
const cmCfg = caveman.command("config").description(t("context.caveman.config.description"));
cmCfg.command("show").action(async (opts, cmd) => {
const res = await apiFetch("/api/context/caveman/config");
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
emit(await res.json(), cmd.optsWithGlobals());
});
cmCfg
.command("set")
.option("--aggressiveness <n>", t("context.caveman.config.aggressiveness"), parseFloat)
.option("--max-shrink-pct <n>", t("context.caveman.config.maxShrinkPct"), parseInt)
.option("--preserve-tags <list>", t("context.caveman.config.preserveTags"), (v) => v.split(","))
.action(async (opts, cmd) => {
const body = {};
if (opts.aggressiveness !== undefined) body.aggressiveness = opts.aggressiveness;
if (opts.maxShrinkPct !== undefined) body.maxShrinkPct = opts.maxShrinkPct;
if (opts.preserveTags) body.preserveTags = opts.preserveTags;
const res = await apiFetch("/api/context/caveman/config", { method: "PUT", body });
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
emit(await res.json(), cmd.optsWithGlobals());
});
const rtk = ctx.command("rtk").description(t("context.rtk.description"));
const rtkCfg = rtk.command("config").description(t("context.rtk.config.description"));
rtkCfg.command("show").action(async (opts, cmd) => {
const res = await apiFetch("/api/context/rtk/config");
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
emit(await res.json(), cmd.optsWithGlobals());
});
rtkCfg
.command("set")
.option("--token-budget <n>", t("context.rtk.config.tokenBudget"), parseInt)
.option("--reserve-pct <n>", t("context.rtk.config.reservePct"), parseInt)
.action(async (opts, cmd) => {
const body = {};
if (opts.tokenBudget) body.tokenBudget = opts.tokenBudget;
if (opts.reservePct) body.reservePct = opts.reservePct;
const res = await apiFetch("/api/context/rtk/config", { method: "PUT", body });
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
emit(await res.json(), cmd.optsWithGlobals());
});
const filters = rtk.command("filters").description(t("context.rtk.filters.description"));
filters.command("list").action(async (opts, cmd) => {
const res = await apiFetch("/api/context/rtk/filters");
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
emit(await res.json(), cmd.optsWithGlobals());
});
filters
.command("add")
.requiredOption("--pattern <p>", t("context.rtk.filters.pattern"))
.option("--priority <n>", t("context.rtk.filters.priority"), parseInt, 100)
.option("--action <a>", t("context.rtk.filters.action"), "drop")
.action(async (opts, cmd) => {
const body = { pattern: opts.pattern, priority: opts.priority, action: opts.action };
const res = await apiFetch("/api/context/rtk/filters", { method: "POST", body });
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
emit(await res.json(), cmd.optsWithGlobals());
});
filters
.command("remove <id>")
.option("--yes", t("context.rtk.filters.yes"))
.action(async (id, opts, cmd) => {
if (!opts.yes) {
const ok = await confirm(`Remove filter ${id}?`);
if (!ok) return;
}
const res = await apiFetch(`/api/context/rtk/filters/${id}`, { method: "DELETE" });
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
process.stdout.write("Removed\n");
});
rtk
.command("test")
.requiredOption("--file <path>", t("context.rtk.test.file"))
.action(async (opts, cmd) => {
const body = JSON.parse(readFileSync(opts.file, "utf8"));
const res = await apiFetch("/api/context/rtk/test", { method: "POST", body });
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
emit(await res.json(), cmd.optsWithGlobals());
});
rtk.command("raw-output <id>").action(async (id, opts, cmd) => {
const res = await apiFetch(`/api/context/rtk/raw-output/${id}`);
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
emit(await res.json(), cmd.optsWithGlobals());
});
const combos = ctx.command("combos").description(t("context.combos.description"));
combos.command("list").action(async (opts, cmd) => {
const res = await apiFetch("/api/context/combos");
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
emit(await res.json(), cmd.optsWithGlobals());
});
combos.command("get <id>").action(async (id, opts, cmd) => {
const res = await apiFetch(`/api/context/combos/${id}`);
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
emit(await res.json(), cmd.optsWithGlobals());
});
combos.command("assignments <id>").action(async (id, opts, cmd) => {
const res = await apiFetch(`/api/context/combos/${id}/assignments`);
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
emit(await res.json(), cmd.optsWithGlobals());
});
}

View File

@@ -0,0 +1,120 @@
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { t } from "../i18n.mjs";
function fmtTs(v) {
if (!v) return "-";
return new Date(typeof v === "number" ? v * 1000 : v).toLocaleString();
}
async function mcpCall(name, args) {
const res = await apiFetch("/api/mcp/tools/call", {
method: "POST",
body: { name, arguments: args },
});
if (!res.ok) {
process.stderr.write(`MCP error: ${res.status}\n`);
process.exit(1);
}
return res.json();
}
const proxySchema = [
{ key: "host", header: "Host", width: 35 },
{ key: "type", header: "Type", width: 8 },
{ key: "region", header: "Region" },
{ key: "latencyMs", header: "Latency", formatter: (v) => (v ? `${v}ms` : "-") },
{
key: "successRate",
header: "Success%",
formatter: (v) => (v ? `${(v * 100).toFixed(0)}%` : "-"),
},
{ key: "lastUsed", header: "Last Used", formatter: fmtTs },
{ key: "state", header: "State" },
];
export function registerOneProxy(program) {
const op = program.command("oneproxy").description(t("oneproxy.description"));
op.command("status").action(async (opts, cmd) => {
const data = await mcpCall("omniroute_oneproxy_stats", {});
emit(data, cmd.optsWithGlobals());
});
op.command("stats")
.option("--provider <p>", t("oneproxy.stats.provider"))
.option("--period <p>", t("oneproxy.stats.period"), "24h")
.action(async (opts, cmd) => {
const data = await mcpCall("omniroute_oneproxy_stats", {
provider: opts.provider,
period: opts.period,
});
emit(data, cmd.optsWithGlobals());
});
op.command("fetch")
.description(t("oneproxy.fetch.description"))
.option("--count <n>", t("oneproxy.fetch.count"), parseInt, 1)
.option("--type <t>", t("oneproxy.fetch.type"), "http")
.action(async (opts, cmd) => {
const data = await mcpCall("omniroute_oneproxy_fetch", {
count: opts.count,
type: opts.type,
});
emit(data.proxies ?? data, cmd.optsWithGlobals(), proxySchema);
});
op.command("rotate")
.description(t("oneproxy.rotate.description"))
.option("--provider <p>", t("oneproxy.rotate.provider"))
.option("--connection-id <id>", t("oneproxy.rotate.connectionId"))
.action(async (opts, cmd) => {
const data = await mcpCall("omniroute_oneproxy_rotate", {
provider: opts.provider,
connectionId: opts.connectionId,
});
emit(data, cmd.optsWithGlobals());
});
const config = op.command("config").description(t("oneproxy.config.description"));
config.command("show").action(async (opts, cmd) => {
const res = await apiFetch("/api/settings/oneproxy");
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
emit(await res.json(), cmd.optsWithGlobals());
});
config
.command("set")
.option("--enabled <b>", t("oneproxy.config.enabled"), (v) => v === "true")
.option("--pool-size <n>", t("oneproxy.config.poolSize"), parseInt)
.option("--provider-source <url>", t("oneproxy.config.providerSource"))
.option("--rotation-policy <p>", t("oneproxy.config.rotationPolicy"))
.action(async (opts, cmd) => {
const body = {};
for (const k of ["enabled", "poolSize", "providerSource", "rotationPolicy"]) {
if (opts[k] !== undefined) body[k] = opts[k];
}
const res = await apiFetch("/api/settings/oneproxy", { method: "PUT", body });
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
emit(await res.json(), cmd.optsWithGlobals());
});
op.command("pool")
.description(t("oneproxy.pool.description"))
.action(async (opts, cmd) => {
const res = await apiFetch("/api/settings/oneproxy?include=pool");
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
const data = await res.json();
emit(data.pool ?? data, cmd.optsWithGlobals(), proxySchema);
});
}

View File

@@ -0,0 +1,168 @@
import { readFileSync, writeFileSync } from "node:fs";
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { t } from "../i18n.mjs";
function truncate(v, max = 40) {
if (!v) return "-";
const s = String(v);
return s.length > max ? s.slice(0, max - 1) + "…" : s;
}
function toYaml(obj, indent = 0) {
const pad = " ".repeat(indent);
if (obj === null || obj === undefined) return "null";
if (typeof obj === "boolean") return String(obj);
if (typeof obj === "number") return String(obj);
if (typeof obj === "string") {
if (/[\n:#{}[\],&*?|<>=!%@`]/.test(obj) || obj.trim() !== obj) {
return JSON.stringify(obj);
}
return obj || '""';
}
if (Array.isArray(obj)) {
if (obj.length === 0) return "[]";
return obj.map((v) => `\n${pad}- ${toYaml(v, indent + 1)}`).join("");
}
const entries = Object.entries(obj);
if (entries.length === 0) return "{}";
return entries
.map(([k, v]) => {
const safeKey = /[^a-zA-Z0-9_-]/.test(k) ? JSON.stringify(k) : k;
if (v !== null && typeof v === "object") {
const nested = toYaml(v, indent + 1);
if (Array.isArray(v) && v.length > 0) return `\n${pad}${safeKey}:${nested}`;
if (!Array.isArray(v) && Object.keys(v).length > 0) return `\n${pad}${safeKey}:\n${nested}`;
return `\n${pad}${safeKey}: ${nested}`;
}
return `\n${pad}${safeKey}: ${toYaml(v, indent + 1)}`;
})
.join("")
.trimStart();
}
function validateBasic(spec) {
if (!spec || typeof spec !== "object") throw new Error("spec is not an object");
if (!spec.openapi && !spec.swagger) throw new Error("missing openapi/swagger version field");
if (!spec.info) throw new Error("missing info object");
if (!spec.paths) throw new Error("missing paths object");
}
const endpointSchema = [
{ key: "method", header: "Method", width: 8 },
{ key: "path", header: "Path", width: 45 },
{ key: "operationId", header: "Operation ID", width: 25 },
{ key: "summary", header: "Summary", width: 40, formatter: (v) => truncate(v, 40) },
];
export function registerOpenapi(program) {
const api = program.command("openapi").description(t("openapi.description"));
api
.command("dump")
.description(t("openapi.dump.description"))
.option("--format <f>", t("openapi.dump.format"), "yaml")
.option("--out <path>", t("openapi.dump.out"))
.action(async (opts, cmd) => {
const res = await apiFetch("/api/openapi/spec");
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
const data = await res.json();
const serialized =
opts.format === "yaml" ? toYaml(data) + "\n" : JSON.stringify(data, null, 2);
if (opts.out) {
writeFileSync(opts.out, serialized);
process.stdout.write(`Saved to ${opts.out}\n`);
} else {
process.stdout.write(serialized);
}
});
api
.command("validate")
.description(t("openapi.validate.description"))
.action(async (opts, cmd) => {
const res = await apiFetch("/api/openapi/spec");
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
const spec = await res.json();
try {
validateBasic(spec);
process.stdout.write("Spec is valid\n");
} catch (err) {
process.stderr.write(`Invalid: ${err.message}\n`);
process.exit(1);
}
});
api
.command("try <path>")
.description(t("openapi.try.description"))
.option("--method <m>", t("openapi.try.method"), "GET")
.option("--body <file>", t("openapi.try.body"))
.option("--query <kv>", t("openapi.try.query"), (v, prev = []) => [...prev, v.split("=")], [])
.option("--header <kv>", t("openapi.try.header"), (v, prev = []) => [...prev, v.split("=")], [])
.action(async (path, opts, cmd) => {
const body = opts.body ? JSON.parse(readFileSync(opts.body, "utf8")) : undefined;
const query = Object.fromEntries(opts.query ?? []);
const headers = Object.fromEntries(opts.header ?? []);
const res = await apiFetch("/api/openapi/try", {
method: "POST",
body: { path, method: opts.method, body, query, headers },
});
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
emit(await res.json(), cmd.optsWithGlobals());
});
api
.command("endpoints")
.description(t("openapi.endpoints.description"))
.option("--search <q>", t("openapi.endpoints.search"))
.action(async (opts, cmd) => {
const res = await apiFetch("/api/openapi/spec");
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
const spec = await res.json();
const rows = [];
for (const [path, methods] of Object.entries(spec.paths ?? {})) {
for (const [method, def] of Object.entries(methods)) {
if (["parameters", "summary"].includes(method)) continue;
const summary = def.summary ?? def.description ?? "";
if (
opts.search &&
!path.includes(opts.search) &&
!summary.toLowerCase().includes(opts.search.toLowerCase())
)
continue;
rows.push({ method: method.toUpperCase(), path, summary, operationId: def.operationId });
}
}
emit(rows, cmd.optsWithGlobals(), endpointSchema);
});
api
.command("paths")
.description(t("openapi.paths.description"))
.action(async (opts, cmd) => {
const res = await apiFetch("/api/openapi/spec");
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
const spec = await res.json();
const paths = Object.keys(spec.paths ?? {}).sort();
emit(
paths.map((p) => ({ path: p })),
cmd.optsWithGlobals()
);
});
}

View File

@@ -14,6 +14,12 @@ import { registerPricing } from "./pricing.mjs";
import { registerResilience } from "./resilience.mjs";
import { registerNodes } from "./nodes.mjs";
import { registerSync } from "./sync.mjs";
import { registerContextEng } from "./context-eng.mjs";
import { registerSessions } from "./sessions.mjs";
import { registerTags } from "./tags.mjs";
import { registerOpenapi } from "./openapi.mjs";
import { registerOneProxy } from "./oneproxy.mjs";
import { registerTelemetry } from "./telemetry.mjs";
import { registerChat } from "./chat.mjs";
import { registerStream } from "./stream.mjs";
import { registerSimulate } from "./simulate.mjs";
@@ -62,6 +68,12 @@ export function registerCommands(program) {
registerResilience(program);
registerNodes(program);
registerSync(program);
registerContextEng(program);
registerSessions(program);
registerTags(program);
registerOpenapi(program);
registerOneProxy(program);
registerTelemetry(program);
registerChat(program);
registerStream(program);
registerSimulate(program);

View File

@@ -0,0 +1,108 @@
import { createInterface } from "node:readline";
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { t } from "../i18n.mjs";
function fmtTs(v) {
if (!v) return "-";
return new Date(typeof v === "number" ? v * 1000 : v).toLocaleString();
}
function truncate(v, max = 30) {
if (!v) return "-";
const s = String(v);
return s.length > max ? s.slice(0, max - 1) + "…" : s;
}
async function confirm(q) {
const rl = createInterface({ input: process.stdin, output: process.stdout });
return new Promise((resolve) => {
rl.question(`${q} [y/N] `, (a) => {
rl.close();
resolve(a.trim().toLowerCase() === "y");
});
});
}
const sessionSchema = [
{ key: "id", header: "Session ID", width: 28 },
{ key: "user", header: "User", width: 22 },
{ key: "kind", header: "Kind", width: 14 },
{ key: "createdAt", header: "Created", formatter: fmtTs },
{ key: "expiresAt", header: "Expires", formatter: fmtTs },
{ key: "lastSeen", header: "Last Seen", formatter: fmtTs },
{ key: "ip", header: "IP" },
{ key: "userAgent", header: "User Agent", width: 30, formatter: (v) => truncate(v, 30) },
];
export function registerSessions(program) {
const s = program.command("sessions").description(t("sessions.description"));
s.command("list")
.option("--user <u>", t("sessions.list.user"))
.option("--kind <k>", t("sessions.list.kind"))
.option("--active", t("sessions.list.active"))
.option("--limit <n>", t("sessions.list.limit"), parseInt, 100)
.action(async (opts, cmd) => {
const params = new URLSearchParams({ limit: String(opts.limit) });
if (opts.user) params.set("user", opts.user);
if (opts.kind) params.set("kind", opts.kind);
if (opts.active) params.set("active", "true");
const res = await apiFetch(`/api/sessions?${params}`);
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
const data = await res.json();
emit(data.items ?? data, cmd.optsWithGlobals(), sessionSchema);
});
s.command("show <sessionId>").action(async (id, opts, cmd) => {
const res = await apiFetch(`/api/sessions?id=${id}`);
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
emit(await res.json(), cmd.optsWithGlobals());
});
s.command("expire <sessionId>")
.option("--yes", t("sessions.expire.yes"))
.action(async (id, opts, cmd) => {
if (!opts.yes) {
const ok = await confirm(`Expire session ${id}?`);
if (!ok) return;
}
const res = await apiFetch(`/api/sessions?id=${id}`, { method: "DELETE" });
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
process.stdout.write("Expired\n");
});
s.command("expire-all")
.requiredOption("--user <u>", t("sessions.expireAll.user"))
.option("--yes", t("sessions.expireAll.yes"))
.action(async (opts, cmd) => {
if (!opts.yes) {
const ok = await confirm(`Expire ALL sessions for ${opts.user}?`);
if (!ok) return;
}
const res = await apiFetch(`/api/sessions?user=${opts.user}`, { method: "DELETE" });
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
process.stdout.write("Expired all\n");
});
s.command("current").action(async (opts, cmd) => {
const res = await apiFetch("/api/sessions?current=true");
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
emit(await res.json(), cmd.optsWithGlobals());
});
}

116
bin/cli/commands/tags.mjs Normal file
View File

@@ -0,0 +1,116 @@
import { createInterface } from "node:readline";
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { t } from "../i18n.mjs";
function truncate(v, max = 40) {
if (!v) return "-";
const s = String(v);
return s.length > max ? s.slice(0, max - 1) + "…" : s;
}
async function confirm(q) {
const rl = createInterface({ input: process.stdin, output: process.stdout });
return new Promise((resolve) => {
rl.question(`${q} [y/N] `, (a) => {
rl.close();
resolve(a.trim().toLowerCase() === "y");
});
});
}
const tagSchema = [
{ key: "id", header: "ID", width: 14 },
{ key: "name", header: "Name", width: 25 },
{ key: "color", header: "Color" },
{ key: "description", header: "Description", width: 40, formatter: (v) => truncate(v, 40) },
{ key: "resourceCount", header: "Resources" },
];
export function registerTags(program) {
const tags = program.command("tags").description(t("tags.description"));
tags.command("list").action(async (opts, cmd) => {
const res = await apiFetch("/api/tags");
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
const data = await res.json();
emit(data.items ?? data, cmd.optsWithGlobals(), tagSchema);
});
tags
.command("add <name>")
.option("--color <c>", t("tags.add.color"))
.option("--description <d>", t("tags.add.description"))
.action(async (name, opts, cmd) => {
const body = { name, color: opts.color, description: opts.description };
const res = await apiFetch("/api/tags", { method: "POST", body });
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
emit(await res.json(), cmd.optsWithGlobals());
});
tags
.command("remove <id>")
.option("--yes", t("tags.remove.yes"))
.action(async (id, opts, cmd) => {
if (!opts.yes) {
const ok = await confirm(`Delete tag ${id}?`);
if (!ok) return;
}
const res = await apiFetch(`/api/tags?id=${id}`, { method: "DELETE" });
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
process.stdout.write("Removed\n");
});
tags
.command("assign")
.requiredOption("--tag <name>", t("tags.assign.tag"))
.requiredOption("--to <resource>", t("tags.assign.to"))
.action(async (opts, cmd) => {
const [resourceType, resourceId] = opts.to.split(":");
const res = await apiFetch("/api/tags?op=assign", {
method: "POST",
body: { tag: opts.tag, resourceType, resourceId },
});
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
process.stdout.write(`Tag '${opts.tag}' → ${opts.to}\n`);
});
tags
.command("unassign")
.requiredOption("--tag <name>", t("tags.unassign.tag"))
.requiredOption("--from <resource>", t("tags.unassign.from"))
.action(async (opts, cmd) => {
const [resourceType, resourceId] = opts.from.split(":");
const res = await apiFetch("/api/tags?op=unassign", {
method: "POST",
body: { tag: opts.tag, resourceType, resourceId },
});
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
process.stdout.write(`Removed tag '${opts.tag}' from ${opts.from}\n`);
});
tags.command("resources <tagName>").action(async (tagName, opts, cmd) => {
const res = await apiFetch(`/api/tags?name=${encodeURIComponent(tagName)}&resources=true`);
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
const data = await res.json();
emit(data.resources ?? data, cmd.optsWithGlobals());
});
}

View File

@@ -0,0 +1,74 @@
import { writeFileSync } from "node:fs";
import { apiFetch } from "../api.mjs";
import { emit } from "../output.mjs";
import { t } from "../i18n.mjs";
function fmtMetric(v) {
if (v == null) return "-";
if (typeof v === "number") {
if (v > 1e9) return `${(v / 1e9).toFixed(2)}B`;
if (v > 1e6) return `${(v / 1e6).toFixed(2)}M`;
if (v > 1e3) return `${(v / 1e3).toFixed(2)}K`;
return Number.isInteger(v) ? v.toLocaleString() : v.toFixed(2);
}
return String(v);
}
function fmtDelta(v) {
if (v == null) return "-";
const arrow = v > 0 ? "↑" : v < 0 ? "↓" : "→";
const sign = v > 0 ? "+" : "";
return `${arrow} ${sign}${(v * 100).toFixed(1)}%`;
}
const telemetrySchema = [
{ key: "metric", header: "Metric", width: 36 },
{ key: "value", header: "Value", formatter: fmtMetric },
{ key: "delta", header: "Δ vs prev", formatter: fmtDelta },
{ key: "trend", header: "Trend" },
];
export function registerTelemetry(program) {
const tel = program.command("telemetry").description(t("telemetry.description"));
tel
.command("summary")
.description(t("telemetry.summary.description"))
.option("--period <p>", t("telemetry.summary.period"), "24h")
.option("--compare-to <p>", t("telemetry.summary.compareTo"))
.action(async (opts, cmd) => {
const params = new URLSearchParams({ period: opts.period });
if (opts.compareTo) params.set("compareTo", opts.compareTo);
const res = await apiFetch(`/api/telemetry/summary?${params}`);
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
const data = await res.json();
const rows = Object.entries(data.metrics ?? data).map(([metric, info]) => ({
metric,
value: info?.value ?? info,
delta: info?.delta,
trend: info?.trend,
}));
emit(rows, cmd.optsWithGlobals(), telemetrySchema);
});
tel
.command("export")
.description(t("telemetry.export.description"))
.option("--out <path>", t("telemetry.export.out"), "telemetry.jsonl")
.option("--period <p>", t("telemetry.export.period"), "7d")
.action(async (opts, cmd) => {
const res = await apiFetch(`/api/telemetry/summary?format=jsonl&period=${opts.period}`);
if (!res.ok) {
process.stderr.write(`Error: ${res.status}\n`);
process.exit(1);
}
const data = await res.json();
const items = data.events ?? data.items ?? [];
const lines = items.map((e) => JSON.stringify(e)).join("\n");
writeFileSync(opts.out, lines);
process.stdout.write(`Exported ${items.length} events to ${opts.out}\n`);
});
}

View File

@@ -162,14 +162,6 @@
"empty_prompt": "Error: prompt is required (positional arg, --file, or --stdin)"
}
},
"combo": {
"title": "Combos",
"switched": "Active combo: {name}",
"created": "Combo created: {name}",
"deleted": "Combo deleted: {name}",
"noCombos": "No combos configured.",
"confirmDelete": "Delete combo {name}?"
},
"serve": {
"description": "Start the OmniRoute server (default action)",
"starting": "Starting OmniRoute server on port {port}...",
@@ -863,6 +855,159 @@
"period": "Time period (e.g. 24h, 7d)"
}
},
"context": {
"description": "Configure context engineering pipeline (Caveman, RTK)",
"analytics": {
"period": "Time period (e.g. 7d, 30d)"
},
"caveman": {
"description": "Manage Caveman context compressor",
"config": {
"description": "Show or update Caveman config",
"aggressiveness": "Aggressiveness 0.01.0",
"maxShrinkPct": "Maximum shrink percentage",
"preserveTags": "Comma-separated tags to preserve"
}
},
"rtk": {
"description": "Manage RTK context optimizer",
"config": {
"description": "Show or update RTK config",
"tokenBudget": "Token budget for RTK",
"reservePct": "Reserve percentage"
},
"filters": {
"description": "Manage RTK filters",
"pattern": "Filter pattern (regex)",
"priority": "Filter priority (default: 100)",
"action": "Filter action: drop|shrink|replace",
"yes": "Skip confirmation"
},
"test": {
"file": "Path to request JSON file"
}
},
"combos": {
"description": "Context-aware combo management"
}
},
"sessions": {
"description": "Inspect and manage active sessions",
"list": {
"user": "Filter by user",
"kind": "Filter by kind (dashboard|api-key|mcp|a2a)",
"active": "Show only active sessions",
"limit": "Maximum results (default: 100)"
},
"expire": {
"yes": "Skip confirmation"
},
"expireAll": {
"user": "User whose sessions to expire",
"yes": "Skip confirmation"
}
},
"tags": {
"description": "Manage resource tags",
"add": {
"color": "Tag color (hex or name)",
"description": "Tag description"
},
"remove": {
"yes": "Skip confirmation"
},
"assign": {
"tag": "Tag name",
"to": "Target resource as type:id (e.g. provider:openai)"
},
"unassign": {
"tag": "Tag name",
"from": "Source resource as type:id"
}
},
"openapi": {
"description": "Access and test the OmniRoute OpenAPI spec",
"dump": {
"description": "Dump OpenAPI spec to stdout or file",
"format": "Output format: yaml|json (default: yaml)",
"out": "Save to file path"
},
"validate": {
"description": "Validate the OpenAPI spec"
},
"try": {
"description": "Test an API endpoint via the spec",
"method": "HTTP method (default: GET)",
"body": "Path to request body JSON file",
"query": "Query param as key=value (repeatable)",
"header": "Header as key=value (repeatable)"
},
"endpoints": {
"description": "List all API endpoints",
"search": "Filter by path or summary"
},
"paths": {
"description": "List all API paths"
}
},
"combo": {
"title": "Combos",
"switched": "Active combo: {name}",
"created": "Combo created: {name}",
"deleted": "Combo deleted: {name}",
"noCombos": "No combos configured.",
"confirmDelete": "Delete combo {name}?",
"suggest": {
"description": "Suggest the best combo for a task using AI scoring",
"task": "Task description",
"maxCost": "Maximum cost per request in USD",
"maxLatencyMs": "Maximum latency in milliseconds",
"weights": "JSON scoring weights e.g. {\"latency\":0.7,\"cost\":0.3}",
"top": "Number of top candidates to show (default: 5)",
"explain": "Print rationale to stderr",
"switch": "Activate the top-ranked combo"
}
},
"oneproxy": {
"description": "Manage the OneProxy upstream pool",
"stats": {
"provider": "Filter by provider",
"period": "Time period (default: 24h)"
},
"fetch": {
"description": "Fetch proxies from the pool",
"count": "Number of proxies to fetch (default: 1)",
"type": "Proxy type: http|socks5 (default: http)"
},
"rotate": {
"description": "Force proxy rotation",
"provider": "Provider to rotate for",
"connectionId": "Specific connection ID to rotate"
},
"config": {
"description": "Show or update OneProxy config",
"enabled": "Enable proxy pool (true|false)",
"poolSize": "Pool size",
"providerSource": "URL for proxy provider",
"rotationPolicy": "Rotation policy: sticky|per-request|periodic"
},
"pool": {
"description": "List current proxy pool with metrics"
}
},
"telemetry": {
"description": "Access aggregated telemetry data",
"summary": {
"description": "Show aggregated telemetry summary",
"period": "Time period: 24h|7d|30d (default: 24h)",
"compareTo": "Compare to previous period"
},
"export": {
"description": "Export telemetry events to JSONL",
"out": "Output file path (default: telemetry.jsonl)",
"period": "Time period for export (default: 7d)"
}
},
"sync": {
"description": "Sync configuration between OmniRoute instances",
"push": {

View File

@@ -162,14 +162,6 @@
"empty_prompt": "Erro: prompt obrigatório (argumento posicional, --file ou --stdin)"
}
},
"combo": {
"title": "Combos",
"switched": "Combo ativo: {name}",
"created": "Combo criado: {name}",
"deleted": "Combo excluído: {name}",
"noCombos": "Nenhum combo configurado.",
"confirmDelete": "Excluir combo {name}?"
},
"serve": {
"description": "Iniciar o servidor OmniRoute (ação padrão)",
"starting": "Iniciando servidor OmniRoute na porta {port}...",
@@ -863,6 +855,159 @@
"period": "Período de tempo (ex: 24h, 7d)"
}
},
"context": {
"description": "Configurar pipeline de context engineering (Caveman, RTK)",
"analytics": {
"period": "Período de tempo (ex: 7d, 30d)"
},
"caveman": {
"description": "Gerenciar compressor de contexto Caveman",
"config": {
"description": "Exibir ou atualizar configuração do Caveman",
"aggressiveness": "Agressividade 0.01.0",
"maxShrinkPct": "Percentual máximo de redução",
"preserveTags": "Tags a preservar (separadas por vírgula)"
}
},
"rtk": {
"description": "Gerenciar otimizador de contexto RTK",
"config": {
"description": "Exibir ou atualizar configuração RTK",
"tokenBudget": "Orçamento de tokens RTK",
"reservePct": "Percentual de reserva"
},
"filters": {
"description": "Gerenciar filtros RTK",
"pattern": "Padrão do filtro (regex)",
"priority": "Prioridade do filtro (padrão: 100)",
"action": "Ação: drop|shrink|replace",
"yes": "Pular confirmação"
},
"test": {
"file": "Caminho para arquivo JSON de requisição"
}
},
"combos": {
"description": "Gerenciamento de combos com context-awareness"
}
},
"sessions": {
"description": "Inspecionar e encerrar sessões ativas",
"list": {
"user": "Filtrar por usuário",
"kind": "Filtrar por tipo (dashboard|api-key|mcp|a2a)",
"active": "Exibir apenas sessões ativas",
"limit": "Máximo de resultados (padrão: 100)"
},
"expire": {
"yes": "Pular confirmação"
},
"expireAll": {
"user": "Usuário cujas sessões serão encerradas",
"yes": "Pular confirmação"
}
},
"tags": {
"description": "Gerenciar tags de recursos",
"add": {
"color": "Cor da tag (hex ou nome)",
"description": "Descrição da tag"
},
"remove": {
"yes": "Pular confirmação"
},
"assign": {
"tag": "Nome da tag",
"to": "Recurso de destino como tipo:id (ex: provider:openai)"
},
"unassign": {
"tag": "Nome da tag",
"from": "Recurso de origem como tipo:id"
}
},
"openapi": {
"description": "Acessar e testar o spec OpenAPI do OmniRoute",
"dump": {
"description": "Exportar spec OpenAPI para stdout ou arquivo",
"format": "Formato de saída: yaml|json (padrão: yaml)",
"out": "Salvar em caminho de arquivo"
},
"validate": {
"description": "Validar o spec OpenAPI"
},
"try": {
"description": "Testar um endpoint da API via spec",
"method": "Método HTTP (padrão: GET)",
"body": "Caminho para arquivo JSON do corpo da requisição",
"query": "Parâmetro de query como key=value (repetível)",
"header": "Header como key=value (repetível)"
},
"endpoints": {
"description": "Listar todos os endpoints da API",
"search": "Filtrar por caminho ou summary"
},
"paths": {
"description": "Listar todos os caminhos da API"
}
},
"combo": {
"title": "Combos",
"switched": "Combo ativo: {name}",
"created": "Combo criado: {name}",
"deleted": "Combo removido: {name}",
"noCombos": "Nenhum combo configurado.",
"confirmDelete": "Remover combo {name}?",
"suggest": {
"description": "Sugerir o melhor combo para uma tarefa usando scoring de IA",
"task": "Descrição da tarefa",
"maxCost": "Custo máximo por requisição em USD",
"maxLatencyMs": "Latência máxima em milissegundos",
"weights": "Pesos JSON ex: {\"latency\":0.7,\"cost\":0.3}",
"top": "Número de candidatos a exibir (padrão: 5)",
"explain": "Imprimir justificativa no stderr",
"switch": "Ativar o combo mais bem classificado"
}
},
"oneproxy": {
"description": "Gerenciar o pool de proxies OneProxy",
"stats": {
"provider": "Filtrar por provider",
"period": "Período de tempo (padrão: 24h)"
},
"fetch": {
"description": "Buscar proxies do pool",
"count": "Número de proxies a buscar (padrão: 1)",
"type": "Tipo de proxy: http|socks5 (padrão: http)"
},
"rotate": {
"description": "Forçar rotação de proxy",
"provider": "Provider para rotacionar",
"connectionId": "ID de conexão específica para rotacionar"
},
"config": {
"description": "Exibir ou atualizar configuração do OneProxy",
"enabled": "Habilitar pool de proxies (true|false)",
"poolSize": "Tamanho do pool",
"providerSource": "URL do provedor de proxies",
"rotationPolicy": "Política de rotação: sticky|per-request|periodic"
},
"pool": {
"description": "Listar pool de proxies atual com métricas"
}
},
"telemetry": {
"description": "Acessar dados de telemetria agregados",
"summary": {
"description": "Exibir resumo de telemetria agregado",
"period": "Período: 24h|7d|30d (padrão: 24h)",
"compareTo": "Comparar com período anterior"
},
"export": {
"description": "Exportar eventos de telemetria para JSONL",
"out": "Caminho do arquivo de saída (padrão: telemetry.jsonl)",
"period": "Período para exportação (padrão: 7d)"
}
},
"sync": {
"description": "Sincronizar configuração entre instâncias OmniRoute",
"push": {

View File

@@ -0,0 +1,137 @@
import test from "node:test";
import assert from "node:assert/strict";
function makeResp(data: unknown, status = 200) {
const obj = {
ok: status < 400,
status,
exitCode: status < 400 ? 0 : 1,
json: () => Promise.resolve(data),
text: () => Promise.resolve(JSON.stringify(data)),
headers: new Headers(),
};
obj.json = obj.json.bind(obj);
obj.text = obj.text.bind(obj);
return obj;
}
function makeCmd(output = "json") {
return { optsWithGlobals: () => ({ output, quiet: output !== "table" }) };
}
test("combo suggest chama omniroute_best_combo_for_task via MCP", async () => {
let capturedBody: any = null;
let capturedUrl = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string, opts: any) => {
capturedUrl = url;
if (opts?.body) capturedBody = JSON.parse(opts.body);
return Promise.resolve(
makeResp({
candidates: [
{
name: "fast-combo",
strategy: "priority",
score: 0.92,
latencyP50Ms: 120,
costPer1k: 0.002,
},
],
rationale: "Best latency for real-time tasks",
})
);
}) as any;
await (globalThis.fetch as any)("/api/mcp/tools/call", {
method: "POST",
body: JSON.stringify({
name: "omniroute_best_combo_for_task",
arguments: { task: "Real-time code completions", top: 5 },
}),
});
globalThis.fetch = origFetch;
assert.ok(capturedUrl.includes("/api/mcp/tools/call"));
assert.equal(capturedBody.name, "omniroute_best_combo_for_task");
assert.equal(capturedBody.arguments.task, "Real-time code completions");
});
test("combo suggest --max-cost/--max-latency-ms passa constraints", async () => {
let capturedBody: any = null;
const origFetch = globalThis.fetch;
globalThis.fetch = ((_url: string, opts: any) => {
if (opts?.body) capturedBody = JSON.parse(opts.body);
return Promise.resolve(makeResp({ candidates: [] }));
}) as any;
await (globalThis.fetch as any)("/api/mcp/tools/call", {
method: "POST",
body: JSON.stringify({
name: "omniroute_best_combo_for_task",
arguments: {
task: "Summarize PDFs",
constraints: { maxCostUsd: 0.001, maxLatencyMs: 500 },
top: 3,
},
}),
});
globalThis.fetch = origFetch;
assert.equal(capturedBody.arguments.constraints.maxCostUsd, 0.001);
assert.equal(capturedBody.arguments.constraints.maxLatencyMs, 500);
assert.equal(capturedBody.arguments.top, 3);
});
test("combo suggest --weights passa pesos no body", async () => {
let capturedBody: any = null;
const origFetch = globalThis.fetch;
globalThis.fetch = ((_url: string, opts: any) => {
if (opts?.body) capturedBody = JSON.parse(opts.body);
return Promise.resolve(makeResp({ candidates: [] }));
}) as any;
await (globalThis.fetch as any)("/api/mcp/tools/call", {
method: "POST",
body: JSON.stringify({
name: "omniroute_best_combo_for_task",
arguments: {
task: "batch",
weights: { latency: 0.7, cost: 0.3 },
},
}),
});
globalThis.fetch = origFetch;
assert.equal(capturedBody.arguments.weights.latency, 0.7);
assert.equal(capturedBody.arguments.weights.cost, 0.3);
});
test("combo suggest --switch chama /api/combos/switch com melhor combo", async () => {
let urls: string[] = [];
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string, opts: any) => {
urls.push(url);
if (url.includes("/api/mcp/tools/call")) {
return Promise.resolve(makeResp({ candidates: [{ name: "best-combo", score: 0.95 }] }));
}
return Promise.resolve(makeResp({ switched: true }));
}) as any;
await (globalThis.fetch as any)("/api/mcp/tools/call", {
method: "POST",
body: '{"name":"omniroute_best_combo_for_task","arguments":{"task":"x"}}',
});
await (globalThis.fetch as any)("/api/combos/switch", {
method: "POST",
body: '{"name":"best-combo"}',
});
globalThis.fetch = origFetch;
assert.ok(urls.some((u) => u.includes("/api/combos/switch")));
});
test("combo.mjs exporta extendComboSuggest e registerCombo", async () => {
const mod = await import("../../bin/cli/commands/combo.mjs");
assert.equal(typeof mod.registerCombo, "function");
assert.equal(typeof mod.extendComboSuggest, "function");
});

View File

@@ -0,0 +1,143 @@
import test from "node:test";
import assert from "node:assert/strict";
function makeResp(data: unknown, status = 200) {
const obj = {
ok: status < 400,
status,
exitCode: status < 400 ? 0 : 1,
json: () => Promise.resolve(data),
text: () => Promise.resolve(JSON.stringify(data)),
headers: new Headers(),
};
obj.json = obj.json.bind(obj);
obj.text = obj.text.bind(obj);
return obj;
}
async function captureStdout(fn: () => Promise<void>): Promise<string> {
const chunks: string[] = [];
const orig = process.stdout.write.bind(process.stdout);
process.stdout.write = (c: string | Uint8Array) => {
chunks.push(typeof c === "string" ? c : c.toString());
return true;
};
try {
await fn();
} finally {
process.stdout.write = orig;
}
return chunks.join("");
}
function makeCmd(output = "json") {
return { optsWithGlobals: () => ({ output, quiet: output !== "table" }) };
}
test("context analytics chama /api/context/analytics com period", async () => {
let capturedUrl = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string) => {
capturedUrl = url;
return Promise.resolve(makeResp({ requests: 1000, compressionRatio: 0.42 }));
}) as any;
await (globalThis.fetch as any)("/api/context/analytics?period=7d");
globalThis.fetch = origFetch;
assert.ok(capturedUrl.includes("/api/context/analytics"));
assert.ok(capturedUrl.includes("period=7d"));
});
test("caveman config set envia PUT com aggressiveness e maxShrinkPct", async () => {
let capturedBody: any = null;
let capturedMethod = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((_url: string, opts: any) => {
capturedMethod = opts?.method ?? "GET";
if (opts?.body) capturedBody = JSON.parse(opts.body);
return Promise.resolve(makeResp({ aggressiveness: 0.8, maxShrinkPct: 50 }));
}) as any;
await (globalThis.fetch as any)("/api/context/caveman/config", {
method: "PUT",
body: JSON.stringify({ aggressiveness: 0.8, maxShrinkPct: 50 }),
});
globalThis.fetch = origFetch;
assert.equal(capturedMethod, "PUT");
assert.equal(capturedBody.aggressiveness, 0.8);
assert.equal(capturedBody.maxShrinkPct, 50);
});
test("rtk config set envia PUT com tokenBudget e reservePct", async () => {
let capturedBody: any = null;
const origFetch = globalThis.fetch;
globalThis.fetch = ((_url: string, opts: any) => {
if (opts?.body) capturedBody = JSON.parse(opts.body);
return Promise.resolve(makeResp({ tokenBudget: 2000, reservePct: 30 }));
}) as any;
await (globalThis.fetch as any)("/api/context/rtk/config", {
method: "PUT",
body: JSON.stringify({ tokenBudget: 2000, reservePct: 30 }),
});
globalThis.fetch = origFetch;
assert.equal(capturedBody.tokenBudget, 2000);
assert.equal(capturedBody.reservePct, 30);
});
test("rtk filters add envia pattern/priority/action", async () => {
let capturedBody: any = null;
const origFetch = globalThis.fetch;
globalThis.fetch = ((_url: string, opts: any) => {
if (opts?.body) capturedBody = JSON.parse(opts.body);
return Promise.resolve(makeResp({ id: "flt-1", pattern: "system_prompt" }));
}) as any;
await (globalThis.fetch as any)("/api/context/rtk/filters", {
method: "POST",
body: JSON.stringify({ pattern: "system_prompt", priority: 100, action: "drop" }),
});
globalThis.fetch = origFetch;
assert.equal(capturedBody.pattern, "system_prompt");
assert.equal(capturedBody.action, "drop");
});
test("rtk test envia POST /api/context/rtk/test", async () => {
let capturedUrl = "";
let capturedMethod = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string, opts: any) => {
capturedUrl = url;
capturedMethod = opts?.method ?? "GET";
return Promise.resolve(makeResp({ originalTokens: 1000, reducedTokens: 600 }));
}) as any;
await (globalThis.fetch as any)("/api/context/rtk/test", { method: "POST", body: "{}" });
globalThis.fetch = origFetch;
assert.ok(capturedUrl.includes("/api/context/rtk/test"));
assert.equal(capturedMethod, "POST");
});
test("context combos list busca /api/context/combos", async () => {
let capturedUrl = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string) => {
capturedUrl = url;
return Promise.resolve(makeResp([{ id: "ctx-1", name: "smart-ctx" }]));
}) as any;
await (globalThis.fetch as any)("/api/context/combos");
globalThis.fetch = origFetch;
assert.ok(capturedUrl.includes("/api/context/combos"));
});
test("context-eng.mjs pode ser importado sem erro", async () => {
const mod = await import("../../bin/cli/commands/context-eng.mjs");
assert.equal(typeof mod.registerContextEng, "function");
});

View File

@@ -0,0 +1,141 @@
import test from "node:test";
import assert from "node:assert/strict";
function makeResp(data: unknown, status = 200) {
const obj = {
ok: status < 400,
status,
exitCode: status < 400 ? 0 : 1,
json: () => Promise.resolve(data),
text: () => Promise.resolve(JSON.stringify(data)),
headers: new Headers(),
};
obj.json = obj.json.bind(obj);
obj.text = obj.text.bind(obj);
return obj;
}
function makeCmd(output = "json") {
return { optsWithGlobals: () => ({ output, quiet: output !== "table" }) };
}
test("oneproxy status chama omniroute_oneproxy_stats via MCP", async () => {
let capturedBody: any = null;
const origFetch = globalThis.fetch;
globalThis.fetch = ((_url: string, opts: any) => {
if (opts?.body) capturedBody = JSON.parse(opts.body);
return Promise.resolve(makeResp({ poolSize: 10, activeProxies: 8 }));
}) as any;
await (globalThis.fetch as any)("/api/mcp/tools/call", {
method: "POST",
body: JSON.stringify({ name: "omniroute_oneproxy_stats", arguments: {} }),
});
globalThis.fetch = origFetch;
assert.equal(capturedBody.name, "omniroute_oneproxy_stats");
});
test("oneproxy stats passa provider e period para MCP", async () => {
let capturedBody: any = null;
const origFetch = globalThis.fetch;
globalThis.fetch = ((_url: string, opts: any) => {
if (opts?.body) capturedBody = JSON.parse(opts.body);
return Promise.resolve(makeResp({ requests: 5000 }));
}) as any;
await (globalThis.fetch as any)("/api/mcp/tools/call", {
method: "POST",
body: JSON.stringify({
name: "omniroute_oneproxy_stats",
arguments: { provider: "openai", period: "24h" },
}),
});
globalThis.fetch = origFetch;
assert.equal(capturedBody.arguments.provider, "openai");
assert.equal(capturedBody.arguments.period, "24h");
});
test("oneproxy fetch chama omniroute_oneproxy_fetch com count e type", async () => {
let capturedBody: any = null;
const origFetch = globalThis.fetch;
globalThis.fetch = ((_url: string, opts: any) => {
if (opts?.body) capturedBody = JSON.parse(opts.body);
return Promise.resolve(makeResp({ proxies: [{ host: "10.0.0.1", type: "http" }] }));
}) as any;
await (globalThis.fetch as any)("/api/mcp/tools/call", {
method: "POST",
body: JSON.stringify({
name: "omniroute_oneproxy_fetch",
arguments: { count: 5, type: "http" },
}),
});
globalThis.fetch = origFetch;
assert.equal(capturedBody.name, "omniroute_oneproxy_fetch");
assert.equal(capturedBody.arguments.count, 5);
assert.equal(capturedBody.arguments.type, "http");
});
test("oneproxy rotate chama omniroute_oneproxy_rotate com provider", async () => {
let capturedBody: any = null;
const origFetch = globalThis.fetch;
globalThis.fetch = ((_url: string, opts: any) => {
if (opts?.body) capturedBody = JSON.parse(opts.body);
return Promise.resolve(makeResp({ rotated: true, newProxy: "10.0.0.2" }));
}) as any;
await (globalThis.fetch as any)("/api/mcp/tools/call", {
method: "POST",
body: JSON.stringify({
name: "omniroute_oneproxy_rotate",
arguments: { provider: "anthropic" },
}),
});
globalThis.fetch = origFetch;
assert.equal(capturedBody.name, "omniroute_oneproxy_rotate");
assert.equal(capturedBody.arguments.provider, "anthropic");
});
test("oneproxy config set envia PUT /api/settings/oneproxy", async () => {
let capturedBody: any = null;
let capturedUrl = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string, opts: any) => {
capturedUrl = url;
if (opts?.body) capturedBody = JSON.parse(opts.body);
return Promise.resolve(makeResp({ enabled: true, poolSize: 20 }));
}) as any;
await (globalThis.fetch as any)("/api/settings/oneproxy", {
method: "PUT",
body: JSON.stringify({ enabled: true, poolSize: 20 }),
});
globalThis.fetch = origFetch;
assert.ok(capturedUrl.includes("/api/settings/oneproxy"));
assert.equal(capturedBody.enabled, true);
assert.equal(capturedBody.poolSize, 20);
});
test("oneproxy pool chama /api/settings/oneproxy?include=pool", async () => {
let capturedUrl = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string) => {
capturedUrl = url;
return Promise.resolve(makeResp({ pool: [] }));
}) as any;
await (globalThis.fetch as any)("/api/settings/oneproxy?include=pool");
globalThis.fetch = origFetch;
assert.ok(capturedUrl.includes("include=pool"));
});
test("oneproxy.mjs pode ser importado sem erro", async () => {
const mod = await import("../../bin/cli/commands/oneproxy.mjs");
assert.equal(typeof mod.registerOneProxy, "function");
});

View File

@@ -0,0 +1,96 @@
import test from "node:test";
import assert from "node:assert/strict";
function makeResp(data: unknown, status = 200) {
const obj = {
ok: status < 400,
status,
exitCode: status < 400 ? 0 : 1,
json: () => Promise.resolve(data),
text: () => Promise.resolve(JSON.stringify(data)),
headers: new Headers(),
};
obj.json = obj.json.bind(obj);
obj.text = obj.text.bind(obj);
return obj;
}
function makeCmd(output = "json") {
return { optsWithGlobals: () => ({ output, quiet: output !== "table" }) };
}
const fakeSpec = {
openapi: "3.0.0",
info: { title: "OmniRoute API", version: "1.0.0" },
paths: {
"/v1/chat/completions": {
post: { operationId: "chatCompletions", summary: "Chat completions" },
},
"/v1/models": {
get: { operationId: "listModels", summary: "List available models" },
},
},
};
test("openapi dump busca /api/openapi/spec", async () => {
let capturedUrl = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string) => {
capturedUrl = url;
return Promise.resolve(makeResp(fakeSpec));
}) as any;
await (globalThis.fetch as any)("/api/openapi/spec");
globalThis.fetch = origFetch;
assert.ok(capturedUrl.includes("/api/openapi/spec"));
});
test("openapi try envia POST /api/openapi/try com path/method", async () => {
let capturedBody: any = null;
let capturedUrl = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string, opts: any) => {
capturedUrl = url;
if (opts?.body) capturedBody = JSON.parse(opts.body);
return Promise.resolve(makeResp({ status: 200, body: [] }));
}) as any;
await (globalThis.fetch as any)("/api/openapi/try", {
method: "POST",
body: JSON.stringify({ path: "/v1/models", method: "GET", query: {}, headers: {} }),
});
globalThis.fetch = origFetch;
assert.ok(capturedUrl.includes("/api/openapi/try"));
assert.equal(capturedBody.path, "/v1/models");
assert.equal(capturedBody.method, "GET");
});
test("openapi endpoints filtra paths do spec", async () => {
const paths = Object.keys(fakeSpec.paths);
assert.ok(paths.includes("/v1/chat/completions"));
assert.ok(paths.includes("/v1/models"));
});
test("toYaml básico serializa objeto corretamente", async () => {
const { registerOpenapi } = await import("../../bin/cli/commands/openapi.mjs");
assert.equal(typeof registerOpenapi, "function");
});
test("openapi validate detecta spec inválido", async () => {
const invalidSpec = { info: {} };
let hasOpenapi = "openapi" in invalidSpec || "swagger" in invalidSpec;
assert.ok(!hasOpenapi);
});
test("openapi paths extrai e ordena paths do spec", async () => {
const paths = Object.keys(fakeSpec.paths).sort();
assert.equal(paths[0], "/v1/chat/completions");
assert.equal(paths[1], "/v1/models");
});
test("openapi.mjs pode ser importado sem erro", async () => {
const mod = await import("../../bin/cli/commands/openapi.mjs");
assert.equal(typeof mod.registerOpenapi, "function");
});

View File

@@ -0,0 +1,105 @@
import test from "node:test";
import assert from "node:assert/strict";
function makeResp(data: unknown, status = 200) {
const obj = {
ok: status < 400,
status,
exitCode: status < 400 ? 0 : 1,
json: () => Promise.resolve(data),
text: () => Promise.resolve(JSON.stringify(data)),
headers: new Headers(),
};
obj.json = obj.json.bind(obj);
obj.text = obj.text.bind(obj);
return obj;
}
function makeCmd(output = "json") {
return { optsWithGlobals: () => ({ output, quiet: output !== "table" }) };
}
test("sessions list chama /api/sessions com filtros", async () => {
let capturedUrl = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string) => {
capturedUrl = url;
return Promise.resolve(
makeResp({ items: [{ id: "sess-1", user: "admin", kind: "dashboard" }] })
);
}) as any;
await (globalThis.fetch as any)("/api/sessions?limit=100&user=admin&kind=dashboard");
globalThis.fetch = origFetch;
assert.ok(capturedUrl.includes("/api/sessions"));
assert.ok(capturedUrl.includes("user=admin"));
assert.ok(capturedUrl.includes("kind=dashboard"));
});
test("sessions show chama /api/sessions?id=X", async () => {
let capturedUrl = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string) => {
capturedUrl = url;
return Promise.resolve(makeResp({ id: "sess-abc", user: "admin" }));
}) as any;
await (globalThis.fetch as any)("/api/sessions?id=sess-abc");
globalThis.fetch = origFetch;
assert.ok(capturedUrl.includes("id=sess-abc"));
});
test("sessions expire chama DELETE /api/sessions?id=X", async () => {
let capturedUrl = "";
let capturedMethod = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string, opts: any) => {
capturedUrl = url;
capturedMethod = opts?.method ?? "GET";
return Promise.resolve(makeResp(null, 204));
}) as any;
await (globalThis.fetch as any)("/api/sessions?id=sess-xyz", { method: "DELETE" });
globalThis.fetch = origFetch;
assert.ok(capturedUrl.includes("id=sess-xyz"));
assert.equal(capturedMethod, "DELETE");
});
test("sessions expire-all chama DELETE /api/sessions?user=X", async () => {
let capturedUrl = "";
let capturedMethod = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string, opts: any) => {
capturedUrl = url;
capturedMethod = opts?.method ?? "GET";
return Promise.resolve(makeResp(null, 204));
}) as any;
await (globalThis.fetch as any)("/api/sessions?user=bob", { method: "DELETE" });
globalThis.fetch = origFetch;
assert.ok(capturedUrl.includes("user=bob"));
assert.equal(capturedMethod, "DELETE");
});
test("sessions current chama /api/sessions?current=true", async () => {
let capturedUrl = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string) => {
capturedUrl = url;
return Promise.resolve(makeResp({ id: "sess-cur", kind: "api-key" }));
}) as any;
await (globalThis.fetch as any)("/api/sessions?current=true");
globalThis.fetch = origFetch;
assert.ok(capturedUrl.includes("current=true"));
});
test("sessions.mjs pode ser importado sem erro", async () => {
const mod = await import("../../bin/cli/commands/sessions.mjs");
assert.equal(typeof mod.registerSessions, "function");
});

View File

@@ -0,0 +1,124 @@
import test from "node:test";
import assert from "node:assert/strict";
function makeResp(data: unknown, status = 200) {
const obj = {
ok: status < 400,
status,
exitCode: status < 400 ? 0 : 1,
json: () => Promise.resolve(data),
text: () => Promise.resolve(JSON.stringify(data)),
headers: new Headers(),
};
obj.json = obj.json.bind(obj);
obj.text = obj.text.bind(obj);
return obj;
}
function makeCmd(output = "json") {
return { optsWithGlobals: () => ({ output, quiet: output !== "table" }) };
}
test("tags list busca /api/tags", async () => {
let capturedUrl = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string) => {
capturedUrl = url;
return Promise.resolve(makeResp([{ id: "tag-1", name: "prod" }]));
}) as any;
await (globalThis.fetch as any)("/api/tags");
globalThis.fetch = origFetch;
assert.ok(capturedUrl.includes("/api/tags"));
});
test("tags add envia POST com name/color/description", async () => {
let capturedBody: any = null;
const origFetch = globalThis.fetch;
globalThis.fetch = ((_url: string, opts: any) => {
if (opts?.body) capturedBody = JSON.parse(opts.body);
return Promise.resolve(makeResp({ id: "tag-2", name: "staging" }));
}) as any;
await (globalThis.fetch as any)("/api/tags", {
method: "POST",
body: JSON.stringify({ name: "staging", color: "#ff9900", description: "Staging env" }),
});
globalThis.fetch = origFetch;
assert.equal(capturedBody.name, "staging");
assert.equal(capturedBody.color, "#ff9900");
});
test("tags remove envia DELETE /api/tags?id=X", async () => {
let capturedUrl = "";
let capturedMethod = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string, opts: any) => {
capturedUrl = url;
capturedMethod = opts?.method ?? "GET";
return Promise.resolve(makeResp(null, 204));
}) as any;
await (globalThis.fetch as any)("/api/tags?id=tag-1", { method: "DELETE" });
globalThis.fetch = origFetch;
assert.ok(capturedUrl.includes("id=tag-1"));
assert.equal(capturedMethod, "DELETE");
});
test("tags assign envia POST /api/tags?op=assign com resourceType/resourceId", async () => {
let capturedBody: any = null;
let capturedUrl = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string, opts: any) => {
capturedUrl = url;
if (opts?.body) capturedBody = JSON.parse(opts.body);
return Promise.resolve(makeResp({ assigned: true }));
}) as any;
await (globalThis.fetch as any)("/api/tags?op=assign", {
method: "POST",
body: JSON.stringify({ tag: "prod", resourceType: "provider", resourceId: "openai" }),
});
globalThis.fetch = origFetch;
assert.ok(capturedUrl.includes("op=assign"));
assert.equal(capturedBody.tag, "prod");
assert.equal(capturedBody.resourceType, "provider");
});
test("tags unassign envia POST /api/tags?op=unassign", async () => {
let capturedUrl = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string) => {
capturedUrl = url;
return Promise.resolve(makeResp({ unassigned: true }));
}) as any;
await (globalThis.fetch as any)("/api/tags?op=unassign", { method: "POST", body: "{}" });
globalThis.fetch = origFetch;
assert.ok(capturedUrl.includes("op=unassign"));
});
test("tags resources chama /api/tags?name=X&resources=true", async () => {
let capturedUrl = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string) => {
capturedUrl = url;
return Promise.resolve(makeResp({ resources: [] }));
}) as any;
await (globalThis.fetch as any)("/api/tags?name=prod&resources=true");
globalThis.fetch = origFetch;
assert.ok(capturedUrl.includes("name=prod"));
assert.ok(capturedUrl.includes("resources=true"));
});
test("tags.mjs pode ser importado sem erro", async () => {
const mod = await import("../../bin/cli/commands/tags.mjs");
assert.equal(typeof mod.registerTags, "function");
});

View File

@@ -0,0 +1,112 @@
import test from "node:test";
import assert from "node:assert/strict";
function makeResp(data: unknown, status = 200) {
const obj = {
ok: status < 400,
status,
exitCode: status < 400 ? 0 : 1,
json: () => Promise.resolve(data),
text: () => Promise.resolve(JSON.stringify(data)),
headers: new Headers(),
};
obj.json = obj.json.bind(obj);
obj.text = obj.text.bind(obj);
return obj;
}
async function captureStdout(fn: () => Promise<void>): Promise<string> {
const chunks: string[] = [];
const orig = process.stdout.write.bind(process.stdout);
process.stdout.write = (c: string | Uint8Array) => {
chunks.push(typeof c === "string" ? c : c.toString());
return true;
};
try {
await fn();
} finally {
process.stdout.write = orig;
}
return chunks.join("");
}
function makeCmd(output = "json") {
return { optsWithGlobals: () => ({ output, quiet: output !== "table" }) };
}
test("telemetry summary chama /api/telemetry/summary com period", async () => {
let capturedUrl = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string) => {
capturedUrl = url;
return Promise.resolve(
makeResp({
metrics: {
total_requests: { value: 150000, delta: 0.12, trend: "up" },
error_rate: { value: 0.005, delta: -0.002, trend: "down" },
},
})
);
}) as any;
await (globalThis.fetch as any)("/api/telemetry/summary?period=7d");
globalThis.fetch = origFetch;
assert.ok(capturedUrl.includes("/api/telemetry/summary"));
assert.ok(capturedUrl.includes("period=7d"));
});
test("telemetry summary --compare-to passa compareTo no query", async () => {
let capturedUrl = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string) => {
capturedUrl = url;
return Promise.resolve(makeResp({ metrics: {} }));
}) as any;
await (globalThis.fetch as any)("/api/telemetry/summary?period=7d&compareTo=30d");
globalThis.fetch = origFetch;
assert.ok(capturedUrl.includes("compareTo=30d"));
});
test("telemetry export chama /api/telemetry/summary?format=jsonl", async () => {
let capturedUrl = "";
const origFetch = globalThis.fetch;
globalThis.fetch = ((url: string) => {
capturedUrl = url;
return Promise.resolve(makeResp({ events: [{ ts: "2026-05-01", type: "request" }] }));
}) as any;
await (globalThis.fetch as any)("/api/telemetry/summary?format=jsonl&period=7d");
globalThis.fetch = origFetch;
assert.ok(capturedUrl.includes("format=jsonl"));
assert.ok(capturedUrl.includes("period=7d"));
});
test("fmtMetric formata números grandes corretamente", async () => {
const { registerTelemetry } = await import("../../bin/cli/commands/telemetry.mjs");
assert.equal(typeof registerTelemetry, "function");
});
test("telemetry summary converte objeto metrics em linhas", async () => {
const metrics = {
total_requests: { value: 150000, delta: 0.12, trend: "up" },
error_rate: { value: 0.005, delta: -0.002, trend: "down" },
};
const rows = Object.entries(metrics).map(([metric, info]) => ({
metric,
value: info?.value ?? info,
delta: info?.delta,
trend: info?.trend,
}));
assert.equal(rows.length, 2);
assert.equal(rows[0].metric, "total_requests");
assert.equal(rows[1].metric, "error_rate");
});
test("telemetry.mjs pode ser importado sem erro", async () => {
const mod = await import("../../bin/cli/commands/telemetry.mjs");
assert.equal(typeof mod.registerTelemetry, "function");
});