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.
Files changed (116) hide show
  1. package/README.md +19 -2
  2. package/SKILL.md +2 -2
  3. package/VERSION +1 -1
  4. package/autonomy/lib/backlog.py +11 -2
  5. package/autonomy/lib/chat.sh +57 -1
  6. package/autonomy/lib/loki_yaml.py +8 -2
  7. package/autonomy/lib/workspace.py +267 -11
  8. package/autonomy/loki +327 -222
  9. package/autonomy/notification-checker.py +1 -1
  10. package/autonomy/trigger-server.py +185 -2
  11. package/autonomy/verify.sh +4 -0
  12. package/completions/_loki +4 -0
  13. package/completions/loki.bash +20 -2
  14. package/dashboard/__init__.py +3 -10
  15. package/dashboard/control.py +5 -435
  16. package/docs/ARCHITECTURE.md +1 -2
  17. package/docs/CLI-CORE-VERBS.md +2 -6
  18. package/docs/CLI-REFERENCE.md +2 -1
  19. package/docs/COMPONENTS.md +0 -2
  20. package/docs/DEPLOY-PLAN.md +17 -8
  21. package/docs/EVALUATING.md +8 -0
  22. package/docs/INSTALLATION.md +1 -1
  23. package/docs/WORKSPACES.md +15 -2
  24. package/docs/authentication.md +19 -1
  25. package/docs/dev/architecture-reference.md +8 -0
  26. package/docs/dev/release-checklist.md +9 -8
  27. package/docs/enterprise/security.md +3 -234
  28. package/docs/sentry-intake.md +11 -0
  29. package/docs/v10/ARCHITECT-CUTS.md +304 -0
  30. package/docs/v10/CLI-MODERN.md +1 -1
  31. package/docs/v10/DECISIONS.md +5 -5
  32. package/docs/v10/ENGINE.md +735 -299
  33. package/docs/v10/GUARDS.md +16 -14
  34. package/docs/v10/GUIDE.md +5 -7
  35. package/docs/v10/PROGRESS.md +12 -1
  36. package/docs/v11/MARKET-SLICES.md +1 -5
  37. package/integrations/openclaw/README.md +20 -0
  38. package/integrations/vibe-kanban.md +12 -50
  39. package/loki-ts/dist/loki.js +1213 -1178
  40. package/mcp/__init__.py +1 -1
  41. package/mcp/_sdk_loader.py +1 -1
  42. package/package.json +2 -2
  43. package/packages/control-plane/dist/server.js +1090 -924
  44. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  45. package/references/quality-control.md +1 -116
  46. package/schemas/loki-yaml.schema.json +5 -2
  47. package/skills/00-index.md +2 -2
  48. package/skills/artifacts.md +0 -22
  49. package/skills/production.md +2 -38
  50. package/src/policies/engine.js +41 -2
  51. package/src/policies/types.js +49 -0
  52. package/web-app/dist/assets/{AdminPage-Cbu3pXL8.js → AdminPage-S3BYeapm.js} +1 -1
  53. package/web-app/dist/assets/{Avatar-DGqGGcGx.js → Avatar-C1rHwLgn.js} +1 -1
  54. package/web-app/dist/assets/{Badge-Bhlipt6v.js → Badge-CzlnN5aQ.js} +1 -1
  55. package/web-app/dist/assets/{Button-CpN2sO61.js → Button-B1w5AeGC.js} +1 -1
  56. package/web-app/dist/assets/{CockpitPage-BqeDJwdL.js → CockpitPage-Dyeqjfkc.js} +1 -1
  57. package/web-app/dist/assets/{ComparePage-DUieA2ba.js → ComparePage-C6y2GkGR.js} +1 -1
  58. package/web-app/dist/assets/{ErrorBoundary-DTWsYrOm.js → ErrorBoundary-Dg2fcGkR.js} +1 -1
  59. package/web-app/dist/assets/{EvidenceReceiptPanel-BU_B9X19.js → EvidenceReceiptPanel-CxbyjvTj.js} +1 -1
  60. package/web-app/dist/assets/{GitHubIssuesPanel-DEZoLOsP.js → GitHubIssuesPanel-Dpys1xDb.js} +1 -1
  61. package/web-app/dist/assets/{GitHubPRsPanel-BEsnrq7Y.js → GitHubPRsPanel-CRVjWoFl.js} +1 -1
  62. package/web-app/dist/assets/{HomePage-BoUVuq7h.js → HomePage-BKnv-oYw.js} +2 -2
  63. package/web-app/dist/assets/{LoginPage-CmOED7vb.js → LoginPage-BGksmFRd.js} +1 -1
  64. package/web-app/dist/assets/{MagicPage-DATZitrZ.js → MagicPage-OCvhp16M.js} +1 -1
  65. package/web-app/dist/assets/{MetricsPage-DGL1v0I-.js → MetricsPage-CJOJpXWC.js} +1 -1
  66. package/web-app/dist/assets/{NotFoundPage-C2WgOjZd.js → NotFoundPage-C04p3QvN.js} +1 -1
  67. package/web-app/dist/assets/{ProjectPage-BMi1tepj.js → ProjectPage-BRB8txsY.js} +3 -3
  68. package/web-app/dist/assets/{ProjectsPage-vc3y5YPh.js → ProjectsPage-CoUYeQEh.js} +1 -1
  69. package/web-app/dist/assets/{SettingsPage-kbq0Ftvi.js → SettingsPage-BkjmJGfM.js} +1 -1
  70. package/web-app/dist/assets/{ShowcasePage-Bn6Q8Kbg.js → ShowcasePage-B4vU9TjQ.js} +1 -1
  71. package/web-app/dist/assets/{SystemSettingsPage-Basmhs_b.js → SystemSettingsPage-Z2jiVsni.js} +1 -1
  72. package/web-app/dist/assets/{TeamsPage-BTqOc4TR.js → TeamsPage-Ulm8SISq.js} +1 -1
  73. package/web-app/dist/assets/{TemplatesPage-2P9002VL.js → TemplatesPage-C_7MM6Ey.js} +1 -1
  74. package/web-app/dist/assets/{TerminalOutput-CAoSPBrg.js → TerminalOutput-Cumd7Tgs.js} +1 -1
  75. package/web-app/dist/assets/{activity-BcWVWCqU.js → activity-CZAUkbiY.js} +1 -1
  76. package/web-app/dist/assets/{bell-CYRqqgZ6.js → bell-BOvSXpEr.js} +1 -1
  77. package/web-app/dist/assets/{bot-CU7gdn3g.js → bot-DOTZxBYj.js} +1 -1
  78. package/web-app/dist/assets/{check-DLlCpz9V.js → check-BxpE0B5u.js} +1 -1
  79. package/web-app/dist/assets/{chevron-left-CE9Cb30C.js → chevron-left-D6KPvBOA.js} +1 -1
  80. package/web-app/dist/assets/{circle-alert-uou4bjua.js → circle-alert-Bajq86oe.js} +1 -1
  81. package/web-app/dist/assets/{clock-C_dSJcDX.js → clock-CnlHAVJc.js} +1 -1
  82. package/web-app/dist/assets/{cloud-DZ22ITF6.js → cloud-DjaymjwM.js} +1 -1
  83. package/web-app/dist/assets/{code-xml-BrJS0hhS.js → code-xml-BADEw2Ld.js} +1 -1
  84. package/web-app/dist/assets/{database-D2HOmxtl.js → database-B4aKb5Cq.js} +1 -1
  85. package/web-app/dist/assets/{dollar-sign-CQ1vK_6q.js → dollar-sign-DrldXpja.js} +1 -1
  86. package/web-app/dist/assets/{file-code-corner-w2vpGm5d.js → file-code-corner-DVebDVR-.js} +1 -1
  87. package/web-app/dist/assets/{file-plus-DlF6wjkD.js → file-plus-BD-N_-Tl.js} +1 -1
  88. package/web-app/dist/assets/{globe-Dy3lBJg1.js → globe-C7ieInC-.js} +1 -1
  89. package/web-app/dist/assets/{hammer-C3xIiRXN.js → hammer-BSugKIji.js} +1 -1
  90. package/web-app/dist/assets/{index-4t-_IW2y.js → index-nLQgfvOn.js} +3 -3
  91. package/web-app/dist/assets/{layers-Y8Fs8qXI.js → layers-CHXxU2on.js} +1 -1
  92. package/web-app/dist/assets/{loader-circle-CxgN1v4m.js → loader-circle-BEEz0LbD.js} +1 -1
  93. package/web-app/dist/assets/{lock-DFFNbXDs.js → lock-CzQGfcnE.js} +1 -1
  94. package/web-app/dist/assets/{package-5e6qCTUg.js → package-CcHYQLGd.js} +1 -1
  95. package/web-app/dist/assets/{plus-C0Go_ytj.js → plus-DdzgFEXn.js} +1 -1
  96. package/web-app/dist/assets/{refresh-cw-D4i-NW3o.js → refresh-cw-7x0HbH9Y.js} +1 -1
  97. package/web-app/dist/assets/{rotate-ccw-YlKkiUW6.js → rotate-ccw-DBahX1Sp.js} +1 -1
  98. package/web-app/dist/assets/{scroll-text-4qXOHTap.js → scroll-text-BB8y8a9Z.js} +1 -1
  99. package/web-app/dist/assets/{server-BB6zXNp9.js → server-CfkbW2MH.js} +1 -1
  100. package/web-app/dist/assets/{shield-alert-D4tzjB1H.js → shield-alert-DUgD8rBF.js} +1 -1
  101. package/web-app/dist/assets/{thumbs-up-DZiRwdFj.js → thumbs-up-DGoyY6QC.js} +1 -1
  102. package/web-app/dist/assets/{trash-2-Dv_LkRIK.js → trash-2-B6xrSUMr.js} +1 -1
  103. package/web-app/dist/assets/{trending-down-BJYp9PQe.js → trending-down-B6RGKTOx.js} +1 -1
  104. package/web-app/dist/assets/{trending-up-BTcXLklK.js → trending-up-B44DCrt1.js} +1 -1
  105. package/web-app/dist/assets/{upload-fcHqwOxr.js → upload-4kWm33ZY.js} +1 -1
  106. package/web-app/dist/assets/{usePolling-BeJYw_4L.js → usePolling-zkUtRQG6.js} +1 -1
  107. package/web-app/dist/assets/{user-BcDwUCsO.js → user-04cEVIe2.js} +1 -1
  108. package/web-app/dist/index.html +1 -1
  109. package/dashboard/run.py +0 -63
  110. package/docs/openclaw-integration.md +0 -52
  111. package/docs/v10/HANDOFF-NEXT-WEEK.md +0 -40
  112. package/docs/v10/MORNING-BRIEF-1003.md +0 -25
  113. package/docs/v10/MORNING-BRIEF.md +0 -52
  114. package/docs/v10/TODO.md +0 -35
  115. package/mcp/resources.py +0 -351
  116. 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 statSync12, lstatSync as lstatSync4 } from "fs";
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 join28 } from "path";
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(join28(root, "loki-gh-config-"));
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() && statSync12(p).isDirectory();
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 existsSync16, mkdirSync as mkdirSync5, mkdtempSync as mkdtempSync3, readFileSync as readFileSync19, rmSync as rmSync5, symlinkSync, writeFileSync as writeFileSync8 } from "fs";
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 dirname8, isAbsolute as isAbsolute2, join as join29, relative as relative2 } from "path";
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(join29(tmpdir4(), "loki-mutproof-"));
7831
- wt = join29(parent, "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 = existsSync16(wt) || add2.status === 0;
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 = join29(i.runDir, "wall", basename8(rel)), src = existsSync16(sealed) ? sealed : join29(i.repoDir, rel);
7838
- if (!existsSync16(src))
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(dirname8(join29(wt, rel)), { recursive: true });
7841
- writeFileSync8(join29(wt, rel), readFileSync19(src));
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 = join29(i.repoDir, anc, d), dst = join29(wt, anc, d);
7849
- if (existsSync16(src) && !existsSync16(dst)) {
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 init_mutation_proof = __esm(() => {
7891
- init_safe_git();
7892
- init_run_cap();
7893
- DEP_DIRS = ["node_modules", ".venv", "venv"];
7894
- });
7895
-
7896
- // ../../loki-ts/src/features/lean_prefix.ts
7897
- var LEAN_PREFIX, STAGE_PREFIX, withStagePrefix = (brief) => process.env["LOKI_SPEED"] !== "0" ? `${STAGE_PREFIX}
7898
-
7899
- ${brief}` : brief;
7900
- var init_lean_prefix = __esm(() => {
7901
- LEAN_PREFIX = "You are Loki, an autonomous coding agent. Follow the task prompt exactly " + "and report only what you did.";
7902
- 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.";
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 = norm2(content).split(`
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}`, ...norm2(f.content).split(`
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: norm2(f.content).split(`
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(norm2(content), jsx) ? [] : tsSignatures(content, jsx);
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: norm2(f.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
- }, norm2 = (s) => s.replace(/\r\n?/g, `
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, PY_TIMEOUT_MS = 5000, PY_SCRIPT = `
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 createHash7 } from "crypto";
8965
- import { basename as basename9, dirname as dirname9 } from "path";
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(dirname9(e.path));
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 text3 = buildWallManifest([...files, ...listed.map((e) => ({ path: e.path, content: "" }))], named.map((e) => e.path), matched.map((e) => e.path));
9024
- return { text: text3, sha256: createHash7("sha256").update(text3).digest("hex") };
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 createHash8 } from "crypto";
9057
- import { existsSync as existsSync17, mkdirSync as mkdirSync6, readFileSync as readFileSync20, writeFileSync as writeFileSync9 } from "fs";
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 createHash8("sha256").update(basis).digest("hex");
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 readJson4(path, isValid = (_v) => true) {
8997
+ function readJson3(path, isValid = (_v) => true) {
9070
8998
  if (!existsSync17(path))
9071
8999
  return null;
9072
9000
  try {
9073
- const parsed = JSON.parse(readFileSync20(path, "utf8"));
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 readJson4(resolve8(dir, `repomap-${tree}.json`), isRepoMap);
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 = (text3) => text3.toLowerCase().match(/[a-z0-9_]+/g) ?? [];
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 readFileSync21 } from "fs";
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(readFileSync21(path, "utf8")).providers?.claude?.cli_aliases?.[want] ?? want;
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 { mkdirSync as mkdirSync7, readdirSync as readdirSync10, readFileSync as readFileSync22, writeFileSync as writeFileSync10 } from "fs";
9178
- import { join as join30 } from "path";
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 num4(v) {
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 join30(lokiRoot, "metrics", `result-cost-${iteration}.json`);
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(readFileSync22(resultCostPath(lokiRoot, iter), "utf8")));
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(readFileSync22(resultCostPath(lokiRoot, iter), "utf8")) });
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 rec2 = parsed.get(iter);
9234
- if (!rec2) {
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 = num4(rec2["input_tokens"]);
9245
- const outTok = num4(rec2["output_tokens"]);
9246
- const cacheR = num4(rec2["cache_read_tokens"]);
9247
- const cacheC = num4(rec2["cache_creation_tokens"]);
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 rec2["cache_read_tokens"] === "number")
9191
+ if (typeof rec["cache_read_tokens"] === "number")
9253
9192
  readSeen++;
9254
- if (typeof rec2["cache_creation_tokens"] === "number")
9193
+ if (typeof rec["cache_creation_tokens"] === "number")
9255
9194
  creationSeen++;
9256
- if (typeof rec2["duration_ms"] === "number" && Number.isFinite(rec2["duration_ms"])) {
9257
- out2.duration_ms = (out2.duration_ms ?? 0) + rec2["duration_ms"];
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"] += num4(rec2["requests_total"]);
9200
+ out2.router["requests_total"] += num3(rec["requests_total"]);
9262
9201
  if (out2.router)
9263
- out2.router["requests_over_100k"] += num4(rec2["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"] += num4(rec2["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"] += num4(rec2["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"] += num4(rec2["advisor_calls"]);
9208
+ out2.router["advisor_calls"] += num3(rec["advisor_calls"]);
9270
9209
  if (out2.router)
9271
- out2.router["advisor_input_tokens"] += num4(rec2["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"] += num4(rec2["advisor_output_tokens"]);
9274
- if (typeof rec2["model"] === "string" && rec2["model"])
9275
- out2.model = rec2["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: rec2 });
9278
- const c = rec2["total_cost_usd"];
9279
- const unmetered = rec2["source"] === 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 (rec2["estimated"] === true)
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 mkdirSync8, readdirSync as readdirSync11, readFileSync as readFileSync23, renameSync as renameSync4, writeFileSync as writeFileSync11 } from "fs";
9325
- import { dirname as dirname10, join as join31, resolve as resolve10 } from "path";
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(readFileSync23(resolve10(here, ...rel, "model-pricing.json"), "utf8"));
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(readFileSync23(jsonPath, "utf8"));
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 readFileSync24 } from "fs";
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(readFileSync24(repomapRef, "utf8"));
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 lstatSync5, realpathSync as realpathSync14, statSync as statSync14 } from "fs";
9527
- import { isAbsolute as isAbsolute3, join as join33, normalize, sep as sep9 } from "path";
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 = realpathSync14(join33(repoDir, rel));
9537
- const base = realpathSync14(repoDir);
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 = join33(repoDir, rel);
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 (!lstatSync5(join33(repoDir, rel)).isFile() || !insideRepo(repoDir, rel))
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 = join33(repoDir, rel);
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 createHash9 } from "crypto";
9693
- import { closeSync as closeSync5, lstatSync as lstatSync6, openSync as openSync5, readFileSync as readFileSync25, readSync as readSync4 } from "fs";
9694
- import { dirname as dirname11, join as join34 } from "path";
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 = createHash9("sha256");
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 = join34(repoDir, f);
9721
- const size = lstatSync6(abs).size;
9722
- h.update(size <= GATHER_CAPS.maxHashBytes ? readFileSync25(abs) : `too-large:${size}`);
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 createHash9("sha256").update(JSON.stringify(rest)).digest("hex");
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 mkdirSync9, readFileSync as readFileSync26, rmSync as rmSync6, writeFileSync as writeFileSync12 } from "fs";
9766
- import { join as join35 } from "path";
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(readFileSync26(join35(repoDir, PROJECT_FILE), "utf8")), now2);
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(readFileSync26(join35(repoDir, PROJECT_FILE), "utf8"));
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 join36 } from "path";
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: join36(repoDir, pkg.root), file: rel };
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 readFileSync27, rmSync as rmSync7 } from "fs";
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 join37 } from "path";
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(join37(tmpdir6(), "loki-ad-"));
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
- rmSync7(cwd, { recursive: true, force: true });
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) : readFileSync27(join37(repoDir, path), "utf8");
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 join38, relative as relative3, sep as sep10 } from "path";
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 mkdirSync10, readFileSync as readFileSync28, renameSync as renameSync5, writeFileSync as writeFileSync13 } from "fs";
10213
- import { basename as basename13, join as join39 } from "path";
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 text3 = stripAnsi(i.out);
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(text3);
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(text3) || GO_FAIL_EVIDENCE.test(text3) ? { result: "fail" } : { result: "not_run", reason: UNCONFIRMED_REASON };
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(text3))
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 run = (args) => safeGit(repoDir, args).split(`
10476
+ const run2 = (args) => safeGit(repoDir, args).split(`
10480
10477
  `).map((l) => l.trim()).filter(Boolean);
10481
- const tracked = run(["diff", "--name-only", baseSha]);
10482
- const untracked = run(["ls-files", "--others", "--exclude-standard"]);
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 = readFileSync28(join39(repoDir, path), "utf8").split(`
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 = join39(repoDir, ".loki", "state"), p = join39(dir, "risk-tier.json");
10514
- mkdirSync10(dir, { recursive: true });
10515
- writeFileSync13(`${p}.tmp`, JSON.stringify(a, null, 2) + `
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 realpathSync15, rmSync as rmSync8 } from "fs";
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 join40 } from "path";
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(join40(repoDir, f)))
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, realpathSync15(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(join40(tmpdir7(), "e10-loadown-"));
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
- rmSync8(dir, { recursive: true, force: true });
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 join41, relative as relative4 } from "path";
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 : join41(cwd, 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 readFileSync29, mkdirSync as mkdirSync12, readdirSync as readdirSync12, renameSync as renameSync7, rmSync as rmSync10, writeFileSync as writeFileSync14 } from "fs";
10817
- import { basename as basename15, join as join42, resolve as resolve11, isAbsolute as isAbsolute5 } from "path";
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(readFileSync29(commandProfilePath(repoDir), "utf8"));
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 norm3 = (s) => s.replace(/\s+--silent\b/, "").trim(), p = loadProfile(repoDir);
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) => norm3(c.cmd) !== norm3(p.baseline.command ?? "")))
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) => join42(repoDir, ".loki", "state", "repo-profile.json");
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 createHash10 } from "crypto";
10807
+ import { createHash as createHash9 } from "crypto";
10862
10808
  import {
10863
10809
  existsSync as existsSync23,
10864
- readdirSync as readdirSync13,
10865
- readFileSync as readFileSync30,
10866
- statSync as statSync16,
10867
- writeFileSync as writeFileSync15,
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 dirname13, join as join43, resolve as resolve12 } from "path";
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 = readFileSync30(path, "utf8");
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 = readdirSync13(rootDir);
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 = join43(rootDir, child);
10875
+ const full = join42(rootDir, child);
10930
10876
  if (seen.has(full))
10931
10877
  continue;
10932
10878
  let st;
10933
10879
  try {
10934
- st = statSync16(full);
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 = join43(rootDir, child);
10892
+ const full = join42(rootDir, child);
10947
10893
  if (seen.has(full))
10948
10894
  continue;
10949
10895
  let st;
10950
10896
  try {
10951
- st = statSync16(full);
10897
+ st = statSync15(full);
10952
10898
  } catch {
10953
10899
  continue;
10954
10900
  }
10955
10901
  if (!st.isDirectory())
10956
10902
  continue;
10957
- if (!existsSync23(join43(full, ".loki", "app.json")))
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 = statSync16(p).mtimeMs;
10916
+ mtime = statSync15(p).mtimeMs;
10971
10917
  } catch {}
10972
10918
  parts.push(`${p}:${mtime}`);
10973
10919
  }
10974
- return createHash10("sha256").update(parts.join("|")).digest("hex");
10920
+ return createHash9("sha256").update(parts.join("|")).digest("hex");
10975
10921
  }
10976
10922
  function writeCache(targetDir, key, result) {
10977
10923
  try {
10978
- const cacheDir = join43(targetDir, ".loki", "state");
10924
+ const cacheDir = join42(targetDir, ".loki", "state");
10979
10925
  mkdirSync13(cacheDir, { recursive: true });
10980
- const cachePath = join43(cacheDir, "project-graph.json");
10981
- writeFileSync15(cachePath, JSON.stringify({ key, result }, null, 2), "utf8");
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 = join43(absTarget, ".loki", "app.json");
10987
- const parentDir = dirname13(absTarget);
10988
- const parentManifest = join43(parentDir, ".loki", "app.json");
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 = join43(m, ".loki", "app.json");
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 MAX_SPEC_BYTES, MAX_TOKEN_BUDGET = 1e9, norm3 = (p) => p.replace(/^\.\//, ""), CTRL, strs = (v) => Array.isArray(v) && v.every((x) => typeof x === "string" && !CTRL.test(x)) ? v.map(norm3) : null, memo, inWriteSet = (spec, f) => spec.writeSet.some((w) => w.endsWith("/") ? f.startsWith(w) : f === w);
11172
- var init_unit_mode = __esm(() => {
11173
- MAX_SPEC_BYTES = 1024 * 1024;
11174
- CTRL = /[\x00-\x1f\x7f]/;
11175
- memo = new Map;
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 readFileSync31 } from "fs";
11217
- import { dirname as dirname14, join as join44 } from "path";
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(readFileSync31(p, "utf-8"));
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(dirname14(p), { recursive: true });
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) => join44(repoDir, ".loki", "memory", "semantic", "pr-lessons.json");
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 readFileSync32 } from "fs";
11262
- import { resolve as resolvePath, dirname as dirname15 } from "path";
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 = dirname15(fileURLToPath3(import.meta.url));
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 readFileSync32(p, "utf8");
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 readFileSync33, writeFileSync as writeFileSync16 } from "fs";
11352
- import { join as join45 } from "path";
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 = join45(runDir, ROUTE_RECORD_FILE);
11187
+ const p = join44(runDir, ROUTE_RECORD_FILE);
11356
11188
  if (!existsSync26(p) || !lstatSync9(p).isFile())
11357
11189
  return;
11358
- const v = JSON.parse(readFileSync33(p, "utf8"));
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 readFileSync34, renameSync as renameSync8, rmSync as rmSync11, writeFileSync as writeFileSync17 } from "fs";
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(readFileSync34(path, "utf8"));
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
- writeFileSync17(tmp, JSON.stringify({ runs: runs2 }));
11399
- renameSync8(tmp, target);
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 dirname16, join as join46, resolve as resolve14 } from "path";
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(dirname16(fileURLToPath4(import.meta.url)), "..", "..", "..", "data", "router-shape-defaults.json");
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 join47 } from "path";
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: join47(repoDir, tc.cwd), timeoutMs: opts.timeoutMs, ...opts.path ? { env: { PATH: opts.path } } : {} });
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: join47(repoDir, tc.cwd), ...opts.path ? { env: { PATH: opts.path } } : {} });
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 writeFileSync18 } from "fs";
11632
- import { join as join48 } from "path";
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) => join48(ctx.repoDir, f))], { cwd: ctx.repoDir, timeoutMs: 30000 });
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 = join48(ctx.runDir, "deep-comment.md");
11771
- writeFileSync18(bodyFile, buildCommentBody(checks, notProven, statusState), "utf8");
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
- writeFileSync18(join48(ctx.runDir, "receipt-addendum-1.json"), JSON.stringify(addendum, null, 2) + `
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 dirname17, isAbsolute as isAbsolute6, join as join49, relative as relative5 } from "path";
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 = [join49(repoDir, ".venv", "bin", bin), join49(repoDir, "venv", "bin", bin), ...venvEnv && inRepo(venvEnv) ? [join49(venvEnv, "bin", bin)] : []].find(existsSync29);
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", `./${dirname17(t.path)}`]];
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(join49(tmpdir8(), "e10-base-"));
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(join49(repoDir, "scripts", "select-tests.sh"));
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(join49(g.cwd, "tsconfig.json")))
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(join49(g.cwd, f))))
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 readdirSync14, readFileSync as readFileSync35 } from "fs";
12185
- import { dirname as dirname18, join as join50 } from "path";
12186
- function parseJsonc(text3) {
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 < text3.length) {
12189
- const c = text3[i], n2 = text3[i + 1];
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 < text3.length && text3[j] !== '"')
12193
- j += text3[j] === "\\" ? 2 : 1;
12194
- out2 += text3.slice(i, j + 1);
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 < text3.length && text3[i] !== `
12029
+ while (i < text2.length && text2[i] !== `
12198
12030
  `)
12199
12031
  i++;
12200
12032
  } else if (c === "/" && n2 === "*") {
12201
- const e = text3.indexOf("*/", i + 2);
12202
- i = e < 0 ? text3.length : e + 2;
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 = readJson5(file);
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 = join50(dirname18(file), ext.endsWith(".json") ? ext : `${ext}.json`);
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 = readdirSync14(pkgDir).filter((f) => f.endsWith(".json")).sort((x, y) => x.length - y.length || x.localeCompare(y));
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 = readJson5(join50(pkgDir, n2));
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(join50(pkgDir, n2));
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 readJson5 = (p) => {
12090
+ var readJson4 = (p) => {
12259
12091
  try {
12260
- const v = parseJsonc(readFileSync35(p, "utf8"));
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 readFileSync36, readdirSync as readdirSync15, realpathSync as realpathSync18, rmSync as rmSync13, writeFileSync as writeFileSync19 } from "fs";
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 dirname19, isAbsolute as isAbsolute7, join as join51, relative as relative6 } from "path";
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 : join51(repoDir, 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(join51(repoDir, `${rel}.py`)) || existsSync31(join51(repoDir, rel, "__init__.py"));
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 ?? join51(ctx.runDir, "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(readFileSync36(issueJsonPath, "utf8"));
12414
- const text3 = [issue.title, issue.body].filter((s) => typeof s === "string" && s.length > 0).join(`
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 (text3)
12418
- return text3;
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 ? join51(repoDir, dirname19(first.path)) : join51(repoDir, "tests");
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(join51(ctx.repoDir, pkg?.root ?? "."), pkg?.runner ?? null);
12457
- const cwd = mkdtempSync7(join51(tmpdir9(), "loki-e15-wall-"));
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
- writeFileSync19(join51(cwd, n2), c, "utf8");
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 = readdirSync15(cwd).filter((f) => f.startsWith(WALL_PREFIX));
12476
- const sealedDir = join51(ctx.runDir, "wall");
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 = readFileSync36(join51(cwd, name), "utf8"), bad = conventionViolation(conv2, name, content);
12483
- writeFileSync19(join51(sealedDir, name), content, "utf8");
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 = join51(targetDir, name), runner = guessRunner(name, runners);
12504
- writeFileSync19(dest, content, "utf8");
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 = join51(ctx.repoDir, t.path);
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 readFileSync37, realpathSync as realpathSync19, rmdirSync, unlinkSync as unlinkSync4, writeFileSync as writeFileSync20 } from "fs";
12565
- import { dirname as dirname20, join as join52, relative as relative7, sep as sep11 } from "path";
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 = join52(root, f), rel = relative7(root, dirname20(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 = join52(cur, part);
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() && readFileSync37(fp).equals(want)) {
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
- writeFileSync20(fd, want);
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, sha3) {
12612
- const r = safeGitSpawn(repoDir, ["cat-file", "blob", sha3], { maxBuffer: 1 << 28 });
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 ${sha3} failed`);
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 = join52(repoDir, f);
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 [sha3, mode] = v.split(" "), want = catBlob(repoDir, sha3);
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(join52(repoDir, f));
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 dirname21 } from "path";
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) && dirname21(m) === dirname21(f)) && /(^|\/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|bun\.lockb?|poetry\.lock|Cargo\.lock|go\.sum)$/.test(f));
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 dirname22 } from "path";
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 text3 = `${plan}
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(text3), plannedDirs = new Set(rel.map((r) => dirname22(r)).filter((d) => d !== "."));
12705
- return staged.filter(({ st, f }) => st !== "A" && !isTestFile(f) && !Object.hasOwn(pre, f) && !rel.includes(f) && !mentions(text3, f) && !mentions(text3, basename18(f)) && !plannedDirs.has(dirname22(f)) && !dirSegs(f).some((d) => toks.has(d))).map(({ f }) => f);
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 = (text3, name) => new RegExp(`(?<![\\w./-])${esc2(name)}(?![\\w-]|\\.\\w)`).test(text3), STOP, stem = (w) => w.length > 3 && w.endsWith("s") ? w.slice(0, -1) : w, surfaceTokens = (text3) => new Set((text3.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()));
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 readFileSync38, statSync as statSync17, unlinkSync as unlinkSync5, writeFileSync as writeFileSync21 } from "fs";
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 dirname23, join as join53 } from "path";
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 || join53(process.env["HOME"] || homedir8(), ".loki", "keys", RECEIPT_SIGNER_BASENAME);
12578
+ const file = given || join52(process.env["HOME"] || homedir8(), ".loki", "keys", RECEIPT_SIGNER_BASENAME);
12743
12579
  try {
12744
- pem = readFileSync38(file);
12580
+ pem = readFileSync37(file);
12745
12581
  if (!given) {
12746
- for (const [f, m] of [[file, 384], [dirname23(file), 448]])
12747
- if (statSync17(f).mode & 63)
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(dirname23(dirname23(file)), { recursive: true, mode: 448 });
12754
- mkdirSync20(dirname23(file), { recursive: true, mode: 448 });
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
- writeFileSync21(tmp, generateKeyPairSync("ed25519").privateKey.export({ type: "pkcs8", format: "pem" }), { flag: "wx", mode: 384 });
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 = readFileSync38(file);
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 readdirSync16, readFileSync as readFileSync39, writeFileSync as writeFileSync22 } from "fs";
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 dirname24, isAbsolute as isAbsolute8, join as join54, normalize as normalize2, relative as relative8, sep as sep12 } from "path";
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(join54(runDir, rel)) });
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 = join54(runDir, s.path);
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 = join54(cur, seg);
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 = join54(repoDir, f);
12699
+ const p = join53(repoDir, f);
12864
12700
  if (!existsSync32(p))
12865
12701
  continue;
12866
12702
  try {
12867
- const txt = readFileSync39(p, "utf8");
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 = join54(runDir, relDir, "e2e");
12717
+ const dir = join53(runDir, relDir, "e2e");
12882
12718
  mkdirSync21(dir, { recursive: true });
12883
- writeFileSync22(join54(dir, "walk.spec.cjs"), e2eSpecSource(pkg, base, routes));
12884
- writeFileSync22(join54(dir, "playwright.config.cjs"), `module.exports = { testDir: ".", testMatch: "walk.spec.cjs", outputDir: "./out", reporter: "null", use: { video: "on", trace: "on" } };
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", join54(dir, "playwright.config.cjs")], repoDir, ms, signal))
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 readdirSync16(d, { withFileTypes: true })) {
12891
- const full = join54(d, e.name);
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(join54(relDir, "e2e", relative8(dir, full)));
12731
+ rels.push(join53(relDir, "e2e", relative8(dir, full)));
12896
12732
  }
12897
12733
  };
12898
- walk(join54(dir, "out"));
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 ? join54(repoDir, boot.boot.cwd) : repoDir;
12968
- const pkgPath = join54(appDir, "package.json");
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(readFileSync39(pkgPath, "utf8")));
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 = join54(runDir, "evidence");
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 = join54("evidence", randomBytes4(6).toString("hex"));
13006
- mkdirSync21(join54(runDir, rel0));
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 = join54(rel0, `${screenName(route)}.png`);
13012
- const ok = await shoot(pw, ["screenshot", `${base}${route}`, join54(runDir, rel)], appDir, left(), signal);
13013
- if (ok && !aborted() && !isSymlink(join54(runDir, rel)) && existsSync32(join54(runDir, rel)))
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 = join54(evRoot, randomBytes4(6).toString("hex"));
12874
+ const hdir = join53(evRoot, randomBytes4(6).toString("hex"));
13039
12875
  mkdirSync21(hdir);
13040
- writeFileSync22(join54(hdir, "http.json"), JSON.stringify(rows, null, 2) + `
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(dirname24(receiptPath), receipt["evidence_screens"]);
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(readFileSync39(p)).digest("hex"), playwrightBin = (repoDir) => {
13066
- const bin = join54(repoDir, "node_modules", ".bin", "playwright");
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 = join54(repoDir, "node_modules", "@playwright", "test");
13070
- return existsSync32(join54(d, "package.json")) ? d : null;
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 readdirSync17, readFileSync as readFileSync40 } from "fs";
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 join55 } from "path";
12939
+ import { join as join54 } from "path";
13104
12940
  function agentDirs(repoDir, env = process.env) {
13105
- return [env["LOKI_AGENTS_PROJECT_DIR"] || join55(repoDir, ".loki", "agents"), env["LOKI_AGENTS_USER_DIR"] || join55(env["XDG_CONFIG_HOME"] || join55(homedir9(), ".config"), "loki", "agents")];
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(readFileSync40(file, "utf8"));
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 = readdirSync17(d).filter((n2) => n2.endsWith(".md") && !n2.startsWith(".")).sort();
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(join55(d, n2), n2.slice(0, -3));
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 readFileSync41 } from "fs";
13151
- import { join as join56 } from "path";
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 = join56(repoDir, f);
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(readFileSync41(p, "utf8"));
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 readFileSync42, rmSync as rmSync14, writeFileSync as writeFileSync23 } from "fs";
13304
- import { dirname as dirname25, join as join57 } from "path";
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 join57(repoDir, ".loki", "contract.json");
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 = readFileSync42(p);
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 = join57(".loki", "state", "requirements-map.json");
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 existsSync36, readFileSync as readFileSync43, statSync as statSync18 } from "fs";
13427
- import { basename as basename19, join as join58 } from "path";
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(basename19(path));
13571
+ return MANIFESTS.test(basename20(path));
13440
13572
  }
13441
13573
  function readDeclared(repoDir) {
13442
13574
  const p = join58(repoDir, ".loki", DECLARED_FILE);
13443
- if (!existsSync36(p))
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 (!existsSync36(p))
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 createHash14 } from "crypto";
13671
- import { existsSync as existsSync37, readdirSync as readdirSync18, mkdirSync as mkdirSync23, readFileSync as readFileSync44, writeFileSync as writeFileSync24 } from "fs";
13672
- import { basename as basename20, isAbsolute as isAbsolute9, join as join59, relative as relative9 } from "path";
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) => createHash14("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) => {
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) => basename20(String(f.path))));
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(existsSync37(eventsPath) ? readFileSync44(eventsPath) : ""),
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
- writeFileSync24(path, JSON.stringify(receipt, null, 2) + `
14119
+ writeFileSync25(path, JSON.stringify(receipt, null, 2) + `
13989
14120
  `);
13990
- writeFileSync24(join59(ctx.runDir, "receipt.md"), renderReceiptMd(receipt));
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 existsSync38, readdirSync as readdirSync19, readFileSync as readFileSync46, statSync as statSync20 } from "fs";
14097
- import { dirname as dirname27, join as join60 } from "path";
14098
- import { createHash as createHash15, createPublicKey as createPublicKey4, verify as verify3 } from "crypto";
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 === createHash15("sha256").digest("hex"))
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 (!existsSync38(path))
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 = createHash15("sha256");
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 = createHash15("sha256").update(lines.slice(0, done + 1).join(`
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 (!existsSync38(receiptPath))
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 existsSync40, readFileSync as readFileSync49, statSync as statSync21 } from "fs";
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`). Accepted unconditionally; runtime behavior is gated by LOKI_WORKSPACES=1.",
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 existsSync39, readFileSync as readFileSync48 } from "fs";
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 (existsSync39(f))
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) => existsSync40(join63(d, "index.html")));
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) && existsSync40(f) && statSync21(f).isFile())
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);