loki-mode 11.5.1 → 11.7.1
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/README.md +19 -2
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/lib/backlog.py +11 -2
- package/autonomy/lib/chat.sh +57 -1
- package/autonomy/lib/loki_yaml.py +8 -2
- package/autonomy/lib/workspace.py +267 -11
- package/autonomy/loki +327 -222
- package/autonomy/notification-checker.py +1 -1
- package/autonomy/trigger-server.py +185 -2
- package/autonomy/verify.sh +4 -0
- package/completions/_loki +4 -0
- package/completions/loki.bash +20 -2
- package/dashboard/__init__.py +3 -10
- package/dashboard/control.py +5 -435
- package/docs/ARCHITECTURE.md +1 -2
- package/docs/CLI-CORE-VERBS.md +2 -6
- package/docs/CLI-REFERENCE.md +2 -1
- package/docs/COMPONENTS.md +0 -2
- package/docs/DEPLOY-PLAN.md +17 -8
- package/docs/EVALUATING.md +8 -0
- package/docs/INSTALLATION.md +1 -1
- package/docs/WORKSPACES.md +15 -2
- package/docs/authentication.md +19 -1
- package/docs/dev/architecture-reference.md +8 -0
- package/docs/dev/release-checklist.md +9 -8
- package/docs/enterprise/security.md +3 -234
- package/docs/sentry-intake.md +11 -0
- package/docs/v10/ARCHITECT-CUTS.md +304 -0
- package/docs/v10/CLI-MODERN.md +1 -1
- package/docs/v10/DECISIONS.md +5 -5
- package/docs/v10/ENGINE.md +735 -299
- package/docs/v10/GUARDS.md +16 -14
- package/docs/v10/GUIDE.md +5 -7
- package/docs/v10/PROGRESS.md +12 -1
- package/docs/v11/MARKET-SLICES.md +1 -5
- package/integrations/openclaw/README.md +20 -0
- package/integrations/vibe-kanban.md +12 -50
- package/loki-ts/dist/loki.js +1213 -1178
- package/mcp/__init__.py +1 -1
- package/mcp/_sdk_loader.py +1 -1
- package/package.json +2 -2
- package/packages/control-plane/dist/server.js +1090 -924
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/references/quality-control.md +1 -116
- package/schemas/loki-yaml.schema.json +5 -2
- package/skills/00-index.md +2 -2
- package/skills/artifacts.md +0 -22
- package/skills/production.md +2 -38
- package/src/policies/engine.js +41 -2
- package/src/policies/types.js +49 -0
- package/web-app/dist/assets/{AdminPage-Cbu3pXL8.js → AdminPage-S3BYeapm.js} +1 -1
- package/web-app/dist/assets/{Avatar-DGqGGcGx.js → Avatar-C1rHwLgn.js} +1 -1
- package/web-app/dist/assets/{Badge-Bhlipt6v.js → Badge-CzlnN5aQ.js} +1 -1
- package/web-app/dist/assets/{Button-CpN2sO61.js → Button-B1w5AeGC.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-BqeDJwdL.js → CockpitPage-Dyeqjfkc.js} +1 -1
- package/web-app/dist/assets/{ComparePage-DUieA2ba.js → ComparePage-C6y2GkGR.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-DTWsYrOm.js → ErrorBoundary-Dg2fcGkR.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-BU_B9X19.js → EvidenceReceiptPanel-CxbyjvTj.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-DEZoLOsP.js → GitHubIssuesPanel-Dpys1xDb.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-BEsnrq7Y.js → GitHubPRsPanel-CRVjWoFl.js} +1 -1
- package/web-app/dist/assets/{HomePage-BoUVuq7h.js → HomePage-BKnv-oYw.js} +2 -2
- package/web-app/dist/assets/{LoginPage-CmOED7vb.js → LoginPage-BGksmFRd.js} +1 -1
- package/web-app/dist/assets/{MagicPage-DATZitrZ.js → MagicPage-OCvhp16M.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-DGL1v0I-.js → MetricsPage-CJOJpXWC.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-C2WgOjZd.js → NotFoundPage-C04p3QvN.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-BMi1tepj.js → ProjectPage-BRB8txsY.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-vc3y5YPh.js → ProjectsPage-CoUYeQEh.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-kbq0Ftvi.js → SettingsPage-BkjmJGfM.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-Bn6Q8Kbg.js → ShowcasePage-B4vU9TjQ.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-Basmhs_b.js → SystemSettingsPage-Z2jiVsni.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-BTqOc4TR.js → TeamsPage-Ulm8SISq.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-2P9002VL.js → TemplatesPage-C_7MM6Ey.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-CAoSPBrg.js → TerminalOutput-Cumd7Tgs.js} +1 -1
- package/web-app/dist/assets/{activity-BcWVWCqU.js → activity-CZAUkbiY.js} +1 -1
- package/web-app/dist/assets/{bell-CYRqqgZ6.js → bell-BOvSXpEr.js} +1 -1
- package/web-app/dist/assets/{bot-CU7gdn3g.js → bot-DOTZxBYj.js} +1 -1
- package/web-app/dist/assets/{check-DLlCpz9V.js → check-BxpE0B5u.js} +1 -1
- package/web-app/dist/assets/{chevron-left-CE9Cb30C.js → chevron-left-D6KPvBOA.js} +1 -1
- package/web-app/dist/assets/{circle-alert-uou4bjua.js → circle-alert-Bajq86oe.js} +1 -1
- package/web-app/dist/assets/{clock-C_dSJcDX.js → clock-CnlHAVJc.js} +1 -1
- package/web-app/dist/assets/{cloud-DZ22ITF6.js → cloud-DjaymjwM.js} +1 -1
- package/web-app/dist/assets/{code-xml-BrJS0hhS.js → code-xml-BADEw2Ld.js} +1 -1
- package/web-app/dist/assets/{database-D2HOmxtl.js → database-B4aKb5Cq.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-CQ1vK_6q.js → dollar-sign-DrldXpja.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-w2vpGm5d.js → file-code-corner-DVebDVR-.js} +1 -1
- package/web-app/dist/assets/{file-plus-DlF6wjkD.js → file-plus-BD-N_-Tl.js} +1 -1
- package/web-app/dist/assets/{globe-Dy3lBJg1.js → globe-C7ieInC-.js} +1 -1
- package/web-app/dist/assets/{hammer-C3xIiRXN.js → hammer-BSugKIji.js} +1 -1
- package/web-app/dist/assets/{index-4t-_IW2y.js → index-nLQgfvOn.js} +3 -3
- package/web-app/dist/assets/{layers-Y8Fs8qXI.js → layers-CHXxU2on.js} +1 -1
- package/web-app/dist/assets/{loader-circle-CxgN1v4m.js → loader-circle-BEEz0LbD.js} +1 -1
- package/web-app/dist/assets/{lock-DFFNbXDs.js → lock-CzQGfcnE.js} +1 -1
- package/web-app/dist/assets/{package-5e6qCTUg.js → package-CcHYQLGd.js} +1 -1
- package/web-app/dist/assets/{plus-C0Go_ytj.js → plus-DdzgFEXn.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-D4i-NW3o.js → refresh-cw-7x0HbH9Y.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-YlKkiUW6.js → rotate-ccw-DBahX1Sp.js} +1 -1
- package/web-app/dist/assets/{scroll-text-4qXOHTap.js → scroll-text-BB8y8a9Z.js} +1 -1
- package/web-app/dist/assets/{server-BB6zXNp9.js → server-CfkbW2MH.js} +1 -1
- package/web-app/dist/assets/{shield-alert-D4tzjB1H.js → shield-alert-DUgD8rBF.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-DZiRwdFj.js → thumbs-up-DGoyY6QC.js} +1 -1
- package/web-app/dist/assets/{trash-2-Dv_LkRIK.js → trash-2-B6xrSUMr.js} +1 -1
- package/web-app/dist/assets/{trending-down-BJYp9PQe.js → trending-down-B6RGKTOx.js} +1 -1
- package/web-app/dist/assets/{trending-up-BTcXLklK.js → trending-up-B44DCrt1.js} +1 -1
- package/web-app/dist/assets/{upload-fcHqwOxr.js → upload-4kWm33ZY.js} +1 -1
- package/web-app/dist/assets/{usePolling-BeJYw_4L.js → usePolling-zkUtRQG6.js} +1 -1
- package/web-app/dist/assets/{user-BcDwUCsO.js → user-04cEVIe2.js} +1 -1
- package/web-app/dist/index.html +1 -1
- package/dashboard/run.py +0 -63
- package/docs/openclaw-integration.md +0 -52
- package/docs/v10/HANDOFF-NEXT-WEEK.md +0 -40
- package/docs/v10/MORNING-BRIEF-1003.md +0 -25
- package/docs/v10/MORNING-BRIEF.md +0 -52
- package/docs/v10/TODO.md +0 -35
- package/mcp/resources.py +0 -351
- package/mcp/tools.py +0 -200
|
@@ -7325,6 +7325,25 @@ var init_paths = __esm(() => {
|
|
|
7325
7325
|
REPO_ROOT = findRepoRoot();
|
|
7326
7326
|
});
|
|
7327
7327
|
|
|
7328
|
+
// ../../loki-ts/src/engine10/registry.ts
|
|
7329
|
+
var init_registry = () => {};
|
|
7330
|
+
|
|
7331
|
+
// ../../loki-ts/src/engine10/output.ts
|
|
7332
|
+
var init_output = __esm(() => {
|
|
7333
|
+
init_registry();
|
|
7334
|
+
init_redact();
|
|
7335
|
+
});
|
|
7336
|
+
|
|
7337
|
+
// ../../loki-ts/src/commands/run_status.ts
|
|
7338
|
+
var STALE_S, TERMINAL2;
|
|
7339
|
+
var init_run_status = __esm(() => {
|
|
7340
|
+
init_discover();
|
|
7341
|
+
init_events();
|
|
7342
|
+
init_output();
|
|
7343
|
+
STALE_S = 30 * 60;
|
|
7344
|
+
TERMINAL2 = new Set(["stage.completed", "stage.failed", "stage.skipped"]);
|
|
7345
|
+
});
|
|
7346
|
+
|
|
7328
7347
|
// ../../loki-ts/src/engine10/types.ts
|
|
7329
7348
|
function pushArgv(a) {
|
|
7330
7349
|
switch (a.cmd) {
|
|
@@ -7372,243 +7391,6 @@ var init_spec_file = __esm(() => {
|
|
|
7372
7391
|
SPEC_DIR = join26(".loki", "specs");
|
|
7373
7392
|
});
|
|
7374
7393
|
|
|
7375
|
-
// ../../loki-ts/src/engine10/registry.ts
|
|
7376
|
-
var init_registry = () => {};
|
|
7377
|
-
|
|
7378
|
-
// ../../loki-ts/src/engine10/output.ts
|
|
7379
|
-
var init_output = __esm(() => {
|
|
7380
|
-
init_registry();
|
|
7381
|
-
init_redact();
|
|
7382
|
-
});
|
|
7383
|
-
|
|
7384
|
-
// ../../loki-ts/src/runner/router/flag.ts
|
|
7385
|
-
function routerMode(env = process.env) {
|
|
7386
|
-
const v = (env.LOKI_ROUTER ?? "").trim().toLowerCase();
|
|
7387
|
-
if (v === "0" || v === "false" || v === "off")
|
|
7388
|
-
return "opt-out";
|
|
7389
|
-
if (v === "1" || v === "true" || v === "on")
|
|
7390
|
-
return "on";
|
|
7391
|
-
return "off";
|
|
7392
|
-
}
|
|
7393
|
-
var routerEnabled = (env = process.env) => routerMode(env) === "on";
|
|
7394
|
-
|
|
7395
|
-
// ../../loki-ts/src/runner/router/route_block.ts
|
|
7396
|
-
function advisorUnavailableReason(env, provider) {
|
|
7397
|
-
if (provider !== "claude")
|
|
7398
|
-
return `provider ${provider} has no advisor tool`;
|
|
7399
|
-
if (env["CLAUDE_CODE_USE_BEDROCK"] || env["CLAUDE_CODE_USE_VERTEX"] || env["CLAUDE_CODE_USE_FOUNDRY"])
|
|
7400
|
-
return "advisor tool is unsupported on Bedrock, Vertex and Foundry";
|
|
7401
|
-
if ((env["LOKI_ROUTER_ADVISOR"] ?? "").trim().toLowerCase() === "off")
|
|
7402
|
-
return "LOKI_ROUTER_ADVISOR=off";
|
|
7403
|
-
return null;
|
|
7404
|
-
}
|
|
7405
|
-
function toEsc(raw2) {
|
|
7406
|
-
const esc = Array.isArray(raw2) ? raw2 : [];
|
|
7407
|
-
return esc.map((e) => ({ trigger: s0(e["trigger"]) ?? "unknown", from: modelLabel(s0(e["from"]) ?? "?"), to: modelLabel(s0(e["to"]) ?? "?"), evidence: s0(e["evidence"]) ?? "none recorded" }));
|
|
7408
|
-
}
|
|
7409
|
-
function buildRouteBlock(env, provider, route, telemetry, runModel) {
|
|
7410
|
-
if (!routerEnabled(env))
|
|
7411
|
-
return null;
|
|
7412
|
-
const applied = route?.["applied"] !== false;
|
|
7413
|
-
const executor = s0(route?.["executor"]);
|
|
7414
|
-
const unavailable = s0(route?.["advisor_unavailable_reason"]) ?? advisorUnavailableReason(env, provider);
|
|
7415
|
-
const total = nN(telemetry?.requests_total);
|
|
7416
|
-
const over = nN(telemetry?.requests_over_100k);
|
|
7417
|
-
const shape = s0(route?.["shape_key"]);
|
|
7418
|
-
const escalations = toEsc(route?.["escalations"]);
|
|
7419
|
-
const source = s0(route?.["source"]);
|
|
7420
|
-
const reason = s0(route?.["reason"]) ?? (executor ? "no reason recorded" : "no route recorded by implement");
|
|
7421
|
-
const rawUnits = Array.isArray(route?.["units"]) ? route["units"] : [];
|
|
7422
|
-
const units = rawUnits.length > 0 ? rawUnits.map((u, i) => ({ id: s0(u["id"]) ?? String(i + 1), executor: modelLabel(s0(u["executor"]) ?? "unknown"), applied, assigned_by: assignedBy(s0(u["source"]) ?? source, u["assigned_by"]), reason: s0(u["reason"]) ?? "no reason recorded", escalations: toEsc(u["escalations"]) })) : executor && route?.["routed"] !== false ? [{ id: "run", executor: modelLabel(executor), applied, assigned_by: assignedBy(source, route?.["assigned_by"]), reason, escalations }] : [];
|
|
7423
|
-
return {
|
|
7424
|
-
routed: route?.["routed"] === false ? false : executor !== null || units.length > 0,
|
|
7425
|
-
units,
|
|
7426
|
-
executor: !applied ? `${runModel ? modelLabel(runModel) : "run model"} (per-unit assignment not applied)` : executor ? modelLabel(executor) : units[0]?.executor ?? null,
|
|
7427
|
-
advisor: unavailable ? null : modelLabel(s0(route?.["advisor"]) ?? "opus"),
|
|
7428
|
-
advisor_unavailable_reason: unavailable,
|
|
7429
|
-
reason,
|
|
7430
|
-
source,
|
|
7431
|
-
shape_key: shape,
|
|
7432
|
-
shape_parity: shape ? `NOT PROVEN (no B9 row for shape ${shape})` : "NOT PROVEN (no shape key recorded)",
|
|
7433
|
-
escalations: units.length > 0 ? units.flatMap((u) => u.escalations) : escalations,
|
|
7434
|
-
requests_total: total,
|
|
7435
|
-
requests_over_100k: over,
|
|
7436
|
-
over_100k_share: total !== null && over !== null && total > 0 ? Math.round(over / total * 1e4) / 1e4 : null,
|
|
7437
|
-
advisor_calls: nN(telemetry?.advisor_calls),
|
|
7438
|
-
advisor_input_tokens: nN(telemetry?.advisor_input_tokens),
|
|
7439
|
-
advisor_output_tokens: nN(telemetry?.advisor_output_tokens),
|
|
7440
|
-
plan_model: s0(route?.["plan_model"]),
|
|
7441
|
-
applied,
|
|
7442
|
-
run_model: runModel ?? null,
|
|
7443
|
-
not_proven: Array.isArray(route?.["route_not_proven"]) ? route["route_not_proven"].filter((x) => typeof x === "string") : []
|
|
7444
|
-
};
|
|
7445
|
-
}
|
|
7446
|
-
function routePrLine(r) {
|
|
7447
|
-
if (!r.routed)
|
|
7448
|
-
return `Route: not routed (${r.reason})`;
|
|
7449
|
-
const adv = r.advisor ? `advisor ${r.advisor}` : "advisor unavailable";
|
|
7450
|
-
return `Route: executor ${r.executor}, ${adv}; advisor tokens ${rec(r.advisor_input_tokens)} in / ${rec(r.advisor_output_tokens)} out; over 100K: ${over(r, " requests")}`;
|
|
7451
|
-
}
|
|
7452
|
-
function routeReceiptLines(r) {
|
|
7453
|
-
if (!r.routed)
|
|
7454
|
-
return [`- Route: not routed (${r.reason})`, `- Route shape_parity: ${r.shape_parity}`];
|
|
7455
|
-
return [
|
|
7456
|
-
`- Route: executor ${r.executor}, ${r.advisor ? `advisor ${r.advisor}` : `advisor unavailable: ${r.advisor_unavailable_reason}`}: ${r.reason}`,
|
|
7457
|
-
`- Route shape_key: ${r.shape_key ?? "unknown"} shape_parity: ${r.shape_parity}`,
|
|
7458
|
-
`- Route escalations: ${r.escalations.length === 0 ? "none" : r.escalations.map((e) => `${e.from} -> ${e.to} (${e.trigger}; evidence ${e.evidence})`).join("; ")}`,
|
|
7459
|
-
`- Route advisor: ${rec(r.advisor_calls)} calls, ${rec(r.advisor_input_tokens)} in / ${rec(r.advisor_output_tokens)} out tokens`,
|
|
7460
|
-
...r.units.map((u) => `- Route unit ${u.id}: executor ${u.applied ? u.executor : `not applied (assigned ${u.executor})`}, assigned by ${u.assigned_by}: ${u.reason}; escalation: ${u.escalations.length === 0 ? "none" : u.escalations.map((e) => `${e.from} -> ${e.to} (${e.trigger})`).join(", ")}`),
|
|
7461
|
-
`- Route requests over 100K: ${over(r, "")}`
|
|
7462
|
-
];
|
|
7463
|
-
}
|
|
7464
|
-
function routeNotProven(r) {
|
|
7465
|
-
return [
|
|
7466
|
-
...r.advisor_unavailable_reason ? [`advisor: NOT PROVEN (owner provider): ${r.advisor_unavailable_reason}`] : [],
|
|
7467
|
-
`route.shape_parity: ${r.shape_parity}`,
|
|
7468
|
-
...r.applied ? [] : [`route.executor: NOT PROVEN (owner engine): per-unit executor assignment is not applied (R1-11); every stage ran ${r.run_model ?? "the run model"}`],
|
|
7469
|
-
...r.not_proven
|
|
7470
|
-
];
|
|
7471
|
-
}
|
|
7472
|
-
var ALIAS, modelLabel = (m) => ALIAS[m] ?? m, nN = (v) => typeof v === "number" && Number.isFinite(v) ? v : null, rec = (v) => v === null ? "not recorded" : String(v), s0 = (v) => typeof v === "string" && v.trim() ? v.trim() : null, assignedBy = (src, explicit) => s0(explicit) ?? (src === null || src === "opus" ? "opus" : src), over = (r, unit) => r.requests_total === null || r.requests_over_100k === null ? "not recorded" : `${r.requests_over_100k} of ${r.requests_total}${unit} (${pct(r)})`, pct = (r) => r.over_100k_share === null ? "n/a (no requests)" : `${(r.over_100k_share * 100).toFixed(1)}%`;
|
|
7473
|
-
var init_route_block = __esm(() => {
|
|
7474
|
-
ALIAS = { haiku: "haiku-5.5", sonnet: "sonnet-5.5", opus: "opus-5.5" };
|
|
7475
|
-
});
|
|
7476
|
-
|
|
7477
|
-
// ../../loki-ts/src/features/speed/seal_group.ts
|
|
7478
|
-
import { createHash as createHash6 } from "crypto";
|
|
7479
|
-
import { existsSync as existsSync15, readdirSync as readdirSync9, readFileSync as readFileSync18, statSync as statSync11 } from "fs";
|
|
7480
|
-
import { dirname as dirname7, join as join27 } from "path";
|
|
7481
|
-
function sealGroup(runDir, rh) {
|
|
7482
|
-
const manifestPath = join27(runDir, "group", "manifest.json");
|
|
7483
|
-
if (!existsSync15(manifestPath))
|
|
7484
|
-
return { section: undefined, notProven: [], problems: 0, allUnitsPass: true };
|
|
7485
|
-
const notProven = [];
|
|
7486
|
-
let problems = 0;
|
|
7487
|
-
const fail = (m2) => {
|
|
7488
|
-
problems++;
|
|
7489
|
-
notProven.push(`group: ${m2}`);
|
|
7490
|
-
};
|
|
7491
|
-
const m = readJson3(manifestPath);
|
|
7492
|
-
const list = isObj10(m) && Array.isArray(m["units"]) ? m["units"] : [];
|
|
7493
|
-
if (!isObj10(m) || !ID_RE.test(String(m["group_id"] ?? "")) || list.length === 0) {
|
|
7494
|
-
fail("manifest missing, unreadable or empty");
|
|
7495
|
-
return { section: undefined, notProven, problems, allUnitsPass: false };
|
|
7496
|
-
}
|
|
7497
|
-
const units = [];
|
|
7498
|
-
const seen = new Set, seenLower = new Set;
|
|
7499
|
-
let allUnitsPass = true;
|
|
7500
|
-
list.forEach((raw2, index2) => {
|
|
7501
|
-
const u = isObj10(raw2) ? raw2 : {};
|
|
7502
|
-
const id = String(u["unit_id"] ?? "");
|
|
7503
|
-
if (!ID_RE.test(id) || seen.has(id) || seenLower.has(id.toLowerCase()))
|
|
7504
|
-
return fail(`unit ${index2} has an invalid, duplicate or case-colliding id`);
|
|
7505
|
-
seen.add(id);
|
|
7506
|
-
seenLower.add(id.toLowerCase());
|
|
7507
|
-
const dir = join27(unitsDir(runDir), id), rp = join27(dir, "receipt.json"), ep = join27(dir, "events.jsonl");
|
|
7508
|
-
let bytes;
|
|
7509
|
-
try {
|
|
7510
|
-
bytes = readFileSync18(rp);
|
|
7511
|
-
} catch {
|
|
7512
|
-
return fail(`unit ${id} sub-receipt missing`);
|
|
7513
|
-
}
|
|
7514
|
-
const sub = readJson3(rp);
|
|
7515
|
-
if (!isObj10(sub) || typeof sub["receipt_sha256"] !== "string" || rh(sub) !== sub["receipt_sha256"])
|
|
7516
|
-
return fail(`unit ${id} sub-receipt unreadable or its hash does not recompute`);
|
|
7517
|
-
const verdict = String(sub["verdict"] ?? "");
|
|
7518
|
-
if (!PASSING.has(verdict)) {
|
|
7519
|
-
allUnitsPass = false;
|
|
7520
|
-
notProven.push(`group: unit ${id} verdict ${verdict || "unknown"}`);
|
|
7521
|
-
}
|
|
7522
|
-
units.push({
|
|
7523
|
-
index: index2,
|
|
7524
|
-
unit_id: id,
|
|
7525
|
-
sub_receipt_sha256: sha2(bytes),
|
|
7526
|
-
receipt_sha256: sub["receipt_sha256"],
|
|
7527
|
-
events_file_sha256: existsSync15(ep) ? sha2(readFileSync18(ep)) : null,
|
|
7528
|
-
verdict,
|
|
7529
|
-
goal: text2(u["goal"], 200),
|
|
7530
|
-
files: (Array.isArray(u["files"]) ? u["files"] : []).map((f) => text2(f, 200)).filter(Boolean).slice(0, 50),
|
|
7531
|
-
tests: num3(u["tests"]),
|
|
7532
|
-
tokens: num3(u["tokens"]),
|
|
7533
|
-
model: text2(u["model"], 64)
|
|
7534
|
-
});
|
|
7535
|
-
});
|
|
7536
|
-
const extra = (dirNames(unitsDir(runDir)) ?? []).filter((n2) => !seen.has(n2));
|
|
7537
|
-
for (const n2 of extra)
|
|
7538
|
-
fail(`unit directory ${text2(n2, 64)} is not in the manifest`);
|
|
7539
|
-
return { section: problems === 0 ? { group_id: String(m["group_id"]), units } : undefined, notProven, problems, allUnitsPass: allUnitsPass && problems === 0 };
|
|
7540
|
-
}
|
|
7541
|
-
function capGroupVerdict(v, g) {
|
|
7542
|
-
if (g.problems > 0)
|
|
7543
|
-
return v === "SPEC_CONFLICT" ? v : "FAILED";
|
|
7544
|
-
return !g.allUnitsPass && (v === "VERIFIED" || v === "ALREADY_SATISFIED") ? "PARTIAL" : v;
|
|
7545
|
-
}
|
|
7546
|
-
async function verifyGroup(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
7547
|
-
const runDir = dirname7(receiptPath);
|
|
7548
|
-
const signed = isObj10(receipt["verification"]) && typeof receipt["verification"]["jwt"] === "string";
|
|
7549
|
-
const bad = (reason) => ({ verdict: "TAMPERED", reason: `group: ${reason}` });
|
|
7550
|
-
const g = receipt["group"];
|
|
7551
|
-
if (g === undefined)
|
|
7552
|
-
return existsSync15(join27(runDir, "group", "manifest.json")) ? bad("group directory present but the receipt has no group section") : null;
|
|
7553
|
-
if (!isObj10(g) || !ID_RE.test(String(g["group_id"] ?? "")) || !Array.isArray(g["units"]) || g["units"].length === 0)
|
|
7554
|
-
return bad("group section malformed");
|
|
7555
|
-
const entries = g["units"];
|
|
7556
|
-
const ids = entries.map((e) => isObj10(e) ? String(e["unit_id"] ?? "") : "");
|
|
7557
|
-
if (ids.some((id) => !ID_RE.test(id)) || new Set(ids.map((i) => i.toLowerCase())).size !== ids.length)
|
|
7558
|
-
return bad("unit ids invalid, duplicated or case-colliding");
|
|
7559
|
-
const onDisk = dirNames(unitsDir(runDir));
|
|
7560
|
-
if (onDisk === null || onDisk.join("\x00") !== [...ids].sort().join("\x00"))
|
|
7561
|
-
return bad("unit directories do not match the receipt (missing or extra unit)");
|
|
7562
|
-
let unchecked = null;
|
|
7563
|
-
for (let i = 0;i < entries.length; i++) {
|
|
7564
|
-
const e = entries[i], id = ids[i], dir = join27(unitsDir(runDir), id), rp = join27(dir, "receipt.json"), ep = join27(dir, "events.jsonl");
|
|
7565
|
-
if (e["index"] !== i)
|
|
7566
|
-
return bad(`unit ${id} is out of order (index ${String(e["index"])} at position ${i})`);
|
|
7567
|
-
let bytes;
|
|
7568
|
-
try {
|
|
7569
|
-
if (!statSync11(dir).isDirectory())
|
|
7570
|
-
return bad(`unit ${id} is not a directory`);
|
|
7571
|
-
bytes = readFileSync18(rp);
|
|
7572
|
-
} catch {
|
|
7573
|
-
return bad(`unit ${id} sub-receipt missing`);
|
|
7574
|
-
}
|
|
7575
|
-
if (sha2(bytes) !== e["sub_receipt_sha256"])
|
|
7576
|
-
return bad(`unit ${id} sub-receipt does not match its recorded hash`);
|
|
7577
|
-
const evSha = existsSync15(ep) ? sha2(readFileSync18(ep)) : null;
|
|
7578
|
-
if (evSha !== (e["events_file_sha256"] ?? null))
|
|
7579
|
-
return bad(`unit ${id} events.jsonl does not match its recorded hash`);
|
|
7580
|
-
const sub = readJson3(rp);
|
|
7581
|
-
if (!isObj10(sub) || sub["receipt_sha256"] !== e["receipt_sha256"] || rh(sub) !== e["receipt_sha256"])
|
|
7582
|
-
return bad(`unit ${id} sub-receipt hash does not recompute`);
|
|
7583
|
-
if (String(sub["verdict"] ?? "") !== e["verdict"])
|
|
7584
|
-
return bad(`unit ${id} verdict differs from the combined receipt`);
|
|
7585
|
-
const r = await verifyOne(rp, deps);
|
|
7586
|
-
if (r.verdict === "UNSIGNED" && signed)
|
|
7587
|
-
unchecked ??= `unit ${id} sub-receipt is unsigned under a signed combined receipt`;
|
|
7588
|
-
if (r.verdict === "TAMPERED")
|
|
7589
|
-
return bad(`unit ${id} sub-receipt failed verify: ${r.reasons.join("; ")}`);
|
|
7590
|
-
if (r.verdict === "UNCHECKED")
|
|
7591
|
-
unchecked ??= `unit ${id} sub-receipt not checked: ${r.reasons.join("; ")}`;
|
|
7592
|
-
}
|
|
7593
|
-
return unchecked ? { verdict: "UNCHECKED", reason: `group: ${unchecked}` } : null;
|
|
7594
|
-
}
|
|
7595
|
-
var ID_RE, PASSING, sha2 = (b) => createHash6("sha256").update(b).digest("hex"), isObj10 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), text2 = (v, cap) => typeof v === "string" ? v.replace(/[\x00-\x1f\x7f]+/g, " ").trim().slice(0, cap) : "", num3 = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : 0, unitsDir = (runDir) => join27(runDir, "group", "units"), readJson3 = (p) => {
|
|
7596
|
-
try {
|
|
7597
|
-
return JSON.parse(readFileSync18(p, "utf8"));
|
|
7598
|
-
} catch {
|
|
7599
|
-
return;
|
|
7600
|
-
}
|
|
7601
|
-
}, dirNames = (d) => {
|
|
7602
|
-
try {
|
|
7603
|
-
return readdirSync9(d).filter((n2) => !n2.startsWith(".")).sort();
|
|
7604
|
-
} catch {
|
|
7605
|
-
return null;
|
|
7606
|
-
}
|
|
7607
|
-
};
|
|
7608
|
-
var init_seal_group = __esm(() => {
|
|
7609
|
-
ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
7610
|
-
PASSING = new Set(["VERIFIED", "ALREADY_SATISFIED"]);
|
|
7611
|
-
});
|
|
7612
7394
|
// ../../loki-ts/src/engine10/pr_body.ts
|
|
7613
7395
|
function aiTrailers(i, env = process.env) {
|
|
7614
7396
|
if (!markingOn(env))
|
|
@@ -7616,16 +7398,11 @@ function aiTrailers(i, env = process.env) {
|
|
|
7616
7398
|
return ["AI-Generated: true", `AI-Provider: ${clean(i.provider)}`, `AI-Model: ${clean(i.model)}`, `Loki-Receipt: ${clean(i.receiptRel)}`];
|
|
7617
7399
|
}
|
|
7618
7400
|
var markingOn = (env) => env["LOKI_AI_MARKING"] === "1", clean = (v) => v.replace(/[\u0000-\u001f\u007f\u2028\u2029]+/g, " ").replace(/\s+/g, " ").trim().slice(0, 100) || "unknown";
|
|
7619
|
-
var init_pr_body = __esm(() => {
|
|
7620
|
-
init_output();
|
|
7621
|
-
init_route_block();
|
|
7622
|
-
init_seal_group();
|
|
7623
|
-
});
|
|
7624
7401
|
|
|
7625
7402
|
// ../../loki-ts/src/util/credential_env.ts
|
|
7626
|
-
import { mkdtempSync as mkdtempSync2, rmSync as rmSync4, statSync as
|
|
7403
|
+
import { mkdtempSync as mkdtempSync2, rmSync as rmSync4, statSync as statSync11, lstatSync as lstatSync4 } from "fs";
|
|
7627
7404
|
import { tmpdir as tmpdir3 } from "os";
|
|
7628
|
-
import { join as
|
|
7405
|
+
import { join as join27 } from "path";
|
|
7629
7406
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
7630
7407
|
function withheldSentinel(fresh = false) {
|
|
7631
7408
|
if (fresh)
|
|
@@ -7644,7 +7421,7 @@ function emptyGhConfigDir(env = process.env) {
|
|
|
7644
7421
|
const runTmp = env["LOKI_RUN_TMP"] ?? "";
|
|
7645
7422
|
const root = runTmp !== "" && isDir(runTmp) ? runTmp : tmpdir3();
|
|
7646
7423
|
try {
|
|
7647
|
-
configDir = mkdtempSync2(
|
|
7424
|
+
configDir = mkdtempSync2(join27(root, "loki-gh-config-"));
|
|
7648
7425
|
} catch {
|
|
7649
7426
|
return null;
|
|
7650
7427
|
}
|
|
@@ -7685,7 +7462,7 @@ function hardenCredentialEnv(env, fresh = false) {
|
|
|
7685
7462
|
}
|
|
7686
7463
|
var GITHUB_TOKEN_VARS, SENTINEL_PREFIX = "ghp_LOKIWITHHELDsentinel", sentinel = null, configDir = null, exitHooked = false, sigtermHooked = false, isDir = (p) => {
|
|
7687
7464
|
try {
|
|
7688
|
-
return !lstatSync4(p).isSymbolicLink() &&
|
|
7465
|
+
return !lstatSync4(p).isSymbolicLink() && statSync11(p).isDirectory();
|
|
7689
7466
|
} catch {
|
|
7690
7467
|
return false;
|
|
7691
7468
|
}
|
|
@@ -7799,17 +7576,21 @@ var init_safe_git = __esm(() => {
|
|
|
7799
7576
|
OPT_WITH_VALUE = new Set(["-C", "-c", "--git-dir", "--work-tree", "--namespace", "--exec-path", "--config-env", "--attr-source"]);
|
|
7800
7577
|
SECRET_VARS = ["GH_TOKEN", "GITHUB_TOKEN", "GH_ENTERPRISE_TOKEN", "GITHUB_ENTERPRISE_TOKEN", "SSH_AUTH_SOCK"];
|
|
7801
7578
|
});
|
|
7579
|
+
// ../../loki-ts/src/util/yaml_key.ts
|
|
7580
|
+
var init_yaml_key = () => {};
|
|
7581
|
+
|
|
7802
7582
|
// ../../loki-ts/src/util/run_cap.ts
|
|
7803
7583
|
var MAX_SCOPE_BYTES;
|
|
7804
7584
|
var init_run_cap = __esm(() => {
|
|
7805
7585
|
init_types();
|
|
7586
|
+
init_yaml_key();
|
|
7806
7587
|
MAX_SCOPE_BYTES = 256 * 1024;
|
|
7807
7588
|
});
|
|
7808
7589
|
|
|
7809
7590
|
// ../../loki-ts/src/util/mutation_proof.ts
|
|
7810
|
-
import { existsSync as
|
|
7591
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync5, mkdtempSync as mkdtempSync3, readFileSync as readFileSync18, rmSync as rmSync5, symlinkSync, writeFileSync as writeFileSync8 } from "fs";
|
|
7811
7592
|
import { tmpdir as tmpdir4 } from "os";
|
|
7812
|
-
import { basename as basename8, dirname as
|
|
7593
|
+
import { basename as basename8, dirname as dirname7, isAbsolute as isAbsolute2, join as join28, relative as relative2 } from "path";
|
|
7813
7594
|
function mutationProof(i) {
|
|
7814
7595
|
const rels = i.wallFiles.map((f) => isAbsolute2(f.path) ? relative2(i.repoDir, f.path) : f.path);
|
|
7815
7596
|
if (rels.length === 0)
|
|
@@ -7827,26 +7608,26 @@ function mutationProof(i) {
|
|
|
7827
7608
|
const deadline = Date.now() + budgetS * 1000, remaining = () => deadline - Date.now();
|
|
7828
7609
|
let parent = null, wt = null, added = false;
|
|
7829
7610
|
try {
|
|
7830
|
-
parent = mkdtempSync3(
|
|
7831
|
-
wt =
|
|
7611
|
+
parent = mkdtempSync3(join28(tmpdir4(), "loki-mutproof-"));
|
|
7612
|
+
wt = join28(parent, "wt");
|
|
7832
7613
|
const add2 = git(i.repoDir, ["worktree", "add", "--detach", wt, i.baseSha], Math.max(1000, Math.min(30000, remaining())));
|
|
7833
|
-
added =
|
|
7614
|
+
added = existsSync15(wt) || add2.status === 0;
|
|
7834
7615
|
if (add2.status !== 0)
|
|
7835
7616
|
return np("could not create the base worktree");
|
|
7836
7617
|
for (const rel of rels) {
|
|
7837
|
-
const sealed =
|
|
7838
|
-
if (!
|
|
7618
|
+
const sealed = join28(i.runDir, "wall", basename8(rel)), src = existsSync15(sealed) ? sealed : join28(i.repoDir, rel);
|
|
7619
|
+
if (!existsSync15(src))
|
|
7839
7620
|
return np(`Wall file missing: ${rel}`);
|
|
7840
|
-
mkdirSync5(
|
|
7841
|
-
writeFileSync8(
|
|
7621
|
+
mkdirSync5(dirname7(join28(wt, rel)), { recursive: true });
|
|
7622
|
+
writeFileSync8(join28(wt, rel), readFileSync18(src));
|
|
7842
7623
|
}
|
|
7843
7624
|
for (const rel of rels) {
|
|
7844
7625
|
const parts = rel.split("/").slice(0, -1);
|
|
7845
7626
|
for (let n2 = 0;n2 <= parts.length; n2++) {
|
|
7846
7627
|
const anc = parts.slice(0, n2).join("/");
|
|
7847
7628
|
for (const d of DEP_DIRS) {
|
|
7848
|
-
const src =
|
|
7849
|
-
if (
|
|
7629
|
+
const src = join28(i.repoDir, anc, d), dst = join28(wt, anc, d);
|
|
7630
|
+
if (existsSync15(src) && !existsSync15(dst)) {
|
|
7850
7631
|
try {
|
|
7851
7632
|
symlinkSync(src, dst);
|
|
7852
7633
|
} catch {}
|
|
@@ -7884,28 +7665,302 @@ var mutationStrict = (env = process.env) => (env["LOKI_MUTATION_STRICT"] ?? "").
|
|
|
7884
7665
|
safeGit(cwd, args, { timeout });
|
|
7885
7666
|
return { status: 0 };
|
|
7886
7667
|
} catch {
|
|
7887
|
-
return { status: 1 };
|
|
7668
|
+
return { status: 1 };
|
|
7669
|
+
}
|
|
7670
|
+
};
|
|
7671
|
+
var init_mutation_proof = __esm(() => {
|
|
7672
|
+
init_safe_git();
|
|
7673
|
+
init_run_cap();
|
|
7674
|
+
DEP_DIRS = ["node_modules", ".venv", "venv"];
|
|
7675
|
+
});
|
|
7676
|
+
|
|
7677
|
+
// ../../loki-ts/src/features/speed/unit_mode.ts
|
|
7678
|
+
import { closeSync as closeSync5, constants, fstatSync as fstatSync4, lstatSync as lstatSync5, openSync as openSync5, readSync as readSync4, realpathSync as realpathSync14 } from "fs";
|
|
7679
|
+
function readBounded(path) {
|
|
7680
|
+
const l = lstatSync5(path);
|
|
7681
|
+
if (l.isSymbolicLink() || !l.isFile() || l.size > MAX_SPEC_BYTES)
|
|
7682
|
+
return null;
|
|
7683
|
+
const fd = openSync5(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
|
7684
|
+
try {
|
|
7685
|
+
const st = fstatSync4(fd);
|
|
7686
|
+
if (!st.isFile() || st.size > MAX_SPEC_BYTES)
|
|
7687
|
+
return null;
|
|
7688
|
+
const buf = Buffer.alloc(st.size + 1);
|
|
7689
|
+
let n2 = 0;
|
|
7690
|
+
for (;; ) {
|
|
7691
|
+
const r = readSync4(fd, buf, n2, buf.length - n2, null);
|
|
7692
|
+
if (r <= 0)
|
|
7693
|
+
break;
|
|
7694
|
+
n2 += r;
|
|
7695
|
+
if (n2 >= buf.length)
|
|
7696
|
+
return null;
|
|
7697
|
+
}
|
|
7698
|
+
return buf.subarray(0, n2).toString("utf8");
|
|
7699
|
+
} finally {
|
|
7700
|
+
closeSync5(fd);
|
|
7701
|
+
}
|
|
7702
|
+
}
|
|
7703
|
+
function parseText(txt) {
|
|
7704
|
+
try {
|
|
7705
|
+
const j = JSON.parse(txt), ws = strs(j.writeSet), pack = strs(j.pack), tb = j.tokenBudget;
|
|
7706
|
+
if (typeof j.id !== "string" || !j.id || !ws || ws.length === 0 || !pack || typeof tb !== "number" || !Number.isFinite(tb) || !(tb > 0) || tb > MAX_TOKEN_BUDGET)
|
|
7707
|
+
return null;
|
|
7708
|
+
const acc = j.acceptance === undefined ? [] : strs(j.acceptance);
|
|
7709
|
+
if (acc === null)
|
|
7710
|
+
return null;
|
|
7711
|
+
return { id: j.id, writeSet: ws, pack, tokenBudget: tb, ...acc.length ? { acceptance: acc.map((a) => a.slice(0, 500)).slice(0, 50) } : {} };
|
|
7712
|
+
} catch {
|
|
7713
|
+
return null;
|
|
7714
|
+
}
|
|
7715
|
+
}
|
|
7716
|
+
function parseSpec(path) {
|
|
7717
|
+
try {
|
|
7718
|
+
const txt = readBounded(path);
|
|
7719
|
+
return txt === null ? null : parseText(txt);
|
|
7720
|
+
} catch {
|
|
7721
|
+
return null;
|
|
7722
|
+
}
|
|
7723
|
+
}
|
|
7724
|
+
function unitSpec(env = process.env) {
|
|
7725
|
+
const path = env["LOKI_UNIT_SPEC"], frozen = env["LOKI_UNIT_SPEC_FROZEN"];
|
|
7726
|
+
if (env["LOKI_SPEED"] === "0" || !path)
|
|
7727
|
+
return null;
|
|
7728
|
+
if (frozen !== undefined)
|
|
7729
|
+
return frozen.length <= MAX_SPEC_BYTES ? parseText(frozen) : null;
|
|
7730
|
+
if (!memo.has(path))
|
|
7731
|
+
memo.set(path, parseSpec(path));
|
|
7732
|
+
return memo.get(path) ?? null;
|
|
7733
|
+
}
|
|
7734
|
+
function unitFlags(staged, env = process.env, pre = {}) {
|
|
7735
|
+
const s = unitSpec(env);
|
|
7736
|
+
return s ? staged.filter(({ f }) => !inWriteSet(s, f) && !Object.hasOwn(pre, f)).map(({ f }) => f) : null;
|
|
7737
|
+
}
|
|
7738
|
+
var MAX_SPEC_BYTES, MAX_TOKEN_BUDGET = 1e9, norm2 = (p) => p.replace(/^\.\//, ""), CTRL, strs = (v) => Array.isArray(v) && v.every((x) => typeof x === "string" && !CTRL.test(x)) ? v.map(norm2) : null, memo, inWriteSet = (spec, f) => spec.writeSet.some((w) => w.endsWith("/") ? f.startsWith(w) : f === w);
|
|
7739
|
+
var init_unit_mode = __esm(() => {
|
|
7740
|
+
MAX_SPEC_BYTES = 1024 * 1024;
|
|
7741
|
+
CTRL = /[\x00-\x1f\x7f]/;
|
|
7742
|
+
memo = new Map;
|
|
7743
|
+
});
|
|
7744
|
+
|
|
7745
|
+
// ../../loki-ts/src/features/lean_prefix.ts
|
|
7746
|
+
var LEAN_PREFIX, STAGE_PREFIX, withStagePrefix = (brief) => process.env["LOKI_SPEED"] !== "0" ? `${STAGE_PREFIX}
|
|
7747
|
+
|
|
7748
|
+
${brief}` : brief;
|
|
7749
|
+
var init_lean_prefix = __esm(() => {
|
|
7750
|
+
LEAN_PREFIX = "You are Loki, an autonomous coding agent. Follow the task prompt exactly " + "and report only what you did.";
|
|
7751
|
+
STAGE_PREFIX = "You are Loki, an autonomous coding agent working one stage of a run. " + "Follow the stage prompt exactly, including the role it gives you and the rules it sets, " + "and report only what you did. " + "Stage-specific instructions and the task follow this block.";
|
|
7752
|
+
});
|
|
7753
|
+
|
|
7754
|
+
// ../../loki-ts/src/util/shell.ts
|
|
7755
|
+
async function readStreamCapped(stream, maxBytes = MAX_STDOUT_BYTES) {
|
|
7756
|
+
const reader = stream.getReader();
|
|
7757
|
+
const decoder = new TextDecoder;
|
|
7758
|
+
let out2 = "";
|
|
7759
|
+
let total = 0;
|
|
7760
|
+
try {
|
|
7761
|
+
while (total < maxBytes) {
|
|
7762
|
+
const { done, value } = await reader.read();
|
|
7763
|
+
if (done)
|
|
7764
|
+
break;
|
|
7765
|
+
if (!value)
|
|
7766
|
+
continue;
|
|
7767
|
+
total += value.byteLength;
|
|
7768
|
+
if (total > maxBytes) {
|
|
7769
|
+
const keep = value.byteLength - (total - maxBytes);
|
|
7770
|
+
out2 += decoder.decode(value.subarray(0, keep), { stream: true });
|
|
7771
|
+
break;
|
|
7772
|
+
}
|
|
7773
|
+
out2 += decoder.decode(value, { stream: true });
|
|
7774
|
+
}
|
|
7775
|
+
out2 += decoder.decode();
|
|
7776
|
+
} finally {
|
|
7777
|
+
try {
|
|
7778
|
+
await reader.cancel();
|
|
7779
|
+
} catch {}
|
|
7780
|
+
reader.releaseLock();
|
|
7781
|
+
}
|
|
7782
|
+
return out2;
|
|
7783
|
+
}
|
|
7784
|
+
async function run(argv, opts = {}) {
|
|
7785
|
+
const proc = Bun.spawn({
|
|
7786
|
+
cmd: [...argv],
|
|
7787
|
+
stdout: "pipe",
|
|
7788
|
+
stderr: "pipe",
|
|
7789
|
+
env: opts.env ? { ...process.env, ...opts.env } : process.env,
|
|
7790
|
+
cwd: opts.cwd
|
|
7791
|
+
});
|
|
7792
|
+
let timer;
|
|
7793
|
+
let killTimer;
|
|
7794
|
+
if (opts.timeoutMs && opts.timeoutMs > 0) {
|
|
7795
|
+
timer = setTimeout(() => {
|
|
7796
|
+
try {
|
|
7797
|
+
proc.kill("SIGTERM");
|
|
7798
|
+
} catch {}
|
|
7799
|
+
killTimer = setTimeout(() => {
|
|
7800
|
+
try {
|
|
7801
|
+
proc.kill("SIGKILL");
|
|
7802
|
+
} catch {}
|
|
7803
|
+
}, 2000);
|
|
7804
|
+
}, opts.timeoutMs);
|
|
7805
|
+
}
|
|
7806
|
+
try {
|
|
7807
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
7808
|
+
readStreamCapped(proc.stdout),
|
|
7809
|
+
new Response(proc.stderr).text(),
|
|
7810
|
+
proc.exited
|
|
7811
|
+
]);
|
|
7812
|
+
return { stdout, stderr, exitCode };
|
|
7813
|
+
} finally {
|
|
7814
|
+
if (timer)
|
|
7815
|
+
clearTimeout(timer);
|
|
7816
|
+
if (killTimer)
|
|
7817
|
+
clearTimeout(killTimer);
|
|
7818
|
+
}
|
|
7819
|
+
}
|
|
7820
|
+
var MAX_STDOUT_BYTES;
|
|
7821
|
+
var init_shell = __esm(() => {
|
|
7822
|
+
MAX_STDOUT_BYTES = 16 * 1024 * 1024;
|
|
7823
|
+
});
|
|
7824
|
+
|
|
7825
|
+
// ../../loki-ts/src/util/python.ts
|
|
7826
|
+
import { accessSync, constants as constants2, existsSync as existsSync16, statSync as statSync12 } from "fs";
|
|
7827
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
7828
|
+
import { tmpdir as tmpdir5 } from "os";
|
|
7829
|
+
function resolvePython3() {
|
|
7830
|
+
for (const dir of (process.env.PATH ?? "").split(":")) {
|
|
7831
|
+
if (!dir || !dir.startsWith("/"))
|
|
7832
|
+
continue;
|
|
7833
|
+
const cand = `${dir}/python3`;
|
|
7834
|
+
try {
|
|
7835
|
+
accessSync(cand, constants2.X_OK);
|
|
7836
|
+
if (statSync12(cand).isFile())
|
|
7837
|
+
return cand;
|
|
7838
|
+
} catch {}
|
|
7839
|
+
}
|
|
7840
|
+
return null;
|
|
7841
|
+
}
|
|
7842
|
+
function pySignatures(src) {
|
|
7843
|
+
try {
|
|
7844
|
+
const py = resolvePython3();
|
|
7845
|
+
if (!py)
|
|
7846
|
+
return [];
|
|
7847
|
+
const r = spawnSync2(py, ["-I", "-S", "-c", PY_SCRIPT], {
|
|
7848
|
+
input: src.replace(/\r\n?/g, `
|
|
7849
|
+
`),
|
|
7850
|
+
cwd: tmpdir5(),
|
|
7851
|
+
timeout: PY_TIMEOUT_MS,
|
|
7852
|
+
encoding: "utf8",
|
|
7853
|
+
env: { PATH: process.env.PATH ?? "/usr/bin:/bin" },
|
|
7854
|
+
maxBuffer: 8 * 1024 * 1024,
|
|
7855
|
+
stdio: ["pipe", "pipe", "ignore"]
|
|
7856
|
+
});
|
|
7857
|
+
if (r.error || r.status !== 0)
|
|
7858
|
+
return [];
|
|
7859
|
+
const parsed = JSON.parse(r.stdout);
|
|
7860
|
+
return Array.isArray(parsed) && parsed.every((l) => typeof l === "string") ? parsed : [];
|
|
7861
|
+
} catch {
|
|
7862
|
+
return [];
|
|
7888
7863
|
}
|
|
7889
|
-
}
|
|
7890
|
-
var
|
|
7891
|
-
|
|
7892
|
-
|
|
7893
|
-
|
|
7894
|
-
|
|
7895
|
-
|
|
7896
|
-
|
|
7897
|
-
|
|
7898
|
-
|
|
7899
|
-
|
|
7900
|
-
|
|
7901
|
-
|
|
7902
|
-
|
|
7864
|
+
}
|
|
7865
|
+
var PY_TIMEOUT_MS = 5000, PY_SCRIPT = `
|
|
7866
|
+
import ast, sys, json, re
|
|
7867
|
+
def u(n): return ast.unparse(n)
|
|
7868
|
+
def chain(n):
|
|
7869
|
+
if isinstance(n, ast.Name): return n.id
|
|
7870
|
+
if isinstance(n, ast.Attribute):
|
|
7871
|
+
c = chain(n.value)
|
|
7872
|
+
return None if c is None else c + "." + n.attr
|
|
7873
|
+
return None
|
|
7874
|
+
def deco(d):
|
|
7875
|
+
if isinstance(d, ast.Call):
|
|
7876
|
+
c = chain(d.func)
|
|
7877
|
+
return "@" + c + "(...)" if c else "@..."
|
|
7878
|
+
c = chain(d)
|
|
7879
|
+
return "@" + c if c else "@..."
|
|
7880
|
+
def lit(n):
|
|
7881
|
+
if isinstance(n, ast.Constant): return u(n)
|
|
7882
|
+
if isinstance(n, ast.UnaryOp) and isinstance(n.op, ast.USub) and isinstance(n.operand, ast.Constant): return u(n)
|
|
7883
|
+
if isinstance(n, ast.Tuple):
|
|
7884
|
+
p = [lit(e) for e in n.elts]
|
|
7885
|
+
return None if None in p else ", ".join(p)
|
|
7886
|
+
return chain(n)
|
|
7887
|
+
def ann(n):
|
|
7888
|
+
if isinstance(n, (ast.Name, ast.Attribute)): return chain(n)
|
|
7889
|
+
if isinstance(n, ast.Constant): return u(n) if (n.value is None or n.value is Ellipsis) else None
|
|
7890
|
+
if isinstance(n, ast.BinOp) and isinstance(n.op, ast.BitOr):
|
|
7891
|
+
l, r = ann(n.left), ann(n.right)
|
|
7892
|
+
return None if l is None or r is None else l + " | " + r
|
|
7893
|
+
if isinstance(n, ast.List):
|
|
7894
|
+
p = [ann(e) for e in n.elts]
|
|
7895
|
+
return None if None in p else "[" + ", ".join(p) + "]"
|
|
7896
|
+
if isinstance(n, ast.Tuple):
|
|
7897
|
+
p = [ann(e) for e in n.elts]
|
|
7898
|
+
return None if None in p else ", ".join(p)
|
|
7899
|
+
if isinstance(n, ast.Subscript):
|
|
7900
|
+
v = chain(n.value)
|
|
7901
|
+
if v is None: return None
|
|
7902
|
+
last = v.split(".")[-1]
|
|
7903
|
+
if last == "Literal":
|
|
7904
|
+
s = lit(n.slice)
|
|
7905
|
+
return None if s is None else v + "[" + s + "]"
|
|
7906
|
+
if last == "Annotated" and isinstance(n.slice, ast.Tuple) and n.slice.elts:
|
|
7907
|
+
first = ann(n.slice.elts[0])
|
|
7908
|
+
return None if first is None else v + "[" + first + ", ...]"
|
|
7909
|
+
s = ann(n.slice)
|
|
7910
|
+
return None if s is None else v + "[" + s + "]"
|
|
7911
|
+
return None
|
|
7912
|
+
def a_or_dots(n):
|
|
7913
|
+
r = ann(n)
|
|
7914
|
+
return "..." if r is None else r
|
|
7915
|
+
def clean(n):
|
|
7916
|
+
r = ann(n)
|
|
7917
|
+
return "..." if r is None else r
|
|
7918
|
+
def arg(a, has_default):
|
|
7919
|
+
t = a.arg
|
|
7920
|
+
if a.annotation is not None: t += ": " + a_or_dots(a.annotation)
|
|
7921
|
+
if has_default: t += " = ..." if a.annotation is not None else "=..."
|
|
7922
|
+
return t
|
|
7923
|
+
def args(a):
|
|
7924
|
+
pos = list(a.posonlyargs) + list(a.args)
|
|
7925
|
+
first_default = len(pos) - len(a.defaults)
|
|
7926
|
+
out = []
|
|
7927
|
+
for i, x in enumerate(pos):
|
|
7928
|
+
out.append(arg(x, i >= first_default))
|
|
7929
|
+
if a.posonlyargs and i == len(a.posonlyargs) - 1: out.append("/")
|
|
7930
|
+
if a.vararg is not None: out.append("*" + arg(a.vararg, False))
|
|
7931
|
+
elif a.kwonlyargs: out.append("*")
|
|
7932
|
+
for x, d in zip(a.kwonlyargs, a.kw_defaults): out.append(arg(x, d is not None))
|
|
7933
|
+
if a.kwarg is not None: out.append("**" + arg(a.kwarg, False))
|
|
7934
|
+
return ", ".join(out)
|
|
7935
|
+
def fn(n, ind):
|
|
7936
|
+
r = [ind + deco(d) for d in n.decorator_list]
|
|
7937
|
+
h = ind + ("async def " if isinstance(n, ast.AsyncFunctionDef) else "def ") + n.name + "(" + args(n.args) + ")"
|
|
7938
|
+
if n.returns is not None: h += " -> " + a_or_dots(n.returns)
|
|
7939
|
+
return r + [h + ":"]
|
|
7940
|
+
def cls(n):
|
|
7941
|
+
r = [deco(d) for d in n.decorator_list]
|
|
7942
|
+
parts = [clean(b) for b in n.bases] + [(k.arg + "=" + clean(k.value)) if k.arg else "**..." for k in n.keywords]
|
|
7943
|
+
return r + ["class " + n.name + ("(" + ", ".join(parts) + ")" if parts else "") + ":"]
|
|
7944
|
+
tree = ast.parse(sys.stdin.read())
|
|
7945
|
+
out = []
|
|
7946
|
+
for n in tree.body:
|
|
7947
|
+
if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef)) and not n.name.startswith("_"):
|
|
7948
|
+
out += fn(n, "")
|
|
7949
|
+
elif isinstance(n, ast.ClassDef) and not n.name.startswith("_"):
|
|
7950
|
+
out += cls(n)
|
|
7951
|
+
for m in n.body:
|
|
7952
|
+
if isinstance(m, (ast.FunctionDef, ast.AsyncFunctionDef)) and (not m.name.startswith("_") or re.fullmatch(r"__\\w+__", m.name)):
|
|
7953
|
+
out += fn(m, " ")
|
|
7954
|
+
else:
|
|
7955
|
+
t = n.targets[0] if isinstance(n, ast.Assign) and len(n.targets) == 1 else (n.target if isinstance(n, ast.AnnAssign) else None)
|
|
7956
|
+
if isinstance(t, ast.Name) and re.fullmatch(r"[A-Z][A-Z0-9_]*", t.id): out.append(t.id + " = ...")
|
|
7957
|
+
print(json.dumps(out))
|
|
7958
|
+
`;
|
|
7959
|
+
var init_python = __esm(() => {
|
|
7960
|
+
init_shell();
|
|
7903
7961
|
});
|
|
7904
7962
|
|
|
7905
7963
|
// ../../loki-ts/src/features/wall_manifest.ts
|
|
7906
|
-
import { spawnSync as spawnSync2 } from "child_process";
|
|
7907
|
-
import { accessSync, constants, statSync as statSync13 } from "fs";
|
|
7908
|
-
import { tmpdir as tmpdir5 } from "os";
|
|
7909
7964
|
function templateEnd(s, i) {
|
|
7910
7965
|
for (let j = i + 1;j < s.length; ) {
|
|
7911
7966
|
const c = s[j];
|
|
@@ -8631,41 +8686,6 @@ function tsSignatures(src, jsx) {
|
|
|
8631
8686
|
}
|
|
8632
8687
|
return out2;
|
|
8633
8688
|
}
|
|
8634
|
-
function resolvePython3() {
|
|
8635
|
-
for (const dir of (process.env.PATH ?? "").split(":")) {
|
|
8636
|
-
if (!dir || !dir.startsWith("/"))
|
|
8637
|
-
continue;
|
|
8638
|
-
const cand = `${dir}/python3`;
|
|
8639
|
-
try {
|
|
8640
|
-
accessSync(cand, constants.X_OK);
|
|
8641
|
-
if (statSync13(cand).isFile())
|
|
8642
|
-
return cand;
|
|
8643
|
-
} catch {}
|
|
8644
|
-
}
|
|
8645
|
-
return null;
|
|
8646
|
-
}
|
|
8647
|
-
function pySignatures(src) {
|
|
8648
|
-
try {
|
|
8649
|
-
const py = resolvePython3();
|
|
8650
|
-
if (!py)
|
|
8651
|
-
return [];
|
|
8652
|
-
const r = spawnSync2(py, ["-I", "-S", "-c", PY_SCRIPT], {
|
|
8653
|
-
input: norm2(src),
|
|
8654
|
-
cwd: tmpdir5(),
|
|
8655
|
-
timeout: PY_TIMEOUT_MS,
|
|
8656
|
-
encoding: "utf8",
|
|
8657
|
-
env: { PATH: process.env.PATH ?? "/usr/bin:/bin" },
|
|
8658
|
-
maxBuffer: 8 * 1024 * 1024,
|
|
8659
|
-
stdio: ["pipe", "pipe", "ignore"]
|
|
8660
|
-
});
|
|
8661
|
-
if (r.error || r.status !== 0)
|
|
8662
|
-
return [];
|
|
8663
|
-
const parsed = JSON.parse(r.stdout);
|
|
8664
|
-
return Array.isArray(parsed) && parsed.every((l) => typeof l === "string") ? parsed : [];
|
|
8665
|
-
} catch {
|
|
8666
|
-
return [];
|
|
8667
|
-
}
|
|
8668
|
-
}
|
|
8669
8689
|
function packageRunner(content) {
|
|
8670
8690
|
try {
|
|
8671
8691
|
const pkg = JSON.parse(content);
|
|
@@ -8678,7 +8698,7 @@ function packageRunner(content) {
|
|
|
8678
8698
|
}
|
|
8679
8699
|
}
|
|
8680
8700
|
function pytestSection(content, header) {
|
|
8681
|
-
const lines =
|
|
8701
|
+
const lines = norm3(content).split(`
|
|
8682
8702
|
`);
|
|
8683
8703
|
const at = lines.findIndex((l) => header.test(l));
|
|
8684
8704
|
if (at < 0)
|
|
@@ -8695,10 +8715,10 @@ function runnerSection(files) {
|
|
|
8695
8715
|
if (js)
|
|
8696
8716
|
out2.push(`runner: ${js}`, "config: package.json (scripts.test only)");
|
|
8697
8717
|
for (const f of get(/^(bunfig\.toml|(vitest|jest)\.config\.[cm]?[jt]s)$/))
|
|
8698
|
-
out2.push(`config: ${f.path}`, ...
|
|
8718
|
+
out2.push(`config: ${f.path}`, ...norm3(f.content).split(`
|
|
8699
8719
|
`).slice(0, 20));
|
|
8700
8720
|
const py = [
|
|
8701
|
-
...get(/^pytest\.ini$/).map((f) => ({ f, lines:
|
|
8721
|
+
...get(/^pytest\.ini$/).map((f) => ({ f, lines: norm3(f.content).split(`
|
|
8702
8722
|
`).filter((l) => l.trim()) })),
|
|
8703
8723
|
...get(/^pyproject\.toml$/).map((f) => ({ f, lines: pytestSection(f.content, /^\[tool\.pytest/) })),
|
|
8704
8724
|
...get(/^(setup\.cfg|tox\.ini)$/).map((f) => ({ f, lines: pytestSection(f.content, /^\[(tool:)?pytest\]/) }))
|
|
@@ -8786,13 +8806,13 @@ function importsNamed(path, raw2, stems, importStems = stems, hits = () => false
|
|
|
8786
8806
|
function safeTs(content, path) {
|
|
8787
8807
|
const jsx = /\.[jt]sx$/.test(path);
|
|
8788
8808
|
try {
|
|
8789
|
-
return tsAmbiguous(
|
|
8809
|
+
return tsAmbiguous(norm3(content), jsx) ? [] : tsSignatures(content, jsx);
|
|
8790
8810
|
} catch {
|
|
8791
8811
|
return [];
|
|
8792
8812
|
}
|
|
8793
8813
|
}
|
|
8794
8814
|
function buildWallManifest(files, taskModules, alsoNamed = []) {
|
|
8795
|
-
const all = [...files].sort(byPath).map((f) => ({ path: f.path.replace(/^\.\//, ""), content:
|
|
8815
|
+
const all = [...files].sort(byPath).map((f) => ({ path: f.path.replace(/^\.\//, ""), content: norm3(f.content) }));
|
|
8796
8816
|
const mods = [...new Set(taskModules.map((m) => m.replace(/^\.\//, "")))].sort();
|
|
8797
8817
|
const excl = [...new Set([...mods, ...alsoNamed.map((m) => m.replace(/^\.\//, ""))])];
|
|
8798
8818
|
const stems = new Set(excl.flatMap(stemsOfTarget));
|
|
@@ -8848,109 +8868,17 @@ var MANIFEST_MAX_LINES = 400, MAX_EXAMPLES = 2, EXAMPLE_LINES = 40, MAX_LAYOUT =
|
|
|
8848
8868
|
continue;
|
|
8849
8869
|
if (seg === "..")
|
|
8850
8870
|
out2.pop();
|
|
8851
|
-
else
|
|
8852
|
-
out2.push(seg);
|
|
8853
|
-
}
|
|
8854
|
-
return out2.join("/");
|
|
8855
|
-
}, stemsOfTarget = (m) => {
|
|
8856
|
-
const raw2 = stemOf(m).toLowerCase(), parent = m.split("/").slice(-2, -1)[0];
|
|
8857
|
-
return [normStem(raw2), ...["index", "__init__", "mod", "main"].includes(raw2) && parent ? [normStem(parent)] : []];
|
|
8858
|
-
},
|
|
8859
|
-
`), stemOf = (p) => (p.split("/").pop() ?? p).replace(/\.[^.]*$/, ""), byPath = (a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : a.content < b.content ? -1 : a.content > b.content ? 1 : 0, REGEX_PREV = "(,=:[!&|?{;+-*%~^", isComment = (s, i) => s[i] === "/" && (s[i + 1] === "/" || s[i + 1] === "*"), MODS = "(?:(?:public|private|protected|static|readonly|abstract|async|get|set|declare|override)\\s+)*", MEMBER_GRAMMAR, NOT_MEMBER, RESERVED_AFTER_DECORATOR
|
|
8860
|
-
import ast, sys, json, re
|
|
8861
|
-
def u(n): return ast.unparse(n)
|
|
8862
|
-
def chain(n):
|
|
8863
|
-
if isinstance(n, ast.Name): return n.id
|
|
8864
|
-
if isinstance(n, ast.Attribute):
|
|
8865
|
-
c = chain(n.value)
|
|
8866
|
-
return None if c is None else c + "." + n.attr
|
|
8867
|
-
return None
|
|
8868
|
-
def deco(d):
|
|
8869
|
-
if isinstance(d, ast.Call):
|
|
8870
|
-
c = chain(d.func)
|
|
8871
|
-
return "@" + c + "(...)" if c else "@..."
|
|
8872
|
-
c = chain(d)
|
|
8873
|
-
return "@" + c if c else "@..."
|
|
8874
|
-
def lit(n):
|
|
8875
|
-
if isinstance(n, ast.Constant): return u(n)
|
|
8876
|
-
if isinstance(n, ast.UnaryOp) and isinstance(n.op, ast.USub) and isinstance(n.operand, ast.Constant): return u(n)
|
|
8877
|
-
if isinstance(n, ast.Tuple):
|
|
8878
|
-
p = [lit(e) for e in n.elts]
|
|
8879
|
-
return None if None in p else ", ".join(p)
|
|
8880
|
-
return chain(n)
|
|
8881
|
-
def ann(n):
|
|
8882
|
-
if isinstance(n, (ast.Name, ast.Attribute)): return chain(n)
|
|
8883
|
-
if isinstance(n, ast.Constant): return u(n) if (n.value is None or n.value is Ellipsis) else None
|
|
8884
|
-
if isinstance(n, ast.BinOp) and isinstance(n.op, ast.BitOr):
|
|
8885
|
-
l, r = ann(n.left), ann(n.right)
|
|
8886
|
-
return None if l is None or r is None else l + " | " + r
|
|
8887
|
-
if isinstance(n, ast.List):
|
|
8888
|
-
p = [ann(e) for e in n.elts]
|
|
8889
|
-
return None if None in p else "[" + ", ".join(p) + "]"
|
|
8890
|
-
if isinstance(n, ast.Tuple):
|
|
8891
|
-
p = [ann(e) for e in n.elts]
|
|
8892
|
-
return None if None in p else ", ".join(p)
|
|
8893
|
-
if isinstance(n, ast.Subscript):
|
|
8894
|
-
v = chain(n.value)
|
|
8895
|
-
if v is None: return None
|
|
8896
|
-
last = v.split(".")[-1]
|
|
8897
|
-
if last == "Literal":
|
|
8898
|
-
s = lit(n.slice)
|
|
8899
|
-
return None if s is None else v + "[" + s + "]"
|
|
8900
|
-
if last == "Annotated" and isinstance(n.slice, ast.Tuple) and n.slice.elts:
|
|
8901
|
-
first = ann(n.slice.elts[0])
|
|
8902
|
-
return None if first is None else v + "[" + first + ", ...]"
|
|
8903
|
-
s = ann(n.slice)
|
|
8904
|
-
return None if s is None else v + "[" + s + "]"
|
|
8905
|
-
return None
|
|
8906
|
-
def a_or_dots(n):
|
|
8907
|
-
r = ann(n)
|
|
8908
|
-
return "..." if r is None else r
|
|
8909
|
-
def clean(n):
|
|
8910
|
-
r = ann(n)
|
|
8911
|
-
return "..." if r is None else r
|
|
8912
|
-
def arg(a, has_default):
|
|
8913
|
-
t = a.arg
|
|
8914
|
-
if a.annotation is not None: t += ": " + a_or_dots(a.annotation)
|
|
8915
|
-
if has_default: t += " = ..." if a.annotation is not None else "=..."
|
|
8916
|
-
return t
|
|
8917
|
-
def args(a):
|
|
8918
|
-
pos = list(a.posonlyargs) + list(a.args)
|
|
8919
|
-
first_default = len(pos) - len(a.defaults)
|
|
8920
|
-
out = []
|
|
8921
|
-
for i, x in enumerate(pos):
|
|
8922
|
-
out.append(arg(x, i >= first_default))
|
|
8923
|
-
if a.posonlyargs and i == len(a.posonlyargs) - 1: out.append("/")
|
|
8924
|
-
if a.vararg is not None: out.append("*" + arg(a.vararg, False))
|
|
8925
|
-
elif a.kwonlyargs: out.append("*")
|
|
8926
|
-
for x, d in zip(a.kwonlyargs, a.kw_defaults): out.append(arg(x, d is not None))
|
|
8927
|
-
if a.kwarg is not None: out.append("**" + arg(a.kwarg, False))
|
|
8928
|
-
return ", ".join(out)
|
|
8929
|
-
def fn(n, ind):
|
|
8930
|
-
r = [ind + deco(d) for d in n.decorator_list]
|
|
8931
|
-
h = ind + ("async def " if isinstance(n, ast.AsyncFunctionDef) else "def ") + n.name + "(" + args(n.args) + ")"
|
|
8932
|
-
if n.returns is not None: h += " -> " + a_or_dots(n.returns)
|
|
8933
|
-
return r + [h + ":"]
|
|
8934
|
-
def cls(n):
|
|
8935
|
-
r = [deco(d) for d in n.decorator_list]
|
|
8936
|
-
parts = [clean(b) for b in n.bases] + [(k.arg + "=" + clean(k.value)) if k.arg else "**..." for k in n.keywords]
|
|
8937
|
-
return r + ["class " + n.name + ("(" + ", ".join(parts) + ")" if parts else "") + ":"]
|
|
8938
|
-
tree = ast.parse(sys.stdin.read())
|
|
8939
|
-
out = []
|
|
8940
|
-
for n in tree.body:
|
|
8941
|
-
if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef)) and not n.name.startswith("_"):
|
|
8942
|
-
out += fn(n, "")
|
|
8943
|
-
elif isinstance(n, ast.ClassDef) and not n.name.startswith("_"):
|
|
8944
|
-
out += cls(n)
|
|
8945
|
-
for m in n.body:
|
|
8946
|
-
if isinstance(m, (ast.FunctionDef, ast.AsyncFunctionDef)) and (not m.name.startswith("_") or re.fullmatch(r"__\\w+__", m.name)):
|
|
8947
|
-
out += fn(m, " ")
|
|
8948
|
-
else:
|
|
8949
|
-
t = n.targets[0] if isinstance(n, ast.Assign) and len(n.targets) == 1 else (n.target if isinstance(n, ast.AnnAssign) else None)
|
|
8950
|
-
if isinstance(t, ast.Name) and re.fullmatch(r"[A-Z][A-Z0-9_]*", t.id): out.append(t.id + " = ...")
|
|
8951
|
-
print(json.dumps(out))
|
|
8952
|
-
`;
|
|
8871
|
+
else
|
|
8872
|
+
out2.push(seg);
|
|
8873
|
+
}
|
|
8874
|
+
return out2.join("/");
|
|
8875
|
+
}, stemsOfTarget = (m) => {
|
|
8876
|
+
const raw2 = stemOf(m).toLowerCase(), parent = m.split("/").slice(-2, -1)[0];
|
|
8877
|
+
return [normStem(raw2), ...["index", "__init__", "mod", "main"].includes(raw2) && parent ? [normStem(parent)] : []];
|
|
8878
|
+
}, norm3 = (s) => s.replace(/\r\n?/g, `
|
|
8879
|
+
`), stemOf = (p) => (p.split("/").pop() ?? p).replace(/\.[^.]*$/, ""), byPath = (a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : a.content < b.content ? -1 : a.content > b.content ? 1 : 0, REGEX_PREV = "(,=:[!&|?{;+-*%~^", isComment = (s, i) => s[i] === "/" && (s[i + 1] === "/" || s[i + 1] === "*"), MODS = "(?:(?:public|private|protected|static|readonly|abstract|async|get|set|declare|override)\\s+)*", MEMBER_GRAMMAR, NOT_MEMBER, RESERVED_AFTER_DECORATOR;
|
|
8953
8880
|
var init_wall_manifest = __esm(() => {
|
|
8881
|
+
init_python();
|
|
8954
8882
|
TEST_PATH = /(^|\/)(tests?|__tests__|spec)\/|\.(test|spec)\.[jt]sx?$|(^|\/)test_[^/]*\.py$|_test\.(py|go)$/;
|
|
8955
8883
|
TEST_FILE = /\.(test|spec)\.[cm]?[jt]sx?$|(^|\/)test_[^/]*\.py$|_test\.py$/;
|
|
8956
8884
|
EXAMPLE_EXT = /\.(py|[cm]?[jt]sx?)$/;
|
|
@@ -8961,8 +8889,8 @@ var init_wall_manifest = __esm(() => {
|
|
|
8961
8889
|
});
|
|
8962
8890
|
|
|
8963
8891
|
// ../../loki-ts/src/features/wall_manifest_wire.ts
|
|
8964
|
-
import { createHash as
|
|
8965
|
-
import { basename as basename9, dirname as
|
|
8892
|
+
import { createHash as createHash6 } from "crypto";
|
|
8893
|
+
import { basename as basename9, dirname as dirname8 } from "path";
|
|
8966
8894
|
function blobEntries(ls) {
|
|
8967
8895
|
const out2 = [];
|
|
8968
8896
|
for (const raw2 of ls.toString("latin1").split("\x00")) {
|
|
@@ -8992,7 +8920,7 @@ function wallManifestFor(repoDir, tree, task, env = process.env) {
|
|
|
8992
8920
|
return null;
|
|
8993
8921
|
const low = task.toLowerCase().replace(/\\/g, "/");
|
|
8994
8922
|
const token = (n2) => new RegExp(`(?<![A-Za-z0-9_])${n2.toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![A-Za-z0-9_])`).test(low);
|
|
8995
|
-
const dirModule = (e) => /^(index|__init__|mod|main)\.[^.]+$/.test(basename9(e.path)) && e.path.includes("/") && token(
|
|
8923
|
+
const dirModule = (e) => /^(index|__init__|mod|main)\.[^.]+$/.test(basename9(e.path)) && e.path.includes("/") && token(dirname8(e.path));
|
|
8996
8924
|
const matched = all.filter((e) => SOURCE.test(e.path) && (token(basename9(e.path)) || token(e.path) || token(basename9(e.path).replace(/\.[^.]*$/, "")) || dirModule(e)));
|
|
8997
8925
|
const spans = (p) => [...low.matchAll(new RegExp(`(?<![A-Za-z0-9_])${p.toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![A-Za-z0-9_])`, "g"))].map((m) => [m.index, m.index + m[0].length]);
|
|
8998
8926
|
const occ = new Map(matched.map((e) => [e, spans(e.path)]));
|
|
@@ -9020,8 +8948,8 @@ function wallManifestFor(repoDir, tree, task, env = process.env) {
|
|
|
9020
8948
|
}
|
|
9021
8949
|
if (at !== cat.length)
|
|
9022
8950
|
return null;
|
|
9023
|
-
const
|
|
9024
|
-
return { text:
|
|
8951
|
+
const text2 = buildWallManifest([...files, ...listed.map((e) => ({ path: e.path, content: "" }))], named.map((e) => e.path), matched.map((e) => e.path));
|
|
8952
|
+
return { text: text2, sha256: createHash6("sha256").update(text2).digest("hex") };
|
|
9025
8953
|
} catch {
|
|
9026
8954
|
return null;
|
|
9027
8955
|
}
|
|
@@ -9053,12 +8981,12 @@ Example: test('name', () => { assert.strictEqual(fn(1), 2); }); Run: node --tes
|
|
|
9053
8981
|
});
|
|
9054
8982
|
|
|
9055
8983
|
// ../../loki-ts/src/engine10/cache.ts
|
|
9056
|
-
import { createHash as
|
|
9057
|
-
import { existsSync as existsSync17, mkdirSync as mkdirSync6, readFileSync as
|
|
8984
|
+
import { createHash as createHash7 } from "crypto";
|
|
8985
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync6, readFileSync as readFileSync19, writeFileSync as writeFileSync9 } from "fs";
|
|
9058
8986
|
import { resolve as resolve8 } from "path";
|
|
9059
8987
|
function repoKey(originUrl, repoDir) {
|
|
9060
8988
|
const basis = originUrl && originUrl.trim() !== "" ? originUrl : resolve8(repoDir);
|
|
9061
|
-
return
|
|
8989
|
+
return createHash7("sha256").update(basis).digest("hex");
|
|
9062
8990
|
}
|
|
9063
8991
|
function defaultCacheRoot() {
|
|
9064
8992
|
return resolve8(homeLokiDir(), "cache", "v10");
|
|
@@ -9066,11 +8994,11 @@ function defaultCacheRoot() {
|
|
|
9066
8994
|
function repoCacheDir(key, cacheRoot = defaultCacheRoot()) {
|
|
9067
8995
|
return resolve8(cacheRoot, key);
|
|
9068
8996
|
}
|
|
9069
|
-
function
|
|
8997
|
+
function readJson3(path, isValid = (_v) => true) {
|
|
9070
8998
|
if (!existsSync17(path))
|
|
9071
8999
|
return null;
|
|
9072
9000
|
try {
|
|
9073
|
-
const parsed = JSON.parse(
|
|
9001
|
+
const parsed = JSON.parse(readFileSync19(path, "utf8"));
|
|
9074
9002
|
return isValid(parsed) ? parsed : null;
|
|
9075
9003
|
} catch {
|
|
9076
9004
|
return null;
|
|
@@ -9080,7 +9008,7 @@ function isRepoMap(v) {
|
|
|
9080
9008
|
return typeof v === "object" && v !== null && Array.isArray(v.files) && Array.isArray(v.entries);
|
|
9081
9009
|
}
|
|
9082
9010
|
function readRepoMapCache(dir, tree) {
|
|
9083
|
-
return
|
|
9011
|
+
return readJson3(resolve8(dir, `repomap-${tree}.json`), isRepoMap);
|
|
9084
9012
|
}
|
|
9085
9013
|
var init_cache = __esm(() => {
|
|
9086
9014
|
init_paths();
|
|
@@ -9105,7 +9033,7 @@ function selectSpecificFiles(task, repoMap, max = MAX_RELEVANT_FILES) {
|
|
|
9105
9033
|
const scored = sets.map((toks, idx) => ({ path: entries[idx].path, score: specific.reduce((n2, w) => n2 + (toks.has(w) ? 1 : 0), 0), idx }));
|
|
9106
9034
|
return scored.filter((s) => s.score > 0).sort((a, b) => b.score - a.score || a.idx - b.idx).slice(0, max).map((s) => s.path);
|
|
9107
9035
|
}
|
|
9108
|
-
var MAX_RELEVANT_FILES = 8, haystack = (entry) => `${entry.path} ${entry.symbols.join(" ")}`.toLowerCase(), wordTokens = (
|
|
9036
|
+
var MAX_RELEVANT_FILES = 8, haystack = (entry) => `${entry.path} ${entry.symbols.join(" ")}`.toLowerCase(), wordTokens = (text2) => text2.toLowerCase().match(/[a-z0-9_]+/g) ?? [];
|
|
9109
9037
|
|
|
9110
9038
|
// ../../loki-ts/src/features/speed/lean_select.ts
|
|
9111
9039
|
function speedLikelyFiles(task, map, env = process.env) {
|
|
@@ -9120,12 +9048,12 @@ function speedLikelyFiles(task, map, env = process.env) {
|
|
|
9120
9048
|
var init_lean_select = () => {};
|
|
9121
9049
|
|
|
9122
9050
|
// ../../loki-ts/src/util/claude_model.ts
|
|
9123
|
-
import { readFileSync as
|
|
9051
|
+
import { readFileSync as readFileSync20 } from "fs";
|
|
9124
9052
|
import { resolve as resolve9 } from "path";
|
|
9125
9053
|
function resolveClaudeModel(want) {
|
|
9126
9054
|
try {
|
|
9127
9055
|
const path = process.env["LOKI_MODEL_CATALOG"] || resolve9(REPO_ROOT, "providers/model_catalog.json");
|
|
9128
|
-
return JSON.parse(
|
|
9056
|
+
return JSON.parse(readFileSync20(path, "utf8")).providers?.claude?.cli_aliases?.[want] ?? want;
|
|
9129
9057
|
} catch {
|
|
9130
9058
|
return want;
|
|
9131
9059
|
}
|
|
@@ -9173,17 +9101,28 @@ var init_hooks = __esm(() => {
|
|
|
9173
9101
|
hooks = {};
|
|
9174
9102
|
});
|
|
9175
9103
|
|
|
9104
|
+
// ../../loki-ts/src/runner/router/flag.ts
|
|
9105
|
+
function routerMode(env = process.env) {
|
|
9106
|
+
const v = (env.LOKI_ROUTER ?? "").trim().toLowerCase();
|
|
9107
|
+
if (v === "0" || v === "false" || v === "off")
|
|
9108
|
+
return "opt-out";
|
|
9109
|
+
if (v === "1" || v === "true" || v === "on")
|
|
9110
|
+
return "on";
|
|
9111
|
+
return "off";
|
|
9112
|
+
}
|
|
9113
|
+
var routerEnabled = (env = process.env) => routerMode(env) === "on";
|
|
9114
|
+
|
|
9176
9115
|
// ../../loki-ts/src/engine10/cost.ts
|
|
9177
|
-
import {
|
|
9178
|
-
import { join as
|
|
9116
|
+
import { readdirSync as readdirSync9, readFileSync as readFileSync21 } from "fs";
|
|
9117
|
+
import { join as join29 } from "path";
|
|
9179
9118
|
function routerTelemetryOn(env = process.env) {
|
|
9180
9119
|
return routerEnabled(env);
|
|
9181
9120
|
}
|
|
9182
|
-
function
|
|
9121
|
+
function num3(v) {
|
|
9183
9122
|
return typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
9184
9123
|
}
|
|
9185
9124
|
function resultCostPath(lokiRoot, iteration) {
|
|
9186
|
-
return
|
|
9125
|
+
return join29(lokiRoot, "metrics", `result-cost-${iteration}.json`);
|
|
9187
9126
|
}
|
|
9188
9127
|
function sumResultCosts(lokiRoot, iterations, context = []) {
|
|
9189
9128
|
const out2 = {
|
|
@@ -9214,7 +9153,7 @@ function sumResultCosts(lokiRoot, iterations, context = []) {
|
|
|
9214
9153
|
const parsed = new Map;
|
|
9215
9154
|
for (const iter of iterations) {
|
|
9216
9155
|
try {
|
|
9217
|
-
parsed.set(iter, JSON.parse(
|
|
9156
|
+
parsed.set(iter, JSON.parse(readFileSync21(resultCostPath(lokiRoot, iter), "utf8")));
|
|
9218
9157
|
} catch {}
|
|
9219
9158
|
}
|
|
9220
9159
|
const own = new Set(iterations);
|
|
@@ -9223,15 +9162,15 @@ function sumResultCosts(lokiRoot, iterations, context = []) {
|
|
|
9223
9162
|
if (own.has(iter))
|
|
9224
9163
|
continue;
|
|
9225
9164
|
try {
|
|
9226
|
-
lookup.push({ iter, rec: JSON.parse(
|
|
9165
|
+
lookup.push({ iter, rec: JSON.parse(readFileSync21(resultCostPath(lokiRoot, iter), "utf8")) });
|
|
9227
9166
|
} catch {}
|
|
9228
9167
|
}
|
|
9229
9168
|
const verdicts = hooks.costRecords?.resumeVerdicts(lookup) ?? { ambiguous: [], separate: [] };
|
|
9230
9169
|
const rv = { ambiguous: verdicts.ambiguous.filter((i) => own.has(i)), separate: verdicts.separate.filter((i) => own.has(i)) };
|
|
9231
9170
|
for (const iter of iterations) {
|
|
9232
9171
|
const path = resultCostPath(lokiRoot, iter);
|
|
9233
|
-
const
|
|
9234
|
-
if (!
|
|
9172
|
+
const rec = parsed.get(iter);
|
|
9173
|
+
if (!rec) {
|
|
9235
9174
|
out2.missing.push(iter);
|
|
9236
9175
|
continue;
|
|
9237
9176
|
}
|
|
@@ -9241,45 +9180,45 @@ function sumResultCosts(lokiRoot, iterations, context = []) {
|
|
|
9241
9180
|
continue;
|
|
9242
9181
|
}
|
|
9243
9182
|
tokenSessions++;
|
|
9244
|
-
const inTok =
|
|
9245
|
-
const outTok =
|
|
9246
|
-
const cacheR =
|
|
9247
|
-
const cacheC =
|
|
9183
|
+
const inTok = num3(rec["input_tokens"]);
|
|
9184
|
+
const outTok = num3(rec["output_tokens"]);
|
|
9185
|
+
const cacheR = num3(rec["cache_read_tokens"]);
|
|
9186
|
+
const cacheC = num3(rec["cache_creation_tokens"]);
|
|
9248
9187
|
out2.input_tokens += inTok;
|
|
9249
9188
|
out2.output_tokens += outTok;
|
|
9250
9189
|
out2.cache_read_tokens += cacheR;
|
|
9251
9190
|
out2.cache_creation_tokens += cacheC;
|
|
9252
|
-
if (typeof
|
|
9191
|
+
if (typeof rec["cache_read_tokens"] === "number")
|
|
9253
9192
|
readSeen++;
|
|
9254
|
-
if (typeof
|
|
9193
|
+
if (typeof rec["cache_creation_tokens"] === "number")
|
|
9255
9194
|
creationSeen++;
|
|
9256
|
-
if (typeof
|
|
9257
|
-
out2.duration_ms = (out2.duration_ms ?? 0) +
|
|
9195
|
+
if (typeof rec["duration_ms"] === "number" && Number.isFinite(rec["duration_ms"])) {
|
|
9196
|
+
out2.duration_ms = (out2.duration_ms ?? 0) + rec["duration_ms"];
|
|
9258
9197
|
durSeen++;
|
|
9259
9198
|
}
|
|
9260
9199
|
if (out2.router)
|
|
9261
|
-
out2.router["requests_total"] +=
|
|
9200
|
+
out2.router["requests_total"] += num3(rec["requests_total"]);
|
|
9262
9201
|
if (out2.router)
|
|
9263
|
-
out2.router["requests_over_100k"] +=
|
|
9202
|
+
out2.router["requests_over_100k"] += num3(rec["requests_over_100k"]);
|
|
9264
9203
|
if (out2.router)
|
|
9265
|
-
out2.router["over_100k_input_tokens"] +=
|
|
9204
|
+
out2.router["over_100k_input_tokens"] += num3(rec["over_100k_input_tokens"]);
|
|
9266
9205
|
if (out2.router)
|
|
9267
|
-
out2.router["over_100k_output_tokens"] +=
|
|
9206
|
+
out2.router["over_100k_output_tokens"] += num3(rec["over_100k_output_tokens"]);
|
|
9268
9207
|
if (out2.router)
|
|
9269
|
-
out2.router["advisor_calls"] +=
|
|
9208
|
+
out2.router["advisor_calls"] += num3(rec["advisor_calls"]);
|
|
9270
9209
|
if (out2.router)
|
|
9271
|
-
out2.router["advisor_input_tokens"] +=
|
|
9210
|
+
out2.router["advisor_input_tokens"] += num3(rec["advisor_input_tokens"]);
|
|
9272
9211
|
if (out2.router)
|
|
9273
|
-
out2.router["advisor_output_tokens"] +=
|
|
9274
|
-
if (typeof
|
|
9275
|
-
out2.model =
|
|
9212
|
+
out2.router["advisor_output_tokens"] += num3(rec["advisor_output_tokens"]);
|
|
9213
|
+
if (typeof rec["model"] === "string" && rec["model"])
|
|
9214
|
+
out2.model = rec["model"];
|
|
9276
9215
|
sources2.push(path);
|
|
9277
|
-
recs.push({ iter, rec
|
|
9278
|
-
const c =
|
|
9279
|
-
const unmetered =
|
|
9216
|
+
recs.push({ iter, rec });
|
|
9217
|
+
const c = rec["total_cost_usd"];
|
|
9218
|
+
const unmetered = rec["source"] === UNMETERED;
|
|
9280
9219
|
if (unmetered)
|
|
9281
9220
|
out2.unmetered = true;
|
|
9282
|
-
if (
|
|
9221
|
+
if (rec["estimated"] === true)
|
|
9283
9222
|
out2.estimated = true;
|
|
9284
9223
|
const noUsage = !unmetered && inTok === 0 && outTok === 0 && cacheR === 0 && cacheC === 0;
|
|
9285
9224
|
if (typeof c !== "number" || !Number.isFinite(c) || noUsage) {
|
|
@@ -9318,17 +9257,74 @@ function sumResultCosts(lokiRoot, iterations, context = []) {
|
|
|
9318
9257
|
var UNMETERED = "cli-invoker-unmetered";
|
|
9319
9258
|
var init_cost = __esm(() => {
|
|
9320
9259
|
init_hooks();
|
|
9260
|
+
init_provider_cost();
|
|
9261
|
+
init_provider_cost();
|
|
9262
|
+
});
|
|
9263
|
+
|
|
9264
|
+
// ../../loki-ts/src/util/atomic.ts
|
|
9265
|
+
import {
|
|
9266
|
+
closeSync as closeSync6,
|
|
9267
|
+
fstatSync as fstatSync5,
|
|
9268
|
+
fsyncSync as fsyncSync2,
|
|
9269
|
+
lstatSync as lstatSync6,
|
|
9270
|
+
mkdirSync as mkdirSync8,
|
|
9271
|
+
openSync as openSync6,
|
|
9272
|
+
readSync as readSync5,
|
|
9273
|
+
renameSync as renameSync4,
|
|
9274
|
+
rmSync as rmSync6,
|
|
9275
|
+
statSync as statSync13,
|
|
9276
|
+
unlinkSync as unlinkSync3,
|
|
9277
|
+
writeFileSync as writeFileSync11,
|
|
9278
|
+
writeSync as writeSync3
|
|
9279
|
+
} from "fs";
|
|
9280
|
+
import { dirname as dirname9 } from "path";
|
|
9281
|
+
function durableWriteThenRename(target, body) {
|
|
9282
|
+
mkdirSync8(dirname9(target), { recursive: true });
|
|
9283
|
+
const tmp = tmpPathFor(target);
|
|
9284
|
+
const fd = openSync6(tmp, "w");
|
|
9285
|
+
try {
|
|
9286
|
+
writeSync3(fd, body);
|
|
9287
|
+
fsyncSync2(fd);
|
|
9288
|
+
} finally {
|
|
9289
|
+
closeSync6(fd);
|
|
9290
|
+
}
|
|
9291
|
+
renameSync4(tmp, target);
|
|
9292
|
+
fsyncParentDir(target);
|
|
9293
|
+
}
|
|
9294
|
+
function fsyncParentDir(target) {
|
|
9295
|
+
let dfd = null;
|
|
9296
|
+
try {
|
|
9297
|
+
dfd = openSync6(dirname9(target), "r");
|
|
9298
|
+
fsyncSync2(dfd);
|
|
9299
|
+
} catch {} finally {
|
|
9300
|
+
if (dfd !== null) {
|
|
9301
|
+
try {
|
|
9302
|
+
closeSync6(dfd);
|
|
9303
|
+
} catch {}
|
|
9304
|
+
}
|
|
9305
|
+
}
|
|
9306
|
+
}
|
|
9307
|
+
function atomicWriteJson(target, data) {
|
|
9308
|
+
durableWriteThenRename(target, `${JSON.stringify(data, null, 2)}
|
|
9309
|
+
`);
|
|
9310
|
+
}
|
|
9311
|
+
function tmpPathFor(target) {
|
|
9312
|
+
return `${target}.tmp.${process.pid}.${++_tmpCounter}`;
|
|
9313
|
+
}
|
|
9314
|
+
var _tmpCounter = 0, _appendChains;
|
|
9315
|
+
var init_atomic = __esm(() => {
|
|
9316
|
+
_appendChains = new Map;
|
|
9321
9317
|
});
|
|
9322
9318
|
|
|
9323
9319
|
// ../../loki-ts/src/runner/budget.ts
|
|
9324
|
-
import { existsSync as existsSync18, mkdirSync as
|
|
9325
|
-
import { dirname as dirname10, join as
|
|
9320
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync9, readdirSync as readdirSync10, readFileSync as readFileSync22, writeFileSync as writeFileSync12 } from "fs";
|
|
9321
|
+
import { dirname as dirname10, join as join30, resolve as resolve10 } from "path";
|
|
9326
9322
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
9327
9323
|
function loadDefaultMaxCostUsd() {
|
|
9328
9324
|
const here = dirname10(fileURLToPath2(import.meta.url));
|
|
9329
9325
|
for (const rel of [["..", "..", "data"], ["..", "data"]]) {
|
|
9330
9326
|
try {
|
|
9331
|
-
const j = JSON.parse(
|
|
9327
|
+
const j = JSON.parse(readFileSync22(resolve10(here, ...rel, "model-pricing.json"), "utf8"));
|
|
9332
9328
|
if (typeof j.default_max_cost_usd === "number" && Number.isFinite(j.default_max_cost_usd) && j.default_max_cost_usd > 0)
|
|
9333
9329
|
return j.default_max_cost_usd;
|
|
9334
9330
|
} catch {}
|
|
@@ -9341,7 +9337,7 @@ function _loadPricing() {
|
|
|
9341
9337
|
const jsonPath = resolve10(moduleDir, "..", "..", "data", "model-pricing.json");
|
|
9342
9338
|
if (!existsSync18(jsonPath))
|
|
9343
9339
|
return _FALLBACK_PRICING;
|
|
9344
|
-
const raw2 = JSON.parse(
|
|
9340
|
+
const raw2 = JSON.parse(readFileSync22(jsonPath, "utf8"));
|
|
9345
9341
|
const pricing2 = raw2["pricing"];
|
|
9346
9342
|
if (!pricing2 || typeof pricing2 !== "object")
|
|
9347
9343
|
return _FALLBACK_PRICING;
|
|
@@ -9371,6 +9367,7 @@ function _loadPricing() {
|
|
|
9371
9367
|
}
|
|
9372
9368
|
var DEFAULT_FALLBACK_USD = 100, _FALLBACK_PRICING, PRICING;
|
|
9373
9369
|
var init_budget = __esm(() => {
|
|
9370
|
+
init_atomic();
|
|
9374
9371
|
init_paths();
|
|
9375
9372
|
init_cost();
|
|
9376
9373
|
_FALLBACK_PRICING = {
|
|
@@ -9470,7 +9467,7 @@ var init_model_rank = __esm(() => {
|
|
|
9470
9467
|
});
|
|
9471
9468
|
|
|
9472
9469
|
// ../../loki-ts/src/engine10/sizing.ts
|
|
9473
|
-
import { existsSync as existsSync19, readFileSync as
|
|
9470
|
+
import { existsSync as existsSync19, readFileSync as readFileSync23 } from "fs";
|
|
9474
9471
|
import { basename as basename10 } from "path";
|
|
9475
9472
|
function namedFiles(task, map) {
|
|
9476
9473
|
return (map?.files ?? []).filter((f) => task.toLowerCase().includes(basename10(f).toLowerCase()));
|
|
@@ -9492,7 +9489,7 @@ function loadRepoMap(repomapRef) {
|
|
|
9492
9489
|
if (!repomapRef || !existsSync19(repomapRef))
|
|
9493
9490
|
return null;
|
|
9494
9491
|
try {
|
|
9495
|
-
return JSON.parse(
|
|
9492
|
+
return JSON.parse(readFileSync23(repomapRef, "utf8"));
|
|
9496
9493
|
} catch {
|
|
9497
9494
|
return null;
|
|
9498
9495
|
}
|
|
@@ -9523,8 +9520,8 @@ var init_sizing = __esm(() => {
|
|
|
9523
9520
|
});
|
|
9524
9521
|
|
|
9525
9522
|
// ../../loki-ts/src/project_model/schema.ts
|
|
9526
|
-
import { existsSync as existsSync20, lstatSync as
|
|
9527
|
-
import { isAbsolute as isAbsolute3, join as
|
|
9523
|
+
import { existsSync as existsSync20, lstatSync as lstatSync7, realpathSync as realpathSync15, statSync as statSync14 } from "fs";
|
|
9524
|
+
import { isAbsolute as isAbsolute3, join as join32, normalize, sep as sep9 } from "path";
|
|
9528
9525
|
function safeRel(p) {
|
|
9529
9526
|
const n2 = normalize(p.trim()).split(sep9).join("/").replace(/\/$/, "");
|
|
9530
9527
|
if (n2 === "" || isAbsolute3(n2) || n2 === ".." || n2.startsWith("../"))
|
|
@@ -9533,8 +9530,8 @@ function safeRel(p) {
|
|
|
9533
9530
|
}
|
|
9534
9531
|
function insideRepo(repoDir, rel) {
|
|
9535
9532
|
try {
|
|
9536
|
-
const real2 =
|
|
9537
|
-
const base =
|
|
9533
|
+
const real2 = realpathSync15(join32(repoDir, rel));
|
|
9534
|
+
const base = realpathSync15(repoDir);
|
|
9538
9535
|
return real2 === base || real2.startsWith(base + sep9);
|
|
9539
9536
|
} catch {
|
|
9540
9537
|
return false;
|
|
@@ -9546,7 +9543,7 @@ function checkCitation(repoDir, raw2) {
|
|
|
9546
9543
|
const rel = safeRel(raw2.replace(/:\d+(?:-\d+)?$/, ""));
|
|
9547
9544
|
if (rel === null)
|
|
9548
9545
|
return `citation "${raw2}" is not a repo-relative path`;
|
|
9549
|
-
const abs =
|
|
9546
|
+
const abs = join32(repoDir, rel);
|
|
9550
9547
|
if (!existsSync20(abs) || !statSync14(abs).isFile() || !insideRepo(repoDir, rel))
|
|
9551
9548
|
return `citation "${raw2}" names a file that does not exist`;
|
|
9552
9549
|
return null;
|
|
@@ -9558,7 +9555,7 @@ function checkFingerprint(repoDir, raw2) {
|
|
|
9558
9555
|
if (rel === null)
|
|
9559
9556
|
return `fingerprint "${raw2}" is not a repo-relative path`;
|
|
9560
9557
|
try {
|
|
9561
|
-
if (!
|
|
9558
|
+
if (!lstatSync7(join32(repoDir, rel)).isFile() || !insideRepo(repoDir, rel))
|
|
9562
9559
|
return `fingerprint "${raw2}" is not a regular file inside the repo`;
|
|
9563
9560
|
} catch {
|
|
9564
9561
|
return `fingerprint "${raw2}" names a file that does not exist`;
|
|
@@ -9586,7 +9583,7 @@ function checkDir(repoDir, v, where, errs) {
|
|
|
9586
9583
|
errs.push(`${where}: must be a repo-relative directory ("." for the repo root)`);
|
|
9587
9584
|
return ".";
|
|
9588
9585
|
}
|
|
9589
|
-
const abs =
|
|
9586
|
+
const abs = join32(repoDir, rel);
|
|
9590
9587
|
if (!existsSync20(abs) || !statSync14(abs).isDirectory() || !insideRepo(repoDir, rel))
|
|
9591
9588
|
errs.push(`${where}: directory "${rel}" does not exist`);
|
|
9592
9589
|
return rel;
|
|
@@ -9689,9 +9686,9 @@ var init_schema = __esm(() => {
|
|
|
9689
9686
|
});
|
|
9690
9687
|
|
|
9691
9688
|
// ../../loki-ts/src/project_model/gather.ts
|
|
9692
|
-
import { createHash as
|
|
9693
|
-
import { closeSync as
|
|
9694
|
-
import { dirname as dirname11, join as
|
|
9689
|
+
import { createHash as createHash8 } from "crypto";
|
|
9690
|
+
import { closeSync as closeSync7, lstatSync as lstatSync8, openSync as openSync7, readFileSync as readFileSync24, readSync as readSync6 } from "fs";
|
|
9691
|
+
import { dirname as dirname11, join as join33 } from "path";
|
|
9695
9692
|
function listShallow(repoDir) {
|
|
9696
9693
|
try {
|
|
9697
9694
|
const out2 = safeGit(repoDir, ["ls-files", "-z"], { maxBuffer: 256 * 1024 * 1024 });
|
|
@@ -9704,7 +9701,7 @@ function shallowDirs(repoDir) {
|
|
|
9704
9701
|
return [...new Set(listShallow(repoDir).map((p) => dirname11(p)))].sort();
|
|
9705
9702
|
}
|
|
9706
9703
|
function computeKey(repoDir, fingerprintFiles, dirs, committedHash = null) {
|
|
9707
|
-
const h =
|
|
9704
|
+
const h = createHash8("sha256");
|
|
9708
9705
|
h.update(`${MODEL_REV}
|
|
9709
9706
|
`);
|
|
9710
9707
|
if (committedHash !== null)
|
|
@@ -9717,9 +9714,9 @@ function computeKey(repoDir, fingerprintFiles, dirs, committedHash = null) {
|
|
|
9717
9714
|
if (checkFingerprint(repoDir, f) !== null)
|
|
9718
9715
|
h.update("invalid");
|
|
9719
9716
|
else {
|
|
9720
|
-
const abs =
|
|
9721
|
-
const size =
|
|
9722
|
-
h.update(size <= GATHER_CAPS.maxHashBytes ?
|
|
9717
|
+
const abs = join33(repoDir, f);
|
|
9718
|
+
const size = lstatSync8(abs).size;
|
|
9719
|
+
h.update(size <= GATHER_CAPS.maxHashBytes ? readFileSync24(abs) : `too-large:${size}`);
|
|
9723
9720
|
}
|
|
9724
9721
|
} catch {
|
|
9725
9722
|
h.update("missing");
|
|
@@ -9744,7 +9741,7 @@ function committedModelHash(raw2) {
|
|
|
9744
9741
|
if (typeof raw2 !== "object" || raw2 === null || Array.isArray(raw2))
|
|
9745
9742
|
return null;
|
|
9746
9743
|
const { key: _key, expiresAt: _exp, ...rest } = raw2;
|
|
9747
|
-
return
|
|
9744
|
+
return createHash8("sha256").update(JSON.stringify(rest)).digest("hex");
|
|
9748
9745
|
}
|
|
9749
9746
|
var GATHER_CAPS, depthOf = (p) => p.split("/").length, MODEL_REV = "model-rev:2";
|
|
9750
9747
|
var init_gather = __esm(() => {
|
|
@@ -9762,14 +9759,14 @@ var init_gather = __esm(() => {
|
|
|
9762
9759
|
});
|
|
9763
9760
|
|
|
9764
9761
|
// ../../loki-ts/src/project_model/discover.ts
|
|
9765
|
-
import { existsSync as existsSync21, mkdirSync as
|
|
9766
|
-
import { join as
|
|
9762
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync10, readFileSync as readFileSync25, rmSync as rmSync7, writeFileSync as writeFileSync13 } from "fs";
|
|
9763
|
+
import { join as join34 } from "path";
|
|
9767
9764
|
function projectModelEnabled(env = process.env) {
|
|
9768
9765
|
return env["LOKI_E10_PROJECT_MODEL"] !== "0";
|
|
9769
9766
|
}
|
|
9770
9767
|
function loadCached(repoDir, now2 = Date.now()) {
|
|
9771
9768
|
try {
|
|
9772
|
-
return parseCached(repoDir, JSON.parse(
|
|
9769
|
+
return parseCached(repoDir, JSON.parse(readFileSync25(join34(repoDir, PROJECT_FILE), "utf8")), now2);
|
|
9773
9770
|
} catch {
|
|
9774
9771
|
return null;
|
|
9775
9772
|
}
|
|
@@ -9784,7 +9781,7 @@ function loadCommitted(repoDir) {
|
|
|
9784
9781
|
};
|
|
9785
9782
|
let raw2;
|
|
9786
9783
|
try {
|
|
9787
|
-
raw2 = JSON.parse(
|
|
9784
|
+
raw2 = JSON.parse(readFileSync25(join34(repoDir, PROJECT_FILE), "utf8"));
|
|
9788
9785
|
} catch (e) {
|
|
9789
9786
|
return ignore(`unreadable JSON (${e instanceof Error ? e.message : String(e)})`);
|
|
9790
9787
|
}
|
|
@@ -9857,7 +9854,7 @@ var clean2 = (p) => typeof p === "string" ? posix.normalize(p.replace(/\\/g, "/"
|
|
|
9857
9854
|
var init_api = () => {};
|
|
9858
9855
|
|
|
9859
9856
|
// ../../loki-ts/src/project_model/resolve.ts
|
|
9860
|
-
import { join as
|
|
9857
|
+
import { join as join35 } from "path";
|
|
9861
9858
|
function loadProjectApi(repoDir, env = process.env) {
|
|
9862
9859
|
if (!projectModelEnabled(env))
|
|
9863
9860
|
return null;
|
|
@@ -9879,7 +9876,7 @@ function siteFor(api, repoDir, file) {
|
|
|
9879
9876
|
const rel = api.relativeToRoot(file);
|
|
9880
9877
|
if (!pkg || pkg.root === "." || rel === null)
|
|
9881
9878
|
return null;
|
|
9882
|
-
return { pkg, root: pkg.root, cwd:
|
|
9879
|
+
return { pkg, root: pkg.root, cwd: join35(repoDir, pkg.root), file: rel };
|
|
9883
9880
|
}
|
|
9884
9881
|
function groupByPackage(api, repoDir, files) {
|
|
9885
9882
|
const out2 = new Map;
|
|
@@ -9912,9 +9909,9 @@ var init_scope = __esm(() => {
|
|
|
9912
9909
|
|
|
9913
9910
|
// ../../loki-ts/src/e10ext/assert_delta.ts
|
|
9914
9911
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
9915
|
-
import { mkdtempSync as mkdtempSync4, readFileSync as
|
|
9912
|
+
import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync26, rmSync as rmSync8 } from "fs";
|
|
9916
9913
|
import { tmpdir as tmpdir6 } from "os";
|
|
9917
|
-
import { join as
|
|
9914
|
+
import { join as join36 } from "path";
|
|
9918
9915
|
import { basename as basename11 } from "path";
|
|
9919
9916
|
function classifyAssertDelta(inp) {
|
|
9920
9917
|
const f = basename11(inp.path);
|
|
@@ -9924,7 +9921,7 @@ function classifyAssertDelta(inp) {
|
|
|
9924
9921
|
return WEAKENED;
|
|
9925
9922
|
let cwd = "";
|
|
9926
9923
|
try {
|
|
9927
|
-
cwd = mkdtempSync4(
|
|
9924
|
+
cwd = mkdtempSync4(join36(tmpdir6(), "loki-ad-"));
|
|
9928
9925
|
const raw2 = execFileSync5("python3", ["-I", "-c", PY], {
|
|
9929
9926
|
input: JSON.stringify({ path: inp.path, base: inp.base, head: inp.head, task: inp.task }),
|
|
9930
9927
|
cwd,
|
|
@@ -9947,7 +9944,7 @@ function classifyAssertDelta(inp) {
|
|
|
9947
9944
|
return WEAKENED;
|
|
9948
9945
|
} finally {
|
|
9949
9946
|
if (cwd)
|
|
9950
|
-
|
|
9947
|
+
rmSync8(cwd, { recursive: true, force: true });
|
|
9951
9948
|
}
|
|
9952
9949
|
}
|
|
9953
9950
|
function assertDeltaNotes(repoDir, baseSha, headRef, path, task, baseCounts, headCounts) {
|
|
@@ -9955,7 +9952,7 @@ function assertDeltaNotes(repoDir, baseSha, headRef, path, task, baseCounts, hea
|
|
|
9955
9952
|
return null;
|
|
9956
9953
|
try {
|
|
9957
9954
|
const show = (ref) => safeGit(repoDir, ["show", `${ref}:${path}`]);
|
|
9958
|
-
const head = headRef ? show(headRef) :
|
|
9955
|
+
const head = headRef ? show(headRef) : readFileSync26(join36(repoDir, path), "utf8");
|
|
9959
9956
|
const r = classifyTestEdit(path, show(baseSha), head, task, baseCounts, headCounts);
|
|
9960
9957
|
return r[0]?.kind === "literal-only" ? r.map((e) => `assertion value changed (not shown to be required by the task): ${e.file}:${e.line} ${e.old} -> ${e.new}`) : null;
|
|
9961
9958
|
} catch {
|
|
@@ -10179,7 +10176,7 @@ var init_runner_errors = __esm(() => {
|
|
|
10179
10176
|
});
|
|
10180
10177
|
|
|
10181
10178
|
// ../../loki-ts/src/engine10/testmap.ts
|
|
10182
|
-
import { basename as basename12, extname, join as
|
|
10179
|
+
import { basename as basename12, extname, join as join37, relative as relative3, sep as sep10 } from "path";
|
|
10183
10180
|
function isTestFile(rel) {
|
|
10184
10181
|
const name = basename12(rel);
|
|
10185
10182
|
return JS_TEST_RE.test(name) || PY_TEST_RE.test(name) || GO_TEST_RE.test(name);
|
|
@@ -10209,8 +10206,8 @@ var init_testmap = __esm(() => {
|
|
|
10209
10206
|
});
|
|
10210
10207
|
|
|
10211
10208
|
// ../../loki-ts/src/util/check_result.ts
|
|
10212
|
-
import { mkdirSync as
|
|
10213
|
-
import { basename as basename13, join as
|
|
10209
|
+
import { mkdirSync as mkdirSync11, readFileSync as readFileSync27, renameSync as renameSync5, writeFileSync as writeFileSync14 } from "fs";
|
|
10210
|
+
import { basename as basename13, join as join38 } from "path";
|
|
10214
10211
|
function plainTestEnv(base = process.env) {
|
|
10215
10212
|
const e = {};
|
|
10216
10213
|
for (const [k, v] of Object.entries(tokenFreeEnv(base)))
|
|
@@ -10389,17 +10386,17 @@ function classifyCheck(i) {
|
|
|
10389
10386
|
return { result: "not_run", reason: "timed out or aborted" };
|
|
10390
10387
|
if (i.kind === "static")
|
|
10391
10388
|
return { result: i.ok ? "pass" : "fail" };
|
|
10392
|
-
const
|
|
10389
|
+
const text2 = stripAnsi(i.out);
|
|
10393
10390
|
if (i.runner === "go") {
|
|
10394
10391
|
if (i.ok)
|
|
10395
10392
|
return { result: "not_run", reason: GO_EXIT0_REASON };
|
|
10396
|
-
const j = goJson(
|
|
10393
|
+
const j = goJson(text2);
|
|
10397
10394
|
if (j)
|
|
10398
10395
|
return j.failed ? { result: "fail" } : { result: "not_run", reason: UNCONFIRMED_REASON };
|
|
10399
|
-
return FAIL_EVIDENCE.test(
|
|
10396
|
+
return FAIL_EVIDENCE.test(text2) || GO_FAIL_EVIDENCE.test(text2) ? { result: "fail" } : { result: "not_run", reason: UNCONFIRMED_REASON };
|
|
10400
10397
|
}
|
|
10401
10398
|
const n2 = testCount(i.out, i.path, i.ok);
|
|
10402
|
-
if (!i.ok && FAIL_EVIDENCE.test(
|
|
10399
|
+
if (!i.ok && FAIL_EVIDENCE.test(text2))
|
|
10403
10400
|
return { result: "fail", ...n2 !== null ? { n: n2 } : {} };
|
|
10404
10401
|
if (n2 === 0)
|
|
10405
10402
|
return { result: "not_run", n: 0, reason: `${NO_TESTS_REASON} (ran 0 tests, empty or all skipped)` };
|
|
@@ -10476,10 +10473,10 @@ function classifyRisk(files, env = process.env) {
|
|
|
10476
10473
|
};
|
|
10477
10474
|
}
|
|
10478
10475
|
function changedFiles(repoDir, baseSha) {
|
|
10479
|
-
const
|
|
10476
|
+
const run2 = (args) => safeGit(repoDir, args).split(`
|
|
10480
10477
|
`).map((l) => l.trim()).filter(Boolean);
|
|
10481
|
-
const tracked =
|
|
10482
|
-
const untracked =
|
|
10478
|
+
const tracked = run2(["diff", "--name-only", baseSha]);
|
|
10479
|
+
const untracked = run2(["ls-files", "--others", "--exclude-standard"]);
|
|
10483
10480
|
return [...new Set([...tracked, ...untracked])].filter((f) => !f.startsWith(".loki/"));
|
|
10484
10481
|
}
|
|
10485
10482
|
function diffFiles(repoDir, baseSha) {
|
|
@@ -10502,7 +10499,7 @@ function diffFiles(repoDir, baseSha) {
|
|
|
10502
10499
|
return f;
|
|
10503
10500
|
let n2 = 0;
|
|
10504
10501
|
try {
|
|
10505
|
-
n2 =
|
|
10502
|
+
n2 = readFileSync27(join38(repoDir, path), "utf8").split(`
|
|
10506
10503
|
`).length;
|
|
10507
10504
|
} catch {}
|
|
10508
10505
|
return { path, added: n2, deleted: 0, status: "added" };
|
|
@@ -10510,9 +10507,9 @@ function diffFiles(repoDir, baseSha) {
|
|
|
10510
10507
|
}
|
|
10511
10508
|
function recordRisk(repoDir, a) {
|
|
10512
10509
|
try {
|
|
10513
|
-
const dir =
|
|
10514
|
-
|
|
10515
|
-
|
|
10510
|
+
const dir = join38(repoDir, ".loki", "state"), p = join38(dir, "risk-tier.json");
|
|
10511
|
+
mkdirSync11(dir, { recursive: true });
|
|
10512
|
+
writeFileSync14(`${p}.tmp`, JSON.stringify(a, null, 2) + `
|
|
10516
10513
|
`);
|
|
10517
10514
|
renameSync5(`${p}.tmp`, p);
|
|
10518
10515
|
return p;
|
|
@@ -10553,12 +10550,12 @@ var init_check_result = __esm(() => {
|
|
|
10553
10550
|
|
|
10554
10551
|
// ../../loki-ts/src/runner/load_owner.ts
|
|
10555
10552
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
10556
|
-
import { mkdtempSync as mkdtempSync5, realpathSync as
|
|
10553
|
+
import { mkdtempSync as mkdtempSync5, realpathSync as realpathSync16, rmSync as rmSync9 } from "fs";
|
|
10557
10554
|
import { tmpdir as tmpdir7 } from "os";
|
|
10558
|
-
import { basename as basename14, extname as extname2, join as
|
|
10555
|
+
import { basename as basename14, extname as extname2, join as join39 } from "path";
|
|
10559
10556
|
function changedFilesNamed(out2, repoDir, changed) {
|
|
10560
10557
|
return changed.filter((f) => {
|
|
10561
|
-
if (out2.includes(f) || out2.includes(
|
|
10558
|
+
if (out2.includes(f) || out2.includes(join39(repoDir, f)))
|
|
10562
10559
|
return true;
|
|
10563
10560
|
const segs = f.split("/");
|
|
10564
10561
|
if (suffixes(segs, 2).some((x) => x !== f && bounded(out2, x, "(?![\\w-])")))
|
|
@@ -10575,7 +10572,7 @@ function loadSignature(out2, roots) {
|
|
|
10575
10572
|
let o = out2;
|
|
10576
10573
|
for (const r of roots.flatMap((x) => {
|
|
10577
10574
|
try {
|
|
10578
|
-
return [x,
|
|
10575
|
+
return [x, realpathSync16(x)];
|
|
10579
10576
|
} catch {
|
|
10580
10577
|
return [x];
|
|
10581
10578
|
}
|
|
@@ -10669,7 +10666,7 @@ async function loadErrorIsHarnessOwned(i) {
|
|
|
10669
10666
|
return false;
|
|
10670
10667
|
if (i.args.some((a) => changed.includes(a.replace(/^\.\//, ""))))
|
|
10671
10668
|
return false;
|
|
10672
|
-
const dir = mkdtempSync5(
|
|
10669
|
+
const dir = mkdtempSync5(join39(tmpdir7(), "e10-loadown-"));
|
|
10673
10670
|
const git3 = (args) => {
|
|
10674
10671
|
safeGit(i.repoDir, args, { stdio: "ignore" });
|
|
10675
10672
|
};
|
|
@@ -10683,7 +10680,7 @@ async function loadErrorIsHarnessOwned(i) {
|
|
|
10683
10680
|
try {
|
|
10684
10681
|
git3(["worktree", "remove", "--force", dir]);
|
|
10685
10682
|
} catch {}
|
|
10686
|
-
|
|
10683
|
+
rmSync9(dir, { recursive: true, force: true });
|
|
10687
10684
|
try {
|
|
10688
10685
|
git3(["worktree", "prune"]);
|
|
10689
10686
|
} catch {}
|
|
@@ -10701,7 +10698,7 @@ var init_load_owner = __esm(() => {
|
|
|
10701
10698
|
});
|
|
10702
10699
|
|
|
10703
10700
|
// ../../loki-ts/src/util/wall_owned.ts
|
|
10704
|
-
import { isAbsolute as isAbsolute4, join as
|
|
10701
|
+
import { isAbsolute as isAbsolute4, join as join40, relative as relative4 } from "path";
|
|
10705
10702
|
function failingLocations(raw2, cwd, repoDir) {
|
|
10706
10703
|
const out2 = raw2.replace(ANSI2, "").replace(/\r\n?/g, `
|
|
10707
10704
|
`), files = new Set;
|
|
@@ -10733,7 +10730,7 @@ function failingLocations(raw2, cwd, repoDir) {
|
|
|
10733
10730
|
}
|
|
10734
10731
|
if (errors2 === 0 || located !== errors2)
|
|
10735
10732
|
return null;
|
|
10736
|
-
return [...files].map((f) => relative4(repoDir, isAbsolute4(f) ? f :
|
|
10733
|
+
return [...files].map((f) => relative4(repoDir, isAbsolute4(f) ? f : join40(cwd, f)));
|
|
10737
10734
|
}
|
|
10738
10735
|
function wallOwnedFailure(raw2, cwd, repoDir, wall) {
|
|
10739
10736
|
const locs = failingLocations(raw2, cwd, repoDir);
|
|
@@ -10744,57 +10741,6 @@ var init_wall_owned = __esm(() => {
|
|
|
10744
10741
|
ANSI2 = /\u001b\[[0-9;?]*[ -/]*[@-~]/g;
|
|
10745
10742
|
});
|
|
10746
10743
|
|
|
10747
|
-
// ../../loki-ts/src/util/atomic.ts
|
|
10748
|
-
import {
|
|
10749
|
-
closeSync as closeSync6,
|
|
10750
|
-
fstatSync as fstatSync4,
|
|
10751
|
-
fsyncSync as fsyncSync2,
|
|
10752
|
-
lstatSync as lstatSync7,
|
|
10753
|
-
mkdirSync as mkdirSync11,
|
|
10754
|
-
openSync as openSync6,
|
|
10755
|
-
readSync as readSync5,
|
|
10756
|
-
renameSync as renameSync6,
|
|
10757
|
-
rmSync as rmSync9,
|
|
10758
|
-
statSync as statSync15,
|
|
10759
|
-
unlinkSync as unlinkSync3,
|
|
10760
|
-
writeSync as writeSync3
|
|
10761
|
-
} from "fs";
|
|
10762
|
-
import { dirname as dirname12 } from "path";
|
|
10763
|
-
function durableWriteThenRename(target, body) {
|
|
10764
|
-
mkdirSync11(dirname12(target), { recursive: true });
|
|
10765
|
-
const tmp = `${target}.tmp.${process.pid}.${++_tmpCounter}`;
|
|
10766
|
-
const fd = openSync6(tmp, "w");
|
|
10767
|
-
try {
|
|
10768
|
-
writeSync3(fd, body);
|
|
10769
|
-
fsyncSync2(fd);
|
|
10770
|
-
} finally {
|
|
10771
|
-
closeSync6(fd);
|
|
10772
|
-
}
|
|
10773
|
-
renameSync6(tmp, target);
|
|
10774
|
-
fsyncParentDir(target);
|
|
10775
|
-
}
|
|
10776
|
-
function fsyncParentDir(target) {
|
|
10777
|
-
let dfd = null;
|
|
10778
|
-
try {
|
|
10779
|
-
dfd = openSync6(dirname12(target), "r");
|
|
10780
|
-
fsyncSync2(dfd);
|
|
10781
|
-
} catch {} finally {
|
|
10782
|
-
if (dfd !== null) {
|
|
10783
|
-
try {
|
|
10784
|
-
closeSync6(dfd);
|
|
10785
|
-
} catch {}
|
|
10786
|
-
}
|
|
10787
|
-
}
|
|
10788
|
-
}
|
|
10789
|
-
function atomicWriteJson(target, data) {
|
|
10790
|
-
durableWriteThenRename(target, `${JSON.stringify(data, null, 2)}
|
|
10791
|
-
`);
|
|
10792
|
-
}
|
|
10793
|
-
var _tmpCounter = 0, _appendChains;
|
|
10794
|
-
var init_atomic = __esm(() => {
|
|
10795
|
-
_appendChains = new Map;
|
|
10796
|
-
});
|
|
10797
|
-
|
|
10798
10744
|
// ../../loki-ts/src/runner/state.ts
|
|
10799
10745
|
var TERMINAL_STATUSES;
|
|
10800
10746
|
var init_state = __esm(() => {
|
|
@@ -10813,11 +10759,11 @@ var init_state = __esm(() => {
|
|
|
10813
10759
|
});
|
|
10814
10760
|
|
|
10815
10761
|
// ../../loki-ts/src/runner/repo_profile.ts
|
|
10816
|
-
import { existsSync as existsSync22, readFileSync as
|
|
10817
|
-
import { basename as basename15, join as
|
|
10762
|
+
import { existsSync as existsSync22, readFileSync as readFileSync28, mkdirSync as mkdirSync12, readdirSync as readdirSync11, renameSync as renameSync6, rmSync as rmSync10, writeFileSync as writeFileSync15 } from "fs";
|
|
10763
|
+
import { basename as basename15, join as join41, resolve as resolve11, isAbsolute as isAbsolute5 } from "path";
|
|
10818
10764
|
function loadProfile(repoDir) {
|
|
10819
10765
|
try {
|
|
10820
|
-
const p = JSON.parse(
|
|
10766
|
+
const p = JSON.parse(readFileSync28(commandProfilePath(repoDir), "utf8"));
|
|
10821
10767
|
return p?.version === 1 && Array.isArray(p.commands) && p.baseline ? p : null;
|
|
10822
10768
|
} catch {
|
|
10823
10769
|
return null;
|
|
@@ -10840,15 +10786,15 @@ function attribute(repoDir, baseSha, failing) {
|
|
|
10840
10786
|
}
|
|
10841
10787
|
function attributeFullSuite(repoDir, baseSha, full, blocked, changed) {
|
|
10842
10788
|
const bad = full.filter((c) => c.result === "fail"), none = { preExistingChecks: [], preExistingIds: [], introducedChecks: bad.map((c) => c.name), line: null };
|
|
10843
|
-
const
|
|
10789
|
+
const norm4 = (s) => s.replace(/\s+--silent\b/, "").trim(), p = loadProfile(repoDir);
|
|
10844
10790
|
if (!bad.length || !p || p.revision !== baseSha || !p.baseline.attributable || !p.baseline.failing_ids.length)
|
|
10845
10791
|
return none;
|
|
10846
|
-
if (bad.some((c) =>
|
|
10792
|
+
if (bad.some((c) => norm4(c.cmd) !== norm4(p.baseline.command ?? "")))
|
|
10847
10793
|
return { ...none, line: `baseline: ran "${p.baseline.command}", not the full suite command, ids not comparable, full suite failures not excused` };
|
|
10848
10794
|
const block = new Set(blocked);
|
|
10849
10795
|
return attribute(repoDir, baseSha, bad.map((c) => ({ name: c.name, ...c.ids ? { ids: c.ids } : {}, eligible: (c.ids ?? []).every((i) => !block.has(i) && !changed.some((f) => i.includes(f))) })));
|
|
10850
10796
|
}
|
|
10851
|
-
var commandProfilePath = (repoDir) =>
|
|
10797
|
+
var commandProfilePath = (repoDir) => join41(repoDir, ".loki", "state", "repo-profile.json");
|
|
10852
10798
|
var init_repo_profile = __esm(() => {
|
|
10853
10799
|
init_failures();
|
|
10854
10800
|
init_check_result();
|
|
@@ -10858,23 +10804,23 @@ var init_repo_profile = __esm(() => {
|
|
|
10858
10804
|
});
|
|
10859
10805
|
|
|
10860
10806
|
// ../../loki-ts/src/project_graph.ts
|
|
10861
|
-
import { createHash as
|
|
10807
|
+
import { createHash as createHash9 } from "crypto";
|
|
10862
10808
|
import {
|
|
10863
10809
|
existsSync as existsSync23,
|
|
10864
|
-
readdirSync as
|
|
10865
|
-
readFileSync as
|
|
10866
|
-
statSync as
|
|
10867
|
-
writeFileSync as
|
|
10810
|
+
readdirSync as readdirSync12,
|
|
10811
|
+
readFileSync as readFileSync29,
|
|
10812
|
+
statSync as statSync15,
|
|
10813
|
+
writeFileSync as writeFileSync16,
|
|
10868
10814
|
mkdirSync as mkdirSync13
|
|
10869
10815
|
} from "fs";
|
|
10870
|
-
import { basename as basename16, dirname as
|
|
10816
|
+
import { basename as basename16, dirname as dirname12, join as join42, resolve as resolve12 } from "path";
|
|
10871
10817
|
function readManifest(path) {
|
|
10872
10818
|
if (!existsSync23(path)) {
|
|
10873
10819
|
return null;
|
|
10874
10820
|
}
|
|
10875
10821
|
let raw2;
|
|
10876
10822
|
try {
|
|
10877
|
-
raw2 =
|
|
10823
|
+
raw2 = readFileSync29(path, "utf8");
|
|
10878
10824
|
} catch {
|
|
10879
10825
|
return null;
|
|
10880
10826
|
}
|
|
@@ -10911,7 +10857,7 @@ function resolveMembers(rootDir, declared, selfBasename) {
|
|
|
10911
10857
|
const seen = new Set;
|
|
10912
10858
|
let children;
|
|
10913
10859
|
try {
|
|
10914
|
-
children =
|
|
10860
|
+
children = readdirSync12(rootDir);
|
|
10915
10861
|
} catch {
|
|
10916
10862
|
children = [];
|
|
10917
10863
|
}
|
|
@@ -10926,12 +10872,12 @@ function resolveMembers(rootDir, declared, selfBasename) {
|
|
|
10926
10872
|
for (const child of children) {
|
|
10927
10873
|
if (!matchPattern(name, child))
|
|
10928
10874
|
continue;
|
|
10929
|
-
const full =
|
|
10875
|
+
const full = join42(rootDir, child);
|
|
10930
10876
|
if (seen.has(full))
|
|
10931
10877
|
continue;
|
|
10932
10878
|
let st;
|
|
10933
10879
|
try {
|
|
10934
|
-
st =
|
|
10880
|
+
st = statSync15(full);
|
|
10935
10881
|
} catch {
|
|
10936
10882
|
continue;
|
|
10937
10883
|
}
|
|
@@ -10943,18 +10889,18 @@ function resolveMembers(rootDir, declared, selfBasename) {
|
|
|
10943
10889
|
}
|
|
10944
10890
|
if (declared.length === 0) {
|
|
10945
10891
|
for (const child of children) {
|
|
10946
|
-
const full =
|
|
10892
|
+
const full = join42(rootDir, child);
|
|
10947
10893
|
if (seen.has(full))
|
|
10948
10894
|
continue;
|
|
10949
10895
|
let st;
|
|
10950
10896
|
try {
|
|
10951
|
-
st =
|
|
10897
|
+
st = statSync15(full);
|
|
10952
10898
|
} catch {
|
|
10953
10899
|
continue;
|
|
10954
10900
|
}
|
|
10955
10901
|
if (!st.isDirectory())
|
|
10956
10902
|
continue;
|
|
10957
|
-
if (!existsSync23(
|
|
10903
|
+
if (!existsSync23(join42(full, ".loki", "app.json")))
|
|
10958
10904
|
continue;
|
|
10959
10905
|
seen.add(full);
|
|
10960
10906
|
out2.push(full);
|
|
@@ -10967,25 +10913,25 @@ function cacheKey(manifestPaths) {
|
|
|
10967
10913
|
for (const p of manifestPaths.sort()) {
|
|
10968
10914
|
let mtime = 0;
|
|
10969
10915
|
try {
|
|
10970
|
-
mtime =
|
|
10916
|
+
mtime = statSync15(p).mtimeMs;
|
|
10971
10917
|
} catch {}
|
|
10972
10918
|
parts.push(`${p}:${mtime}`);
|
|
10973
10919
|
}
|
|
10974
|
-
return
|
|
10920
|
+
return createHash9("sha256").update(parts.join("|")).digest("hex");
|
|
10975
10921
|
}
|
|
10976
10922
|
function writeCache(targetDir, key, result) {
|
|
10977
10923
|
try {
|
|
10978
|
-
const cacheDir =
|
|
10924
|
+
const cacheDir = join42(targetDir, ".loki", "state");
|
|
10979
10925
|
mkdirSync13(cacheDir, { recursive: true });
|
|
10980
|
-
const cachePath =
|
|
10981
|
-
|
|
10926
|
+
const cachePath = join42(cacheDir, "project-graph.json");
|
|
10927
|
+
writeFileSync16(cachePath, JSON.stringify({ key, result }, null, 2), "utf8");
|
|
10982
10928
|
} catch {}
|
|
10983
10929
|
}
|
|
10984
10930
|
function discoverProjectGraph(targetDir) {
|
|
10985
10931
|
const absTarget = resolve12(targetDir);
|
|
10986
|
-
const targetManifest =
|
|
10987
|
-
const parentDir =
|
|
10988
|
-
const parentManifest =
|
|
10932
|
+
const targetManifest = join42(absTarget, ".loki", "app.json");
|
|
10933
|
+
const parentDir = dirname12(absTarget);
|
|
10934
|
+
const parentManifest = join42(parentDir, ".loki", "app.json");
|
|
10989
10935
|
const examined = [];
|
|
10990
10936
|
let chosenManifest = null;
|
|
10991
10937
|
let chosenRoot = "";
|
|
@@ -11005,7 +10951,7 @@ function discoverProjectGraph(targetDir) {
|
|
|
11005
10951
|
const members = resolveMembers(chosenRoot, declared, basename16(absTarget));
|
|
11006
10952
|
const filtered = [];
|
|
11007
10953
|
for (const m of members) {
|
|
11008
|
-
const sibManifestPath =
|
|
10954
|
+
const sibManifestPath = join42(m, ".loki", "app.json");
|
|
11009
10955
|
if (existsSync23(sibManifestPath)) {
|
|
11010
10956
|
examined.push(sibManifestPath);
|
|
11011
10957
|
const sibManifest = readManifest(sibManifestPath);
|
|
@@ -11020,161 +10966,26 @@ function discoverProjectGraph(targetDir) {
|
|
|
11020
10966
|
root: chosenRoot,
|
|
11021
10967
|
members: filtered,
|
|
11022
10968
|
sharedMemoryDir: chosenManifest.shared_memory_dir
|
|
11023
|
-
};
|
|
11024
|
-
writeCache(absTarget, cacheKey(examined), result);
|
|
11025
|
-
return result;
|
|
11026
|
-
}
|
|
11027
|
-
var APP_ID_REGEX, SUPPORTED_SCHEMA_VERSION = 1;
|
|
11028
|
-
var init_project_graph = __esm(() => {
|
|
11029
|
-
APP_ID_REGEX = /^[a-z0-9-]{3,40}$/;
|
|
11030
|
-
});
|
|
11031
|
-
|
|
11032
|
-
// ../../loki-ts/src/util/shell.ts
|
|
11033
|
-
async function readStreamCapped(stream, maxBytes = MAX_STDOUT_BYTES) {
|
|
11034
|
-
const reader = stream.getReader();
|
|
11035
|
-
const decoder = new TextDecoder;
|
|
11036
|
-
let out2 = "";
|
|
11037
|
-
let total = 0;
|
|
11038
|
-
try {
|
|
11039
|
-
while (total < maxBytes) {
|
|
11040
|
-
const { done, value } = await reader.read();
|
|
11041
|
-
if (done)
|
|
11042
|
-
break;
|
|
11043
|
-
if (!value)
|
|
11044
|
-
continue;
|
|
11045
|
-
total += value.byteLength;
|
|
11046
|
-
if (total > maxBytes) {
|
|
11047
|
-
const keep = value.byteLength - (total - maxBytes);
|
|
11048
|
-
out2 += decoder.decode(value.subarray(0, keep), { stream: true });
|
|
11049
|
-
break;
|
|
11050
|
-
}
|
|
11051
|
-
out2 += decoder.decode(value, { stream: true });
|
|
11052
|
-
}
|
|
11053
|
-
out2 += decoder.decode();
|
|
11054
|
-
} finally {
|
|
11055
|
-
try {
|
|
11056
|
-
await reader.cancel();
|
|
11057
|
-
} catch {}
|
|
11058
|
-
reader.releaseLock();
|
|
11059
|
-
}
|
|
11060
|
-
return out2;
|
|
11061
|
-
}
|
|
11062
|
-
async function run(argv, opts = {}) {
|
|
11063
|
-
const proc = Bun.spawn({
|
|
11064
|
-
cmd: [...argv],
|
|
11065
|
-
stdout: "pipe",
|
|
11066
|
-
stderr: "pipe",
|
|
11067
|
-
env: opts.env ? { ...process.env, ...opts.env } : process.env,
|
|
11068
|
-
cwd: opts.cwd
|
|
11069
|
-
});
|
|
11070
|
-
let timer;
|
|
11071
|
-
let killTimer;
|
|
11072
|
-
if (opts.timeoutMs && opts.timeoutMs > 0) {
|
|
11073
|
-
timer = setTimeout(() => {
|
|
11074
|
-
try {
|
|
11075
|
-
proc.kill("SIGTERM");
|
|
11076
|
-
} catch {}
|
|
11077
|
-
killTimer = setTimeout(() => {
|
|
11078
|
-
try {
|
|
11079
|
-
proc.kill("SIGKILL");
|
|
11080
|
-
} catch {}
|
|
11081
|
-
}, 2000);
|
|
11082
|
-
}, opts.timeoutMs);
|
|
11083
|
-
}
|
|
11084
|
-
try {
|
|
11085
|
-
const [stdout, stderr, exitCode] = await Promise.all([
|
|
11086
|
-
readStreamCapped(proc.stdout),
|
|
11087
|
-
new Response(proc.stderr).text(),
|
|
11088
|
-
proc.exited
|
|
11089
|
-
]);
|
|
11090
|
-
return { stdout, stderr, exitCode };
|
|
11091
|
-
} finally {
|
|
11092
|
-
if (timer)
|
|
11093
|
-
clearTimeout(timer);
|
|
11094
|
-
if (killTimer)
|
|
11095
|
-
clearTimeout(killTimer);
|
|
11096
|
-
}
|
|
11097
|
-
}
|
|
11098
|
-
var MAX_STDOUT_BYTES;
|
|
11099
|
-
var init_shell = __esm(() => {
|
|
11100
|
-
MAX_STDOUT_BYTES = 16 * 1024 * 1024;
|
|
11101
|
-
});
|
|
11102
|
-
|
|
11103
|
-
// ../../loki-ts/src/e10ext/budget_cap.ts
|
|
11104
|
-
var DEFAULT_MAX_COST_USD;
|
|
11105
|
-
var init_budget_cap = __esm(() => {
|
|
11106
|
-
init_budget();
|
|
11107
|
-
DEFAULT_MAX_COST_USD = loadDefaultMaxCostUsd();
|
|
11108
|
-
});
|
|
11109
|
-
|
|
11110
|
-
// ../../loki-ts/src/runner/retry_class.ts
|
|
11111
|
-
var init_retry_class = () => {};
|
|
11112
|
-
|
|
11113
|
-
// ../../loki-ts/src/features/speed/unit_mode.ts
|
|
11114
|
-
import { closeSync as closeSync7, constants as constants2, fstatSync as fstatSync5, lstatSync as lstatSync8, openSync as openSync7, readSync as readSync6, realpathSync as realpathSync16 } from "fs";
|
|
11115
|
-
function readBounded(path) {
|
|
11116
|
-
const l = lstatSync8(path);
|
|
11117
|
-
if (l.isSymbolicLink() || !l.isFile() || l.size > MAX_SPEC_BYTES)
|
|
11118
|
-
return null;
|
|
11119
|
-
const fd = openSync7(path, constants2.O_RDONLY | constants2.O_NOFOLLOW | constants2.O_NONBLOCK);
|
|
11120
|
-
try {
|
|
11121
|
-
const st = fstatSync5(fd);
|
|
11122
|
-
if (!st.isFile() || st.size > MAX_SPEC_BYTES)
|
|
11123
|
-
return null;
|
|
11124
|
-
const buf = Buffer.alloc(st.size + 1);
|
|
11125
|
-
let n2 = 0;
|
|
11126
|
-
for (;; ) {
|
|
11127
|
-
const r = readSync6(fd, buf, n2, buf.length - n2, null);
|
|
11128
|
-
if (r <= 0)
|
|
11129
|
-
break;
|
|
11130
|
-
n2 += r;
|
|
11131
|
-
if (n2 >= buf.length)
|
|
11132
|
-
return null;
|
|
11133
|
-
}
|
|
11134
|
-
return buf.subarray(0, n2).toString("utf8");
|
|
11135
|
-
} finally {
|
|
11136
|
-
closeSync7(fd);
|
|
11137
|
-
}
|
|
11138
|
-
}
|
|
11139
|
-
function parseText(txt) {
|
|
11140
|
-
try {
|
|
11141
|
-
const j = JSON.parse(txt), ws = strs(j.writeSet), pack = strs(j.pack), tb = j.tokenBudget;
|
|
11142
|
-
if (typeof j.id !== "string" || !j.id || !ws || ws.length === 0 || !pack || typeof tb !== "number" || !Number.isFinite(tb) || !(tb > 0) || tb > MAX_TOKEN_BUDGET)
|
|
11143
|
-
return null;
|
|
11144
|
-
return { id: j.id, writeSet: ws, pack, tokenBudget: tb };
|
|
11145
|
-
} catch {
|
|
11146
|
-
return null;
|
|
11147
|
-
}
|
|
11148
|
-
}
|
|
11149
|
-
function parseSpec(path) {
|
|
11150
|
-
try {
|
|
11151
|
-
const txt = readBounded(path);
|
|
11152
|
-
return txt === null ? null : parseText(txt);
|
|
11153
|
-
} catch {
|
|
11154
|
-
return null;
|
|
11155
|
-
}
|
|
11156
|
-
}
|
|
11157
|
-
function unitSpec(env = process.env) {
|
|
11158
|
-
const path = env["LOKI_UNIT_SPEC"], frozen = env["LOKI_UNIT_SPEC_FROZEN"];
|
|
11159
|
-
if (env["LOKI_SPEED"] === "0" || !path)
|
|
11160
|
-
return null;
|
|
11161
|
-
if (frozen !== undefined)
|
|
11162
|
-
return frozen.length <= MAX_SPEC_BYTES ? parseText(frozen) : null;
|
|
11163
|
-
if (!memo.has(path))
|
|
11164
|
-
memo.set(path, parseSpec(path));
|
|
11165
|
-
return memo.get(path) ?? null;
|
|
11166
|
-
}
|
|
11167
|
-
function unitFlags(staged, env = process.env, pre = {}) {
|
|
11168
|
-
const s = unitSpec(env);
|
|
11169
|
-
return s ? staged.filter(({ f }) => !inWriteSet(s, f) && !Object.hasOwn(pre, f)).map(({ f }) => f) : null;
|
|
10969
|
+
};
|
|
10970
|
+
writeCache(absTarget, cacheKey(examined), result);
|
|
10971
|
+
return result;
|
|
11170
10972
|
}
|
|
11171
|
-
var
|
|
11172
|
-
var
|
|
11173
|
-
|
|
11174
|
-
|
|
11175
|
-
|
|
10973
|
+
var APP_ID_REGEX, SUPPORTED_SCHEMA_VERSION = 1;
|
|
10974
|
+
var init_project_graph = __esm(() => {
|
|
10975
|
+
APP_ID_REGEX = /^[a-z0-9-]{3,40}$/;
|
|
10976
|
+
});
|
|
10977
|
+
|
|
10978
|
+
// ../../loki-ts/src/e10ext/budget_cap.ts
|
|
10979
|
+
var DEFAULT_MAX_COST_USD;
|
|
10980
|
+
var init_budget_cap = __esm(() => {
|
|
10981
|
+
init_yaml_key();
|
|
10982
|
+
init_budget();
|
|
10983
|
+
DEFAULT_MAX_COST_USD = loadDefaultMaxCostUsd();
|
|
11176
10984
|
});
|
|
11177
10985
|
|
|
10986
|
+
// ../../loki-ts/src/runner/retry_class.ts
|
|
10987
|
+
var init_retry_class = () => {};
|
|
10988
|
+
|
|
11178
10989
|
// ../../loki-ts/src/e10ext/repomemory.ts
|
|
11179
10990
|
var init_repomemory = __esm(() => {
|
|
11180
10991
|
init_cache();
|
|
@@ -11213,14 +11024,15 @@ var init_steer = __esm(() => {
|
|
|
11213
11024
|
});
|
|
11214
11025
|
|
|
11215
11026
|
// ../../loki-ts/src/util/pr_lessons.ts
|
|
11216
|
-
import { existsSync as existsSync24, mkdirSync as mkdirSync14, readFileSync as
|
|
11217
|
-
import { dirname as
|
|
11027
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync14, readFileSync as readFileSync30 } from "fs";
|
|
11028
|
+
import { dirname as dirname13, join as join43 } from "path";
|
|
11029
|
+
import { createHash as createHash10 } from "crypto";
|
|
11218
11030
|
function loadLessons(repoDir) {
|
|
11219
11031
|
const p = lessonsPath(repoDir);
|
|
11220
11032
|
if (!existsSync24(p))
|
|
11221
11033
|
return [];
|
|
11222
11034
|
try {
|
|
11223
|
-
const j = JSON.parse(
|
|
11035
|
+
const j = JSON.parse(readFileSync30(p, "utf-8"));
|
|
11224
11036
|
return Array.isArray(j.lessons) ? j.lessons : [];
|
|
11225
11037
|
} catch {
|
|
11226
11038
|
return [];
|
|
@@ -11228,9 +11040,28 @@ function loadLessons(repoDir) {
|
|
|
11228
11040
|
}
|
|
11229
11041
|
function save(repoDir, lessons) {
|
|
11230
11042
|
const p = lessonsPath(repoDir);
|
|
11231
|
-
mkdirSync14(
|
|
11043
|
+
mkdirSync14(dirname13(p), { recursive: true });
|
|
11232
11044
|
atomicWriteJson(p, { version: 2, lessons });
|
|
11233
11045
|
}
|
|
11046
|
+
function appendReceiptFact(repoDir, f, now2 = () => new Date) {
|
|
11047
|
+
const id = `rcp-${createHash10("sha256").update(f.runId).digest("hex").slice(0, 12)}`;
|
|
11048
|
+
const lessons = loadLessons(repoDir);
|
|
11049
|
+
if (lessons.some((l) => l.id === id))
|
|
11050
|
+
return false;
|
|
11051
|
+
const cited = f.receiptSha256 !== null;
|
|
11052
|
+
const title = f.title.replace(/\s+/g, " ").trim().slice(0, 200);
|
|
11053
|
+
lessons.push({
|
|
11054
|
+
id,
|
|
11055
|
+
kind: "receipt",
|
|
11056
|
+
text: `Run ${f.runId} sealed ${f.verdict}: ${title}`,
|
|
11057
|
+
source: { pr: `run:${f.runId}`, pr_url: "", comment_url: "", kind: "receipt", author: "loki" },
|
|
11058
|
+
learned_at: now2().toISOString(),
|
|
11059
|
+
uses: [],
|
|
11060
|
+
justified_by: { run_id: f.runId, receipt_sha256: f.receiptSha256, verdict: cited ? f.verdict : "unverified" }
|
|
11061
|
+
});
|
|
11062
|
+
save(repoDir, lessons);
|
|
11063
|
+
return true;
|
|
11064
|
+
}
|
|
11234
11065
|
function recordRunVerdict(repoDir, runId, verdict) {
|
|
11235
11066
|
const lessons = loadLessons(repoDir);
|
|
11236
11067
|
let dirty = false;
|
|
@@ -11243,9 +11074,10 @@ function recordRunVerdict(repoDir, runId, verdict) {
|
|
|
11243
11074
|
if (dirty)
|
|
11244
11075
|
save(repoDir, lessons);
|
|
11245
11076
|
}
|
|
11246
|
-
var lessonsPath = (repoDir) =>
|
|
11077
|
+
var lessonsPath = (repoDir) => join43(repoDir, ".loki", "memory", "semantic", "pr-lessons.json"), KINDS;
|
|
11247
11078
|
var init_pr_lessons = __esm(() => {
|
|
11248
11079
|
init_atomic();
|
|
11080
|
+
KINDS = new Set(["pr", "receipt", "ticket", "rejected"]);
|
|
11249
11081
|
});
|
|
11250
11082
|
|
|
11251
11083
|
// ../../loki-ts/src/runner/model_downgrades.ts
|
|
@@ -11258,19 +11090,19 @@ var init_model_downgrades = __esm(() => {
|
|
|
11258
11090
|
var init_mcp_config = () => {};
|
|
11259
11091
|
|
|
11260
11092
|
// ../../loki-ts/src/providers/claude_flags.ts
|
|
11261
|
-
import { existsSync as existsSync25, readFileSync as
|
|
11262
|
-
import { resolve as resolvePath, dirname as
|
|
11093
|
+
import { existsSync as existsSync25, readFileSync as readFileSync31 } from "fs";
|
|
11094
|
+
import { resolve as resolvePath, dirname as dirname14 } from "path";
|
|
11263
11095
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
11264
11096
|
function designArchetypesText() {
|
|
11265
11097
|
try {
|
|
11266
|
-
const moduleDir =
|
|
11098
|
+
const moduleDir = dirname14(fileURLToPath3(import.meta.url));
|
|
11267
11099
|
for (const rel of [
|
|
11268
11100
|
["..", "..", "..", "references", "design-archetypes.md"],
|
|
11269
11101
|
["..", "..", "references", "design-archetypes.md"]
|
|
11270
11102
|
]) {
|
|
11271
11103
|
const p = resolvePath(moduleDir, ...rel);
|
|
11272
11104
|
if (existsSync25(p))
|
|
11273
|
-
return
|
|
11105
|
+
return readFileSync31(p, "utf8");
|
|
11274
11106
|
}
|
|
11275
11107
|
} catch {}
|
|
11276
11108
|
return "";
|
|
@@ -11348,14 +11180,14 @@ var init_providers = __esm(() => {
|
|
|
11348
11180
|
});
|
|
11349
11181
|
|
|
11350
11182
|
// ../../loki-ts/src/runner/router/route_record.ts
|
|
11351
|
-
import { existsSync as existsSync26, lstatSync as lstatSync9, mkdirSync as mkdirSync15, readFileSync as
|
|
11352
|
-
import { join as
|
|
11183
|
+
import { existsSync as existsSync26, lstatSync as lstatSync9, mkdirSync as mkdirSync15, readFileSync as readFileSync32, writeFileSync as writeFileSync17 } from "fs";
|
|
11184
|
+
import { join as join44 } from "path";
|
|
11353
11185
|
function loadRouteRecord(runDir) {
|
|
11354
11186
|
try {
|
|
11355
|
-
const p =
|
|
11187
|
+
const p = join44(runDir, ROUTE_RECORD_FILE);
|
|
11356
11188
|
if (!existsSync26(p) || !lstatSync9(p).isFile())
|
|
11357
11189
|
return;
|
|
11358
|
-
const v = JSON.parse(
|
|
11190
|
+
const v = JSON.parse(readFileSync32(p, "utf8"));
|
|
11359
11191
|
return typeof v === "object" && v !== null && !Array.isArray(v) ? v : undefined;
|
|
11360
11192
|
} catch {
|
|
11361
11193
|
return;
|
|
@@ -11365,7 +11197,7 @@ var ROUTE_RECORD_FILE = "route.json";
|
|
|
11365
11197
|
var init_route_record = () => {};
|
|
11366
11198
|
|
|
11367
11199
|
// ../../loki-ts/src/runner/router/history_store.ts
|
|
11368
|
-
import { existsSync as existsSync27, mkdirSync as mkdirSync16, readFileSync as
|
|
11200
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync16, readFileSync as readFileSync33, renameSync as renameSync7, rmSync as rmSync11, writeFileSync as writeFileSync18 } from "fs";
|
|
11369
11201
|
import { resolve as resolve13 } from "path";
|
|
11370
11202
|
function validRun(v) {
|
|
11371
11203
|
if (typeof v !== "object" || v === null)
|
|
@@ -11381,7 +11213,7 @@ function readRunHistory(key, cacheRoot) {
|
|
|
11381
11213
|
if (!existsSync27(path))
|
|
11382
11214
|
return [];
|
|
11383
11215
|
try {
|
|
11384
|
-
const parsed = JSON.parse(
|
|
11216
|
+
const parsed = JSON.parse(readFileSync33(path, "utf8"));
|
|
11385
11217
|
const runs2 = parsed?.runs;
|
|
11386
11218
|
return Array.isArray(runs2) ? runs2.filter(validRun) : [];
|
|
11387
11219
|
} catch {
|
|
@@ -11395,8 +11227,8 @@ function appendRunOutcome(key, outcome, cacheRoot) {
|
|
|
11395
11227
|
const target = historyPath(key, cacheRoot);
|
|
11396
11228
|
const tmp = `${target}.${process.pid}.tmp`;
|
|
11397
11229
|
try {
|
|
11398
|
-
|
|
11399
|
-
|
|
11230
|
+
writeFileSync18(tmp, JSON.stringify({ runs: runs2 }));
|
|
11231
|
+
renameSync7(tmp, target);
|
|
11400
11232
|
} catch (e) {
|
|
11401
11233
|
rmSync11(tmp, { force: true, recursive: false });
|
|
11402
11234
|
throw e;
|
|
@@ -11415,7 +11247,7 @@ var init_history_store = __esm(() => {
|
|
|
11415
11247
|
});
|
|
11416
11248
|
|
|
11417
11249
|
// ../../loki-ts/src/runner/router/history.ts
|
|
11418
|
-
import { dirname as
|
|
11250
|
+
import { dirname as dirname15, join as join45, resolve as resolve14 } from "path";
|
|
11419
11251
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
11420
11252
|
function shapeKey(model) {
|
|
11421
11253
|
if (!model || model.status !== "ok")
|
|
@@ -11444,7 +11276,7 @@ var init_history = __esm(() => {
|
|
|
11444
11276
|
init_discover2();
|
|
11445
11277
|
init_gather();
|
|
11446
11278
|
init_history_store();
|
|
11447
|
-
SHAPE_DEFAULTS_FILE = resolve14(
|
|
11279
|
+
SHAPE_DEFAULTS_FILE = resolve14(dirname15(fileURLToPath4(import.meta.url)), "..", "..", "..", "data", "router-shape-defaults.json");
|
|
11448
11280
|
});
|
|
11449
11281
|
|
|
11450
11282
|
// ../../loki-ts/src/runner/router/plan_route.ts
|
|
@@ -11575,7 +11407,7 @@ var init_worker = __esm(() => {
|
|
|
11575
11407
|
});
|
|
11576
11408
|
|
|
11577
11409
|
// ../../loki-ts/src/project_model/package_suite.ts
|
|
11578
|
-
import { join as
|
|
11410
|
+
import { join as join46 } from "path";
|
|
11579
11411
|
async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
|
|
11580
11412
|
const api = loadProjectApi(repoDir);
|
|
11581
11413
|
if (!isMultiRoot(api))
|
|
@@ -11586,7 +11418,7 @@ async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
|
|
|
11586
11418
|
for (const pkg of withTests) {
|
|
11587
11419
|
const tc = pkg.commands.test, name = `full suite: ${pkg.name}`, cmd = `(cd ${tc.cwd} && ${tc.cmd})`;
|
|
11588
11420
|
const started = Date.now();
|
|
11589
|
-
const r = await run(["bash", "-c", tc.cmd], { cwd:
|
|
11421
|
+
const r = await run(["bash", "-c", tc.cmd], { cwd: join46(repoDir, tc.cwd), timeoutMs: opts.timeoutMs, ...opts.path ? { env: { PATH: opts.path } } : {} });
|
|
11590
11422
|
const duration_s = (Date.now() - started) / 1000;
|
|
11591
11423
|
if (signal.aborted) {
|
|
11592
11424
|
checks.push({ name, cmd, result: "not_run", duration_s });
|
|
@@ -11595,7 +11427,7 @@ async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
|
|
|
11595
11427
|
}
|
|
11596
11428
|
const out2 = `${r.stdout}
|
|
11597
11429
|
${r.stderr}`;
|
|
11598
|
-
const lr = r.exitCode === 0 || !opts.baseSha ? undefined : await harnessLoadReason({ repoDir, baseSha: opts.baseSha, out: out2, cmd: "bash", args: ["-c", tc.cmd], signal, cwd:
|
|
11430
|
+
const lr = r.exitCode === 0 || !opts.baseSha ? undefined : await harnessLoadReason({ repoDir, baseSha: opts.baseSha, out: out2, cmd: "bash", args: ["-c", tc.cmd], signal, cwd: join46(repoDir, tc.cwd), ...opts.path ? { env: { PATH: opts.path } } : {} });
|
|
11599
11431
|
if (lr) {
|
|
11600
11432
|
checks.push({ name, cmd, result: "not_run", duration_s });
|
|
11601
11433
|
notProven.add(`${lr} (${name}; harness-owned)`);
|
|
@@ -11628,8 +11460,8 @@ __export(exports_deep, {
|
|
|
11628
11460
|
DEFAULT_SECRET_SCAN_SH: () => DEFAULT_SECRET_SCAN_SH,
|
|
11629
11461
|
DEFAULT_PUSH_SH: () => DEFAULT_PUSH_SH
|
|
11630
11462
|
});
|
|
11631
|
-
import { existsSync as existsSync28, mkdirSync as mkdirSync17, writeFileSync as
|
|
11632
|
-
import { join as
|
|
11463
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync17, writeFileSync as writeFileSync19 } from "fs";
|
|
11464
|
+
import { join as join47 } from "path";
|
|
11633
11465
|
async function runFullSuite(ctx, signal, opts, checks, notProven) {
|
|
11634
11466
|
if (await runPackageSuites(ctx.repoDir, signal, { path: opts.path, timeoutMs: opts.fullSuiteTimeoutMs ?? FULL_SUITE_TIMEOUT_MS, baseSha: ctx.baseSha }, checks, notProven))
|
|
11635
11467
|
return;
|
|
@@ -11726,7 +11558,7 @@ async function runSecretScan(ctx, changed, opts, checks, notProven) {
|
|
|
11726
11558
|
}
|
|
11727
11559
|
const inline = 'script="$1"; shift; . "$script" || exit 3; hit=0; for f in "$@"; do if _commit_scan_secret_file "$f" || _commit_path_looks_secret "$f"; then printf "%s\\n" "$f"; hit=1; fi; done; exit "$hit"';
|
|
11728
11560
|
const started = Date.now();
|
|
11729
|
-
const r = await run(["bash", "-c", inline, "_", scriptPath, ...changed.map((f) =>
|
|
11561
|
+
const r = await run(["bash", "-c", inline, "_", scriptPath, ...changed.map((f) => join47(ctx.repoDir, f))], { cwd: ctx.repoDir, timeoutMs: 30000 });
|
|
11730
11562
|
const durationS = (Date.now() - started) / 1000;
|
|
11731
11563
|
if (r.exitCode === 3) {
|
|
11732
11564
|
checks.push({ name, cmd: "secret-scan.sh", result: "not_run", duration_s: durationS });
|
|
@@ -11767,8 +11599,8 @@ async function postResults(ctx, opts, checks, notProven, statusState) {
|
|
|
11767
11599
|
const prNumber = prUrl ? PR_NUMBER_RE.exec(prUrl)?.[1] : undefined;
|
|
11768
11600
|
if (prNumber) {
|
|
11769
11601
|
mkdirSync17(ctx.runDir, { recursive: true });
|
|
11770
|
-
const bodyFile =
|
|
11771
|
-
|
|
11602
|
+
const bodyFile = join47(ctx.runDir, "deep-comment.md");
|
|
11603
|
+
writeFileSync19(bodyFile, buildCommentBody(checks, notProven, statusState), "utf8");
|
|
11772
11604
|
const commentResult = await run(["bash", scriptPath, ...commentArgv(prNumber, bodyFile)], { cwd: ctx.repoDir, env, timeoutMs: 30000 });
|
|
11773
11605
|
if (commentResult.exitCode !== 0)
|
|
11774
11606
|
out2.push(`deep comment not posted (engine10-push.sh exit ${commentResult.exitCode})`);
|
|
@@ -11821,7 +11653,7 @@ async function runDeep(ctx, signal, opts = {}) {
|
|
|
11821
11653
|
const sig = signReceipt(`${ctx.runId}-deep`, addendumSha256);
|
|
11822
11654
|
const addendum = { ...addendumBody, addendum_sha256: addendumSha256, verification: { jwt: sig.jwt, kid: sig.kid } };
|
|
11823
11655
|
mkdirSync17(ctx.runDir, { recursive: true });
|
|
11824
|
-
|
|
11656
|
+
writeFileSync19(join47(ctx.runDir, "receipt-addendum-1.json"), JSON.stringify(addendum, null, 2) + `
|
|
11825
11657
|
`);
|
|
11826
11658
|
const pushNotProven = await postResults(ctx, opts, checks, notProvenList, statusState);
|
|
11827
11659
|
const allNotProven = [...notProvenList, ...pushNotProven];
|
|
@@ -11866,7 +11698,7 @@ var init_deep = __esm(() => {
|
|
|
11866
11698
|
// ../../loki-ts/src/engine10/stages/verify.ts
|
|
11867
11699
|
import { existsSync as existsSync29, mkdtempSync as mkdtempSync6, realpathSync as realpathSync17, rmSync as rmSync12 } from "fs";
|
|
11868
11700
|
import { tmpdir as tmpdir8 } from "os";
|
|
11869
|
-
import { dirname as
|
|
11701
|
+
import { dirname as dirname16, isAbsolute as isAbsolute6, join as join48, relative as relative5 } from "path";
|
|
11870
11702
|
function resolveTool(repoDir, bin, fallback, lastResort = fallback) {
|
|
11871
11703
|
const inRepo = (p) => {
|
|
11872
11704
|
try {
|
|
@@ -11877,7 +11709,7 @@ function resolveTool(repoDir, bin, fallback, lastResort = fallback) {
|
|
|
11877
11709
|
}
|
|
11878
11710
|
};
|
|
11879
11711
|
const venvEnv = process.env["VIRTUAL_ENV"];
|
|
11880
|
-
const project = [
|
|
11712
|
+
const project = [join48(repoDir, ".venv", "bin", bin), join48(repoDir, "venv", "bin", bin), ...venvEnv && inRepo(venvEnv) ? [join48(venvEnv, "bin", bin)] : []].find(existsSync29);
|
|
11881
11713
|
return project ? [project, "project"] : [Bun.which(fallback) ? fallback : lastResort, "system"];
|
|
11882
11714
|
}
|
|
11883
11715
|
function runnerCmd(t, repoDir) {
|
|
@@ -11897,7 +11729,7 @@ function runnerCmd(t, repoDir) {
|
|
|
11897
11729
|
case "npm":
|
|
11898
11730
|
return ["npm", ["test", "--silent"]];
|
|
11899
11731
|
case "go":
|
|
11900
|
-
return ["go", ["test", "-json", `./${
|
|
11732
|
+
return ["go", ["test", "-json", `./${dirname16(t.path)}`]];
|
|
11901
11733
|
case "cargo":
|
|
11902
11734
|
return ["cargo", ["test"]];
|
|
11903
11735
|
}
|
|
@@ -11995,7 +11827,7 @@ async function subtractBase(ctx, api, checks, tests, changed, wall, rel, signal)
|
|
|
11995
11827
|
const sus = pairs.filter(({ c }) => rel.has(c.name) && c.result === "pass");
|
|
11996
11828
|
if (!(un.some(({ c }) => c.result === "fail" && c.ids?.length) || sus.length) || signal.aborted)
|
|
11997
11829
|
return out2;
|
|
11998
|
-
const dir = mkdtempSync6(
|
|
11830
|
+
const dir = mkdtempSync6(join48(tmpdir8(), "e10-base-"));
|
|
11999
11831
|
const git3 = (args) => {
|
|
12000
11832
|
safeGit(ctx.repoDir, args, { stdio: "ignore", repoDrivers: true });
|
|
12001
11833
|
};
|
|
@@ -12030,7 +11862,7 @@ async function subtractBase(ctx, api, checks, tests, changed, wall, rel, signal)
|
|
|
12030
11862
|
return out2;
|
|
12031
11863
|
}
|
|
12032
11864
|
function isLokiModeRepo(repoDir) {
|
|
12033
|
-
return existsSync29(
|
|
11865
|
+
return existsSync29(join48(repoDir, "scripts", "select-tests.sh"));
|
|
12034
11866
|
}
|
|
12035
11867
|
async function runLintChecks(ctx, changed, signal, checks, opts = {}) {
|
|
12036
11868
|
const { api, ...runOpts } = opts;
|
|
@@ -12047,9 +11879,9 @@ async function runLintChecks(ctx, changed, signal, checks, opts = {}) {
|
|
|
12047
11879
|
}
|
|
12048
11880
|
for (const g of groupByPackage(api, ctx.repoDir, changed.filter((f) => /\.(ts|tsx|js|jsx)$/.test(f)))) {
|
|
12049
11881
|
const sfx = g.root === "." ? "" : `:${g.root}`, co = g.root === "." ? opts : { ...opts, cwd: g.cwd };
|
|
12050
|
-
if (existsSync29(
|
|
11882
|
+
if (existsSync29(join48(g.cwd, "tsconfig.json")))
|
|
12051
11883
|
await runCheck(ctx, `lint:tsc${sfx}`, "npx", ["tsc", "--noEmit", "-p", "."], signal, checks, { ...co, kind: "static" });
|
|
12052
|
-
if (ESLINT_CONFIGS.some((f) => existsSync29(
|
|
11884
|
+
if (ESLINT_CONFIGS.some((f) => existsSync29(join48(g.cwd, f))))
|
|
12053
11885
|
await runCheck(ctx, `lint:eslint${sfx}`, "npx", ["eslint", ...g.rel], signal, checks, { ...co, kind: "static" });
|
|
12054
11886
|
}
|
|
12055
11887
|
}
|
|
@@ -12181,25 +12013,25 @@ var init_verify = __esm(() => {
|
|
|
12181
12013
|
});
|
|
12182
12014
|
|
|
12183
12015
|
// ../../loki-ts/src/project_model/conventions.ts
|
|
12184
|
-
import { existsSync as existsSync30, readdirSync as
|
|
12185
|
-
import { dirname as
|
|
12186
|
-
function parseJsonc(
|
|
12016
|
+
import { existsSync as existsSync30, readdirSync as readdirSync13, readFileSync as readFileSync34 } from "fs";
|
|
12017
|
+
import { dirname as dirname17, join as join49 } from "path";
|
|
12018
|
+
function parseJsonc(text2) {
|
|
12187
12019
|
let out2 = "", i = 0;
|
|
12188
|
-
while (i <
|
|
12189
|
-
const c =
|
|
12020
|
+
while (i < text2.length) {
|
|
12021
|
+
const c = text2[i], n2 = text2[i + 1];
|
|
12190
12022
|
if (c === '"') {
|
|
12191
12023
|
let j = i + 1;
|
|
12192
|
-
while (j <
|
|
12193
|
-
j +=
|
|
12194
|
-
out2 +=
|
|
12024
|
+
while (j < text2.length && text2[j] !== '"')
|
|
12025
|
+
j += text2[j] === "\\" ? 2 : 1;
|
|
12026
|
+
out2 += text2.slice(i, j + 1);
|
|
12195
12027
|
i = j + 1;
|
|
12196
12028
|
} else if (c === "/" && n2 === "/") {
|
|
12197
|
-
while (i <
|
|
12029
|
+
while (i < text2.length && text2[i] !== `
|
|
12198
12030
|
`)
|
|
12199
12031
|
i++;
|
|
12200
12032
|
} else if (c === "/" && n2 === "*") {
|
|
12201
|
-
const e =
|
|
12202
|
-
i = e < 0 ?
|
|
12033
|
+
const e = text2.indexOf("*/", i + 2);
|
|
12034
|
+
i = e < 0 ? text2.length : e + 2;
|
|
12203
12035
|
} else {
|
|
12204
12036
|
out2 += c;
|
|
12205
12037
|
i++;
|
|
@@ -12208,7 +12040,7 @@ function parseJsonc(text3) {
|
|
|
12208
12040
|
return JSON.parse(out2.replace(/,(\s*[}\]])/g, "$1"));
|
|
12209
12041
|
}
|
|
12210
12042
|
function moduleOf(file, depth = 0) {
|
|
12211
|
-
const j =
|
|
12043
|
+
const j = readJson4(file);
|
|
12212
12044
|
if (!j || depth > 4)
|
|
12213
12045
|
return null;
|
|
12214
12046
|
const m = j.compilerOptions?.module;
|
|
@@ -12217,25 +12049,25 @@ function moduleOf(file, depth = 0) {
|
|
|
12217
12049
|
const ext = typeof j.extends === "string" ? j.extends : null;
|
|
12218
12050
|
if (!ext || !ext.startsWith("."))
|
|
12219
12051
|
return null;
|
|
12220
|
-
const next =
|
|
12052
|
+
const next = join49(dirname17(file), ext.endsWith(".json") ? ext : `${ext}.json`);
|
|
12221
12053
|
return existsSync30(next) ? moduleOf(next, depth + 1) : null;
|
|
12222
12054
|
}
|
|
12223
12055
|
function readPackageConventions(pkgDir, runner = null) {
|
|
12224
12056
|
let names = [];
|
|
12225
12057
|
try {
|
|
12226
|
-
names =
|
|
12058
|
+
names = readdirSync13(pkgDir).filter((f) => f.endsWith(".json")).sort((x, y) => x.length - y.length || x.localeCompare(y));
|
|
12227
12059
|
} catch {
|
|
12228
12060
|
return null;
|
|
12229
12061
|
}
|
|
12230
12062
|
let packageType = null, tsModule = null;
|
|
12231
12063
|
for (const n2 of names) {
|
|
12232
|
-
const j =
|
|
12064
|
+
const j = readJson4(join49(pkgDir, n2));
|
|
12233
12065
|
if (!j)
|
|
12234
12066
|
continue;
|
|
12235
12067
|
if (packageType === null && typeof j.type === "string" && typeof j.name === "string")
|
|
12236
12068
|
packageType = j.type;
|
|
12237
12069
|
if (tsModule === null && j.compilerOptions !== undefined)
|
|
12238
|
-
tsModule = moduleOf(
|
|
12070
|
+
tsModule = moduleOf(join49(pkgDir, n2));
|
|
12239
12071
|
}
|
|
12240
12072
|
if (packageType === null && tsModule === null)
|
|
12241
12073
|
return null;
|
|
@@ -12255,9 +12087,9 @@ function conventionViolation(c, fileName, content) {
|
|
|
12255
12087
|
const code = content.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1").replace(/(["'`])(?:\\.|(?!\1)[^\\\n])*\1/g, '""');
|
|
12256
12088
|
return /\bimport\.meta\b/.test(code) ? "import.meta is not allowed in a CommonJS package (TS1470)" : null;
|
|
12257
12089
|
}
|
|
12258
|
-
var
|
|
12090
|
+
var readJson4 = (p) => {
|
|
12259
12091
|
try {
|
|
12260
|
-
const v = parseJsonc(
|
|
12092
|
+
const v = parseJsonc(readFileSync34(p, "utf8"));
|
|
12261
12093
|
return v && typeof v === "object" && !Array.isArray(v) ? v : null;
|
|
12262
12094
|
} catch {
|
|
12263
12095
|
return null;
|
|
@@ -12267,15 +12099,15 @@ var init_conventions = () => {};
|
|
|
12267
12099
|
|
|
12268
12100
|
// ../../loki-ts/src/engine10/stages/wall.ts
|
|
12269
12101
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
12270
|
-
import { existsSync as existsSync31, mkdirSync as mkdirSync18, mkdtempSync as mkdtempSync7, readFileSync as
|
|
12102
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync18, mkdtempSync as mkdtempSync7, readFileSync as readFileSync35, readdirSync as readdirSync14, realpathSync as realpathSync18, rmSync as rmSync13, writeFileSync as writeFileSync20 } from "fs";
|
|
12271
12103
|
import { tmpdir as tmpdir9 } from "os";
|
|
12272
|
-
import { dirname as
|
|
12104
|
+
import { dirname as dirname18, isAbsolute as isAbsolute7, join as join50, relative as relative6 } from "path";
|
|
12273
12105
|
function pytestCollectionIsRed(output, repoDir) {
|
|
12274
12106
|
if (/ModuleNotFoundError/.test(output))
|
|
12275
12107
|
return false;
|
|
12276
12108
|
const real2 = (p) => {
|
|
12277
12109
|
try {
|
|
12278
|
-
return realpathSync18(isAbsolute7(p) ? p :
|
|
12110
|
+
return realpathSync18(isAbsolute7(p) ? p : join50(repoDir, p));
|
|
12279
12111
|
} catch {
|
|
12280
12112
|
return null;
|
|
12281
12113
|
}
|
|
@@ -12312,7 +12144,7 @@ function pytestCollectionIsRed(output, repoDir) {
|
|
|
12312
12144
|
}
|
|
12313
12145
|
function moduleUnderRepo(repoDir, name) {
|
|
12314
12146
|
const rel = name.replace(/\./g, "/");
|
|
12315
|
-
return existsSync31(
|
|
12147
|
+
return existsSync31(join50(repoDir, `${rel}.py`)) || existsSync31(join50(repoDir, rel, "__init__.py"));
|
|
12316
12148
|
}
|
|
12317
12149
|
function pytestExit1IsRed(output) {
|
|
12318
12150
|
if (/^!+ _pytest\.outcomes\.Exit\b/m.test(output))
|
|
@@ -12389,13 +12221,16 @@ ${r.stderr ?? ""}`), repoDir, interpreter);
|
|
|
12389
12221
|
return { pass, fail, not_run };
|
|
12390
12222
|
}
|
|
12391
12223
|
}
|
|
12392
|
-
function buildWallBrief(task, repomapText = "", runners = [], hasManifest = false, conventions = "") {
|
|
12224
|
+
function buildWallBrief(task, repomapText = "", runners = [], hasManifest = false, conventions = "", acceptance = []) {
|
|
12393
12225
|
return withStagePrefix([
|
|
12394
12226
|
"You are the Loki 10 Wall author.",
|
|
12395
12227
|
`You cannot see the repository. This directory holds only task.md and repomap.txt${hasManifest ? " and wall_manifest.txt (signatures, runner config, test layout and test-style examples)" : ""}.`,
|
|
12396
12228
|
...repomapText ? [`Repository paths (repomap.txt):
|
|
12397
12229
|
${repomapText}`] : [],
|
|
12398
12230
|
...taskBlock(task),
|
|
12231
|
+
...acceptance.length ? [`Acceptance criteria frozen for this unit (each must be covered by a test):
|
|
12232
|
+
${acceptance.map((a) => `Acceptance: ${a}`).join(`
|
|
12233
|
+
`)}`] : [],
|
|
12399
12234
|
"Write behavioral acceptance tests that prove the task is done. A test that errors on import, uses another framework's globals, or fails for a reason unrelated to the task is discarded.",
|
|
12400
12235
|
`Test runner: ${runners.map((r) => RUNNER_HINT[r]).find(Boolean) ?? "the framework named in repomap.txt"}`,
|
|
12401
12236
|
...conventions ? [conventions] : [],
|
|
@@ -12407,22 +12242,22 @@ ${repomapText}`] : [],
|
|
|
12407
12242
|
function loadTaskText(ctx, fromPrior) {
|
|
12408
12243
|
if (fromPrior)
|
|
12409
12244
|
return fromPrior;
|
|
12410
|
-
const issueJsonPath = process.env.LOKI_E10_ISSUE_JSON ??
|
|
12245
|
+
const issueJsonPath = process.env.LOKI_E10_ISSUE_JSON ?? join50(ctx.runDir, "issue.json");
|
|
12411
12246
|
if (existsSync31(issueJsonPath)) {
|
|
12412
12247
|
try {
|
|
12413
|
-
const issue = JSON.parse(
|
|
12414
|
-
const
|
|
12248
|
+
const issue = JSON.parse(readFileSync35(issueJsonPath, "utf8"));
|
|
12249
|
+
const text2 = [issue.title, issue.body].filter((s) => typeof s === "string" && s.length > 0).join(`
|
|
12415
12250
|
|
|
12416
12251
|
`);
|
|
12417
|
-
if (
|
|
12418
|
-
return
|
|
12252
|
+
if (text2)
|
|
12253
|
+
return text2;
|
|
12419
12254
|
} catch {}
|
|
12420
12255
|
}
|
|
12421
12256
|
return process.env.LOKI_E10_TASK_TEXT ?? "";
|
|
12422
12257
|
}
|
|
12423
12258
|
function wallTargetDir(repoDir, existingTests) {
|
|
12424
12259
|
const first = existingTests[0];
|
|
12425
|
-
return first ?
|
|
12260
|
+
return first ? join50(repoDir, dirname18(first.path)) : join50(repoDir, "tests");
|
|
12426
12261
|
}
|
|
12427
12262
|
function guessRunner(fileName, runners) {
|
|
12428
12263
|
if (fileName.endsWith(".py"))
|
|
@@ -12453,14 +12288,14 @@ async function wallAuthor(ctx, signal) {
|
|
|
12453
12288
|
const tree = prior.intake?.tree;
|
|
12454
12289
|
const repomapText = repoMapText(ctx.repoDir, tree, repomapRef, WALL_MAP_MAX_LINES);
|
|
12455
12290
|
const targetDir = wallTargetDir(ctx.repoDir, existingTests), pkg = loadProjectApi(ctx.repoDir)?.packageOf(`${relative6(ctx.repoDir, targetDir)}/x`);
|
|
12456
|
-
const conv2 = readPackageConventions(
|
|
12457
|
-
const cwd = mkdtempSync7(
|
|
12291
|
+
const conv2 = readPackageConventions(join50(ctx.repoDir, pkg?.root ?? "."), pkg?.runner ?? null);
|
|
12292
|
+
const cwd = mkdtempSync7(join50(tmpdir9(), "loki-e15-wall-"));
|
|
12458
12293
|
const wm = wallManifestFor(ctx.repoDir, tree, task);
|
|
12459
12294
|
for (const [n2, c] of [["task.md", task], ["repomap.txt", repomapText], ...wm ? [["wall_manifest.txt", wm.text]] : []])
|
|
12460
|
-
|
|
12295
|
+
writeFileSync20(join50(cwd, n2), c, "utf8");
|
|
12461
12296
|
const session = await ctx.sessions.run({
|
|
12462
12297
|
stage: "wall",
|
|
12463
|
-
brief: buildWallBrief(task, repomapText, runners, !!wm, conventionsBrief(conv2)),
|
|
12298
|
+
brief: buildWallBrief(task, repomapText, runners, !!wm, conventionsBrief(conv2), unitSpec()?.acceptance ?? []),
|
|
12464
12299
|
tier: "development",
|
|
12465
12300
|
model: wallModel(),
|
|
12466
12301
|
iterationId: `${ctx.runId}-wall`,
|
|
@@ -12472,15 +12307,15 @@ async function wallAuthor(ctx, signal) {
|
|
|
12472
12307
|
rmSync13(cwd, { recursive: true, force: true });
|
|
12473
12308
|
return done({ status: "failed", data: {}, reason: "wall session aborted, killed, or timed out", killed: true });
|
|
12474
12309
|
}
|
|
12475
|
-
const generated =
|
|
12476
|
-
const sealedDir =
|
|
12310
|
+
const generated = readdirSync14(cwd).filter((f) => f.startsWith(WALL_PREFIX));
|
|
12311
|
+
const sealedDir = join50(ctx.runDir, "wall");
|
|
12477
12312
|
if (generated.length > 0)
|
|
12478
12313
|
mkdirSync18(sealedDir, { recursive: true });
|
|
12479
12314
|
const contents = new Map;
|
|
12480
12315
|
const discarded = [];
|
|
12481
12316
|
for (const name of generated) {
|
|
12482
|
-
const content =
|
|
12483
|
-
|
|
12317
|
+
const content = readFileSync35(join50(cwd, name), "utf8"), bad = conventionViolation(conv2, name, content);
|
|
12318
|
+
writeFileSync20(join50(sealedDir, name), content, "utf8");
|
|
12484
12319
|
if (bad)
|
|
12485
12320
|
discarded.push({ file: name, reason: `${bad}; wall test did not compile under the package config` });
|
|
12486
12321
|
else
|
|
@@ -12500,8 +12335,8 @@ function installWall(ctx, a, baseDir, opts = {}) {
|
|
|
12500
12335
|
const content = contents.get(name);
|
|
12501
12336
|
if (content === undefined)
|
|
12502
12337
|
continue;
|
|
12503
|
-
const dest =
|
|
12504
|
-
|
|
12338
|
+
const dest = join50(targetDir, name), runner = guessRunner(name, runners);
|
|
12339
|
+
writeFileSync20(dest, content, "utf8");
|
|
12505
12340
|
sealedFiles.push({ path: dest, sha256: sha2562(content) });
|
|
12506
12341
|
readOnlyFiles.push({ path: dest, content });
|
|
12507
12342
|
if (runner)
|
|
@@ -12510,7 +12345,7 @@ function installWall(ctx, a, baseDir, opts = {}) {
|
|
|
12510
12345
|
ctx.emit("wall.sealed", "wall", { files: sealedFiles, ...a.manifestSha256 ? { manifest_sha256: a.manifestSha256 } : {} });
|
|
12511
12346
|
const baseRunner = opts.baseRunner ?? new RealBaseTestRunner, baseRun = { pass: 0, fail: 0, not_run: discarded.length }, notRunFiles = [];
|
|
12512
12347
|
for (const t of wallTests) {
|
|
12513
|
-
const r = baseRunner.run(baseDir, [t]), abs =
|
|
12348
|
+
const r = baseRunner.run(baseDir, [t]), abs = join50(ctx.repoDir, t.path);
|
|
12514
12349
|
baseRun.pass += r.pass;
|
|
12515
12350
|
baseRun.fail += r.fail;
|
|
12516
12351
|
baseRun.not_run += r.not_run ?? 0;
|
|
@@ -12543,6 +12378,7 @@ async function runWall(ctx, signal, opts = {}) {
|
|
|
12543
12378
|
var WALL_PREFIX = "loki_wall_", BASE_RUN_TIMEOUT_MS = 60000, WALL_MAP_MAX_LINES = 200, wallStage, stage2;
|
|
12544
12379
|
var init_wall = __esm(() => {
|
|
12545
12380
|
init_types();
|
|
12381
|
+
init_unit_mode();
|
|
12546
12382
|
init_lean_prefix();
|
|
12547
12383
|
init_wall_hints();
|
|
12548
12384
|
init_sizing();
|
|
@@ -12561,15 +12397,15 @@ var init_wall = __esm(() => {
|
|
|
12561
12397
|
});
|
|
12562
12398
|
|
|
12563
12399
|
// ../../loki-ts/src/e10ext/discard.ts
|
|
12564
|
-
import { chmodSync as chmodSync4, closeSync as closeSync8, lstatSync as lstatSync10, mkdirSync as mkdirSync19, openSync as openSync8, readFileSync as
|
|
12565
|
-
import { dirname as
|
|
12400
|
+
import { chmodSync as chmodSync4, closeSync as closeSync8, lstatSync as lstatSync10, mkdirSync as mkdirSync19, openSync as openSync8, readFileSync as readFileSync36, realpathSync as realpathSync19, rmdirSync, unlinkSync as unlinkSync4, writeFileSync as writeFileSync21 } from "fs";
|
|
12401
|
+
import { dirname as dirname19, join as join51, relative as relative7, sep as sep11 } from "path";
|
|
12566
12402
|
function safeRestore(repoDir, f, want, mode) {
|
|
12567
|
-
const root = realpathSync19(repoDir), fp =
|
|
12403
|
+
const root = realpathSync19(repoDir), fp = join51(root, f), rel = relative7(root, dirname19(fp));
|
|
12568
12404
|
if (rel.startsWith(".."))
|
|
12569
12405
|
throw new Error("outside repo");
|
|
12570
12406
|
let cur = root;
|
|
12571
12407
|
for (const part of rel === "" ? [] : rel.split(sep11)) {
|
|
12572
|
-
cur =
|
|
12408
|
+
cur = join51(cur, part);
|
|
12573
12409
|
let st2;
|
|
12574
12410
|
try {
|
|
12575
12411
|
st2 = lstatSync10(cur);
|
|
@@ -12586,7 +12422,7 @@ function safeRestore(repoDir, f, want, mode) {
|
|
|
12586
12422
|
} catch {
|
|
12587
12423
|
st = null;
|
|
12588
12424
|
}
|
|
12589
|
-
if (st?.isFile() &&
|
|
12425
|
+
if (st?.isFile() && readFileSync36(fp).equals(want)) {
|
|
12590
12426
|
chmodSync4(fp, mode);
|
|
12591
12427
|
return;
|
|
12592
12428
|
}
|
|
@@ -12598,7 +12434,7 @@ function safeRestore(repoDir, f, want, mode) {
|
|
|
12598
12434
|
}
|
|
12599
12435
|
const fd = openSync8(fp, "wx", mode);
|
|
12600
12436
|
try {
|
|
12601
|
-
|
|
12437
|
+
writeFileSync21(fd, want);
|
|
12602
12438
|
} finally {
|
|
12603
12439
|
closeSync8(fd);
|
|
12604
12440
|
}
|
|
@@ -12608,10 +12444,10 @@ function alreadySatisfied(o) {
|
|
|
12608
12444
|
const b = o.wall?.base_run ?? {};
|
|
12609
12445
|
return o.intake?.already_satisfied === true || o.implement?.exit === "already_done" || typeof b.pass === "number" && b.pass > 0 && b.fail === 0 && (b.not_run ?? 0) === 0;
|
|
12610
12446
|
}
|
|
12611
|
-
function catBlob(repoDir,
|
|
12612
|
-
const r = safeGitSpawn(repoDir, ["cat-file", "blob",
|
|
12447
|
+
function catBlob(repoDir, sha2) {
|
|
12448
|
+
const r = safeGitSpawn(repoDir, ["cat-file", "blob", sha2], { maxBuffer: 1 << 28 });
|
|
12613
12449
|
if (r.error || r.status !== 0)
|
|
12614
|
-
throw r.error ?? new Error(`git cat-file blob ${
|
|
12450
|
+
throw r.error ?? new Error(`git cat-file blob ${sha2} failed`);
|
|
12615
12451
|
return r.stdout;
|
|
12616
12452
|
}
|
|
12617
12453
|
async function discardIfSatisfied(git3, base, o, staged, keep, repoDir) {
|
|
@@ -12624,7 +12460,7 @@ async function discardIfSatisfied(git3, base, o, staged, keep, repoDir) {
|
|
|
12624
12460
|
return { status: "failed", data: {}, reason: "already-satisfied discard failed" };
|
|
12625
12461
|
const notProven = [];
|
|
12626
12462
|
for (const [f, v] of Object.entries(o.intake?.preexisting_untracked_blobs ?? {})) {
|
|
12627
|
-
const fp =
|
|
12463
|
+
const fp = join51(repoDir, f);
|
|
12628
12464
|
try {
|
|
12629
12465
|
if (v.startsWith("!")) {
|
|
12630
12466
|
const st = lstatSync10(fp);
|
|
@@ -12632,7 +12468,7 @@ async function discardIfSatisfied(git3, base, o, staged, keep, repoDir) {
|
|
|
12632
12468
|
throw new Error("changed, not snapshotted");
|
|
12633
12469
|
continue;
|
|
12634
12470
|
}
|
|
12635
|
-
const [
|
|
12471
|
+
const [sha2, mode] = v.split(" "), want = catBlob(repoDir, sha2);
|
|
12636
12472
|
safeRestore(repoDir, f, want, parseInt(mode ?? "644", 8));
|
|
12637
12473
|
} catch {
|
|
12638
12474
|
notProven.push(f);
|
|
@@ -12643,7 +12479,7 @@ async function discardIfSatisfied(git3, base, o, staged, keep, repoDir) {
|
|
|
12643
12479
|
try {
|
|
12644
12480
|
let m = 420;
|
|
12645
12481
|
try {
|
|
12646
|
-
const l = lstatSync10(
|
|
12482
|
+
const l = lstatSync10(join51(repoDir, f));
|
|
12647
12483
|
if (l.isFile())
|
|
12648
12484
|
m = l.mode & 511;
|
|
12649
12485
|
} catch {}
|
|
@@ -12676,9 +12512,9 @@ var init_preexisting_dirty = __esm(() => {
|
|
|
12676
12512
|
});
|
|
12677
12513
|
|
|
12678
12514
|
// ../../loki-ts/src/e10ext/commit_filter.ts
|
|
12679
|
-
import { dirname as
|
|
12515
|
+
import { dirname as dirname20 } from "path";
|
|
12680
12516
|
function dropSet(repoDir, staged, preexistingDirty, env = process.env) {
|
|
12681
|
-
return staged.concat(untouchedSinceIntake(repoDir, preexistingDirty, env).map((f) => ({ st: "L", f }))).filter(({ st, f }) => f.startsWith(".loki/") || st === "L" || /(^|\/)loki_wall_[^/]*$/.test(f) || st === "A" && !staged.some(({ f: m }) => /(^|\/)(package\.json|pyproject\.toml|requirements\.txt|Cargo\.toml|go\.mod)$/.test(m) &&
|
|
12517
|
+
return staged.concat(untouchedSinceIntake(repoDir, preexistingDirty, env).map((f) => ({ st: "L", f }))).filter(({ st, f }) => f.startsWith(".loki/") || st === "L" || /(^|\/)loki_wall_[^/]*$/.test(f) || st === "A" && !staged.some(({ f: m }) => /(^|\/)(package\.json|pyproject\.toml|requirements\.txt|Cargo\.toml|go\.mod)$/.test(m) && dirname20(m) === dirname20(f)) && /(^|\/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|bun\.lockb?|poetry\.lock|Cargo\.lock|go\.sum)$/.test(f));
|
|
12682
12518
|
}
|
|
12683
12519
|
var parseStaged = (out2) => out2.split("\x00").reduce((a, t, i, all) => i % 2 === 0 && t ? [...a, { st: t, f: all[i + 1] }] : a, []);
|
|
12684
12520
|
var init_commit_filter = __esm(() => {
|
|
@@ -12687,7 +12523,7 @@ var init_commit_filter = __esm(() => {
|
|
|
12687
12523
|
});
|
|
12688
12524
|
|
|
12689
12525
|
// ../../loki-ts/src/e10ext/scope.ts
|
|
12690
|
-
import { basename as basename18, dirname as
|
|
12526
|
+
import { basename as basename18, dirname as dirname21 } from "path";
|
|
12691
12527
|
function contractText(o) {
|
|
12692
12528
|
const c = o.intake?.contract_snapshot?.contract;
|
|
12693
12529
|
return Array.isArray(c?.criteria) ? c.criteria.map((x) => typeof x?.text === "string" ? x.text : "").join(`
|
|
@@ -12698,18 +12534,18 @@ function outsideScope(o, staged) {
|
|
|
12698
12534
|
const plan = typeof o.plan?.plan === "string" ? o.plan.plan : "";
|
|
12699
12535
|
if (rel.length === 0 && plan.trim() === "")
|
|
12700
12536
|
return null;
|
|
12701
|
-
const
|
|
12537
|
+
const text2 = `${plan}
|
|
12702
12538
|
${typeof o.intake?.task === "string" ? o.intake.task : ""}
|
|
12703
12539
|
${contractText(o)}`, pre = o.intake?.preexisting_dirty ?? {};
|
|
12704
|
-
const toks = surfaceTokens(
|
|
12705
|
-
return staged.filter(({ st, f }) => st !== "A" && !isTestFile(f) && !Object.hasOwn(pre, f) && !rel.includes(f) && !mentions(
|
|
12540
|
+
const toks = surfaceTokens(text2), plannedDirs = new Set(rel.map((r) => dirname21(r)).filter((d) => d !== "."));
|
|
12541
|
+
return staged.filter(({ st, f }) => st !== "A" && !isTestFile(f) && !Object.hasOwn(pre, f) && !rel.includes(f) && !mentions(text2, f) && !mentions(text2, basename18(f)) && !plannedDirs.has(dirname21(f)) && !dirSegs(f).some((d) => toks.has(d))).map(({ f }) => f);
|
|
12706
12542
|
}
|
|
12707
12543
|
function flagOutsideScope(o, staged) {
|
|
12708
12544
|
const unit = unitFlags(staged, process.env, o.intake?.preexisting_dirty ?? {});
|
|
12709
12545
|
const un = outsideScope(o, staged), seen = new Set((unit ?? []).map(outsideNote));
|
|
12710
12546
|
return [...(unit ?? []).map(outsideNote), ...un ? un.map(outsideNote).filter((n2) => !seen.has(n2)) : staged.length > 0 ? [SCOPE_UNDETERMINED] : []];
|
|
12711
12547
|
}
|
|
12712
|
-
var SCOPE_UNDETERMINED = "scope not determined; all edits committed", outsideNote = (f) => `outside stated scope: ${f}`, esc2 = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), mentions = (
|
|
12548
|
+
var SCOPE_UNDETERMINED = "scope not determined; all edits committed", outsideNote = (f) => `outside stated scope: ${f}`, esc2 = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), mentions = (text2, name) => new RegExp(`(?<![\\w./-])${esc2(name)}(?![\\w-]|\\.\\w)`).test(text2), STOP, stem = (w) => w.length > 3 && w.endsWith("s") ? w.slice(0, -1) : w, surfaceTokens = (text2) => new Set((text2.toLowerCase().match(/[a-z][a-z0-9_-]{2,}/g) ?? []).filter((w) => !STOP.has(w)).map(stem)), dirSegs = (f) => f.split("/").slice(0, -1).map((d) => stem(d.toLowerCase()));
|
|
12713
12549
|
var init_scope2 = __esm(() => {
|
|
12714
12550
|
init_testmap();
|
|
12715
12551
|
init_unit_mode();
|
|
@@ -12718,9 +12554,9 @@ var init_scope2 = __esm(() => {
|
|
|
12718
12554
|
|
|
12719
12555
|
// ../../loki-ts/src/util/receipt_signer.ts
|
|
12720
12556
|
import { createHash as createHash11, randomBytes as randomBytes3, createPrivateKey, createPublicKey as createPublicKey2, generateKeyPairSync, sign } from "crypto";
|
|
12721
|
-
import { chmodSync as chmodSync5, linkSync, mkdirSync as mkdirSync20, readFileSync as
|
|
12557
|
+
import { chmodSync as chmodSync5, linkSync, mkdirSync as mkdirSync20, readFileSync as readFileSync37, statSync as statSync16, unlinkSync as unlinkSync5, writeFileSync as writeFileSync22 } from "fs";
|
|
12722
12558
|
import { homedir as homedir8 } from "os";
|
|
12723
|
-
import { dirname as
|
|
12559
|
+
import { dirname as dirname22, join as join52 } from "path";
|
|
12724
12560
|
function canonicalJson(x) {
|
|
12725
12561
|
const walk = (v) => {
|
|
12726
12562
|
if (Array.isArray(v))
|
|
@@ -12739,21 +12575,21 @@ function loadSigningKey(generate = true) {
|
|
|
12739
12575
|
let pem = inline ?? "";
|
|
12740
12576
|
if (!inline) {
|
|
12741
12577
|
const given = process.env["LOKI_RECEIPT_SIGNING_KEY_FILE"]?.trim();
|
|
12742
|
-
const file = given ||
|
|
12578
|
+
const file = given || join52(process.env["HOME"] || homedir8(), ".loki", "keys", RECEIPT_SIGNER_BASENAME);
|
|
12743
12579
|
try {
|
|
12744
|
-
pem =
|
|
12580
|
+
pem = readFileSync37(file);
|
|
12745
12581
|
if (!given) {
|
|
12746
|
-
for (const [f, m] of [[file, 384], [
|
|
12747
|
-
if (
|
|
12582
|
+
for (const [f, m] of [[file, 384], [dirname22(file), 448]])
|
|
12583
|
+
if (statSync16(f).mode & 63)
|
|
12748
12584
|
chmodSync5(f, m);
|
|
12749
12585
|
}
|
|
12750
12586
|
} catch (e) {
|
|
12751
12587
|
if (e.code !== "ENOENT" || !generate)
|
|
12752
12588
|
return null;
|
|
12753
|
-
mkdirSync20(
|
|
12754
|
-
mkdirSync20(
|
|
12589
|
+
mkdirSync20(dirname22(dirname22(file)), { recursive: true, mode: 448 });
|
|
12590
|
+
mkdirSync20(dirname22(file), { recursive: true, mode: 448 });
|
|
12755
12591
|
const tmp = `${file}.${randomBytes3(6).toString("hex")}.tmp`;
|
|
12756
|
-
|
|
12592
|
+
writeFileSync22(tmp, generateKeyPairSync("ed25519").privateKey.export({ type: "pkcs8", format: "pem" }), { flag: "wx", mode: 384 });
|
|
12757
12593
|
try {
|
|
12758
12594
|
linkSync(tmp, file);
|
|
12759
12595
|
} catch (l) {
|
|
@@ -12762,7 +12598,7 @@ function loadSigningKey(generate = true) {
|
|
|
12762
12598
|
} finally {
|
|
12763
12599
|
unlinkSync5(tmp);
|
|
12764
12600
|
}
|
|
12765
|
-
pem =
|
|
12601
|
+
pem = readFileSync37(file);
|
|
12766
12602
|
}
|
|
12767
12603
|
}
|
|
12768
12604
|
const k = createPrivateKey(pem);
|
|
@@ -12785,9 +12621,9 @@ var init_receipt_signer = () => {};
|
|
|
12785
12621
|
// ../../loki-ts/src/features/visual_evidence.ts
|
|
12786
12622
|
import { spawn as spawn7 } from "child_process";
|
|
12787
12623
|
import { createHash as createHash12, randomBytes as randomBytes4 } from "crypto";
|
|
12788
|
-
import { existsSync as existsSync32, lstatSync as lstatSync11, mkdirSync as mkdirSync21, readdirSync as
|
|
12624
|
+
import { existsSync as existsSync32, lstatSync as lstatSync11, mkdirSync as mkdirSync21, readdirSync as readdirSync15, readFileSync as readFileSync38, writeFileSync as writeFileSync23 } from "fs";
|
|
12789
12625
|
import { createServer } from "net";
|
|
12790
|
-
import { dirname as
|
|
12626
|
+
import { dirname as dirname23, isAbsolute as isAbsolute8, join as join53, normalize as normalize2, relative as relative8, sep as sep12 } from "path";
|
|
12791
12627
|
function routeFor(file) {
|
|
12792
12628
|
let r = file.replace(/^(?:.*?\/)?(?:app|pages|src|public)\//, "").replace(/^(?:routes|pages)\//, "");
|
|
12793
12629
|
r = r.replace(/\.(?:html|jsx|tsx|vue|svelte)$/, "").replace(/\/?(?:page|index|\+page)$/, "");
|
|
@@ -12797,7 +12633,7 @@ function hashScreens(runDir, rels) {
|
|
|
12797
12633
|
const out2 = [];
|
|
12798
12634
|
for (const rel of rels) {
|
|
12799
12635
|
try {
|
|
12800
|
-
out2.push({ path: rel, sha256: sha256File(
|
|
12636
|
+
out2.push({ path: rel, sha256: sha256File(join53(runDir, rel)) });
|
|
12801
12637
|
} catch {}
|
|
12802
12638
|
}
|
|
12803
12639
|
return out2;
|
|
@@ -12810,10 +12646,10 @@ function checkScreens(runDir, screens) {
|
|
|
12810
12646
|
return "evidence_screens entry is malformed";
|
|
12811
12647
|
if (isAbsolute8(s.path) || normalize2(s.path).startsWith(".."))
|
|
12812
12648
|
return `evidence screenshot path escapes the evidence dir: ${s.path}`;
|
|
12813
|
-
const file =
|
|
12649
|
+
const file = join53(runDir, s.path);
|
|
12814
12650
|
let cur = runDir;
|
|
12815
12651
|
for (const seg of normalize2(s.path).split(sep12)) {
|
|
12816
|
-
cur =
|
|
12652
|
+
cur = join53(cur, seg);
|
|
12817
12653
|
if (isSymlink(cur))
|
|
12818
12654
|
return `evidence screenshot path is a symlink: ${s.path}`;
|
|
12819
12655
|
}
|
|
@@ -12860,11 +12696,11 @@ async function waitUp(url, ms, signal) {
|
|
|
12860
12696
|
}
|
|
12861
12697
|
function openapiPaths(repoDir) {
|
|
12862
12698
|
for (const f of ["openapi.json", "openapi.yaml", "openapi.yml", "swagger.json"]) {
|
|
12863
|
-
const p =
|
|
12699
|
+
const p = join53(repoDir, f);
|
|
12864
12700
|
if (!existsSync32(p))
|
|
12865
12701
|
continue;
|
|
12866
12702
|
try {
|
|
12867
|
-
const txt =
|
|
12703
|
+
const txt = readFileSync38(p, "utf8");
|
|
12868
12704
|
const paths = f.endsWith(".json") ? Object.keys(JSON.parse(txt).paths ?? {}) : [...txt.matchAll(/^ {2}(\/[^\s:]*):\s*$/gm)].map((m) => m[1]);
|
|
12869
12705
|
return paths.filter((x) => !x.includes("{")).slice(0, 10);
|
|
12870
12706
|
} catch {
|
|
@@ -12878,24 +12714,24 @@ async function recordE2eMedia(repoDir, runDir, relDir, base, routes, ms, signal)
|
|
|
12878
12714
|
if (!pw || !pkg)
|
|
12879
12715
|
return { rels: [], skipped: "playwright e2e video and trace skipped: @playwright/test is not installed in the repo" };
|
|
12880
12716
|
try {
|
|
12881
|
-
const dir =
|
|
12717
|
+
const dir = join53(runDir, relDir, "e2e");
|
|
12882
12718
|
mkdirSync21(dir, { recursive: true });
|
|
12883
|
-
|
|
12884
|
-
|
|
12719
|
+
writeFileSync23(join53(dir, "walk.spec.cjs"), e2eSpecSource(pkg, base, routes));
|
|
12720
|
+
writeFileSync23(join53(dir, "playwright.config.cjs"), `module.exports = { testDir: ".", testMatch: "walk.spec.cjs", outputDir: "./out", reporter: "null", use: { video: "on", trace: "on" } };
|
|
12885
12721
|
`);
|
|
12886
|
-
if (!await shoot(pw, ["test", "--config",
|
|
12722
|
+
if (!await shoot(pw, ["test", "--config", join53(dir, "playwright.config.cjs")], repoDir, ms, signal))
|
|
12887
12723
|
return { rels: [], skipped: "playwright e2e video and trace skipped: the run failed or timed out" };
|
|
12888
12724
|
const rels = [];
|
|
12889
12725
|
const walk = (d) => {
|
|
12890
|
-
for (const e of
|
|
12891
|
-
const full =
|
|
12726
|
+
for (const e of readdirSync15(d, { withFileTypes: true })) {
|
|
12727
|
+
const full = join53(d, e.name);
|
|
12892
12728
|
if (e.isDirectory())
|
|
12893
12729
|
walk(full);
|
|
12894
12730
|
else if (e.isFile() && /\.(webm|zip)$/.test(e.name))
|
|
12895
|
-
rels.push(
|
|
12731
|
+
rels.push(join53(relDir, "e2e", relative8(dir, full)));
|
|
12896
12732
|
}
|
|
12897
12733
|
};
|
|
12898
|
-
walk(
|
|
12734
|
+
walk(join53(dir, "out"));
|
|
12899
12735
|
return rels.length > 0 ? { rels, skipped: null } : { rels, skipped: "playwright e2e video and trace skipped: no video or trace was produced" };
|
|
12900
12736
|
} catch (e) {
|
|
12901
12737
|
return { rels: [], skipped: `playwright e2e video and trace skipped: ${String(e?.message ?? e).slice(0, 120)}` };
|
|
@@ -12964,13 +12800,13 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
12964
12800
|
if (!visualEvidenceEnabled(opts.env))
|
|
12965
12801
|
return skip("LOKI_VISUAL_EVIDENCE is 0");
|
|
12966
12802
|
const api = loadProjectApi(repoDir), boot = isMultiRoot(api) ? api.uiBoot() : null;
|
|
12967
|
-
const appDir = boot ?
|
|
12968
|
-
const pkgPath =
|
|
12803
|
+
const appDir = boot ? join53(repoDir, boot.boot.cwd) : repoDir;
|
|
12804
|
+
const pkgPath = join53(appDir, "package.json");
|
|
12969
12805
|
let script = null;
|
|
12970
12806
|
if (!boot) {
|
|
12971
12807
|
if (!existsSync32(pkgPath))
|
|
12972
12808
|
return skip("no package.json");
|
|
12973
|
-
script = pickScript(JSON.parse(
|
|
12809
|
+
script = pickScript(JSON.parse(readFileSync38(pkgPath, "utf8")));
|
|
12974
12810
|
if (!script)
|
|
12975
12811
|
return skip("no dev, preview or start script");
|
|
12976
12812
|
}
|
|
@@ -12997,20 +12833,20 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
12997
12833
|
}
|
|
12998
12834
|
if (!await waitUp(base, left(), signal))
|
|
12999
12835
|
return skip(aborted() ? "aborted" : `${script} server did not answer within ${Math.round(budget / 1000)}s`);
|
|
13000
|
-
const evRoot =
|
|
12836
|
+
const evRoot = join53(runDir, "evidence");
|
|
13001
12837
|
if (isSymlink(evRoot))
|
|
13002
12838
|
return skip("evidence dir is a symlink");
|
|
13003
12839
|
mkdirSync21(evRoot, { recursive: true });
|
|
13004
12840
|
if (pages.length > 0) {
|
|
13005
|
-
const rel0 =
|
|
13006
|
-
mkdirSync21(
|
|
12841
|
+
const rel0 = join53("evidence", randomBytes4(6).toString("hex"));
|
|
12842
|
+
mkdirSync21(join53(runDir, rel0));
|
|
13007
12843
|
const rels = [];
|
|
13008
12844
|
for (const route of [...new Set(pages.map(routeFor))].slice(0, opts.maxRoutes ?? MAX_ROUTES)) {
|
|
13009
12845
|
if (aborted() || left() <= 0)
|
|
13010
12846
|
break;
|
|
13011
|
-
const rel =
|
|
13012
|
-
const ok = await shoot(pw, ["screenshot", `${base}${route}`,
|
|
13013
|
-
if (ok && !aborted() && !isSymlink(
|
|
12847
|
+
const rel = join53(rel0, `${screenName(route)}.png`);
|
|
12848
|
+
const ok = await shoot(pw, ["screenshot", `${base}${route}`, join53(runDir, rel)], appDir, left(), signal);
|
|
12849
|
+
if (ok && !aborted() && !isSymlink(join53(runDir, rel)) && existsSync32(join53(runDir, rel)))
|
|
13014
12850
|
rels.push(rel);
|
|
13015
12851
|
}
|
|
13016
12852
|
if (aborted())
|
|
@@ -13035,9 +12871,9 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
|
|
|
13035
12871
|
}
|
|
13036
12872
|
if (aborted())
|
|
13037
12873
|
return skip("aborted");
|
|
13038
|
-
const hdir =
|
|
12874
|
+
const hdir = join53(evRoot, randomBytes4(6).toString("hex"));
|
|
13039
12875
|
mkdirSync21(hdir);
|
|
13040
|
-
|
|
12876
|
+
writeFileSync23(join53(hdir, "http.json"), JSON.stringify(rows, null, 2) + `
|
|
13041
12877
|
`);
|
|
13042
12878
|
return { screens: [], http: true, skipped: null };
|
|
13043
12879
|
} catch (e) {
|
|
@@ -13060,14 +12896,14 @@ async function sealEvidence(repoDir, runDir, o, notProven, signal, emit) {
|
|
|
13060
12896
|
return ev.screens.length > 0 ? { evidence_screens: ev.screens } : {};
|
|
13061
12897
|
}
|
|
13062
12898
|
function receiptScreensProblem(receiptPath, receipt) {
|
|
13063
|
-
return receipt["evidence_screens"] === undefined ? null : checkScreens(
|
|
12899
|
+
return receipt["evidence_screens"] === undefined ? null : checkScreens(dirname23(receiptPath), receipt["evidence_screens"]);
|
|
13064
12900
|
}
|
|
13065
|
-
var visualEvidenceEnabled = (env = process.env) => env["LOKI_VISUAL_EVIDENCE"] !== "0", PAGE_RE, isPageFile = (p) => PAGE_RE.test(p), screenName = (route) => (route === "/" ? "index" : route.slice(1).replace(/[^A-Za-z0-9._-]+/g, "_")) || "index", sha256File = (p) => createHash12("sha256").update(
|
|
13066
|
-
const bin =
|
|
12901
|
+
var visualEvidenceEnabled = (env = process.env) => env["LOKI_VISUAL_EVIDENCE"] !== "0", PAGE_RE, isPageFile = (p) => PAGE_RE.test(p), screenName = (route) => (route === "/" ? "index" : route.slice(1).replace(/[^A-Za-z0-9._-]+/g, "_")) || "index", sha256File = (p) => createHash12("sha256").update(readFileSync38(p)).digest("hex"), playwrightBin = (repoDir) => {
|
|
12902
|
+
const bin = join53(repoDir, "node_modules", ".bin", "playwright");
|
|
13067
12903
|
return existsSync32(bin) ? bin : null;
|
|
13068
12904
|
}, playwrightTestPkg = (repoDir) => {
|
|
13069
|
-
const d =
|
|
13070
|
-
return existsSync32(
|
|
12905
|
+
const d = join53(repoDir, "node_modules", "@playwright", "test");
|
|
12906
|
+
return existsSync32(join53(d, "package.json")) ? d : null;
|
|
13071
12907
|
}, e2eSpecSource = (pkgDir, base, routes) => `const { test } = require(${JSON.stringify(pkgDir)});
|
|
13072
12908
|
test("loki e2e walkthrough", async ({ page }) => {
|
|
13073
12909
|
for (const r of ${JSON.stringify(routes)}) { await page.goto(${JSON.stringify(base)} + r); await page.waitForLoadState("load"); }
|
|
@@ -13098,14 +12934,14 @@ var init_visual_evidence = __esm(() => {
|
|
|
13098
12934
|
});
|
|
13099
12935
|
|
|
13100
12936
|
// ../../loki-ts/src/council/role_agents.ts
|
|
13101
|
-
import { existsSync as existsSync33, readdirSync as
|
|
12937
|
+
import { existsSync as existsSync33, readdirSync as readdirSync16, readFileSync as readFileSync39 } from "fs";
|
|
13102
12938
|
import { homedir as homedir9 } from "os";
|
|
13103
|
-
import { join as
|
|
12939
|
+
import { join as join54 } from "path";
|
|
13104
12940
|
function agentDirs(repoDir, env = process.env) {
|
|
13105
|
-
return [env["LOKI_AGENTS_PROJECT_DIR"] ||
|
|
12941
|
+
return [env["LOKI_AGENTS_PROJECT_DIR"] || join54(repoDir, ".loki", "agents"), env["LOKI_AGENTS_USER_DIR"] || join54(env["XDG_CONFIG_HOME"] || join54(homedir9(), ".config"), "loki", "agents")];
|
|
13106
12942
|
}
|
|
13107
12943
|
function parseAgent(file, stem2) {
|
|
13108
|
-
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(
|
|
12944
|
+
const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(readFileSync39(file, "utf8"));
|
|
13109
12945
|
if (!m)
|
|
13110
12946
|
return null;
|
|
13111
12947
|
const body = m[2].trim();
|
|
@@ -13123,14 +12959,14 @@ function loadRoleAgent(repoDir, role, env = process.env) {
|
|
|
13123
12959
|
continue;
|
|
13124
12960
|
let names;
|
|
13125
12961
|
try {
|
|
13126
|
-
names =
|
|
12962
|
+
names = readdirSync16(d).filter((n2) => n2.endsWith(".md") && !n2.startsWith(".")).sort();
|
|
13127
12963
|
} catch {
|
|
13128
12964
|
continue;
|
|
13129
12965
|
}
|
|
13130
12966
|
const ordered = [...names.filter((n2) => n2 === `${role}.md`), ...names.filter((n2) => n2 !== `${role}.md`)];
|
|
13131
12967
|
for (const n2 of ordered) {
|
|
13132
12968
|
try {
|
|
13133
|
-
const a = parseAgent(
|
|
12969
|
+
const a = parseAgent(join54(d, n2), n2.slice(0, -3));
|
|
13134
12970
|
if (a && a.role === role)
|
|
13135
12971
|
return a;
|
|
13136
12972
|
} catch {}
|
|
@@ -13147,8 +12983,8 @@ var init_role_agents = __esm(() => {
|
|
|
13147
12983
|
});
|
|
13148
12984
|
|
|
13149
12985
|
// ../../loki-ts/src/engine10/stages/xreview.ts
|
|
13150
|
-
import { existsSync as existsSync34, readFileSync as
|
|
13151
|
-
import { join as
|
|
12986
|
+
import { existsSync as existsSync34, readFileSync as readFileSync40 } from "fs";
|
|
12987
|
+
import { join as join55 } from "path";
|
|
13152
12988
|
function minVerdict(verdict, review) {
|
|
13153
12989
|
const ceiling = review?.level === "block" ? "PARTIAL" : verdict;
|
|
13154
12990
|
return RANK3[ceiling] < RANK3[verdict] ? ceiling : verdict;
|
|
@@ -13161,11 +12997,11 @@ function explicitReview(repoDir, env) {
|
|
|
13161
12997
|
if (flag && isOff(ev))
|
|
13162
12998
|
return "off";
|
|
13163
12999
|
for (const f of ["loki.yaml", "loki.yml"]) {
|
|
13164
|
-
const p =
|
|
13000
|
+
const p = join55(repoDir, f);
|
|
13165
13001
|
if (!existsSync34(p))
|
|
13166
13002
|
continue;
|
|
13167
13003
|
try {
|
|
13168
|
-
const m = /^review:[ \t]*["']?([A-Za-z]+)["']?[ \t]*(?:#.*)?$/m.exec(
|
|
13004
|
+
const m = /^review:[ \t]*["']?([A-Za-z]+)["']?[ \t]*(?:#.*)?$/m.exec(readFileSync40(p, "utf8"));
|
|
13169
13005
|
const v = asProvider(m?.[1]);
|
|
13170
13006
|
if (v)
|
|
13171
13007
|
return v;
|
|
@@ -13254,6 +13090,88 @@ var init_xreview = __esm(() => {
|
|
|
13254
13090
|
RANK3 = { FAILED: 0, SPEC_CONFLICT: 0, PARTIAL: 1, ALREADY_SATISFIED: 2, VERIFIED: 2 };
|
|
13255
13091
|
});
|
|
13256
13092
|
|
|
13093
|
+
// ../../loki-ts/src/runner/router/route_block.ts
|
|
13094
|
+
function advisorUnavailableReason(env, provider) {
|
|
13095
|
+
if (provider !== "claude")
|
|
13096
|
+
return `provider ${provider} has no advisor tool`;
|
|
13097
|
+
if (env["CLAUDE_CODE_USE_BEDROCK"] || env["CLAUDE_CODE_USE_VERTEX"] || env["CLAUDE_CODE_USE_FOUNDRY"])
|
|
13098
|
+
return "advisor tool is unsupported on Bedrock, Vertex and Foundry";
|
|
13099
|
+
if ((env["LOKI_ROUTER_ADVISOR"] ?? "").trim().toLowerCase() === "off")
|
|
13100
|
+
return "LOKI_ROUTER_ADVISOR=off";
|
|
13101
|
+
return null;
|
|
13102
|
+
}
|
|
13103
|
+
function toEsc(raw2) {
|
|
13104
|
+
const esc3 = Array.isArray(raw2) ? raw2 : [];
|
|
13105
|
+
return esc3.map((e) => ({ trigger: s0(e["trigger"]) ?? "unknown", from: modelLabel(s0(e["from"]) ?? "?"), to: modelLabel(s0(e["to"]) ?? "?"), evidence: s0(e["evidence"]) ?? "none recorded" }));
|
|
13106
|
+
}
|
|
13107
|
+
function buildRouteBlock(env, provider, route, telemetry, runModel) {
|
|
13108
|
+
if (!routerEnabled(env))
|
|
13109
|
+
return null;
|
|
13110
|
+
const applied = route?.["applied"] !== false;
|
|
13111
|
+
const executor = s0(route?.["executor"]);
|
|
13112
|
+
const unavailable = s0(route?.["advisor_unavailable_reason"]) ?? advisorUnavailableReason(env, provider);
|
|
13113
|
+
const total = nN(telemetry?.requests_total);
|
|
13114
|
+
const over = nN(telemetry?.requests_over_100k);
|
|
13115
|
+
const shape = s0(route?.["shape_key"]);
|
|
13116
|
+
const escalations = toEsc(route?.["escalations"]);
|
|
13117
|
+
const source = s0(route?.["source"]);
|
|
13118
|
+
const reason = s0(route?.["reason"]) ?? (executor ? "no reason recorded" : "no route recorded by implement");
|
|
13119
|
+
const rawUnits = Array.isArray(route?.["units"]) ? route["units"] : [];
|
|
13120
|
+
const units = rawUnits.length > 0 ? rawUnits.map((u, i) => ({ id: s0(u["id"]) ?? String(i + 1), executor: modelLabel(s0(u["executor"]) ?? "unknown"), applied, assigned_by: assignedBy(s0(u["source"]) ?? source, u["assigned_by"]), reason: s0(u["reason"]) ?? "no reason recorded", escalations: toEsc(u["escalations"]) })) : executor && route?.["routed"] !== false ? [{ id: "run", executor: modelLabel(executor), applied, assigned_by: assignedBy(source, route?.["assigned_by"]), reason, escalations }] : [];
|
|
13121
|
+
return {
|
|
13122
|
+
routed: route?.["routed"] === false ? false : executor !== null || units.length > 0,
|
|
13123
|
+
units,
|
|
13124
|
+
executor: !applied ? `${runModel ? modelLabel(runModel) : "run model"} (per-unit assignment not applied)` : executor ? modelLabel(executor) : units[0]?.executor ?? null,
|
|
13125
|
+
advisor: unavailable ? null : modelLabel(s0(route?.["advisor"]) ?? "opus"),
|
|
13126
|
+
advisor_unavailable_reason: unavailable,
|
|
13127
|
+
reason,
|
|
13128
|
+
source,
|
|
13129
|
+
shape_key: shape,
|
|
13130
|
+
shape_parity: shape ? `NOT PROVEN (no B9 row for shape ${shape})` : "NOT PROVEN (no shape key recorded)",
|
|
13131
|
+
escalations: units.length > 0 ? units.flatMap((u) => u.escalations) : escalations,
|
|
13132
|
+
requests_total: total,
|
|
13133
|
+
requests_over_100k: over,
|
|
13134
|
+
over_100k_share: total !== null && over !== null && total > 0 ? Math.round(over / total * 1e4) / 1e4 : null,
|
|
13135
|
+
advisor_calls: nN(telemetry?.advisor_calls),
|
|
13136
|
+
advisor_input_tokens: nN(telemetry?.advisor_input_tokens),
|
|
13137
|
+
advisor_output_tokens: nN(telemetry?.advisor_output_tokens),
|
|
13138
|
+
plan_model: s0(route?.["plan_model"]),
|
|
13139
|
+
applied,
|
|
13140
|
+
run_model: runModel ?? null,
|
|
13141
|
+
not_proven: Array.isArray(route?.["route_not_proven"]) ? route["route_not_proven"].filter((x) => typeof x === "string") : []
|
|
13142
|
+
};
|
|
13143
|
+
}
|
|
13144
|
+
function routePrLine(r) {
|
|
13145
|
+
if (!r.routed)
|
|
13146
|
+
return `Route: not routed (${r.reason})`;
|
|
13147
|
+
const adv = r.advisor ? `advisor ${r.advisor}` : "advisor unavailable";
|
|
13148
|
+
return `Route: executor ${r.executor}, ${adv}; advisor tokens ${rec(r.advisor_input_tokens)} in / ${rec(r.advisor_output_tokens)} out; over 100K: ${over(r, " requests")}`;
|
|
13149
|
+
}
|
|
13150
|
+
function routeReceiptLines(r) {
|
|
13151
|
+
if (!r.routed)
|
|
13152
|
+
return [`- Route: not routed (${r.reason})`, `- Route shape_parity: ${r.shape_parity}`];
|
|
13153
|
+
return [
|
|
13154
|
+
`- Route: executor ${r.executor}, ${r.advisor ? `advisor ${r.advisor}` : `advisor unavailable: ${r.advisor_unavailable_reason}`}: ${r.reason}`,
|
|
13155
|
+
`- Route shape_key: ${r.shape_key ?? "unknown"} shape_parity: ${r.shape_parity}`,
|
|
13156
|
+
`- Route escalations: ${r.escalations.length === 0 ? "none" : r.escalations.map((e) => `${e.from} -> ${e.to} (${e.trigger}; evidence ${e.evidence})`).join("; ")}`,
|
|
13157
|
+
`- Route advisor: ${rec(r.advisor_calls)} calls, ${rec(r.advisor_input_tokens)} in / ${rec(r.advisor_output_tokens)} out tokens`,
|
|
13158
|
+
...r.units.map((u) => `- Route unit ${u.id}: executor ${u.applied ? u.executor : `not applied (assigned ${u.executor})`}, assigned by ${u.assigned_by}: ${u.reason}; escalation: ${u.escalations.length === 0 ? "none" : u.escalations.map((e) => `${e.from} -> ${e.to} (${e.trigger})`).join(", ")}`),
|
|
13159
|
+
`- Route requests over 100K: ${over(r, "")}`
|
|
13160
|
+
];
|
|
13161
|
+
}
|
|
13162
|
+
function routeNotProven(r) {
|
|
13163
|
+
return [
|
|
13164
|
+
...r.advisor_unavailable_reason ? [`advisor: NOT PROVEN (owner provider): ${r.advisor_unavailable_reason}`] : [],
|
|
13165
|
+
`route.shape_parity: ${r.shape_parity}`,
|
|
13166
|
+
...r.applied ? [] : [`route.executor: NOT PROVEN (owner engine): per-unit executor assignment is not applied (R1-11); every stage ran ${r.run_model ?? "the run model"}`],
|
|
13167
|
+
...r.not_proven
|
|
13168
|
+
];
|
|
13169
|
+
}
|
|
13170
|
+
var ALIAS, modelLabel = (m) => ALIAS[m] ?? m, nN = (v) => typeof v === "number" && Number.isFinite(v) ? v : null, rec = (v) => v === null ? "not recorded" : String(v), s0 = (v) => typeof v === "string" && v.trim() ? v.trim() : null, assignedBy = (src, explicit) => s0(explicit) ?? (src === null || src === "opus" ? "opus" : src), over = (r, unit) => r.requests_total === null || r.requests_over_100k === null ? "not recorded" : `${r.requests_over_100k} of ${r.requests_total}${unit} (${pct(r)})`, pct = (r) => r.over_100k_share === null ? "n/a (no requests)" : `${(r.over_100k_share * 100).toFixed(1)}%`;
|
|
13171
|
+
var init_route_block = __esm(() => {
|
|
13172
|
+
ALIAS = { haiku: "haiku-5.5", sonnet: "sonnet-5.5", opus: "opus-5.5" };
|
|
13173
|
+
});
|
|
13174
|
+
|
|
13257
13175
|
// ../../loki-ts/src/util/engine_origin.ts
|
|
13258
13176
|
function readOriginUrl(repoDir) {
|
|
13259
13177
|
try {
|
|
@@ -13264,6 +13182,7 @@ function readOriginUrl(repoDir) {
|
|
|
13264
13182
|
}
|
|
13265
13183
|
}
|
|
13266
13184
|
var init_engine_origin = __esm(() => {
|
|
13185
|
+
init_atomic();
|
|
13267
13186
|
init_safe_git();
|
|
13268
13187
|
});
|
|
13269
13188
|
|
|
@@ -13300,8 +13219,8 @@ var init_cost_preview = __esm(() => {
|
|
|
13300
13219
|
});
|
|
13301
13220
|
|
|
13302
13221
|
// ../../loki-ts/src/features/contract.ts
|
|
13303
|
-
import { existsSync as existsSync35, lstatSync as lstatSync12, mkdirSync as mkdirSync22, readFileSync as
|
|
13304
|
-
import { dirname as
|
|
13222
|
+
import { existsSync as existsSync35, lstatSync as lstatSync12, mkdirSync as mkdirSync22, readFileSync as readFileSync41, rmSync as rmSync14, writeFileSync as writeFileSync24 } from "fs";
|
|
13223
|
+
import { dirname as dirname24, join as join56 } from "path";
|
|
13305
13224
|
import { createHash as createHash13 } from "crypto";
|
|
13306
13225
|
function contractEnabled(env = process.env) {
|
|
13307
13226
|
return env["LOKI_CONTRACT"] !== "0";
|
|
@@ -13333,7 +13252,7 @@ function untracedLines(trace) {
|
|
|
13333
13252
|
return trace.criteria.filter((c) => c.status === "no_match").map((c) => `contract ${sanitizeCriterion(c.id)} untraced (no keyword match in changed files): ${sanitizeCriterion(c.text)}`);
|
|
13334
13253
|
}
|
|
13335
13254
|
function contractPath(repoDir) {
|
|
13336
|
-
return
|
|
13255
|
+
return join56(repoDir, ".loki", "contract.json");
|
|
13337
13256
|
}
|
|
13338
13257
|
function readContract(repoDir) {
|
|
13339
13258
|
const p = contractPath(repoDir);
|
|
@@ -13349,7 +13268,7 @@ function readContract(repoDir) {
|
|
|
13349
13268
|
return { contract: null, notes: ["contract unreadable: too large"], sha256: null };
|
|
13350
13269
|
let raw2;
|
|
13351
13270
|
try {
|
|
13352
|
-
raw2 =
|
|
13271
|
+
raw2 = readFileSync41(p);
|
|
13353
13272
|
} catch {
|
|
13354
13273
|
return { contract: null, notes: ["contract unreadable: read failed"], sha256: null };
|
|
13355
13274
|
}
|
|
@@ -13418,13 +13337,226 @@ var init_contract = __esm(() => {
|
|
|
13418
13337
|
init_safe_git();
|
|
13419
13338
|
STOP2 = new Set(["the", "and", "for", "with", "that", "this", "must", "should", "shall", "when", "then", "are", "was", "all", "any", "can", "not", "has", "have", "from", "into", "each", "user", "users"]);
|
|
13420
13339
|
MAX_CONTRACT_BYTES = 1024 * 1024;
|
|
13421
|
-
REQ_MAP_REL =
|
|
13340
|
+
REQ_MAP_REL = join56(".loki", "state", "requirements-map.json");
|
|
13422
13341
|
REQ_STOP = new Set(["with", "that", "this", "from", "have", "will", "should", "must", "when", "then", "into", "each", "every", "user", "users", "page", "able", "allow", "support", "ensure", "using", "their", "there", "which", "shall"]);
|
|
13423
13342
|
});
|
|
13424
13343
|
|
|
13344
|
+
// ../../loki-ts/src/features/speed/seal_group.ts
|
|
13345
|
+
import { createHash as createHash14 } from "crypto";
|
|
13346
|
+
import { existsSync as existsSync36, readdirSync as readdirSync17, readFileSync as readFileSync42, statSync as statSync17 } from "fs";
|
|
13347
|
+
import { basename as basename19, dirname as dirname25, join as join57 } from "path";
|
|
13348
|
+
function sealGroup(runDir, rh) {
|
|
13349
|
+
const manifestPath = join57(runDir, "group", "manifest.json");
|
|
13350
|
+
if (!existsSync36(manifestPath))
|
|
13351
|
+
return { section: undefined, notProven: [], problems: 0, allUnitsPass: true };
|
|
13352
|
+
const notProven = [];
|
|
13353
|
+
let problems = 0;
|
|
13354
|
+
const fail = (m2) => {
|
|
13355
|
+
problems++;
|
|
13356
|
+
notProven.push(`group: ${m2}`);
|
|
13357
|
+
};
|
|
13358
|
+
const m = readJson5(manifestPath);
|
|
13359
|
+
const list = isObj10(m) && Array.isArray(m["units"]) ? m["units"] : [];
|
|
13360
|
+
if (!isObj10(m) || !ID_RE.test(String(m["group_id"] ?? "")) || list.length === 0) {
|
|
13361
|
+
fail("manifest missing, unreadable or empty");
|
|
13362
|
+
return { section: undefined, notProven, problems, allUnitsPass: false };
|
|
13363
|
+
}
|
|
13364
|
+
const units = [];
|
|
13365
|
+
const seen = new Set, seenLower = new Set;
|
|
13366
|
+
let allUnitsPass = true;
|
|
13367
|
+
list.forEach((raw2, index2) => {
|
|
13368
|
+
const u = isObj10(raw2) ? raw2 : {};
|
|
13369
|
+
const id = String(u["unit_id"] ?? "");
|
|
13370
|
+
if (!ID_RE.test(id) || seen.has(id) || seenLower.has(id.toLowerCase()))
|
|
13371
|
+
return fail(`unit ${index2} has an invalid, duplicate or case-colliding id`);
|
|
13372
|
+
seen.add(id);
|
|
13373
|
+
seenLower.add(id.toLowerCase());
|
|
13374
|
+
const dir = join57(unitsDir(runDir), id), rp = join57(dir, "receipt.json"), ep = join57(dir, "events.jsonl");
|
|
13375
|
+
let bytes;
|
|
13376
|
+
try {
|
|
13377
|
+
bytes = readFileSync42(rp);
|
|
13378
|
+
} catch {
|
|
13379
|
+
return fail(`unit ${id} sub-receipt missing`);
|
|
13380
|
+
}
|
|
13381
|
+
const sub = readJson5(rp);
|
|
13382
|
+
if (!isObj10(sub) || typeof sub["receipt_sha256"] !== "string" || rh(sub) !== sub["receipt_sha256"])
|
|
13383
|
+
return fail(`unit ${id} sub-receipt unreadable or its hash does not recompute`);
|
|
13384
|
+
const verdict = String(sub["verdict"] ?? "");
|
|
13385
|
+
if (!PASSING.has(verdict)) {
|
|
13386
|
+
allUnitsPass = false;
|
|
13387
|
+
notProven.push(`group: unit ${id} verdict ${verdict || "unknown"}`);
|
|
13388
|
+
}
|
|
13389
|
+
units.push({
|
|
13390
|
+
index: index2,
|
|
13391
|
+
unit_id: id,
|
|
13392
|
+
sub_receipt_sha256: sha2(bytes),
|
|
13393
|
+
receipt_sha256: sub["receipt_sha256"],
|
|
13394
|
+
events_file_sha256: existsSync36(ep) ? sha2(readFileSync42(ep)) : null,
|
|
13395
|
+
verdict,
|
|
13396
|
+
goal: text2(u["goal"], 200),
|
|
13397
|
+
files: (Array.isArray(u["files"]) ? u["files"] : []).map((f) => text2(f, 200)).filter(Boolean).slice(0, 50),
|
|
13398
|
+
tests: num4(u["tests"]),
|
|
13399
|
+
tokens: num4(u["tokens"]),
|
|
13400
|
+
model: text2(u["model"], 64)
|
|
13401
|
+
});
|
|
13402
|
+
});
|
|
13403
|
+
const extra = (dirNames(unitsDir(runDir)) ?? []).filter((n2) => !seen.has(n2));
|
|
13404
|
+
for (const n2 of extra)
|
|
13405
|
+
fail(`unit directory ${text2(n2, 64)} is not in the manifest`);
|
|
13406
|
+
return { section: problems === 0 ? { group_id: String(m["group_id"]), units } : undefined, notProven, problems, allUnitsPass: allUnitsPass && problems === 0 };
|
|
13407
|
+
}
|
|
13408
|
+
function capGroupVerdict(v, g) {
|
|
13409
|
+
if (g.problems > 0)
|
|
13410
|
+
return v === "SPEC_CONFLICT" ? v : "FAILED";
|
|
13411
|
+
return !g.allUnitsPass && (v === "VERIFIED" || v === "ALREADY_SATISFIED") ? "PARTIAL" : v;
|
|
13412
|
+
}
|
|
13413
|
+
async function verifyGroup(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
13414
|
+
const runDir = dirname25(receiptPath);
|
|
13415
|
+
const signed = isObj10(receipt["verification"]) && typeof receipt["verification"]["jwt"] === "string";
|
|
13416
|
+
const bad = (reason) => ({ verdict: "TAMPERED", reason: `group: ${reason}` });
|
|
13417
|
+
const g = receipt["group"];
|
|
13418
|
+
if (g === undefined)
|
|
13419
|
+
return existsSync36(join57(runDir, "group", "manifest.json")) ? bad("group directory present but the receipt has no group section") : null;
|
|
13420
|
+
if (!isObj10(g) || !ID_RE.test(String(g["group_id"] ?? "")) || !Array.isArray(g["units"]) || g["units"].length === 0)
|
|
13421
|
+
return bad("group section malformed");
|
|
13422
|
+
const entries = g["units"];
|
|
13423
|
+
const ids = entries.map((e) => isObj10(e) ? String(e["unit_id"] ?? "") : "");
|
|
13424
|
+
if (ids.some((id) => !ID_RE.test(id)) || new Set(ids.map((i) => i.toLowerCase())).size !== ids.length)
|
|
13425
|
+
return bad("unit ids invalid, duplicated or case-colliding");
|
|
13426
|
+
const onDisk = dirNames(unitsDir(runDir));
|
|
13427
|
+
if (onDisk === null || onDisk.join("\x00") !== [...ids].sort().join("\x00"))
|
|
13428
|
+
return bad("unit directories do not match the receipt (missing or extra unit)");
|
|
13429
|
+
let unchecked = null;
|
|
13430
|
+
for (let i = 0;i < entries.length; i++) {
|
|
13431
|
+
const e = entries[i], id = ids[i], dir = join57(unitsDir(runDir), id), rp = join57(dir, "receipt.json"), ep = join57(dir, "events.jsonl");
|
|
13432
|
+
if (e["index"] !== i)
|
|
13433
|
+
return bad(`unit ${id} is out of order (index ${String(e["index"])} at position ${i})`);
|
|
13434
|
+
let bytes;
|
|
13435
|
+
try {
|
|
13436
|
+
if (!statSync17(dir).isDirectory())
|
|
13437
|
+
return bad(`unit ${id} is not a directory`);
|
|
13438
|
+
bytes = readFileSync42(rp);
|
|
13439
|
+
} catch {
|
|
13440
|
+
return bad(`unit ${id} sub-receipt missing`);
|
|
13441
|
+
}
|
|
13442
|
+
if (sha2(bytes) !== e["sub_receipt_sha256"])
|
|
13443
|
+
return bad(`unit ${id} sub-receipt does not match its recorded hash`);
|
|
13444
|
+
const evSha = existsSync36(ep) ? sha2(readFileSync42(ep)) : null;
|
|
13445
|
+
if (evSha !== (e["events_file_sha256"] ?? null))
|
|
13446
|
+
return bad(`unit ${id} events.jsonl does not match its recorded hash`);
|
|
13447
|
+
const sub = readJson5(rp);
|
|
13448
|
+
if (!isObj10(sub) || sub["receipt_sha256"] !== e["receipt_sha256"] || rh(sub) !== e["receipt_sha256"])
|
|
13449
|
+
return bad(`unit ${id} sub-receipt hash does not recompute`);
|
|
13450
|
+
if (String(sub["verdict"] ?? "") !== e["verdict"])
|
|
13451
|
+
return bad(`unit ${id} verdict differs from the combined receipt`);
|
|
13452
|
+
const r = await verifyOne(rp, deps);
|
|
13453
|
+
if (r.verdict === "UNSIGNED" && signed)
|
|
13454
|
+
unchecked ??= `unit ${id} sub-receipt is unsigned under a signed combined receipt`;
|
|
13455
|
+
if (r.verdict === "TAMPERED")
|
|
13456
|
+
return bad(`unit ${id} sub-receipt failed verify: ${r.reasons.join("; ")}`);
|
|
13457
|
+
if (r.verdict === "UNCHECKED")
|
|
13458
|
+
unchecked ??= `unit ${id} sub-receipt not checked: ${r.reasons.join("; ")}`;
|
|
13459
|
+
}
|
|
13460
|
+
return unchecked ? { verdict: "UNCHECKED", reason: `group: ${unchecked}` } : null;
|
|
13461
|
+
}
|
|
13462
|
+
function compositeVerdict(childVerdicts) {
|
|
13463
|
+
const base = childVerdicts.includes("SPEC_CONFLICT") ? "SPEC_CONFLICT" : childVerdicts.length > 0 && childVerdicts.every((v) => v === "ALREADY_SATISFIED") ? "ALREADY_SATISFIED" : "VERIFIED";
|
|
13464
|
+
const failed = childVerdicts.filter((v) => v === "FAILED" || !["VERIFIED", "ALREADY_SATISFIED", "PARTIAL", "SPEC_CONFLICT"].includes(v)).length;
|
|
13465
|
+
return capGroupVerdict(base, { section: undefined, notProven: [], problems: failed, allUnitsPass: childVerdicts.every((v) => PASSING.has(v)) });
|
|
13466
|
+
}
|
|
13467
|
+
async function verifyComposite(receiptPath, receipt, rh, verifyOne, deps = {}) {
|
|
13468
|
+
const runDir = dirname25(receiptPath);
|
|
13469
|
+
const signed = isObj10(receipt["verification"]) && typeof receipt["verification"]["jwt"] === "string";
|
|
13470
|
+
const bad = (reason) => ({ problem: { verdict: "TAMPERED", reason: `composite: ${reason}` }, verdict: "FAILED" });
|
|
13471
|
+
const kids = receipt["children"];
|
|
13472
|
+
if (!Array.isArray(kids) || kids.length === 0 || !ID_RE.test(String(receipt["run_id"] ?? "")))
|
|
13473
|
+
return bad("body malformed");
|
|
13474
|
+
let ibytes;
|
|
13475
|
+
try {
|
|
13476
|
+
ibytes = readFileSync42(join57(runDir, "integration.json"));
|
|
13477
|
+
} catch {
|
|
13478
|
+
return bad("integration.json missing");
|
|
13479
|
+
}
|
|
13480
|
+
if (sha2(ibytes) !== receipt["integration_sha256"])
|
|
13481
|
+
return bad("integration.json does not match its recorded hash");
|
|
13482
|
+
const integ = readJson5(join57(runDir, "integration.json"));
|
|
13483
|
+
if (!isObj10(integ) || !isObj10(integ["outcomes"]))
|
|
13484
|
+
return bad("integration.json has no outcomes");
|
|
13485
|
+
const heads = isObj10(integ["heads"]) ? integ["heads"] : {}, outcomes = integ["outcomes"];
|
|
13486
|
+
const order2 = Array.isArray(integ["order"]) ? integ["order"].map(String) : Object.keys(outcomes).sort();
|
|
13487
|
+
const kidRepos = kids.map((k) => isObj10(k) ? String(k["repo"] ?? "") : "");
|
|
13488
|
+
if (new Set(kidRepos).size !== kidRepos.length)
|
|
13489
|
+
return bad("children list a repo more than once");
|
|
13490
|
+
if (kidRepos.length !== order2.length || kidRepos.some((r, i) => r !== order2[i]))
|
|
13491
|
+
return bad("children do not cover the integrated repos in order (a repo is missing or extra)");
|
|
13492
|
+
let unchecked = null;
|
|
13493
|
+
const verdicts = [];
|
|
13494
|
+
for (const raw2 of kids) {
|
|
13495
|
+
const c = isObj10(raw2) ? raw2 : {}, repo = String(c["repo"] ?? ""), rel = String(c["receipt_path"] ?? "");
|
|
13496
|
+
if (!repo || !relOk(rel) || !rel.startsWith(`worktrees/${slugOf(repo)}/.loki/runs/`))
|
|
13497
|
+
return bad(`child ${text2(repo, 80) || "?"} has an invalid receipt path`);
|
|
13498
|
+
if (outcomes[repo] !== "ok")
|
|
13499
|
+
return bad(`child ${text2(repo, 80)} did not finish ok in integration.json`);
|
|
13500
|
+
const rp = join57(runDir, rel);
|
|
13501
|
+
let bytes;
|
|
13502
|
+
try {
|
|
13503
|
+
bytes = readFileSync42(rp);
|
|
13504
|
+
} catch {
|
|
13505
|
+
return bad(`child ${repo} receipt missing`);
|
|
13506
|
+
}
|
|
13507
|
+
if (sha2(bytes) !== c["receipt_file_sha256"])
|
|
13508
|
+
return bad(`child ${repo} receipt does not match its recorded hash (swapped or edited)`);
|
|
13509
|
+
const sub = readJson5(rp);
|
|
13510
|
+
if (!isObj10(sub) || sub["receipt_sha256"] !== c["receipt_sha256"] || rh(sub) !== c["receipt_sha256"])
|
|
13511
|
+
return bad(`child ${repo} receipt hash does not recompute`);
|
|
13512
|
+
if (String(sub["verdict"] ?? "") !== c["verdict"])
|
|
13513
|
+
return bad(`child ${repo} verdict differs from the composite`);
|
|
13514
|
+
if (String(sub["head_sha"] ?? "") !== c["head_sha"] || !c["head_sha"])
|
|
13515
|
+
return bad(`child ${repo} head_sha differs from the composite`);
|
|
13516
|
+
verdicts.push(String(c["verdict"]));
|
|
13517
|
+
if (typeof heads[repo] !== "string" || heads[repo] === "")
|
|
13518
|
+
unchecked ??= `child ${repo} has no integrated head to compare (freshness not checked)`;
|
|
13519
|
+
else if (heads[repo] !== c["head_sha"])
|
|
13520
|
+
unchecked ??= `child ${repo} head ${String(c["head_sha"])} is not the integrated head ${String(heads[repo])}`;
|
|
13521
|
+
const r = await verifyOne(rp, deps);
|
|
13522
|
+
if (r.verdict === "TAMPERED")
|
|
13523
|
+
return bad(`child ${repo} failed verify: ${r.reasons.join("; ")}`);
|
|
13524
|
+
if (r.verdict === "UNSIGNED" && signed)
|
|
13525
|
+
unchecked ??= `child ${repo} receipt is unsigned under a signed composite`;
|
|
13526
|
+
if (r.verdict === "UNCHECKED")
|
|
13527
|
+
unchecked ??= `child ${repo} not checked: ${r.reasons.join("; ")}`;
|
|
13528
|
+
}
|
|
13529
|
+
const expect = compositeVerdict(verdicts);
|
|
13530
|
+
if (receipt["verdict"] !== expect)
|
|
13531
|
+
return bad(`recorded verdict ${String(receipt["verdict"])} differs from the children (${expect})`);
|
|
13532
|
+
return { problem: unchecked ? { verdict: "UNCHECKED", reason: `composite: ${unchecked}` } : null, verdict: expect };
|
|
13533
|
+
}
|
|
13534
|
+
function compositeHash(r) {
|
|
13535
|
+
const { composite_sha256: _c, verification: _v, ...body } = r;
|
|
13536
|
+
return sha2(canonicalJson(body));
|
|
13537
|
+
}
|
|
13538
|
+
var ID_RE, PASSING, sha2 = (b) => createHash14("sha256").update(b).digest("hex"), isObj10 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), text2 = (v, cap) => typeof v === "string" ? v.replace(/[\x00-\x1f\x7f]+/g, " ").trim().slice(0, cap) : "", num4 = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : 0, unitsDir = (runDir) => join57(runDir, "group", "units"), readJson5 = (p) => {
|
|
13539
|
+
try {
|
|
13540
|
+
return JSON.parse(readFileSync42(p, "utf8"));
|
|
13541
|
+
} catch {
|
|
13542
|
+
return;
|
|
13543
|
+
}
|
|
13544
|
+
}, dirNames = (d) => {
|
|
13545
|
+
try {
|
|
13546
|
+
return readdirSync17(d).filter((n2) => !n2.startsWith(".")).sort();
|
|
13547
|
+
} catch {
|
|
13548
|
+
return null;
|
|
13549
|
+
}
|
|
13550
|
+
}, COMPOSITE_SCHEMA = "loki.v10.composite/1", slugOf = (repo) => repo.replace(/\//g, "__"), isComposite = (r) => r["schema"] === COMPOSITE_SCHEMA, relOk = (p) => p !== "" && !p.startsWith("/") && !p.split("/").includes("..");
|
|
13551
|
+
var init_seal_group = __esm(() => {
|
|
13552
|
+
init_receipt_signer();
|
|
13553
|
+
ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
13554
|
+
PASSING = new Set(["VERIFIED", "ALREADY_SATISFIED"]);
|
|
13555
|
+
});
|
|
13556
|
+
|
|
13425
13557
|
// ../../loki-ts/src/supply/supply_guard.ts
|
|
13426
|
-
import { existsSync as
|
|
13427
|
-
import { basename as
|
|
13558
|
+
import { existsSync as existsSync37, readFileSync as readFileSync43, statSync as statSync18 } from "fs";
|
|
13559
|
+
import { basename as basename20, join as join58 } from "path";
|
|
13428
13560
|
function supplyEnabled(env) {
|
|
13429
13561
|
return env["LOKI_SUPPLY_GUARD"] !== "0";
|
|
13430
13562
|
}
|
|
@@ -13436,11 +13568,11 @@ function supplyVerdict(verdict, r) {
|
|
|
13436
13568
|
return r.blocked && verdict === "VERIFIED" ? "FAILED" : verdict;
|
|
13437
13569
|
}
|
|
13438
13570
|
function isManifestPath(path) {
|
|
13439
|
-
return MANIFESTS.test(
|
|
13571
|
+
return MANIFESTS.test(basename20(path));
|
|
13440
13572
|
}
|
|
13441
13573
|
function readDeclared(repoDir) {
|
|
13442
13574
|
const p = join58(repoDir, ".loki", DECLARED_FILE);
|
|
13443
|
-
if (!
|
|
13575
|
+
if (!existsSync37(p))
|
|
13444
13576
|
return { deps: [], problem: null };
|
|
13445
13577
|
try {
|
|
13446
13578
|
if (statSync18(p).size > MAX_FILE_BYTES)
|
|
@@ -13466,7 +13598,7 @@ function readDeclared(repoDir) {
|
|
|
13466
13598
|
}
|
|
13467
13599
|
function readAllowlist(repoDir) {
|
|
13468
13600
|
const p = join58(repoDir, ".loki", "supply-allowlist");
|
|
13469
|
-
if (!
|
|
13601
|
+
if (!existsSync37(p))
|
|
13470
13602
|
return new Set;
|
|
13471
13603
|
try {
|
|
13472
13604
|
return new Set(readFileSync43(p, "utf8").split(`
|
|
@@ -13667,9 +13799,9 @@ var init_supply_guard = __esm(() => {
|
|
|
13667
13799
|
});
|
|
13668
13800
|
|
|
13669
13801
|
// ../../loki-ts/src/engine10/stages/seal.ts
|
|
13670
|
-
import { createHash as
|
|
13671
|
-
import { existsSync as
|
|
13672
|
-
import { basename as
|
|
13802
|
+
import { createHash as createHash15 } from "crypto";
|
|
13803
|
+
import { existsSync as existsSync38, readdirSync as readdirSync18, mkdirSync as mkdirSync23, readFileSync as readFileSync44, writeFileSync as writeFileSync25 } from "fs";
|
|
13804
|
+
import { basename as basename21, isAbsolute as isAbsolute9, join as join59, relative as relative9 } from "path";
|
|
13673
13805
|
function sanitizeReason(s) {
|
|
13674
13806
|
const collapsed = s.replace(/[\x00-\x1f\x7f]+/g, " ").trim();
|
|
13675
13807
|
const capped = collapsed.length > 500 ? `${collapsed.slice(0, 500)}...` : collapsed;
|
|
@@ -13743,13 +13875,12 @@ function renderReceiptMd(r) {
|
|
|
13743
13875
|
].join(`
|
|
13744
13876
|
`);
|
|
13745
13877
|
}
|
|
13746
|
-
var DEEP_NOT_PROVEN, SIGNING_UNAVAILABLE = "receipt signing unavailable (no usable signing key: invalid key or unwritable ~/.loki/keys)", EXCLUDE_LOKI = ":(exclude).loki", sha2562 = (s) =>
|
|
13878
|
+
var DEEP_NOT_PROVEN, SIGNING_UNAVAILABLE = "receipt signing unavailable (no usable signing key: invalid key or unwritable ~/.loki/keys)", EXCLUDE_LOKI = ":(exclude).loki", sha2562 = (s) => createHash15("sha256").update(s).digest("hex"), str3 = (v) => typeof v === "string" && v !== "" ? v : null, strs2 = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string" && x !== "") : [], receiptRel = (ctx) => {
|
|
13747
13879
|
const r = relative9(ctx.repoDir, join59(ctx.runDir, "receipt.json"));
|
|
13748
13880
|
return r.startsWith("..") || isAbsolute9(r) ? `.loki/runs/${ctx.runId}/receipt.json` : r;
|
|
13749
13881
|
}, commitStage, sealStage;
|
|
13750
13882
|
var init_seal = __esm(() => {
|
|
13751
13883
|
init_spec_file();
|
|
13752
|
-
init_pr_body();
|
|
13753
13884
|
init_mutation_proof();
|
|
13754
13885
|
init_wall();
|
|
13755
13886
|
init_assert_delta();
|
|
@@ -13847,7 +13978,7 @@ var init_seal = __esm(() => {
|
|
|
13847
13978
|
notProven.add(`Wall test not executed: ${wallNotRun} file(s), no reason recorded`);
|
|
13848
13979
|
if (wallNotRun > 0) {
|
|
13849
13980
|
try {
|
|
13850
|
-
const kept = new Set((Array.isArray(o.wall?.files) ? o.wall.files : []).map((f) =>
|
|
13981
|
+
const kept = new Set((Array.isArray(o.wall?.files) ? o.wall.files : []).map((f) => basename21(String(f.path))));
|
|
13851
13982
|
for (const n2 of readdirSync18(join59(ctx.runDir, "wall")).sort())
|
|
13852
13983
|
if (!kept.has(n2))
|
|
13853
13984
|
notProven.add(`wall test discarded: ${n2} (not_run)`);
|
|
@@ -13963,7 +14094,7 @@ var init_seal = __esm(() => {
|
|
|
13963
14094
|
provider: ctx.provider,
|
|
13964
14095
|
model: ctx.model,
|
|
13965
14096
|
resumed: o.intake?.resumed === true,
|
|
13966
|
-
events_sha256: sha2562(
|
|
14097
|
+
events_sha256: sha2562(existsSync38(eventsPath) ? readFileSync44(eventsPath) : ""),
|
|
13967
14098
|
...await sealEvidence(ctx.repoDir, ctx.runDir, o, notProven, signal, ctx.emit),
|
|
13968
14099
|
log_seal: true,
|
|
13969
14100
|
...receiptBlock(process.env, cost.usd, cost.unmetered === true, totalS),
|
|
@@ -13985,15 +14116,20 @@ var init_seal = __esm(() => {
|
|
|
13985
14116
|
const receipt = { ...body, receipt_sha256: hash, verification: { jwt: sig.jwt, kid: sig.kid } };
|
|
13986
14117
|
mkdirSync23(ctx.runDir, { recursive: true });
|
|
13987
14118
|
const path = join59(ctx.runDir, "receipt.json");
|
|
13988
|
-
|
|
14119
|
+
writeFileSync25(path, JSON.stringify(receipt, null, 2) + `
|
|
13989
14120
|
`);
|
|
13990
|
-
|
|
14121
|
+
writeFileSync25(join59(ctx.runDir, "receipt.md"), renderReceiptMd(receipt));
|
|
13991
14122
|
recordRun(process.env, ctx.repoDir, ctx.model, verdict, cost.usd, cost.unmetered === true, totalS);
|
|
13992
14123
|
const signed = sig.jwt !== null;
|
|
13993
14124
|
const data = { receipt_path: path, receipt_sha256: hash, signed, kid: sig.kid, verdict, not_proven: receipt.not_proven, ...mp ? { mutation_line: mp.line } : {}, ...routeBlock ? { route_line: routePrLine(routeBlock) } : {} };
|
|
13994
14125
|
try {
|
|
13995
14126
|
recordRunVerdict(ctx.repoDir, ctx.runId, verdict);
|
|
13996
14127
|
} catch {}
|
|
14128
|
+
if (process.env["LOKI_AUTO_LEARN_PR"] !== "0") {
|
|
14129
|
+
try {
|
|
14130
|
+
appendReceiptFact(ctx.repoDir, { runId: ctx.runId, verdict, receiptSha256: signed ? hash : null, title: str3(ctx.outputs().intake?.title) ?? `run ${ctx.runId}`, headSha: receipt.head_sha });
|
|
14131
|
+
} catch {}
|
|
14132
|
+
}
|
|
13997
14133
|
ctx.emit("receipt.sealed", "seal", { path, receipt_sha256: hash, signed, kid: sig.kid, verdict, not_proven: receipt.not_proven, ...routeBlock ? { route_line: routePrLine(routeBlock) } : {} });
|
|
13998
14134
|
return { status: "completed", data: { ...data, summary: `${verdict} receipt ${hash.slice(0, 12)} ${signed ? `SIGNED kid ${sig.kid}` : "UNSIGNED"}` } };
|
|
13999
14135
|
}
|
|
@@ -14093,9 +14229,9 @@ var init_keys_cmd = __esm(() => {
|
|
|
14093
14229
|
});
|
|
14094
14230
|
|
|
14095
14231
|
// ../../loki-ts/src/engine10/verify_cmd.ts
|
|
14096
|
-
import { existsSync as
|
|
14097
|
-
import { dirname as dirname27, join as join60 } from "path";
|
|
14098
|
-
import { createHash as
|
|
14232
|
+
import { existsSync as existsSync39, readFileSync as readFileSync46, renameSync as renameSync8, statSync as statSync20, writeFileSync as writeFileSync26 } from "fs";
|
|
14233
|
+
import { basename as basename22, dirname as dirname27, join as join60 } from "path";
|
|
14234
|
+
import { createHash as createHash16, createPublicKey as createPublicKey4, verify as verify3 } from "crypto";
|
|
14099
14235
|
function pubFor(kid, given) {
|
|
14100
14236
|
if (given)
|
|
14101
14237
|
return kidOf2(given) === kid ? given : undefined;
|
|
@@ -14132,10 +14268,10 @@ function checkAttestation(jwt, expectedHash, given) {
|
|
|
14132
14268
|
}
|
|
14133
14269
|
function checkEventLog(receiptPath, receipt) {
|
|
14134
14270
|
const bound = receipt["events_sha256"];
|
|
14135
|
-
if (typeof bound !== "string" || bound ===
|
|
14271
|
+
if (typeof bound !== "string" || bound === createHash16("sha256").digest("hex"))
|
|
14136
14272
|
return null;
|
|
14137
14273
|
const path = join60(dirname27(receiptPath), "events.jsonl");
|
|
14138
|
-
if (!
|
|
14274
|
+
if (!existsSync39(path))
|
|
14139
14275
|
return "events.jsonl is missing";
|
|
14140
14276
|
const raw2 = readFileSync46(path, "utf8"), events2 = readEvents(path), lines = raw2.split(`
|
|
14141
14277
|
`).filter((l) => l.trim() !== "");
|
|
@@ -14143,7 +14279,7 @@ function checkEventLog(receiptPath, receipt) {
|
|
|
14143
14279
|
return "events.jsonl has a forged, edited or missing line";
|
|
14144
14280
|
if (events2.some((e) => e.type === "tamper.detected"))
|
|
14145
14281
|
return "the supervisor detected events.jsonl being modified during the run";
|
|
14146
|
-
const h =
|
|
14282
|
+
const h = createHash16("sha256");
|
|
14147
14283
|
for (const l of lines) {
|
|
14148
14284
|
if (h.copy().digest("hex") === bound)
|
|
14149
14285
|
return null;
|
|
@@ -14162,7 +14298,7 @@ function checkLogSeal(receiptPath, hash, kid, given) {
|
|
|
14162
14298
|
if (!d)
|
|
14163
14299
|
return { verdict: "TAMPERED", reason: "events.jsonl has no signed log.sealed line after run.completed" };
|
|
14164
14300
|
const lines = readFileSync46(path, "utf8").split(`
|
|
14165
|
-
`).filter((l) => l.trim() !== ""), sha3 =
|
|
14301
|
+
`).filter((l) => l.trim() !== ""), sha3 = createHash16("sha256").update(lines.slice(0, done + 1).join(`
|
|
14166
14302
|
`) + `
|
|
14167
14303
|
`).digest("hex");
|
|
14168
14304
|
const pub = d["kid"] === kid ? pubFor(kid, given) : undefined;
|
|
@@ -14171,7 +14307,7 @@ function checkLogSeal(receiptPath, hash, kid, given) {
|
|
|
14171
14307
|
return null;
|
|
14172
14308
|
}
|
|
14173
14309
|
async function verifyReceipt(receiptPath, deps = {}) {
|
|
14174
|
-
if (!
|
|
14310
|
+
if (!existsSync39(receiptPath))
|
|
14175
14311
|
return { verdict: "UNCHECKED", reasons: [`receipt not found: ${receiptPath}`] };
|
|
14176
14312
|
let receipt;
|
|
14177
14313
|
try {
|
|
@@ -14181,6 +14317,8 @@ async function verifyReceipt(receiptPath, deps = {}) {
|
|
|
14181
14317
|
}
|
|
14182
14318
|
if (isEnvelope(receipt))
|
|
14183
14319
|
return verifyDsseReceipt(receipt, { pubFor: (kid) => pubFor(kid, deps.pubkey), hash: computeReceiptHash, attest: (j, h) => checkAttestation(j, h, deps.pubkey) });
|
|
14320
|
+
if (isComposite(receipt))
|
|
14321
|
+
return verifyCompositeFile(receiptPath, receipt, deps);
|
|
14184
14322
|
const recorded = receipt["receipt_sha256"];
|
|
14185
14323
|
const computed = computeReceiptHash(receipt);
|
|
14186
14324
|
if (typeof recorded !== "string" || recorded !== computed) {
|
|
@@ -14218,9 +14356,34 @@ async function verifyReceipt(receiptPath, deps = {}) {
|
|
|
14218
14356
|
return { verdict: gp.verdict, reasons: [gp.reason] };
|
|
14219
14357
|
return { verdict: "VERIFIED", reasons: [], receiptSha256: computed };
|
|
14220
14358
|
}
|
|
14359
|
+
async function verifyCompositeFile(receiptPath, receipt, deps) {
|
|
14360
|
+
const computed = compositeHash(receipt);
|
|
14361
|
+
if (receipt["composite_sha256"] !== computed)
|
|
14362
|
+
return { verdict: "TAMPERED", reasons: [`composite_sha256 mismatch: recorded ${JSON.stringify(receipt["composite_sha256"])}, computed ${computed}`] };
|
|
14363
|
+
const c = await verifyComposite(receiptPath, receipt, computeReceiptHash, verifyReceipt, deps);
|
|
14364
|
+
if (c.problem?.verdict === "TAMPERED")
|
|
14365
|
+
return { verdict: "TAMPERED", reasons: [c.problem.reason] };
|
|
14366
|
+
const jwt = (receipt["verification"] ?? {}).jwt ?? null;
|
|
14367
|
+
if (jwt !== null && typeof jwt !== "string")
|
|
14368
|
+
return { verdict: "UNCHECKED", reasons: ["verification.jwt is not a string"] };
|
|
14369
|
+
if (!jwt)
|
|
14370
|
+
return c.problem ? { verdict: c.problem.verdict, reasons: [c.problem.reason] } : { verdict: "UNSIGNED", reasons: [], receiptSha256: computed };
|
|
14371
|
+
const outcome = checkAttestation(jwt, computed, deps.pubkey);
|
|
14372
|
+
if (outcome.status === "unchecked")
|
|
14373
|
+
return { verdict: "UNCHECKED", reasons: [outcome.reason ?? "attestation not checked"] };
|
|
14374
|
+
if (outcome.status === "tampered")
|
|
14375
|
+
return { verdict: "TAMPERED", reasons: [outcome.reason ?? "attestation invalid"] };
|
|
14376
|
+
const shown = receipt["verification"].kid, signed = JSON.parse(Buffer.from(jwt.split(".")[0], "base64url").toString()).kid;
|
|
14377
|
+
if (shown !== undefined && shown !== signed)
|
|
14378
|
+
return { verdict: "TAMPERED", reasons: ["verification.kid differs from the signing kid in the attestation header"] };
|
|
14379
|
+
if (c.problem)
|
|
14380
|
+
return { verdict: c.problem.verdict, reasons: [c.problem.reason] };
|
|
14381
|
+
return { verdict: "VERIFIED", reasons: [], receiptSha256: computed };
|
|
14382
|
+
}
|
|
14221
14383
|
var computeReceiptHash = (receipt) => receiptSha256(receipt);
|
|
14222
14384
|
var init_verify_cmd = __esm(() => {
|
|
14223
14385
|
init_paths();
|
|
14386
|
+
init_run_status();
|
|
14224
14387
|
init_events();
|
|
14225
14388
|
init_seal();
|
|
14226
14389
|
init_receipt_dsse();
|
|
@@ -14230,7 +14393,7 @@ var init_verify_cmd = __esm(() => {
|
|
|
14230
14393
|
});
|
|
14231
14394
|
|
|
14232
14395
|
// src/server/app.ts
|
|
14233
|
-
import { existsSync as
|
|
14396
|
+
import { existsSync as existsSync41, readFileSync as readFileSync49, statSync as statSync21 } from "fs";
|
|
14234
14397
|
import { join as join63, resolve as resolve15, sep as sep14 } from "path";
|
|
14235
14398
|
|
|
14236
14399
|
// node_modules/hono/dist/request/constants.js
|
|
@@ -22438,7 +22601,7 @@ var loki_yaml_schema_default = {
|
|
|
22438
22601
|
items: { type: "string", minLength: 1 }
|
|
22439
22602
|
},
|
|
22440
22603
|
workspaces: {
|
|
22441
|
-
description: "Named groups of repos for cross-repo runs (`loki workspace run`).
|
|
22604
|
+
description: "Named groups of repos for cross-repo runs (`loki workspace run`). On by default; LOKI_WORKSPACES=0 disables. Unknown or mistyped keys fail validation.",
|
|
22442
22605
|
type: "object",
|
|
22443
22606
|
additionalProperties: {
|
|
22444
22607
|
type: "object",
|
|
@@ -22462,9 +22625,12 @@ var loki_yaml_schema_default = {
|
|
|
22462
22625
|
additionalProperties: false,
|
|
22463
22626
|
properties: {
|
|
22464
22627
|
command: { type: "string", minLength: 1 },
|
|
22465
|
-
timeout_s: { type: "integer", minimum: 1 }
|
|
22628
|
+
timeout_s: { type: "integer", minimum: 1 },
|
|
22629
|
+
per_stage: { type: "boolean" }
|
|
22466
22630
|
}
|
|
22467
22631
|
},
|
|
22632
|
+
concurrency: { type: "integer", minimum: 1 },
|
|
22633
|
+
plan: { type: "boolean" },
|
|
22468
22634
|
integration_files: { type: "array", items: { type: "string", minLength: 1 } }
|
|
22469
22635
|
}
|
|
22470
22636
|
}
|
|
@@ -24592,7 +24758,7 @@ function ttlCache(ttlMs = PROBE_CACHE_MS, now2 = Date.now) {
|
|
|
24592
24758
|
}
|
|
24593
24759
|
|
|
24594
24760
|
// src/server/legacy/shim.ts
|
|
24595
|
-
import { existsSync as
|
|
24761
|
+
import { existsSync as existsSync40, readFileSync as readFileSync48 } from "fs";
|
|
24596
24762
|
import { join as join62 } from "path";
|
|
24597
24763
|
|
|
24598
24764
|
// src/server/legacy/routes.ts
|
|
@@ -24967,7 +25133,7 @@ var NOT_SUPPORTED = "not yet supported by the Control Plane";
|
|
|
24967
25133
|
var repoVersion = () => {
|
|
24968
25134
|
for (const f of [join62(import.meta.dir, "../../../../../VERSION")]) {
|
|
24969
25135
|
try {
|
|
24970
|
-
if (
|
|
25136
|
+
if (existsSync40(f))
|
|
24971
25137
|
return readFileSync48(f, "utf8").trim();
|
|
24972
25138
|
} catch {}
|
|
24973
25139
|
}
|
|
@@ -25150,7 +25316,7 @@ function legacyShim(opts) {
|
|
|
25150
25316
|
|
|
25151
25317
|
// src/server/app.ts
|
|
25152
25318
|
var MAX_BODY2 = 1e6;
|
|
25153
|
-
var defaultUiDir = () => [join63(import.meta.dir, "../../ui/dist"), join63(import.meta.dir, "../ui/dist")].find((d) =>
|
|
25319
|
+
var defaultUiDir = () => [join63(import.meta.dir, "../../ui/dist"), join63(import.meta.dir, "../ui/dist")].find((d) => existsSync41(join63(d, "index.html")));
|
|
25154
25320
|
function createApp(opts) {
|
|
25155
25321
|
const uiDir = opts.uiDir ?? defaultUiDir();
|
|
25156
25322
|
const { db, sqlite } = openDb(opts.dbPath);
|
|
@@ -25293,7 +25459,7 @@ function createApp(opts) {
|
|
|
25293
25459
|
return c.json({ error: "not found" }, 404);
|
|
25294
25460
|
const root = resolve15(uiDir);
|
|
25295
25461
|
const f = resolve15(root, `.${p}`);
|
|
25296
|
-
if (f.startsWith(root + sep14) &&
|
|
25462
|
+
if (f.startsWith(root + sep14) && existsSync41(f) && statSync21(f).isFile())
|
|
25297
25463
|
return new Response(Bun.file(f));
|
|
25298
25464
|
if (/\.[a-z0-9]+$/i.test(p))
|
|
25299
25465
|
return c.json({ error: "not found" }, 404);
|