loki-mode 11.4.2 → 11.5.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 (100) hide show
  1. package/SKILL.md +2 -2
  2. package/VERSION +1 -1
  3. package/autonomy/lib/chat.sh +6 -3
  4. package/autonomy/lib/engine10-push.sh +19 -1
  5. package/autonomy/lib/help-core.sh +1 -1
  6. package/autonomy/lib/proof-generator.py +23 -5
  7. package/autonomy/lib/proof-verify.py +607 -5
  8. package/autonomy/lib/run-summary.sh +17 -1
  9. package/autonomy/lib/setup-requirements.json +35 -0
  10. package/autonomy/loki +232 -36
  11. package/autonomy/provider-offer.sh +95 -47
  12. package/autonomy/route.sh +38 -6
  13. package/autonomy/run.sh +42 -14
  14. package/autonomy/setup-wizard.sh +19 -10
  15. package/autonomy/verify.sh +40 -1
  16. package/completions/_loki +3 -1
  17. package/completions/loki.bash +9 -3
  18. package/dashboard/__init__.py +1 -1
  19. package/docs/CLI-REFERENCE.md +3 -1
  20. package/docs/EVALUATING.md +27 -0
  21. package/docs/HARNESS-INTELLIGENCE-PLAN.md +20 -0
  22. package/docs/INSTALLATION.md +1 -1
  23. package/docs/KNOWN-ISSUES.md +10 -1
  24. package/docs/PROOF-PASSPORT.md +114 -0
  25. package/docs/alternative-installations.md +103 -0
  26. package/docs/cost-controls.md +139 -0
  27. package/docs/environment-variables.md +36 -0
  28. package/docs/exit-codes.md +102 -2
  29. package/docs/spec-first-intent.md +29 -0
  30. package/docs/v10/CLI-MODERN.md +2 -2
  31. package/docs/v10/ENGINE.md +32 -0
  32. package/loki-ts/data/model-pricing.json +1 -0
  33. package/loki-ts/dist/loki.js +1095 -1043
  34. package/mcp/__init__.py +1 -1
  35. package/package.json +2 -2
  36. package/packages/control-plane/dist/server.js +1721 -707
  37. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  38. package/plugins/loki-mode/README.md +41 -1
  39. package/plugins/loki-mode/commands/handoff.md +12 -0
  40. package/plugins/loki-mode/commands/loki-verify.md +9 -2
  41. package/plugins/loki-mode/commands/start.md +20 -0
  42. package/plugins/loki-mode/hooks/hooks.json +11 -0
  43. package/plugins/loki-mode/scripts/loki-stop-verify.sh +84 -0
  44. package/web-app/dist/assets/{AdminPage-CYJ2BWRC.js → AdminPage-Cbu3pXL8.js} +1 -1
  45. package/web-app/dist/assets/{Avatar-DdK4wynI.js → Avatar-DGqGGcGx.js} +1 -1
  46. package/web-app/dist/assets/{Badge-CrX3MI7J.js → Badge-Bhlipt6v.js} +1 -1
  47. package/web-app/dist/assets/{Button-709-wwGM.js → Button-CpN2sO61.js} +1 -1
  48. package/web-app/dist/assets/{CockpitPage-BapdTInO.js → CockpitPage-BqeDJwdL.js} +1 -1
  49. package/web-app/dist/assets/{ComparePage-DT99pGvA.js → ComparePage-DUieA2ba.js} +1 -1
  50. package/web-app/dist/assets/{ErrorBoundary-B0uJSys8.js → ErrorBoundary-DTWsYrOm.js} +1 -1
  51. package/web-app/dist/assets/{EvidenceReceiptPanel-BtMFgElP.js → EvidenceReceiptPanel-BU_B9X19.js} +1 -1
  52. package/web-app/dist/assets/{GitHubIssuesPanel-DjJuU941.js → GitHubIssuesPanel-DEZoLOsP.js} +1 -1
  53. package/web-app/dist/assets/{GitHubPRsPanel-HXfEX1BC.js → GitHubPRsPanel-BEsnrq7Y.js} +1 -1
  54. package/web-app/dist/assets/{HomePage-Cqyves-S.js → HomePage-BoUVuq7h.js} +2 -2
  55. package/web-app/dist/assets/{LoginPage-jUbtC7_Y.js → LoginPage-CmOED7vb.js} +1 -1
  56. package/web-app/dist/assets/{MagicPage-DHRsqjgR.js → MagicPage-DATZitrZ.js} +1 -1
  57. package/web-app/dist/assets/{MetricsPage-B-pED05R.js → MetricsPage-DGL1v0I-.js} +1 -1
  58. package/web-app/dist/assets/{NotFoundPage-CsbUs21R.js → NotFoundPage-C2WgOjZd.js} +1 -1
  59. package/web-app/dist/assets/{ProjectPage-BtlLEQwB.js → ProjectPage-BMi1tepj.js} +3 -3
  60. package/web-app/dist/assets/{ProjectsPage-DaRbRjSp.js → ProjectsPage-vc3y5YPh.js} +1 -1
  61. package/web-app/dist/assets/{SettingsPage-DALrtP3F.js → SettingsPage-kbq0Ftvi.js} +1 -1
  62. package/web-app/dist/assets/{ShowcasePage-CoPHSNP0.js → ShowcasePage-Bn6Q8Kbg.js} +1 -1
  63. package/web-app/dist/assets/{SystemSettingsPage-kOuSN50O.js → SystemSettingsPage-Basmhs_b.js} +1 -1
  64. package/web-app/dist/assets/{TeamsPage-DGWK0LMp.js → TeamsPage-BTqOc4TR.js} +1 -1
  65. package/web-app/dist/assets/{TemplatesPage-C-_10CwA.js → TemplatesPage-2P9002VL.js} +1 -1
  66. package/web-app/dist/assets/{TerminalOutput-Cz_vPbXL.js → TerminalOutput-CAoSPBrg.js} +1 -1
  67. package/web-app/dist/assets/{activity-icIsXJVa.js → activity-BcWVWCqU.js} +1 -1
  68. package/web-app/dist/assets/{bell-DbPR2_4r.js → bell-CYRqqgZ6.js} +1 -1
  69. package/web-app/dist/assets/{bot-DvjP3Yh5.js → bot-CU7gdn3g.js} +1 -1
  70. package/web-app/dist/assets/{check-D1OBxHeU.js → check-DLlCpz9V.js} +1 -1
  71. package/web-app/dist/assets/{chevron-left-D09jDZ29.js → chevron-left-CE9Cb30C.js} +1 -1
  72. package/web-app/dist/assets/{circle-alert-DyZMLOcC.js → circle-alert-uou4bjua.js} +1 -1
  73. package/web-app/dist/assets/{clock-CdpdJTId.js → clock-C_dSJcDX.js} +1 -1
  74. package/web-app/dist/assets/{cloud-CoLTlmoj.js → cloud-DZ22ITF6.js} +1 -1
  75. package/web-app/dist/assets/{code-xml-DrkE2ZZY.js → code-xml-BrJS0hhS.js} +1 -1
  76. package/web-app/dist/assets/{database-CMQQuM2R.js → database-D2HOmxtl.js} +1 -1
  77. package/web-app/dist/assets/{dollar-sign-CuioDaOG.js → dollar-sign-CQ1vK_6q.js} +1 -1
  78. package/web-app/dist/assets/{file-code-corner-Cx9j9K1S.js → file-code-corner-w2vpGm5d.js} +1 -1
  79. package/web-app/dist/assets/{file-plus-CYD2zaaI.js → file-plus-DlF6wjkD.js} +1 -1
  80. package/web-app/dist/assets/{globe-6w-hnQkL.js → globe-Dy3lBJg1.js} +1 -1
  81. package/web-app/dist/assets/{hammer-BpqtautL.js → hammer-C3xIiRXN.js} +1 -1
  82. package/web-app/dist/assets/{index-Dzs-9EgJ.js → index-4t-_IW2y.js} +3 -3
  83. package/web-app/dist/assets/{layers-D5hd7jb7.js → layers-Y8Fs8qXI.js} +1 -1
  84. package/web-app/dist/assets/{loader-circle-C6Y9x_7H.js → loader-circle-CxgN1v4m.js} +1 -1
  85. package/web-app/dist/assets/{lock-D51L7rYh.js → lock-DFFNbXDs.js} +1 -1
  86. package/web-app/dist/assets/{package-BJF8hkP8.js → package-5e6qCTUg.js} +1 -1
  87. package/web-app/dist/assets/{plus-D5kUQ79n.js → plus-C0Go_ytj.js} +1 -1
  88. package/web-app/dist/assets/{refresh-cw-BKdlCa7F.js → refresh-cw-D4i-NW3o.js} +1 -1
  89. package/web-app/dist/assets/{rotate-ccw-_bd_YI1e.js → rotate-ccw-YlKkiUW6.js} +1 -1
  90. package/web-app/dist/assets/{scroll-text-DbkegIxF.js → scroll-text-4qXOHTap.js} +1 -1
  91. package/web-app/dist/assets/{server-DAwqFIsq.js → server-BB6zXNp9.js} +1 -1
  92. package/web-app/dist/assets/{shield-alert-BuR1tPHu.js → shield-alert-D4tzjB1H.js} +1 -1
  93. package/web-app/dist/assets/{thumbs-up-BF6p3mRd.js → thumbs-up-DZiRwdFj.js} +1 -1
  94. package/web-app/dist/assets/{trash-2-BVpnkqqz.js → trash-2-Dv_LkRIK.js} +1 -1
  95. package/web-app/dist/assets/{trending-down-DpsDvRwW.js → trending-down-BJYp9PQe.js} +1 -1
  96. package/web-app/dist/assets/{trending-up-mFogTjt3.js → trending-up-BTcXLklK.js} +1 -1
  97. package/web-app/dist/assets/{upload-4T8zpBsi.js → upload-fcHqwOxr.js} +1 -1
  98. package/web-app/dist/assets/{usePolling-DPXQv8WO.js → usePolling-BeJYw_4L.js} +1 -1
  99. package/web-app/dist/assets/{user-BYGIFaTm.js → user-BcDwUCsO.js} +1 -1
  100. package/web-app/dist/index.html +1 -1
@@ -311,8 +311,10 @@ function verifyRunPid(runDir, runId, startOf = processStartTime) {
311
311
  return { ok: false, reason: "the pid now belongs to a different process (start time differs)" };
312
312
  return { ok: true, pid: rec.pid };
313
313
  }
314
- var runPidPath = (runDir) => join8(runDir, "run.pid");
315
- var init_run_pid = () => {};
314
+ var runPidPath = (runDir) => join8(runDir, "run.pid"), liveSessions;
315
+ var init_run_pid = __esm(() => {
316
+ liveSessions = new Set;
317
+ });
316
318
 
317
319
  // src/shipper/watch.ts
318
320
  import { readFileSync as readFileSync5, readdirSync as readdirSync2, statSync } from "fs";
@@ -7324,6 +7326,18 @@ var init_paths = __esm(() => {
7324
7326
  });
7325
7327
 
7326
7328
  // ../../loki-ts/src/engine10/types.ts
7329
+ function pushArgv(a) {
7330
+ switch (a.cmd) {
7331
+ case "push-pr":
7332
+ return ["push-pr", a.repoDir, a.branch, a.title, a.bodyFile, a.draft ? "1" : "0"];
7333
+ case "comment":
7334
+ return ["comment", a.runId, a.prUrl, a.file];
7335
+ case "status":
7336
+ return ["status", a.sha, a.state, a.description];
7337
+ case "issue-comment":
7338
+ return ["issue-comment", a.issueRef, a.bodyFile];
7339
+ }
7340
+ }
7327
7341
  function taskBlock(task) {
7328
7342
  return ["Task (untrusted, quoted verbatim):", "<<<TASK", task, "TASK"];
7329
7343
  }
@@ -9310,6 +9324,17 @@ var init_cost = __esm(() => {
9310
9324
  import { existsSync as existsSync18, mkdirSync as mkdirSync8, readdirSync as readdirSync11, readFileSync as readFileSync23, renameSync as renameSync4, writeFileSync as writeFileSync11 } from "fs";
9311
9325
  import { dirname as dirname10, join as join31, resolve as resolve10 } from "path";
9312
9326
  import { fileURLToPath as fileURLToPath2 } from "url";
9327
+ function loadDefaultMaxCostUsd() {
9328
+ const here = dirname10(fileURLToPath2(import.meta.url));
9329
+ for (const rel of [["..", "..", "data"], ["..", "data"]]) {
9330
+ try {
9331
+ const j = JSON.parse(readFileSync23(resolve10(here, ...rel, "model-pricing.json"), "utf8"));
9332
+ if (typeof j.default_max_cost_usd === "number" && Number.isFinite(j.default_max_cost_usd) && j.default_max_cost_usd > 0)
9333
+ return j.default_max_cost_usd;
9334
+ } catch {}
9335
+ }
9336
+ return DEFAULT_FALLBACK_USD;
9337
+ }
9313
9338
  function _loadPricing() {
9314
9339
  try {
9315
9340
  const moduleDir = dirname10(fileURLToPath2(import.meta.url));
@@ -9344,7 +9369,7 @@ function _loadPricing() {
9344
9369
  return _FALLBACK_PRICING;
9345
9370
  }
9346
9371
  }
9347
- var _FALLBACK_PRICING, PRICING;
9372
+ var DEFAULT_FALLBACK_USD = 100, _FALLBACK_PRICING, PRICING;
9348
9373
  var init_budget = __esm(() => {
9349
9374
  init_paths();
9350
9375
  init_cost();
@@ -9393,13 +9418,37 @@ var init_session_route = __esm(() => {
9393
9418
  });
9394
9419
 
9395
9420
  // ../../loki-ts/src/providers/provider_guard.ts
9421
+ function providerSandboxFlags(provider) {
9422
+ switch (provider) {
9423
+ case "codex":
9424
+ return ["--sandbox", "workspace-write"];
9425
+ case "aider":
9426
+ return ["--no-auto-commits"];
9427
+ default:
9428
+ return [];
9429
+ }
9430
+ }
9431
+ var E10_COMMON = "loki-ts/src/engine10/session.ts (detached spawn, killGroupWithGrace, recordCost, watchBudget), loki-ts/src/providers/provider_guard.ts, loki-ts/src/e10ext/budget_cap.ts", U = "unknown", CAPABILITIES;
9396
9432
  var init_provider_guard = __esm(() => {
9397
9433
  init_safe_git();
9434
+ CAPABILITIES = [
9435
+ { provider: "claude", engine: "engine10", invocation: "Agent SDK query() (default) or claude CLI via loki-ts/src/runner/providers.ts", cost: "measured", budgetKill: "post-iteration", cancelProcessGroup: "yes", sandboxFlags: [], receipt: "yes", resume: "yes", guardScan: "native", killBlocking: "native", source: `${E10_COMMON}; loki-ts/src/runner/providers.ts (LOKI_E10_RESUME_SESSION, claude only)` },
9436
+ { provider: "codex", engine: "engine10", invocation: "codex exec --sandbox workspace-write --skip-git-repo-check", cost: "estimated", budgetKill: "post-iteration", cancelProcessGroup: "yes", sandboxFlags: providerSandboxFlags("codex"), receipt: "yes", resume: "no", guardScan: "post-iteration", killBlocking: "none", source: `${E10_COMMON}; loki-ts/src/providers/provider_cost.ts (ESTIMATED_PROVIDERS); loki-ts/src/runner/providers.ts codexProvider` },
9437
+ { provider: "cline", engine: "engine10", invocation: "cline -y", cost: "estimated", budgetKill: "post-iteration", cancelProcessGroup: "yes", sandboxFlags: providerSandboxFlags("cline"), receipt: "yes", resume: "no", guardScan: "post-iteration", killBlocking: "none", source: `${E10_COMMON}; loki-ts/src/providers/provider_cost.ts; providers/cline.sh` },
9438
+ { provider: "aider", engine: "engine10", invocation: "aider --yes-always", cost: "estimated", budgetKill: "post-iteration", cancelProcessGroup: "yes", sandboxFlags: providerSandboxFlags("aider"), receipt: "yes", resume: "no", guardScan: "post-iteration", killBlocking: "none", source: `${E10_COMMON}; loki-ts/src/providers/provider_cost.ts (a reported "Cost: $X session" line is used as-is); providers/aider.sh` },
9439
+ { provider: "opencode", engine: "engine10", invocation: "opencode run --auto [-m provider/model]", cost: "none", budgetKill: "none", cancelProcessGroup: "yes", sandboxFlags: providerSandboxFlags("opencode"), receipt: "yes", resume: "no", guardScan: "post-iteration", killBlocking: "none", source: `${E10_COMMON}; loki-ts/src/runner/provider_opencode.ts (costMeasured false); loki-ts/src/providers/provider_cost.ts (opencode not in ESTIMATED_PROVIDERS); docs/v10/GUIDE.md provider table` },
9440
+ { provider: "claude", engine: "legacy", invocation: "claude --dangerously-skip-permissions (bash loop)", cost: U, budgetKill: U, cancelProcessGroup: U, sandboxFlags: U, receipt: U, resume: U, guardScan: U, killBlocking: U, source: "providers/claude.sh (PROVIDER_AUTONOMOUS_FLAG); autonomy/run.sh (LOKI_BUDGET_LIMIT); other fields not confirmed" },
9441
+ { provider: "codex", engine: "legacy", invocation: "codex exec --sandbox workspace-write --skip-git-repo-check (bash loop)", cost: U, budgetKill: U, cancelProcessGroup: U, sandboxFlags: ["--sandbox", "workspace-write"], receipt: U, resume: U, guardScan: U, killBlocking: U, source: "providers/codex.sh (PROVIDER_AUTONOMOUS_FLAG); other fields not confirmed" },
9442
+ { provider: "cline", engine: "legacy", invocation: "cline -y (bash loop)", cost: U, budgetKill: U, cancelProcessGroup: U, sandboxFlags: U, receipt: U, resume: U, guardScan: U, killBlocking: U, source: "providers/cline.sh (PROVIDER_AUTONOMOUS_FLAG); other fields not confirmed" },
9443
+ { provider: "aider", engine: "legacy", invocation: "aider --yes-always (bash loop)", cost: U, budgetKill: U, cancelProcessGroup: U, sandboxFlags: U, receipt: U, resume: U, guardScan: U, killBlocking: U, source: "providers/aider.sh (PROVIDER_AUTONOMOUS_FLAG); other fields not confirmed" },
9444
+ { provider: "opencode", engine: "legacy", invocation: "opencode run --auto (bash loop)", cost: U, budgetKill: U, cancelProcessGroup: U, sandboxFlags: U, receipt: U, resume: U, guardScan: U, killBlocking: U, source: "providers/opencode.sh (PROVIDER_AUTONOMOUS_FLAG); other fields not confirmed" }
9445
+ ];
9398
9446
  });
9399
9447
 
9400
9448
  // ../../loki-ts/src/engine10/session.ts
9401
9449
  var STDERR_TAIL_BYTES, ADVISOR_MARKED_STAGES;
9402
9450
  var init_session = __esm(() => {
9451
+ init_run_pid();
9403
9452
  init_provider_cost();
9404
9453
  init_model_routes();
9405
9454
  init_cost();
@@ -10129,8 +10178,39 @@ var init_runner_errors = __esm(() => {
10129
10178
  ];
10130
10179
  });
10131
10180
 
10181
+ // ../../loki-ts/src/engine10/testmap.ts
10182
+ import { basename as basename12, extname, join as join38, relative as relative3, sep as sep10 } from "path";
10183
+ function isTestFile(rel) {
10184
+ const name = basename12(rel);
10185
+ return JS_TEST_RE.test(name) || PY_TEST_RE.test(name) || GO_TEST_RE.test(name);
10186
+ }
10187
+ var SKIP_DIRS, JS_TEST_RE, PY_TEST_RE, GO_TEST_RE;
10188
+ var init_testmap = __esm(() => {
10189
+ init_resolve();
10190
+ init_scope();
10191
+ SKIP_DIRS = new Set([
10192
+ ".git",
10193
+ "node_modules",
10194
+ "dist",
10195
+ "build",
10196
+ "target",
10197
+ "coverage",
10198
+ ".venv",
10199
+ "venv",
10200
+ "__pycache__",
10201
+ ".tox",
10202
+ ".pytest_cache",
10203
+ ".loki",
10204
+ ".next"
10205
+ ]);
10206
+ JS_TEST_RE = /\.(test|spec)\.[cm]?[jt]sx?$/;
10207
+ PY_TEST_RE = /^(test_.+|.+_test)\.py$/;
10208
+ GO_TEST_RE = /_test\.go$/;
10209
+ });
10210
+
10132
10211
  // ../../loki-ts/src/util/check_result.ts
10133
- import { basename as basename12 } from "path";
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";
10134
10214
  function plainTestEnv(base = process.env) {
10135
10215
  const e = {};
10136
10216
  for (const [k, v] of Object.entries(tokenFreeEnv(base)))
@@ -10148,7 +10228,7 @@ function ran(raw2, path, ok) {
10148
10228
  if (blk) {
10149
10229
  const c = n2(blk, /(?:#|\u2139) pass (\d+)/) + n2(blk, /(?:#|\u2139) fail (\d+)/);
10150
10230
  const nm = out2.match(/^(?:ok \d+ - |\u2714 )(\S+\.[cm]?[jt]s)(?: \(|$)/m)?.[1];
10151
- return c === 1 && nm && (!path || basename12(nm) === basename12(path)) ? 0 : c;
10231
+ return c === 1 && nm && (!path || basename13(nm) === basename13(path)) ? 0 : c;
10152
10232
  }
10153
10233
  const cg = cargoTrailer(out2);
10154
10234
  if (cg.length)
@@ -10239,16 +10319,16 @@ function goRunner(cmd, args) {
10239
10319
  let k = 0;
10240
10320
  for (;k < t.length; k++) {
10241
10321
  const x = t[k];
10242
- if (/^[A-Za-z_]\w*=/.test(x) || /^(?:env|command|exec|time|nohup)$/.test(basename12(x)))
10322
+ if (/^[A-Za-z_]\w*=/.test(x) || /^(?:env|command|exec|time|nohup)$/.test(basename13(x)))
10243
10323
  continue;
10244
- if (/^-/.test(x) && k > 0 && basename12(t[k - 1]) === "env") {
10324
+ if (/^-/.test(x) && k > 0 && basename13(t[k - 1]) === "env") {
10245
10325
  if (x === "-u" || x === "-C" || x === "-S")
10246
10326
  k++;
10247
10327
  continue;
10248
10328
  }
10249
10329
  break;
10250
10330
  }
10251
- if (t[k] !== undefined && basename12(t[k]) === "go")
10331
+ if (t[k] !== undefined && basename13(t[k]) === "go")
10252
10332
  return { runner: "go" };
10253
10333
  }
10254
10334
  return {};
@@ -10329,31 +10409,163 @@ function classifyCheck(i) {
10329
10409
  return { result: "not_run", reason: UNMEASURED_REASON };
10330
10410
  return { result: "pass", n: n2 };
10331
10411
  }
10412
+ function summaryOf(a) {
10413
+ const why = a.tier === a.computed ? a.reasons.slice(0, 2).join("; ") : `computed ${a.computed}; override ${a.override?.from} to ${a.override?.to}: ${a.override?.reason}`;
10414
+ const def = a.checks_deferred;
10415
+ return `risk: ${a.tier} (${why}), ${def.length ? def.join(", ") : "no deeper checks"} not run`;
10416
+ }
10417
+ function markExecuted(a, executed) {
10418
+ const checks_deferred = deferredOf(a.tier, a.checks_selected, executed);
10419
+ return { ...a, checks_deferred, summary: summaryOf({ ...a, checks_deferred }) };
10420
+ }
10421
+ function classifyRisk(files, env = process.env) {
10422
+ const lines = files.reduce((n2, f) => n2 + f.added + f.deleted, 0);
10423
+ const sensitive = files.flatMap((f) => {
10424
+ const hit = SENSITIVE.find(([, re]) => re.test(f.path));
10425
+ return hit && !isTestFile(f.path) ? [`${f.path} (${hit[0]})`] : [];
10426
+ });
10427
+ const testFiles = files.filter((f) => isTestFile(f.path));
10428
+ const testsDeleted = testFiles.filter((f) => f.status === "deleted").map((f) => f.path);
10429
+ const testsModified = [...testFiles.filter((f) => f.status !== "added" && f.status !== "deleted").map((f) => f.path), ...files.filter((f) => TEST_CFG.test(f.path)).map((f) => f.path)];
10430
+ const api = files.filter((f) => API.test(f.path) && !isTestFile(f.path)).map((f) => f.path);
10431
+ const high = [], med = [];
10432
+ if (sensitive.length)
10433
+ high.push(`sensitive paths: ${sensitive.slice(0, 5).join(", ")}${sensitive.length > 5 ? ` (+${sensitive.length - 5})` : ""}`);
10434
+ if (testsDeleted.length)
10435
+ high.push(`test files deleted: ${testsDeleted.join(", ")}`);
10436
+ if (api.length)
10437
+ high.push(`public API surface: ${api.slice(0, 3).join(", ")}`);
10438
+ if (files.length >= FILES_HIGH)
10439
+ high.push(`${files.length} files >= ${FILES_HIGH}`);
10440
+ if (lines >= LINES_HIGH)
10441
+ high.push(`${lines} changed lines >= ${LINES_HIGH}`);
10442
+ if (testsModified.length)
10443
+ med.push(`existing tests or test config modified: ${testsModified.slice(0, 3).join(", ")}`);
10444
+ if (files.length >= FILES_MEDIUM)
10445
+ med.push(`${files.length} files >= ${FILES_MEDIUM}`);
10446
+ if (lines >= LINES_MEDIUM)
10447
+ med.push(`${lines} changed lines >= ${LINES_MEDIUM}`);
10448
+ const computed = high.length ? "high" : med.length ? "medium" : "low";
10449
+ const reasons = high.length ? [...high, ...med] : med.length ? med : [`${files.length} file${files.length === 1 ? "" : "s"}, no sensitive paths`];
10450
+ let tier = computed, override, ignored;
10451
+ const asked = (env["LOKI_RISK_TIER"] ?? "").trim().toLowerCase();
10452
+ if (asked in RANK2 && asked !== computed) {
10453
+ const reason = (env["LOKI_RISK_OVERRIDE_REASON"] ?? "").trim();
10454
+ if (RANK2[asked] > RANK2[computed]) {
10455
+ tier = asked;
10456
+ override = { from: computed, to: asked, reason: reason || "raised by LOKI_RISK_TIER" };
10457
+ } else if (reason) {
10458
+ tier = asked;
10459
+ override = { from: computed, to: asked, reason };
10460
+ } else
10461
+ ignored = `LOKI_RISK_TIER=${asked} ignored: lowering from ${computed} needs LOKI_RISK_OVERRIDE_REASON`;
10462
+ }
10463
+ const plan = PLAN[tier], checks_deferred = deferredOf(tier, plan.selected, []);
10464
+ const summary = summaryOf({ tier, computed, reasons, ...override ? { override } : {}, checks_deferred });
10465
+ return {
10466
+ version: 1,
10467
+ tier,
10468
+ computed,
10469
+ reasons,
10470
+ stats: { files: files.length, lines, sensitive, tests_modified: testsModified, tests_deleted: testsDeleted, api },
10471
+ checks_selected: plan.selected,
10472
+ checks_deferred,
10473
+ ...override ? { override } : {},
10474
+ ...ignored ? { override_ignored: ignored } : {},
10475
+ summary
10476
+ };
10477
+ }
10478
+ function changedFiles(repoDir, baseSha) {
10479
+ const run = (args) => safeGit(repoDir, args).split(`
10480
+ `).map((l) => l.trim()).filter(Boolean);
10481
+ const tracked = run(["diff", "--name-only", baseSha]);
10482
+ const untracked = run(["ls-files", "--others", "--exclude-standard"]);
10483
+ return [...new Set([...tracked, ...untracked])].filter((f) => !f.startsWith(".loki/"));
10484
+ }
10485
+ function diffFiles(repoDir, baseSha) {
10486
+ const paths = changedFiles(repoDir, baseSha), stat = new Map;
10487
+ for (const l of safeGit(repoDir, ["diff", "--numstat", baseSha]).split(`
10488
+ `)) {
10489
+ const [a, d, ...p] = l.split("\t"), path = p.join("\t");
10490
+ if (path)
10491
+ stat.set(path, { path, added: Number(a) || 0, deleted: Number(d) || 0 });
10492
+ }
10493
+ for (const l of safeGit(repoDir, ["diff", "--name-status", baseSha]).split(`
10494
+ `)) {
10495
+ const [s, ...p] = l.split("\t"), f = stat.get(p[p.length - 1] ?? "");
10496
+ if (f)
10497
+ f.status = s?.startsWith("A") ? "added" : s?.startsWith("D") ? "deleted" : "modified";
10498
+ }
10499
+ return paths.map((path) => {
10500
+ const f = stat.get(path);
10501
+ if (f)
10502
+ return f;
10503
+ let n2 = 0;
10504
+ try {
10505
+ n2 = readFileSync28(join39(repoDir, path), "utf8").split(`
10506
+ `).length;
10507
+ } catch {}
10508
+ return { path, added: n2, deleted: 0, status: "added" };
10509
+ });
10510
+ }
10511
+ function recordRisk(repoDir, a) {
10512
+ 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) + `
10516
+ `);
10517
+ renameSync5(`${p}.tmp`, p);
10518
+ return p;
10519
+ } catch {
10520
+ return null;
10521
+ }
10522
+ }
10332
10523
  var NO_TESTS_REASON = "no tests executed", GO_EXIT0_REASON = "test count could not be confirmed: go test output is produced by the code under test and cannot confirm execution (a Go exit 0 is never a pass)", UNCONFIRMED_REASON = "test count could not be confirmed", FAIL_EVIDENCE, GO_FAIL_EVIDENCE, UNMEASURED_REASON = "executed count unmeasured (Loki could not parse the runner summary, harness-owned)", stripAnsi = (s) => s.replace(/\u001b\][^\u0007\u001b]*(?:\u0007|\u001b\\)/g, "").replace(/(?:\u001b\[|\u009b)[0-9;?]*[ -\/]*[@-~]/g, "").replace(/\r\n?/g, `
10333
10524
  `), tailLines = (out2) => out2.split(`
10334
- `).filter((x) => x.trim()).slice(-12), GO_PKG_RE, isExecutedProof = (c) => c.result === "pass" && typeof c.n === "number" && c.n > 0, hasExecutedProof = (checks) => checks.some(isExecutedProof);
10525
+ `).filter((x) => x.trim()).slice(-12), GO_PKG_RE, isExecutedProof = (c) => c.result === "pass" && typeof c.n === "number" && c.n > 0, hasExecutedProof = (checks) => checks.some(isExecutedProof), SENSITIVE, API, TEST_CFG, RANK2, FILES_MEDIUM = 4, FILES_HIGH = 15, LINES_MEDIUM = 100, LINES_HIGH = 500, RAN_ALWAYS, PLAN, LOW_SKIPPED, deferredOf = (tier, selected, executed) => (tier === "low" ? LOW_SKIPPED : selected).filter((c) => !RAN_ALWAYS.includes(c) && !executed.includes(c));
10335
10526
  var init_check_result = __esm(() => {
10527
+ init_testmap();
10336
10528
  init_safe_git();
10337
10529
  FAIL_EVIDENCE = /\[(?:build|setup) failed\]|^--- FAIL|^[\w./-]+\.go:\d+:\d+: \S|\b[1-9]\d* (?:failed|errors?)\b/m;
10338
10530
  GO_FAIL_EVIDENCE = /^FAIL\t\S+\t[\d.]+s$|^panic: /m;
10339
10531
  GO_PKG_RE = /^(?:ok|FAIL|\?)\s+\S+\s+(?:\(cached\)|[\d.]+s\b|\[(?:no test files|build failed|setup failed)\])/;
10532
+ SENSITIVE = [
10533
+ ["auth", /(^|\/)(auth|oauth|sso|session|login|permission|rbac|acl)[\w.-]*(\/|\.|$)/i],
10534
+ ["crypto", /(^|\/)(crypt|crypto|jwt|signing|keys?|secrets?|tokens?|credential|password)[\w.-]*(\/|\.|$)/i],
10535
+ ["payments", /(^|\/)(payments?|billing|checkout|stripe|invoice)[\w.-]*(\/|\.|$)/i],
10536
+ ["migration", /(^|\/)(migrations?|alembic)\/|\.sql$/i],
10537
+ ["ci", /(^|\/)(\.github\/(workflows|actions)|\.gitlab-ci\.yml|\.circleci|Jenkinsfile|azure-pipelines)/i],
10538
+ ["lockfile", /(^|\/)(package-lock\.json|pnpm-lock\.yaml|bun\.lockb?|go\.sum|[\w-]+\.lock)$/],
10539
+ ["infra", /(^|\/)(Dockerfile[\w.-]*|docker-compose[\w.-]*\.ya?ml|terraform|helm|k8s|kubernetes|infra|deploy)(\/|\.|$)|\.tf$/i],
10540
+ ["env", /(^|\/)\.env[\w.]*$/]
10541
+ ];
10542
+ API = /(^|\/)(openapi|swagger)[\w.-]*\.(ya?ml|json)$|\.proto$|\.d\.ts$|(^|\/)(api|routes|public)\/|(^|\/)index\.(ts|js|py)$/i;
10543
+ TEST_CFG = /(^|\/)(conftest\.py|\.?pytest\.(ini|toml)|tox\.ini|jest\.config\.[\w.]+|vitest\.config\.[\w.]+)$/;
10544
+ RANK2 = { low: 0, medium: 1, high: 2 };
10545
+ RAN_ALWAYS = ["targeted tests", "lint of changed files"];
10546
+ PLAN = {
10547
+ low: { selected: [...RAN_ALWAYS] },
10548
+ medium: { selected: [...RAN_ALWAYS, "full test command", "one reviewer"] },
10549
+ high: { selected: [...RAN_ALWAYS, "full test command", "full suite", "council", "security scan"] }
10550
+ };
10551
+ LOW_SKIPPED = ["full test command", "reviewer", "council", "security scan"];
10340
10552
  });
10341
10553
 
10342
10554
  // ../../loki-ts/src/runner/load_owner.ts
10343
10555
  import { spawnSync as spawnSync3 } from "child_process";
10344
10556
  import { mkdtempSync as mkdtempSync5, realpathSync as realpathSync15, rmSync as rmSync8 } from "fs";
10345
10557
  import { tmpdir as tmpdir7 } from "os";
10346
- import { basename as basename13, extname, join as join38 } from "path";
10558
+ import { basename as basename14, extname as extname2, join as join40 } from "path";
10347
10559
  function changedFilesNamed(out2, repoDir, changed) {
10348
10560
  return changed.filter((f) => {
10349
- if (out2.includes(f) || out2.includes(join38(repoDir, f)))
10561
+ if (out2.includes(f) || out2.includes(join40(repoDir, f)))
10350
10562
  return true;
10351
10563
  const segs = f.split("/");
10352
10564
  if (suffixes(segs, 2).some((x) => x !== f && bounded(out2, x, "(?![\\w-])")))
10353
10565
  return true;
10354
- if (extname(f) === ".go" && segs.length > 1 && suffixes(segs.slice(0, -1), 1).some((d) => new RegExp(`(?<=[\\w-])/${esc(d)}(?![\\w./-])`).test(out2)))
10566
+ if (extname2(f) === ".go" && segs.length > 1 && suffixes(segs.slice(0, -1), 1).some((d) => new RegExp(`(?<=[\\w-])/${esc(d)}(?![\\w./-])`).test(out2)))
10355
10567
  return true;
10356
- const stem = basename13(f, extname(f));
10568
+ const stem = basename14(f, extname2(f));
10357
10569
  if (stem.length < 2 || stem === "index" || stem === "__init__")
10358
10570
  return false;
10359
10571
  return new RegExp(`(?<![\\w-])${esc(stem)}(?![\\w-])`).test(out2);
@@ -10457,7 +10669,7 @@ async function loadErrorIsHarnessOwned(i) {
10457
10669
  return false;
10458
10670
  if (i.args.some((a) => changed.includes(a.replace(/^\.\//, ""))))
10459
10671
  return false;
10460
- const dir = mkdtempSync5(join38(tmpdir7(), "e10-loadown-"));
10672
+ const dir = mkdtempSync5(join40(tmpdir7(), "e10-loadown-"));
10461
10673
  const git3 = (args) => {
10462
10674
  safeGit(i.repoDir, args, { stdio: "ignore" });
10463
10675
  };
@@ -10488,38 +10700,8 @@ var init_load_owner = __esm(() => {
10488
10700
  init_check_result();
10489
10701
  });
10490
10702
 
10491
- // ../../loki-ts/src/engine10/testmap.ts
10492
- import { basename as basename14, extname as extname2, join as join39, relative as relative3, sep as sep10 } from "path";
10493
- function isTestFile(rel) {
10494
- const name = basename14(rel);
10495
- return JS_TEST_RE.test(name) || PY_TEST_RE.test(name) || GO_TEST_RE.test(name);
10496
- }
10497
- var SKIP_DIRS, JS_TEST_RE, PY_TEST_RE, GO_TEST_RE;
10498
- var init_testmap = __esm(() => {
10499
- init_resolve();
10500
- init_scope();
10501
- SKIP_DIRS = new Set([
10502
- ".git",
10503
- "node_modules",
10504
- "dist",
10505
- "build",
10506
- "target",
10507
- "coverage",
10508
- ".venv",
10509
- "venv",
10510
- "__pycache__",
10511
- ".tox",
10512
- ".pytest_cache",
10513
- ".loki",
10514
- ".next"
10515
- ]);
10516
- JS_TEST_RE = /\.(test|spec)\.[cm]?[jt]sx?$/;
10517
- PY_TEST_RE = /^(test_.+|.+_test)\.py$/;
10518
- GO_TEST_RE = /_test\.go$/;
10519
- });
10520
-
10521
10703
  // ../../loki-ts/src/util/wall_owned.ts
10522
- import { isAbsolute as isAbsolute4, join as join40, relative as relative4 } from "path";
10704
+ import { isAbsolute as isAbsolute4, join as join41, relative as relative4 } from "path";
10523
10705
  function failingLocations(raw2, cwd, repoDir) {
10524
10706
  const out2 = raw2.replace(ANSI2, "").replace(/\r\n?/g, `
10525
10707
  `), files = new Set;
@@ -10551,7 +10733,7 @@ function failingLocations(raw2, cwd, repoDir) {
10551
10733
  }
10552
10734
  if (errors2 === 0 || located !== errors2)
10553
10735
  return null;
10554
- return [...files].map((f) => relative4(repoDir, isAbsolute4(f) ? f : join40(cwd, f)));
10736
+ return [...files].map((f) => relative4(repoDir, isAbsolute4(f) ? f : join41(cwd, f)));
10555
10737
  }
10556
10738
  function wallOwnedFailure(raw2, cwd, repoDir, wall) {
10557
10739
  const locs = failingLocations(raw2, cwd, repoDir);
@@ -10562,108 +10744,1220 @@ var init_wall_owned = __esm(() => {
10562
10744
  ANSI2 = /\u001b\[[0-9;?]*[ -/]*[@-~]/g;
10563
10745
  });
10564
10746
 
10565
- // ../../loki-ts/src/engine10/stages/verify.ts
10566
- import { existsSync as existsSync22, mkdtempSync as mkdtempSync6, realpathSync as realpathSync16, rmSync as rmSync9 } from "fs";
10567
- import { tmpdir as tmpdir8 } from "os";
10568
- import { dirname as dirname12, isAbsolute as isAbsolute5, join as join41, relative as relative5 } from "path";
10569
- function resolveTool(repoDir, bin, fallback, lastResort = fallback) {
10570
- const inRepo = (p) => {
10571
- try {
10572
- const r = relative5(realpathSync16(repoDir), realpathSync16(p));
10573
- return r !== "" && !r.startsWith("..") && !isAbsolute5(r);
10574
- } catch {
10575
- return false;
10576
- }
10577
- };
10578
- const venvEnv = process.env["VIRTUAL_ENV"];
10579
- const project = [join41(repoDir, ".venv", "bin", bin), join41(repoDir, "venv", "bin", bin), ...venvEnv && inRepo(venvEnv) ? [join41(venvEnv, "bin", bin)] : []].find(existsSync22);
10580
- return project ? [project, "project"] : [Bun.which(fallback) ? fallback : lastResort, "system"];
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);
10581
10775
  }
10582
- function runnerCmd(t, repoDir) {
10583
- switch (t.runner) {
10584
- case "pytest": {
10585
- const [cmd, interpreter] = resolveTool(repoDir, "python", "python3", "python");
10586
- return [cmd, ["-m", "pytest", "-q", t.path], interpreter];
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 {}
10587
10786
  }
10588
- case "vitest":
10589
- return ["npx", ["vitest", "run", t.path]];
10590
- case "jest":
10591
- return ["npx", ["jest", t.path]];
10592
- case "bun":
10593
- return ["bun", ["test", t.path]];
10594
- case "node":
10595
- return ["node", ["--test", `./${t.path}`]];
10596
- case "npm":
10597
- return ["npm", ["test", "--silent"]];
10598
- case "go":
10599
- return ["go", ["test", "-json", `./${dirname12(t.path)}`]];
10600
- case "cargo":
10601
- return ["cargo", ["test"]];
10602
10787
  }
10603
10788
  }
10604
- function commandFor(t, repoDir, api) {
10605
- const site = siteFor(api, repoDir, t.path);
10606
- const [cmd, args, interpreter] = runnerCmd(site ? { runner: t.runner, path: site.file } : t, repoDir);
10607
- return { cwd: site?.cwd ?? repoDir, cmd, args, argv: [cmd, ...args], ...interpreter ? { interpreter } : {}, pkgRoot: site?.root ?? "." };
10789
+ function atomicWriteJson(target, data) {
10790
+ durableWriteThenRename(target, `${JSON.stringify(data, null, 2)}
10791
+ `);
10608
10792
  }
10609
- function changedFiles(repoDir, baseSha) {
10610
- const run = (args) => safeGit(repoDir, args).split(`
10611
- `).map((l) => l.trim()).filter(Boolean);
10612
- const tracked = run(["diff", "--name-only", baseSha]);
10613
- const untracked = run(["ls-files", "--others", "--exclude-standard"]);
10614
- return [...new Set([...tracked, ...untracked])].filter((f) => !f.startsWith(".loki/"));
10793
+ var _tmpCounter = 0, _appendChains;
10794
+ var init_atomic = __esm(() => {
10795
+ _appendChains = new Map;
10796
+ });
10797
+
10798
+ // ../../loki-ts/src/runner/state.ts
10799
+ var TERMINAL_STATUSES;
10800
+ var init_state = __esm(() => {
10801
+ init_paths();
10802
+ init_atomic();
10803
+ TERMINAL_STATUSES = new Set([
10804
+ "failed",
10805
+ "max_iterations_reached",
10806
+ "max_retries_exceeded",
10807
+ "exited",
10808
+ "council_approved",
10809
+ "council_force_approved",
10810
+ "completion_promise_fulfilled",
10811
+ "running"
10812
+ ]);
10813
+ });
10814
+
10815
+ // ../../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";
10818
+ function loadProfile(repoDir) {
10819
+ try {
10820
+ const p = JSON.parse(readFileSync29(commandProfilePath(repoDir), "utf8"));
10821
+ return p?.version === 1 && Array.isArray(p.commands) && p.baseline ? p : null;
10822
+ } catch {
10823
+ return null;
10824
+ }
10615
10825
  }
10616
- function testConfigChanged(repoDir, baseSha, changed) {
10617
- const diff = (f) => safeGit(repoDir, ["diff", "-U0", baseSha, "--", f]);
10618
- return changed.filter((f) => CFG_ALWAYS.test(f) || CFG_SHARED.test(f) && (() => {
10619
- const d = diff(f);
10620
- return !d || CFG_LINE.test(d);
10621
- })());
10826
+ function attribute(repoDir, baseSha, failing) {
10827
+ const p = loadProfile(repoDir), none = { preExistingChecks: [], preExistingIds: [], introducedChecks: failing.map((f) => f.name), line: null };
10828
+ if (!p || p.revision !== baseSha || !p.baseline.attributable || p.baseline.failing_ids.length === 0 || failing.length === 0)
10829
+ return none;
10830
+ const base = new Set(p.baseline.failing_ids), pre = failing.filter((f) => f.eligible && f.ids?.length && f.ids.every((i) => base.has(i)));
10831
+ const introduced = failing.filter((f) => !pre.includes(f)).map((f) => f.name);
10832
+ if (pre.length === 0)
10833
+ return { ...none, line: `baseline: ${base.size} known failure(s) before this run; none of the failing checks match them, ${introduced.length} introduced (blocking)` };
10834
+ return {
10835
+ preExistingChecks: pre.map((f) => f.name),
10836
+ preExistingIds: pre.flatMap((f) => f.ids ?? []),
10837
+ introducedChecks: introduced,
10838
+ line: `baseline: ${pre.length} pre-existing failing check(s) (not blocking), ${introduced.length} introduced${introduced.length ? " (blocking)" : ""}`
10839
+ };
10622
10840
  }
10623
- async function runOnce(cmd, args, cwd, signal, opts) {
10624
- if (!Bun.which(cmd, { PATH: opts.path ?? process.env["PATH"] ?? "" }))
10625
- return { ok: false, missing: true, cut: false, out: "" };
10626
- const timeout = AbortSignal.timeout(opts.timeoutMs ?? CHECK_TIMEOUT_MS);
10627
- const proc = Bun.spawn([cmd, ...args], {
10628
- cwd,
10629
- stdin: opts.stdin !== undefined ? Buffer.from(opts.stdin) : "ignore",
10630
- stdout: "pipe",
10631
- stderr: "pipe",
10632
- signal: AbortSignal.any([signal, timeout]),
10633
- env: opts.path ? { ...plainTestEnv(), PATH: opts.path } : plainTestEnv()
10634
- });
10635
- let tail = "";
10636
- const rs = [proc.stdout, proc.stderr].map((s) => s.getReader());
10637
- const pumps = rs.map(async (r) => {
10638
- const d = new TextDecoder;
10639
- for (;; ) {
10640
- const c = await r.read().catch(() => ({ done: true, value: undefined }));
10641
- if (c.done)
10642
- return;
10643
- tail = (tail + d.decode(c.value, { stream: true })).slice(-65536);
10644
- }
10645
- });
10646
- const exitCode = await proc.exited;
10647
- await Promise.race([Promise.all(pumps), new Promise((r) => setTimeout(r, 300))]);
10648
- rs.forEach((r) => r.cancel().catch(() => {}));
10649
- const cut = timeout.aborted || signal.aborted;
10650
- return { ok: exitCode === 0 && !cut, missing: false, cut, out: cut ? "" : stripAnsi(tail) };
10841
+ function attributeFullSuite(repoDir, baseSha, full, blocked, changed) {
10842
+ 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);
10844
+ if (!bad.length || !p || p.revision !== baseSha || !p.baseline.attributable || !p.baseline.failing_ids.length)
10845
+ return none;
10846
+ if (bad.some((c) => norm3(c.cmd) !== norm3(p.baseline.command ?? "")))
10847
+ return { ...none, line: `baseline: ran "${p.baseline.command}", not the full suite command, ids not comparable, full suite failures not excused` };
10848
+ const block = new Set(blocked);
10849
+ 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))) })));
10651
10850
  }
10652
- function firstError(out2) {
10653
- const goOut = (l2) => {
10654
- try {
10655
- const e = JSON.parse(l2);
10656
- return typeof e.Action === "string" ? e.Action === "output" || e.Action === "build-output" ? e.Output ?? "" : "" : l2;
10657
- } catch {
10658
- return l2;
10659
- }
10851
+ var commandProfilePath = (repoDir) => join42(repoDir, ".loki", "state", "repo-profile.json");
10852
+ var init_repo_profile = __esm(() => {
10853
+ init_failures();
10854
+ init_check_result();
10855
+ init_safe_git();
10856
+ init_paths();
10857
+ init_state();
10858
+ });
10859
+
10860
+ // ../../loki-ts/src/project_graph.ts
10861
+ import { createHash as createHash10 } from "crypto";
10862
+ import {
10863
+ existsSync as existsSync23,
10864
+ readdirSync as readdirSync13,
10865
+ readFileSync as readFileSync30,
10866
+ statSync as statSync16,
10867
+ writeFileSync as writeFileSync15,
10868
+ mkdirSync as mkdirSync13
10869
+ } from "fs";
10870
+ import { basename as basename16, dirname as dirname13, join as join43, resolve as resolve12 } from "path";
10871
+ function readManifest(path) {
10872
+ if (!existsSync23(path)) {
10873
+ return null;
10874
+ }
10875
+ let raw2;
10876
+ try {
10877
+ raw2 = readFileSync30(path, "utf8");
10878
+ } catch {
10879
+ return null;
10880
+ }
10881
+ let parsed;
10882
+ try {
10883
+ parsed = JSON.parse(raw2);
10884
+ } catch {
10885
+ return null;
10886
+ }
10887
+ if (typeof parsed !== "object" || parsed === null) {
10888
+ return null;
10889
+ }
10890
+ const obj = parsed;
10891
+ if (obj["schema_version"] !== SUPPORTED_SCHEMA_VERSION) {
10892
+ console.warn(`[loki:project_graph] unsupported schema_version in ${path}: ` + `${String(obj["schema_version"])} (expected ${SUPPORTED_SCHEMA_VERSION})`);
10893
+ return null;
10894
+ }
10895
+ const appId = obj["app_id"];
10896
+ if (typeof appId !== "string" || !APP_ID_REGEX.test(appId)) {
10897
+ console.warn(`[loki:project_graph] invalid app_id in ${path}: ${String(appId)}`);
10898
+ return null;
10899
+ }
10900
+ const members = Array.isArray(obj["members"]) ? obj["members"].filter((m) => typeof m === "string") : [];
10901
+ const sharedMemoryDir = typeof obj["shared_memory_dir"] === "string" ? obj["shared_memory_dir"] : undefined;
10902
+ return {
10903
+ schema_version: SUPPORTED_SCHEMA_VERSION,
10904
+ app_id: appId,
10905
+ members,
10906
+ shared_memory_dir: sharedMemoryDir
10660
10907
  };
10661
- const lines = out2.slice(-65536).split(`
10662
- `).map((l2) => (l2.startsWith("{") ? goOut(l2) : l2).trim()).filter(Boolean), l = lines.find((x) => /^(FAILED\s|\u25cf\s.*\u203a|not ok\s|_{3,}\s.+\s_{3,}$)/.test(x)) ?? lines.find((x) => /^[\w./-]+\.go:\d+:\d+: \S/.test(x)) ?? lines.find((x) => /fail|error/i.test(x) && !/^(=|\u2713|ok\b|PASS)/.test(x)) ?? "";
10663
- return l.replace(/\d{4}-\d\d-\d\dT[\d:.]+Z?/g, "").replace(/(^|\s)\/(?:[\w.@-]+\/)*[\w.@-]+/g, "$1<path>").replace(/:\d+(?::\d+)?/g, "").replace(/\[?\d+(?:\.\d+)?m?s\]?/g, "").replace(/\s+/g, " ").slice(0, 160);
10664
10908
  }
10665
- async function runCheck(ctx, name, cmd, args, signal, checks, opts = {}) {
10666
- const started = Date.now();
10909
+ function resolveMembers(rootDir, declared, selfBasename) {
10910
+ const out2 = [];
10911
+ const seen = new Set;
10912
+ let children;
10913
+ try {
10914
+ children = readdirSync13(rootDir);
10915
+ } catch {
10916
+ children = [];
10917
+ }
10918
+ const matchPattern = (pattern, name) => {
10919
+ if (!pattern.includes("*") && !pattern.includes("?")) {
10920
+ return pattern === name;
10921
+ }
10922
+ const re = new RegExp("^" + pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".") + "$");
10923
+ return re.test(name);
10924
+ };
10925
+ for (const name of declared) {
10926
+ for (const child of children) {
10927
+ if (!matchPattern(name, child))
10928
+ continue;
10929
+ const full = join43(rootDir, child);
10930
+ if (seen.has(full))
10931
+ continue;
10932
+ let st;
10933
+ try {
10934
+ st = statSync16(full);
10935
+ } catch {
10936
+ continue;
10937
+ }
10938
+ if (!st.isDirectory())
10939
+ continue;
10940
+ seen.add(full);
10941
+ out2.push(full);
10942
+ }
10943
+ }
10944
+ if (declared.length === 0) {
10945
+ for (const child of children) {
10946
+ const full = join43(rootDir, child);
10947
+ if (seen.has(full))
10948
+ continue;
10949
+ let st;
10950
+ try {
10951
+ st = statSync16(full);
10952
+ } catch {
10953
+ continue;
10954
+ }
10955
+ if (!st.isDirectory())
10956
+ continue;
10957
+ if (!existsSync23(join43(full, ".loki", "app.json")))
10958
+ continue;
10959
+ seen.add(full);
10960
+ out2.push(full);
10961
+ }
10962
+ }
10963
+ return out2;
10964
+ }
10965
+ function cacheKey(manifestPaths) {
10966
+ const parts = [];
10967
+ for (const p of manifestPaths.sort()) {
10968
+ let mtime = 0;
10969
+ try {
10970
+ mtime = statSync16(p).mtimeMs;
10971
+ } catch {}
10972
+ parts.push(`${p}:${mtime}`);
10973
+ }
10974
+ return createHash10("sha256").update(parts.join("|")).digest("hex");
10975
+ }
10976
+ function writeCache(targetDir, key, result) {
10977
+ try {
10978
+ const cacheDir = join43(targetDir, ".loki", "state");
10979
+ mkdirSync13(cacheDir, { recursive: true });
10980
+ const cachePath = join43(cacheDir, "project-graph.json");
10981
+ writeFileSync15(cachePath, JSON.stringify({ key, result }, null, 2), "utf8");
10982
+ } catch {}
10983
+ }
10984
+ function discoverProjectGraph(targetDir) {
10985
+ 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");
10989
+ const examined = [];
10990
+ let chosenManifest = null;
10991
+ let chosenRoot = "";
10992
+ if (existsSync23(parentManifest) && parentDir !== absTarget) {
10993
+ examined.push(parentManifest);
10994
+ chosenManifest = readManifest(parentManifest);
10995
+ chosenRoot = parentDir;
10996
+ }
10997
+ if (!chosenManifest && existsSync23(targetManifest)) {
10998
+ examined.push(targetManifest);
10999
+ chosenManifest = readManifest(targetManifest);
11000
+ chosenRoot = absTarget;
11001
+ }
11002
+ if (!chosenManifest)
11003
+ return null;
11004
+ const declared = chosenManifest.members ?? [];
11005
+ const members = resolveMembers(chosenRoot, declared, basename16(absTarget));
11006
+ const filtered = [];
11007
+ for (const m of members) {
11008
+ const sibManifestPath = join43(m, ".loki", "app.json");
11009
+ if (existsSync23(sibManifestPath)) {
11010
+ examined.push(sibManifestPath);
11011
+ const sibManifest = readManifest(sibManifestPath);
11012
+ if (sibManifest && sibManifest.app_id !== chosenManifest.app_id) {
11013
+ continue;
11014
+ }
11015
+ }
11016
+ filtered.push(m);
11017
+ }
11018
+ const result = {
11019
+ appId: chosenManifest.app_id,
11020
+ root: chosenRoot,
11021
+ members: filtered,
11022
+ 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;
11170
+ }
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;
11176
+ });
11177
+
11178
+ // ../../loki-ts/src/e10ext/repomemory.ts
11179
+ var init_repomemory = __esm(() => {
11180
+ init_cache();
11181
+ });
11182
+
11183
+ // ../../loki-ts/src/e10ext/context.ts
11184
+ var FINISH_LINE = "Finish with exactly one line: LOKI_DONE, or LOKI_ALREADY_DONE: <file:line evidence>, or LOKI_SPEC_CONFLICT: <reason>.", FIXED_RULES;
11185
+ var init_context = __esm(() => {
11186
+ init_cache();
11187
+ init_sizing();
11188
+ init_unit_mode();
11189
+ init_repomemory();
11190
+ init_repo_profile();
11191
+ FIXED_RULES = [
11192
+ "You are the Loki 10 implement stage, doing the complete task described below in this repository. Do whatever a senior engineer would do to finish it correctly: read, change and test as needed across any files the task requires.",
11193
+ "Rules:",
11194
+ "- The Wall tests are read-only: do not edit or delete them. Existing test files are append-only: you may add new test functions, but never edit or delete an existing one.",
11195
+ "- Exception: when the task text itself states the new expected value of an existing assertion, change only that literal in that assertion; never remove, skip or loosen an assertion, and never edit one the task text does not name.",
11196
+ "- Run any tests you need, including the package's full suite (the Project Model commands below say how). The impacted tests named below are a starting hint, not a limit.",
11197
+ "- Never leave a long-lived server running.",
11198
+ "- Never kill processes.",
11199
+ "- Write no documentation unless the task explicitly asks for it.",
11200
+ "- Do not commit or push.",
11201
+ "- If you add a new third-party registry dependency, list it in .loki/supply-declared.json as a JSON array of {ecosystem,name,version_spec,registry}, leaving out workspace, path, git and local packages.",
11202
+ FINISH_LINE
11203
+ ].join(`
11204
+ `);
11205
+ });
11206
+
11207
+ // ../../loki-ts/src/util/steer.ts
11208
+ var STEER_MAX_BYTES, STEER_STAGES;
11209
+ var init_steer = __esm(() => {
11210
+ init_context();
11211
+ STEER_MAX_BYTES = 1024 * 1024;
11212
+ STEER_STAGES = new Set(["plan", "implement"]);
11213
+ });
11214
+
11215
+ // ../../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";
11218
+ function loadLessons(repoDir) {
11219
+ const p = lessonsPath(repoDir);
11220
+ if (!existsSync24(p))
11221
+ return [];
11222
+ try {
11223
+ const j = JSON.parse(readFileSync31(p, "utf-8"));
11224
+ return Array.isArray(j.lessons) ? j.lessons : [];
11225
+ } catch {
11226
+ return [];
11227
+ }
11228
+ }
11229
+ function save(repoDir, lessons) {
11230
+ const p = lessonsPath(repoDir);
11231
+ mkdirSync14(dirname14(p), { recursive: true });
11232
+ atomicWriteJson(p, { version: 2, lessons });
11233
+ }
11234
+ function recordRunVerdict(repoDir, runId, verdict) {
11235
+ const lessons = loadLessons(repoDir);
11236
+ let dirty = false;
11237
+ for (const l of lessons)
11238
+ for (const u of l.uses)
11239
+ if (u.run_id === runId && u.verdict === null) {
11240
+ u.verdict = verdict;
11241
+ dirty = true;
11242
+ }
11243
+ if (dirty)
11244
+ save(repoDir, lessons);
11245
+ }
11246
+ var lessonsPath = (repoDir) => join44(repoDir, ".loki", "memory", "semantic", "pr-lessons.json");
11247
+ var init_pr_lessons = __esm(() => {
11248
+ init_atomic();
11249
+ });
11250
+
11251
+ // ../../loki-ts/src/runner/model_downgrades.ts
11252
+ var init_model_downgrades = __esm(() => {
11253
+ init_sizing();
11254
+ init_decision();
11255
+ });
11256
+
11257
+ // ../../loki-ts/src/providers/mcp_config.ts
11258
+ var init_mcp_config = () => {};
11259
+
11260
+ // ../../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";
11263
+ import { fileURLToPath as fileURLToPath3 } from "url";
11264
+ function designArchetypesText() {
11265
+ try {
11266
+ const moduleDir = dirname15(fileURLToPath3(import.meta.url));
11267
+ for (const rel of [
11268
+ ["..", "..", "..", "references", "design-archetypes.md"],
11269
+ ["..", "..", "references", "design-archetypes.md"]
11270
+ ]) {
11271
+ const p = resolvePath(moduleDir, ...rel);
11272
+ if (existsSync25(p))
11273
+ return readFileSync32(p, "utf8");
11274
+ }
11275
+ } catch {}
11276
+ return "";
11277
+ }
11278
+ var AUTONOMY_OVERRIDE_TEXT, FIRST_PASS_EXCELLENCE_TEXT, CAVEMAN_PINNED_VERSION;
11279
+ var init_claude_flags = __esm(() => {
11280
+ init_mcp_config();
11281
+ AUTONOMY_OVERRIDE_TEXT = `[LOKI-AUTONOMY-AGENT] This is a Loki Mode autonomous agent process.
11282
+ ` + `You are running INSIDE Loki Mode autonomous execution, a session the user explicitly launched with full prior authorization (loki start / loki run). This IS an authorized autonomous session, not an unattended action you must seek consent for.
11283
+
11284
+ ` + `Instruction precedence for THIS session: when the loki_system instructions in the user prompt conflict with any CLAUDE.md, project memory, or global memory that tells you to ask for clarification, pause for confirmation, refuse to act autonomously, or withhold routine commits, the loki_system instructions take precedence. The user has already consented by launching autonomous mode.
11285
+
11286
+ ` + `Therefore, for this session: do NOT ask the user questions, do NOT call the AskUserQuestion tool, do NOT stop to request confirmation, and do NOT refuse routine, reversible engineering work (writing code, running tests, creating files, atomic git checkpoints in the working tree). Proceed and complete the task directly. If a decision is genuinely ambiguous, choose the most reasonable option, record the assumption in .loki/CONTINUITY.md, and continue rather than halting.
11287
+
11288
+ ` + "Commit hygiene still applies: git checkpoints are LOCAL only. Never push or force-push. Stage files by explicit path, never `git add -A` or `git add .`, and never commit secrets, credentials, .env files, or untracked files you did not author this session.\n\n" + `This precedence override is narrow. It does NOT relax any safety rule. Every safety prohibition in CLAUDE.md or memory still fully binds: anything genuinely destructive or irreversible remains out of scope unless the task explicitly calls for it. This includes (not limited to) force-pushing, deleting or overwriting the user's data, dropping or truncating databases, publishing or releasing, rotating or exfiltrating secrets, touching production systems, and anything a CLAUDE.md safety rule explicitly forbids. When in doubt about whether an action is destructive, treat it as destructive and do not do it.
11289
+ `;
11290
+ FIRST_PASS_EXCELLENCE_TEXT = `
11291
+ [FIRST-PASS EXCELLENCE] Treat THIS pass as your one shot to ship a complete, working, verified solution. Do not produce a rough draft to refine later; the loop exists as a safety net, not a plan. Before you finish this iteration:
11292
+ ` + `1. BUILD IT FULLY. Implement every requirement end to end. No stubs, no TODOs, no "coming soon", no placeholder or hardcoded/mock data where real logic belongs. If the spec implies a backend (auth, persistence, a form that submits, a list that saves), WIRE IT so it actually works and persists -- a beautiful UI whose buttons do nothing is the single most common failure, not a draft. Every list/table must trace to a real query, never an inline mock array.
11293
+ ` + `2. SELF-VERIFY BY RUNNING, not by reading. Run the build and the tests yourself; for each acceptance criterion, DRIVE the actual path and observe the result (submit the form, then reload and confirm the record persisted; hit a protected route logged-out and confirm it is rejected). Fix what fails now, in this pass. Do not mark done on "looks right" or a self-claim -- observed behavior is the only proof.
11294
+ ` + `3. LOCK THE ARCHITECTURE on this pass so later edits are small and additive. Decide the data model, routes, and component structure up front and build to them; never rewrite whole files later to patch a small thing (that is the doom loop that breaks working features).
11295
+ ` + `4. DESIGN: commit to ONE named aesthetic direction up front (editorial, brutalist, luxury, retro-futuristic, soft/pastel, industrial, etc. -- chosen from the product domain) and hold it on every surface. Use real content (never lorem). AVOID the AI-slop tells that instantly read as machine-generated: NO indigo/blue-to-purple gradient (the #1 tell), NO Inter/Roboto/system-font headlines (pick a real display+body pairing), NO three-equal-rounded-cards-in-a-row skeleton, NO flat 1px gray card borders or colored left-border strips, NO untouched shadcn defaults, NO reflexive dark mode. Cap the palette at ~3 hues (60/30/10), tinted not pure #fff/#000, separate sections by whitespace then a slight background shift before any border. Aim for Linear/Stripe/Duolingo-tier taste: "this does not look AI-generated".
11296
+ ` + `5. SATISFY THE GATES THAT WILL JUDGE THIS PASS. Your work is checked by deterministic gates before it can be accepted, and in measured runs EVERY extra iteration was caused by one of these rejecting the work -- never by the model failing to finish. Clear them now, in this pass:
11297
+ ` + ` - STATIC ANALYSIS: no syntax errors, no unused/undefined symbols, no lint errors in files you touched.
11298
+ ` + ` - TEST SUITE: the existing tests must still pass. Run them; do not assume.
11299
+ ` + ` - MUTATION/MOCK INTEGRITY: tests must assert real behaviour. No tautological assertions (expect(true).toBe(true)), no test that passes whether or not the code works, no mocking the very unit under test, no inline mock data standing in for a real query.
11300
+ ` + ` - CODE REVIEW: no scope creep beyond the stated task, no dead or commented-out code, no leftover debug output, and follow the conventions already in the surrounding files.
11301
+ ` + `Deliver the finished, self-verified, genuinely-designed result in THIS pass. Additional iterations should be the exception, not the plan.
11302
+ ` + designArchetypesText();
11303
+ CAVEMAN_PINNED_VERSION = process.env["LOKI_CAVEMAN_VERSION"] || "1.9.0";
11304
+ });
11305
+
11306
+ // ../../loki-ts/src/runner/sdk_stream_parser.ts
11307
+ var init_sdk_stream_parser = __esm(() => {
11308
+ init_cost();
11309
+ init_budget();
11310
+ });
11311
+
11312
+ // ../../loki-ts/src/runner/trim.ts
11313
+ var init_trim = () => {};
11314
+
11315
+ // ../../loki-ts/src/util/update_check.ts
11316
+ var CACHE_TTL_MS;
11317
+ var init_update_check = __esm(() => {
11318
+ init_paths();
11319
+ CACHE_TTL_MS = 24 * 60 * 60 * 1000;
11320
+ });
11321
+
11322
+ // ../../loki-ts/src/runner/router/advisor_probe.ts
11323
+ var init_advisor_probe = __esm(() => {
11324
+ init_update_check();
11325
+ });
11326
+
11327
+ // ../../loki-ts/src/runner/provider_opencode.ts
11328
+ var init_provider_opencode = __esm(() => {
11329
+ init_shell();
11330
+ init_providers();
11331
+ });
11332
+
11333
+ // ../../loki-ts/src/runner/providers.ts
11334
+ var _installedVersionCache;
11335
+ var init_providers = __esm(() => {
11336
+ init_shell();
11337
+ init_paths();
11338
+ init_claude_flags();
11339
+ init_mcp_config();
11340
+ init_lean_prefix();
11341
+ init_sdk_stream_parser();
11342
+ init_trim();
11343
+ init_advisor_probe();
11344
+ init_claude_model();
11345
+ init_model_routes();
11346
+ init_provider_opencode();
11347
+ _installedVersionCache = new Map;
11348
+ });
11349
+
11350
+ // ../../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";
11353
+ function loadRouteRecord(runDir) {
11354
+ try {
11355
+ const p = join45(runDir, ROUTE_RECORD_FILE);
11356
+ if (!existsSync26(p) || !lstatSync9(p).isFile())
11357
+ return;
11358
+ const v = JSON.parse(readFileSync33(p, "utf8"));
11359
+ return typeof v === "object" && v !== null && !Array.isArray(v) ? v : undefined;
11360
+ } catch {
11361
+ return;
11362
+ }
11363
+ }
11364
+ var ROUTE_RECORD_FILE = "route.json";
11365
+ var init_route_record = () => {};
11366
+
11367
+ // ../../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";
11369
+ import { resolve as resolve13 } from "path";
11370
+ function validRun(v) {
11371
+ if (typeof v !== "object" || v === null)
11372
+ return false;
11373
+ const r = v;
11374
+ return typeof r["shape"] === "string" && typeof r["executor"] === "string" && EXECUTORS.includes(r["executor"]) && typeof r["verdict"] === "string" && VERDICTS.includes(r["verdict"]) && (r["owner"] === null || typeof r["owner"] === "string" && OWNERS.includes(r["owner"])) && typeof r["escalated"] === "boolean" && typeof r["usd"] === "number" && Number.isFinite(r["usd"]) && typeof r["wallS"] === "number" && Number.isFinite(r["wallS"]);
11375
+ }
11376
+ function historyPath(key, cacheRoot) {
11377
+ return resolve13(repoCacheDir(key, cacheRoot), HISTORY_FILE);
11378
+ }
11379
+ function readRunHistory(key, cacheRoot) {
11380
+ const path = historyPath(key, cacheRoot);
11381
+ if (!existsSync27(path))
11382
+ return [];
11383
+ try {
11384
+ const parsed = JSON.parse(readFileSync34(path, "utf8"));
11385
+ const runs2 = parsed?.runs;
11386
+ return Array.isArray(runs2) ? runs2.filter(validRun) : [];
11387
+ } catch {
11388
+ return [];
11389
+ }
11390
+ }
11391
+ function appendRunOutcome(key, outcome, cacheRoot) {
11392
+ try {
11393
+ const runs2 = [...readRunHistory(key, cacheRoot), outcome].slice(-HISTORY_CAP);
11394
+ mkdirSync16(repoCacheDir(key, cacheRoot), { recursive: true });
11395
+ const target = historyPath(key, cacheRoot);
11396
+ const tmp = `${target}.${process.pid}.tmp`;
11397
+ try {
11398
+ writeFileSync17(tmp, JSON.stringify({ runs: runs2 }));
11399
+ renameSync8(tmp, target);
11400
+ } catch (e) {
11401
+ rmSync11(tmp, { force: true, recursive: false });
11402
+ throw e;
11403
+ }
11404
+ return true;
11405
+ } catch {
11406
+ return false;
11407
+ }
11408
+ }
11409
+ var HISTORY_FILE = "router_history.json", HISTORY_CAP = 200, WALL_KIND = "total-v1", EXECUTORS, VERDICTS, OWNERS;
11410
+ var init_history_store = __esm(() => {
11411
+ init_cache();
11412
+ EXECUTORS = ["haiku", "sonnet"];
11413
+ VERDICTS = ["pass", "fail", "error", "not_proven"];
11414
+ OWNERS = ["code", "harness", "env", "provider"];
11415
+ });
11416
+
11417
+ // ../../loki-ts/src/runner/router/history.ts
11418
+ import { dirname as dirname16, join as join46, resolve as resolve14 } from "path";
11419
+ import { fileURLToPath as fileURLToPath4 } from "url";
11420
+ function shapeKey(model) {
11421
+ if (!model || model.status !== "ok")
11422
+ return null;
11423
+ const runners = new Set(model.packages.map((p) => (p.runner ?? "").trim().toLowerCase() || "none"));
11424
+ return `${model.workspaceKind}:${[...runners].sort().join("+")}`;
11425
+ }
11426
+ function shapeKeyForRepo(repoDir) {
11427
+ try {
11428
+ const dirs = shallowDirs(repoDir);
11429
+ const committed = loadCommitted(repoDir);
11430
+ if (committed)
11431
+ return shapeKey({ ...committed.model, key: computeKey(repoDir, committed.model.fingerprintFiles, dirs, committed.hash) });
11432
+ const cached = loadCached(repoDir);
11433
+ if (!cached || computeKey(repoDir, cached.fingerprintFiles, dirs) !== cached.key)
11434
+ return null;
11435
+ return shapeKey(cached);
11436
+ } catch {
11437
+ return null;
11438
+ }
11439
+ }
11440
+ var SHAPE_DEFAULTS_FILE;
11441
+ var init_history = __esm(() => {
11442
+ init_schema();
11443
+ init_history_store();
11444
+ init_discover2();
11445
+ init_gather();
11446
+ init_history_store();
11447
+ SHAPE_DEFAULTS_FILE = resolve14(dirname16(fileURLToPath4(import.meta.url)), "..", "..", "..", "data", "router-shape-defaults.json");
11448
+ });
11449
+
11450
+ // ../../loki-ts/src/runner/router/plan_route.ts
11451
+ var init_plan_route = __esm(() => {
11452
+ init_run_cap();
11453
+ init_providers();
11454
+ init_decision();
11455
+ init_advisor_probe();
11456
+ init_route_record();
11457
+ init_history();
11458
+ });
11459
+
11460
+ // ../../loki-ts/src/util/intent_card.ts
11461
+ var INTENT_HEADER = "What I think you want:", CARD_MIN_LINES = 3, CARD_MAX_LINES = 5, INTENT_CARD_INSTRUCTION;
11462
+ var init_intent_card = __esm(() => {
11463
+ INTENT_CARD_INSTRUCTION = `After the plan lines, append an intent card of ${CARD_MIN_LINES} to ${CARD_MAX_LINES} lines: a first line starting "${INTENT_HEADER}" with one sentence on what you think the user wants, then ${CARD_MIN_LINES - 1} to ${CARD_MAX_LINES - 1} lines each starting "Acceptance:" naming one check you will hold yourself to. You may add one optional line starting "Out of scope:" naming what you will NOT do; it counts toward the ${CARD_MAX_LINES} lines.`;
11464
+ });
11465
+
11466
+ // ../../loki-ts/src/engine10/repomap.ts
11467
+ var init_repomap = __esm(() => {
11468
+ init_safe_git();
11469
+ });
11470
+
11471
+ // ../../loki-ts/src/util/reviewer_brief.ts
11472
+ var init_reviewer_brief = __esm(() => {
11473
+ init_repomap();
11474
+ init_safe_git();
11475
+ });
11476
+
11477
+ // ../../loki-ts/src/engine10/stages/plan.ts
11478
+ var init_plan = __esm(() => {
11479
+ init_session();
11480
+ init_sizing();
11481
+ init_lean_prefix();
11482
+ init_types();
11483
+ init_run_cap();
11484
+ init_wall();
11485
+ init_model_downgrades();
11486
+ init_plan_route();
11487
+ init_intent_card();
11488
+ init_mutation_proof();
11489
+ init_reviewer_brief();
11490
+ });
11491
+
11492
+ // ../../loki-ts/src/runner/session_resume.ts
11493
+ var init_session_resume = __esm(() => {
11494
+ init_session();
11495
+ });
11496
+
11497
+ // ../../loki-ts/src/util/conflict_resume.ts
11498
+ var CONFLICT_CORRECTION, EMPTY_DONE_CORRECTION;
11499
+ var init_conflict_resume = __esm(() => {
11500
+ init_session_resume();
11501
+ init_context();
11502
+ CONFLICT_CORRECTION = "Loki imposes no file or test limits on you. If your conflict is only about Loki's own rules, finish the task. If the task itself conflicts, restate the conflict. " + FINISH_LINE;
11503
+ EMPTY_DONE_CORRECTION = "Your session finished with LOKI_DONE but the working tree has no change against the base. Make the change the task asks for, or if the task is already satisfied finish with LOKI_ALREADY_DONE: <file:line evidence>, or if the task itself conflicts finish with LOKI_SPEC_CONFLICT: <reason>. " + FINISH_LINE;
11504
+ });
11505
+
11506
+ // ../../loki-ts/src/runner/router/implement_route.ts
11507
+ var init_implement_route = __esm(() => {
11508
+ init_model_rank();
11509
+ init_unit_model();
11510
+ });
11511
+
11512
+ // ../../loki-ts/src/engine10/stages/implement.ts
11513
+ var init_implement = __esm(() => {
11514
+ init_lean_prefix();
11515
+ init_pr_lessons();
11516
+ init_context();
11517
+ init_model_downgrades();
11518
+ init_sizing();
11519
+ init_plan();
11520
+ init_verify();
11521
+ init_resolve();
11522
+ init_session();
11523
+ init_conflict_resume();
11524
+ init_session_resume();
11525
+ init_implement_route();
11526
+ init_unit_model();
11527
+ init_types();
11528
+ init_spec_file();
11529
+ });
11530
+
11531
+ // ../../loki-ts/src/engine10/machine.ts
11532
+ var init_machine = __esm(() => {
11533
+ init_hooks();
11534
+ init_retry_class();
11535
+ init_registry();
11536
+ init_run_cap();
11537
+ init_context();
11538
+ init_steer();
11539
+ init_implement();
11540
+ init_unit_model();
11541
+ init_types();
11542
+ });
11543
+
11544
+ // ../../loki-ts/src/runner/provider_failover.ts
11545
+ var DEFAULT_ORDER, ALLOWED;
11546
+ var init_provider_failover = __esm(() => {
11547
+ DEFAULT_ORDER = ["claude", "cline", "codex", "aider", "opencode"];
11548
+ ALLOWED = new Set(DEFAULT_ORDER);
11549
+ });
11550
+
11551
+ // ../../loki-ts/src/engine10/worker.ts
11552
+ function assertWorkerEnv(env = process.env) {
11553
+ if (env.LOKI_ALLOW_AGENT_GITHUB_TOKEN === "1")
11554
+ return;
11555
+ for (const v of GITHUB_TOKEN_VARS) {
11556
+ const val = env[v] ?? "";
11557
+ if (val !== "" && !val.startsWith(SENTINEL_PREFIX)) {
11558
+ throw new Error(`engine10 worker: ${v} holds a real token; the worker must run with withheld credentials`);
11559
+ }
11560
+ }
11561
+ }
11562
+ var init_worker = __esm(() => {
11563
+ init_credential_env();
11564
+ init_cost();
11565
+ init_budget_cap();
11566
+ init_run_cap();
11567
+ init_resolve();
11568
+ init_budget_cap();
11569
+ init_machine();
11570
+ init_provider_failover();
11571
+ init_session();
11572
+ init_testmap();
11573
+ init_types();
11574
+ init_safe_git();
11575
+ });
11576
+
11577
+ // ../../loki-ts/src/project_model/package_suite.ts
11578
+ import { join as join47 } from "path";
11579
+ async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
11580
+ const api = loadProjectApi(repoDir);
11581
+ if (!isMultiRoot(api))
11582
+ return false;
11583
+ const withTests = api.packages().filter((p) => p.commands.test);
11584
+ if (withTests.length === 0)
11585
+ return false;
11586
+ for (const pkg of withTests) {
11587
+ const tc = pkg.commands.test, name = `full suite: ${pkg.name}`, cmd = `(cd ${tc.cwd} && ${tc.cmd})`;
11588
+ 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 } } : {} });
11590
+ const duration_s = (Date.now() - started) / 1000;
11591
+ if (signal.aborted) {
11592
+ checks.push({ name, cmd, result: "not_run", duration_s });
11593
+ notProven.add(`not run: ${name} (aborted)`);
11594
+ continue;
11595
+ }
11596
+ const out2 = `${r.stdout}
11597
+ ${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 } } : {} });
11599
+ if (lr) {
11600
+ checks.push({ name, cmd, result: "not_run", duration_s });
11601
+ notProven.add(`${lr} (${name}; harness-owned)`);
11602
+ continue;
11603
+ }
11604
+ const cls = classifyCheck({ kind: "test", ok: r.exitCode === 0, out: out2, ...goRunner(tc.cmd) });
11605
+ checks.push({ name, cmd, result: cls.result, duration_s, ...cls.result === "fail" ? { ids: failIds(out2) } : {} });
11606
+ if (cls.result === "not_run")
11607
+ notProven.add(`not run: ${name} (${cls.reason ?? NO_TESTS_REASON})`);
11608
+ }
11609
+ for (const pkg of api.packages().filter((p) => !p.commands.test))
11610
+ notProven.add(`full suite: package ${pkg.name} defines no test command`);
11611
+ return true;
11612
+ }
11613
+ var init_package_suite = __esm(() => {
11614
+ init_load_owner();
11615
+ init_check_result();
11616
+ init_shell();
11617
+ init_failures();
11618
+ init_resolve();
11619
+ });
11620
+
11621
+ // ../../loki-ts/src/engine10/stages/deep.ts
11622
+ var exports_deep = {};
11623
+ __export(exports_deep, {
11624
+ stage: () => stage,
11625
+ runFullSuite: () => runFullSuite,
11626
+ runDeep: () => runDeep,
11627
+ deepStage: () => deepStage,
11628
+ DEFAULT_SECRET_SCAN_SH: () => DEFAULT_SECRET_SCAN_SH,
11629
+ DEFAULT_PUSH_SH: () => DEFAULT_PUSH_SH
11630
+ });
11631
+ import { existsSync as existsSync28, mkdirSync as mkdirSync17, writeFileSync as writeFileSync18 } from "fs";
11632
+ import { join as join48 } from "path";
11633
+ async function runFullSuite(ctx, signal, opts, checks, notProven) {
11634
+ if (await runPackageSuites(ctx.repoDir, signal, { path: opts.path, timeoutMs: opts.fullSuiteTimeoutMs ?? FULL_SUITE_TIMEOUT_MS, baseSha: ctx.baseSha }, checks, notProven))
11635
+ return;
11636
+ const map = await ctx.tests.detect(ctx.repoDir);
11637
+ if (map.runners.length === 0) {
11638
+ notProven.add("full suite (no test runner detected)");
11639
+ return;
11640
+ }
11641
+ for (const runner of map.runners) {
11642
+ const spec = FULL_SUITE_CMD[runner];
11643
+ const name = `full suite: ${runner}`;
11644
+ if (!Bun.which(spec.cmd, opts.path ? { PATH: opts.path } : undefined)) {
11645
+ checks.push({ name, cmd: [spec.cmd, ...spec.args].join(" "), result: "not_run", duration_s: 0 });
11646
+ notProven.add(`not run: ${name}`);
11647
+ continue;
11648
+ }
11649
+ const started = Date.now();
11650
+ const r = await run([spec.cmd, ...spec.args], {
11651
+ cwd: ctx.repoDir,
11652
+ timeoutMs: opts.fullSuiteTimeoutMs ?? FULL_SUITE_TIMEOUT_MS,
11653
+ ...opts.path ? { env: { PATH: opts.path } } : {}
11654
+ });
11655
+ const durationS = (Date.now() - started) / 1000;
11656
+ if (signal.aborted) {
11657
+ checks.push({ name, cmd: [spec.cmd, ...spec.args].join(" "), result: "not_run", duration_s: durationS });
11658
+ notProven.add(`not run: ${name} (aborted)`);
11659
+ continue;
11660
+ }
11661
+ const out2 = `${r.stdout}
11662
+ ${r.stderr}`, lr = r.exitCode === 0 ? undefined : await harnessLoadReason({ repoDir: ctx.repoDir, baseSha: ctx.baseSha, out: out2, cmd: spec.cmd, args: spec.args, signal, ...opts.path ? { env: { PATH: opts.path } } : {} });
11663
+ if (lr) {
11664
+ checks.push({ name, cmd: [spec.cmd, ...spec.args].join(" "), result: "not_run", duration_s: durationS });
11665
+ notProven.add(`${lr} (${name}; harness-owned)`);
11666
+ continue;
11667
+ }
11668
+ const cls = classifyCheck({ kind: "test", ok: r.exitCode === 0, out: out2, ...goRunner(spec.cmd, spec.args) });
11669
+ checks.push({ name, cmd: [spec.cmd, ...spec.args].join(" "), result: cls.result, duration_s: durationS, ...cls.result === "fail" ? { ids: failIds(out2) } : {} });
11670
+ if (cls.result === "not_run")
11671
+ notProven.add(`not run: ${name} (${cls.reason ?? NO_TESTS_REASON})`);
11672
+ }
11673
+ }
11674
+ function runAppBoot(ctx, opts, checks, notProven) {
11675
+ const discover = opts.discoverGraph ?? discoverProjectGraph;
11676
+ let graph = null;
11677
+ try {
11678
+ graph = discover(ctx.repoDir);
11679
+ } catch {
11680
+ graph = null;
11681
+ }
11682
+ checks.push({
11683
+ name: "app boot",
11684
+ cmd: "project_graph.ts discoverProjectGraph",
11685
+ result: "not_run",
11686
+ duration_s: 0
11687
+ });
11688
+ notProven.add(graph ? `app boot not run (app graph discovered, ${graph.members.length} member(s))` : "app boot not run (no app graph discovered)");
11689
+ }
11690
+ async function runCouncilCheck(ctx, changed, baseSha, signal, opts, checks, notProven) {
11691
+ const codeFiles = changed.filter((f) => !f.endsWith(".md"));
11692
+ if (codeFiles.length === 0) {
11693
+ notProven.add("council (no non-doc changes to review)");
11694
+ return;
11695
+ }
11696
+ if (!opts.council) {
11697
+ notProven.add("council (not wired: see the contract-gap note in stages/deep.ts)");
11698
+ return;
11699
+ }
11700
+ const diffResult = await safeGitRun(ctx.repoDir, ["diff", "--no-color", baseSha, "HEAD", "--", ...codeFiles], { timeoutMs: 20000 });
11701
+ const diff = diffResult.exitCode === 0 ? diffResult.stdout : "";
11702
+ const maxBytes = opts.maxCouncilDiffBytes ?? MAX_COUNCIL_DIFF_BYTES;
11703
+ if (Buffer.byteLength(diff, "utf8") > maxBytes) {
11704
+ notProven.add("council (context oversized, refused)");
11705
+ return;
11706
+ }
11707
+ const started = Date.now();
11708
+ try {
11709
+ const outcome = await opts.council.run({ runId: ctx.runId, diff, files: codeFiles }, signal);
11710
+ checks.push({ name: "council", cmd: "dispatchClaudeAgents", result: "pass", duration_s: (Date.now() - started) / 1000 });
11711
+ } catch (err) {
11712
+ notProven.add(`council (refused: ${err.message})`);
11713
+ }
11714
+ }
11715
+ async function runSecretScan(ctx, changed, opts, checks, notProven) {
11716
+ const scriptPath = opts.secretScanShPath ?? DEFAULT_SECRET_SCAN_SH;
11717
+ const name = "security scan";
11718
+ if (!existsSync28(scriptPath)) {
11719
+ checks.push({ name, cmd: "secret-scan.sh", result: "not_run", duration_s: 0 });
11720
+ notProven.add(`not run: ${name} (secret-scan.sh not found)`);
11721
+ return;
11722
+ }
11723
+ if (changed.length === 0) {
11724
+ checks.push({ name, cmd: "secret-scan.sh", result: "pass", duration_s: 0 });
11725
+ return;
11726
+ }
11727
+ 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
+ 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 });
11730
+ const durationS = (Date.now() - started) / 1000;
11731
+ if (r.exitCode === 3) {
11732
+ checks.push({ name, cmd: "secret-scan.sh", result: "not_run", duration_s: durationS });
11733
+ notProven.add(`not run: ${name} (secret-scan.sh failed to load)`);
11734
+ return;
11735
+ }
11736
+ const hits = r.stdout.split(`
11737
+ `).map((l) => l.trim()).filter(Boolean);
11738
+ checks.push({
11739
+ name,
11740
+ cmd: "secret-scan.sh",
11741
+ result: hits.length > 0 ? "fail" : "pass",
11742
+ duration_s: durationS,
11743
+ ...hits.length > 0 ? { reason: `secret match: ${hits.join(", ")}` } : {}
11744
+ });
11745
+ }
11746
+ function commentArgv(prNumber, bodyFile) {
11747
+ return ["comment", prNumber, bodyFile];
11748
+ }
11749
+ function buildCommentBody(checks, notProven, statusState) {
11750
+ const lines = [`## Loki deep verify: ${statusState}`, "", "### Checks"];
11751
+ lines.push(...checks.length ? checks.map((c) => `- ${c.result}: ${c.name}${c.reason ? ` (${c.reason})` : ""}`) : ["- none"]);
11752
+ lines.push("", "### NOT PROVEN", ...notProven.length ? notProven.map((n2) => `- ${n2}`) : ["- none"]);
11753
+ return `${lines.join(`
11754
+ `)}
11755
+ `;
11756
+ }
11757
+ async function postResults(ctx, opts, checks, notProven, statusState) {
11758
+ const out2 = [];
11759
+ const pinnedOrigin = ctx.pinnedOrigin;
11760
+ if (!pinnedOrigin) {
11761
+ out2.push("push refused: no pinned origin (Rule of Two)");
11762
+ return out2;
11763
+ }
11764
+ const scriptPath = opts.pushScriptPath ?? DEFAULT_PUSH_SH;
11765
+ const env = { ...process.env, ...opts.pushExtraEnv, _LOKI_ORIGIN_PINNED: "1", _LOKI_PINNED_ORIGIN: pinnedOrigin };
11766
+ const prUrl = ctx.outputs().pr?.pr_url;
11767
+ const prNumber = prUrl ? PR_NUMBER_RE.exec(prUrl)?.[1] : undefined;
11768
+ if (prNumber) {
11769
+ mkdirSync17(ctx.runDir, { recursive: true });
11770
+ const bodyFile = join48(ctx.runDir, "deep-comment.md");
11771
+ writeFileSync18(bodyFile, buildCommentBody(checks, notProven, statusState), "utf8");
11772
+ const commentResult = await run(["bash", scriptPath, ...commentArgv(prNumber, bodyFile)], { cwd: ctx.repoDir, env, timeoutMs: 30000 });
11773
+ if (commentResult.exitCode !== 0)
11774
+ out2.push(`deep comment not posted (engine10-push.sh exit ${commentResult.exitCode})`);
11775
+ } else {
11776
+ out2.push("deep comment not posted (no PR number)");
11777
+ }
11778
+ const headSha = (await safeGitRun(ctx.repoDir, ["rev-parse", "HEAD"], { timeoutMs: 1e4 })).stdout.trim();
11779
+ if (SHA_RE.test(headSha)) {
11780
+ const statusArgs = { cmd: "status", sha: headSha, state: statusState, description: `Loki 10 deep verify: ${statusState}` };
11781
+ const statusResult = await run(["bash", scriptPath, ...pushArgv(statusArgs)], { cwd: ctx.repoDir, env, timeoutMs: 30000 });
11782
+ if (statusResult.exitCode !== 0)
11783
+ out2.push(`loki/deep-verify status not set (engine10-push.sh exit ${statusResult.exitCode})`);
11784
+ } else {
11785
+ out2.push("loki/deep-verify status not set (HEAD sha not resolvable)");
11786
+ }
11787
+ return out2;
11788
+ }
11789
+ async function runDeep(ctx, signal, opts = {}) {
11790
+ if (signal.aborted)
11791
+ return { status: "failed", data: {}, reason: "aborted before deep verify started" };
11792
+ try {
11793
+ assertWorkerEnv(opts.env ?? process.env);
11794
+ } catch (err) {
11795
+ return { status: "failed", data: {}, reason: err.message };
11796
+ }
11797
+ let changed;
11798
+ try {
11799
+ changed = changedFiles(ctx.repoDir, ctx.baseSha);
11800
+ } catch (err) {
11801
+ return { status: "failed", data: {}, reason: `git diff against base failed: ${err.message}` };
11802
+ }
11803
+ const checks = [];
11804
+ const notProven = new Set;
11805
+ await runFullSuite(ctx, signal, opts, checks, notProven);
11806
+ runAppBoot(ctx, opts, checks, notProven);
11807
+ await runCouncilCheck(ctx, changed, ctx.baseSha, signal, opts, checks, notProven);
11808
+ await runSecretScan(ctx, changed, opts, checks, notProven);
11809
+ const statusState = checks.some((c) => c.result === "fail") ? "failure" : "success";
11810
+ const notProvenList = [...notProven];
11811
+ const seal = ctx.outputs().seal;
11812
+ const addendumBody = {
11813
+ schema: "loki.v10.receipt-addendum/1",
11814
+ run_id: ctx.runId,
11815
+ base_receipt_sha256: seal?.receipt_sha256 ?? null,
11816
+ checks,
11817
+ not_proven: notProvenList,
11818
+ status_state: statusState
11819
+ };
11820
+ const addendumSha256 = sha2562(canonicalJson(addendumBody));
11821
+ const sig = signReceipt(`${ctx.runId}-deep`, addendumSha256);
11822
+ const addendum = { ...addendumBody, addendum_sha256: addendumSha256, verification: { jwt: sig.jwt, kid: sig.kid } };
11823
+ mkdirSync17(ctx.runDir, { recursive: true });
11824
+ writeFileSync18(join48(ctx.runDir, "receipt-addendum-1.json"), JSON.stringify(addendum, null, 2) + `
11825
+ `);
11826
+ const pushNotProven = await postResults(ctx, opts, checks, notProvenList, statusState);
11827
+ const allNotProven = [...notProvenList, ...pushNotProven];
11828
+ ctx.emit("deep.completed", "deep", { checks, status_state: statusState, addendum_sha256: addendumSha256 });
11829
+ return { status: "completed", data: { checks, addendum_sha256: addendumSha256, status_state: statusState, not_proven: allNotProven } };
11830
+ }
11831
+ var DEFAULT_PUSH_SH, DEFAULT_SECRET_SCAN_SH, MAX_COUNCIL_DIFF_BYTES = 400000, FULL_SUITE_TIMEOUT_MS = 300000, PR_NUMBER_RE, SHA_RE, FULL_SUITE_CMD, deepStage, stage;
11832
+ var init_deep = __esm(() => {
11833
+ init_project_graph();
11834
+ init_shell();
11835
+ init_load_owner();
11836
+ init_worker();
11837
+ init_seal();
11838
+ init_verify();
11839
+ init_package_suite();
11840
+ init_check_result();
11841
+ init_failures();
11842
+ init_types();
11843
+ init_safe_git();
11844
+ DEFAULT_PUSH_SH = new URL("../../../../autonomy/lib/engine10-push.sh", import.meta.url).pathname;
11845
+ DEFAULT_SECRET_SCAN_SH = new URL("../../../../autonomy/lib/secret-scan.sh", import.meta.url).pathname;
11846
+ PR_NUMBER_RE = /\/pull\/(\d+)$/;
11847
+ SHA_RE = /^[0-9a-f]{40}$/;
11848
+ FULL_SUITE_CMD = {
11849
+ pytest: { cmd: "python", args: ["-m", "pytest", "-q"] },
11850
+ vitest: { cmd: "npx", args: ["vitest", "run"] },
11851
+ jest: { cmd: "npx", args: ["jest"] },
11852
+ bun: { cmd: "bun", args: ["test"] },
11853
+ node: { cmd: "node", args: ["--test"] },
11854
+ npm: { cmd: "npm", args: ["test", "--silent"] },
11855
+ go: { cmd: "go", args: ["test", "-json", "./..."] },
11856
+ cargo: { cmd: "cargo", args: ["test"] }
11857
+ };
11858
+ deepStage = {
11859
+ name: "deep",
11860
+ ...STAGE_BUDGETS.deep,
11861
+ run: (ctx, signal) => runDeep(ctx, signal)
11862
+ };
11863
+ stage = deepStage;
11864
+ });
11865
+
11866
+ // ../../loki-ts/src/engine10/stages/verify.ts
11867
+ import { existsSync as existsSync29, mkdtempSync as mkdtempSync6, realpathSync as realpathSync17, rmSync as rmSync12 } from "fs";
11868
+ import { tmpdir as tmpdir8 } from "os";
11869
+ import { dirname as dirname17, isAbsolute as isAbsolute6, join as join49, relative as relative5 } from "path";
11870
+ function resolveTool(repoDir, bin, fallback, lastResort = fallback) {
11871
+ const inRepo = (p) => {
11872
+ try {
11873
+ const r = relative5(realpathSync17(repoDir), realpathSync17(p));
11874
+ return r !== "" && !r.startsWith("..") && !isAbsolute6(r);
11875
+ } catch {
11876
+ return false;
11877
+ }
11878
+ };
11879
+ 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);
11881
+ return project ? [project, "project"] : [Bun.which(fallback) ? fallback : lastResort, "system"];
11882
+ }
11883
+ function runnerCmd(t, repoDir) {
11884
+ switch (t.runner) {
11885
+ case "pytest": {
11886
+ const [cmd, interpreter] = resolveTool(repoDir, "python", "python3", "python");
11887
+ return [cmd, ["-m", "pytest", "-q", t.path], interpreter];
11888
+ }
11889
+ case "vitest":
11890
+ return ["npx", ["vitest", "run", t.path]];
11891
+ case "jest":
11892
+ return ["npx", ["jest", t.path]];
11893
+ case "bun":
11894
+ return ["bun", ["test", t.path]];
11895
+ case "node":
11896
+ return ["node", ["--test", `./${t.path}`]];
11897
+ case "npm":
11898
+ return ["npm", ["test", "--silent"]];
11899
+ case "go":
11900
+ return ["go", ["test", "-json", `./${dirname17(t.path)}`]];
11901
+ case "cargo":
11902
+ return ["cargo", ["test"]];
11903
+ }
11904
+ }
11905
+ function commandFor(t, repoDir, api) {
11906
+ const site = siteFor(api, repoDir, t.path);
11907
+ const [cmd, args, interpreter] = runnerCmd(site ? { runner: t.runner, path: site.file } : t, repoDir);
11908
+ return { cwd: site?.cwd ?? repoDir, cmd, args, argv: [cmd, ...args], ...interpreter ? { interpreter } : {}, pkgRoot: site?.root ?? "." };
11909
+ }
11910
+ function testConfigChanged(repoDir, baseSha, changed) {
11911
+ const diff = (f) => safeGit(repoDir, ["diff", "-U0", baseSha, "--", f]);
11912
+ return changed.filter((f) => CFG_ALWAYS.test(f) || CFG_SHARED.test(f) && (() => {
11913
+ const d = diff(f);
11914
+ return !d || CFG_LINE.test(d);
11915
+ })());
11916
+ }
11917
+ async function runOnce(cmd, args, cwd, signal, opts) {
11918
+ if (!Bun.which(cmd, { PATH: opts.path ?? process.env["PATH"] ?? "" }))
11919
+ return { ok: false, missing: true, cut: false, out: "" };
11920
+ const timeout = AbortSignal.timeout(opts.timeoutMs ?? CHECK_TIMEOUT_MS);
11921
+ const proc = Bun.spawn([cmd, ...args], {
11922
+ cwd,
11923
+ stdin: opts.stdin !== undefined ? Buffer.from(opts.stdin) : "ignore",
11924
+ stdout: "pipe",
11925
+ stderr: "pipe",
11926
+ signal: AbortSignal.any([signal, timeout]),
11927
+ env: opts.path ? { ...plainTestEnv(), PATH: opts.path } : plainTestEnv()
11928
+ });
11929
+ let tail = "";
11930
+ const rs = [proc.stdout, proc.stderr].map((s) => s.getReader());
11931
+ const pumps = rs.map(async (r) => {
11932
+ const d = new TextDecoder;
11933
+ for (;; ) {
11934
+ const c = await r.read().catch(() => ({ done: true, value: undefined }));
11935
+ if (c.done)
11936
+ return;
11937
+ tail = (tail + d.decode(c.value, { stream: true })).slice(-65536);
11938
+ }
11939
+ });
11940
+ const exitCode = await proc.exited;
11941
+ await Promise.race([Promise.all(pumps), new Promise((r) => setTimeout(r, 300))]);
11942
+ rs.forEach((r) => r.cancel().catch(() => {}));
11943
+ const cut = timeout.aborted || signal.aborted;
11944
+ return { ok: exitCode === 0 && !cut, missing: false, cut, out: cut ? "" : stripAnsi(tail) };
11945
+ }
11946
+ function firstError(out2) {
11947
+ const goOut = (l2) => {
11948
+ try {
11949
+ const e = JSON.parse(l2);
11950
+ return typeof e.Action === "string" ? e.Action === "output" || e.Action === "build-output" ? e.Output ?? "" : "" : l2;
11951
+ } catch {
11952
+ return l2;
11953
+ }
11954
+ };
11955
+ const lines = out2.slice(-65536).split(`
11956
+ `).map((l2) => (l2.startsWith("{") ? goOut(l2) : l2).trim()).filter(Boolean), l = lines.find((x) => /^(FAILED\s|\u25cf\s.*\u203a|not ok\s|_{3,}\s.+\s_{3,}$)/.test(x)) ?? lines.find((x) => /^[\w./-]+\.go:\d+:\d+: \S/.test(x)) ?? lines.find((x) => /fail|error/i.test(x) && !/^(=|\u2713|ok\b|PASS)/.test(x)) ?? "";
11957
+ return l.replace(/\d{4}-\d\d-\d\dT[\d:.]+Z?/g, "").replace(/(^|\s)\/(?:[\w.@-]+\/)*[\w.@-]+/g, "$1<path>").replace(/:\d+(?::\d+)?/g, "").replace(/\[?\d+(?:\.\d+)?m?s\]?/g, "").replace(/\s+/g, " ").slice(0, 160);
11958
+ }
11959
+ async function runCheck(ctx, name, cmd, args, signal, checks, opts = {}) {
11960
+ const started = Date.now();
10667
11961
  const cmdStr = [cmd, ...args].join(" ");
10668
11962
  const kind = opts.kind ?? "test";
10669
11963
  const cwd = opts.cwd ?? ctx.repoDir;
@@ -10701,7 +11995,7 @@ async function subtractBase(ctx, api, checks, tests, changed, wall, rel, signal)
10701
11995
  const sus = pairs.filter(({ c }) => rel.has(c.name) && c.result === "pass");
10702
11996
  if (!(un.some(({ c }) => c.result === "fail" && c.ids?.length) || sus.length) || signal.aborted)
10703
11997
  return out2;
10704
- const dir = mkdtempSync6(join41(tmpdir8(), "e10-base-"));
11998
+ const dir = mkdtempSync6(join49(tmpdir8(), "e10-base-"));
10705
11999
  const git3 = (args) => {
10706
12000
  safeGit(ctx.repoDir, args, { stdio: "ignore", repoDrivers: true });
10707
12001
  };
@@ -10728,7 +12022,7 @@ async function subtractBase(ctx, api, checks, tests, changed, wall, rel, signal)
10728
12022
  try {
10729
12023
  git3(["worktree", "remove", "--force", dir]);
10730
12024
  } catch {}
10731
- rmSync9(dir, { recursive: true, force: true });
12025
+ rmSync12(dir, { recursive: true, force: true });
10732
12026
  try {
10733
12027
  git3(["worktree", "prune"]);
10734
12028
  } catch {}
@@ -10736,7 +12030,7 @@ async function subtractBase(ctx, api, checks, tests, changed, wall, rel, signal)
10736
12030
  return out2;
10737
12031
  }
10738
12032
  function isLokiModeRepo(repoDir) {
10739
- return existsSync22(join41(repoDir, "scripts", "select-tests.sh"));
12033
+ return existsSync29(join49(repoDir, "scripts", "select-tests.sh"));
10740
12034
  }
10741
12035
  async function runLintChecks(ctx, changed, signal, checks, opts = {}) {
10742
12036
  const { api, ...runOpts } = opts;
@@ -10753,9 +12047,9 @@ async function runLintChecks(ctx, changed, signal, checks, opts = {}) {
10753
12047
  }
10754
12048
  for (const g of groupByPackage(api, ctx.repoDir, changed.filter((f) => /\.(ts|tsx|js|jsx)$/.test(f)))) {
10755
12049
  const sfx = g.root === "." ? "" : `:${g.root}`, co = g.root === "." ? opts : { ...opts, cwd: g.cwd };
10756
- if (existsSync22(join41(g.cwd, "tsconfig.json")))
12050
+ if (existsSync29(join49(g.cwd, "tsconfig.json")))
10757
12051
  await runCheck(ctx, `lint:tsc${sfx}`, "npx", ["tsc", "--noEmit", "-p", "."], signal, checks, { ...co, kind: "static" });
10758
- if (ESLINT_CONFIGS.some((f) => existsSync22(join41(g.cwd, f))))
12052
+ if (ESLINT_CONFIGS.some((f) => existsSync29(join49(g.cwd, f))))
10759
12053
  await runCheck(ctx, `lint:eslint${sfx}`, "npx", ["eslint", ...g.rel], signal, checks, { ...co, kind: "static" });
10760
12054
  }
10761
12055
  }
@@ -10772,6 +12066,8 @@ var init_verify = __esm(() => {
10772
12066
  init_types();
10773
12067
  init_resolve();
10774
12068
  init_safe_git();
12069
+ init_repo_profile();
12070
+ init_check_result();
10775
12071
  init_check_result();
10776
12072
  CODE_EXT = /\.(?:[cm]?[jt]sx?|py|go)$/;
10777
12073
  CFG_ALWAYS = /(^|\/)(conftest\.py|\.?pytest\.(?:ini|toml)|tox\.ini|jest\.config\.[\w.]+|vitest\.config\.[\w.]+|\.mocharc[\w.]*)$/;
@@ -10796,13 +12092,22 @@ var init_verify = __esm(() => {
10796
12092
  }
10797
12093
  return { status: "failed", data: { changed_files: [] }, reason: "empty diff without an already_done marker" };
10798
12094
  }
12095
+ let risk = (() => {
12096
+ try {
12097
+ const r = classifyRisk(diffFiles(ctx.repoDir, ctx.baseSha));
12098
+ recordRisk(ctx.repoDir, r);
12099
+ return r;
12100
+ } catch {
12101
+ return null;
12102
+ }
12103
+ })();
10799
12104
  const checks = [];
10800
12105
  const api = loadProjectApi(ctx.repoDir);
10801
12106
  const map = await ctx.tests.detect(ctx.repoDir);
10802
12107
  const impacted = ctx.tests.impacted(map, changed);
10803
12108
  const changedTestFiles = map.tests.filter((t) => changed.includes(t.path));
10804
12109
  const wall = ctx.outputs().wall ?? {};
10805
- const wallPaths = new Set((wall.files ?? []).map((f) => isAbsolute5(f.path) ? relative5(ctx.repoDir, f.path) : f.path));
12110
+ const wallPaths = new Set((wall.files ?? []).map((f) => isAbsolute6(f.path) ? relative5(ctx.repoDir, f.path) : f.path));
10806
12111
  const wallTests = map.tests.filter((t) => wallPaths.has(t.path));
10807
12112
  const intake = ctx.outputs().intake, relevant = ctx.tests.impacted(map, namedFiles(intake?.task ?? "", loadRepoMap(intake?.repomap_ref)));
10808
12113
  const tests = dedupeTests([...impacted, ...changedTestFiles, ...wallTests, ...relevant]);
@@ -10817,6 +12122,9 @@ var init_verify = __esm(() => {
10817
12122
  }
10818
12123
  const targetNames = new Set([...wallTests, ...relevant].map((t) => `${t.runner}:${t.path}`));
10819
12124
  const preRed = await subtractBase(ctx, api, checks, tests, changed, new Set(wallTests.map((t) => `${t.runner}:${t.path}`)), new Set(relevant.map((t) => `${t.runner}:${t.path}`)), signal);
12125
+ const attr = attribute(ctx.repoDir, ctx.baseSha, checks.filter((c) => c.result === "fail" && !preRed.names.includes(c.name)).map((c) => ({ name: c.name, ids: c.ids, eligible: !targetNames.has(c.name) && !changed.includes(c.name.slice(c.name.indexOf(":") + 1)) })));
12126
+ preRed.names.push(...attr.preExistingChecks);
12127
+ preRed.ids.push(...attr.preExistingIds);
10820
12128
  if (!signal.aborted) {
10821
12129
  await runLintChecks(ctx, changed, signal, checks, { api, wall: wallPaths });
10822
12130
  if (isLokiModeRepo(ctx.repoDir)) {
@@ -10828,6 +12136,23 @@ var init_verify = __esm(() => {
10828
12136
  });
10829
12137
  }
10830
12138
  }
12139
+ const fullNotProven = new Set;
12140
+ if (risk && risk.tier !== "low" && !signal.aborted) {
12141
+ const { runFullSuite: runFullSuite2 } = await Promise.resolve().then(() => (init_deep(), exports_deep));
12142
+ const full = [];
12143
+ await runFullSuite2(ctx, signal, {}, full, fullNotProven);
12144
+ for (const c of full)
12145
+ checks.push({ name: c.name, cmd: c.cmd, result: c.result, duration_s: c.duration_s, ...c.reason ? { reason: c.reason } : {} });
12146
+ const fa = attributeFullSuite(ctx.repoDir, ctx.baseSha, full, checks.filter((c) => c.result === "fail" && !preRed.names.includes(c.name)).flatMap((c) => c.ids ?? []), changed);
12147
+ preRed.names.push(...fa.preExistingChecks);
12148
+ preRed.ids.push(...fa.preExistingIds);
12149
+ attr.introducedChecks.push(...fa.introducedChecks);
12150
+ attr.line = [attr.line, fa.line].filter(Boolean).join("; ") || null;
12151
+ if (full.some((c) => c.result === "pass" || c.result === "fail")) {
12152
+ risk = markExecuted(risk, ["full test command", "full suite"]);
12153
+ recordRisk(ctx.repoDir, risk);
12154
+ }
12155
+ }
10831
12156
  const cfgChanged = testConfigChanged(ctx.repoDir, ctx.baseSha, changed);
10832
12157
  const covered = (f) => ctx.tests.impacted(map, [f]).some((t) => checks.some((c) => c.name === `${t.runner}:${t.path}` && hasExecutedProof([c])));
10833
12158
  const uncoveredChanged = changed.filter((f) => CODE_EXT.test(f) && !isTestFile(f) && !wallPaths.has(f) && !cfgChanged.includes(f) && !covered(f));
@@ -10849,15 +12174,15 @@ var init_verify = __esm(() => {
10849
12174
  return [`weakened test: ${t.path}`, ...assertDeltaNotes(ctx.repoDir, ctx.baseSha, null, t.path, intake?.task ?? "", k?.b, k?.h) ?? []];
10850
12175
  });
10851
12176
  const weakened = [...modifiedRel, ...cfgChanged.map((f) => `test configuration changed: ${f}`), ...preRed.weak.map((n2) => `skipped or fewer tests than base: ${n2}`)];
10852
- const notProven = [...weakened, ...checks.filter((c) => c.owner === "harness").map((c) => `${c.reason} (${c.name}; harness-owned, no fix rounds)`), ...new Set(checks.filter((c) => c.interpreter === "system" && c.result !== "not_run").map((c) => c.name.startsWith("lint:") ? "lint ran on the system ruff" : "tests ran on the system interpreter"))];
10853
- return { status: "completed", data: { checks, flaky, failures_grouped: failuresGrouped, changed_files: changed, not_proven: notProven, pre_red: preRed.ids, pre_red_checks: preRed.names, test_counts: testCounts, uncovered_changed: uncoveredChanged, target_checks: checks.filter((c) => c.result === "pass" && targetNames.has(c.name)).map((c) => c.name) } };
12177
+ const notProven = [...weakened, ...[...fullNotProven].filter((n2) => !n2.startsWith("full suite (no test runner")), ...checks.filter((c) => c.owner === "harness").map((c) => `${c.reason} (${c.name}; harness-owned, no fix rounds)`), ...new Set(checks.filter((c) => c.interpreter === "system" && c.result !== "not_run").map((c) => c.name.startsWith("lint:") ? "lint ran on the system ruff" : "tests ran on the system interpreter"))];
12178
+ return { status: "completed", data: { checks, flaky, failures_grouped: failuresGrouped, changed_files: changed, not_proven: notProven, pre_red: preRed.ids, pre_red_checks: preRed.names, ...attr.line ? { baseline_line: attr.line, introduced_checks: attr.introducedChecks } : {}, test_counts: testCounts, uncovered_changed: uncoveredChanged, target_checks: checks.filter((c) => c.result === "pass" && targetNames.has(c.name)).map((c) => c.name), risk } };
10854
12179
  }
10855
12180
  };
10856
12181
  });
10857
12182
 
10858
12183
  // ../../loki-ts/src/project_model/conventions.ts
10859
- import { existsSync as existsSync23, readdirSync as readdirSync12, readFileSync as readFileSync28 } from "fs";
10860
- import { dirname as dirname13, join as join42 } from "path";
12184
+ import { existsSync as existsSync30, readdirSync as readdirSync14, readFileSync as readFileSync35 } from "fs";
12185
+ import { dirname as dirname18, join as join50 } from "path";
10861
12186
  function parseJsonc(text3) {
10862
12187
  let out2 = "", i = 0;
10863
12188
  while (i < text3.length) {
@@ -10892,25 +12217,25 @@ function moduleOf(file, depth = 0) {
10892
12217
  const ext = typeof j.extends === "string" ? j.extends : null;
10893
12218
  if (!ext || !ext.startsWith("."))
10894
12219
  return null;
10895
- const next = join42(dirname13(file), ext.endsWith(".json") ? ext : `${ext}.json`);
10896
- return existsSync23(next) ? moduleOf(next, depth + 1) : null;
12220
+ const next = join50(dirname18(file), ext.endsWith(".json") ? ext : `${ext}.json`);
12221
+ return existsSync30(next) ? moduleOf(next, depth + 1) : null;
10897
12222
  }
10898
12223
  function readPackageConventions(pkgDir, runner = null) {
10899
12224
  let names = [];
10900
12225
  try {
10901
- names = readdirSync12(pkgDir).filter((f) => f.endsWith(".json")).sort((x, y) => x.length - y.length || x.localeCompare(y));
12226
+ names = readdirSync14(pkgDir).filter((f) => f.endsWith(".json")).sort((x, y) => x.length - y.length || x.localeCompare(y));
10902
12227
  } catch {
10903
12228
  return null;
10904
12229
  }
10905
12230
  let packageType = null, tsModule = null;
10906
12231
  for (const n2 of names) {
10907
- const j = readJson5(join42(pkgDir, n2));
12232
+ const j = readJson5(join50(pkgDir, n2));
10908
12233
  if (!j)
10909
12234
  continue;
10910
12235
  if (packageType === null && typeof j.type === "string" && typeof j.name === "string")
10911
12236
  packageType = j.type;
10912
12237
  if (tsModule === null && j.compilerOptions !== undefined)
10913
- tsModule = moduleOf(join42(pkgDir, n2));
12238
+ tsModule = moduleOf(join50(pkgDir, n2));
10914
12239
  }
10915
12240
  if (packageType === null && tsModule === null)
10916
12241
  return null;
@@ -10932,7 +12257,7 @@ function conventionViolation(c, fileName, content) {
10932
12257
  }
10933
12258
  var readJson5 = (p) => {
10934
12259
  try {
10935
- const v = parseJsonc(readFileSync28(p, "utf8"));
12260
+ const v = parseJsonc(readFileSync35(p, "utf8"));
10936
12261
  return v && typeof v === "object" && !Array.isArray(v) ? v : null;
10937
12262
  } catch {
10938
12263
  return null;
@@ -10942,15 +12267,15 @@ var init_conventions = () => {};
10942
12267
 
10943
12268
  // ../../loki-ts/src/engine10/stages/wall.ts
10944
12269
  import { spawnSync as spawnSync4 } from "child_process";
10945
- import { existsSync as existsSync24, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync7, readFileSync as readFileSync29, readdirSync as readdirSync13, realpathSync as realpathSync17, rmSync as rmSync10, writeFileSync as writeFileSync13 } from "fs";
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";
10946
12271
  import { tmpdir as tmpdir9 } from "os";
10947
- import { dirname as dirname14, isAbsolute as isAbsolute6, join as join43, relative as relative6 } from "path";
12272
+ import { dirname as dirname19, isAbsolute as isAbsolute7, join as join51, relative as relative6 } from "path";
10948
12273
  function pytestCollectionIsRed(output, repoDir) {
10949
12274
  if (/ModuleNotFoundError/.test(output))
10950
12275
  return false;
10951
12276
  const real2 = (p) => {
10952
12277
  try {
10953
- return realpathSync17(isAbsolute6(p) ? p : join43(repoDir, p));
12278
+ return realpathSync18(isAbsolute7(p) ? p : join51(repoDir, p));
10954
12279
  } catch {
10955
12280
  return null;
10956
12281
  }
@@ -10987,7 +12312,7 @@ function pytestCollectionIsRed(output, repoDir) {
10987
12312
  }
10988
12313
  function moduleUnderRepo(repoDir, name) {
10989
12314
  const rel = name.replace(/\./g, "/");
10990
- return existsSync24(join43(repoDir, `${rel}.py`)) || existsSync24(join43(repoDir, rel, "__init__.py"));
12315
+ return existsSync31(join51(repoDir, `${rel}.py`)) || existsSync31(join51(repoDir, rel, "__init__.py"));
10991
12316
  }
10992
12317
  function pytestExit1IsRed(output) {
10993
12318
  if (/^!+ _pytest\.outcomes\.Exit\b/m.test(output))
@@ -11082,10 +12407,10 @@ ${repomapText}`] : [],
11082
12407
  function loadTaskText(ctx, fromPrior) {
11083
12408
  if (fromPrior)
11084
12409
  return fromPrior;
11085
- const issueJsonPath = process.env.LOKI_E10_ISSUE_JSON ?? join43(ctx.runDir, "issue.json");
11086
- if (existsSync24(issueJsonPath)) {
12410
+ const issueJsonPath = process.env.LOKI_E10_ISSUE_JSON ?? join51(ctx.runDir, "issue.json");
12411
+ if (existsSync31(issueJsonPath)) {
11087
12412
  try {
11088
- const issue = JSON.parse(readFileSync29(issueJsonPath, "utf8"));
12413
+ const issue = JSON.parse(readFileSync36(issueJsonPath, "utf8"));
11089
12414
  const text3 = [issue.title, issue.body].filter((s) => typeof s === "string" && s.length > 0).join(`
11090
12415
 
11091
12416
  `);
@@ -11097,7 +12422,7 @@ function loadTaskText(ctx, fromPrior) {
11097
12422
  }
11098
12423
  function wallTargetDir(repoDir, existingTests) {
11099
12424
  const first = existingTests[0];
11100
- return first ? join43(repoDir, dirname14(first.path)) : join43(repoDir, "tests");
12425
+ return first ? join51(repoDir, dirname19(first.path)) : join51(repoDir, "tests");
11101
12426
  }
11102
12427
  function guessRunner(fileName, runners) {
11103
12428
  if (fileName.endsWith(".py"))
@@ -11128,11 +12453,11 @@ async function wallAuthor(ctx, signal) {
11128
12453
  const tree = prior.intake?.tree;
11129
12454
  const repomapText = repoMapText(ctx.repoDir, tree, repomapRef, WALL_MAP_MAX_LINES);
11130
12455
  const targetDir = wallTargetDir(ctx.repoDir, existingTests), pkg = loadProjectApi(ctx.repoDir)?.packageOf(`${relative6(ctx.repoDir, targetDir)}/x`);
11131
- const conv2 = readPackageConventions(join43(ctx.repoDir, pkg?.root ?? "."), pkg?.runner ?? null);
11132
- const cwd = mkdtempSync7(join43(tmpdir9(), "loki-e15-wall-"));
12456
+ const conv2 = readPackageConventions(join51(ctx.repoDir, pkg?.root ?? "."), pkg?.runner ?? null);
12457
+ const cwd = mkdtempSync7(join51(tmpdir9(), "loki-e15-wall-"));
11133
12458
  const wm = wallManifestFor(ctx.repoDir, tree, task);
11134
12459
  for (const [n2, c] of [["task.md", task], ["repomap.txt", repomapText], ...wm ? [["wall_manifest.txt", wm.text]] : []])
11135
- writeFileSync13(join43(cwd, n2), c, "utf8");
12460
+ writeFileSync19(join51(cwd, n2), c, "utf8");
11136
12461
  const session = await ctx.sessions.run({
11137
12462
  stage: "wall",
11138
12463
  brief: buildWallBrief(task, repomapText, runners, !!wm, conventionsBrief(conv2)),
@@ -11144,30 +12469,30 @@ async function wallAuthor(ctx, signal) {
11144
12469
  cwd
11145
12470
  });
11146
12471
  if (session.killed || session.exit === null) {
11147
- rmSync10(cwd, { recursive: true, force: true });
12472
+ rmSync13(cwd, { recursive: true, force: true });
11148
12473
  return done({ status: "failed", data: {}, reason: "wall session aborted, killed, or timed out", killed: true });
11149
12474
  }
11150
- const generated = readdirSync13(cwd).filter((f) => f.startsWith(WALL_PREFIX));
11151
- const sealedDir = join43(ctx.runDir, "wall");
12475
+ const generated = readdirSync15(cwd).filter((f) => f.startsWith(WALL_PREFIX));
12476
+ const sealedDir = join51(ctx.runDir, "wall");
11152
12477
  if (generated.length > 0)
11153
- mkdirSync10(sealedDir, { recursive: true });
12478
+ mkdirSync18(sealedDir, { recursive: true });
11154
12479
  const contents = new Map;
11155
12480
  const discarded = [];
11156
12481
  for (const name of generated) {
11157
- const content = readFileSync29(join43(cwd, name), "utf8"), bad = conventionViolation(conv2, name, content);
11158
- writeFileSync13(join43(sealedDir, name), content, "utf8");
12482
+ const content = readFileSync36(join51(cwd, name), "utf8"), bad = conventionViolation(conv2, name, content);
12483
+ writeFileSync19(join51(sealedDir, name), content, "utf8");
11159
12484
  if (bad)
11160
12485
  discarded.push({ file: name, reason: `${bad}; wall test did not compile under the package config` });
11161
12486
  else
11162
12487
  contents.set(name, content);
11163
12488
  }
11164
- rmSync10(cwd, { recursive: true, force: true });
12489
+ rmSync13(cwd, { recursive: true, force: true });
11165
12490
  return { kind: "authored", task, sizeName: sz.size, runners, targetDir, generated, contents, discarded, ...wm ? { manifestSha256: wm.sha256 } : {} };
11166
12491
  }
11167
12492
  function installWall(ctx, a, baseDir, opts = {}) {
11168
12493
  const { generated, contents, discarded, targetDir, runners } = a;
11169
12494
  if (generated.length > 0)
11170
- mkdirSync10(targetDir, { recursive: true });
12495
+ mkdirSync18(targetDir, { recursive: true });
11171
12496
  const sealedFiles = [];
11172
12497
  const readOnlyFiles = [];
11173
12498
  const wallTests = [];
@@ -11175,8 +12500,8 @@ function installWall(ctx, a, baseDir, opts = {}) {
11175
12500
  const content = contents.get(name);
11176
12501
  if (content === undefined)
11177
12502
  continue;
11178
- const dest = join43(targetDir, name), runner = guessRunner(name, runners);
11179
- writeFileSync13(dest, content, "utf8");
12503
+ const dest = join51(targetDir, name), runner = guessRunner(name, runners);
12504
+ writeFileSync19(dest, content, "utf8");
11180
12505
  sealedFiles.push({ path: dest, sha256: sha2562(content) });
11181
12506
  readOnlyFiles.push({ path: dest, content });
11182
12507
  if (runner)
@@ -11185,13 +12510,13 @@ function installWall(ctx, a, baseDir, opts = {}) {
11185
12510
  ctx.emit("wall.sealed", "wall", { files: sealedFiles, ...a.manifestSha256 ? { manifest_sha256: a.manifestSha256 } : {} });
11186
12511
  const baseRunner = opts.baseRunner ?? new RealBaseTestRunner, baseRun = { pass: 0, fail: 0, not_run: discarded.length }, notRunFiles = [];
11187
12512
  for (const t of wallTests) {
11188
- const r = baseRunner.run(baseDir, [t]), abs = join43(ctx.repoDir, t.path);
12513
+ const r = baseRunner.run(baseDir, [t]), abs = join51(ctx.repoDir, t.path);
11189
12514
  baseRun.pass += r.pass;
11190
12515
  baseRun.fail += r.fail;
11191
12516
  baseRun.not_run += r.not_run ?? 0;
11192
12517
  notRunFiles.push(...baseRunner.lastNotRunFiles ?? []);
11193
12518
  if (r.pass + r.fail === 0) {
11194
- rmSync10(abs, { force: true });
12519
+ rmSync13(abs, { force: true });
11195
12520
  for (const l of [sealedFiles, readOnlyFiles])
11196
12521
  l.splice(0, l.length, ...l.filter((f) => f.path !== abs));
11197
12522
  }
@@ -11215,7 +12540,7 @@ async function runWall(ctx, signal, opts = {}) {
11215
12540
  const a = await wallAuthor(ctx, signal);
11216
12541
  return a.kind === "done" ? a.result : installWall(ctx, a, ctx.repoDir, opts);
11217
12542
  }
11218
- var WALL_PREFIX = "loki_wall_", BASE_RUN_TIMEOUT_MS = 60000, WALL_MAP_MAX_LINES = 200, wallStage, stage;
12543
+ var WALL_PREFIX = "loki_wall_", BASE_RUN_TIMEOUT_MS = 60000, WALL_MAP_MAX_LINES = 200, wallStage, stage2;
11219
12544
  var init_wall = __esm(() => {
11220
12545
  init_types();
11221
12546
  init_lean_prefix();
@@ -11232,24 +12557,24 @@ var init_wall = __esm(() => {
11232
12557
  limitS: 300,
11233
12558
  run: (ctx, signal) => runWall(ctx, signal)
11234
12559
  };
11235
- stage = Object.assign(wallStage, { split: { author: wallAuthor, install: installWall } });
12560
+ stage2 = Object.assign(wallStage, { split: { author: wallAuthor, install: installWall } });
11236
12561
  });
11237
12562
 
11238
12563
  // ../../loki-ts/src/e10ext/discard.ts
11239
- import { chmodSync as chmodSync4, closeSync as closeSync6, lstatSync as lstatSync7, mkdirSync as mkdirSync11, openSync as openSync6, readFileSync as readFileSync30, realpathSync as realpathSync18, rmdirSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync14 } from "fs";
11240
- import { dirname as dirname15, join as join44, relative as relative7, sep as sep11 } from "path";
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";
11241
12566
  function safeRestore(repoDir, f, want, mode) {
11242
- const root = realpathSync18(repoDir), fp = join44(root, f), rel = relative7(root, dirname15(fp));
12567
+ const root = realpathSync19(repoDir), fp = join52(root, f), rel = relative7(root, dirname20(fp));
11243
12568
  if (rel.startsWith(".."))
11244
12569
  throw new Error("outside repo");
11245
12570
  let cur = root;
11246
12571
  for (const part of rel === "" ? [] : rel.split(sep11)) {
11247
- cur = join44(cur, part);
12572
+ cur = join52(cur, part);
11248
12573
  let st2;
11249
12574
  try {
11250
- st2 = lstatSync7(cur);
12575
+ st2 = lstatSync10(cur);
11251
12576
  } catch {
11252
- mkdirSync11(cur);
12577
+ mkdirSync19(cur);
11253
12578
  continue;
11254
12579
  }
11255
12580
  if (!st2.isDirectory())
@@ -11257,11 +12582,11 @@ function safeRestore(repoDir, f, want, mode) {
11257
12582
  }
11258
12583
  let st;
11259
12584
  try {
11260
- st = lstatSync7(fp);
12585
+ st = lstatSync10(fp);
11261
12586
  } catch {
11262
12587
  st = null;
11263
12588
  }
11264
- if (st?.isFile() && readFileSync30(fp).equals(want)) {
12589
+ if (st?.isFile() && readFileSync37(fp).equals(want)) {
11265
12590
  chmodSync4(fp, mode);
11266
12591
  return;
11267
12592
  }
@@ -11269,13 +12594,13 @@ function safeRestore(repoDir, f, want, mode) {
11269
12594
  if (st.isDirectory())
11270
12595
  rmdirSync(fp);
11271
12596
  else
11272
- unlinkSync3(fp);
12597
+ unlinkSync4(fp);
11273
12598
  }
11274
- const fd = openSync6(fp, "wx", mode);
12599
+ const fd = openSync8(fp, "wx", mode);
11275
12600
  try {
11276
- writeFileSync14(fd, want);
12601
+ writeFileSync20(fd, want);
11277
12602
  } finally {
11278
- closeSync6(fd);
12603
+ closeSync8(fd);
11279
12604
  }
11280
12605
  chmodSync4(fp, mode);
11281
12606
  }
@@ -11299,10 +12624,10 @@ async function discardIfSatisfied(git3, base, o, staged, keep, repoDir) {
11299
12624
  return { status: "failed", data: {}, reason: "already-satisfied discard failed" };
11300
12625
  const notProven = [];
11301
12626
  for (const [f, v] of Object.entries(o.intake?.preexisting_untracked_blobs ?? {})) {
11302
- const fp = join44(repoDir, f);
12627
+ const fp = join52(repoDir, f);
11303
12628
  try {
11304
12629
  if (v.startsWith("!")) {
11305
- const st = lstatSync7(fp);
12630
+ const st = lstatSync10(fp);
11306
12631
  if (`!${st.size}:${st.mtimeMs}:${st.ctimeMs}` !== v)
11307
12632
  throw new Error("changed, not snapshotted");
11308
12633
  continue;
@@ -11318,7 +12643,7 @@ async function discardIfSatisfied(git3, base, o, staged, keep, repoDir) {
11318
12643
  try {
11319
12644
  let m = 420;
11320
12645
  try {
11321
- const l = lstatSync7(join44(repoDir, f));
12646
+ const l = lstatSync10(join52(repoDir, f));
11322
12647
  if (l.isFile())
11323
12648
  m = l.mode & 511;
11324
12649
  } catch {}
@@ -11351,9 +12676,9 @@ var init_preexisting_dirty = __esm(() => {
11351
12676
  });
11352
12677
 
11353
12678
  // ../../loki-ts/src/e10ext/commit_filter.ts
11354
- import { dirname as dirname16 } from "path";
12679
+ import { dirname as dirname21 } from "path";
11355
12680
  function dropSet(repoDir, staged, preexistingDirty, env = process.env) {
11356
- 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) && dirname16(m) === dirname16(f)) && /(^|\/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|bun\.lockb?|poetry\.lock|Cargo\.lock|go\.sum)$/.test(f));
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));
11357
12682
  }
11358
12683
  var parseStaged = (out2) => out2.split("\x00").reduce((a, t, i, all) => i % 2 === 0 && t ? [...a, { st: t, f: all[i + 1] }] : a, []);
11359
12684
  var init_commit_filter = __esm(() => {
@@ -11361,73 +12686,8 @@ var init_commit_filter = __esm(() => {
11361
12686
  init_safe_git();
11362
12687
  });
11363
12688
 
11364
- // ../../loki-ts/src/features/speed/unit_mode.ts
11365
- import { closeSync as closeSync7, constants as constants2, fstatSync as fstatSync4, lstatSync as lstatSync8, openSync as openSync7, readSync as readSync5, realpathSync as realpathSync19 } from "fs";
11366
- function readBounded(path) {
11367
- const l = lstatSync8(path);
11368
- if (l.isSymbolicLink() || !l.isFile() || l.size > MAX_SPEC_BYTES)
11369
- return null;
11370
- const fd = openSync7(path, constants2.O_RDONLY | constants2.O_NOFOLLOW | constants2.O_NONBLOCK);
11371
- try {
11372
- const st = fstatSync4(fd);
11373
- if (!st.isFile() || st.size > MAX_SPEC_BYTES)
11374
- return null;
11375
- const buf = Buffer.alloc(st.size + 1);
11376
- let n2 = 0;
11377
- for (;; ) {
11378
- const r = readSync5(fd, buf, n2, buf.length - n2, null);
11379
- if (r <= 0)
11380
- break;
11381
- n2 += r;
11382
- if (n2 >= buf.length)
11383
- return null;
11384
- }
11385
- return buf.subarray(0, n2).toString("utf8");
11386
- } finally {
11387
- closeSync7(fd);
11388
- }
11389
- }
11390
- function parseText(txt) {
11391
- try {
11392
- const j = JSON.parse(txt), ws = strs(j.writeSet), pack = strs(j.pack), tb = j.tokenBudget;
11393
- if (typeof j.id !== "string" || !j.id || !ws || ws.length === 0 || !pack || typeof tb !== "number" || !Number.isFinite(tb) || !(tb > 0) || tb > MAX_TOKEN_BUDGET)
11394
- return null;
11395
- return { id: j.id, writeSet: ws, pack, tokenBudget: tb };
11396
- } catch {
11397
- return null;
11398
- }
11399
- }
11400
- function parseSpec(path) {
11401
- try {
11402
- const txt = readBounded(path);
11403
- return txt === null ? null : parseText(txt);
11404
- } catch {
11405
- return null;
11406
- }
11407
- }
11408
- function unitSpec(env = process.env) {
11409
- const path = env["LOKI_UNIT_SPEC"], frozen = env["LOKI_UNIT_SPEC_FROZEN"];
11410
- if (env["LOKI_SPEED"] === "0" || !path)
11411
- return null;
11412
- if (frozen !== undefined)
11413
- return frozen.length <= MAX_SPEC_BYTES ? parseText(frozen) : null;
11414
- if (!memo.has(path))
11415
- memo.set(path, parseSpec(path));
11416
- return memo.get(path) ?? null;
11417
- }
11418
- function unitFlags(staged, env = process.env, pre = {}) {
11419
- const s = unitSpec(env);
11420
- return s ? staged.filter(({ f }) => !inWriteSet(s, f) && !Object.hasOwn(pre, f)).map(({ f }) => f) : null;
11421
- }
11422
- 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);
11423
- var init_unit_mode = __esm(() => {
11424
- MAX_SPEC_BYTES = 1024 * 1024;
11425
- CTRL = /[\x00-\x1f\x7f]/;
11426
- memo = new Map;
11427
- });
11428
-
11429
12689
  // ../../loki-ts/src/e10ext/scope.ts
11430
- import { basename as basename16, dirname as dirname17 } from "path";
12690
+ import { basename as basename18, dirname as dirname22 } from "path";
11431
12691
  function contractText(o) {
11432
12692
  const c = o.intake?.contract_snapshot?.contract;
11433
12693
  return Array.isArray(c?.criteria) ? c.criteria.map((x) => typeof x?.text === "string" ? x.text : "").join(`
@@ -11441,8 +12701,8 @@ function outsideScope(o, staged) {
11441
12701
  const text3 = `${plan}
11442
12702
  ${typeof o.intake?.task === "string" ? o.intake.task : ""}
11443
12703
  ${contractText(o)}`, pre = o.intake?.preexisting_dirty ?? {};
11444
- const toks = surfaceTokens(text3), plannedDirs = new Set(rel.map((r) => dirname17(r)).filter((d) => d !== "."));
11445
- return staged.filter(({ st, f }) => st !== "A" && !isTestFile(f) && !Object.hasOwn(pre, f) && !rel.includes(f) && !mentions(text3, f) && !mentions(text3, basename16(f)) && !plannedDirs.has(dirname17(f)) && !dirSegs(f).some((d) => toks.has(d))).map(({ f }) => f);
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);
11446
12706
  }
11447
12707
  function flagOutsideScope(o, staged) {
11448
12708
  const unit = unitFlags(staged, process.env, o.intake?.preexisting_dirty ?? {});
@@ -11457,101 +12717,77 @@ var init_scope2 = __esm(() => {
11457
12717
  });
11458
12718
 
11459
12719
  // ../../loki-ts/src/util/receipt_signer.ts
11460
- var RECEIPT_SIGNER_BASENAME = "receipt-ed25519.pem";
11461
-
11462
- // ../../loki-ts/src/util/atomic.ts
11463
- import {
11464
- closeSync as closeSync8,
11465
- fstatSync as fstatSync5,
11466
- fsyncSync as fsyncSync2,
11467
- lstatSync as lstatSync9,
11468
- mkdirSync as mkdirSync12,
11469
- openSync as openSync8,
11470
- readSync as readSync6,
11471
- renameSync as renameSync5,
11472
- rmSync as rmSync11,
11473
- statSync as statSync15,
11474
- unlinkSync as unlinkSync4,
11475
- writeSync as writeSync3
11476
- } from "fs";
11477
- import { dirname as dirname18 } from "path";
11478
- function durableWriteThenRename(target, body) {
11479
- mkdirSync12(dirname18(target), { recursive: true });
11480
- const tmp = `${target}.tmp.${process.pid}.${++_tmpCounter}`;
11481
- const fd = openSync8(tmp, "w");
11482
- try {
11483
- writeSync3(fd, body);
11484
- fsyncSync2(fd);
11485
- } finally {
11486
- closeSync8(fd);
11487
- }
11488
- renameSync5(tmp, target);
11489
- fsyncParentDir(target);
11490
- }
11491
- function fsyncParentDir(target) {
11492
- let dfd = null;
11493
- try {
11494
- dfd = openSync8(dirname18(target), "r");
11495
- fsyncSync2(dfd);
11496
- } catch {} finally {
11497
- if (dfd !== null) {
11498
- try {
11499
- closeSync8(dfd);
11500
- } catch {}
12720
+ 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";
12722
+ import { homedir as homedir8 } from "os";
12723
+ import { dirname as dirname23, join as join53 } from "path";
12724
+ function canonicalJson(x) {
12725
+ const walk = (v) => {
12726
+ if (Array.isArray(v))
12727
+ return `[${v.map(walk).join(",")}]`;
12728
+ if (v !== null && typeof v === "object") {
12729
+ const o = v;
12730
+ return `{${Object.keys(o).filter((k) => o[k] !== undefined).sort().map((k) => `${JSON.stringify(k)}:${walk(o[k])}`).join(",")}}`;
11501
12731
  }
11502
- }
11503
- }
11504
- function atomicWriteJson(target, data) {
11505
- durableWriteThenRename(target, `${JSON.stringify(data, null, 2)}
11506
- `);
12732
+ return JSON.stringify(v ?? null);
12733
+ };
12734
+ return walk(x).replace(/[\u0080-\uFFFF]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`);
11507
12735
  }
11508
- var _tmpCounter = 0, _appendChains;
11509
- var init_atomic = __esm(() => {
11510
- _appendChains = new Map;
11511
- });
11512
-
11513
- // ../../loki-ts/src/util/pr_lessons.ts
11514
- import { existsSync as existsSync25, mkdirSync as mkdirSync13, readFileSync as readFileSync31 } from "fs";
11515
- import { dirname as dirname19, join as join45 } from "path";
11516
- function loadLessons(repoDir) {
11517
- const p = lessonsPath(repoDir);
11518
- if (!existsSync25(p))
11519
- return [];
12736
+ function loadSigningKey(generate = true) {
11520
12737
  try {
11521
- const j = JSON.parse(readFileSync31(p, "utf-8"));
11522
- return Array.isArray(j.lessons) ? j.lessons : [];
12738
+ const inline = process.env["LOKI_RECEIPT_SIGNING_KEY"]?.trim();
12739
+ let pem = inline ?? "";
12740
+ if (!inline) {
12741
+ const given = process.env["LOKI_RECEIPT_SIGNING_KEY_FILE"]?.trim();
12742
+ const file = given || join53(process.env["HOME"] || homedir8(), ".loki", "keys", RECEIPT_SIGNER_BASENAME);
12743
+ try {
12744
+ pem = readFileSync38(file);
12745
+ if (!given) {
12746
+ for (const [f, m] of [[file, 384], [dirname23(file), 448]])
12747
+ if (statSync17(f).mode & 63)
12748
+ chmodSync5(f, m);
12749
+ }
12750
+ } catch (e) {
12751
+ if (e.code !== "ENOENT" || !generate)
12752
+ return null;
12753
+ mkdirSync20(dirname23(dirname23(file)), { recursive: true, mode: 448 });
12754
+ mkdirSync20(dirname23(file), { recursive: true, mode: 448 });
12755
+ const tmp = `${file}.${randomBytes3(6).toString("hex")}.tmp`;
12756
+ writeFileSync21(tmp, generateKeyPairSync("ed25519").privateKey.export({ type: "pkcs8", format: "pem" }), { flag: "wx", mode: 384 });
12757
+ try {
12758
+ linkSync(tmp, file);
12759
+ } catch (l) {
12760
+ if (l.code !== "EEXIST")
12761
+ throw l;
12762
+ } finally {
12763
+ unlinkSync5(tmp);
12764
+ }
12765
+ pem = readFileSync38(file);
12766
+ }
12767
+ }
12768
+ const k = createPrivateKey(pem);
12769
+ return k.asymmetricKeyType === "ed25519" ? k : null;
11523
12770
  } catch {
11524
- return [];
12771
+ return null;
11525
12772
  }
11526
12773
  }
11527
- function save(repoDir, lessons) {
11528
- const p = lessonsPath(repoDir);
11529
- mkdirSync13(dirname19(p), { recursive: true });
11530
- atomicWriteJson(p, { version: 2, lessons });
11531
- }
11532
- function recordRunVerdict(repoDir, runId, verdict) {
11533
- const lessons = loadLessons(repoDir);
11534
- let dirty = false;
11535
- for (const l of lessons)
11536
- for (const u of l.uses)
11537
- if (u.run_id === runId && u.verdict === null) {
11538
- u.verdict = verdict;
11539
- dirty = true;
11540
- }
11541
- if (dirty)
11542
- save(repoDir, lessons);
12774
+ function signReceipt(runId, hash) {
12775
+ const key = loadSigningKey();
12776
+ if (!key)
12777
+ return { jwt: null, kid: null };
12778
+ const kid = kidOf2(createPublicKey2(key));
12779
+ const input = `${b64u(canonicalJson({ alg: "EdDSA", typ: "JWT", kid }))}.${b64u(canonicalJson({ job_id: runId, run_id: runId, receipt_sha256: hash, iat: Math.floor(Date.now() / 1000) }))}`;
12780
+ return { jwt: `${input}.${b64u(sign(null, Buffer.from(input), key))}`, kid };
11543
12781
  }
11544
- var lessonsPath = (repoDir) => join45(repoDir, ".loki", "memory", "semantic", "pr-lessons.json");
11545
- var init_pr_lessons = __esm(() => {
11546
- init_atomic();
11547
- });
12782
+ var RECEIPT_SIGNER_BASENAME = "receipt-ed25519.pem", b64u = (b) => Buffer.from(b).toString("base64url"), kidOf2 = (pub) => b64u(createHash11("sha256").update(`{"crv":"Ed25519","kty":"OKP","x":"${pub.export({ format: "jwk" }).x}"}`).digest());
12783
+ var init_receipt_signer = () => {};
11548
12784
 
11549
12785
  // ../../loki-ts/src/features/visual_evidence.ts
11550
12786
  import { spawn as spawn7 } from "child_process";
11551
- import { createHash as createHash10, randomBytes as randomBytes3 } from "crypto";
11552
- import { existsSync as existsSync26, lstatSync as lstatSync10, mkdirSync as mkdirSync14, readdirSync as readdirSync14, readFileSync as readFileSync32, writeFileSync as writeFileSync15 } from "fs";
12787
+ 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";
11553
12789
  import { createServer } from "net";
11554
- import { dirname as dirname20, isAbsolute as isAbsolute7, join as join46, normalize as normalize2, relative as relative8, sep as sep12 } from "path";
12790
+ import { dirname as dirname24, isAbsolute as isAbsolute8, join as join54, normalize as normalize2, relative as relative8, sep as sep12 } from "path";
11555
12791
  function routeFor(file) {
11556
12792
  let r = file.replace(/^(?:.*?\/)?(?:app|pages|src|public)\//, "").replace(/^(?:routes|pages)\//, "");
11557
12793
  r = r.replace(/\.(?:html|jsx|tsx|vue|svelte)$/, "").replace(/\/?(?:page|index|\+page)$/, "");
@@ -11561,7 +12797,7 @@ function hashScreens(runDir, rels) {
11561
12797
  const out2 = [];
11562
12798
  for (const rel of rels) {
11563
12799
  try {
11564
- out2.push({ path: rel, sha256: sha256File(join46(runDir, rel)) });
12800
+ out2.push({ path: rel, sha256: sha256File(join54(runDir, rel)) });
11565
12801
  } catch {}
11566
12802
  }
11567
12803
  return out2;
@@ -11572,16 +12808,16 @@ function checkScreens(runDir, screens) {
11572
12808
  for (const s of screens) {
11573
12809
  if (typeof s?.path !== "string" || typeof s.sha256 !== "string")
11574
12810
  return "evidence_screens entry is malformed";
11575
- if (isAbsolute7(s.path) || normalize2(s.path).startsWith(".."))
12811
+ if (isAbsolute8(s.path) || normalize2(s.path).startsWith(".."))
11576
12812
  return `evidence screenshot path escapes the evidence dir: ${s.path}`;
11577
- const file = join46(runDir, s.path);
12813
+ const file = join54(runDir, s.path);
11578
12814
  let cur = runDir;
11579
12815
  for (const seg of normalize2(s.path).split(sep12)) {
11580
- cur = join46(cur, seg);
12816
+ cur = join54(cur, seg);
11581
12817
  if (isSymlink(cur))
11582
12818
  return `evidence screenshot path is a symlink: ${s.path}`;
11583
12819
  }
11584
- if (!existsSync26(file))
12820
+ if (!existsSync32(file))
11585
12821
  return `evidence screenshot is missing: ${s.path}`;
11586
12822
  if (!isRegularFile(file))
11587
12823
  return `evidence screenshot is not a regular file: ${s.path}`;
@@ -11624,11 +12860,11 @@ async function waitUp(url, ms, signal) {
11624
12860
  }
11625
12861
  function openapiPaths(repoDir) {
11626
12862
  for (const f of ["openapi.json", "openapi.yaml", "openapi.yml", "swagger.json"]) {
11627
- const p = join46(repoDir, f);
11628
- if (!existsSync26(p))
12863
+ const p = join54(repoDir, f);
12864
+ if (!existsSync32(p))
11629
12865
  continue;
11630
12866
  try {
11631
- const txt = readFileSync32(p, "utf8");
12867
+ const txt = readFileSync39(p, "utf8");
11632
12868
  const paths = f.endsWith(".json") ? Object.keys(JSON.parse(txt).paths ?? {}) : [...txt.matchAll(/^ {2}(\/[^\s:]*):\s*$/gm)].map((m) => m[1]);
11633
12869
  return paths.filter((x) => !x.includes("{")).slice(0, 10);
11634
12870
  } catch {
@@ -11642,24 +12878,24 @@ async function recordE2eMedia(repoDir, runDir, relDir, base, routes, ms, signal)
11642
12878
  if (!pw || !pkg)
11643
12879
  return { rels: [], skipped: "playwright e2e video and trace skipped: @playwright/test is not installed in the repo" };
11644
12880
  try {
11645
- const dir = join46(runDir, relDir, "e2e");
11646
- mkdirSync14(dir, { recursive: true });
11647
- writeFileSync15(join46(dir, "walk.spec.cjs"), e2eSpecSource(pkg, base, routes));
11648
- writeFileSync15(join46(dir, "playwright.config.cjs"), `module.exports = { testDir: ".", testMatch: "walk.spec.cjs", outputDir: "./out", reporter: "null", use: { video: "on", trace: "on" } };
12881
+ const dir = join54(runDir, relDir, "e2e");
12882
+ 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" } };
11649
12885
  `);
11650
- if (!await shoot(pw, ["test", "--config", join46(dir, "playwright.config.cjs")], repoDir, ms, signal))
12886
+ if (!await shoot(pw, ["test", "--config", join54(dir, "playwright.config.cjs")], repoDir, ms, signal))
11651
12887
  return { rels: [], skipped: "playwright e2e video and trace skipped: the run failed or timed out" };
11652
12888
  const rels = [];
11653
12889
  const walk = (d) => {
11654
- for (const e of readdirSync14(d, { withFileTypes: true })) {
11655
- const full = join46(d, e.name);
12890
+ for (const e of readdirSync16(d, { withFileTypes: true })) {
12891
+ const full = join54(d, e.name);
11656
12892
  if (e.isDirectory())
11657
12893
  walk(full);
11658
12894
  else if (e.isFile() && /\.(webm|zip)$/.test(e.name))
11659
- rels.push(join46(relDir, "e2e", relative8(dir, full)));
12895
+ rels.push(join54(relDir, "e2e", relative8(dir, full)));
11660
12896
  }
11661
12897
  };
11662
- walk(join46(dir, "out"));
12898
+ walk(join54(dir, "out"));
11663
12899
  return rels.length > 0 ? { rels, skipped: null } : { rels, skipped: "playwright e2e video and trace skipped: no video or trace was produced" };
11664
12900
  } catch (e) {
11665
12901
  return { rels: [], skipped: `playwright e2e video and trace skipped: ${String(e?.message ?? e).slice(0, 120)}` };
@@ -11728,13 +12964,13 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
11728
12964
  if (!visualEvidenceEnabled(opts.env))
11729
12965
  return skip("LOKI_VISUAL_EVIDENCE is 0");
11730
12966
  const api = loadProjectApi(repoDir), boot = isMultiRoot(api) ? api.uiBoot() : null;
11731
- const appDir = boot ? join46(repoDir, boot.boot.cwd) : repoDir;
11732
- const pkgPath = join46(appDir, "package.json");
12967
+ const appDir = boot ? join54(repoDir, boot.boot.cwd) : repoDir;
12968
+ const pkgPath = join54(appDir, "package.json");
11733
12969
  let script = null;
11734
12970
  if (!boot) {
11735
- if (!existsSync26(pkgPath))
12971
+ if (!existsSync32(pkgPath))
11736
12972
  return skip("no package.json");
11737
- script = pickScript(JSON.parse(readFileSync32(pkgPath, "utf8")));
12973
+ script = pickScript(JSON.parse(readFileSync39(pkgPath, "utf8")));
11738
12974
  if (!script)
11739
12975
  return skip("no dev, preview or start script");
11740
12976
  }
@@ -11761,20 +12997,20 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
11761
12997
  }
11762
12998
  if (!await waitUp(base, left(), signal))
11763
12999
  return skip(aborted() ? "aborted" : `${script} server did not answer within ${Math.round(budget / 1000)}s`);
11764
- const evRoot = join46(runDir, "evidence");
13000
+ const evRoot = join54(runDir, "evidence");
11765
13001
  if (isSymlink(evRoot))
11766
13002
  return skip("evidence dir is a symlink");
11767
- mkdirSync14(evRoot, { recursive: true });
13003
+ mkdirSync21(evRoot, { recursive: true });
11768
13004
  if (pages.length > 0) {
11769
- const rel0 = join46("evidence", randomBytes3(6).toString("hex"));
11770
- mkdirSync14(join46(runDir, rel0));
13005
+ const rel0 = join54("evidence", randomBytes4(6).toString("hex"));
13006
+ mkdirSync21(join54(runDir, rel0));
11771
13007
  const rels = [];
11772
13008
  for (const route of [...new Set(pages.map(routeFor))].slice(0, opts.maxRoutes ?? MAX_ROUTES)) {
11773
13009
  if (aborted() || left() <= 0)
11774
13010
  break;
11775
- const rel = join46(rel0, `${screenName(route)}.png`);
11776
- const ok = await shoot(pw, ["screenshot", `${base}${route}`, join46(runDir, rel)], appDir, left(), signal);
11777
- if (ok && !aborted() && !isSymlink(join46(runDir, rel)) && existsSync26(join46(runDir, rel)))
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)))
11778
13014
  rels.push(rel);
11779
13015
  }
11780
13016
  if (aborted())
@@ -11799,9 +13035,9 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
11799
13035
  }
11800
13036
  if (aborted())
11801
13037
  return skip("aborted");
11802
- const hdir = join46(evRoot, randomBytes3(6).toString("hex"));
11803
- mkdirSync14(hdir);
11804
- writeFileSync15(join46(hdir, "http.json"), JSON.stringify(rows, null, 2) + `
13038
+ const hdir = join54(evRoot, randomBytes4(6).toString("hex"));
13039
+ mkdirSync21(hdir);
13040
+ writeFileSync22(join54(hdir, "http.json"), JSON.stringify(rows, null, 2) + `
11805
13041
  `);
11806
13042
  return { screens: [], http: true, skipped: null };
11807
13043
  } catch (e) {
@@ -11824,27 +13060,27 @@ async function sealEvidence(repoDir, runDir, o, notProven, signal, emit) {
11824
13060
  return ev.screens.length > 0 ? { evidence_screens: ev.screens } : {};
11825
13061
  }
11826
13062
  function receiptScreensProblem(receiptPath, receipt) {
11827
- return receipt["evidence_screens"] === undefined ? null : checkScreens(dirname20(receiptPath), receipt["evidence_screens"]);
13063
+ return receipt["evidence_screens"] === undefined ? null : checkScreens(dirname24(receiptPath), receipt["evidence_screens"]);
11828
13064
  }
11829
- 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) => createHash10("sha256").update(readFileSync32(p)).digest("hex"), playwrightBin = (repoDir) => {
11830
- const bin = join46(repoDir, "node_modules", ".bin", "playwright");
11831
- return existsSync26(bin) ? bin : null;
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");
13067
+ return existsSync32(bin) ? bin : null;
11832
13068
  }, playwrightTestPkg = (repoDir) => {
11833
- const d = join46(repoDir, "node_modules", "@playwright", "test");
11834
- return existsSync26(join46(d, "package.json")) ? d : null;
13069
+ const d = join54(repoDir, "node_modules", "@playwright", "test");
13070
+ return existsSync32(join54(d, "package.json")) ? d : null;
11835
13071
  }, e2eSpecSource = (pkgDir, base, routes) => `const { test } = require(${JSON.stringify(pkgDir)});
11836
13072
  test("loki e2e walkthrough", async ({ page }) => {
11837
13073
  for (const r of ${JSON.stringify(routes)}) { await page.goto(${JSON.stringify(base)} + r); await page.waitForLoadState("load"); }
11838
13074
  });
11839
13075
  `, DEFAULT_BUDGET_MS = 25000, MAX_ROUTES = 5, isSymlink = (p) => {
11840
13076
  try {
11841
- return lstatSync10(p).isSymbolicLink();
13077
+ return lstatSync11(p).isSymbolicLink();
11842
13078
  } catch {
11843
13079
  return false;
11844
13080
  }
11845
13081
  }, isRegularFile = (p) => {
11846
13082
  try {
11847
- return lstatSync10(p).isFile();
13083
+ return lstatSync11(p).isFile();
11848
13084
  } catch {
11849
13085
  return false;
11850
13086
  }
@@ -11862,14 +13098,14 @@ var init_visual_evidence = __esm(() => {
11862
13098
  });
11863
13099
 
11864
13100
  // ../../loki-ts/src/council/role_agents.ts
11865
- import { existsSync as existsSync27, readdirSync as readdirSync15, readFileSync as readFileSync33 } from "fs";
11866
- import { homedir as homedir8 } from "os";
11867
- import { join as join47 } from "path";
13101
+ import { existsSync as existsSync33, readdirSync as readdirSync17, readFileSync as readFileSync40 } from "fs";
13102
+ import { homedir as homedir9 } from "os";
13103
+ import { join as join55 } from "path";
11868
13104
  function agentDirs(repoDir, env = process.env) {
11869
- return [env["LOKI_AGENTS_PROJECT_DIR"] || join47(repoDir, ".loki", "agents"), env["LOKI_AGENTS_USER_DIR"] || join47(env["XDG_CONFIG_HOME"] || join47(homedir8(), ".config"), "loki", "agents")];
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")];
11870
13106
  }
11871
13107
  function parseAgent(file, stem2) {
11872
- const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(readFileSync33(file, "utf8"));
13108
+ const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(readFileSync40(file, "utf8"));
11873
13109
  if (!m)
11874
13110
  return null;
11875
13111
  const body = m[2].trim();
@@ -11883,18 +13119,18 @@ function parseAgent(file, stem2) {
11883
13119
  }
11884
13120
  function loadRoleAgent(repoDir, role, env = process.env) {
11885
13121
  for (const d of agentDirs(repoDir, env)) {
11886
- if (!existsSync27(d))
13122
+ if (!existsSync33(d))
11887
13123
  continue;
11888
13124
  let names;
11889
13125
  try {
11890
- names = readdirSync15(d).filter((n2) => n2.endsWith(".md") && !n2.startsWith(".")).sort();
13126
+ names = readdirSync17(d).filter((n2) => n2.endsWith(".md") && !n2.startsWith(".")).sort();
11891
13127
  } catch {
11892
13128
  continue;
11893
13129
  }
11894
13130
  const ordered = [...names.filter((n2) => n2 === `${role}.md`), ...names.filter((n2) => n2 !== `${role}.md`)];
11895
13131
  for (const n2 of ordered) {
11896
13132
  try {
11897
- const a = parseAgent(join47(d, n2), n2.slice(0, -3));
13133
+ const a = parseAgent(join55(d, n2), n2.slice(0, -3));
11898
13134
  if (a && a.role === role)
11899
13135
  return a;
11900
13136
  } catch {}
@@ -11910,83 +13146,12 @@ var init_role_agents = __esm(() => {
11910
13146
  ROLES = ["council", "reviewer"];
11911
13147
  });
11912
13148
 
11913
- // ../../loki-ts/src/util/shell.ts
11914
- async function readStreamCapped(stream, maxBytes = MAX_STDOUT_BYTES) {
11915
- const reader = stream.getReader();
11916
- const decoder = new TextDecoder;
11917
- let out2 = "";
11918
- let total = 0;
11919
- try {
11920
- while (total < maxBytes) {
11921
- const { done, value } = await reader.read();
11922
- if (done)
11923
- break;
11924
- if (!value)
11925
- continue;
11926
- total += value.byteLength;
11927
- if (total > maxBytes) {
11928
- const keep = value.byteLength - (total - maxBytes);
11929
- out2 += decoder.decode(value.subarray(0, keep), { stream: true });
11930
- break;
11931
- }
11932
- out2 += decoder.decode(value, { stream: true });
11933
- }
11934
- out2 += decoder.decode();
11935
- } finally {
11936
- try {
11937
- await reader.cancel();
11938
- } catch {}
11939
- reader.releaseLock();
11940
- }
11941
- return out2;
11942
- }
11943
- async function run(argv, opts = {}) {
11944
- const proc = Bun.spawn({
11945
- cmd: [...argv],
11946
- stdout: "pipe",
11947
- stderr: "pipe",
11948
- env: opts.env ? { ...process.env, ...opts.env } : process.env,
11949
- cwd: opts.cwd
11950
- });
11951
- let timer;
11952
- let killTimer;
11953
- if (opts.timeoutMs && opts.timeoutMs > 0) {
11954
- timer = setTimeout(() => {
11955
- try {
11956
- proc.kill("SIGTERM");
11957
- } catch {}
11958
- killTimer = setTimeout(() => {
11959
- try {
11960
- proc.kill("SIGKILL");
11961
- } catch {}
11962
- }, 2000);
11963
- }, opts.timeoutMs);
11964
- }
11965
- try {
11966
- const [stdout, stderr, exitCode] = await Promise.all([
11967
- readStreamCapped(proc.stdout),
11968
- new Response(proc.stderr).text(),
11969
- proc.exited
11970
- ]);
11971
- return { stdout, stderr, exitCode };
11972
- } finally {
11973
- if (timer)
11974
- clearTimeout(timer);
11975
- if (killTimer)
11976
- clearTimeout(killTimer);
11977
- }
11978
- }
11979
- var MAX_STDOUT_BYTES;
11980
- var init_shell = __esm(() => {
11981
- MAX_STDOUT_BYTES = 16 * 1024 * 1024;
11982
- });
11983
-
11984
13149
  // ../../loki-ts/src/engine10/stages/xreview.ts
11985
- import { existsSync as existsSync28, readFileSync as readFileSync34 } from "fs";
11986
- import { join as join48 } from "path";
13150
+ import { existsSync as existsSync34, readFileSync as readFileSync41 } from "fs";
13151
+ import { join as join56 } from "path";
11987
13152
  function minVerdict(verdict, review) {
11988
13153
  const ceiling = review?.level === "block" ? "PARTIAL" : verdict;
11989
- return RANK2[ceiling] < RANK2[verdict] ? ceiling : verdict;
13154
+ return RANK3[ceiling] < RANK3[verdict] ? ceiling : verdict;
11990
13155
  }
11991
13156
  function explicitReview(repoDir, env) {
11992
13157
  const flag = xvendorDefault(env);
@@ -11996,11 +13161,11 @@ function explicitReview(repoDir, env) {
11996
13161
  if (flag && isOff(ev))
11997
13162
  return "off";
11998
13163
  for (const f of ["loki.yaml", "loki.yml"]) {
11999
- const p = join48(repoDir, f);
12000
- if (!existsSync28(p))
13164
+ const p = join56(repoDir, f);
13165
+ if (!existsSync34(p))
12001
13166
  continue;
12002
13167
  try {
12003
- const m = /^review:[ \t]*["']?([A-Za-z]+)["']?[ \t]*(?:#.*)?$/m.exec(readFileSync34(p, "utf8"));
13168
+ const m = /^review:[ \t]*["']?([A-Za-z]+)["']?[ \t]*(?:#.*)?$/m.exec(readFileSync41(p, "utf8"));
12004
13169
  const v = asProvider(m?.[1]);
12005
13170
  if (v)
12006
13171
  return v;
@@ -12078,7 +13243,7 @@ Review ONLY the diff below. Do not modify files.` : "You are an independent code
12078
13243
  return { provider: p, level: "not_run", notes: [`cross-review not run: ${p} CLI unavailable`] };
12079
13244
  }
12080
13245
  }
12081
- var RANK2, TIMEOUT_MS = 300000, MAX_DIFF = 60000, MAX_NOTES = 5, asProvider = (v) => {
13246
+ var RANK3, TIMEOUT_MS = 300000, MAX_DIFF = 60000, MAX_NOTES = 5, asProvider = (v) => {
12082
13247
  const s = v?.trim().toLowerCase();
12083
13248
  return s === "codex" || s === "claude" ? s : null;
12084
13249
  }, isOff = (v) => /^(off|none|false|0)$/i.test(v?.trim() ?? ""), xvendorDefault = (env = process.env) => /^(1|true|yes|on)$/i.test(env["LOKI_XVENDOR_DEFAULT"]?.trim() ?? ""), reviewCli = (p, env = process.env) => env[`LOKI_${p.toUpperCase()}_CLI`]?.trim() || p, clean3 = (s) => s.replace(/[\x00-\x1f\x7f`]+/g, " ").trim().slice(0, 300);
@@ -12086,107 +13251,7 @@ var init_xreview = __esm(() => {
12086
13251
  init_role_agents();
12087
13252
  init_shell();
12088
13253
  init_safe_git();
12089
- RANK2 = { FAILED: 0, SPEC_CONFLICT: 0, PARTIAL: 1, ALREADY_SATISFIED: 2, VERIFIED: 2 };
12090
- });
12091
-
12092
- // ../../loki-ts/src/runner/router/route_record.ts
12093
- import { existsSync as existsSync29, lstatSync as lstatSync11, mkdirSync as mkdirSync15, readFileSync as readFileSync35, writeFileSync as writeFileSync16 } from "fs";
12094
- import { join as join49 } from "path";
12095
- function loadRouteRecord(runDir) {
12096
- try {
12097
- const p = join49(runDir, ROUTE_RECORD_FILE);
12098
- if (!existsSync29(p) || !lstatSync11(p).isFile())
12099
- return;
12100
- const v = JSON.parse(readFileSync35(p, "utf8"));
12101
- return typeof v === "object" && v !== null && !Array.isArray(v) ? v : undefined;
12102
- } catch {
12103
- return;
12104
- }
12105
- }
12106
- var ROUTE_RECORD_FILE = "route.json";
12107
- var init_route_record = () => {};
12108
-
12109
- // ../../loki-ts/src/runner/router/history_store.ts
12110
- import { existsSync as existsSync30, mkdirSync as mkdirSync16, readFileSync as readFileSync36, renameSync as renameSync6, rmSync as rmSync12, writeFileSync as writeFileSync17 } from "fs";
12111
- import { resolve as resolve11 } from "path";
12112
- function validRun(v) {
12113
- if (typeof v !== "object" || v === null)
12114
- return false;
12115
- const r = v;
12116
- return typeof r["shape"] === "string" && typeof r["executor"] === "string" && EXECUTORS.includes(r["executor"]) && typeof r["verdict"] === "string" && VERDICTS.includes(r["verdict"]) && (r["owner"] === null || typeof r["owner"] === "string" && OWNERS.includes(r["owner"])) && typeof r["escalated"] === "boolean" && typeof r["usd"] === "number" && Number.isFinite(r["usd"]) && typeof r["wallS"] === "number" && Number.isFinite(r["wallS"]);
12117
- }
12118
- function historyPath(key, cacheRoot) {
12119
- return resolve11(repoCacheDir(key, cacheRoot), HISTORY_FILE);
12120
- }
12121
- function readRunHistory(key, cacheRoot) {
12122
- const path = historyPath(key, cacheRoot);
12123
- if (!existsSync30(path))
12124
- return [];
12125
- try {
12126
- const parsed = JSON.parse(readFileSync36(path, "utf8"));
12127
- const runs2 = parsed?.runs;
12128
- return Array.isArray(runs2) ? runs2.filter(validRun) : [];
12129
- } catch {
12130
- return [];
12131
- }
12132
- }
12133
- function appendRunOutcome(key, outcome, cacheRoot) {
12134
- try {
12135
- const runs2 = [...readRunHistory(key, cacheRoot), outcome].slice(-HISTORY_CAP);
12136
- mkdirSync16(repoCacheDir(key, cacheRoot), { recursive: true });
12137
- const target = historyPath(key, cacheRoot);
12138
- const tmp = `${target}.${process.pid}.tmp`;
12139
- try {
12140
- writeFileSync17(tmp, JSON.stringify({ runs: runs2 }));
12141
- renameSync6(tmp, target);
12142
- } catch (e) {
12143
- rmSync12(tmp, { force: true, recursive: false });
12144
- throw e;
12145
- }
12146
- return true;
12147
- } catch {
12148
- return false;
12149
- }
12150
- }
12151
- var HISTORY_FILE = "router_history.json", HISTORY_CAP = 200, WALL_KIND = "total-v1", EXECUTORS, VERDICTS, OWNERS;
12152
- var init_history_store = __esm(() => {
12153
- init_cache();
12154
- EXECUTORS = ["haiku", "sonnet"];
12155
- VERDICTS = ["pass", "fail", "error", "not_proven"];
12156
- OWNERS = ["code", "harness", "env", "provider"];
12157
- });
12158
-
12159
- // ../../loki-ts/src/runner/router/history.ts
12160
- import { dirname as dirname21, join as join50, resolve as resolve12 } from "path";
12161
- import { fileURLToPath as fileURLToPath3 } from "url";
12162
- function shapeKey(model) {
12163
- if (!model || model.status !== "ok")
12164
- return null;
12165
- const runners = new Set(model.packages.map((p) => (p.runner ?? "").trim().toLowerCase() || "none"));
12166
- return `${model.workspaceKind}:${[...runners].sort().join("+")}`;
12167
- }
12168
- function shapeKeyForRepo(repoDir) {
12169
- try {
12170
- const dirs = shallowDirs(repoDir);
12171
- const committed = loadCommitted(repoDir);
12172
- if (committed)
12173
- return shapeKey({ ...committed.model, key: computeKey(repoDir, committed.model.fingerprintFiles, dirs, committed.hash) });
12174
- const cached = loadCached(repoDir);
12175
- if (!cached || computeKey(repoDir, cached.fingerprintFiles, dirs) !== cached.key)
12176
- return null;
12177
- return shapeKey(cached);
12178
- } catch {
12179
- return null;
12180
- }
12181
- }
12182
- var SHAPE_DEFAULTS_FILE;
12183
- var init_history = __esm(() => {
12184
- init_schema();
12185
- init_history_store();
12186
- init_discover2();
12187
- init_gather();
12188
- init_history_store();
12189
- SHAPE_DEFAULTS_FILE = resolve12(dirname21(fileURLToPath3(import.meta.url)), "..", "..", "..", "data", "router-shape-defaults.json");
13254
+ RANK3 = { FAILED: 0, SPEC_CONFLICT: 0, PARTIAL: 1, ALREADY_SATISFIED: 2, VERIFIED: 2 };
12190
13255
  });
12191
13256
 
12192
13257
  // ../../loki-ts/src/util/engine_origin.ts
@@ -12235,9 +13300,9 @@ var init_cost_preview = __esm(() => {
12235
13300
  });
12236
13301
 
12237
13302
  // ../../loki-ts/src/features/contract.ts
12238
- import { existsSync as existsSync31, lstatSync as lstatSync12, mkdirSync as mkdirSync17, readFileSync as readFileSync37, writeFileSync as writeFileSync18 } from "fs";
12239
- import { dirname as dirname22, join as join51 } from "path";
12240
- import { createHash as createHash11 } from "crypto";
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";
13305
+ import { createHash as createHash13 } from "crypto";
12241
13306
  function contractEnabled(env = process.env) {
12242
13307
  return env["LOKI_CONTRACT"] !== "0";
12243
13308
  }
@@ -12268,7 +13333,7 @@ function untracedLines(trace) {
12268
13333
  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)}`);
12269
13334
  }
12270
13335
  function contractPath(repoDir) {
12271
- return join51(repoDir, ".loki", "contract.json");
13336
+ return join57(repoDir, ".loki", "contract.json");
12272
13337
  }
12273
13338
  function readContract(repoDir) {
12274
13339
  const p = contractPath(repoDir);
@@ -12284,11 +13349,11 @@ function readContract(repoDir) {
12284
13349
  return { contract: null, notes: ["contract unreadable: too large"], sha256: null };
12285
13350
  let raw2;
12286
13351
  try {
12287
- raw2 = readFileSync37(p);
13352
+ raw2 = readFileSync42(p);
12288
13353
  } catch {
12289
13354
  return { contract: null, notes: ["contract unreadable: read failed"], sha256: null };
12290
13355
  }
12291
- const sha2563 = createHash11("sha256").update(raw2).digest("hex");
13356
+ const sha2563 = createHash13("sha256").update(raw2).digest("hex");
12292
13357
  let j;
12293
13358
  try {
12294
13359
  j = JSON.parse(raw2.toString("utf8"));
@@ -12345,16 +13410,21 @@ function sealContract(repoDir, body, rawDiff, checks, env = process.env, snap) {
12345
13410
  return [`contract trace failed: ${sanitizeCriterion(e instanceof Error ? e.message : String(e))}`];
12346
13411
  }
12347
13412
  }
12348
- var MAX_CRITERIA = 50, MAX_TEXT = 500, STOP2, MAX_CONTRACT_BYTES;
13413
+ var MAX_CRITERIA = 50, MAX_TEXT = 500, STOP2, MAX_CONTRACT_BYTES, REQ_MAP_REL, REQ_STOP;
12349
13414
  var init_contract = __esm(() => {
13415
+ init_atomic();
13416
+ init_spec_file();
13417
+ init_paths();
12350
13418
  init_safe_git();
12351
13419
  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"]);
12352
13420
  MAX_CONTRACT_BYTES = 1024 * 1024;
13421
+ REQ_MAP_REL = join57(".loki", "state", "requirements-map.json");
13422
+ 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"]);
12353
13423
  });
12354
13424
 
12355
13425
  // ../../loki-ts/src/supply/supply_guard.ts
12356
- import { existsSync as existsSync32, readFileSync as readFileSync38, statSync as statSync16 } from "fs";
12357
- import { basename as basename17, join as join52 } from "path";
13426
+ import { existsSync as existsSync36, readFileSync as readFileSync43, statSync as statSync18 } from "fs";
13427
+ import { basename as basename19, join as join58 } from "path";
12358
13428
  function supplyEnabled(env) {
12359
13429
  return env["LOKI_SUPPLY_GUARD"] !== "0";
12360
13430
  }
@@ -12366,16 +13436,16 @@ function supplyVerdict(verdict, r) {
12366
13436
  return r.blocked && verdict === "VERIFIED" ? "FAILED" : verdict;
12367
13437
  }
12368
13438
  function isManifestPath(path) {
12369
- return MANIFESTS.test(basename17(path));
13439
+ return MANIFESTS.test(basename19(path));
12370
13440
  }
12371
13441
  function readDeclared(repoDir) {
12372
- const p = join52(repoDir, ".loki", DECLARED_FILE);
12373
- if (!existsSync32(p))
13442
+ const p = join58(repoDir, ".loki", DECLARED_FILE);
13443
+ if (!existsSync36(p))
12374
13444
  return { deps: [], problem: null };
12375
13445
  try {
12376
- if (statSync16(p).size > MAX_FILE_BYTES)
13446
+ if (statSync18(p).size > MAX_FILE_BYTES)
12377
13447
  return { deps: [], problem: "declaration file too large" };
12378
- const j = JSON.parse(readFileSync38(p, "utf8"));
13448
+ const j = JSON.parse(readFileSync43(p, "utf8"));
12379
13449
  if (!Array.isArray(j))
12380
13450
  return { deps: [], problem: "declaration is not a JSON array" };
12381
13451
  const deps = [];
@@ -12395,11 +13465,11 @@ function readDeclared(repoDir) {
12395
13465
  }
12396
13466
  }
12397
13467
  function readAllowlist(repoDir) {
12398
- const p = join52(repoDir, ".loki", "supply-allowlist");
12399
- if (!existsSync32(p))
13468
+ const p = join58(repoDir, ".loki", "supply-allowlist");
13469
+ if (!existsSync36(p))
12400
13470
  return new Set;
12401
13471
  try {
12402
- return new Set(readFileSync38(p, "utf8").split(`
13472
+ return new Set(readFileSync43(p, "utf8").split(`
12403
13473
  `).map((l) => l.replace(/#.*$/, "").trim()).filter(Boolean));
12404
13474
  } catch {
12405
13475
  return new Set;
@@ -12440,7 +13510,7 @@ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
12440
13510
  if (eco === "npm") {
12441
13511
  if (privateUrlList([env["npm_config_registry"] ?? "", env["NPM_CONFIG_REGISTRY"] ?? ""]))
12442
13512
  return true;
12443
- return files(join52(repoDir, ".npmrc"), home ? join52(home, ".npmrc") : "").some((t) => t.split(`
13513
+ return files(join58(repoDir, ".npmrc"), home ? join58(home, ".npmrc") : "").some((t) => t.split(`
12444
13514
  `).some((l) => {
12445
13515
  const m = /^\s*(?:(@[^:\s]+):)?registry\s*=\s*(\S+)/.exec(l);
12446
13516
  return !!m && privateUrl(m[2]) && (m[1] === undefined || name.startsWith(`${m[1]}/`));
@@ -12449,7 +13519,7 @@ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
12449
13519
  if (eco === "pypi") {
12450
13520
  if (privateUrlList([env["PIP_INDEX_URL"] ?? "", env["PIP_EXTRA_INDEX_URL"] ?? ""]))
12451
13521
  return true;
12452
- const cfg = [env["PIP_CONFIG_FILE"] ?? "", home ? join52(home, ".config", "pip", "pip.conf") : "", home ? join52(home, ".pip", "pip.conf") : "", join52(repoDir, "pip.conf")];
13522
+ const cfg = [env["PIP_CONFIG_FILE"] ?? "", home ? join58(home, ".config", "pip", "pip.conf") : "", home ? join58(home, ".pip", "pip.conf") : "", join58(repoDir, "pip.conf")];
12453
13523
  return files(...cfg).some((t) => t.split(`
12454
13524
  `).some((l) => {
12455
13525
  const m = /^\s*(?:extra-)?index-url\s*[=:]\s*(.+)$/.exec(l);
@@ -12459,7 +13529,7 @@ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
12459
13529
  if (eco === "cargo") {
12460
13530
  if (Object.keys(env).some((k) => /^CARGO_REGISTRIES_.+_INDEX$/.test(k) || /^CARGO_SOURCE_/.test(k)))
12461
13531
  return true;
12462
- return files(join52(repoDir, ".cargo", "config.toml"), join52(repoDir, ".cargo", "config"), home ? join52(home, ".cargo", "config.toml") : "", home ? join52(home, ".cargo", "config") : "").some((t) => /^\s*\[(registries\.|source\.)/m.test(t) || /replace-with\s*=/.test(t));
13532
+ return files(join58(repoDir, ".cargo", "config.toml"), join58(repoDir, ".cargo", "config"), home ? join58(home, ".cargo", "config.toml") : "", home ? join58(home, ".cargo", "config") : "").some((t) => /^\s*\[(registries\.|source\.)/m.test(t) || /replace-with\s*=/.test(t));
12463
13533
  }
12464
13534
  if (eco === "go") {
12465
13535
  const gp = goEnv["GOPROXY"] ?? env["GOPROXY"] ?? "";
@@ -12582,7 +13652,7 @@ var MIN_AGE_DAYS = 7, DECLARED_FILE = "supply-declared.json", MAX_CHECKED = 50,
12582
13652
  }
12583
13653
  }, PUBLIC_HOSTS, hostOf = (u) => u.trim().toLowerCase().replace(/^[a-z][a-z0-9+.-]*:\/\//, "").replace(/^www\./, "").split(/[/?#\s]/)[0].replace(/^[^@]*@/, "").replace(/:\d+$/, ""), privateUrl = (u) => /[a-z0-9]/i.test(u) && !PUBLIC_HOSTS.has(hostOf(u)), readSmall = (p) => {
12584
13654
  try {
12585
- return statSync16(p).size <= MAX_FILE_BYTES ? readFileSync38(p, "utf8") : "";
13655
+ return statSync18(p).size <= MAX_FILE_BYTES ? readFileSync43(p, "utf8") : "";
12586
13656
  } catch {
12587
13657
  return "";
12588
13658
  }
@@ -12597,77 +13667,18 @@ var init_supply_guard = __esm(() => {
12597
13667
  });
12598
13668
 
12599
13669
  // ../../loki-ts/src/engine10/stages/seal.ts
12600
- import { createHash as createHash12, randomBytes as randomBytes4, createPrivateKey, createPublicKey as createPublicKey2, generateKeyPairSync, sign } from "crypto";
12601
- import { chmodSync as chmodSync5, existsSync as existsSync33, readdirSync as readdirSync16, linkSync, mkdirSync as mkdirSync18, readFileSync as readFileSync39, statSync as statSync17, unlinkSync as unlinkSync5, writeFileSync as writeFileSync19 } from "fs";
12602
- import { homedir as homedir9 } from "os";
12603
- import { basename as basename18, dirname as dirname23, isAbsolute as isAbsolute8, join as join53, relative as relative9 } from "path";
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";
12604
13673
  function sanitizeReason(s) {
12605
13674
  const collapsed = s.replace(/[\x00-\x1f\x7f]+/g, " ").trim();
12606
13675
  const capped = collapsed.length > 500 ? `${collapsed.slice(0, 500)}...` : collapsed;
12607
13676
  return capped.replace(/`/g, "'");
12608
13677
  }
12609
- function canonicalJson(x) {
12610
- const walk = (v) => {
12611
- if (Array.isArray(v))
12612
- return `[${v.map(walk).join(",")}]`;
12613
- if (v !== null && typeof v === "object") {
12614
- const o = v;
12615
- return `{${Object.keys(o).filter((k) => o[k] !== undefined).sort().map((k) => `${JSON.stringify(k)}:${walk(o[k])}`).join(",")}}`;
12616
- }
12617
- return JSON.stringify(v ?? null);
12618
- };
12619
- return walk(x).replace(/[\u0080-\uFFFF]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`);
12620
- }
12621
13678
  function receiptSha256(r) {
12622
13679
  const { verification: _v, receipt_sha256: _h, ...body } = r;
12623
13680
  return sha2562(canonicalJson(body));
12624
13681
  }
12625
- function loadSigningKey(generate = true) {
12626
- try {
12627
- const inline = process.env["LOKI_RECEIPT_SIGNING_KEY"]?.trim();
12628
- let pem = inline ?? "";
12629
- if (!inline) {
12630
- const given = process.env["LOKI_RECEIPT_SIGNING_KEY_FILE"]?.trim();
12631
- const file = given || join53(process.env["HOME"] || homedir9(), ".loki", "keys", RECEIPT_SIGNER_BASENAME);
12632
- try {
12633
- pem = readFileSync39(file);
12634
- if (!given) {
12635
- for (const [f, m] of [[file, 384], [dirname23(file), 448]])
12636
- if (statSync17(f).mode & 63)
12637
- chmodSync5(f, m);
12638
- }
12639
- } catch (e) {
12640
- if (e.code !== "ENOENT" || !generate)
12641
- return null;
12642
- mkdirSync18(dirname23(dirname23(file)), { recursive: true, mode: 448 });
12643
- mkdirSync18(dirname23(file), { recursive: true, mode: 448 });
12644
- const tmp = `${file}.${randomBytes4(6).toString("hex")}.tmp`;
12645
- writeFileSync19(tmp, generateKeyPairSync("ed25519").privateKey.export({ type: "pkcs8", format: "pem" }), { flag: "wx", mode: 384 });
12646
- try {
12647
- linkSync(tmp, file);
12648
- } catch (l) {
12649
- if (l.code !== "EEXIST")
12650
- throw l;
12651
- } finally {
12652
- unlinkSync5(tmp);
12653
- }
12654
- pem = readFileSync39(file);
12655
- }
12656
- }
12657
- const k = createPrivateKey(pem);
12658
- return k.asymmetricKeyType === "ed25519" ? k : null;
12659
- } catch {
12660
- return null;
12661
- }
12662
- }
12663
- function signReceipt(runId, hash) {
12664
- const key = loadSigningKey();
12665
- if (!key)
12666
- return { jwt: null, kid: null };
12667
- const kid = kidOf2(createPublicKey2(key));
12668
- const input = `${b64u(canonicalJson({ alg: "EdDSA", typ: "JWT", kid }))}.${b64u(canonicalJson({ job_id: runId, run_id: runId, receipt_sha256: hash, iat: Math.floor(Date.now() / 1000) }))}`;
12669
- return { jwt: `${input}.${b64u(sign(null, Buffer.from(input), key))}`, kid };
12670
- }
12671
13682
  async function git3(ctx, args, keep = {}) {
12672
13683
  const r = await safeGitRun(ctx.repoDir, args, { timeoutMs: 20000, ...keep });
12673
13684
  return { out: r.stdout, code: r.exitCode };
@@ -12732,9 +13743,9 @@ function renderReceiptMd(r) {
12732
13743
  ].join(`
12733
13744
  `);
12734
13745
  }
12735
- 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) => createHash12("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 !== "") : [], b64u = (b) => Buffer.from(b).toString("base64url"), kidOf2 = (pub) => b64u(createHash12("sha256").update(`{"crv":"Ed25519","kty":"OKP","x":"${pub.export({ format: "jwk" }).x}"}`).digest()), receiptRel = (ctx) => {
12736
- const r = relative9(ctx.repoDir, join53(ctx.runDir, "receipt.json"));
12737
- return r.startsWith("..") || isAbsolute8(r) ? `.loki/runs/${ctx.runId}/receipt.json` : r;
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) => {
13747
+ const r = relative9(ctx.repoDir, join59(ctx.runDir, "receipt.json"));
13748
+ return r.startsWith("..") || isAbsolute9(r) ? `.loki/runs/${ctx.runId}/receipt.json` : r;
12738
13749
  }, commitStage, sealStage;
12739
13750
  var init_seal = __esm(() => {
12740
13751
  init_spec_file();
@@ -12745,6 +13756,7 @@ var init_seal = __esm(() => {
12745
13756
  init_discard();
12746
13757
  init_commit_filter();
12747
13758
  init_scope2();
13759
+ init_receipt_signer();
12748
13760
  init_pr_lessons();
12749
13761
  init_visual_evidence();
12750
13762
  init_testmap();
@@ -12835,8 +13847,8 @@ var init_seal = __esm(() => {
12835
13847
  notProven.add(`Wall test not executed: ${wallNotRun} file(s), no reason recorded`);
12836
13848
  if (wallNotRun > 0) {
12837
13849
  try {
12838
- const kept = new Set((Array.isArray(o.wall?.files) ? o.wall.files : []).map((f) => basename18(String(f.path))));
12839
- for (const n2 of readdirSync16(join53(ctx.runDir, "wall")).sort())
13850
+ const kept = new Set((Array.isArray(o.wall?.files) ? o.wall.files : []).map((f) => basename20(String(f.path))));
13851
+ for (const n2 of readdirSync18(join59(ctx.runDir, "wall")).sort())
12840
13852
  if (!kept.has(n2))
12841
13853
  notProven.add(`wall test discarded: ${n2} (not_run)`);
12842
13854
  } catch {}
@@ -12875,6 +13887,8 @@ var init_seal = __esm(() => {
12875
13887
  notProven.add(n2);
12876
13888
  for (const id of strs2(o.verify?.pre_red))
12877
13889
  notProven.add(`pre red: ${id}`);
13890
+ if (typeof o.verify?.baseline_line === "string" && strs2(o.verify?.pre_red).length)
13891
+ notProven.add(o.verify.baseline_line);
12878
13892
  for (const t of strs2(o.implement?.tests_reverted))
12879
13893
  notProven.add(`reverted test edit: ${t}`);
12880
13894
  if (ctx.provider !== "claude")
@@ -12895,19 +13909,19 @@ var init_seal = __esm(() => {
12895
13909
  for (const [s, d] of Object.entries(o))
12896
13910
  if (typeof d?.duration_s === "number")
12897
13911
  stages[s] = d.duration_s;
12898
- const T = hooks.time, time = T ? T.build(ctx, stages, T.firstEventMs(join53(ctx.runDir, "events.jsonl"))) : { wall_s: Object.values(stages).reduce((a, b) => a + (b ?? 0), 0), stages }, totalS = T?.reconciled(time) ?? null;
13912
+ const T = hooks.time, time = T ? T.build(ctx, stages, T.firstEventMs(join59(ctx.runDir, "events.jsonl"))) : { wall_s: Object.values(stages).reduce((a, b) => a + (b ?? 0), 0), stages }, totalS = T?.reconciled(time) ?? null;
12899
13913
  const iterIds = Object.values(o).flatMap((d) => [...strs2(d?.iteration_ids), ...strs2([d?.iteration_id])]);
12900
13914
  if (iterIds.length === 0)
12901
13915
  notProven.add("cost not measured (no iteration ids recorded)");
12902
13916
  const cost = ctx.cost.read(ctx.repoDir, iterIds);
12903
13917
  if (cost.unmetered)
12904
13918
  notProven.add("cost unmetered (CLI invoker; recorded as 0)");
12905
- const eventsPath = join53(ctx.runDir, "events.jsonl");
13919
+ const eventsPath = join59(ctx.runDir, "events.jsonl");
12906
13920
  const wallFiles = Array.isArray(o.wall?.files) ? o.wall.files : [];
12907
13921
  const wallPassed = typeof o.verify?.wall_passed === "boolean" ? o.verify.wall_passed : null;
12908
13922
  if (wallFiles.length > 0 && wallPassed === null)
12909
13923
  notProven.add("wall result not recorded by verify");
12910
- const routeBlock = buildRouteBlock(process.env, ctx.provider, o.implement?.route ?? o.plan?.route_record ?? (routerEnabled(process.env) ? loadRouteRecord(ctx.runDir) : undefined), cost.router ?? (routerEnabled(process.env) ? sumResultCosts(join53(ctx.repoDir, ".loki"), iterIds).router : undefined), ctx.model);
13924
+ const routeBlock = buildRouteBlock(process.env, ctx.provider, o.implement?.route ?? o.plan?.route_record ?? (routerEnabled(process.env) ? loadRouteRecord(ctx.runDir) : undefined), cost.router ?? (routerEnabled(process.env) ? sumResultCosts(join59(ctx.repoDir, ".loki"), iterIds).router : undefined), ctx.model);
12911
13925
  if (routeBlock)
12912
13926
  for (const l of routeNotProven(routeBlock))
12913
13927
  notProven.add(l);
@@ -12949,7 +13963,7 @@ var init_seal = __esm(() => {
12949
13963
  provider: ctx.provider,
12950
13964
  model: ctx.model,
12951
13965
  resumed: o.intake?.resumed === true,
12952
- events_sha256: sha2562(existsSync33(eventsPath) ? readFileSync39(eventsPath) : ""),
13966
+ events_sha256: sha2562(existsSync37(eventsPath) ? readFileSync44(eventsPath) : ""),
12953
13967
  ...await sealEvidence(ctx.repoDir, ctx.runDir, o, notProven, signal, ctx.emit),
12954
13968
  log_seal: true,
12955
13969
  ...receiptBlock(process.env, cost.usd, cost.unmetered === true, totalS),
@@ -12969,11 +13983,11 @@ var init_seal = __esm(() => {
12969
13983
  hash = receiptSha256(body);
12970
13984
  }
12971
13985
  const receipt = { ...body, receipt_sha256: hash, verification: { jwt: sig.jwt, kid: sig.kid } };
12972
- mkdirSync18(ctx.runDir, { recursive: true });
12973
- const path = join53(ctx.runDir, "receipt.json");
12974
- writeFileSync19(path, JSON.stringify(receipt, null, 2) + `
13986
+ mkdirSync23(ctx.runDir, { recursive: true });
13987
+ const path = join59(ctx.runDir, "receipt.json");
13988
+ writeFileSync24(path, JSON.stringify(receipt, null, 2) + `
12975
13989
  `);
12976
- writeFileSync19(join53(ctx.runDir, "receipt.md"), renderReceiptMd(receipt));
13990
+ writeFileSync24(join59(ctx.runDir, "receipt.md"), renderReceiptMd(receipt));
12977
13991
  recordRun(process.env, ctx.repoDir, ctx.model, verdict, cost.usd, cost.unmetered === true, totalS);
12978
13992
  const signed = sig.jwt !== null;
12979
13993
  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) } : {} };
@@ -12988,7 +14002,7 @@ var init_seal = __esm(() => {
12988
14002
 
12989
14003
  // ../../loki-ts/src/features/receipt_dsse.ts
12990
14004
  import { createPublicKey as createPublicKey3, sign as sign2, verify as verify2 } from "crypto";
12991
- import { readFileSync as readFileSync40 } from "fs";
14005
+ import { readFileSync as readFileSync45 } from "fs";
12992
14006
  function pae(payloadType, body) {
12993
14007
  const t = Buffer.from(payloadType, "utf8");
12994
14008
  return Buffer.concat([Buffer.from(`DSSEv1 ${t.length} `), t, Buffer.from(` ${body.length} `), body]);
@@ -13065,7 +14079,7 @@ function verifyDsseReceipt(env, d) {
13065
14079
  }
13066
14080
  function runIdGuard(receiptPath, runId) {
13067
14081
  try {
13068
- return envelopeRunIdProblem(JSON.parse(readFileSync40(receiptPath, "utf8")), runId);
14082
+ return envelopeRunIdProblem(JSON.parse(readFileSync45(receiptPath, "utf8")), runId);
13069
14083
  } catch {
13070
14084
  return null;
13071
14085
  }
@@ -13079,16 +14093,16 @@ var init_keys_cmd = __esm(() => {
13079
14093
  });
13080
14094
 
13081
14095
  // ../../loki-ts/src/engine10/verify_cmd.ts
13082
- import { existsSync as existsSync34, readdirSync as readdirSync17, readFileSync as readFileSync41, statSync as statSync18 } from "fs";
13083
- import { dirname as dirname24, join as join54 } from "path";
13084
- import { createHash as createHash13, createPublicKey as createPublicKey4, verify as verify3 } from "crypto";
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";
13085
14099
  function pubFor(kid, given) {
13086
14100
  if (given)
13087
14101
  return kidOf2(given) === kid ? given : undefined;
13088
14102
  const active = loadSigningKey(false);
13089
14103
  const pubs = (process.env["LOKI_RECEIPT_RETIRED_PUBKEYS"] ?? "").split(":").map((f) => f.trim()).filter(Boolean).flatMap((f) => {
13090
14104
  try {
13091
- return [createPublicKey4(readFileSync41(f))];
14105
+ return [createPublicKey4(readFileSync46(f))];
13092
14106
  } catch {
13093
14107
  return [];
13094
14108
  }
@@ -13118,18 +14132,18 @@ function checkAttestation(jwt, expectedHash, given) {
13118
14132
  }
13119
14133
  function checkEventLog(receiptPath, receipt) {
13120
14134
  const bound = receipt["events_sha256"];
13121
- if (typeof bound !== "string" || bound === createHash13("sha256").digest("hex"))
14135
+ if (typeof bound !== "string" || bound === createHash15("sha256").digest("hex"))
13122
14136
  return null;
13123
- const path = join54(dirname24(receiptPath), "events.jsonl");
13124
- if (!existsSync34(path))
14137
+ const path = join60(dirname27(receiptPath), "events.jsonl");
14138
+ if (!existsSync38(path))
13125
14139
  return "events.jsonl is missing";
13126
- const raw2 = readFileSync41(path, "utf8"), events2 = readEvents(path), lines = raw2.split(`
14140
+ const raw2 = readFileSync46(path, "utf8"), events2 = readEvents(path), lines = raw2.split(`
13127
14141
  `).filter((l) => l.trim() !== "");
13128
14142
  if (events2.length !== lines.length || events2.some((e, i) => e.seq !== i))
13129
14143
  return "events.jsonl has a forged, edited or missing line";
13130
14144
  if (events2.some((e) => e.type === "tamper.detected"))
13131
14145
  return "the supervisor detected events.jsonl being modified during the run";
13132
- const h = createHash13("sha256");
14146
+ const h = createHash15("sha256");
13133
14147
  for (const l of lines) {
13134
14148
  if (h.copy().digest("hex") === bound)
13135
14149
  return null;
@@ -13139,7 +14153,7 @@ function checkEventLog(receiptPath, receipt) {
13139
14153
  return h.digest("hex") === bound ? null : "events.jsonl does not match the hash recorded at seal";
13140
14154
  }
13141
14155
  function checkLogSeal(receiptPath, hash, kid, given) {
13142
- const path = join54(dirname24(receiptPath), "events.jsonl"), events2 = readEvents(path), done = events2.findIndex((e) => e.type === "run.completed");
14156
+ const path = join60(dirname27(receiptPath), "events.jsonl"), events2 = readEvents(path), done = events2.findIndex((e) => e.type === "run.completed");
13143
14157
  if (!events2.some((e) => e.type === "receipt.sealed" && e.data["receipt_sha256"] === hash))
13144
14158
  return { verdict: "TAMPERED", reason: "events.jsonl has no receipt.sealed event for this receipt" };
13145
14159
  if (done < 0)
@@ -13147,8 +14161,8 @@ function checkLogSeal(receiptPath, hash, kid, given) {
13147
14161
  const seal = events2[done + 1], d = seal?.type === "log.sealed" ? seal.data : null;
13148
14162
  if (!d)
13149
14163
  return { verdict: "TAMPERED", reason: "events.jsonl has no signed log.sealed line after run.completed" };
13150
- const lines = readFileSync41(path, "utf8").split(`
13151
- `).filter((l) => l.trim() !== ""), sha3 = createHash13("sha256").update(lines.slice(0, done + 1).join(`
14164
+ const lines = readFileSync46(path, "utf8").split(`
14165
+ `).filter((l) => l.trim() !== ""), sha3 = createHash15("sha256").update(lines.slice(0, done + 1).join(`
13152
14166
  `) + `
13153
14167
  `).digest("hex");
13154
14168
  const pub = d["kid"] === kid ? pubFor(kid, given) : undefined;
@@ -13157,11 +14171,11 @@ function checkLogSeal(receiptPath, hash, kid, given) {
13157
14171
  return null;
13158
14172
  }
13159
14173
  async function verifyReceipt(receiptPath, deps = {}) {
13160
- if (!existsSync34(receiptPath))
14174
+ if (!existsSync38(receiptPath))
13161
14175
  return { verdict: "UNCHECKED", reasons: [`receipt not found: ${receiptPath}`] };
13162
14176
  let receipt;
13163
14177
  try {
13164
- receipt = JSON.parse((deps.read ?? ((p) => readFileSync41(p, "utf8")))(receiptPath));
14178
+ receipt = JSON.parse((deps.read ?? ((p) => readFileSync46(p, "utf8")))(receiptPath));
13165
14179
  } catch {
13166
14180
  return { verdict: "UNCHECKED", reasons: ["receipt.json is not valid JSON"] };
13167
14181
  }
@@ -13216,8 +14230,8 @@ var init_verify_cmd = __esm(() => {
13216
14230
  });
13217
14231
 
13218
14232
  // src/server/app.ts
13219
- import { existsSync as existsSync36, readFileSync as readFileSync44, statSync as statSync19 } from "fs";
13220
- import { join as join57, resolve as resolve13, sep as sep14 } from "path";
14233
+ import { existsSync as existsSync40, readFileSync as readFileSync49, statSync as statSync21 } from "fs";
14234
+ import { join as join63, resolve as resolve15, sep as sep14 } from "path";
13221
14235
 
13222
14236
  // node_modules/hono/dist/request/constants.js
13223
14237
  var GET_MATCH_RESULT = Symbol();
@@ -23464,9 +24478,9 @@ function mount20(ctx) {
23464
24478
  }
23465
24479
 
23466
24480
  // src/server/routes/verify.ts
23467
- import { readFileSync as readFileSync42, realpathSync as realpathSync20 } from "fs";
24481
+ import { readFileSync as readFileSync47, realpathSync as realpathSync20 } from "fs";
23468
24482
  import { createPublicKey as createPublicKey5 } from "crypto";
23469
- import { join as join55, sep as sep13 } from "path";
24483
+ import { join as join61, sep as sep13 } from "path";
23470
24484
  init_verify_cmd();
23471
24485
  init_seal();
23472
24486
  init_receipt_dsse();
@@ -23493,11 +24507,11 @@ function mount21(ctx) {
23493
24507
  return done(404, "receipt not available", "not_found");
23494
24508
  let runDir, file;
23495
24509
  try {
23496
- const root = realpathSync20(join55(repo.p, ".loki", "runs"));
23497
- runDir = realpathSync20(join55(root, run2));
23498
- if (runDir !== join55(root, run2))
24510
+ const root = realpathSync20(join61(repo.p, ".loki", "runs"));
24511
+ runDir = realpathSync20(join61(root, run2));
24512
+ if (runDir !== join61(root, run2))
23499
24513
  return done(404, "receipt not found", "not_found");
23500
- file = realpathSync20(join55(runDir, "receipt.json"));
24514
+ file = realpathSync20(join61(runDir, "receipt.json"));
23501
24515
  } catch {
23502
24516
  return done(404, "receipt not found", "not_found");
23503
24517
  }
@@ -23516,7 +24530,7 @@ function mount21(ctx) {
23516
24530
  sha3 = r.receiptSha256 ?? null;
23517
24531
  }
23518
24532
  try {
23519
- outcome = outcomeOf(JSON.parse(readFileSync42(file, "utf8")));
24533
+ outcome = outcomeOf(JSON.parse(readFileSync47(file, "utf8")));
23520
24534
  } catch {
23521
24535
  outcome = "UNREADABLE";
23522
24536
  }
@@ -23578,8 +24592,8 @@ function ttlCache(ttlMs = PROBE_CACHE_MS, now2 = Date.now) {
23578
24592
  }
23579
24593
 
23580
24594
  // src/server/legacy/shim.ts
23581
- import { existsSync as existsSync35, readFileSync as readFileSync43 } from "fs";
23582
- import { join as join56 } from "path";
24595
+ import { existsSync as existsSync39, readFileSync as readFileSync48 } from "fs";
24596
+ import { join as join62 } from "path";
23583
24597
 
23584
24598
  // src/server/legacy/routes.ts
23585
24599
  var LEGACY_ROUTES = [
@@ -23951,10 +24965,10 @@ var logged = new Set;
23951
24965
  var toHono = (p) => p.replace(/\{([A-Za-z_]+):path\}/g, ":$1{.+}").replace(/\{([A-Za-z_]+)\}/g, ":$1");
23952
24966
  var NOT_SUPPORTED = "not yet supported by the Control Plane";
23953
24967
  var repoVersion = () => {
23954
- for (const f of [join56(import.meta.dir, "../../../../../VERSION")]) {
24968
+ for (const f of [join62(import.meta.dir, "../../../../../VERSION")]) {
23955
24969
  try {
23956
- if (existsSync35(f))
23957
- return readFileSync43(f, "utf8").trim();
24970
+ if (existsSync39(f))
24971
+ return readFileSync48(f, "utf8").trim();
23958
24972
  } catch {}
23959
24973
  }
23960
24974
  return "unknown";
@@ -24136,7 +25150,7 @@ function legacyShim(opts) {
24136
25150
 
24137
25151
  // src/server/app.ts
24138
25152
  var MAX_BODY2 = 1e6;
24139
- var defaultUiDir = () => [join57(import.meta.dir, "../../ui/dist"), join57(import.meta.dir, "../ui/dist")].find((d) => existsSync36(join57(d, "index.html")));
25153
+ var defaultUiDir = () => [join63(import.meta.dir, "../../ui/dist"), join63(import.meta.dir, "../ui/dist")].find((d) => existsSync40(join63(d, "index.html")));
24140
25154
  function createApp(opts) {
24141
25155
  const uiDir = opts.uiDir ?? defaultUiDir();
24142
25156
  const { db, sqlite } = openDb(opts.dbPath);
@@ -24165,10 +25179,10 @@ function createApp(opts) {
24165
25179
  await next();
24166
25180
  });
24167
25181
  const readInstalled = () => {
24168
- for (const f of [process.env.LOKI_VERSION_FILE, join57(import.meta.dir, "../../../../VERSION")]) {
25182
+ for (const f of [process.env.LOKI_VERSION_FILE, join63(import.meta.dir, "../../../../VERSION")]) {
24169
25183
  try {
24170
25184
  if (f)
24171
- return readFileSync44(f, "utf8").trim() || "unknown";
25185
+ return readFileSync49(f, "utf8").trim() || "unknown";
24172
25186
  } catch {}
24173
25187
  }
24174
25188
  return "unknown";
@@ -24277,13 +25291,13 @@ function createApp(opts) {
24277
25291
  }
24278
25292
  if (!uiDir || p.startsWith("/v1/"))
24279
25293
  return c.json({ error: "not found" }, 404);
24280
- const root = resolve13(uiDir);
24281
- const f = resolve13(root, `.${p}`);
24282
- if (f.startsWith(root + sep14) && existsSync36(f) && statSync19(f).isFile())
25294
+ const root = resolve15(uiDir);
25295
+ const f = resolve15(root, `.${p}`);
25296
+ if (f.startsWith(root + sep14) && existsSync40(f) && statSync21(f).isFile())
24283
25297
  return new Response(Bun.file(f));
24284
25298
  if (/\.[a-z0-9]+$/i.test(p))
24285
25299
  return c.json({ error: "not found" }, 404);
24286
- return new Response(Bun.file(join57(root, "index.html")));
25300
+ return new Response(Bun.file(join63(root, "index.html")));
24287
25301
  });
24288
25302
  return { app, db, close: () => {
24289
25303
  clearInterval(reconciler);