opencara 0.15.3 → 0.15.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +253 -65
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command3 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/agent.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -204,10 +204,10 @@ function parseAgents(data) {
|
|
|
204
204
|
`\u26A0 Config warning: agents[${i}].tool "${resolvedTool}" is deprecated, using "${alias}" instead`
|
|
205
205
|
);
|
|
206
206
|
resolvedTool = alias;
|
|
207
|
-
} else {
|
|
207
|
+
} else if (typeof obj.command !== "string") {
|
|
208
208
|
const toolNames = [...KNOWN_TOOL_NAMES].join(", ");
|
|
209
209
|
console.warn(
|
|
210
|
-
`\u26A0 Config warning: agents[${i}].tool "${resolvedTool}" not in registry (known: ${toolNames}), skipping agent`
|
|
210
|
+
`\u26A0 Config warning: agents[${i}].tool "${resolvedTool}" not in registry (known: ${toolNames}) and no custom command provided, skipping agent`
|
|
211
211
|
);
|
|
212
212
|
continue;
|
|
213
213
|
}
|
|
@@ -469,19 +469,36 @@ var HttpError = class extends Error {
|
|
|
469
469
|
this.name = "HttpError";
|
|
470
470
|
}
|
|
471
471
|
};
|
|
472
|
+
var UpgradeRequiredError = class extends Error {
|
|
473
|
+
constructor(currentVersion, minimumVersion) {
|
|
474
|
+
const minPart = minimumVersion ? ` Minimum required: ${minimumVersion}` : "";
|
|
475
|
+
super(
|
|
476
|
+
`Your CLI version (${currentVersion}) is outdated.${minPart} Please upgrade: npm update -g opencara`
|
|
477
|
+
);
|
|
478
|
+
this.currentVersion = currentVersion;
|
|
479
|
+
this.minimumVersion = minimumVersion;
|
|
480
|
+
this.name = "UpgradeRequiredError";
|
|
481
|
+
}
|
|
482
|
+
};
|
|
472
483
|
var ApiClient = class {
|
|
473
484
|
constructor(baseUrl, debugOrOptions) {
|
|
474
485
|
this.baseUrl = baseUrl;
|
|
475
486
|
if (typeof debugOrOptions === "object" && debugOrOptions !== null) {
|
|
476
487
|
this.debug = debugOrOptions.debug ?? process.env.OPENCARA_DEBUG === "1";
|
|
477
488
|
this.apiKey = debugOrOptions.apiKey ?? null;
|
|
489
|
+
this.cliVersion = debugOrOptions.cliVersion ?? null;
|
|
490
|
+
this.versionOverride = debugOrOptions.versionOverride ?? null;
|
|
478
491
|
} else {
|
|
479
492
|
this.debug = debugOrOptions ?? process.env.OPENCARA_DEBUG === "1";
|
|
480
493
|
this.apiKey = null;
|
|
494
|
+
this.cliVersion = null;
|
|
495
|
+
this.versionOverride = null;
|
|
481
496
|
}
|
|
482
497
|
}
|
|
483
498
|
debug;
|
|
484
499
|
apiKey;
|
|
500
|
+
cliVersion;
|
|
501
|
+
versionOverride;
|
|
485
502
|
log(msg) {
|
|
486
503
|
if (this.debug) console.debug(`[ApiClient] ${msg}`);
|
|
487
504
|
}
|
|
@@ -492,6 +509,12 @@ var ApiClient = class {
|
|
|
492
509
|
if (this.apiKey) {
|
|
493
510
|
h["Authorization"] = `Bearer ${this.apiKey}`;
|
|
494
511
|
}
|
|
512
|
+
if (this.cliVersion) {
|
|
513
|
+
h["X-OpenCara-CLI-Version"] = this.cliVersion;
|
|
514
|
+
}
|
|
515
|
+
if (this.versionOverride) {
|
|
516
|
+
h["Cloudflare-Workers-Version-Overrides"] = this.versionOverride;
|
|
517
|
+
}
|
|
495
518
|
return h;
|
|
496
519
|
}
|
|
497
520
|
async get(path6) {
|
|
@@ -515,15 +538,22 @@ var ApiClient = class {
|
|
|
515
538
|
if (!res.ok) {
|
|
516
539
|
let message = `HTTP ${res.status}`;
|
|
517
540
|
let errorCode;
|
|
541
|
+
let minimumVersion;
|
|
518
542
|
try {
|
|
519
543
|
const body = await res.json();
|
|
520
544
|
if (body.error && typeof body.error === "object" && "code" in body.error) {
|
|
521
545
|
errorCode = body.error.code;
|
|
522
546
|
message = body.error.message;
|
|
523
547
|
}
|
|
548
|
+
if (body.minimum_version) {
|
|
549
|
+
minimumVersion = body.minimum_version;
|
|
550
|
+
}
|
|
524
551
|
} catch {
|
|
525
552
|
}
|
|
526
553
|
this.log(`${res.status} ${message} (${path6})`);
|
|
554
|
+
if (res.status === 426) {
|
|
555
|
+
throw new UpgradeRequiredError(this.cliVersion ?? "unknown", minimumVersion);
|
|
556
|
+
}
|
|
527
557
|
throw new HttpError(res.status, message, errorCode);
|
|
528
558
|
}
|
|
529
559
|
this.log(`${res.status} OK (${path6})`);
|
|
@@ -1601,6 +1631,7 @@ var icons = {
|
|
|
1601
1631
|
success: pc.green("\u2713"),
|
|
1602
1632
|
running: pc.blue("\u25B6"),
|
|
1603
1633
|
stop: pc.red("\u25A0"),
|
|
1634
|
+
info: pc.blue("\u2139"),
|
|
1604
1635
|
warn: pc.yellow("\u26A0"),
|
|
1605
1636
|
error: pc.red("\u2717")
|
|
1606
1637
|
};
|
|
@@ -1798,6 +1829,11 @@ async function pollLoop(client, agentId, reviewDeps, consumptionDeps, agentInfo,
|
|
|
1798
1829
|
}
|
|
1799
1830
|
} catch (err) {
|
|
1800
1831
|
if (signal?.aborted) break;
|
|
1832
|
+
if (err instanceof UpgradeRequiredError) {
|
|
1833
|
+
logWarn(`${icons.warn} ${err.message}`);
|
|
1834
|
+
process.exitCode = 1;
|
|
1835
|
+
break;
|
|
1836
|
+
}
|
|
1801
1837
|
agentSession.errorsEncountered++;
|
|
1802
1838
|
if (err instanceof HttpError && (err.status === 401 || err.status === 403)) {
|
|
1803
1839
|
consecutiveAuthErrors++;
|
|
@@ -2212,8 +2248,8 @@ async function executeSummaryTask(client, agentId, taskId, owner, repo, prNumber
|
|
|
2212
2248
|
}
|
|
2213
2249
|
const summaryReviews = reviews.map((r) => ({
|
|
2214
2250
|
agentId: r.agent_id,
|
|
2215
|
-
model: "unknown",
|
|
2216
|
-
tool: "unknown",
|
|
2251
|
+
model: r.model ?? "unknown",
|
|
2252
|
+
tool: r.tool ?? "unknown",
|
|
2217
2253
|
review: r.review_text,
|
|
2218
2254
|
verdict: r.verdict
|
|
2219
2255
|
}));
|
|
@@ -2319,7 +2355,11 @@ function sleep2(ms, signal) {
|
|
|
2319
2355
|
});
|
|
2320
2356
|
}
|
|
2321
2357
|
async function startAgent(agentId, platformUrl, agentInfo, reviewDeps, consumptionDeps, options) {
|
|
2322
|
-
const client = new ApiClient(platformUrl, {
|
|
2358
|
+
const client = new ApiClient(platformUrl, {
|
|
2359
|
+
apiKey: options?.apiKey,
|
|
2360
|
+
cliVersion: "0.15.6",
|
|
2361
|
+
versionOverride: options?.versionOverride
|
|
2362
|
+
});
|
|
2323
2363
|
const session = consumptionDeps?.session ?? createSessionTracker();
|
|
2324
2364
|
const usageTracker = consumptionDeps?.usageTracker ?? new UsageTracker();
|
|
2325
2365
|
const usageLimits = options?.usageLimits ?? {
|
|
@@ -2337,6 +2377,9 @@ async function startAgent(agentId, platformUrl, agentInfo, reviewDeps, consumpti
|
|
|
2337
2377
|
const agentSession = createAgentSession();
|
|
2338
2378
|
log(`${icons.start} Agent started (polling ${platformUrl})`);
|
|
2339
2379
|
log(`Model: ${agentInfo.model} | Tool: ${agentInfo.tool}`);
|
|
2380
|
+
if (options?.versionOverride) {
|
|
2381
|
+
log(`${icons.info} Version override active: ${options.versionOverride}`);
|
|
2382
|
+
}
|
|
2340
2383
|
if (!reviewDeps) {
|
|
2341
2384
|
logError(`${icons.error} No review command configured. Set command in config.yml`);
|
|
2342
2385
|
return;
|
|
@@ -2407,6 +2450,7 @@ async function startAgentRouter() {
|
|
|
2407
2450
|
const tool = agentConfig?.tool ?? "unknown";
|
|
2408
2451
|
const label = agentConfig?.name ?? "agent[0]";
|
|
2409
2452
|
const roles = agentConfig ? computeRoles(agentConfig) : void 0;
|
|
2453
|
+
const versionOverride = process.env.OPENCARA_VERSION_OVERRIDE || null;
|
|
2410
2454
|
await startAgent(
|
|
2411
2455
|
agentId,
|
|
2412
2456
|
config.platformUrl,
|
|
@@ -2428,12 +2472,13 @@ async function startAgentRouter() {
|
|
|
2428
2472
|
githubUsername,
|
|
2429
2473
|
label,
|
|
2430
2474
|
apiKey: config.apiKey,
|
|
2431
|
-
usageLimits: config.usageLimits
|
|
2475
|
+
usageLimits: config.usageLimits,
|
|
2476
|
+
versionOverride
|
|
2432
2477
|
}
|
|
2433
2478
|
);
|
|
2434
2479
|
router.stop();
|
|
2435
2480
|
}
|
|
2436
|
-
function startAgentByIndex(config, agentIndex, pollIntervalMs, auth, githubUsername) {
|
|
2481
|
+
function startAgentByIndex(config, agentIndex, pollIntervalMs, auth, githubUsername, versionOverride) {
|
|
2437
2482
|
const agentId = crypto.randomUUID();
|
|
2438
2483
|
let commandTemplate;
|
|
2439
2484
|
let agentConfig;
|
|
@@ -2496,7 +2541,8 @@ function startAgentByIndex(config, agentIndex, pollIntervalMs, auth, githubUsern
|
|
|
2496
2541
|
githubUsername,
|
|
2497
2542
|
label,
|
|
2498
2543
|
apiKey: config.apiKey,
|
|
2499
|
-
usageLimits: config.usageLimits
|
|
2544
|
+
usageLimits: config.usageLimits,
|
|
2545
|
+
versionOverride
|
|
2500
2546
|
}
|
|
2501
2547
|
).finally(() => {
|
|
2502
2548
|
routerRelay?.stop();
|
|
@@ -2504,75 +2550,217 @@ function startAgentByIndex(config, agentIndex, pollIntervalMs, auth, githubUsern
|
|
|
2504
2550
|
return agentPromise;
|
|
2505
2551
|
}
|
|
2506
2552
|
var agentCommand = new Command("agent").description("Manage review agents");
|
|
2507
|
-
agentCommand.command("start").description("Start agents in polling mode").option("--poll-interval <seconds>", "Poll interval in seconds", "10").option("--agent <index>", "Agent index from config.yml (0-based)", "0").option("--all", "Start all configured agents concurrently").
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2553
|
+
agentCommand.command("start").description("Start agents in polling mode").option("--poll-interval <seconds>", "Poll interval in seconds", "10").option("--agent <index>", "Agent index from config.yml (0-based)", "0").option("--all", "Start all configured agents concurrently").option(
|
|
2554
|
+
"--version-override <value>",
|
|
2555
|
+
"Cloudflare Workers version override (e.g. opencara-server=abc123)"
|
|
2556
|
+
).action(
|
|
2557
|
+
async (opts) => {
|
|
2558
|
+
const config = loadConfig();
|
|
2559
|
+
const pollIntervalMs = parseInt(opts.pollInterval, 10) * 1e3;
|
|
2560
|
+
const versionOverride = opts.versionOverride || process.env.OPENCARA_VERSION_OVERRIDE || null;
|
|
2561
|
+
const configToken = resolveGithubToken(void 0, config.githubToken);
|
|
2562
|
+
const auth = resolveGithubToken2(configToken);
|
|
2563
|
+
logAuthMethod(auth.method, console.log.bind(console));
|
|
2564
|
+
const githubUsername = config.githubUsername ?? await resolveGithubUsername(auth.token) ?? void 0;
|
|
2565
|
+
if (githubUsername) {
|
|
2566
|
+
console.log(`GitHub identity: ${githubUsername}`);
|
|
2567
|
+
}
|
|
2568
|
+
if (opts.all) {
|
|
2569
|
+
if (!config.agents || config.agents.length === 0) {
|
|
2570
|
+
console.error("No agents configured in ~/.opencara/config.yml");
|
|
2571
|
+
process.exit(1);
|
|
2572
|
+
return;
|
|
2573
|
+
}
|
|
2574
|
+
console.log(`Starting ${config.agents.length} agent(s)...`);
|
|
2575
|
+
const promises = [];
|
|
2576
|
+
let startFailed = false;
|
|
2577
|
+
for (let i = 0; i < config.agents.length; i++) {
|
|
2578
|
+
const p = startAgentByIndex(
|
|
2579
|
+
config,
|
|
2580
|
+
i,
|
|
2581
|
+
pollIntervalMs,
|
|
2582
|
+
auth,
|
|
2583
|
+
githubUsername,
|
|
2584
|
+
versionOverride
|
|
2585
|
+
);
|
|
2586
|
+
if (p) {
|
|
2587
|
+
promises.push(p);
|
|
2588
|
+
} else {
|
|
2589
|
+
startFailed = true;
|
|
2590
|
+
}
|
|
2591
|
+
}
|
|
2592
|
+
if (promises.length === 0) {
|
|
2593
|
+
console.error("No agents could be started. Check your config.");
|
|
2594
|
+
process.exit(1);
|
|
2595
|
+
return;
|
|
2596
|
+
}
|
|
2597
|
+
if (startFailed) {
|
|
2598
|
+
console.error(
|
|
2599
|
+
"One or more agents could not start (see warnings above). Continuing with the rest."
|
|
2600
|
+
);
|
|
2601
|
+
}
|
|
2602
|
+
console.log(`${promises.length} agent(s) running. Press Ctrl+C to stop all.
|
|
2603
|
+
`);
|
|
2604
|
+
const results = await Promise.allSettled(promises);
|
|
2605
|
+
const failures = results.filter((r) => r.status === "rejected");
|
|
2606
|
+
if (failures.length > 0) {
|
|
2607
|
+
for (const f of failures) {
|
|
2608
|
+
console.error(`Agent exited with error: ${f.reason}`);
|
|
2609
|
+
}
|
|
2610
|
+
process.exit(1);
|
|
2611
|
+
}
|
|
2612
|
+
} else {
|
|
2613
|
+
const maxIndex = (config.agents?.length ?? 0) - 1;
|
|
2614
|
+
const agentIndex = Number(opts.agent);
|
|
2615
|
+
if (!Number.isInteger(agentIndex) || agentIndex < 0 || agentIndex > maxIndex) {
|
|
2616
|
+
console.error(
|
|
2617
|
+
maxIndex >= 0 ? `--agent must be an integer between 0 and ${maxIndex}.` : "No agents configured in ~/.opencara/config.yml"
|
|
2618
|
+
);
|
|
2619
|
+
process.exit(1);
|
|
2620
|
+
return;
|
|
2621
|
+
}
|
|
2622
|
+
const p = startAgentByIndex(
|
|
2623
|
+
config,
|
|
2624
|
+
agentIndex,
|
|
2625
|
+
pollIntervalMs,
|
|
2626
|
+
auth,
|
|
2627
|
+
githubUsername,
|
|
2628
|
+
versionOverride
|
|
2629
|
+
);
|
|
2630
|
+
if (!p) {
|
|
2631
|
+
process.exit(1);
|
|
2632
|
+
return;
|
|
2633
|
+
}
|
|
2634
|
+
await p;
|
|
2635
|
+
}
|
|
2516
2636
|
}
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2637
|
+
);
|
|
2638
|
+
|
|
2639
|
+
// src/commands/status.ts
|
|
2640
|
+
import { Command as Command2 } from "commander";
|
|
2641
|
+
import pc2 from "picocolors";
|
|
2642
|
+
var REQUEST_TIMEOUT_MS = 1e4;
|
|
2643
|
+
function isValidMetrics(data) {
|
|
2644
|
+
if (!data || typeof data !== "object") return false;
|
|
2645
|
+
const obj = data;
|
|
2646
|
+
if (!obj.tasks || typeof obj.tasks !== "object") return false;
|
|
2647
|
+
const tasks = obj.tasks;
|
|
2648
|
+
return typeof tasks.pending === "number" && typeof tasks.reviewing === "number" && typeof tasks.failed === "number";
|
|
2649
|
+
}
|
|
2650
|
+
function agentRoleLabel(agent) {
|
|
2651
|
+
if (agent.review_only) return "reviewer only";
|
|
2652
|
+
if (agent.synthesizer_only) return "synthesizer only";
|
|
2653
|
+
return "reviewer+synthesizer";
|
|
2654
|
+
}
|
|
2655
|
+
function resolveToolBinary(toolName) {
|
|
2656
|
+
const entry = DEFAULT_REGISTRY.tools.find((t) => t.name === toolName);
|
|
2657
|
+
return entry?.binary ?? toolName;
|
|
2658
|
+
}
|
|
2659
|
+
function resolveCommand(agent) {
|
|
2660
|
+
if (agent.command) return agent.command;
|
|
2661
|
+
const entry = DEFAULT_REGISTRY.tools.find((t) => t.name === agent.tool);
|
|
2662
|
+
return entry?.commandTemplate ?? null;
|
|
2663
|
+
}
|
|
2664
|
+
async function checkConnectivity(platformUrl, fetchFn = fetch) {
|
|
2665
|
+
const start = Date.now();
|
|
2666
|
+
try {
|
|
2667
|
+
const res = await fetchFn(`${platformUrl}/health`, {
|
|
2668
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
2669
|
+
});
|
|
2670
|
+
const ms = Date.now() - start;
|
|
2671
|
+
if (!res.ok) {
|
|
2672
|
+
return { ok: false, ms, error: `HTTP ${res.status}` };
|
|
2522
2673
|
}
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2674
|
+
return { ok: true, ms };
|
|
2675
|
+
} catch (err) {
|
|
2676
|
+
const ms = Date.now() - start;
|
|
2677
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2678
|
+
return { ok: false, ms, error: message };
|
|
2679
|
+
}
|
|
2680
|
+
}
|
|
2681
|
+
async function fetchMetrics(platformUrl, fetchFn = fetch) {
|
|
2682
|
+
try {
|
|
2683
|
+
const res = await fetchFn(`${platformUrl}/metrics`, {
|
|
2684
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
2685
|
+
});
|
|
2686
|
+
if (!res.ok) return null;
|
|
2687
|
+
const data = await res.json();
|
|
2688
|
+
if (!isValidMetrics(data)) return null;
|
|
2689
|
+
return data;
|
|
2690
|
+
} catch {
|
|
2691
|
+
return null;
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
async function runStatus(deps) {
|
|
2695
|
+
const {
|
|
2696
|
+
loadConfigFn = loadConfig,
|
|
2697
|
+
fetchFn = fetch,
|
|
2698
|
+
validateBinaryFn = validateCommandBinary,
|
|
2699
|
+
log = console.log
|
|
2700
|
+
} = deps;
|
|
2701
|
+
const config = loadConfigFn();
|
|
2702
|
+
log(`${pc2.bold("OpenCara Agent Status")}`);
|
|
2703
|
+
log(pc2.dim("\u2500".repeat(30)));
|
|
2704
|
+
log(`Config: ${pc2.cyan(CONFIG_FILE)}`);
|
|
2705
|
+
log(`Platform: ${pc2.cyan(config.platformUrl)}`);
|
|
2706
|
+
log(
|
|
2707
|
+
`GitHub: ${config.githubToken ? `${icons.success} token present` : `${icons.error} no token`}`
|
|
2708
|
+
);
|
|
2709
|
+
log("");
|
|
2710
|
+
const conn = await checkConnectivity(config.platformUrl, fetchFn);
|
|
2711
|
+
if (conn.ok) {
|
|
2712
|
+
log(`Connectivity: ${icons.success} OK (${conn.ms}ms)`);
|
|
2713
|
+
} else {
|
|
2714
|
+
log(`Connectivity: ${icons.error} Connection failed: ${conn.error}`);
|
|
2715
|
+
}
|
|
2716
|
+
log("");
|
|
2717
|
+
const agents = config.agents;
|
|
2718
|
+
if (!agents || agents.length === 0) {
|
|
2719
|
+
log(`Agents: ${pc2.dim("No agents configured")}`);
|
|
2720
|
+
} else {
|
|
2721
|
+
log(`Agents (${agents.length} configured):`);
|
|
2722
|
+
for (let i = 0; i < agents.length; i++) {
|
|
2723
|
+
const agent = agents[i];
|
|
2724
|
+
const label = agent.name ?? `${agent.model}/${agent.tool}`;
|
|
2725
|
+
const role = agentRoleLabel(agent);
|
|
2726
|
+
log(` ${i + 1}. ${pc2.bold(label)} \u2014 ${role}`);
|
|
2727
|
+
const commandTemplate = resolveCommand(agent);
|
|
2728
|
+
if (commandTemplate) {
|
|
2729
|
+
const binaryOk = validateBinaryFn(commandTemplate);
|
|
2730
|
+
const binary = resolveToolBinary(agent.tool);
|
|
2731
|
+
if (binaryOk) {
|
|
2732
|
+
log(` Binary: ${icons.success} ${binary} executable`);
|
|
2733
|
+
} else {
|
|
2734
|
+
log(` Binary: ${icons.error} ${binary} not found`);
|
|
2735
|
+
}
|
|
2530
2736
|
} else {
|
|
2531
|
-
|
|
2737
|
+
log(` Binary: ${icons.warn} unknown tool "${agent.tool}"`);
|
|
2532
2738
|
}
|
|
2533
2739
|
}
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2740
|
+
}
|
|
2741
|
+
log("");
|
|
2742
|
+
if (conn.ok) {
|
|
2743
|
+
const metrics = await fetchMetrics(config.platformUrl, fetchFn);
|
|
2744
|
+
if (metrics) {
|
|
2745
|
+
log("Platform Status:");
|
|
2746
|
+
log(
|
|
2747
|
+
` Tasks: ${metrics.tasks.pending} pending, ${metrics.tasks.reviewing} reviewing, ${metrics.tasks.failed} failed`
|
|
2542
2748
|
);
|
|
2543
|
-
}
|
|
2544
|
-
|
|
2545
|
-
`);
|
|
2546
|
-
const results = await Promise.allSettled(promises);
|
|
2547
|
-
const failures = results.filter((r) => r.status === "rejected");
|
|
2548
|
-
if (failures.length > 0) {
|
|
2549
|
-
for (const f of failures) {
|
|
2550
|
-
console.error(`Agent exited with error: ${f.reason}`);
|
|
2551
|
-
}
|
|
2552
|
-
process.exit(1);
|
|
2749
|
+
} else {
|
|
2750
|
+
log(`Platform Status: ${icons.error} Could not fetch metrics`);
|
|
2553
2751
|
}
|
|
2554
2752
|
} else {
|
|
2555
|
-
|
|
2556
|
-
const agentIndex = Number(opts.agent);
|
|
2557
|
-
if (!Number.isInteger(agentIndex) || agentIndex < 0 || agentIndex > maxIndex) {
|
|
2558
|
-
console.error(
|
|
2559
|
-
maxIndex >= 0 ? `--agent must be an integer between 0 and ${maxIndex}.` : "No agents configured in ~/.opencara/config.yml"
|
|
2560
|
-
);
|
|
2561
|
-
process.exit(1);
|
|
2562
|
-
return;
|
|
2563
|
-
}
|
|
2564
|
-
const p = startAgentByIndex(config, agentIndex, pollIntervalMs, auth, githubUsername);
|
|
2565
|
-
if (!p) {
|
|
2566
|
-
process.exit(1);
|
|
2567
|
-
return;
|
|
2568
|
-
}
|
|
2569
|
-
await p;
|
|
2753
|
+
log(`Platform Status: ${pc2.dim("skipped (no connectivity)")}`);
|
|
2570
2754
|
}
|
|
2755
|
+
}
|
|
2756
|
+
var statusCommand = new Command2("status").description("Show agent config, connectivity, and platform status").action(async () => {
|
|
2757
|
+
await runStatus({});
|
|
2571
2758
|
});
|
|
2572
2759
|
|
|
2573
2760
|
// src/index.ts
|
|
2574
|
-
var program = new
|
|
2761
|
+
var program = new Command3().name("opencara").description("OpenCara \u2014 distributed AI code review agent").version("0.15.6");
|
|
2575
2762
|
program.addCommand(agentCommand);
|
|
2763
|
+
program.addCommand(statusCommand);
|
|
2576
2764
|
program.action(() => {
|
|
2577
2765
|
startAgentRouter();
|
|
2578
2766
|
});
|