@castlemilk/omega 0.6.14 → 0.6.15
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/cli.js +508 -35
- package/dist/server/pglite-data/base/5/1247 +0 -0
- package/dist/server/pglite-data/base/5/1249 +0 -0
- package/dist/server/pglite-data/base/5/1259 +0 -0
- package/dist/server/pglite-data/base/5/16394 +0 -0
- package/dist/server/pglite-data/base/5/16404 +0 -0
- package/dist/server/pglite-data/base/5/16406 +0 -0
- package/dist/server/pglite-data/base/5/16421 +0 -0
- package/dist/server/pglite-data/base/5/16510 +0 -0
- package/dist/server/pglite-data/base/5/2604 +0 -0
- package/dist/server/pglite-data/base/5/2606 +0 -0
- package/dist/server/pglite-data/base/5/2610 +0 -0
- package/dist/server/pglite-data/base/5/2620 +0 -0
- package/dist/server/pglite-data/base/5/2662 +0 -0
- package/dist/server/pglite-data/base/5/2663 +0 -0
- package/dist/server/pglite-data/base/5/pg_internal.init +0 -0
- package/dist/server/pglite-data/global/pg_control +0 -0
- package/dist/server/pglite-data/global/pg_internal.init +0 -0
- package/dist/server/pglite-data/pg_wal/000000010000000000000001 +0 -0
- package/dist/server/pglite-data/pg_xact/0000 +0 -0
- package/dist/server/pglite-data/postmaster.pid +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -330,8 +330,8 @@ function getApiUrl() {
|
|
|
330
330
|
const opts = program.opts();
|
|
331
331
|
return opts.api ?? "http://localhost:4000";
|
|
332
332
|
}
|
|
333
|
-
async function apiFetch(
|
|
334
|
-
const url = `${getApiUrl()}${
|
|
333
|
+
async function apiFetch(path11, init) {
|
|
334
|
+
const url = `${getApiUrl()}${path11}`;
|
|
335
335
|
const res = await fetch(url, init);
|
|
336
336
|
const data = await res.json().catch(() => ({}));
|
|
337
337
|
if (!res.ok) {
|
|
@@ -734,8 +734,8 @@ function getOutputDir() {
|
|
|
734
734
|
}
|
|
735
735
|
try {
|
|
736
736
|
const __filename3 = fileURLToPath3(import.meta.url);
|
|
737
|
-
const
|
|
738
|
-
return path3.join(path3.resolve(
|
|
737
|
+
const __dirname4 = path3.dirname(__filename3);
|
|
738
|
+
return path3.join(path3.resolve(__dirname4, "../../../.."), "packages/skills/src");
|
|
739
739
|
} catch {
|
|
740
740
|
return path3.join(process.cwd(), "harness-skills");
|
|
741
741
|
}
|
|
@@ -819,7 +819,8 @@ agentCmd.command("diffs").description("Show diffs for a task").argument("<id>",
|
|
|
819
819
|
|
|
820
820
|
// ../../apps/cli/src/commands/bench.ts
|
|
821
821
|
import { Command as Command8 } from "commander";
|
|
822
|
-
import
|
|
822
|
+
import fs8 from "node:fs/promises";
|
|
823
|
+
import path10 from "node:path";
|
|
823
824
|
|
|
824
825
|
// ../bench/dist/api-client.js
|
|
825
826
|
var ApiError = class extends Error {
|
|
@@ -836,15 +837,15 @@ async function apiFetch2(url, init) {
|
|
|
836
837
|
}
|
|
837
838
|
return res.json();
|
|
838
839
|
}
|
|
839
|
-
async function ensureProject2(apiUrl, name,
|
|
840
|
+
async function ensureProject2(apiUrl, name, path11) {
|
|
840
841
|
const res = await fetch(`${apiUrl}/projects`, {
|
|
841
842
|
method: "POST",
|
|
842
843
|
headers: { "Content-Type": "application/json" },
|
|
843
|
-
body: JSON.stringify({ name, path:
|
|
844
|
+
body: JSON.stringify({ name, path: path11 })
|
|
844
845
|
});
|
|
845
846
|
if (res.status === 409) {
|
|
846
|
-
const projects = await fetch(`${apiUrl}/projects?path=${encodeURIComponent(
|
|
847
|
-
const existing = projects.find((p) => p.path ===
|
|
847
|
+
const projects = await fetch(`${apiUrl}/projects?path=${encodeURIComponent(path11)}`).then((r) => r.json());
|
|
848
|
+
const existing = projects.find((p) => p.path === path11);
|
|
848
849
|
if (existing)
|
|
849
850
|
return existing;
|
|
850
851
|
}
|
|
@@ -1049,7 +1050,7 @@ async function writeReport(report, outputDir = ".omega/reports") {
|
|
|
1049
1050
|
const jsonFile = path5.join(outputDir, `benchmark-${ts}.json`);
|
|
1050
1051
|
const mdFile = path5.join(outputDir, `benchmark-${ts}.md`);
|
|
1051
1052
|
await fs2.writeFile(jsonFile, JSON.stringify(report, null, 2), "utf-8");
|
|
1052
|
-
const
|
|
1053
|
+
const passRate2 = report.total > 0 ? Math.round(report.passed / report.total * 100) : 0;
|
|
1053
1054
|
const md = [
|
|
1054
1055
|
"# Omega Benchmark Report",
|
|
1055
1056
|
"",
|
|
@@ -1059,7 +1060,7 @@ async function writeReport(report, outputDir = ".omega/reports") {
|
|
|
1059
1060
|
`- Passed: ${String(report.passed)}`,
|
|
1060
1061
|
`- Failed: ${String(report.failed)}`,
|
|
1061
1062
|
`- Timeouts: ${String(report.timeouts)}`,
|
|
1062
|
-
`- Pass rate: ${String(
|
|
1063
|
+
`- Pass rate: ${String(passRate2)}%`,
|
|
1063
1064
|
`- Total duration: ${formatDuration(report.totalDurationMs)}`,
|
|
1064
1065
|
"",
|
|
1065
1066
|
"## Results",
|
|
@@ -1077,11 +1078,11 @@ async function writeReport(report, outputDir = ".omega/reports") {
|
|
|
1077
1078
|
return jsonFile;
|
|
1078
1079
|
}
|
|
1079
1080
|
function printSummary(report) {
|
|
1080
|
-
const
|
|
1081
|
+
const passRate2 = report.total > 0 ? Math.round(report.passed / report.total * 100) : 0;
|
|
1081
1082
|
console.log(`
|
|
1082
1083
|
Benchmark: ${report.suite}`);
|
|
1083
1084
|
console.log(`Total: ${String(report.total)} | Passed: ${String(report.passed)} | Failed: ${String(report.failed)} | Timeouts: ${String(report.timeouts)}`);
|
|
1084
|
-
console.log(`Pass rate: ${String(
|
|
1085
|
+
console.log(`Pass rate: ${String(passRate2)}%`);
|
|
1085
1086
|
console.log(`Duration: ${formatDuration(report.totalDurationMs)}`);
|
|
1086
1087
|
for (const r of report.results) {
|
|
1087
1088
|
console.log(resultLine(r, report.results.indexOf(r)));
|
|
@@ -1289,10 +1290,10 @@ async function readTask(taskDir) {
|
|
|
1289
1290
|
const instructionRaw = await fs4.readFile(path7.join(taskDir, "instruction.md"), "utf-8");
|
|
1290
1291
|
return { toml: parseToml(tomlRaw), instruction: instructionRaw };
|
|
1291
1292
|
}
|
|
1292
|
-
async function cloneRepo(repoUrl,
|
|
1293
|
+
async function cloneRepo(repoUrl, commit2, targetPath) {
|
|
1293
1294
|
await fs4.mkdir(path7.dirname(targetPath), { recursive: true });
|
|
1294
1295
|
await execFileAsync("git", ["clone", repoUrl, targetPath], { timeout: 12e4 });
|
|
1295
|
-
await execFileAsync("git", ["-C", targetPath, "checkout",
|
|
1296
|
+
await execFileAsync("git", ["-C", targetPath, "checkout", commit2], { timeout: 6e4 });
|
|
1296
1297
|
}
|
|
1297
1298
|
async function loadDeepSWESuite(options) {
|
|
1298
1299
|
const entries = await fs4.readdir(options.tasksDir, { withFileTypes: true });
|
|
@@ -1321,7 +1322,7 @@ async function loadDeepSWESuite(options) {
|
|
|
1321
1322
|
const id = toml.metadata?.task_id ?? path7.basename(dir);
|
|
1322
1323
|
const title = toml.metadata?.display_title ?? toml.metadata?.original_title ?? id;
|
|
1323
1324
|
const repo = toml.metadata?.repository_url;
|
|
1324
|
-
const
|
|
1325
|
+
const commit2 = toml.metadata?.base_commit_hash;
|
|
1325
1326
|
tasks.push({
|
|
1326
1327
|
id: `deepswe-${id}`,
|
|
1327
1328
|
name: id,
|
|
@@ -1329,10 +1330,10 @@ async function loadDeepSWESuite(options) {
|
|
|
1329
1330
|
description: instruction,
|
|
1330
1331
|
complexity: "complex",
|
|
1331
1332
|
setup: async (projectPath) => {
|
|
1332
|
-
if (!repo || !
|
|
1333
|
+
if (!repo || !commit2) {
|
|
1333
1334
|
throw new Error(`DeepSWE task ${id} is missing repository_url or base_commit_hash`);
|
|
1334
1335
|
}
|
|
1335
|
-
await cloneRepo(repo,
|
|
1336
|
+
await cloneRepo(repo, commit2, projectPath);
|
|
1336
1337
|
},
|
|
1337
1338
|
evaluate: (ctx) => {
|
|
1338
1339
|
const hasDiff = ctx.diffs.length > 0 && ctx.diffs.some((d) => d.patch.trim().length > 0);
|
|
@@ -1366,12 +1367,12 @@ function summariseTraceFlow(report, maxLines = 60) {
|
|
|
1366
1367
|
return lines.slice(0, maxLines).join("\n") + "\n... (truncated)";
|
|
1367
1368
|
}
|
|
1368
1369
|
function buildOptimisePrompt(report, failedResult, traceFlowText) {
|
|
1369
|
-
const
|
|
1370
|
+
const passRate2 = report.total > 0 ? Math.round(report.passed / report.total * 100) : 0;
|
|
1370
1371
|
const failed = report.results.filter((r) => !r.evaluation.passed);
|
|
1371
1372
|
const lines = [];
|
|
1372
1373
|
lines.push("# Prompt optimisation task");
|
|
1373
1374
|
lines.push("");
|
|
1374
|
-
lines.push(`The latest benchmark run achieved ${String(
|
|
1375
|
+
lines.push(`The latest benchmark run achieved ${String(passRate2)}% pass rate (${String(report.passed)}/${String(report.total)}).`);
|
|
1375
1376
|
lines.push("");
|
|
1376
1377
|
lines.push("## Failed tasks");
|
|
1377
1378
|
for (const r of failed.slice(0, 5)) {
|
|
@@ -1432,6 +1433,335 @@ async function submitOptimiseTask(apiUrl, projectId, prompt) {
|
|
|
1432
1433
|
return res.json();
|
|
1433
1434
|
}
|
|
1434
1435
|
|
|
1436
|
+
// ../bench/dist/ab.js
|
|
1437
|
+
function passRate(report) {
|
|
1438
|
+
return report.total > 0 ? Math.round(report.passed / report.total * 100) : 0;
|
|
1439
|
+
}
|
|
1440
|
+
function findResult(report, taskId) {
|
|
1441
|
+
return report.results.find((r) => r.task.id === taskId);
|
|
1442
|
+
}
|
|
1443
|
+
function buildAbReport(baseline, candidate, baselineReport, candidateReport) {
|
|
1444
|
+
const baselineRate = passRate(baselineReport);
|
|
1445
|
+
const candidateRate = passRate(candidateReport);
|
|
1446
|
+
const taskIds = /* @__PURE__ */ new Set();
|
|
1447
|
+
for (const r of baselineReport.results)
|
|
1448
|
+
taskIds.add(r.task.id);
|
|
1449
|
+
for (const r of candidateReport.results)
|
|
1450
|
+
taskIds.add(r.task.id);
|
|
1451
|
+
const perTask = Array.from(taskIds).map((taskId) => {
|
|
1452
|
+
const base = findResult(baselineReport, taskId);
|
|
1453
|
+
const cand = findResult(candidateReport, taskId);
|
|
1454
|
+
return {
|
|
1455
|
+
taskId,
|
|
1456
|
+
taskName: base?.task.name ?? cand?.task.name ?? taskId,
|
|
1457
|
+
baselinePassed: base?.evaluation.passed ?? false,
|
|
1458
|
+
candidatePassed: cand?.evaluation.passed ?? false,
|
|
1459
|
+
baselineTokens: base?.usage?.totalTokens,
|
|
1460
|
+
candidateTokens: cand?.usage?.totalTokens
|
|
1461
|
+
};
|
|
1462
|
+
});
|
|
1463
|
+
return {
|
|
1464
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1465
|
+
baseline,
|
|
1466
|
+
candidate,
|
|
1467
|
+
baselineReport,
|
|
1468
|
+
candidateReport,
|
|
1469
|
+
delta: {
|
|
1470
|
+
passRate: candidateRate - baselineRate,
|
|
1471
|
+
passedDelta: candidateReport.passed - baselineReport.passed,
|
|
1472
|
+
durationMsDelta: candidateReport.totalDurationMs - baselineReport.totalDurationMs,
|
|
1473
|
+
promptTokensDelta: (candidateReport.totalUsage?.promptTokens ?? 0) - (baselineReport.totalUsage?.promptTokens ?? 0),
|
|
1474
|
+
completionTokensDelta: (candidateReport.totalUsage?.completionTokens ?? 0) - (baselineReport.totalUsage?.completionTokens ?? 0),
|
|
1475
|
+
totalTokensDelta: (candidateReport.totalUsage?.totalTokens ?? 0) - (baselineReport.totalUsage?.totalTokens ?? 0)
|
|
1476
|
+
},
|
|
1477
|
+
perTask
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
async function runAbBenchmark(tasks, baseline, candidate, options) {
|
|
1481
|
+
const suiteName = options.suiteName ?? "ab";
|
|
1482
|
+
const baselineReport = await runBenchmark(tasks, {
|
|
1483
|
+
...options,
|
|
1484
|
+
suiteName: `${suiteName}-baseline`
|
|
1485
|
+
});
|
|
1486
|
+
const candidateReport = await runBenchmark(tasks, {
|
|
1487
|
+
...options,
|
|
1488
|
+
suiteName: `${suiteName}-candidate`
|
|
1489
|
+
});
|
|
1490
|
+
return buildAbReport(baseline, candidate, baselineReport, candidateReport);
|
|
1491
|
+
}
|
|
1492
|
+
function deltaSymbol(value) {
|
|
1493
|
+
if (value > 0)
|
|
1494
|
+
return "+";
|
|
1495
|
+
if (value < 0)
|
|
1496
|
+
return "";
|
|
1497
|
+
return "";
|
|
1498
|
+
}
|
|
1499
|
+
function formatDelta(value) {
|
|
1500
|
+
return `${deltaSymbol(value)}${String(value)}`;
|
|
1501
|
+
}
|
|
1502
|
+
function formatAbReport(report) {
|
|
1503
|
+
const lines = [];
|
|
1504
|
+
lines.push("# Omega A/B Benchmark Report");
|
|
1505
|
+
lines.push("");
|
|
1506
|
+
lines.push(`- Timestamp: ${report.timestamp}`);
|
|
1507
|
+
lines.push(`- Baseline: ${report.baseline.name}`);
|
|
1508
|
+
lines.push(`- Candidate: ${report.candidate.name}`);
|
|
1509
|
+
lines.push("");
|
|
1510
|
+
lines.push("## Summary");
|
|
1511
|
+
lines.push(`| Metric | Baseline | Candidate | Delta |`);
|
|
1512
|
+
lines.push(`|---|---|---|---|`);
|
|
1513
|
+
lines.push(`| Pass rate | ${String(passRate(report.baselineReport))}% | ${String(passRate(report.candidateReport))}% | ${formatDelta(report.delta.passRate)}% |`);
|
|
1514
|
+
lines.push(`| Passed | ${String(report.baselineReport.passed)}/${String(report.baselineReport.total)} | ${String(report.candidateReport.passed)}/${String(report.candidateReport.total)} | ${formatDelta(report.delta.passedDelta)} |`);
|
|
1515
|
+
lines.push(`| Duration | ${formatDuration2(report.baselineReport.totalDurationMs)} | ${formatDuration2(report.candidateReport.totalDurationMs)} | ${formatDuration2(report.delta.durationMsDelta)} |`);
|
|
1516
|
+
lines.push(`| Tokens | ${String(report.baselineReport.totalUsage?.totalTokens ?? 0)} | ${String(report.candidateReport.totalUsage?.totalTokens ?? 0)} | ${formatDelta(report.delta.totalTokensDelta)} |`);
|
|
1517
|
+
lines.push("");
|
|
1518
|
+
lines.push("## Per-task comparison");
|
|
1519
|
+
lines.push(`| Task | Baseline | Candidate | Token delta |`);
|
|
1520
|
+
lines.push(`|---|---|---|---|`);
|
|
1521
|
+
for (const t of report.perTask) {
|
|
1522
|
+
const tokenDelta = t.baselineTokens !== void 0 && t.candidateTokens !== void 0 ? formatDelta(t.candidateTokens - t.baselineTokens) : "-";
|
|
1523
|
+
lines.push(`| ${t.taskName} | ${t.baselinePassed ? "pass" : "fail"} | ${t.candidatePassed ? "pass" : "fail"} | ${tokenDelta} |`);
|
|
1524
|
+
}
|
|
1525
|
+
lines.push("");
|
|
1526
|
+
return lines.join("\n");
|
|
1527
|
+
}
|
|
1528
|
+
function formatDuration2(ms) {
|
|
1529
|
+
if (ms < 1e3)
|
|
1530
|
+
return `${String(Math.round(ms))}ms`;
|
|
1531
|
+
return `${(ms / 1e3).toFixed(1)}s`;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
// ../agent/dist/tool-definitions.js
|
|
1535
|
+
var AGENT_TOOLS = [
|
|
1536
|
+
{
|
|
1537
|
+
name: "read_file",
|
|
1538
|
+
description: "Read a file relative to project root.",
|
|
1539
|
+
parameters: {
|
|
1540
|
+
type: "object",
|
|
1541
|
+
properties: { path: { type: "string" } },
|
|
1542
|
+
required: ["path"]
|
|
1543
|
+
}
|
|
1544
|
+
},
|
|
1545
|
+
{
|
|
1546
|
+
name: "write_file",
|
|
1547
|
+
description: "Write content to a file relative to project root.",
|
|
1548
|
+
parameters: {
|
|
1549
|
+
type: "object",
|
|
1550
|
+
properties: { path: { type: "string" }, content: { type: "string" } },
|
|
1551
|
+
required: ["path", "content"]
|
|
1552
|
+
}
|
|
1553
|
+
},
|
|
1554
|
+
{
|
|
1555
|
+
name: "edit_file",
|
|
1556
|
+
description: "Apply a targeted edit to an existing file relative to project root. Replaces one occurrence of old_string with new_string.",
|
|
1557
|
+
parameters: {
|
|
1558
|
+
type: "object",
|
|
1559
|
+
properties: {
|
|
1560
|
+
path: { type: "string" },
|
|
1561
|
+
old_string: { type: "string" },
|
|
1562
|
+
new_string: { type: "string" }
|
|
1563
|
+
},
|
|
1564
|
+
required: ["path", "old_string", "new_string"]
|
|
1565
|
+
}
|
|
1566
|
+
},
|
|
1567
|
+
{
|
|
1568
|
+
name: "run_command",
|
|
1569
|
+
description: "Run a shell command in the project root.",
|
|
1570
|
+
parameters: {
|
|
1571
|
+
type: "object",
|
|
1572
|
+
properties: { command: { type: "string" } },
|
|
1573
|
+
required: ["command"]
|
|
1574
|
+
}
|
|
1575
|
+
},
|
|
1576
|
+
{
|
|
1577
|
+
name: "think",
|
|
1578
|
+
description: "Record reasoning.",
|
|
1579
|
+
parameters: {
|
|
1580
|
+
type: "object",
|
|
1581
|
+
properties: { thought: { type: "string" } },
|
|
1582
|
+
required: ["thought"]
|
|
1583
|
+
}
|
|
1584
|
+
},
|
|
1585
|
+
{
|
|
1586
|
+
name: "finish",
|
|
1587
|
+
description: "Mark the task complete.",
|
|
1588
|
+
parameters: {
|
|
1589
|
+
type: "object",
|
|
1590
|
+
properties: { summary: { type: "string" }, success: { type: "boolean" } },
|
|
1591
|
+
required: ["summary", "success"]
|
|
1592
|
+
}
|
|
1593
|
+
},
|
|
1594
|
+
{
|
|
1595
|
+
name: "publish",
|
|
1596
|
+
description: "Build, validate, and publish the project.",
|
|
1597
|
+
parameters: {
|
|
1598
|
+
type: "object",
|
|
1599
|
+
properties: { version: { type: "string" } },
|
|
1600
|
+
required: []
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
];
|
|
1604
|
+
|
|
1605
|
+
// ../agent/dist/planner.js
|
|
1606
|
+
var toolDescriptions = AGENT_TOOLS.map((t) => `- ${t.name}: ${t.description}`).join("\n");
|
|
1607
|
+
var PLAN_PROMPT = `You are a planning assistant. Given a task, produce a concise step-by-step plan.
|
|
1608
|
+
|
|
1609
|
+
Respond with strict JSON in this exact shape (no markdown):
|
|
1610
|
+
{
|
|
1611
|
+
"reasoning": "brief reasoning",
|
|
1612
|
+
"plan": [
|
|
1613
|
+
{ "name": "step name", "tool": "optional tool name", "input": { optional tool args } }
|
|
1614
|
+
]
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
Available tools:
|
|
1618
|
+
${toolDescriptions}
|
|
1619
|
+
|
|
1620
|
+
If a step does not need a tool, omit tool/input. Use edit_file for small file changes.`;
|
|
1621
|
+
|
|
1622
|
+
// ../agent/dist/tools.js
|
|
1623
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
1624
|
+
import { promisify as promisify2 } from "node:util";
|
|
1625
|
+
var execFileAsync2 = promisify2(execFile2);
|
|
1626
|
+
|
|
1627
|
+
// ../agent/dist/validator.js
|
|
1628
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
1629
|
+
import { promisify as promisify3 } from "node:util";
|
|
1630
|
+
var execFileAsync3 = promisify3(execFile3);
|
|
1631
|
+
|
|
1632
|
+
// ../agent/dist/publisher.js
|
|
1633
|
+
import { execFile as execFile5 } from "node:child_process";
|
|
1634
|
+
import { promisify as promisify5 } from "node:util";
|
|
1635
|
+
|
|
1636
|
+
// ../agent/dist/git.js
|
|
1637
|
+
import { execFile as execFile4 } from "node:child_process";
|
|
1638
|
+
import { promisify as promisify4 } from "node:util";
|
|
1639
|
+
var execFileAsync4 = promisify4(execFile4);
|
|
1640
|
+
|
|
1641
|
+
// ../agent/dist/publisher.js
|
|
1642
|
+
var execFileAsync5 = promisify5(execFile5);
|
|
1643
|
+
|
|
1644
|
+
// ../agent/dist/prompts.js
|
|
1645
|
+
import fs6 from "node:fs";
|
|
1646
|
+
function loadPromptFromEnv(name) {
|
|
1647
|
+
const direct = process.env[name];
|
|
1648
|
+
if (direct)
|
|
1649
|
+
return direct;
|
|
1650
|
+
const fileKey = `${name}_FILE`;
|
|
1651
|
+
const filePath = process.env[fileKey];
|
|
1652
|
+
if (filePath) {
|
|
1653
|
+
try {
|
|
1654
|
+
return fs6.readFileSync(filePath, "utf-8");
|
|
1655
|
+
} catch {
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
return void 0;
|
|
1659
|
+
}
|
|
1660
|
+
var AGENT_SYSTEM_PROMPT = loadPromptFromEnv("OMEGA_SYSTEM_PROMPT") ?? `You are Omega, an autonomous software engineering agent running inside a project repository.
|
|
1661
|
+
|
|
1662
|
+
Your job is to complete the user's task by calling tools. Do not write prose or explanations outside tool calls. Prefer targeted edits over full rewrites.
|
|
1663
|
+
|
|
1664
|
+
Available tools:
|
|
1665
|
+
|
|
1666
|
+
- read_file: Read a file relative to project root. Arguments: { "path": "relative/path" }
|
|
1667
|
+
- write_file: Overwrite or create a file. Arguments: { "path": "relative/path", "content": "full file content" }
|
|
1668
|
+
- edit_file: Replace one exact occurrence of old_string with new_string in an existing file. Use this for small changes. Arguments: { "path": "relative/path", "old_string": "...", "new_string": "..." }
|
|
1669
|
+
- run_command: Run a single simple command. No pipes (|), &&, ;, redirects, or globs. Prefer pnpm/npm/node. Arguments: { "command": "pnpm lint" }
|
|
1670
|
+
- think: Record a reasoning step. Arguments: { "thought": "..." }
|
|
1671
|
+
- finish: Mark the task complete. Arguments: { "summary": "what was done", "success": true }. Use summary, not message.
|
|
1672
|
+
- publish: Run build/test/publish validation. Only after your edits pass validation. Arguments: { "version": "optional" }
|
|
1673
|
+
|
|
1674
|
+
Rules:
|
|
1675
|
+
1. Read the task, then use think to plan.
|
|
1676
|
+
2. Use edit_file for small changes; write_file only when creating a file or rewriting most of it.
|
|
1677
|
+
3. ALWAYS read a file with read_file before using edit_file on it. Do NOT read a file before write_file when creating a new file.
|
|
1678
|
+
4. Before creating JavaScript files, read package.json to check whether "type" is "module" and use ESM (export) or CommonJS (module.exports) accordingly.
|
|
1679
|
+
5. You MUST run validation (pnpm lint, pnpm test, or the project's validation command) after every edit using publish or run_command.
|
|
1680
|
+
6. Do NOT call finish until validation passes. If validation fails, fix the issue and re-run validation.
|
|
1681
|
+
7. Do not expose secrets or run destructive commands.
|
|
1682
|
+
8. Finish only when the task is done. Always include summary and success.
|
|
1683
|
+
9. Do not repeat the same tool call with the same arguments. If something fails, change your approach.
|
|
1684
|
+
10. Do not ask the user for clarification. Do not say "No task was provided". Use the Task and Description above to proceed.
|
|
1685
|
+
|
|
1686
|
+
Example tool call sequence for "Add a greet function":
|
|
1687
|
+
1. think: { "thought": "I need to create greet.js and export a greet function." }
|
|
1688
|
+
2. write_file: { "path": "greet.js", "content": "export function greet(name) { return 'Hello, ' + name + '!'; }
|
|
1689
|
+
" }
|
|
1690
|
+
3. publish: { }
|
|
1691
|
+
4. finish: { "summary": "Created greet.js with greet(name) function and verified it passes tests.", "success": true }`;
|
|
1692
|
+
var TEXT_TOOLS_SYSTEM_PROMPT = loadPromptFromEnv("OMEGA_TEXT_TOOLS_PROMPT") ?? `You are Omega, an autonomous software engineering agent running inside a project repository.
|
|
1693
|
+
|
|
1694
|
+
You MUST respond with a single JSON object containing a "tool_calls" array. Do not output markdown, explanations, or reasoning outside the JSON.
|
|
1695
|
+
|
|
1696
|
+
Available tools (use ONLY these exact names):
|
|
1697
|
+
|
|
1698
|
+
- read_file: { "path": "relative/path" }
|
|
1699
|
+
- write_file: { "path": "relative/path", "content": "full file content" }
|
|
1700
|
+
- edit_file: { "path": "relative/path", "old_string": "...", "new_string": "..." }
|
|
1701
|
+
- run_command: { "command": "simple command, no pipes/&&/;/redirects" }
|
|
1702
|
+
- think: { "thought": "reasoning text" }
|
|
1703
|
+
- finish: { "summary": "what was done", "success": true | false }
|
|
1704
|
+
- publish: { "version": "optional" }
|
|
1705
|
+
|
|
1706
|
+
Rules:
|
|
1707
|
+
- Plan with think, then act.
|
|
1708
|
+
- Use edit_file for small changes; write_file only for new files or large rewrites.
|
|
1709
|
+
- ALWAYS read a file with read_file before using edit_file on it. Do NOT read a file before write_file when creating a new file.
|
|
1710
|
+
- Before creating JavaScript files, read package.json to check whether "type" is "module" and use ESM (export) or CommonJS (module.exports) accordingly.
|
|
1711
|
+
- You MUST run validation (pnpm lint, pnpm test, or the project's validation command) after every edit using publish or run_command.
|
|
1712
|
+
- Do NOT call finish until validation passes. If validation fails, fix the issue and re-run validation.
|
|
1713
|
+
- Do not expose secrets or run destructive commands.
|
|
1714
|
+
- Finish only when done. Use summary, not message.
|
|
1715
|
+
- Do not repeat the same tool call with the same arguments.
|
|
1716
|
+
- Do not ask the user for clarification. Do not say "No task was provided". Use the Task and Description above to proceed.
|
|
1717
|
+
|
|
1718
|
+
Example response for "Add a greet function":
|
|
1719
|
+
{ "tool_calls": [
|
|
1720
|
+
{ "id": "1", "name": "think", "arguments": { "thought": "Create greet.js with greet(name)." } },
|
|
1721
|
+
{ "id": "2", "name": "write_file", "arguments": { "path": "greet.js", "content": "export function greet(name) { return 'Hello, ' + name + '!'; }
|
|
1722
|
+
" } },
|
|
1723
|
+
{ "id": "3", "name": "publish", "arguments": {} },
|
|
1724
|
+
{ "id": "4", "name": "finish", "arguments": { "summary": "Created greet.js and verified tests pass.", "success": true } }
|
|
1725
|
+
] }`;
|
|
1726
|
+
|
|
1727
|
+
// ../agent/dist/prompt-versioning.js
|
|
1728
|
+
import fs7 from "node:fs/promises";
|
|
1729
|
+
import path9 from "node:path";
|
|
1730
|
+
import crypto from "node:crypto";
|
|
1731
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
1732
|
+
var __dirname3 = path9.dirname(fileURLToPath4(import.meta.url));
|
|
1733
|
+
var PROMPTS_PATH = path9.resolve(__dirname3, "..", "src", "prompts.ts");
|
|
1734
|
+
var PLANNER_PATH = path9.resolve(__dirname3, "..", "src", "planner.ts");
|
|
1735
|
+
function hashString(value) {
|
|
1736
|
+
return crypto.createHash("sha256").update(value).digest("hex").slice(0, 16);
|
|
1737
|
+
}
|
|
1738
|
+
function hashPrompts(input) {
|
|
1739
|
+
return hashString([input.systemPrompt, input.textToolsPrompt, input.planningPrompt ?? ""].join("\n---\n"));
|
|
1740
|
+
}
|
|
1741
|
+
async function readPromptsSource() {
|
|
1742
|
+
const source = await fs7.readFile(PROMPTS_PATH, "utf-8");
|
|
1743
|
+
const systemMatch = /export const AGENT_SYSTEM_PROMPT =\s*(?:loadPromptFromEnv\('OMEGA_SYSTEM_PROMPT'\) \?\?\s*)?`([\s\S]*?)`;/m.exec(source);
|
|
1744
|
+
const textToolsMatch = /export const TEXT_TOOLS_SYSTEM_PROMPT =\s*(?:loadPromptFromEnv\('OMEGA_TEXT_TOOLS_PROMPT'\) \?\?\s*)?`([\s\S]*?)`;/m.exec(source);
|
|
1745
|
+
return {
|
|
1746
|
+
systemPrompt: systemMatch?.[1] ?? "",
|
|
1747
|
+
textToolsPrompt: textToolsMatch?.[1] ?? ""
|
|
1748
|
+
};
|
|
1749
|
+
}
|
|
1750
|
+
async function loadCurrentPrompts() {
|
|
1751
|
+
const { systemPrompt, textToolsPrompt } = await readPromptsSource();
|
|
1752
|
+
const plannerSource = await fs7.readFile(PLANNER_PATH, "utf-8");
|
|
1753
|
+
const planningMatch = /const PLAN_PROMPT = `([\s\S]*?)`;/m.exec(plannerSource);
|
|
1754
|
+
const planningPrompt = planningMatch?.[1];
|
|
1755
|
+
return {
|
|
1756
|
+
name: `auto-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`,
|
|
1757
|
+
sourcePath: PROMPTS_PATH,
|
|
1758
|
+
systemPrompt,
|
|
1759
|
+
textToolsPrompt,
|
|
1760
|
+
planningPrompt,
|
|
1761
|
+
hash: hashPrompts({ systemPrompt, textToolsPrompt, planningPrompt })
|
|
1762
|
+
};
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1435
1765
|
// ../../apps/cli/src/commands/bench.ts
|
|
1436
1766
|
async function waitForApi2(apiUrl, maxMs = 1e4) {
|
|
1437
1767
|
const deadline = Date.now() + maxMs;
|
|
@@ -1447,38 +1777,75 @@ async function waitForApi2(apiUrl, maxMs = 1e4) {
|
|
|
1447
1777
|
}
|
|
1448
1778
|
function currentProject(apiUrl) {
|
|
1449
1779
|
const cwd = process.cwd();
|
|
1450
|
-
const name =
|
|
1780
|
+
const name = path10.basename(cwd);
|
|
1451
1781
|
return ensureProject2(apiUrl, `bench-${name}`, cwd);
|
|
1452
1782
|
}
|
|
1453
|
-
|
|
1454
|
-
const
|
|
1455
|
-
await
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1783
|
+
async function savePromptVersion(apiUrl, name) {
|
|
1784
|
+
const current = await loadCurrentPrompts();
|
|
1785
|
+
const versionRes = await fetch(`${apiUrl}/prompt-versions`, {
|
|
1786
|
+
method: "POST",
|
|
1787
|
+
headers: { "Content-Type": "application/json" },
|
|
1788
|
+
body: JSON.stringify({
|
|
1789
|
+
name: name ?? current.name,
|
|
1790
|
+
sourcePath: current.sourcePath,
|
|
1791
|
+
systemPrompt: current.systemPrompt,
|
|
1792
|
+
textToolsPrompt: current.textToolsPrompt,
|
|
1793
|
+
hash: current.hash,
|
|
1794
|
+
metadata: { planningPrompt: current.planningPrompt }
|
|
1795
|
+
})
|
|
1796
|
+
});
|
|
1797
|
+
if (!versionRes.ok) {
|
|
1798
|
+
console.warn("Could not save prompt version:", await versionRes.text());
|
|
1799
|
+
return void 0;
|
|
1800
|
+
}
|
|
1801
|
+
return versionRes.json();
|
|
1802
|
+
}
|
|
1803
|
+
async function loadPromptSpec(source) {
|
|
1804
|
+
if (source === "current") {
|
|
1805
|
+
const current = await loadCurrentPrompts();
|
|
1806
|
+
return {
|
|
1807
|
+
name: "current",
|
|
1808
|
+
systemPrompt: current.systemPrompt,
|
|
1809
|
+
textToolsPrompt: current.textToolsPrompt
|
|
1810
|
+
};
|
|
1811
|
+
}
|
|
1812
|
+
const raw = await fs8.readFile(path10.resolve(source), "utf-8");
|
|
1813
|
+
const parsed = JSON.parse(raw);
|
|
1814
|
+
if (!parsed.systemPrompt || !parsed.textToolsPrompt) {
|
|
1815
|
+
throw new Error("Prompt spec must include systemPrompt and textToolsPrompt");
|
|
1816
|
+
}
|
|
1817
|
+
return parsed;
|
|
1818
|
+
}
|
|
1819
|
+
async function resolveTasks(opts) {
|
|
1459
1820
|
if (opts.suite === "deep-swe") {
|
|
1460
1821
|
if (!opts.path) {
|
|
1461
1822
|
throw new Error("--path is required for the deep-swe suite");
|
|
1462
1823
|
}
|
|
1463
|
-
tasks = await loadDeepSWESuite({
|
|
1824
|
+
const tasks = await loadDeepSWESuite({
|
|
1464
1825
|
tasksDir: opts.path,
|
|
1465
1826
|
nTasks: opts.nTasks,
|
|
1466
1827
|
sampleSeed: opts.sampleSeed
|
|
1467
1828
|
});
|
|
1468
|
-
suiteName
|
|
1469
|
-
}
|
|
1470
|
-
|
|
1829
|
+
return { tasks, suiteName: "deep-swe" };
|
|
1830
|
+
}
|
|
1831
|
+
if (opts.suite === "synthetic") {
|
|
1832
|
+
let tasks = syntheticSuite();
|
|
1471
1833
|
if (opts.nTasks !== void 0 && opts.nTasks > 0) {
|
|
1472
1834
|
tasks = tasks.slice(0, opts.nTasks);
|
|
1473
1835
|
}
|
|
1474
|
-
suiteName
|
|
1475
|
-
} else {
|
|
1476
|
-
throw new Error(`Unknown suite: ${opts.suite}`);
|
|
1836
|
+
return { tasks, suiteName: "synthetic" };
|
|
1477
1837
|
}
|
|
1838
|
+
throw new Error(`Unknown suite: ${opts.suite}`);
|
|
1839
|
+
}
|
|
1840
|
+
var runCmd = new Command8("run").description("Run a benchmark suite").option("--suite <name>", "suite name: synthetic | deep-swe", "synthetic").option("--path <dir>", "path to DeepSWE tasks directory (for deep-swe suite)").option("--n-tasks <n>", "limit number of tasks", parseInt).option("--sample-seed <n>", "seed for deterministic sampling (for deep-swe)", parseInt).option("--timeout <ms>", "per-task timeout in ms", "120000").option("--output-dir <dir>", "report output directory", ".omega/reports").option("--provider <name>", "provider to use for benchmark tasks").option("--model <model>", "model to use for benchmark tasks").action(async (opts) => {
|
|
1841
|
+
const apiUrl = getApiUrl();
|
|
1842
|
+
await waitForApi2(apiUrl);
|
|
1843
|
+
const { tasks, suiteName } = await resolveTasks(opts);
|
|
1478
1844
|
if (tasks.length === 0) {
|
|
1479
1845
|
console.log("No benchmark tasks to run.");
|
|
1480
1846
|
return;
|
|
1481
1847
|
}
|
|
1848
|
+
const timeoutMs = Number(opts.timeout);
|
|
1482
1849
|
console.log(`Running ${String(tasks.length)} benchmark tasks against ${apiUrl}`);
|
|
1483
1850
|
const report = await runBenchmark(tasks, {
|
|
1484
1851
|
apiUrl,
|
|
@@ -1514,7 +1881,113 @@ var optimiseCmd = new Command8("optimise").description("Create a self-improve ta
|
|
|
1514
1881
|
console.log(`Created self-improve task ${task.id}`);
|
|
1515
1882
|
console.log(`Run \`omega task run ${task.id}\` to execute it.`);
|
|
1516
1883
|
});
|
|
1517
|
-
var
|
|
1884
|
+
var abCmd = new Command8("ab").description("Run an A/B benchmark comparing two prompt versions").option("--baseline <source>", 'baseline prompts: "current" or path to JSON file', "current").option("--candidate <source>", "candidate prompts: path to JSON file").option("--suite <name>", "suite name: synthetic | deep-swe", "synthetic").option("--path <dir>", "path to DeepSWE tasks directory (for deep-swe suite)").option("--n-tasks <n>", "limit number of tasks", parseInt).option("--sample-seed <n>", "seed for deterministic sampling (for deep-swe)", parseInt).option("--timeout <ms>", "per-task timeout in ms", "120000").option("--output-dir <dir>", "report output directory", ".omega/reports").option("--provider <name>", "provider to use for benchmark tasks").option("--model <model>", "model to use for benchmark tasks").action(async (opts) => {
|
|
1885
|
+
if (!opts.candidate) {
|
|
1886
|
+
throw new Error("--candidate is required");
|
|
1887
|
+
}
|
|
1888
|
+
if (opts.suite === "deep-swe") {
|
|
1889
|
+
throw new Error("DeepSWE A/B not yet supported; use --suite synthetic");
|
|
1890
|
+
}
|
|
1891
|
+
const apiUrl = getApiUrl();
|
|
1892
|
+
await waitForApi2(apiUrl);
|
|
1893
|
+
const { tasks, suiteName } = await resolveTasks(opts);
|
|
1894
|
+
if (tasks.length === 0) {
|
|
1895
|
+
console.log("No benchmark tasks to run.");
|
|
1896
|
+
return;
|
|
1897
|
+
}
|
|
1898
|
+
const timeoutMs = Number(opts.timeout);
|
|
1899
|
+
const baselineSpec = await loadPromptSpec(opts.baseline);
|
|
1900
|
+
const candidateSpec = await loadPromptSpec(opts.candidate);
|
|
1901
|
+
console.log(`Baseline: ${baselineSpec.name}`);
|
|
1902
|
+
console.log(`Candidate: ${candidateSpec.name}`);
|
|
1903
|
+
const report = await runAbBenchmark(tasks, baselineSpec, candidateSpec, {
|
|
1904
|
+
apiUrl,
|
|
1905
|
+
suiteName,
|
|
1906
|
+
timeoutMs,
|
|
1907
|
+
provider: opts.provider,
|
|
1908
|
+
model: opts.model,
|
|
1909
|
+
onProgress: (result) => {
|
|
1910
|
+
const symbol = result.evaluation.passed ? "\u2713" : "\u2717";
|
|
1911
|
+
console.log(`${symbol} ${result.task.name} [${result.status}] ${String(result.durationMs)}ms`);
|
|
1912
|
+
}
|
|
1913
|
+
});
|
|
1914
|
+
await fs8.mkdir(opts.outputDir, { recursive: true });
|
|
1915
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1916
|
+
const jsonFile = path10.join(opts.outputDir, `ab-${ts}.json`);
|
|
1917
|
+
const mdFile = path10.join(opts.outputDir, `ab-${ts}.md`);
|
|
1918
|
+
await fs8.writeFile(jsonFile, JSON.stringify(report, null, 2), "utf-8");
|
|
1919
|
+
await fs8.writeFile(mdFile, formatAbReport(report), "utf-8");
|
|
1920
|
+
console.log("\n" + formatAbReport(report));
|
|
1921
|
+
console.log(`
|
|
1922
|
+
A/B report written to ${jsonFile}`);
|
|
1923
|
+
});
|
|
1924
|
+
var loopCmd = new Command8("loop").description("Run a self-improve benchmark loop").option("--suite <name>", "suite name: synthetic | deep-swe", "synthetic").option("--path <dir>", "path to DeepSWE tasks directory (for deep-swe suite)").option("--n-tasks <n>", "limit number of tasks", parseInt).option("--sample-seed <n>", "seed for deterministic sampling (for deep-swe)", parseInt).option("--iterations <n>", "max iterations", "1").option("--timeout <ms>", "per-task timeout in ms", "120000").option("--output-dir <dir>", "report output directory", ".omega/reports").option("--provider <name>", "provider to use for self-improve tasks").option("--model <model>", "model to use for self-improve tasks").action(async (opts) => {
|
|
1925
|
+
const apiUrl = getApiUrl();
|
|
1926
|
+
await waitForApi2(apiUrl);
|
|
1927
|
+
const { tasks, suiteName } = await resolveTasks(opts);
|
|
1928
|
+
if (tasks.length === 0) {
|
|
1929
|
+
console.log("No benchmark tasks to run.");
|
|
1930
|
+
return;
|
|
1931
|
+
}
|
|
1932
|
+
const timeoutMs = Number(opts.timeout);
|
|
1933
|
+
const maxIterations = Number(opts.iterations);
|
|
1934
|
+
const project = await currentProject(apiUrl);
|
|
1935
|
+
for (let i = 1; i <= maxIterations; i++) {
|
|
1936
|
+
console.log(`
|
|
1937
|
+
=== Iteration ${String(i)}/${String(maxIterations)} ===`);
|
|
1938
|
+
const beforeVersion = await savePromptVersion(apiUrl, `loop-before-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`);
|
|
1939
|
+
if (beforeVersion) {
|
|
1940
|
+
console.log(`Saved before-loop prompt version: ${beforeVersion.name} (${beforeVersion.id})`);
|
|
1941
|
+
}
|
|
1942
|
+
console.log(`
|
|
1943
|
+
Running ${String(tasks.length)} benchmark tasks...`);
|
|
1944
|
+
const report = await runBenchmark(tasks, {
|
|
1945
|
+
apiUrl,
|
|
1946
|
+
suiteName,
|
|
1947
|
+
timeoutMs,
|
|
1948
|
+
provider: opts.provider,
|
|
1949
|
+
model: opts.model,
|
|
1950
|
+
onProgress: (result) => {
|
|
1951
|
+
const symbol = result.evaluation.passed ? "\u2713" : "\u2717";
|
|
1952
|
+
console.log(`${symbol} ${result.task.name} [${result.status}] ${String(result.durationMs)}ms`);
|
|
1953
|
+
}
|
|
1954
|
+
});
|
|
1955
|
+
await writeReport(report, opts.outputDir);
|
|
1956
|
+
printSummary(report);
|
|
1957
|
+
const passRate2 = report.total > 0 ? Math.round(report.passed / report.total * 100) : 0;
|
|
1958
|
+
if (passRate2 === 100) {
|
|
1959
|
+
console.log("\nAll tasks passed. Loop complete.");
|
|
1960
|
+
break;
|
|
1961
|
+
}
|
|
1962
|
+
const context = await loadOptimisationContext(apiUrl, opts.outputDir);
|
|
1963
|
+
if (!context) {
|
|
1964
|
+
throw new Error("Benchmark report could not be loaded for optimisation");
|
|
1965
|
+
}
|
|
1966
|
+
const prompt = buildOptimisePrompt(context.report, context.failedResult, context.traceFlowText);
|
|
1967
|
+
const task = await submitOptimiseTask(apiUrl, project.id, prompt);
|
|
1968
|
+
if (opts.provider || opts.model) {
|
|
1969
|
+
await fetch(`${apiUrl}/tasks/${task.id}`, {
|
|
1970
|
+
method: "PATCH",
|
|
1971
|
+
headers: { "Content-Type": "application/json" },
|
|
1972
|
+
body: JSON.stringify({ provider: opts.provider, model: opts.model })
|
|
1973
|
+
});
|
|
1974
|
+
}
|
|
1975
|
+
console.log(`
|
|
1976
|
+
Created self-improve task ${task.id}${opts.provider ? ` (provider: ${opts.provider})` : ""}${opts.model ? ` (model: ${opts.model})` : ""}`);
|
|
1977
|
+
console.log("Running agent...");
|
|
1978
|
+
await runTask(apiUrl, task.id);
|
|
1979
|
+
const finished = await waitForTask(apiUrl, task.id, timeoutMs * 5);
|
|
1980
|
+
console.log(`Agent finished: ${finished.status}`);
|
|
1981
|
+
if (finished.error) {
|
|
1982
|
+
console.error(`Agent error: ${finished.error}`);
|
|
1983
|
+
}
|
|
1984
|
+
const afterVersion = await savePromptVersion(apiUrl, `loop-after-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}`);
|
|
1985
|
+
if (afterVersion) {
|
|
1986
|
+
console.log(`Saved after-loop prompt version: ${afterVersion.name} (${afterVersion.id})`);
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
});
|
|
1990
|
+
var benchCmd = new Command8("bench").description("Run benchmarks and optimise prompts").addCommand(runCmd).addCommand(abCmd).addCommand(optimiseCmd).addCommand(loopCmd);
|
|
1518
1991
|
|
|
1519
1992
|
// ../../apps/cli/src/index.ts
|
|
1520
1993
|
program2.name("harness").description("Omega harness CLI").version("0.1.0").option("--api <url>", "API base URL", "http://localhost:4000");
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|