loki-mode 11.7.1 → 11.9.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 (92) hide show
  1. package/SKILL.md +2 -2
  2. package/VERSION +1 -1
  3. package/autonomy/lib/backlog.py +40 -4
  4. package/autonomy/lib/chat.sh +3 -2
  5. package/autonomy/lib/workspace.py +95 -4
  6. package/autonomy/loki +185 -106
  7. package/autonomy/trigger-server.py +550 -5
  8. package/autonomy/verify.sh +5 -0
  9. package/bin/loki +1 -1
  10. package/completions/_loki +34 -1
  11. package/completions/loki.bash +10 -3
  12. package/dashboard/__init__.py +1 -1
  13. package/docs/ARCHITECTURE.md +0 -1
  14. package/docs/CLI-REFERENCE.md +1 -1
  15. package/docs/COMPONENTS.md +1 -1
  16. package/docs/DEPLOY-PLAN.md +13 -3
  17. package/docs/INSTALLATION.md +1 -1
  18. package/docs/WORKSPACES.md +1 -1
  19. package/docs/dev/architecture-reference.md +1 -1
  20. package/docs/sentry-intake.md +36 -0
  21. package/docs/v10/D61-SPEED.md +14 -0
  22. package/docs/v10/PROGRESS.md +22 -0
  23. package/loki-ts/dist/loki.js +962 -879
  24. package/mcp/__init__.py +1 -1
  25. package/package.json +2 -2
  26. package/packages/control-plane/dist/ask-tools-server.js +13 -4
  27. package/packages/control-plane/dist/server.js +614 -456
  28. package/packages/control-plane/src/server/diffstat.ts +10 -2
  29. package/packages/control-plane/src/server/legacy/routes-control.ts +8 -4
  30. package/packages/control-plane/src/server/routes/checkpoints.ts +11 -2
  31. package/packages/control-plane/ui/dist/assets/index-u8cd6TRQ.js +190 -0
  32. package/packages/control-plane/ui/dist/index.html +1 -1
  33. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  34. package/web-app/dist/assets/{AdminPage-S3BYeapm.js → AdminPage-BdH9iL2I.js} +1 -1
  35. package/web-app/dist/assets/{Avatar-C1rHwLgn.js → Avatar-C-WixxR6.js} +1 -1
  36. package/web-app/dist/assets/{Badge-CzlnN5aQ.js → Badge-BFWpRd_L.js} +1 -1
  37. package/web-app/dist/assets/{Button-B1w5AeGC.js → Button-CE5vG66Y.js} +1 -1
  38. package/web-app/dist/assets/{CockpitPage-Dyeqjfkc.js → CockpitPage-BAVn10bY.js} +1 -1
  39. package/web-app/dist/assets/{ComparePage-C6y2GkGR.js → ComparePage-DOecIGfM.js} +1 -1
  40. package/web-app/dist/assets/{ErrorBoundary-Dg2fcGkR.js → ErrorBoundary-1rNA5v7f.js} +1 -1
  41. package/web-app/dist/assets/{EvidenceReceiptPanel-CxbyjvTj.js → EvidenceReceiptPanel-DjOaWfdH.js} +1 -1
  42. package/web-app/dist/assets/{GitHubIssuesPanel-Dpys1xDb.js → GitHubIssuesPanel-NNPBuRPD.js} +1 -1
  43. package/web-app/dist/assets/{GitHubPRsPanel-CRVjWoFl.js → GitHubPRsPanel-CL1b--tV.js} +1 -1
  44. package/web-app/dist/assets/{HomePage-BKnv-oYw.js → HomePage-BsLDN6MW.js} +2 -2
  45. package/web-app/dist/assets/{LoginPage-BGksmFRd.js → LoginPage-CVIv5bCS.js} +1 -1
  46. package/web-app/dist/assets/{MagicPage-OCvhp16M.js → MagicPage-BgMBB9lK.js} +1 -1
  47. package/web-app/dist/assets/{MetricsPage-CJOJpXWC.js → MetricsPage-BHeJlqPC.js} +1 -1
  48. package/web-app/dist/assets/{NotFoundPage-C04p3QvN.js → NotFoundPage-DDzwfyDK.js} +1 -1
  49. package/web-app/dist/assets/{ProjectPage-BRB8txsY.js → ProjectPage-CuQWEYBF.js} +3 -3
  50. package/web-app/dist/assets/{ProjectsPage-CoUYeQEh.js → ProjectsPage-OoD0RFDZ.js} +1 -1
  51. package/web-app/dist/assets/{SettingsPage-BkjmJGfM.js → SettingsPage-tMFMKkK5.js} +1 -1
  52. package/web-app/dist/assets/{ShowcasePage-B4vU9TjQ.js → ShowcasePage-DVfLoWdz.js} +1 -1
  53. package/web-app/dist/assets/{SystemSettingsPage-Z2jiVsni.js → SystemSettingsPage-CThV9N4l.js} +1 -1
  54. package/web-app/dist/assets/{TeamsPage-Ulm8SISq.js → TeamsPage-CV0nvXI8.js} +1 -1
  55. package/web-app/dist/assets/{TemplatesPage-C_7MM6Ey.js → TemplatesPage-D81EI1L8.js} +1 -1
  56. package/web-app/dist/assets/{TerminalOutput-Cumd7Tgs.js → TerminalOutput-Bj7uKRIe.js} +1 -1
  57. package/web-app/dist/assets/{activity-CZAUkbiY.js → activity-DoNfNkOL.js} +1 -1
  58. package/web-app/dist/assets/{bell-BOvSXpEr.js → bell-BWO3OU50.js} +1 -1
  59. package/web-app/dist/assets/{bot-DOTZxBYj.js → bot-DcvWv_zD.js} +1 -1
  60. package/web-app/dist/assets/{check-BxpE0B5u.js → check-CfG09Z18.js} +1 -1
  61. package/web-app/dist/assets/{chevron-left-D6KPvBOA.js → chevron-left-z0fh4x2h.js} +1 -1
  62. package/web-app/dist/assets/{circle-alert-Bajq86oe.js → circle-alert-C_7GlYul.js} +1 -1
  63. package/web-app/dist/assets/{clock-CnlHAVJc.js → clock-BsYUp070.js} +1 -1
  64. package/web-app/dist/assets/{cloud-DjaymjwM.js → cloud-BVWAJ7Rv.js} +1 -1
  65. package/web-app/dist/assets/{code-xml-BADEw2Ld.js → code-xml-CdZT-6zu.js} +1 -1
  66. package/web-app/dist/assets/{database-B4aKb5Cq.js → database-Dbkm9t2D.js} +1 -1
  67. package/web-app/dist/assets/{dollar-sign-DrldXpja.js → dollar-sign-CfIUM5Pd.js} +1 -1
  68. package/web-app/dist/assets/{file-code-corner-DVebDVR-.js → file-code-corner-CrUKhnj-.js} +1 -1
  69. package/web-app/dist/assets/{file-plus-BD-N_-Tl.js → file-plus-Cf6u0xHY.js} +1 -1
  70. package/web-app/dist/assets/{globe-C7ieInC-.js → globe-DsIqaI7w.js} +1 -1
  71. package/web-app/dist/assets/{hammer-BSugKIji.js → hammer-CA14BeMp.js} +1 -1
  72. package/web-app/dist/assets/{index-nLQgfvOn.js → index-DpJ_GJuZ.js} +3 -3
  73. package/web-app/dist/assets/{layers-CHXxU2on.js → layers-Dh5Oqhrj.js} +1 -1
  74. package/web-app/dist/assets/{loader-circle-BEEz0LbD.js → loader-circle-B0WHIGqt.js} +1 -1
  75. package/web-app/dist/assets/{lock-CzQGfcnE.js → lock-DkgfEGYF.js} +1 -1
  76. package/web-app/dist/assets/{package-CcHYQLGd.js → package-LzjmwD1S.js} +1 -1
  77. package/web-app/dist/assets/{plus-DdzgFEXn.js → plus-BNjA0KSV.js} +1 -1
  78. package/web-app/dist/assets/{refresh-cw-7x0HbH9Y.js → refresh-cw-k3IacuDX.js} +1 -1
  79. package/web-app/dist/assets/{rotate-ccw-DBahX1Sp.js → rotate-ccw-BFON_xv-.js} +1 -1
  80. package/web-app/dist/assets/{scroll-text-BB8y8a9Z.js → scroll-text-CaIlSPZB.js} +1 -1
  81. package/web-app/dist/assets/{server-CfkbW2MH.js → server-CKFUccCG.js} +1 -1
  82. package/web-app/dist/assets/{shield-alert-DUgD8rBF.js → shield-alert-Q4-rPo5r.js} +1 -1
  83. package/web-app/dist/assets/{thumbs-up-DGoyY6QC.js → thumbs-up-BYMeh8oV.js} +1 -1
  84. package/web-app/dist/assets/{trash-2-B6xrSUMr.js → trash-2-BHSUEIHw.js} +1 -1
  85. package/web-app/dist/assets/{trending-down-B6RGKTOx.js → trending-down-BC_FR2VT.js} +1 -1
  86. package/web-app/dist/assets/{trending-up-B44DCrt1.js → trending-up-CmA-WmLW.js} +1 -1
  87. package/web-app/dist/assets/{upload-4kWm33ZY.js → upload-BxLgBa1B.js} +1 -1
  88. package/web-app/dist/assets/{usePolling-zkUtRQG6.js → usePolling-DKNgwt5n.js} +1 -1
  89. package/web-app/dist/assets/{user-04cEVIe2.js → user-CA2DlmLc.js} +1 -1
  90. package/web-app/dist/index.html +1 -1
  91. package/memory/rag_injector.py +0 -161
  92. package/packages/control-plane/ui/dist/assets/index-DbLzr87u.js +0 -190
@@ -248,7 +248,7 @@ async function backfill(o) {
248
248
  }
249
249
  const source = sourceId(o.repoDir);
250
250
  let runs2 = 0, sent = 0;
251
- const failed = [];
251
+ const failed2 = [];
252
252
  for (const id of ids) {
253
253
  const runDir = join7(root, id);
254
254
  if (!hasSpool(runDir))
@@ -264,9 +264,9 @@ async function backfill(o) {
264
264
  await sleep(backoffMs(a));
265
265
  }
266
266
  if (!res.ok)
267
- failed.push(id);
267
+ failed2.push(id);
268
268
  }
269
- return { runs: runs2, sent, failed };
269
+ return { runs: runs2, sent, failed: failed2 };
270
270
  }
271
271
  var init_backfill = __esm(() => {
272
272
  init_ship();
@@ -7325,6 +7325,72 @@ var init_paths = __esm(() => {
7325
7325
  REPO_ROOT = findRepoRoot();
7326
7326
  });
7327
7327
 
7328
+ // ../../loki-ts/src/util/receipt_signer.ts
7329
+ import { createHash as createHash6, randomBytes as randomBytes2, createPrivateKey, createPublicKey as createPublicKey2, generateKeyPairSync, sign, verify as verify2 } from "crypto";
7330
+ import { chmodSync as chmodSync4, linkSync, mkdirSync as mkdirSync5, readdirSync as readdirSync9, readFileSync as readFileSync18, renameSync as renameSync4, statSync as statSync11, unlinkSync as unlinkSync3, writeFileSync as writeFileSync8 } from "fs";
7331
+ import { homedir as homedir8 } from "os";
7332
+ import { dirname as dirname7, join as join26 } from "path";
7333
+ function canonicalJson(x) {
7334
+ const walk = (v) => {
7335
+ if (Array.isArray(v))
7336
+ return `[${v.map(walk).join(",")}]`;
7337
+ if (v !== null && typeof v === "object") {
7338
+ const o = v;
7339
+ return `{${Object.keys(o).filter((k) => o[k] !== undefined).sort().map((k) => `${JSON.stringify(k)}:${walk(o[k])}`).join(",")}}`;
7340
+ }
7341
+ return JSON.stringify(v ?? null);
7342
+ };
7343
+ return walk(x).replace(/[\u0080-\uFFFF]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`);
7344
+ }
7345
+ function loadSigningKey(generate = true) {
7346
+ try {
7347
+ const inline = process.env["LOKI_RECEIPT_SIGNING_KEY"]?.trim();
7348
+ let pem = inline ?? "";
7349
+ if (!inline) {
7350
+ const given = process.env["LOKI_RECEIPT_SIGNING_KEY_FILE"]?.trim();
7351
+ const file = given || join26(process.env["HOME"] || homedir8(), ".loki", "keys", RECEIPT_SIGNER_BASENAME);
7352
+ try {
7353
+ pem = readFileSync18(file);
7354
+ if (!given) {
7355
+ for (const [f, m] of [[file, 384], [dirname7(file), 448]])
7356
+ if (statSync11(f).mode & 63)
7357
+ chmodSync4(f, m);
7358
+ }
7359
+ } catch (e) {
7360
+ if (e.code !== "ENOENT" || !generate)
7361
+ return null;
7362
+ mkdirSync5(dirname7(dirname7(file)), { recursive: true, mode: 448 });
7363
+ mkdirSync5(dirname7(file), { recursive: true, mode: 448 });
7364
+ const tmp = `${file}.${randomBytes2(6).toString("hex")}.tmp`;
7365
+ writeFileSync8(tmp, generateKeyPairSync("ed25519").privateKey.export({ type: "pkcs8", format: "pem" }), { flag: "wx", mode: 384 });
7366
+ try {
7367
+ linkSync(tmp, file);
7368
+ } catch (l) {
7369
+ if (l.code !== "EEXIST")
7370
+ throw l;
7371
+ } finally {
7372
+ unlinkSync3(tmp);
7373
+ }
7374
+ pem = readFileSync18(file);
7375
+ }
7376
+ }
7377
+ const k = createPrivateKey(pem);
7378
+ return k.asymmetricKeyType === "ed25519" ? k : null;
7379
+ } catch {
7380
+ return null;
7381
+ }
7382
+ }
7383
+ function signReceipt(runId, hash) {
7384
+ const key = loadSigningKey();
7385
+ if (!key)
7386
+ return { jwt: null, kid: null };
7387
+ const kid = kidOf2(createPublicKey2(key));
7388
+ 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) }))}`;
7389
+ return { jwt: `${input}.${b64u(sign(null, Buffer.from(input), key))}`, kid };
7390
+ }
7391
+ var RECEIPT_SIGNER_BASENAME = "receipt-ed25519.pem", b64u = (b) => Buffer.from(b).toString("base64url"), kidOf2 = (pub) => b64u(createHash6("sha256").update(`{"crv":"Ed25519","kty":"OKP","x":"${pub.export({ format: "jwk" }).x}"}`).digest());
7392
+ var init_receipt_signer = () => {};
7393
+
7328
7394
  // ../../loki-ts/src/engine10/registry.ts
7329
7395
  var init_registry = () => {};
7330
7396
 
@@ -7377,7 +7443,7 @@ var init_types = __esm(() => {
7377
7443
  });
7378
7444
 
7379
7445
  // ../../loki-ts/src/util/spec_file.ts
7380
- import { isAbsolute, join as join26, relative } from "path";
7446
+ import { isAbsolute, join as join27, relative } from "path";
7381
7447
  function specReceiptBlock(env) {
7382
7448
  const { LOKI_E10_SPEC_PATH: p, LOKI_E10_SPEC_SHA256: sha2 } = env;
7383
7449
  if (!p || !sha2)
@@ -7388,7 +7454,7 @@ function specReceiptBlock(env) {
7388
7454
  var SPEC_DIR;
7389
7455
  var init_spec_file = __esm(() => {
7390
7456
  init_types();
7391
- SPEC_DIR = join26(".loki", "specs");
7457
+ SPEC_DIR = join27(".loki", "specs");
7392
7458
  });
7393
7459
 
7394
7460
  // ../../loki-ts/src/engine10/pr_body.ts
@@ -7400,14 +7466,14 @@ function aiTrailers(i, env = process.env) {
7400
7466
  var markingOn = (env) => env["LOKI_AI_MARKING"] === "1", clean = (v) => v.replace(/[\u0000-\u001f\u007f\u2028\u2029]+/g, " ").replace(/\s+/g, " ").trim().slice(0, 100) || "unknown";
7401
7467
 
7402
7468
  // ../../loki-ts/src/util/credential_env.ts
7403
- import { mkdtempSync as mkdtempSync2, rmSync as rmSync4, statSync as statSync11, lstatSync as lstatSync4 } from "fs";
7469
+ import { mkdtempSync as mkdtempSync2, rmSync as rmSync4, statSync as statSync12, lstatSync as lstatSync4 } from "fs";
7404
7470
  import { tmpdir as tmpdir3 } from "os";
7405
- import { join as join27 } from "path";
7406
- import { randomBytes as randomBytes2 } from "crypto";
7471
+ import { join as join28 } from "path";
7472
+ import { randomBytes as randomBytes3 } from "crypto";
7407
7473
  function withheldSentinel(fresh = false) {
7408
7474
  if (fresh)
7409
7475
  sentinel = null;
7410
- return sentinel ??= `${SENTINEL_PREFIX}${process.pid}${randomBytes2(8).toString("hex")}INVALID`;
7476
+ return sentinel ??= `${SENTINEL_PREFIX}${process.pid}${randomBytes3(8).toString("hex")}INVALID`;
7411
7477
  }
7412
7478
  function removeConfigDir() {
7413
7479
  if (configDir)
@@ -7421,7 +7487,7 @@ function emptyGhConfigDir(env = process.env) {
7421
7487
  const runTmp = env["LOKI_RUN_TMP"] ?? "";
7422
7488
  const root = runTmp !== "" && isDir(runTmp) ? runTmp : tmpdir3();
7423
7489
  try {
7424
- configDir = mkdtempSync2(join27(root, "loki-gh-config-"));
7490
+ configDir = mkdtempSync2(join28(root, "loki-gh-config-"));
7425
7491
  } catch {
7426
7492
  return null;
7427
7493
  }
@@ -7462,7 +7528,7 @@ function hardenCredentialEnv(env, fresh = false) {
7462
7528
  }
7463
7529
  var GITHUB_TOKEN_VARS, SENTINEL_PREFIX = "ghp_LOKIWITHHELDsentinel", sentinel = null, configDir = null, exitHooked = false, sigtermHooked = false, isDir = (p) => {
7464
7530
  try {
7465
- return !lstatSync4(p).isSymbolicLink() && statSync11(p).isDirectory();
7531
+ return !lstatSync4(p).isSymbolicLink() && statSync12(p).isDirectory();
7466
7532
  } catch {
7467
7533
  return false;
7468
7534
  }
@@ -7588,9 +7654,9 @@ var init_run_cap = __esm(() => {
7588
7654
  });
7589
7655
 
7590
7656
  // ../../loki-ts/src/util/mutation_proof.ts
7591
- import { existsSync as existsSync15, mkdirSync as mkdirSync5, mkdtempSync as mkdtempSync3, readFileSync as readFileSync18, rmSync as rmSync5, symlinkSync, writeFileSync as writeFileSync8 } from "fs";
7657
+ import { existsSync as existsSync15, mkdirSync as mkdirSync6, mkdtempSync as mkdtempSync3, readFileSync as readFileSync19, rmSync as rmSync5, symlinkSync, writeFileSync as writeFileSync9 } from "fs";
7592
7658
  import { tmpdir as tmpdir4 } from "os";
7593
- import { basename as basename8, dirname as dirname7, isAbsolute as isAbsolute2, join as join28, relative as relative2 } from "path";
7659
+ import { basename as basename8, dirname as dirname8, isAbsolute as isAbsolute2, join as join29, relative as relative2 } from "path";
7594
7660
  function mutationProof(i) {
7595
7661
  const rels = i.wallFiles.map((f) => isAbsolute2(f.path) ? relative2(i.repoDir, f.path) : f.path);
7596
7662
  if (rels.length === 0)
@@ -7608,25 +7674,25 @@ function mutationProof(i) {
7608
7674
  const deadline = Date.now() + budgetS * 1000, remaining = () => deadline - Date.now();
7609
7675
  let parent = null, wt = null, added = false;
7610
7676
  try {
7611
- parent = mkdtempSync3(join28(tmpdir4(), "loki-mutproof-"));
7612
- wt = join28(parent, "wt");
7677
+ parent = mkdtempSync3(join29(tmpdir4(), "loki-mutproof-"));
7678
+ wt = join29(parent, "wt");
7613
7679
  const add2 = git(i.repoDir, ["worktree", "add", "--detach", wt, i.baseSha], Math.max(1000, Math.min(30000, remaining())));
7614
7680
  added = existsSync15(wt) || add2.status === 0;
7615
7681
  if (add2.status !== 0)
7616
7682
  return np("could not create the base worktree");
7617
7683
  for (const rel of rels) {
7618
- const sealed = join28(i.runDir, "wall", basename8(rel)), src = existsSync15(sealed) ? sealed : join28(i.repoDir, rel);
7684
+ const sealed = join29(i.runDir, "wall", basename8(rel)), src = existsSync15(sealed) ? sealed : join29(i.repoDir, rel);
7619
7685
  if (!existsSync15(src))
7620
7686
  return np(`Wall file missing: ${rel}`);
7621
- mkdirSync5(dirname7(join28(wt, rel)), { recursive: true });
7622
- writeFileSync8(join28(wt, rel), readFileSync18(src));
7687
+ mkdirSync6(dirname8(join29(wt, rel)), { recursive: true });
7688
+ writeFileSync9(join29(wt, rel), readFileSync19(src));
7623
7689
  }
7624
7690
  for (const rel of rels) {
7625
7691
  const parts = rel.split("/").slice(0, -1);
7626
7692
  for (let n2 = 0;n2 <= parts.length; n2++) {
7627
7693
  const anc = parts.slice(0, n2).join("/");
7628
7694
  for (const d of DEP_DIRS) {
7629
- const src = join28(i.repoDir, anc, d), dst = join28(wt, anc, d);
7695
+ const src = join29(i.repoDir, anc, d), dst = join29(wt, anc, d);
7630
7696
  if (existsSync15(src) && !existsSync15(dst)) {
7631
7697
  try {
7632
7698
  symlinkSync(src, dst);
@@ -7823,7 +7889,7 @@ var init_shell = __esm(() => {
7823
7889
  });
7824
7890
 
7825
7891
  // ../../loki-ts/src/util/python.ts
7826
- import { accessSync, constants as constants2, existsSync as existsSync16, statSync as statSync12 } from "fs";
7892
+ import { accessSync, constants as constants2, existsSync as existsSync16, statSync as statSync13 } from "fs";
7827
7893
  import { spawnSync as spawnSync2 } from "child_process";
7828
7894
  import { tmpdir as tmpdir5 } from "os";
7829
7895
  function resolvePython3() {
@@ -7833,7 +7899,7 @@ function resolvePython3() {
7833
7899
  const cand = `${dir}/python3`;
7834
7900
  try {
7835
7901
  accessSync(cand, constants2.X_OK);
7836
- if (statSync12(cand).isFile())
7902
+ if (statSync13(cand).isFile())
7837
7903
  return cand;
7838
7904
  } catch {}
7839
7905
  }
@@ -7960,7 +8026,7 @@ var init_python = __esm(() => {
7960
8026
  init_shell();
7961
8027
  });
7962
8028
 
7963
- // ../../loki-ts/src/features/wall_manifest.ts
8029
+ // ../../loki-ts/src/util/ts_signatures.ts
7964
8030
  function templateEnd(s, i) {
7965
8031
  for (let j = i + 1;j < s.length; ) {
7966
8032
  const c = s[j];
@@ -8686,6 +8752,14 @@ function tsSignatures(src, jsx) {
8686
8752
  }
8687
8753
  return out2;
8688
8754
  }
8755
+ var REGEX_PREV = "(,=:[!&|?{;+-*%~^", isComment = (s, i) => s[i] === "/" && (s[i + 1] === "/" || s[i + 1] === "*"), MODS = "(?:(?:public|private|protected|static|readonly|abstract|async|get|set|declare|override)\\s+)*", MEMBER_GRAMMAR, NOT_MEMBER, RESERVED_AFTER_DECORATOR;
8756
+ var init_ts_signatures = __esm(() => {
8757
+ MEMBER_GRAMMAR = new RegExp(`^(?:@[\\w$.]+(?:\\([^)]*\\))?\\s*)*${MODS}\\*?\\s*(?:[A-Za-z_$][\\w$]*|#[A-Za-z_$][\\w$]*|\\[[^\\]]*\\])\\s*[?!]?\\s*(?:[(<:=]|$)`);
8758
+ NOT_MEMBER = /^(return|const|let|var|if|else|for|while|do|switch|case|default|throw|try|catch|finally|new|await|yield|break|continue|import|export|function|delete|typeof|void)\b/;
8759
+ RESERVED_AFTER_DECORATOR = /^(?:if|else|for|while|do|switch|case|try|catch|finally|return|throw|with|var|let|const|function|new|delete|typeof|void|yield|await|break|continue|import|debugger|instanceof|this|super|null|true|false)(?![\w$])/;
8760
+ });
8761
+
8762
+ // ../../loki-ts/src/features/wall_manifest.ts
8689
8763
  function packageRunner(content) {
8690
8764
  try {
8691
8765
  const pkg = JSON.parse(content);
@@ -8876,21 +8950,19 @@ var MANIFEST_MAX_LINES = 400, MAX_EXAMPLES = 2, EXAMPLE_LINES = 40, MAX_LAYOUT =
8876
8950
  const raw2 = stemOf(m).toLowerCase(), parent = m.split("/").slice(-2, -1)[0];
8877
8951
  return [normStem(raw2), ...["index", "__init__", "mod", "main"].includes(raw2) && parent ? [normStem(parent)] : []];
8878
8952
  }, norm3 = (s) => s.replace(/\r\n?/g, `
8879
- `), stemOf = (p) => (p.split("/").pop() ?? p).replace(/\.[^.]*$/, ""), byPath = (a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : a.content < b.content ? -1 : a.content > b.content ? 1 : 0, REGEX_PREV = "(,=:[!&|?{;+-*%~^", isComment = (s, i) => s[i] === "/" && (s[i + 1] === "/" || s[i + 1] === "*"), MODS = "(?:(?:public|private|protected|static|readonly|abstract|async|get|set|declare|override)\\s+)*", MEMBER_GRAMMAR, NOT_MEMBER, RESERVED_AFTER_DECORATOR;
8953
+ `), stemOf = (p) => (p.split("/").pop() ?? p).replace(/\.[^.]*$/, ""), byPath = (a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : a.content < b.content ? -1 : a.content > b.content ? 1 : 0;
8880
8954
  var init_wall_manifest = __esm(() => {
8881
8955
  init_python();
8956
+ init_ts_signatures();
8882
8957
  TEST_PATH = /(^|\/)(tests?|__tests__|spec)\/|\.(test|spec)\.[jt]sx?$|(^|\/)test_[^/]*\.py$|_test\.(py|go)$/;
8883
8958
  TEST_FILE = /\.(test|spec)\.[cm]?[jt]sx?$|(^|\/)test_[^/]*\.py$|_test\.py$/;
8884
8959
  EXAMPLE_EXT = /\.(py|[cm]?[jt]sx?)$/;
8885
8960
  GENERIC_STEMS = ["index", "init", "mod", "main"];
8886
- MEMBER_GRAMMAR = new RegExp(`^(?:@[\\w$.]+(?:\\([^)]*\\))?\\s*)*${MODS}\\*?\\s*(?:[A-Za-z_$][\\w$]*|#[A-Za-z_$][\\w$]*|\\[[^\\]]*\\])\\s*[?!]?\\s*(?:[(<:=]|$)`);
8887
- NOT_MEMBER = /^(return|const|let|var|if|else|for|while|do|switch|case|default|throw|try|catch|finally|new|await|yield|break|continue|import|export|function|delete|typeof|void)\b/;
8888
- RESERVED_AFTER_DECORATOR = /^(?:if|else|for|while|do|switch|case|try|catch|finally|return|throw|with|var|let|const|function|new|delete|typeof|void|yield|await|break|continue|import|debugger|instanceof|this|super|null|true|false)(?![\w$])/;
8889
8961
  });
8890
8962
 
8891
8963
  // ../../loki-ts/src/features/wall_manifest_wire.ts
8892
- import { createHash as createHash6 } from "crypto";
8893
- import { basename as basename9, dirname as dirname8 } from "path";
8964
+ import { createHash as createHash7 } from "crypto";
8965
+ import { basename as basename9, dirname as dirname9 } from "path";
8894
8966
  function blobEntries(ls) {
8895
8967
  const out2 = [];
8896
8968
  for (const raw2 of ls.toString("latin1").split("\x00")) {
@@ -8920,7 +8992,7 @@ function wallManifestFor(repoDir, tree, task, env = process.env) {
8920
8992
  return null;
8921
8993
  const low = task.toLowerCase().replace(/\\/g, "/");
8922
8994
  const token = (n2) => new RegExp(`(?<![A-Za-z0-9_])${n2.toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![A-Za-z0-9_])`).test(low);
8923
- const dirModule = (e) => /^(index|__init__|mod|main)\.[^.]+$/.test(basename9(e.path)) && e.path.includes("/") && token(dirname8(e.path));
8995
+ const dirModule = (e) => /^(index|__init__|mod|main)\.[^.]+$/.test(basename9(e.path)) && e.path.includes("/") && token(dirname9(e.path));
8924
8996
  const matched = all.filter((e) => SOURCE.test(e.path) && (token(basename9(e.path)) || token(e.path) || token(basename9(e.path).replace(/\.[^.]*$/, "")) || dirModule(e)));
8925
8997
  const spans = (p) => [...low.matchAll(new RegExp(`(?<![A-Za-z0-9_])${p.toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![A-Za-z0-9_])`, "g"))].map((m) => [m.index, m.index + m[0].length]);
8926
8998
  const occ = new Map(matched.map((e) => [e, spans(e.path)]));
@@ -8949,7 +9021,7 @@ function wallManifestFor(repoDir, tree, task, env = process.env) {
8949
9021
  if (at !== cat.length)
8950
9022
  return null;
8951
9023
  const text2 = buildWallManifest([...files, ...listed.map((e) => ({ path: e.path, content: "" }))], named.map((e) => e.path), matched.map((e) => e.path));
8952
- return { text: text2, sha256: createHash6("sha256").update(text2).digest("hex") };
9024
+ return { text: text2, sha256: createHash7("sha256").update(text2).digest("hex") };
8953
9025
  } catch {
8954
9026
  return null;
8955
9027
  }
@@ -8981,12 +9053,12 @@ Example: test('name', () => { assert.strictEqual(fn(1), 2); }); Run: node --tes
8981
9053
  });
8982
9054
 
8983
9055
  // ../../loki-ts/src/engine10/cache.ts
8984
- import { createHash as createHash7 } from "crypto";
8985
- import { existsSync as existsSync17, mkdirSync as mkdirSync6, readFileSync as readFileSync19, writeFileSync as writeFileSync9 } from "fs";
9056
+ import { createHash as createHash8 } from "crypto";
9057
+ import { existsSync as existsSync17, mkdirSync as mkdirSync7, readFileSync as readFileSync20, writeFileSync as writeFileSync10 } from "fs";
8986
9058
  import { resolve as resolve8 } from "path";
8987
9059
  function repoKey(originUrl, repoDir) {
8988
9060
  const basis = originUrl && originUrl.trim() !== "" ? originUrl : resolve8(repoDir);
8989
- return createHash7("sha256").update(basis).digest("hex");
9061
+ return createHash8("sha256").update(basis).digest("hex");
8990
9062
  }
8991
9063
  function defaultCacheRoot() {
8992
9064
  return resolve8(homeLokiDir(), "cache", "v10");
@@ -8998,7 +9070,7 @@ function readJson3(path, isValid = (_v) => true) {
8998
9070
  if (!existsSync17(path))
8999
9071
  return null;
9000
9072
  try {
9001
- const parsed = JSON.parse(readFileSync19(path, "utf8"));
9073
+ const parsed = JSON.parse(readFileSync20(path, "utf8"));
9002
9074
  return isValid(parsed) ? parsed : null;
9003
9075
  } catch {
9004
9076
  return null;
@@ -9048,12 +9120,12 @@ function speedLikelyFiles(task, map, env = process.env) {
9048
9120
  var init_lean_select = () => {};
9049
9121
 
9050
9122
  // ../../loki-ts/src/util/claude_model.ts
9051
- import { readFileSync as readFileSync20 } from "fs";
9123
+ import { readFileSync as readFileSync21 } from "fs";
9052
9124
  import { resolve as resolve9 } from "path";
9053
9125
  function resolveClaudeModel(want) {
9054
9126
  try {
9055
9127
  const path = process.env["LOKI_MODEL_CATALOG"] || resolve9(REPO_ROOT, "providers/model_catalog.json");
9056
- return JSON.parse(readFileSync20(path, "utf8")).providers?.claude?.cli_aliases?.[want] ?? want;
9128
+ return JSON.parse(readFileSync21(path, "utf8")).providers?.claude?.cli_aliases?.[want] ?? want;
9057
9129
  } catch {
9058
9130
  return want;
9059
9131
  }
@@ -9113,8 +9185,8 @@ function routerMode(env = process.env) {
9113
9185
  var routerEnabled = (env = process.env) => routerMode(env) === "on";
9114
9186
 
9115
9187
  // ../../loki-ts/src/engine10/cost.ts
9116
- import { readdirSync as readdirSync9, readFileSync as readFileSync21 } from "fs";
9117
- import { join as join29 } from "path";
9188
+ import { readdirSync as readdirSync10, readFileSync as readFileSync22 } from "fs";
9189
+ import { join as join30 } from "path";
9118
9190
  function routerTelemetryOn(env = process.env) {
9119
9191
  return routerEnabled(env);
9120
9192
  }
@@ -9122,7 +9194,7 @@ function num3(v) {
9122
9194
  return typeof v === "number" && Number.isFinite(v) ? v : 0;
9123
9195
  }
9124
9196
  function resultCostPath(lokiRoot, iteration) {
9125
- return join29(lokiRoot, "metrics", `result-cost-${iteration}.json`);
9197
+ return join30(lokiRoot, "metrics", `result-cost-${iteration}.json`);
9126
9198
  }
9127
9199
  function sumResultCosts(lokiRoot, iterations, context = []) {
9128
9200
  const out2 = {
@@ -9153,7 +9225,7 @@ function sumResultCosts(lokiRoot, iterations, context = []) {
9153
9225
  const parsed = new Map;
9154
9226
  for (const iter of iterations) {
9155
9227
  try {
9156
- parsed.set(iter, JSON.parse(readFileSync21(resultCostPath(lokiRoot, iter), "utf8")));
9228
+ parsed.set(iter, JSON.parse(readFileSync22(resultCostPath(lokiRoot, iter), "utf8")));
9157
9229
  } catch {}
9158
9230
  }
9159
9231
  const own = new Set(iterations);
@@ -9162,7 +9234,7 @@ function sumResultCosts(lokiRoot, iterations, context = []) {
9162
9234
  if (own.has(iter))
9163
9235
  continue;
9164
9236
  try {
9165
- lookup.push({ iter, rec: JSON.parse(readFileSync21(resultCostPath(lokiRoot, iter), "utf8")) });
9237
+ lookup.push({ iter, rec: JSON.parse(readFileSync22(resultCostPath(lokiRoot, iter), "utf8")) });
9166
9238
  } catch {}
9167
9239
  }
9168
9240
  const verdicts = hooks.costRecords?.resumeVerdicts(lookup) ?? { ambiguous: [], separate: [] };
@@ -9267,19 +9339,19 @@ import {
9267
9339
  fstatSync as fstatSync5,
9268
9340
  fsyncSync as fsyncSync2,
9269
9341
  lstatSync as lstatSync6,
9270
- mkdirSync as mkdirSync8,
9342
+ mkdirSync as mkdirSync9,
9271
9343
  openSync as openSync6,
9272
9344
  readSync as readSync5,
9273
- renameSync as renameSync4,
9345
+ renameSync as renameSync5,
9274
9346
  rmSync as rmSync6,
9275
- statSync as statSync13,
9276
- unlinkSync as unlinkSync3,
9277
- writeFileSync as writeFileSync11,
9347
+ statSync as statSync14,
9348
+ unlinkSync as unlinkSync4,
9349
+ writeFileSync as writeFileSync12,
9278
9350
  writeSync as writeSync3
9279
9351
  } from "fs";
9280
- import { dirname as dirname9 } from "path";
9352
+ import { dirname as dirname10 } from "path";
9281
9353
  function durableWriteThenRename(target, body) {
9282
- mkdirSync8(dirname9(target), { recursive: true });
9354
+ mkdirSync9(dirname10(target), { recursive: true });
9283
9355
  const tmp = tmpPathFor(target);
9284
9356
  const fd = openSync6(tmp, "w");
9285
9357
  try {
@@ -9288,13 +9360,13 @@ function durableWriteThenRename(target, body) {
9288
9360
  } finally {
9289
9361
  closeSync6(fd);
9290
9362
  }
9291
- renameSync4(tmp, target);
9363
+ renameSync5(tmp, target);
9292
9364
  fsyncParentDir(target);
9293
9365
  }
9294
9366
  function fsyncParentDir(target) {
9295
9367
  let dfd = null;
9296
9368
  try {
9297
- dfd = openSync6(dirname9(target), "r");
9369
+ dfd = openSync6(dirname10(target), "r");
9298
9370
  fsyncSync2(dfd);
9299
9371
  } catch {} finally {
9300
9372
  if (dfd !== null) {
@@ -9317,14 +9389,14 @@ var init_atomic = __esm(() => {
9317
9389
  });
9318
9390
 
9319
9391
  // ../../loki-ts/src/runner/budget.ts
9320
- import { existsSync as existsSync18, mkdirSync as mkdirSync9, readdirSync as readdirSync10, readFileSync as readFileSync22, writeFileSync as writeFileSync12 } from "fs";
9321
- import { dirname as dirname10, join as join30, resolve as resolve10 } from "path";
9392
+ import { existsSync as existsSync18, mkdirSync as mkdirSync10, readdirSync as readdirSync11, readFileSync as readFileSync23, writeFileSync as writeFileSync13 } from "fs";
9393
+ import { dirname as dirname11, join as join31, resolve as resolve10 } from "path";
9322
9394
  import { fileURLToPath as fileURLToPath2 } from "url";
9323
9395
  function loadDefaultMaxCostUsd() {
9324
- const here = dirname10(fileURLToPath2(import.meta.url));
9396
+ const here = dirname11(fileURLToPath2(import.meta.url));
9325
9397
  for (const rel of [["..", "..", "data"], ["..", "data"]]) {
9326
9398
  try {
9327
- const j = JSON.parse(readFileSync22(resolve10(here, ...rel, "model-pricing.json"), "utf8"));
9399
+ const j = JSON.parse(readFileSync23(resolve10(here, ...rel, "model-pricing.json"), "utf8"));
9328
9400
  if (typeof j.default_max_cost_usd === "number" && Number.isFinite(j.default_max_cost_usd) && j.default_max_cost_usd > 0)
9329
9401
  return j.default_max_cost_usd;
9330
9402
  } catch {}
@@ -9333,11 +9405,11 @@ function loadDefaultMaxCostUsd() {
9333
9405
  }
9334
9406
  function _loadPricing() {
9335
9407
  try {
9336
- const moduleDir = dirname10(fileURLToPath2(import.meta.url));
9408
+ const moduleDir = dirname11(fileURLToPath2(import.meta.url));
9337
9409
  const jsonPath = resolve10(moduleDir, "..", "..", "data", "model-pricing.json");
9338
9410
  if (!existsSync18(jsonPath))
9339
9411
  return _FALLBACK_PRICING;
9340
- const raw2 = JSON.parse(readFileSync22(jsonPath, "utf8"));
9412
+ const raw2 = JSON.parse(readFileSync23(jsonPath, "utf8"));
9341
9413
  const pricing2 = raw2["pricing"];
9342
9414
  if (!pricing2 || typeof pricing2 !== "object")
9343
9415
  return _FALLBACK_PRICING;
@@ -9467,7 +9539,7 @@ var init_model_rank = __esm(() => {
9467
9539
  });
9468
9540
 
9469
9541
  // ../../loki-ts/src/engine10/sizing.ts
9470
- import { existsSync as existsSync19, readFileSync as readFileSync23 } from "fs";
9542
+ import { existsSync as existsSync19, readFileSync as readFileSync24 } from "fs";
9471
9543
  import { basename as basename10 } from "path";
9472
9544
  function namedFiles(task, map) {
9473
9545
  return (map?.files ?? []).filter((f) => task.toLowerCase().includes(basename10(f).toLowerCase()));
@@ -9489,7 +9561,7 @@ function loadRepoMap(repomapRef) {
9489
9561
  if (!repomapRef || !existsSync19(repomapRef))
9490
9562
  return null;
9491
9563
  try {
9492
- return JSON.parse(readFileSync23(repomapRef, "utf8"));
9564
+ return JSON.parse(readFileSync24(repomapRef, "utf8"));
9493
9565
  } catch {
9494
9566
  return null;
9495
9567
  }
@@ -9520,8 +9592,8 @@ var init_sizing = __esm(() => {
9520
9592
  });
9521
9593
 
9522
9594
  // ../../loki-ts/src/project_model/schema.ts
9523
- import { existsSync as existsSync20, lstatSync as lstatSync7, realpathSync as realpathSync15, statSync as statSync14 } from "fs";
9524
- import { isAbsolute as isAbsolute3, join as join32, normalize, sep as sep9 } from "path";
9595
+ import { existsSync as existsSync20, lstatSync as lstatSync7, realpathSync as realpathSync15, statSync as statSync15 } from "fs";
9596
+ import { isAbsolute as isAbsolute3, join as join33, normalize, sep as sep9 } from "path";
9525
9597
  function safeRel(p) {
9526
9598
  const n2 = normalize(p.trim()).split(sep9).join("/").replace(/\/$/, "");
9527
9599
  if (n2 === "" || isAbsolute3(n2) || n2 === ".." || n2.startsWith("../"))
@@ -9530,7 +9602,7 @@ function safeRel(p) {
9530
9602
  }
9531
9603
  function insideRepo(repoDir, rel) {
9532
9604
  try {
9533
- const real2 = realpathSync15(join32(repoDir, rel));
9605
+ const real2 = realpathSync15(join33(repoDir, rel));
9534
9606
  const base = realpathSync15(repoDir);
9535
9607
  return real2 === base || real2.startsWith(base + sep9);
9536
9608
  } catch {
@@ -9543,8 +9615,8 @@ function checkCitation(repoDir, raw2) {
9543
9615
  const rel = safeRel(raw2.replace(/:\d+(?:-\d+)?$/, ""));
9544
9616
  if (rel === null)
9545
9617
  return `citation "${raw2}" is not a repo-relative path`;
9546
- const abs = join32(repoDir, rel);
9547
- if (!existsSync20(abs) || !statSync14(abs).isFile() || !insideRepo(repoDir, rel))
9618
+ const abs = join33(repoDir, rel);
9619
+ if (!existsSync20(abs) || !statSync15(abs).isFile() || !insideRepo(repoDir, rel))
9548
9620
  return `citation "${raw2}" names a file that does not exist`;
9549
9621
  return null;
9550
9622
  }
@@ -9555,7 +9627,7 @@ function checkFingerprint(repoDir, raw2) {
9555
9627
  if (rel === null)
9556
9628
  return `fingerprint "${raw2}" is not a repo-relative path`;
9557
9629
  try {
9558
- if (!lstatSync7(join32(repoDir, rel)).isFile() || !insideRepo(repoDir, rel))
9630
+ if (!lstatSync7(join33(repoDir, rel)).isFile() || !insideRepo(repoDir, rel))
9559
9631
  return `fingerprint "${raw2}" is not a regular file inside the repo`;
9560
9632
  } catch {
9561
9633
  return `fingerprint "${raw2}" names a file that does not exist`;
@@ -9583,8 +9655,8 @@ function checkDir(repoDir, v, where, errs) {
9583
9655
  errs.push(`${where}: must be a repo-relative directory ("." for the repo root)`);
9584
9656
  return ".";
9585
9657
  }
9586
- const abs = join32(repoDir, rel);
9587
- if (!existsSync20(abs) || !statSync14(abs).isDirectory() || !insideRepo(repoDir, rel))
9658
+ const abs = join33(repoDir, rel);
9659
+ if (!existsSync20(abs) || !statSync15(abs).isDirectory() || !insideRepo(repoDir, rel))
9588
9660
  errs.push(`${where}: directory "${rel}" does not exist`);
9589
9661
  return rel;
9590
9662
  }
@@ -9686,9 +9758,9 @@ var init_schema = __esm(() => {
9686
9758
  });
9687
9759
 
9688
9760
  // ../../loki-ts/src/project_model/gather.ts
9689
- import { createHash as createHash8 } from "crypto";
9690
- import { closeSync as closeSync7, lstatSync as lstatSync8, openSync as openSync7, readFileSync as readFileSync24, readSync as readSync6 } from "fs";
9691
- import { dirname as dirname11, join as join33 } from "path";
9761
+ import { createHash as createHash9 } from "crypto";
9762
+ import { closeSync as closeSync7, lstatSync as lstatSync8, openSync as openSync7, readFileSync as readFileSync25, readSync as readSync6 } from "fs";
9763
+ import { dirname as dirname12, join as join34 } from "path";
9692
9764
  function listShallow(repoDir) {
9693
9765
  try {
9694
9766
  const out2 = safeGit(repoDir, ["ls-files", "-z"], { maxBuffer: 256 * 1024 * 1024 });
@@ -9698,10 +9770,10 @@ function listShallow(repoDir) {
9698
9770
  }
9699
9771
  }
9700
9772
  function shallowDirs(repoDir) {
9701
- return [...new Set(listShallow(repoDir).map((p) => dirname11(p)))].sort();
9773
+ return [...new Set(listShallow(repoDir).map((p) => dirname12(p)))].sort();
9702
9774
  }
9703
9775
  function computeKey(repoDir, fingerprintFiles, dirs, committedHash = null) {
9704
- const h = createHash8("sha256");
9776
+ const h = createHash9("sha256");
9705
9777
  h.update(`${MODEL_REV}
9706
9778
  `);
9707
9779
  if (committedHash !== null)
@@ -9714,9 +9786,9 @@ function computeKey(repoDir, fingerprintFiles, dirs, committedHash = null) {
9714
9786
  if (checkFingerprint(repoDir, f) !== null)
9715
9787
  h.update("invalid");
9716
9788
  else {
9717
- const abs = join33(repoDir, f);
9789
+ const abs = join34(repoDir, f);
9718
9790
  const size = lstatSync8(abs).size;
9719
- h.update(size <= GATHER_CAPS.maxHashBytes ? readFileSync24(abs) : `too-large:${size}`);
9791
+ h.update(size <= GATHER_CAPS.maxHashBytes ? readFileSync25(abs) : `too-large:${size}`);
9720
9792
  }
9721
9793
  } catch {
9722
9794
  h.update("missing");
@@ -9741,7 +9813,7 @@ function committedModelHash(raw2) {
9741
9813
  if (typeof raw2 !== "object" || raw2 === null || Array.isArray(raw2))
9742
9814
  return null;
9743
9815
  const { key: _key, expiresAt: _exp, ...rest } = raw2;
9744
- return createHash8("sha256").update(JSON.stringify(rest)).digest("hex");
9816
+ return createHash9("sha256").update(JSON.stringify(rest)).digest("hex");
9745
9817
  }
9746
9818
  var GATHER_CAPS, depthOf = (p) => p.split("/").length, MODEL_REV = "model-rev:2";
9747
9819
  var init_gather = __esm(() => {
@@ -9759,14 +9831,14 @@ var init_gather = __esm(() => {
9759
9831
  });
9760
9832
 
9761
9833
  // ../../loki-ts/src/project_model/discover.ts
9762
- import { existsSync as existsSync21, mkdirSync as mkdirSync10, readFileSync as readFileSync25, rmSync as rmSync7, writeFileSync as writeFileSync13 } from "fs";
9763
- import { join as join34 } from "path";
9834
+ import { existsSync as existsSync21, mkdirSync as mkdirSync11, readFileSync as readFileSync26, rmSync as rmSync7, writeFileSync as writeFileSync14 } from "fs";
9835
+ import { join as join35 } from "path";
9764
9836
  function projectModelEnabled(env = process.env) {
9765
9837
  return env["LOKI_E10_PROJECT_MODEL"] !== "0";
9766
9838
  }
9767
9839
  function loadCached(repoDir, now2 = Date.now()) {
9768
9840
  try {
9769
- return parseCached(repoDir, JSON.parse(readFileSync25(join34(repoDir, PROJECT_FILE), "utf8")), now2);
9841
+ return parseCached(repoDir, JSON.parse(readFileSync26(join35(repoDir, PROJECT_FILE), "utf8")), now2);
9770
9842
  } catch {
9771
9843
  return null;
9772
9844
  }
@@ -9781,7 +9853,7 @@ function loadCommitted(repoDir) {
9781
9853
  };
9782
9854
  let raw2;
9783
9855
  try {
9784
- raw2 = JSON.parse(readFileSync25(join34(repoDir, PROJECT_FILE), "utf8"));
9856
+ raw2 = JSON.parse(readFileSync26(join35(repoDir, PROJECT_FILE), "utf8"));
9785
9857
  } catch (e) {
9786
9858
  return ignore(`unreadable JSON (${e instanceof Error ? e.message : String(e)})`);
9787
9859
  }
@@ -9854,7 +9926,7 @@ var clean2 = (p) => typeof p === "string" ? posix.normalize(p.replace(/\\/g, "/"
9854
9926
  var init_api = () => {};
9855
9927
 
9856
9928
  // ../../loki-ts/src/project_model/resolve.ts
9857
- import { join as join35 } from "path";
9929
+ import { join as join36 } from "path";
9858
9930
  function loadProjectApi(repoDir, env = process.env) {
9859
9931
  if (!projectModelEnabled(env))
9860
9932
  return null;
@@ -9876,7 +9948,7 @@ function siteFor(api, repoDir, file) {
9876
9948
  const rel = api.relativeToRoot(file);
9877
9949
  if (!pkg || pkg.root === "." || rel === null)
9878
9950
  return null;
9879
- return { pkg, root: pkg.root, cwd: join35(repoDir, pkg.root), file: rel };
9951
+ return { pkg, root: pkg.root, cwd: join36(repoDir, pkg.root), file: rel };
9880
9952
  }
9881
9953
  function groupByPackage(api, repoDir, files) {
9882
9954
  const out2 = new Map;
@@ -9907,11 +9979,99 @@ var init_scope = __esm(() => {
9907
9979
  dropped = new WeakMap;
9908
9980
  });
9909
9981
 
9982
+ // ../../loki-ts/src/features/runner_config.ts
9983
+ import { readFileSync as readFileSync27 } from "fs";
9984
+ import { join as join37 } from "path";
9985
+ function relevant(shared, text2) {
9986
+ if (shared === "go") {
9987
+ let blk = false;
9988
+ return lines(text2).filter((l) => {
9989
+ if (blk) {
9990
+ if (l === ")")
9991
+ blk = false;
9992
+ return true;
9993
+ }
9994
+ if (/^replace\s*\($/.test(l)) {
9995
+ blk = true;
9996
+ return true;
9997
+ }
9998
+ return /^replace\s/.test(l);
9999
+ }).join(`
10000
+ `);
10001
+ }
10002
+ if (shared === "tsconfig") {
10003
+ const j = jsonc(text2);
10004
+ const o = j.compilerOptions ?? {};
10005
+ return JSON.stringify(["extends", "baseUrl", "paths", "rootDirs", "moduleSuffixes", "customConditions"].map((k) => k === "extends" ? j["extends"] : o[k]));
10006
+ }
10007
+ if (Array.isArray(shared)) {
10008
+ const j = JSON.parse(text2);
10009
+ return JSON.stringify([shared.map((k) => j[k]), depGuard(j)]);
10010
+ }
10011
+ let on = false;
10012
+ return lines(text2).filter((l) => {
10013
+ if (/^\[[^\]]+\]$/.test(l))
10014
+ on = shared.test(l);
10015
+ return on || KW.test(l);
10016
+ }).join(`
10017
+ `);
10018
+ }
10019
+ function testConfigChanged(repoDir, baseSha, changed) {
10020
+ return changed.filter((f) => {
10021
+ const spec = RUNNER_CONFIGS.find((s) => s.re.test(f));
10022
+ if (!spec)
10023
+ return false;
10024
+ if (!spec.shared)
10025
+ return true;
10026
+ const b = baseText(repoDir, baseSha, f), h = headText(repoDir, f);
10027
+ if (b === h)
10028
+ return false;
10029
+ try {
10030
+ return relevant(spec.shared, b || "{}") !== relevant(spec.shared, h || "{}");
10031
+ } catch {
10032
+ return true;
10033
+ }
10034
+ });
10035
+ }
10036
+ var PKG_KEYS, RUNNER_CONFIGS, DEP_MAPS, RUNNER_DEP, LOCAL_SPEC, depGuard = (j) => DEP_MAPS.map((m) => Object.entries(j[m] ?? {}).filter(([k, v]) => RUNNER_DEP.test(k) || LOCAL_SPEC.test(String(v)))), KW, lines = (t) => t.split(`
10037
+ `).map((l) => l.trim()).filter((l) => l && !l.startsWith("#")), jsonc = (t) => JSON.parse(t.replace(/("(?:\\.|[^"\\])*")|\/\/[^\n]*|\/\*[\s\S]*?\*\//g, "$1").replace(/,(\s*[}\]])/g, "$1")), baseText = (dir, base, f) => {
10038
+ try {
10039
+ return safeGit(dir, ["show", `${base}:./${f}`], { timeout: 20000, maxBuffer: 64 << 20 });
10040
+ } catch {
10041
+ return "";
10042
+ }
10043
+ }, headText = (dir, f) => {
10044
+ try {
10045
+ return readFileSync27(join37(dir, f), "utf8");
10046
+ } catch {
10047
+ return "";
10048
+ }
10049
+ };
10050
+ var init_runner_config = __esm(() => {
10051
+ init_safe_git();
10052
+ PKG_KEYS = ["scripts", "jest", "overrides", "resolutions", "imports", "pnpm", "mocha", "vitest", "ava", "c8", "nyc", "babel", "bun"];
10053
+ RUNNER_CONFIGS = [
10054
+ { re: /(^|\/)(conftest\.py|tox\.ini|bunfig\.toml|\.?pytest\.(ini|toml)|\.mocharc[\w.]*)$/ },
10055
+ { re: /(^|\/)(vitest|vite|jest)\.(config|workspace)\.[\w.]+$/ },
10056
+ { re: /(^|\/)\.cargo\/config(\.toml)?$/ },
10057
+ { re: /(^|\/)package\.json$/, shared: PKG_KEYS },
10058
+ { re: /(^|\/)pyproject\.toml$/, shared: /^\[tool\.pytest/ },
10059
+ { re: /(^|\/)setup\.cfg$/, shared: /^\[tool:pytest\]/ },
10060
+ { re: /(^|\/)go\.mod$/, shared: "go" },
10061
+ { re: /(^|\/)Cargo\.toml$/, shared: /^\[(patch|replace)\b/ },
10062
+ { re: /(^|\/)[jt]sconfig(\.[\w-]+)?\.json$/, shared: "tsconfig" }
10063
+ ];
10064
+ DEP_MAPS = ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"];
10065
+ RUNNER_DEP = /^(jest|vitest|mocha|ava|c8|nyc|pytest[\w-]*|@jest\/.*|ts-jest|babel-jest)$/;
10066
+ LOCAL_SPEC = /^(file|link|npm|workspace):/;
10067
+ KW = /pytest|jest|mocha|vitest|addopts|testpaths/i;
10068
+ });
10069
+
9910
10070
  // ../../loki-ts/src/e10ext/assert_delta.ts
9911
10071
  import { execFileSync as execFileSync5 } from "child_process";
9912
- import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync26, rmSync as rmSync8 } from "fs";
10072
+ import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync28, rmSync as rmSync8 } from "fs";
9913
10073
  import { tmpdir as tmpdir6 } from "os";
9914
- import { join as join36 } from "path";
10074
+ import { join as join38 } from "path";
9915
10075
  import { basename as basename11 } from "path";
9916
10076
  function classifyAssertDelta(inp) {
9917
10077
  const f = basename11(inp.path);
@@ -9921,7 +10081,7 @@ function classifyAssertDelta(inp) {
9921
10081
  return WEAKENED;
9922
10082
  let cwd = "";
9923
10083
  try {
9924
- cwd = mkdtempSync4(join36(tmpdir6(), "loki-ad-"));
10084
+ cwd = mkdtempSync4(join38(tmpdir6(), "loki-ad-"));
9925
10085
  const raw2 = execFileSync5("python3", ["-I", "-c", PY], {
9926
10086
  input: JSON.stringify({ path: inp.path, base: inp.base, head: inp.head, task: inp.task }),
9927
10087
  cwd,
@@ -9952,7 +10112,7 @@ function assertDeltaNotes(repoDir, baseSha, headRef, path, task, baseCounts, hea
9952
10112
  return null;
9953
10113
  try {
9954
10114
  const show = (ref) => safeGit(repoDir, ["show", `${ref}:${path}`]);
9955
- const head = headRef ? show(headRef) : readFileSync26(join36(repoDir, path), "utf8");
10115
+ const head = headRef ? show(headRef) : readFileSync28(join38(repoDir, path), "utf8");
9956
10116
  const r = classifyTestEdit(path, show(baseSha), head, task, baseCounts, headCounts);
9957
10117
  return r[0]?.kind === "literal-only" ? r.map((e) => `assertion value changed (not shown to be required by the task): ${e.file}:${e.line} ${e.old} -> ${e.new}`) : null;
9958
10118
  } catch {
@@ -10142,9 +10302,9 @@ function hasRealTestFailure(out2) {
10142
10302
  return /^\s*Tests:?\s+.*\b[1-9]\d* failed\b/m.test(out2) || /^(?:=+ )?.*\b[1-9]\d* failed\b.* in [\d.]+s/m.test(out2) || /^FAILED \S+::/m.test(out2) || /^(?:#|\u2139) fail [1-9]/m.test(out2) || /^\s*[1-9]\d*\s+fail\s*$/m.test(out2) || /^\s*(?:FAIL|\u00D7)\s+\S.*\s>\s/m.test(out2) || /\bAssertionError\b/.test(out2);
10143
10303
  }
10144
10304
  function firstLoadLine(out2) {
10145
- const lines = out2.split(`
10305
+ const lines2 = out2.split(`
10146
10306
  `).map((l2) => l2.trim()).filter(Boolean);
10147
- const l = lines.find((x) => /^(?:E\s+)?(?:Error|\w*Error|ERROR|Failed|FAIL)\b|Cannot find|Interrupted:|No test files found/.test(x)) ?? lines[0] ?? "";
10307
+ const l = lines2.find((x) => /^(?:E\s+)?(?:Error|\w*Error|ERROR|Failed|FAIL)\b|Cannot find|Interrupted:|No test files found/.test(x)) ?? lines2[0] ?? "";
10148
10308
  return l.replace(/\s+/g, " ").slice(0, 160);
10149
10309
  }
10150
10310
  function classifyRunnerOutput(out2) {
@@ -10176,7 +10336,7 @@ var init_runner_errors = __esm(() => {
10176
10336
  });
10177
10337
 
10178
10338
  // ../../loki-ts/src/engine10/testmap.ts
10179
- import { basename as basename12, extname, join as join37, relative as relative3, sep as sep10 } from "path";
10339
+ import { basename as basename12, extname, join as join39, relative as relative3, sep as sep10 } from "path";
10180
10340
  function isTestFile(rel) {
10181
10341
  const name = basename12(rel);
10182
10342
  return JS_TEST_RE.test(name) || PY_TEST_RE.test(name) || GO_TEST_RE.test(name);
@@ -10206,8 +10366,8 @@ var init_testmap = __esm(() => {
10206
10366
  });
10207
10367
 
10208
10368
  // ../../loki-ts/src/util/check_result.ts
10209
- import { mkdirSync as mkdirSync11, readFileSync as readFileSync27, renameSync as renameSync5, writeFileSync as writeFileSync14 } from "fs";
10210
- import { basename as basename13, join as join38 } from "path";
10369
+ import { mkdirSync as mkdirSync12, readFileSync as readFileSync29, renameSync as renameSync6, writeFileSync as writeFileSync15 } from "fs";
10370
+ import { basename as basename13, join as join40 } from "path";
10211
10371
  function plainTestEnv(base = process.env) {
10212
10372
  const e = {};
10213
10373
  for (const [k, v] of Object.entries(tokenFreeEnv(base)))
@@ -10283,12 +10443,12 @@ function unittestCount(out2, ok) {
10283
10443
  return Math.max(0, +r[1] - +(v.match(/skipped=(\d+)/)?.[1] ?? 0) - +(v.match(/expected failures=(\d+)/)?.[1] ?? 0));
10284
10444
  }
10285
10445
  function goCount(out2, ok) {
10286
- const lines = out2.split(`
10446
+ const lines2 = out2.split(`
10287
10447
  `);
10288
- if (!lines.some((x) => GO_PKG_RE.test(x)))
10448
+ if (!lines2.some((x) => GO_PKG_RE.test(x)))
10289
10449
  return;
10290
- const last = new Map, seen = new Set, skip = new Set, failPkg = ok !== true && lines.some((x) => /^FAIL\s+\S+\s+[\d.]+s\b/.test(x));
10291
- for (const x of lines) {
10450
+ const last = new Map, seen = new Set, skip = new Set, failPkg = ok !== true && lines2.some((x) => /^FAIL\s+\S+\s+[\d.]+s\b/.test(x));
10451
+ for (const x of lines2) {
10292
10452
  const r = x.match(/^=== RUN\s+(\S+)/), m = x.match(/^--- (PASS|FAIL|SKIP): (\S+)/);
10293
10453
  if (r)
10294
10454
  seen.add(r[1]);
@@ -10305,9 +10465,9 @@ function goCount(out2, ok) {
10305
10465
  const t = [...last.values()].filter((v) => v !== "SKIP").length;
10306
10466
  if (t > 0)
10307
10467
  return t;
10308
- if (lines.some((x) => /^(?:=== RUN|PASS$|FAIL$|testing: warning: no tests to run)/.test(x)))
10468
+ if (lines2.some((x) => /^(?:=== RUN|PASS$|FAIL$|testing: warning: no tests to run)/.test(x)))
10309
10469
  return 0;
10310
- return lines.filter((x) => GO_PKG_RE.test(x)).every((x) => /\[no tests? (?:files|to run)\]/.test(x)) ? 0 : null;
10470
+ return lines2.filter((x) => GO_PKG_RE.test(x)).every((x) => /\[no tests? (?:files|to run)\]/.test(x)) ? 0 : null;
10311
10471
  }
10312
10472
  function goRunner(cmd, args) {
10313
10473
  const segs = args ? [[cmd, ...args]] : cmd.split(/&&|\|\||[;|\n]/).map((x) => x.trim().split(/\s+/).filter(Boolean));
@@ -10331,7 +10491,7 @@ function goRunner(cmd, args) {
10331
10491
  return {};
10332
10492
  }
10333
10493
  function goJson(out2) {
10334
- let any = false, failed = false;
10494
+ let any = false, failed2 = false;
10335
10495
  for (const x of out2.split(`
10336
10496
  `)) {
10337
10497
  if (!x.trim() || /^go: /.test(x))
@@ -10346,9 +10506,9 @@ function goJson(out2) {
10346
10506
  return null;
10347
10507
  any = true;
10348
10508
  if (e.Action === "fail")
10349
- failed = true;
10509
+ failed2 = true;
10350
10510
  }
10351
- return any ? { failed } : null;
10511
+ return any ? { failed: failed2 } : null;
10352
10512
  }
10353
10513
  function skipped(raw2) {
10354
10514
  return stripAnsi(raw2).split(`
@@ -10416,7 +10576,7 @@ function markExecuted(a, executed) {
10416
10576
  return { ...a, checks_deferred, summary: summaryOf({ ...a, checks_deferred }) };
10417
10577
  }
10418
10578
  function classifyRisk(files, env = process.env) {
10419
- const lines = files.reduce((n2, f) => n2 + f.added + f.deleted, 0);
10579
+ const lines2 = files.reduce((n2, f) => n2 + f.added + f.deleted, 0);
10420
10580
  const sensitive = files.flatMap((f) => {
10421
10581
  const hit = SENSITIVE.find(([, re]) => re.test(f.path));
10422
10582
  return hit && !isTestFile(f.path) ? [`${f.path} (${hit[0]})`] : [];
@@ -10434,14 +10594,14 @@ function classifyRisk(files, env = process.env) {
10434
10594
  high.push(`public API surface: ${api.slice(0, 3).join(", ")}`);
10435
10595
  if (files.length >= FILES_HIGH)
10436
10596
  high.push(`${files.length} files >= ${FILES_HIGH}`);
10437
- if (lines >= LINES_HIGH)
10438
- high.push(`${lines} changed lines >= ${LINES_HIGH}`);
10597
+ if (lines2 >= LINES_HIGH)
10598
+ high.push(`${lines2} changed lines >= ${LINES_HIGH}`);
10439
10599
  if (testsModified.length)
10440
10600
  med.push(`existing tests or test config modified: ${testsModified.slice(0, 3).join(", ")}`);
10441
10601
  if (files.length >= FILES_MEDIUM)
10442
10602
  med.push(`${files.length} files >= ${FILES_MEDIUM}`);
10443
- if (lines >= LINES_MEDIUM)
10444
- med.push(`${lines} changed lines >= ${LINES_MEDIUM}`);
10603
+ if (lines2 >= LINES_MEDIUM)
10604
+ med.push(`${lines2} changed lines >= ${LINES_MEDIUM}`);
10445
10605
  const computed = high.length ? "high" : med.length ? "medium" : "low";
10446
10606
  const reasons = high.length ? [...high, ...med] : med.length ? med : [`${files.length} file${files.length === 1 ? "" : "s"}, no sensitive paths`];
10447
10607
  let tier = computed, override, ignored;
@@ -10464,7 +10624,7 @@ function classifyRisk(files, env = process.env) {
10464
10624
  tier,
10465
10625
  computed,
10466
10626
  reasons,
10467
- stats: { files: files.length, lines, sensitive, tests_modified: testsModified, tests_deleted: testsDeleted, api },
10627
+ stats: { files: files.length, lines: lines2, sensitive, tests_modified: testsModified, tests_deleted: testsDeleted, api },
10468
10628
  checks_selected: plan.selected,
10469
10629
  checks_deferred,
10470
10630
  ...override ? { override } : {},
@@ -10499,7 +10659,7 @@ function diffFiles(repoDir, baseSha) {
10499
10659
  return f;
10500
10660
  let n2 = 0;
10501
10661
  try {
10502
- n2 = readFileSync27(join38(repoDir, path), "utf8").split(`
10662
+ n2 = readFileSync29(join40(repoDir, path), "utf8").split(`
10503
10663
  `).length;
10504
10664
  } catch {}
10505
10665
  return { path, added: n2, deleted: 0, status: "added" };
@@ -10507,11 +10667,11 @@ function diffFiles(repoDir, baseSha) {
10507
10667
  }
10508
10668
  function recordRisk(repoDir, a) {
10509
10669
  try {
10510
- const dir = join38(repoDir, ".loki", "state"), p = join38(dir, "risk-tier.json");
10511
- mkdirSync11(dir, { recursive: true });
10512
- writeFileSync14(`${p}.tmp`, JSON.stringify(a, null, 2) + `
10670
+ const dir = join40(repoDir, ".loki", "state"), p = join40(dir, "risk-tier.json");
10671
+ mkdirSync12(dir, { recursive: true });
10672
+ writeFileSync15(`${p}.tmp`, JSON.stringify(a, null, 2) + `
10513
10673
  `);
10514
- renameSync5(`${p}.tmp`, p);
10674
+ renameSync6(`${p}.tmp`, p);
10515
10675
  return p;
10516
10676
  } catch {
10517
10677
  return null;
@@ -10552,10 +10712,10 @@ var init_check_result = __esm(() => {
10552
10712
  import { spawnSync as spawnSync3 } from "child_process";
10553
10713
  import { mkdtempSync as mkdtempSync5, realpathSync as realpathSync16, rmSync as rmSync9 } from "fs";
10554
10714
  import { tmpdir as tmpdir7 } from "os";
10555
- import { basename as basename14, extname as extname2, join as join39 } from "path";
10715
+ import { basename as basename14, extname as extname2, join as join41 } from "path";
10556
10716
  function changedFilesNamed(out2, repoDir, changed) {
10557
10717
  return changed.filter((f) => {
10558
- if (out2.includes(f) || out2.includes(join39(repoDir, f)))
10718
+ if (out2.includes(f) || out2.includes(join41(repoDir, f)))
10559
10719
  return true;
10560
10720
  const segs = f.split("/");
10561
10721
  if (suffixes(segs, 2).some((x) => x !== f && bounded(out2, x, "(?![\\w-])")))
@@ -10666,7 +10826,7 @@ async function loadErrorIsHarnessOwned(i) {
10666
10826
  return false;
10667
10827
  if (i.args.some((a) => changed.includes(a.replace(/^\.\//, ""))))
10668
10828
  return false;
10669
- const dir = mkdtempSync5(join39(tmpdir7(), "e10-loadown-"));
10829
+ const dir = mkdtempSync5(join41(tmpdir7(), "e10-loadown-"));
10670
10830
  const git3 = (args) => {
10671
10831
  safeGit(i.repoDir, args, { stdio: "ignore" });
10672
10832
  };
@@ -10698,7 +10858,7 @@ var init_load_owner = __esm(() => {
10698
10858
  });
10699
10859
 
10700
10860
  // ../../loki-ts/src/util/wall_owned.ts
10701
- import { isAbsolute as isAbsolute4, join as join40, relative as relative4 } from "path";
10861
+ import { isAbsolute as isAbsolute4, join as join42, relative as relative4 } from "path";
10702
10862
  function failingLocations(raw2, cwd, repoDir) {
10703
10863
  const out2 = raw2.replace(ANSI2, "").replace(/\r\n?/g, `
10704
10864
  `), files = new Set;
@@ -10730,7 +10890,7 @@ function failingLocations(raw2, cwd, repoDir) {
10730
10890
  }
10731
10891
  if (errors2 === 0 || located !== errors2)
10732
10892
  return null;
10733
- return [...files].map((f) => relative4(repoDir, isAbsolute4(f) ? f : join40(cwd, f)));
10893
+ return [...files].map((f) => relative4(repoDir, isAbsolute4(f) ? f : join42(cwd, f)));
10734
10894
  }
10735
10895
  function wallOwnedFailure(raw2, cwd, repoDir, wall) {
10736
10896
  const locs = failingLocations(raw2, cwd, repoDir);
@@ -10759,11 +10919,11 @@ var init_state = __esm(() => {
10759
10919
  });
10760
10920
 
10761
10921
  // ../../loki-ts/src/runner/repo_profile.ts
10762
- import { existsSync as existsSync22, readFileSync as readFileSync28, mkdirSync as mkdirSync12, readdirSync as readdirSync11, renameSync as renameSync6, rmSync as rmSync10, writeFileSync as writeFileSync15 } from "fs";
10763
- import { basename as basename15, join as join41, resolve as resolve11, isAbsolute as isAbsolute5 } from "path";
10922
+ import { existsSync as existsSync22, readFileSync as readFileSync30, mkdirSync as mkdirSync13, readdirSync as readdirSync12, renameSync as renameSync7, rmSync as rmSync10, writeFileSync as writeFileSync16 } from "fs";
10923
+ import { basename as basename15, join as join43, resolve as resolve11, isAbsolute as isAbsolute5 } from "path";
10764
10924
  function loadProfile(repoDir) {
10765
10925
  try {
10766
- const p = JSON.parse(readFileSync28(commandProfilePath(repoDir), "utf8"));
10926
+ const p = JSON.parse(readFileSync30(commandProfilePath(repoDir), "utf8"));
10767
10927
  return p?.version === 1 && Array.isArray(p.commands) && p.baseline ? p : null;
10768
10928
  } catch {
10769
10929
  return null;
@@ -10794,7 +10954,7 @@ function attributeFullSuite(repoDir, baseSha, full, blocked, changed) {
10794
10954
  const block = new Set(blocked);
10795
10955
  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))) })));
10796
10956
  }
10797
- var commandProfilePath = (repoDir) => join41(repoDir, ".loki", "state", "repo-profile.json");
10957
+ var commandProfilePath = (repoDir) => join43(repoDir, ".loki", "state", "repo-profile.json");
10798
10958
  var init_repo_profile = __esm(() => {
10799
10959
  init_failures();
10800
10960
  init_check_result();
@@ -10804,23 +10964,23 @@ var init_repo_profile = __esm(() => {
10804
10964
  });
10805
10965
 
10806
10966
  // ../../loki-ts/src/project_graph.ts
10807
- import { createHash as createHash9 } from "crypto";
10967
+ import { createHash as createHash10 } from "crypto";
10808
10968
  import {
10809
10969
  existsSync as existsSync23,
10810
- readdirSync as readdirSync12,
10811
- readFileSync as readFileSync29,
10812
- statSync as statSync15,
10813
- writeFileSync as writeFileSync16,
10814
- mkdirSync as mkdirSync13
10970
+ readdirSync as readdirSync13,
10971
+ readFileSync as readFileSync31,
10972
+ statSync as statSync16,
10973
+ writeFileSync as writeFileSync17,
10974
+ mkdirSync as mkdirSync14
10815
10975
  } from "fs";
10816
- import { basename as basename16, dirname as dirname12, join as join42, resolve as resolve12 } from "path";
10976
+ import { basename as basename16, dirname as dirname13, join as join44, resolve as resolve12 } from "path";
10817
10977
  function readManifest(path) {
10818
10978
  if (!existsSync23(path)) {
10819
10979
  return null;
10820
10980
  }
10821
10981
  let raw2;
10822
10982
  try {
10823
- raw2 = readFileSync29(path, "utf8");
10983
+ raw2 = readFileSync31(path, "utf8");
10824
10984
  } catch {
10825
10985
  return null;
10826
10986
  }
@@ -10857,7 +11017,7 @@ function resolveMembers(rootDir, declared, selfBasename) {
10857
11017
  const seen = new Set;
10858
11018
  let children;
10859
11019
  try {
10860
- children = readdirSync12(rootDir);
11020
+ children = readdirSync13(rootDir);
10861
11021
  } catch {
10862
11022
  children = [];
10863
11023
  }
@@ -10872,12 +11032,12 @@ function resolveMembers(rootDir, declared, selfBasename) {
10872
11032
  for (const child of children) {
10873
11033
  if (!matchPattern(name, child))
10874
11034
  continue;
10875
- const full = join42(rootDir, child);
11035
+ const full = join44(rootDir, child);
10876
11036
  if (seen.has(full))
10877
11037
  continue;
10878
11038
  let st;
10879
11039
  try {
10880
- st = statSync15(full);
11040
+ st = statSync16(full);
10881
11041
  } catch {
10882
11042
  continue;
10883
11043
  }
@@ -10889,18 +11049,18 @@ function resolveMembers(rootDir, declared, selfBasename) {
10889
11049
  }
10890
11050
  if (declared.length === 0) {
10891
11051
  for (const child of children) {
10892
- const full = join42(rootDir, child);
11052
+ const full = join44(rootDir, child);
10893
11053
  if (seen.has(full))
10894
11054
  continue;
10895
11055
  let st;
10896
11056
  try {
10897
- st = statSync15(full);
11057
+ st = statSync16(full);
10898
11058
  } catch {
10899
11059
  continue;
10900
11060
  }
10901
11061
  if (!st.isDirectory())
10902
11062
  continue;
10903
- if (!existsSync23(join42(full, ".loki", "app.json")))
11063
+ if (!existsSync23(join44(full, ".loki", "app.json")))
10904
11064
  continue;
10905
11065
  seen.add(full);
10906
11066
  out2.push(full);
@@ -10913,25 +11073,25 @@ function cacheKey(manifestPaths) {
10913
11073
  for (const p of manifestPaths.sort()) {
10914
11074
  let mtime = 0;
10915
11075
  try {
10916
- mtime = statSync15(p).mtimeMs;
11076
+ mtime = statSync16(p).mtimeMs;
10917
11077
  } catch {}
10918
11078
  parts.push(`${p}:${mtime}`);
10919
11079
  }
10920
- return createHash9("sha256").update(parts.join("|")).digest("hex");
11080
+ return createHash10("sha256").update(parts.join("|")).digest("hex");
10921
11081
  }
10922
11082
  function writeCache(targetDir, key, result) {
10923
11083
  try {
10924
- const cacheDir = join42(targetDir, ".loki", "state");
10925
- mkdirSync13(cacheDir, { recursive: true });
10926
- const cachePath = join42(cacheDir, "project-graph.json");
10927
- writeFileSync16(cachePath, JSON.stringify({ key, result }, null, 2), "utf8");
11084
+ const cacheDir = join44(targetDir, ".loki", "state");
11085
+ mkdirSync14(cacheDir, { recursive: true });
11086
+ const cachePath = join44(cacheDir, "project-graph.json");
11087
+ writeFileSync17(cachePath, JSON.stringify({ key, result }, null, 2), "utf8");
10928
11088
  } catch {}
10929
11089
  }
10930
11090
  function discoverProjectGraph(targetDir) {
10931
11091
  const absTarget = resolve12(targetDir);
10932
- const targetManifest = join42(absTarget, ".loki", "app.json");
10933
- const parentDir = dirname12(absTarget);
10934
- const parentManifest = join42(parentDir, ".loki", "app.json");
11092
+ const targetManifest = join44(absTarget, ".loki", "app.json");
11093
+ const parentDir = dirname13(absTarget);
11094
+ const parentManifest = join44(parentDir, ".loki", "app.json");
10935
11095
  const examined = [];
10936
11096
  let chosenManifest = null;
10937
11097
  let chosenRoot = "";
@@ -10951,7 +11111,7 @@ function discoverProjectGraph(targetDir) {
10951
11111
  const members = resolveMembers(chosenRoot, declared, basename16(absTarget));
10952
11112
  const filtered = [];
10953
11113
  for (const m of members) {
10954
- const sibManifestPath = join42(m, ".loki", "app.json");
11114
+ const sibManifestPath = join44(m, ".loki", "app.json");
10955
11115
  if (existsSync23(sibManifestPath)) {
10956
11116
  examined.push(sibManifestPath);
10957
11117
  const sibManifest = readManifest(sibManifestPath);
@@ -11024,15 +11184,15 @@ var init_steer = __esm(() => {
11024
11184
  });
11025
11185
 
11026
11186
  // ../../loki-ts/src/util/pr_lessons.ts
11027
- import { existsSync as existsSync24, mkdirSync as mkdirSync14, readFileSync as readFileSync30 } from "fs";
11028
- import { dirname as dirname13, join as join43 } from "path";
11029
- import { createHash as createHash10 } from "crypto";
11187
+ import { existsSync as existsSync24, mkdirSync as mkdirSync15, readFileSync as readFileSync32 } from "fs";
11188
+ import { dirname as dirname14, join as join45 } from "path";
11189
+ import { createHash as createHash11 } from "crypto";
11030
11190
  function loadLessons(repoDir) {
11031
11191
  const p = lessonsPath(repoDir);
11032
11192
  if (!existsSync24(p))
11033
11193
  return [];
11034
11194
  try {
11035
- const j = JSON.parse(readFileSync30(p, "utf-8"));
11195
+ const j = JSON.parse(readFileSync32(p, "utf-8"));
11036
11196
  return Array.isArray(j.lessons) ? j.lessons : [];
11037
11197
  } catch {
11038
11198
  return [];
@@ -11040,11 +11200,11 @@ function loadLessons(repoDir) {
11040
11200
  }
11041
11201
  function save(repoDir, lessons) {
11042
11202
  const p = lessonsPath(repoDir);
11043
- mkdirSync14(dirname13(p), { recursive: true });
11203
+ mkdirSync15(dirname14(p), { recursive: true });
11044
11204
  atomicWriteJson(p, { version: 2, lessons });
11045
11205
  }
11046
11206
  function appendReceiptFact(repoDir, f, now2 = () => new Date) {
11047
- const id = `rcp-${createHash10("sha256").update(f.runId).digest("hex").slice(0, 12)}`;
11207
+ const id = `rcp-${createHash11("sha256").update(f.runId).digest("hex").slice(0, 12)}`;
11048
11208
  const lessons = loadLessons(repoDir);
11049
11209
  if (lessons.some((l) => l.id === id))
11050
11210
  return false;
@@ -11074,7 +11234,7 @@ function recordRunVerdict(repoDir, runId, verdict) {
11074
11234
  if (dirty)
11075
11235
  save(repoDir, lessons);
11076
11236
  }
11077
- var lessonsPath = (repoDir) => join43(repoDir, ".loki", "memory", "semantic", "pr-lessons.json"), KINDS;
11237
+ var lessonsPath = (repoDir) => join45(repoDir, ".loki", "memory", "semantic", "pr-lessons.json"), KINDS;
11078
11238
  var init_pr_lessons = __esm(() => {
11079
11239
  init_atomic();
11080
11240
  KINDS = new Set(["pr", "receipt", "ticket", "rejected"]);
@@ -11090,19 +11250,19 @@ var init_model_downgrades = __esm(() => {
11090
11250
  var init_mcp_config = () => {};
11091
11251
 
11092
11252
  // ../../loki-ts/src/providers/claude_flags.ts
11093
- import { existsSync as existsSync25, readFileSync as readFileSync31 } from "fs";
11094
- import { resolve as resolvePath, dirname as dirname14 } from "path";
11253
+ import { existsSync as existsSync25, readFileSync as readFileSync33 } from "fs";
11254
+ import { resolve as resolvePath, dirname as dirname15 } from "path";
11095
11255
  import { fileURLToPath as fileURLToPath3 } from "url";
11096
11256
  function designArchetypesText() {
11097
11257
  try {
11098
- const moduleDir = dirname14(fileURLToPath3(import.meta.url));
11258
+ const moduleDir = dirname15(fileURLToPath3(import.meta.url));
11099
11259
  for (const rel of [
11100
11260
  ["..", "..", "..", "references", "design-archetypes.md"],
11101
11261
  ["..", "..", "references", "design-archetypes.md"]
11102
11262
  ]) {
11103
11263
  const p = resolvePath(moduleDir, ...rel);
11104
11264
  if (existsSync25(p))
11105
- return readFileSync31(p, "utf8");
11265
+ return readFileSync33(p, "utf8");
11106
11266
  }
11107
11267
  } catch {}
11108
11268
  return "";
@@ -11180,14 +11340,14 @@ var init_providers = __esm(() => {
11180
11340
  });
11181
11341
 
11182
11342
  // ../../loki-ts/src/runner/router/route_record.ts
11183
- import { existsSync as existsSync26, lstatSync as lstatSync9, mkdirSync as mkdirSync15, readFileSync as readFileSync32, writeFileSync as writeFileSync17 } from "fs";
11184
- import { join as join44 } from "path";
11343
+ import { existsSync as existsSync26, lstatSync as lstatSync9, mkdirSync as mkdirSync16, readFileSync as readFileSync34, writeFileSync as writeFileSync18 } from "fs";
11344
+ import { join as join46 } from "path";
11185
11345
  function loadRouteRecord(runDir) {
11186
11346
  try {
11187
- const p = join44(runDir, ROUTE_RECORD_FILE);
11347
+ const p = join46(runDir, ROUTE_RECORD_FILE);
11188
11348
  if (!existsSync26(p) || !lstatSync9(p).isFile())
11189
11349
  return;
11190
- const v = JSON.parse(readFileSync32(p, "utf8"));
11350
+ const v = JSON.parse(readFileSync34(p, "utf8"));
11191
11351
  return typeof v === "object" && v !== null && !Array.isArray(v) ? v : undefined;
11192
11352
  } catch {
11193
11353
  return;
@@ -11197,7 +11357,7 @@ var ROUTE_RECORD_FILE = "route.json";
11197
11357
  var init_route_record = () => {};
11198
11358
 
11199
11359
  // ../../loki-ts/src/runner/router/history_store.ts
11200
- import { existsSync as existsSync27, mkdirSync as mkdirSync16, readFileSync as readFileSync33, renameSync as renameSync7, rmSync as rmSync11, writeFileSync as writeFileSync18 } from "fs";
11360
+ import { existsSync as existsSync27, mkdirSync as mkdirSync17, readFileSync as readFileSync35, renameSync as renameSync8, rmSync as rmSync11, writeFileSync as writeFileSync19 } from "fs";
11201
11361
  import { resolve as resolve13 } from "path";
11202
11362
  function validRun(v) {
11203
11363
  if (typeof v !== "object" || v === null)
@@ -11213,7 +11373,7 @@ function readRunHistory(key, cacheRoot) {
11213
11373
  if (!existsSync27(path))
11214
11374
  return [];
11215
11375
  try {
11216
- const parsed = JSON.parse(readFileSync33(path, "utf8"));
11376
+ const parsed = JSON.parse(readFileSync35(path, "utf8"));
11217
11377
  const runs2 = parsed?.runs;
11218
11378
  return Array.isArray(runs2) ? runs2.filter(validRun) : [];
11219
11379
  } catch {
@@ -11223,12 +11383,12 @@ function readRunHistory(key, cacheRoot) {
11223
11383
  function appendRunOutcome(key, outcome, cacheRoot) {
11224
11384
  try {
11225
11385
  const runs2 = [...readRunHistory(key, cacheRoot), outcome].slice(-HISTORY_CAP);
11226
- mkdirSync16(repoCacheDir(key, cacheRoot), { recursive: true });
11386
+ mkdirSync17(repoCacheDir(key, cacheRoot), { recursive: true });
11227
11387
  const target = historyPath(key, cacheRoot);
11228
11388
  const tmp = `${target}.${process.pid}.tmp`;
11229
11389
  try {
11230
- writeFileSync18(tmp, JSON.stringify({ runs: runs2 }));
11231
- renameSync7(tmp, target);
11390
+ writeFileSync19(tmp, JSON.stringify({ runs: runs2 }));
11391
+ renameSync8(tmp, target);
11232
11392
  } catch (e) {
11233
11393
  rmSync11(tmp, { force: true, recursive: false });
11234
11394
  throw e;
@@ -11247,7 +11407,7 @@ var init_history_store = __esm(() => {
11247
11407
  });
11248
11408
 
11249
11409
  // ../../loki-ts/src/runner/router/history.ts
11250
- import { dirname as dirname15, join as join45, resolve as resolve14 } from "path";
11410
+ import { dirname as dirname16, join as join47, resolve as resolve14 } from "path";
11251
11411
  import { fileURLToPath as fileURLToPath4 } from "url";
11252
11412
  function shapeKey(model) {
11253
11413
  if (!model || model.status !== "ok")
@@ -11276,7 +11436,7 @@ var init_history = __esm(() => {
11276
11436
  init_discover2();
11277
11437
  init_gather();
11278
11438
  init_history_store();
11279
- SHAPE_DEFAULTS_FILE = resolve14(dirname15(fileURLToPath4(import.meta.url)), "..", "..", "..", "data", "router-shape-defaults.json");
11439
+ SHAPE_DEFAULTS_FILE = resolve14(dirname16(fileURLToPath4(import.meta.url)), "..", "..", "..", "data", "router-shape-defaults.json");
11280
11440
  });
11281
11441
 
11282
11442
  // ../../loki-ts/src/runner/router/plan_route.ts
@@ -11407,7 +11567,7 @@ var init_worker = __esm(() => {
11407
11567
  });
11408
11568
 
11409
11569
  // ../../loki-ts/src/project_model/package_suite.ts
11410
- import { join as join46 } from "path";
11570
+ import { join as join48 } from "path";
11411
11571
  async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
11412
11572
  const api = loadProjectApi(repoDir);
11413
11573
  if (!isMultiRoot(api))
@@ -11418,7 +11578,7 @@ async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
11418
11578
  for (const pkg of withTests) {
11419
11579
  const tc = pkg.commands.test, name = `full suite: ${pkg.name}`, cmd = `(cd ${tc.cwd} && ${tc.cmd})`;
11420
11580
  const started = Date.now();
11421
- const r = await run(["bash", "-c", tc.cmd], { cwd: join46(repoDir, tc.cwd), timeoutMs: opts.timeoutMs, ...opts.path ? { env: { PATH: opts.path } } : {} });
11581
+ const r = await run(["bash", "-c", tc.cmd], { cwd: join48(repoDir, tc.cwd), timeoutMs: opts.timeoutMs, ...opts.path ? { env: { PATH: opts.path } } : {} });
11422
11582
  const duration_s = (Date.now() - started) / 1000;
11423
11583
  if (signal.aborted) {
11424
11584
  checks.push({ name, cmd, result: "not_run", duration_s });
@@ -11427,7 +11587,7 @@ async function runPackageSuites(repoDir, signal, opts, checks, notProven) {
11427
11587
  }
11428
11588
  const out2 = `${r.stdout}
11429
11589
  ${r.stderr}`;
11430
- const lr = r.exitCode === 0 || !opts.baseSha ? undefined : await harnessLoadReason({ repoDir, baseSha: opts.baseSha, out: out2, cmd: "bash", args: ["-c", tc.cmd], signal, cwd: join46(repoDir, tc.cwd), ...opts.path ? { env: { PATH: opts.path } } : {} });
11590
+ const lr = r.exitCode === 0 || !opts.baseSha ? undefined : await harnessLoadReason({ repoDir, baseSha: opts.baseSha, out: out2, cmd: "bash", args: ["-c", tc.cmd], signal, cwd: join48(repoDir, tc.cwd), ...opts.path ? { env: { PATH: opts.path } } : {} });
11431
11591
  if (lr) {
11432
11592
  checks.push({ name, cmd, result: "not_run", duration_s });
11433
11593
  notProven.add(`${lr} (${name}; harness-owned)`);
@@ -11460,8 +11620,8 @@ __export(exports_deep, {
11460
11620
  DEFAULT_SECRET_SCAN_SH: () => DEFAULT_SECRET_SCAN_SH,
11461
11621
  DEFAULT_PUSH_SH: () => DEFAULT_PUSH_SH
11462
11622
  });
11463
- import { existsSync as existsSync28, mkdirSync as mkdirSync17, writeFileSync as writeFileSync19 } from "fs";
11464
- import { join as join47 } from "path";
11623
+ import { existsSync as existsSync28, mkdirSync as mkdirSync18, writeFileSync as writeFileSync20 } from "fs";
11624
+ import { join as join49 } from "path";
11465
11625
  async function runFullSuite(ctx, signal, opts, checks, notProven) {
11466
11626
  if (await runPackageSuites(ctx.repoDir, signal, { path: opts.path, timeoutMs: opts.fullSuiteTimeoutMs ?? FULL_SUITE_TIMEOUT_MS, baseSha: ctx.baseSha }, checks, notProven))
11467
11627
  return;
@@ -11558,7 +11718,7 @@ async function runSecretScan(ctx, changed, opts, checks, notProven) {
11558
11718
  }
11559
11719
  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"';
11560
11720
  const started = Date.now();
11561
- const r = await run(["bash", "-c", inline, "_", scriptPath, ...changed.map((f) => join47(ctx.repoDir, f))], { cwd: ctx.repoDir, timeoutMs: 30000 });
11721
+ const r = await run(["bash", "-c", inline, "_", scriptPath, ...changed.map((f) => join49(ctx.repoDir, f))], { cwd: ctx.repoDir, timeoutMs: 30000 });
11562
11722
  const durationS = (Date.now() - started) / 1000;
11563
11723
  if (r.exitCode === 3) {
11564
11724
  checks.push({ name, cmd: "secret-scan.sh", result: "not_run", duration_s: durationS });
@@ -11579,10 +11739,10 @@ function commentArgv(prNumber, bodyFile) {
11579
11739
  return ["comment", prNumber, bodyFile];
11580
11740
  }
11581
11741
  function buildCommentBody(checks, notProven, statusState) {
11582
- const lines = [`## Loki deep verify: ${statusState}`, "", "### Checks"];
11583
- lines.push(...checks.length ? checks.map((c) => `- ${c.result}: ${c.name}${c.reason ? ` (${c.reason})` : ""}`) : ["- none"]);
11584
- lines.push("", "### NOT PROVEN", ...notProven.length ? notProven.map((n2) => `- ${n2}`) : ["- none"]);
11585
- return `${lines.join(`
11742
+ const lines2 = [`## Loki deep verify: ${statusState}`, "", "### Checks"];
11743
+ lines2.push(...checks.length ? checks.map((c) => `- ${c.result}: ${c.name}${c.reason ? ` (${c.reason})` : ""}`) : ["- none"]);
11744
+ lines2.push("", "### NOT PROVEN", ...notProven.length ? notProven.map((n2) => `- ${n2}`) : ["- none"]);
11745
+ return `${lines2.join(`
11586
11746
  `)}
11587
11747
  `;
11588
11748
  }
@@ -11598,9 +11758,9 @@ async function postResults(ctx, opts, checks, notProven, statusState) {
11598
11758
  const prUrl = ctx.outputs().pr?.pr_url;
11599
11759
  const prNumber = prUrl ? PR_NUMBER_RE.exec(prUrl)?.[1] : undefined;
11600
11760
  if (prNumber) {
11601
- mkdirSync17(ctx.runDir, { recursive: true });
11602
- const bodyFile = join47(ctx.runDir, "deep-comment.md");
11603
- writeFileSync19(bodyFile, buildCommentBody(checks, notProven, statusState), "utf8");
11761
+ mkdirSync18(ctx.runDir, { recursive: true });
11762
+ const bodyFile = join49(ctx.runDir, "deep-comment.md");
11763
+ writeFileSync20(bodyFile, buildCommentBody(checks, notProven, statusState), "utf8");
11604
11764
  const commentResult = await run(["bash", scriptPath, ...commentArgv(prNumber, bodyFile)], { cwd: ctx.repoDir, env, timeoutMs: 30000 });
11605
11765
  if (commentResult.exitCode !== 0)
11606
11766
  out2.push(`deep comment not posted (engine10-push.sh exit ${commentResult.exitCode})`);
@@ -11652,8 +11812,8 @@ async function runDeep(ctx, signal, opts = {}) {
11652
11812
  const addendumSha256 = sha2562(canonicalJson(addendumBody));
11653
11813
  const sig = signReceipt(`${ctx.runId}-deep`, addendumSha256);
11654
11814
  const addendum = { ...addendumBody, addendum_sha256: addendumSha256, verification: { jwt: sig.jwt, kid: sig.kid } };
11655
- mkdirSync17(ctx.runDir, { recursive: true });
11656
- writeFileSync19(join47(ctx.runDir, "receipt-addendum-1.json"), JSON.stringify(addendum, null, 2) + `
11815
+ mkdirSync18(ctx.runDir, { recursive: true });
11816
+ writeFileSync20(join49(ctx.runDir, "receipt-addendum-1.json"), JSON.stringify(addendum, null, 2) + `
11657
11817
  `);
11658
11818
  const pushNotProven = await postResults(ctx, opts, checks, notProvenList, statusState);
11659
11819
  const allNotProven = [...notProvenList, ...pushNotProven];
@@ -11698,7 +11858,7 @@ var init_deep = __esm(() => {
11698
11858
  // ../../loki-ts/src/engine10/stages/verify.ts
11699
11859
  import { existsSync as existsSync29, mkdtempSync as mkdtempSync6, realpathSync as realpathSync17, rmSync as rmSync12 } from "fs";
11700
11860
  import { tmpdir as tmpdir8 } from "os";
11701
- import { dirname as dirname16, isAbsolute as isAbsolute6, join as join48, relative as relative5 } from "path";
11861
+ import { dirname as dirname17, isAbsolute as isAbsolute6, join as join50, relative as relative5 } from "path";
11702
11862
  function resolveTool(repoDir, bin, fallback, lastResort = fallback) {
11703
11863
  const inRepo = (p) => {
11704
11864
  try {
@@ -11709,7 +11869,7 @@ function resolveTool(repoDir, bin, fallback, lastResort = fallback) {
11709
11869
  }
11710
11870
  };
11711
11871
  const venvEnv = process.env["VIRTUAL_ENV"];
11712
- const project = [join48(repoDir, ".venv", "bin", bin), join48(repoDir, "venv", "bin", bin), ...venvEnv && inRepo(venvEnv) ? [join48(venvEnv, "bin", bin)] : []].find(existsSync29);
11872
+ const project = [join50(repoDir, ".venv", "bin", bin), join50(repoDir, "venv", "bin", bin), ...venvEnv && inRepo(venvEnv) ? [join50(venvEnv, "bin", bin)] : []].find(existsSync29);
11713
11873
  return project ? [project, "project"] : [Bun.which(fallback) ? fallback : lastResort, "system"];
11714
11874
  }
11715
11875
  function runnerCmd(t, repoDir) {
@@ -11729,7 +11889,7 @@ function runnerCmd(t, repoDir) {
11729
11889
  case "npm":
11730
11890
  return ["npm", ["test", "--silent"]];
11731
11891
  case "go":
11732
- return ["go", ["test", "-json", `./${dirname16(t.path)}`]];
11892
+ return ["go", ["test", "-json", `./${dirname17(t.path)}`]];
11733
11893
  case "cargo":
11734
11894
  return ["cargo", ["test"]];
11735
11895
  }
@@ -11739,13 +11899,6 @@ function commandFor(t, repoDir, api) {
11739
11899
  const [cmd, args, interpreter] = runnerCmd(site ? { runner: t.runner, path: site.file } : t, repoDir);
11740
11900
  return { cwd: site?.cwd ?? repoDir, cmd, args, argv: [cmd, ...args], ...interpreter ? { interpreter } : {}, pkgRoot: site?.root ?? "." };
11741
11901
  }
11742
- function testConfigChanged(repoDir, baseSha, changed) {
11743
- const diff = (f) => safeGit(repoDir, ["diff", "-U0", baseSha, "--", f]);
11744
- return changed.filter((f) => CFG_ALWAYS.test(f) || CFG_SHARED.test(f) && (() => {
11745
- const d = diff(f);
11746
- return !d || CFG_LINE.test(d);
11747
- })());
11748
- }
11749
11902
  async function runOnce(cmd, args, cwd, signal, opts) {
11750
11903
  if (!Bun.which(cmd, { PATH: opts.path ?? process.env["PATH"] ?? "" }))
11751
11904
  return { ok: false, missing: true, cut: false, out: "" };
@@ -11784,8 +11937,8 @@ function firstError(out2) {
11784
11937
  return l2;
11785
11938
  }
11786
11939
  };
11787
- const lines = out2.slice(-65536).split(`
11788
- `).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)) ?? "";
11940
+ const lines2 = out2.slice(-65536).split(`
11941
+ `).map((l2) => (l2.startsWith("{") ? goOut(l2) : l2).trim()).filter(Boolean), l = lines2.find((x) => /^(FAILED\s|\u25cf\s.*\u203a|not ok\s|_{3,}\s.+\s_{3,}$)/.test(x)) ?? lines2.find((x) => /^[\w./-]+\.go:\d+:\d+: \S/.test(x)) ?? lines2.find((x) => /fail|error/i.test(x) && !/^(=|\u2713|ok\b|PASS)/.test(x)) ?? "";
11789
11942
  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);
11790
11943
  }
11791
11944
  async function runCheck(ctx, name, cmd, args, signal, checks, opts = {}) {
@@ -11827,7 +11980,7 @@ async function subtractBase(ctx, api, checks, tests, changed, wall, rel, signal)
11827
11980
  const sus = pairs.filter(({ c }) => rel.has(c.name) && c.result === "pass");
11828
11981
  if (!(un.some(({ c }) => c.result === "fail" && c.ids?.length) || sus.length) || signal.aborted)
11829
11982
  return out2;
11830
- const dir = mkdtempSync6(join48(tmpdir8(), "e10-base-"));
11983
+ const dir = mkdtempSync6(join50(tmpdir8(), "e10-base-"));
11831
11984
  const git3 = (args) => {
11832
11985
  safeGit(ctx.repoDir, args, { stdio: "ignore", repoDrivers: true });
11833
11986
  };
@@ -11862,7 +12015,7 @@ async function subtractBase(ctx, api, checks, tests, changed, wall, rel, signal)
11862
12015
  return out2;
11863
12016
  }
11864
12017
  function isLokiModeRepo(repoDir) {
11865
- return existsSync29(join48(repoDir, "scripts", "select-tests.sh"));
12018
+ return existsSync29(join50(repoDir, "scripts", "select-tests.sh"));
11866
12019
  }
11867
12020
  async function runLintChecks(ctx, changed, signal, checks, opts = {}) {
11868
12021
  const { api, ...runOpts } = opts;
@@ -11879,15 +12032,16 @@ async function runLintChecks(ctx, changed, signal, checks, opts = {}) {
11879
12032
  }
11880
12033
  for (const g of groupByPackage(api, ctx.repoDir, changed.filter((f) => /\.(ts|tsx|js|jsx)$/.test(f)))) {
11881
12034
  const sfx = g.root === "." ? "" : `:${g.root}`, co = g.root === "." ? opts : { ...opts, cwd: g.cwd };
11882
- if (existsSync29(join48(g.cwd, "tsconfig.json")))
12035
+ if (existsSync29(join50(g.cwd, "tsconfig.json")))
11883
12036
  await runCheck(ctx, `lint:tsc${sfx}`, "npx", ["tsc", "--noEmit", "-p", "."], signal, checks, { ...co, kind: "static" });
11884
- if (ESLINT_CONFIGS.some((f) => existsSync29(join48(g.cwd, f))))
12037
+ if (ESLINT_CONFIGS.some((f) => existsSync29(join50(g.cwd, f))))
11885
12038
  await runCheck(ctx, `lint:eslint${sfx}`, "npx", ["eslint", ...g.rel], signal, checks, { ...co, kind: "static" });
11886
12039
  }
11887
12040
  }
11888
- var CHECK_TIMEOUT_MS = 60000, dedupeTests = (tests) => [...new Map(tests.map((t) => [`${t.runner}:${t.path}`, t])).values()], CODE_EXT, CFG_ALWAYS, CFG_SHARED, CFG_LINE, ESLINT_CONFIGS, verifyStage;
12041
+ var CHECK_TIMEOUT_MS = 60000, dedupeTests = (tests) => [...new Map(tests.map((t) => [`${t.runner}:${t.path}`, t])).values()], CODE_EXT, ESLINT_CONFIGS, verifyStage;
11889
12042
  var init_verify = __esm(() => {
11890
12043
  init_scope();
12044
+ init_runner_config();
11891
12045
  init_assert_delta();
11892
12046
  init_failures();
11893
12047
  init_load_owner();
@@ -11901,10 +12055,8 @@ var init_verify = __esm(() => {
11901
12055
  init_repo_profile();
11902
12056
  init_check_result();
11903
12057
  init_check_result();
12058
+ init_runner_config();
11904
12059
  CODE_EXT = /\.(?:[cm]?[jt]sx?|py|go)$/;
11905
- CFG_ALWAYS = /(^|\/)(conftest\.py|\.?pytest\.(?:ini|toml)|tox\.ini|jest\.config\.[\w.]+|vitest\.config\.[\w.]+|\.mocharc[\w.]*)$/;
11906
- CFG_SHARED = /(^|\/)(setup\.cfg|pyproject\.toml|package\.json)$/;
11907
- CFG_LINE = /^[+-].*(pytest|jest|mocha|vitest|"test"\s*:|addopts|testpaths)/im;
11908
12060
  ESLINT_CONFIGS = [".eslintrc", ".eslintrc.json", ".eslintrc.js", ".eslintrc.cjs", "eslint.config.js", "eslint.config.mjs", "eslint.config.cjs"];
11909
12061
  verifyStage = {
11910
12062
  name: "verify",
@@ -11941,8 +12093,8 @@ var init_verify = __esm(() => {
11941
12093
  const wall = ctx.outputs().wall ?? {};
11942
12094
  const wallPaths = new Set((wall.files ?? []).map((f) => isAbsolute6(f.path) ? relative5(ctx.repoDir, f.path) : f.path));
11943
12095
  const wallTests = map.tests.filter((t) => wallPaths.has(t.path));
11944
- const intake = ctx.outputs().intake, relevant = ctx.tests.impacted(map, namedFiles(intake?.task ?? "", loadRepoMap(intake?.repomap_ref)));
11945
- const tests = dedupeTests([...impacted, ...changedTestFiles, ...wallTests, ...relevant]);
12096
+ const intake = ctx.outputs().intake, relevant2 = ctx.tests.impacted(map, namedFiles(intake?.task ?? "", loadRepoMap(intake?.repomap_ref)));
12097
+ const tests = dedupeTests([...impacted, ...changedTestFiles, ...wallTests, ...relevant2]);
11946
12098
  const scopedOut = scopedOutOf(map);
11947
12099
  if (scopedOut.length)
11948
12100
  ctx.emit("test.scoped_out", "verify", { tests: scopedOut });
@@ -11950,10 +12102,10 @@ var init_verify = __esm(() => {
11950
12102
  if (signal.aborted)
11951
12103
  break;
11952
12104
  const tc = commandFor(t, ctx.repoDir, api);
11953
- await runCheck(ctx, `${t.runner}:${t.path}`, tc.cmd, tc.args, signal, checks, { ...tc.interpreter ? { interpreter: tc.interpreter } : {}, protect: [...wallTests, ...relevant].includes(t), ...tc.pkgRoot !== "." ? { cwd: tc.cwd } : {} });
12105
+ await runCheck(ctx, `${t.runner}:${t.path}`, tc.cmd, tc.args, signal, checks, { ...tc.interpreter ? { interpreter: tc.interpreter } : {}, protect: [...wallTests, ...relevant2].includes(t), ...tc.pkgRoot !== "." ? { cwd: tc.cwd } : {} });
11954
12106
  }
11955
- const targetNames = new Set([...wallTests, ...relevant].map((t) => `${t.runner}:${t.path}`));
11956
- 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);
12107
+ const targetNames = new Set([...wallTests, ...relevant2].map((t) => `${t.runner}:${t.path}`));
12108
+ const preRed = await subtractBase(ctx, api, checks, tests, changed, new Set(wallTests.map((t) => `${t.runner}:${t.path}`)), new Set(relevant2.map((t) => `${t.runner}:${t.path}`)), signal);
11957
12109
  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)) })));
11958
12110
  preRed.names.push(...attr.preExistingChecks);
11959
12111
  preRed.ids.push(...attr.preExistingIds);
@@ -11999,7 +12151,7 @@ var init_verify = __esm(() => {
11999
12151
  }
12000
12152
  };
12001
12153
  const testCounts = {};
12002
- const modifiedRel = relevant.filter((t) => changed.includes(t.path) && inBase(t.path)).flatMap((t) => {
12154
+ const modifiedRel = relevant2.filter((t) => changed.includes(t.path) && inBase(t.path)).flatMap((t) => {
12003
12155
  const k = preRed.cnt[`${t.runner}:${t.path}`];
12004
12156
  if (k)
12005
12157
  testCounts[t.path] = k;
@@ -12013,8 +12165,8 @@ var init_verify = __esm(() => {
12013
12165
  });
12014
12166
 
12015
12167
  // ../../loki-ts/src/project_model/conventions.ts
12016
- import { existsSync as existsSync30, readdirSync as readdirSync13, readFileSync as readFileSync34 } from "fs";
12017
- import { dirname as dirname17, join as join49 } from "path";
12168
+ import { existsSync as existsSync30, readdirSync as readdirSync14, readFileSync as readFileSync36 } from "fs";
12169
+ import { dirname as dirname18, join as join51 } from "path";
12018
12170
  function parseJsonc(text2) {
12019
12171
  let out2 = "", i = 0;
12020
12172
  while (i < text2.length) {
@@ -12049,25 +12201,25 @@ function moduleOf(file, depth = 0) {
12049
12201
  const ext = typeof j.extends === "string" ? j.extends : null;
12050
12202
  if (!ext || !ext.startsWith("."))
12051
12203
  return null;
12052
- const next = join49(dirname17(file), ext.endsWith(".json") ? ext : `${ext}.json`);
12204
+ const next = join51(dirname18(file), ext.endsWith(".json") ? ext : `${ext}.json`);
12053
12205
  return existsSync30(next) ? moduleOf(next, depth + 1) : null;
12054
12206
  }
12055
12207
  function readPackageConventions(pkgDir, runner = null) {
12056
12208
  let names = [];
12057
12209
  try {
12058
- names = readdirSync13(pkgDir).filter((f) => f.endsWith(".json")).sort((x, y) => x.length - y.length || x.localeCompare(y));
12210
+ names = readdirSync14(pkgDir).filter((f) => f.endsWith(".json")).sort((x, y) => x.length - y.length || x.localeCompare(y));
12059
12211
  } catch {
12060
12212
  return null;
12061
12213
  }
12062
12214
  let packageType = null, tsModule = null;
12063
12215
  for (const n2 of names) {
12064
- const j = readJson4(join49(pkgDir, n2));
12216
+ const j = readJson4(join51(pkgDir, n2));
12065
12217
  if (!j)
12066
12218
  continue;
12067
12219
  if (packageType === null && typeof j.type === "string" && typeof j.name === "string")
12068
12220
  packageType = j.type;
12069
12221
  if (tsModule === null && j.compilerOptions !== undefined)
12070
- tsModule = moduleOf(join49(pkgDir, n2));
12222
+ tsModule = moduleOf(join51(pkgDir, n2));
12071
12223
  }
12072
12224
  if (packageType === null && tsModule === null)
12073
12225
  return null;
@@ -12089,7 +12241,7 @@ function conventionViolation(c, fileName, content) {
12089
12241
  }
12090
12242
  var readJson4 = (p) => {
12091
12243
  try {
12092
- const v = parseJsonc(readFileSync34(p, "utf8"));
12244
+ const v = parseJsonc(readFileSync36(p, "utf8"));
12093
12245
  return v && typeof v === "object" && !Array.isArray(v) ? v : null;
12094
12246
  } catch {
12095
12247
  return null;
@@ -12099,15 +12251,15 @@ var init_conventions = () => {};
12099
12251
 
12100
12252
  // ../../loki-ts/src/engine10/stages/wall.ts
12101
12253
  import { spawnSync as spawnSync4 } from "child_process";
12102
- import { existsSync as existsSync31, mkdirSync as mkdirSync18, mkdtempSync as mkdtempSync7, readFileSync as readFileSync35, readdirSync as readdirSync14, realpathSync as realpathSync18, rmSync as rmSync13, writeFileSync as writeFileSync20 } from "fs";
12254
+ import { existsSync as existsSync31, mkdirSync as mkdirSync19, mkdtempSync as mkdtempSync7, readFileSync as readFileSync37, readdirSync as readdirSync15, realpathSync as realpathSync18, rmSync as rmSync13, writeFileSync as writeFileSync21 } from "fs";
12103
12255
  import { tmpdir as tmpdir9 } from "os";
12104
- import { dirname as dirname18, isAbsolute as isAbsolute7, join as join50, relative as relative6 } from "path";
12256
+ import { dirname as dirname19, isAbsolute as isAbsolute7, join as join52, relative as relative6 } from "path";
12105
12257
  function pytestCollectionIsRed(output, repoDir) {
12106
12258
  if (/ModuleNotFoundError/.test(output))
12107
12259
  return false;
12108
12260
  const real2 = (p) => {
12109
12261
  try {
12110
- return realpathSync18(isAbsolute7(p) ? p : join50(repoDir, p));
12262
+ return realpathSync18(isAbsolute7(p) ? p : join52(repoDir, p));
12111
12263
  } catch {
12112
12264
  return null;
12113
12265
  }
@@ -12144,7 +12296,7 @@ function pytestCollectionIsRed(output, repoDir) {
12144
12296
  }
12145
12297
  function moduleUnderRepo(repoDir, name) {
12146
12298
  const rel = name.replace(/\./g, "/");
12147
- return existsSync31(join50(repoDir, `${rel}.py`)) || existsSync31(join50(repoDir, rel, "__init__.py"));
12299
+ return existsSync31(join52(repoDir, `${rel}.py`)) || existsSync31(join52(repoDir, rel, "__init__.py"));
12148
12300
  }
12149
12301
  function pytestExit1IsRed(output) {
12150
12302
  if (/^!+ _pytest\.outcomes\.Exit\b/m.test(output))
@@ -12242,10 +12394,10 @@ ${acceptance.map((a) => `Acceptance: ${a}`).join(`
12242
12394
  function loadTaskText(ctx, fromPrior) {
12243
12395
  if (fromPrior)
12244
12396
  return fromPrior;
12245
- const issueJsonPath = process.env.LOKI_E10_ISSUE_JSON ?? join50(ctx.runDir, "issue.json");
12397
+ const issueJsonPath = process.env.LOKI_E10_ISSUE_JSON ?? join52(ctx.runDir, "issue.json");
12246
12398
  if (existsSync31(issueJsonPath)) {
12247
12399
  try {
12248
- const issue = JSON.parse(readFileSync35(issueJsonPath, "utf8"));
12400
+ const issue = JSON.parse(readFileSync37(issueJsonPath, "utf8"));
12249
12401
  const text2 = [issue.title, issue.body].filter((s) => typeof s === "string" && s.length > 0).join(`
12250
12402
 
12251
12403
  `);
@@ -12257,7 +12409,7 @@ function loadTaskText(ctx, fromPrior) {
12257
12409
  }
12258
12410
  function wallTargetDir(repoDir, existingTests) {
12259
12411
  const first = existingTests[0];
12260
- return first ? join50(repoDir, dirname18(first.path)) : join50(repoDir, "tests");
12412
+ return first ? join52(repoDir, dirname19(first.path)) : join52(repoDir, "tests");
12261
12413
  }
12262
12414
  function guessRunner(fileName, runners) {
12263
12415
  if (fileName.endsWith(".py"))
@@ -12288,11 +12440,11 @@ async function wallAuthor(ctx, signal) {
12288
12440
  const tree = prior.intake?.tree;
12289
12441
  const repomapText = repoMapText(ctx.repoDir, tree, repomapRef, WALL_MAP_MAX_LINES);
12290
12442
  const targetDir = wallTargetDir(ctx.repoDir, existingTests), pkg = loadProjectApi(ctx.repoDir)?.packageOf(`${relative6(ctx.repoDir, targetDir)}/x`);
12291
- const conv2 = readPackageConventions(join50(ctx.repoDir, pkg?.root ?? "."), pkg?.runner ?? null);
12292
- const cwd = mkdtempSync7(join50(tmpdir9(), "loki-e15-wall-"));
12443
+ const conv2 = readPackageConventions(join52(ctx.repoDir, pkg?.root ?? "."), pkg?.runner ?? null);
12444
+ const cwd = mkdtempSync7(join52(tmpdir9(), "loki-e15-wall-"));
12293
12445
  const wm = wallManifestFor(ctx.repoDir, tree, task);
12294
12446
  for (const [n2, c] of [["task.md", task], ["repomap.txt", repomapText], ...wm ? [["wall_manifest.txt", wm.text]] : []])
12295
- writeFileSync20(join50(cwd, n2), c, "utf8");
12447
+ writeFileSync21(join52(cwd, n2), c, "utf8");
12296
12448
  const session = await ctx.sessions.run({
12297
12449
  stage: "wall",
12298
12450
  brief: buildWallBrief(task, repomapText, runners, !!wm, conventionsBrief(conv2), unitSpec()?.acceptance ?? []),
@@ -12307,15 +12459,15 @@ async function wallAuthor(ctx, signal) {
12307
12459
  rmSync13(cwd, { recursive: true, force: true });
12308
12460
  return done({ status: "failed", data: {}, reason: "wall session aborted, killed, or timed out", killed: true });
12309
12461
  }
12310
- const generated = readdirSync14(cwd).filter((f) => f.startsWith(WALL_PREFIX));
12311
- const sealedDir = join50(ctx.runDir, "wall");
12462
+ const generated = readdirSync15(cwd).filter((f) => f.startsWith(WALL_PREFIX));
12463
+ const sealedDir = join52(ctx.runDir, "wall");
12312
12464
  if (generated.length > 0)
12313
- mkdirSync18(sealedDir, { recursive: true });
12465
+ mkdirSync19(sealedDir, { recursive: true });
12314
12466
  const contents = new Map;
12315
12467
  const discarded = [];
12316
12468
  for (const name of generated) {
12317
- const content = readFileSync35(join50(cwd, name), "utf8"), bad = conventionViolation(conv2, name, content);
12318
- writeFileSync20(join50(sealedDir, name), content, "utf8");
12469
+ const content = readFileSync37(join52(cwd, name), "utf8"), bad = conventionViolation(conv2, name, content);
12470
+ writeFileSync21(join52(sealedDir, name), content, "utf8");
12319
12471
  if (bad)
12320
12472
  discarded.push({ file: name, reason: `${bad}; wall test did not compile under the package config` });
12321
12473
  else
@@ -12327,7 +12479,7 @@ async function wallAuthor(ctx, signal) {
12327
12479
  function installWall(ctx, a, baseDir, opts = {}) {
12328
12480
  const { generated, contents, discarded, targetDir, runners } = a;
12329
12481
  if (generated.length > 0)
12330
- mkdirSync18(targetDir, { recursive: true });
12482
+ mkdirSync19(targetDir, { recursive: true });
12331
12483
  const sealedFiles = [];
12332
12484
  const readOnlyFiles = [];
12333
12485
  const wallTests = [];
@@ -12335,8 +12487,8 @@ function installWall(ctx, a, baseDir, opts = {}) {
12335
12487
  const content = contents.get(name);
12336
12488
  if (content === undefined)
12337
12489
  continue;
12338
- const dest = join50(targetDir, name), runner = guessRunner(name, runners);
12339
- writeFileSync20(dest, content, "utf8");
12490
+ const dest = join52(targetDir, name), runner = guessRunner(name, runners);
12491
+ writeFileSync21(dest, content, "utf8");
12340
12492
  sealedFiles.push({ path: dest, sha256: sha2562(content) });
12341
12493
  readOnlyFiles.push({ path: dest, content });
12342
12494
  if (runner)
@@ -12345,7 +12497,7 @@ function installWall(ctx, a, baseDir, opts = {}) {
12345
12497
  ctx.emit("wall.sealed", "wall", { files: sealedFiles, ...a.manifestSha256 ? { manifest_sha256: a.manifestSha256 } : {} });
12346
12498
  const baseRunner = opts.baseRunner ?? new RealBaseTestRunner, baseRun = { pass: 0, fail: 0, not_run: discarded.length }, notRunFiles = [];
12347
12499
  for (const t of wallTests) {
12348
- const r = baseRunner.run(baseDir, [t]), abs = join50(ctx.repoDir, t.path);
12500
+ const r = baseRunner.run(baseDir, [t]), abs = join52(ctx.repoDir, t.path);
12349
12501
  baseRun.pass += r.pass;
12350
12502
  baseRun.fail += r.fail;
12351
12503
  baseRun.not_run += r.not_run ?? 0;
@@ -12397,20 +12549,20 @@ var init_wall = __esm(() => {
12397
12549
  });
12398
12550
 
12399
12551
  // ../../loki-ts/src/e10ext/discard.ts
12400
- import { chmodSync as chmodSync4, closeSync as closeSync8, lstatSync as lstatSync10, mkdirSync as mkdirSync19, openSync as openSync8, readFileSync as readFileSync36, realpathSync as realpathSync19, rmdirSync, unlinkSync as unlinkSync4, writeFileSync as writeFileSync21 } from "fs";
12401
- import { dirname as dirname19, join as join51, relative as relative7, sep as sep11 } from "path";
12552
+ import { chmodSync as chmodSync5, closeSync as closeSync8, lstatSync as lstatSync10, mkdirSync as mkdirSync20, openSync as openSync8, readFileSync as readFileSync38, realpathSync as realpathSync19, rmdirSync, unlinkSync as unlinkSync5, writeFileSync as writeFileSync22 } from "fs";
12553
+ import { dirname as dirname20, join as join53, relative as relative7, sep as sep11 } from "path";
12402
12554
  function safeRestore(repoDir, f, want, mode) {
12403
- const root = realpathSync19(repoDir), fp = join51(root, f), rel = relative7(root, dirname19(fp));
12555
+ const root = realpathSync19(repoDir), fp = join53(root, f), rel = relative7(root, dirname20(fp));
12404
12556
  if (rel.startsWith(".."))
12405
12557
  throw new Error("outside repo");
12406
12558
  let cur = root;
12407
12559
  for (const part of rel === "" ? [] : rel.split(sep11)) {
12408
- cur = join51(cur, part);
12560
+ cur = join53(cur, part);
12409
12561
  let st2;
12410
12562
  try {
12411
12563
  st2 = lstatSync10(cur);
12412
12564
  } catch {
12413
- mkdirSync19(cur);
12565
+ mkdirSync20(cur);
12414
12566
  continue;
12415
12567
  }
12416
12568
  if (!st2.isDirectory())
@@ -12422,23 +12574,23 @@ function safeRestore(repoDir, f, want, mode) {
12422
12574
  } catch {
12423
12575
  st = null;
12424
12576
  }
12425
- if (st?.isFile() && readFileSync36(fp).equals(want)) {
12426
- chmodSync4(fp, mode);
12577
+ if (st?.isFile() && readFileSync38(fp).equals(want)) {
12578
+ chmodSync5(fp, mode);
12427
12579
  return;
12428
12580
  }
12429
12581
  if (st) {
12430
12582
  if (st.isDirectory())
12431
12583
  rmdirSync(fp);
12432
12584
  else
12433
- unlinkSync4(fp);
12585
+ unlinkSync5(fp);
12434
12586
  }
12435
12587
  const fd = openSync8(fp, "wx", mode);
12436
12588
  try {
12437
- writeFileSync21(fd, want);
12589
+ writeFileSync22(fd, want);
12438
12590
  } finally {
12439
12591
  closeSync8(fd);
12440
12592
  }
12441
- chmodSync4(fp, mode);
12593
+ chmodSync5(fp, mode);
12442
12594
  }
12443
12595
  function alreadySatisfied(o) {
12444
12596
  const b = o.wall?.base_run ?? {};
@@ -12460,7 +12612,7 @@ async function discardIfSatisfied(git3, base, o, staged, keep, repoDir) {
12460
12612
  return { status: "failed", data: {}, reason: "already-satisfied discard failed" };
12461
12613
  const notProven = [];
12462
12614
  for (const [f, v] of Object.entries(o.intake?.preexisting_untracked_blobs ?? {})) {
12463
- const fp = join51(repoDir, f);
12615
+ const fp = join53(repoDir, f);
12464
12616
  try {
12465
12617
  if (v.startsWith("!")) {
12466
12618
  const st = lstatSync10(fp);
@@ -12479,7 +12631,7 @@ async function discardIfSatisfied(git3, base, o, staged, keep, repoDir) {
12479
12631
  try {
12480
12632
  let m = 420;
12481
12633
  try {
12482
- const l = lstatSync10(join51(repoDir, f));
12634
+ const l = lstatSync10(join53(repoDir, f));
12483
12635
  if (l.isFile())
12484
12636
  m = l.mode & 511;
12485
12637
  } catch {}
@@ -12512,9 +12664,9 @@ var init_preexisting_dirty = __esm(() => {
12512
12664
  });
12513
12665
 
12514
12666
  // ../../loki-ts/src/e10ext/commit_filter.ts
12515
- import { dirname as dirname20 } from "path";
12667
+ import { dirname as dirname21 } from "path";
12516
12668
  function dropSet(repoDir, staged, preexistingDirty, env = process.env) {
12517
- return staged.concat(untouchedSinceIntake(repoDir, preexistingDirty, env).map((f) => ({ st: "L", f }))).filter(({ st, f }) => f.startsWith(".loki/") || st === "L" || /(^|\/)loki_wall_[^/]*$/.test(f) || st === "A" && !staged.some(({ f: m }) => /(^|\/)(package\.json|pyproject\.toml|requirements\.txt|Cargo\.toml|go\.mod)$/.test(m) && dirname20(m) === dirname20(f)) && /(^|\/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|bun\.lockb?|poetry\.lock|Cargo\.lock|go\.sum)$/.test(f));
12669
+ 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));
12518
12670
  }
12519
12671
  var parseStaged = (out2) => out2.split("\x00").reduce((a, t, i, all) => i % 2 === 0 && t ? [...a, { st: t, f: all[i + 1] }] : a, []);
12520
12672
  var init_commit_filter = __esm(() => {
@@ -12523,7 +12675,7 @@ var init_commit_filter = __esm(() => {
12523
12675
  });
12524
12676
 
12525
12677
  // ../../loki-ts/src/e10ext/scope.ts
12526
- import { basename as basename18, dirname as dirname21 } from "path";
12678
+ import { basename as basename18, dirname as dirname22 } from "path";
12527
12679
  function contractText(o) {
12528
12680
  const c = o.intake?.contract_snapshot?.contract;
12529
12681
  return Array.isArray(c?.criteria) ? c.criteria.map((x) => typeof x?.text === "string" ? x.text : "").join(`
@@ -12537,8 +12689,8 @@ function outsideScope(o, staged) {
12537
12689
  const text2 = `${plan}
12538
12690
  ${typeof o.intake?.task === "string" ? o.intake.task : ""}
12539
12691
  ${contractText(o)}`, pre = o.intake?.preexisting_dirty ?? {};
12540
- const toks = surfaceTokens(text2), plannedDirs = new Set(rel.map((r) => dirname21(r)).filter((d) => d !== "."));
12541
- return staged.filter(({ st, f }) => st !== "A" && !isTestFile(f) && !Object.hasOwn(pre, f) && !rel.includes(f) && !mentions(text2, f) && !mentions(text2, basename18(f)) && !plannedDirs.has(dirname21(f)) && !dirSegs(f).some((d) => toks.has(d))).map(({ f }) => f);
12692
+ const toks = surfaceTokens(text2), plannedDirs = new Set(rel.map((r) => dirname22(r)).filter((d) => d !== "."));
12693
+ return staged.filter(({ st, f }) => st !== "A" && !isTestFile(f) && !Object.hasOwn(pre, f) && !rel.includes(f) && !mentions(text2, f) && !mentions(text2, basename18(f)) && !plannedDirs.has(dirname22(f)) && !dirSegs(f).some((d) => toks.has(d))).map(({ f }) => f);
12542
12694
  }
12543
12695
  function flagOutsideScope(o, staged) {
12544
12696
  const unit = unitFlags(staged, process.env, o.intake?.preexisting_dirty ?? {});
@@ -12552,78 +12704,12 @@ var init_scope2 = __esm(() => {
12552
12704
  STOP = new Set(["the", "and", "for", "with", "that", "this", "all", "any", "src", "from", "into", "each", "across", "apply", "add", "use", "make"]);
12553
12705
  });
12554
12706
 
12555
- // ../../loki-ts/src/util/receipt_signer.ts
12556
- import { createHash as createHash11, randomBytes as randomBytes3, createPrivateKey, createPublicKey as createPublicKey2, generateKeyPairSync, sign } from "crypto";
12557
- import { chmodSync as chmodSync5, linkSync, mkdirSync as mkdirSync20, readFileSync as readFileSync37, statSync as statSync16, unlinkSync as unlinkSync5, writeFileSync as writeFileSync22 } from "fs";
12558
- import { homedir as homedir8 } from "os";
12559
- import { dirname as dirname22, join as join52 } from "path";
12560
- function canonicalJson(x) {
12561
- const walk = (v) => {
12562
- if (Array.isArray(v))
12563
- return `[${v.map(walk).join(",")}]`;
12564
- if (v !== null && typeof v === "object") {
12565
- const o = v;
12566
- return `{${Object.keys(o).filter((k) => o[k] !== undefined).sort().map((k) => `${JSON.stringify(k)}:${walk(o[k])}`).join(",")}}`;
12567
- }
12568
- return JSON.stringify(v ?? null);
12569
- };
12570
- return walk(x).replace(/[\u0080-\uFFFF]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`);
12571
- }
12572
- function loadSigningKey(generate = true) {
12573
- try {
12574
- const inline = process.env["LOKI_RECEIPT_SIGNING_KEY"]?.trim();
12575
- let pem = inline ?? "";
12576
- if (!inline) {
12577
- const given = process.env["LOKI_RECEIPT_SIGNING_KEY_FILE"]?.trim();
12578
- const file = given || join52(process.env["HOME"] || homedir8(), ".loki", "keys", RECEIPT_SIGNER_BASENAME);
12579
- try {
12580
- pem = readFileSync37(file);
12581
- if (!given) {
12582
- for (const [f, m] of [[file, 384], [dirname22(file), 448]])
12583
- if (statSync16(f).mode & 63)
12584
- chmodSync5(f, m);
12585
- }
12586
- } catch (e) {
12587
- if (e.code !== "ENOENT" || !generate)
12588
- return null;
12589
- mkdirSync20(dirname22(dirname22(file)), { recursive: true, mode: 448 });
12590
- mkdirSync20(dirname22(file), { recursive: true, mode: 448 });
12591
- const tmp = `${file}.${randomBytes3(6).toString("hex")}.tmp`;
12592
- writeFileSync22(tmp, generateKeyPairSync("ed25519").privateKey.export({ type: "pkcs8", format: "pem" }), { flag: "wx", mode: 384 });
12593
- try {
12594
- linkSync(tmp, file);
12595
- } catch (l) {
12596
- if (l.code !== "EEXIST")
12597
- throw l;
12598
- } finally {
12599
- unlinkSync5(tmp);
12600
- }
12601
- pem = readFileSync37(file);
12602
- }
12603
- }
12604
- const k = createPrivateKey(pem);
12605
- return k.asymmetricKeyType === "ed25519" ? k : null;
12606
- } catch {
12607
- return null;
12608
- }
12609
- }
12610
- function signReceipt(runId, hash) {
12611
- const key = loadSigningKey();
12612
- if (!key)
12613
- return { jwt: null, kid: null };
12614
- const kid = kidOf2(createPublicKey2(key));
12615
- 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) }))}`;
12616
- return { jwt: `${input}.${b64u(sign(null, Buffer.from(input), key))}`, kid };
12617
- }
12618
- 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());
12619
- var init_receipt_signer = () => {};
12620
-
12621
12707
  // ../../loki-ts/src/features/visual_evidence.ts
12622
12708
  import { spawn as spawn7 } from "child_process";
12623
12709
  import { createHash as createHash12, randomBytes as randomBytes4 } from "crypto";
12624
- import { existsSync as existsSync32, lstatSync as lstatSync11, mkdirSync as mkdirSync21, readdirSync as readdirSync15, readFileSync as readFileSync38, writeFileSync as writeFileSync23 } from "fs";
12710
+ import { existsSync as existsSync32, lstatSync as lstatSync11, mkdirSync as mkdirSync21, readdirSync as readdirSync16, readFileSync as readFileSync39, writeFileSync as writeFileSync23 } from "fs";
12625
12711
  import { createServer } from "net";
12626
- import { dirname as dirname23, isAbsolute as isAbsolute8, join as join53, normalize as normalize2, relative as relative8, sep as sep12 } from "path";
12712
+ import { dirname as dirname23, isAbsolute as isAbsolute8, join as join54, normalize as normalize2, relative as relative8, sep as sep12 } from "path";
12627
12713
  function routeFor(file) {
12628
12714
  let r = file.replace(/^(?:.*?\/)?(?:app|pages|src|public)\//, "").replace(/^(?:routes|pages)\//, "");
12629
12715
  r = r.replace(/\.(?:html|jsx|tsx|vue|svelte)$/, "").replace(/\/?(?:page|index|\+page)$/, "");
@@ -12633,7 +12719,7 @@ function hashScreens(runDir, rels) {
12633
12719
  const out2 = [];
12634
12720
  for (const rel of rels) {
12635
12721
  try {
12636
- out2.push({ path: rel, sha256: sha256File(join53(runDir, rel)) });
12722
+ out2.push({ path: rel, sha256: sha256File(join54(runDir, rel)) });
12637
12723
  } catch {}
12638
12724
  }
12639
12725
  return out2;
@@ -12646,10 +12732,10 @@ function checkScreens(runDir, screens) {
12646
12732
  return "evidence_screens entry is malformed";
12647
12733
  if (isAbsolute8(s.path) || normalize2(s.path).startsWith(".."))
12648
12734
  return `evidence screenshot path escapes the evidence dir: ${s.path}`;
12649
- const file = join53(runDir, s.path);
12735
+ const file = join54(runDir, s.path);
12650
12736
  let cur = runDir;
12651
12737
  for (const seg of normalize2(s.path).split(sep12)) {
12652
- cur = join53(cur, seg);
12738
+ cur = join54(cur, seg);
12653
12739
  if (isSymlink(cur))
12654
12740
  return `evidence screenshot path is a symlink: ${s.path}`;
12655
12741
  }
@@ -12696,11 +12782,11 @@ async function waitUp(url, ms, signal) {
12696
12782
  }
12697
12783
  function openapiPaths(repoDir) {
12698
12784
  for (const f of ["openapi.json", "openapi.yaml", "openapi.yml", "swagger.json"]) {
12699
- const p = join53(repoDir, f);
12785
+ const p = join54(repoDir, f);
12700
12786
  if (!existsSync32(p))
12701
12787
  continue;
12702
12788
  try {
12703
- const txt = readFileSync38(p, "utf8");
12789
+ const txt = readFileSync39(p, "utf8");
12704
12790
  const paths = f.endsWith(".json") ? Object.keys(JSON.parse(txt).paths ?? {}) : [...txt.matchAll(/^ {2}(\/[^\s:]*):\s*$/gm)].map((m) => m[1]);
12705
12791
  return paths.filter((x) => !x.includes("{")).slice(0, 10);
12706
12792
  } catch {
@@ -12714,24 +12800,24 @@ async function recordE2eMedia(repoDir, runDir, relDir, base, routes, ms, signal)
12714
12800
  if (!pw || !pkg)
12715
12801
  return { rels: [], skipped: "playwright e2e video and trace skipped: @playwright/test is not installed in the repo" };
12716
12802
  try {
12717
- const dir = join53(runDir, relDir, "e2e");
12803
+ const dir = join54(runDir, relDir, "e2e");
12718
12804
  mkdirSync21(dir, { recursive: true });
12719
- writeFileSync23(join53(dir, "walk.spec.cjs"), e2eSpecSource(pkg, base, routes));
12720
- writeFileSync23(join53(dir, "playwright.config.cjs"), `module.exports = { testDir: ".", testMatch: "walk.spec.cjs", outputDir: "./out", reporter: "null", use: { video: "on", trace: "on" } };
12805
+ writeFileSync23(join54(dir, "walk.spec.cjs"), e2eSpecSource(pkg, base, routes));
12806
+ writeFileSync23(join54(dir, "playwright.config.cjs"), `module.exports = { testDir: ".", testMatch: "walk.spec.cjs", outputDir: "./out", reporter: "null", use: { video: "on", trace: "on" } };
12721
12807
  `);
12722
- if (!await shoot(pw, ["test", "--config", join53(dir, "playwright.config.cjs")], repoDir, ms, signal))
12808
+ if (!await shoot(pw, ["test", "--config", join54(dir, "playwright.config.cjs")], repoDir, ms, signal))
12723
12809
  return { rels: [], skipped: "playwright e2e video and trace skipped: the run failed or timed out" };
12724
12810
  const rels = [];
12725
12811
  const walk = (d) => {
12726
- for (const e of readdirSync15(d, { withFileTypes: true })) {
12727
- const full = join53(d, e.name);
12812
+ for (const e of readdirSync16(d, { withFileTypes: true })) {
12813
+ const full = join54(d, e.name);
12728
12814
  if (e.isDirectory())
12729
12815
  walk(full);
12730
12816
  else if (e.isFile() && /\.(webm|zip)$/.test(e.name))
12731
- rels.push(join53(relDir, "e2e", relative8(dir, full)));
12817
+ rels.push(join54(relDir, "e2e", relative8(dir, full)));
12732
12818
  }
12733
12819
  };
12734
- walk(join53(dir, "out"));
12820
+ walk(join54(dir, "out"));
12735
12821
  return rels.length > 0 ? { rels, skipped: null } : { rels, skipped: "playwright e2e video and trace skipped: no video or trace was produced" };
12736
12822
  } catch (e) {
12737
12823
  return { rels: [], skipped: `playwright e2e video and trace skipped: ${String(e?.message ?? e).slice(0, 120)}` };
@@ -12791,6 +12877,16 @@ async function stopServer(c, graceMs, signal) {
12791
12877
  for (let i = 0;i < 10 && groupAlive(pid); i++)
12792
12878
  await new Promise((r) => setTimeout(r, 50));
12793
12879
  }
12880
+ function noRootReason(subs, lacking) {
12881
+ const list = (xs) => xs.map((d) => `${d}/`).join(" or ");
12882
+ if (subs.length === 0)
12883
+ return "no package.json";
12884
+ if (lacking.length === subs.length)
12885
+ return `no dev, preview or start script in ${list(lacking)} (no root package.json)`;
12886
+ if (lacking.length === 0)
12887
+ return `no root package.json (${list(subs)} have a dev, preview or start script but no UI boot was resolved)`;
12888
+ return `no root package.json; no dev, preview or start script in ${list(lacking)} (${list(subs.filter((d) => !lacking.includes(d)))} has one)`;
12889
+ }
12794
12890
  async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
12795
12891
  const skip = (why) => ({ screens: [], http: false, skipped: why });
12796
12892
  const signal = opts.signal;
@@ -12800,13 +12896,22 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
12800
12896
  if (!visualEvidenceEnabled(opts.env))
12801
12897
  return skip("LOKI_VISUAL_EVIDENCE is 0");
12802
12898
  const api = loadProjectApi(repoDir), boot = isMultiRoot(api) ? api.uiBoot() : null;
12803
- const appDir = boot ? join53(repoDir, boot.boot.cwd) : repoDir;
12804
- const pkgPath = join53(appDir, "package.json");
12899
+ const appDir = boot ? join54(repoDir, boot.boot.cwd) : repoDir;
12900
+ const pkgPath = join54(appDir, "package.json");
12805
12901
  let script = null;
12806
12902
  if (!boot) {
12807
- if (!existsSync32(pkgPath))
12808
- return skip("no package.json");
12809
- script = pickScript(JSON.parse(readFileSync38(pkgPath, "utf8")));
12903
+ if (!existsSync32(pkgPath)) {
12904
+ const subs = ["backend", "frontend"].filter((d) => existsSync32(join54(repoDir, d, "package.json")));
12905
+ const has = (d) => {
12906
+ try {
12907
+ return pickScript(JSON.parse(readFileSync39(join54(repoDir, d, "package.json"), "utf8"))) !== null;
12908
+ } catch {
12909
+ return false;
12910
+ }
12911
+ };
12912
+ return skip(noRootReason(subs, subs.filter((d) => !has(d))));
12913
+ }
12914
+ script = pickScript(JSON.parse(readFileSync39(pkgPath, "utf8")));
12810
12915
  if (!script)
12811
12916
  return skip("no dev, preview or start script");
12812
12917
  }
@@ -12833,20 +12938,20 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
12833
12938
  }
12834
12939
  if (!await waitUp(base, left(), signal))
12835
12940
  return skip(aborted() ? "aborted" : `${script} server did not answer within ${Math.round(budget / 1000)}s`);
12836
- const evRoot = join53(runDir, "evidence");
12941
+ const evRoot = join54(runDir, "evidence");
12837
12942
  if (isSymlink(evRoot))
12838
12943
  return skip("evidence dir is a symlink");
12839
12944
  mkdirSync21(evRoot, { recursive: true });
12840
12945
  if (pages.length > 0) {
12841
- const rel0 = join53("evidence", randomBytes4(6).toString("hex"));
12842
- mkdirSync21(join53(runDir, rel0));
12946
+ const rel0 = join54("evidence", randomBytes4(6).toString("hex"));
12947
+ mkdirSync21(join54(runDir, rel0));
12843
12948
  const rels = [];
12844
12949
  for (const route of [...new Set(pages.map(routeFor))].slice(0, opts.maxRoutes ?? MAX_ROUTES)) {
12845
12950
  if (aborted() || left() <= 0)
12846
12951
  break;
12847
- const rel = join53(rel0, `${screenName(route)}.png`);
12848
- const ok = await shoot(pw, ["screenshot", `${base}${route}`, join53(runDir, rel)], appDir, left(), signal);
12849
- if (ok && !aborted() && !isSymlink(join53(runDir, rel)) && existsSync32(join53(runDir, rel)))
12952
+ const rel = join54(rel0, `${screenName(route)}.png`);
12953
+ const ok = await shoot(pw, ["screenshot", `${base}${route}`, join54(runDir, rel)], appDir, left(), signal);
12954
+ if (ok && !aborted() && !isSymlink(join54(runDir, rel)) && existsSync32(join54(runDir, rel)))
12850
12955
  rels.push(rel);
12851
12956
  }
12852
12957
  if (aborted())
@@ -12871,9 +12976,9 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
12871
12976
  }
12872
12977
  if (aborted())
12873
12978
  return skip("aborted");
12874
- const hdir = join53(evRoot, randomBytes4(6).toString("hex"));
12979
+ const hdir = join54(evRoot, randomBytes4(6).toString("hex"));
12875
12980
  mkdirSync21(hdir);
12876
- writeFileSync23(join53(hdir, "http.json"), JSON.stringify(rows, null, 2) + `
12981
+ writeFileSync23(join54(hdir, "http.json"), JSON.stringify(rows, null, 2) + `
12877
12982
  `);
12878
12983
  return { screens: [], http: true, skipped: null };
12879
12984
  } catch (e) {
@@ -12898,12 +13003,12 @@ async function sealEvidence(repoDir, runDir, o, notProven, signal, emit) {
12898
13003
  function receiptScreensProblem(receiptPath, receipt) {
12899
13004
  return receipt["evidence_screens"] === undefined ? null : checkScreens(dirname23(receiptPath), receipt["evidence_screens"]);
12900
13005
  }
12901
- var visualEvidenceEnabled = (env = process.env) => env["LOKI_VISUAL_EVIDENCE"] !== "0", PAGE_RE, isPageFile = (p) => PAGE_RE.test(p), screenName = (route) => (route === "/" ? "index" : route.slice(1).replace(/[^A-Za-z0-9._-]+/g, "_")) || "index", sha256File = (p) => createHash12("sha256").update(readFileSync38(p)).digest("hex"), playwrightBin = (repoDir) => {
12902
- const bin = join53(repoDir, "node_modules", ".bin", "playwright");
13006
+ 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) => {
13007
+ const bin = join54(repoDir, "node_modules", ".bin", "playwright");
12903
13008
  return existsSync32(bin) ? bin : null;
12904
13009
  }, playwrightTestPkg = (repoDir) => {
12905
- const d = join53(repoDir, "node_modules", "@playwright", "test");
12906
- return existsSync32(join53(d, "package.json")) ? d : null;
13010
+ const d = join54(repoDir, "node_modules", "@playwright", "test");
13011
+ return existsSync32(join54(d, "package.json")) ? d : null;
12907
13012
  }, e2eSpecSource = (pkgDir, base, routes) => `const { test } = require(${JSON.stringify(pkgDir)});
12908
13013
  test("loki e2e walkthrough", async ({ page }) => {
12909
13014
  for (const r of ${JSON.stringify(routes)}) { await page.goto(${JSON.stringify(base)} + r); await page.waitForLoadState("load"); }
@@ -12934,14 +13039,14 @@ var init_visual_evidence = __esm(() => {
12934
13039
  });
12935
13040
 
12936
13041
  // ../../loki-ts/src/council/role_agents.ts
12937
- import { existsSync as existsSync33, readdirSync as readdirSync16, readFileSync as readFileSync39 } from "fs";
13042
+ import { existsSync as existsSync33, readdirSync as readdirSync17, readFileSync as readFileSync40 } from "fs";
12938
13043
  import { homedir as homedir9 } from "os";
12939
- import { join as join54 } from "path";
13044
+ import { join as join55 } from "path";
12940
13045
  function agentDirs(repoDir, env = process.env) {
12941
- return [env["LOKI_AGENTS_PROJECT_DIR"] || join54(repoDir, ".loki", "agents"), env["LOKI_AGENTS_USER_DIR"] || join54(env["XDG_CONFIG_HOME"] || join54(homedir9(), ".config"), "loki", "agents")];
13046
+ 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")];
12942
13047
  }
12943
13048
  function parseAgent(file, stem2) {
12944
- const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(readFileSync39(file, "utf8"));
13049
+ const m = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(readFileSync40(file, "utf8"));
12945
13050
  if (!m)
12946
13051
  return null;
12947
13052
  const body = m[2].trim();
@@ -12959,14 +13064,14 @@ function loadRoleAgent(repoDir, role, env = process.env) {
12959
13064
  continue;
12960
13065
  let names;
12961
13066
  try {
12962
- names = readdirSync16(d).filter((n2) => n2.endsWith(".md") && !n2.startsWith(".")).sort();
13067
+ names = readdirSync17(d).filter((n2) => n2.endsWith(".md") && !n2.startsWith(".")).sort();
12963
13068
  } catch {
12964
13069
  continue;
12965
13070
  }
12966
13071
  const ordered = [...names.filter((n2) => n2 === `${role}.md`), ...names.filter((n2) => n2 !== `${role}.md`)];
12967
13072
  for (const n2 of ordered) {
12968
13073
  try {
12969
- const a = parseAgent(join54(d, n2), n2.slice(0, -3));
13074
+ const a = parseAgent(join55(d, n2), n2.slice(0, -3));
12970
13075
  if (a && a.role === role)
12971
13076
  return a;
12972
13077
  } catch {}
@@ -12983,8 +13088,8 @@ var init_role_agents = __esm(() => {
12983
13088
  });
12984
13089
 
12985
13090
  // ../../loki-ts/src/engine10/stages/xreview.ts
12986
- import { existsSync as existsSync34, readFileSync as readFileSync40 } from "fs";
12987
- import { join as join55 } from "path";
13091
+ import { existsSync as existsSync34, readFileSync as readFileSync41 } from "fs";
13092
+ import { join as join56 } from "path";
12988
13093
  function minVerdict(verdict, review) {
12989
13094
  const ceiling = review?.level === "block" ? "PARTIAL" : verdict;
12990
13095
  return RANK3[ceiling] < RANK3[verdict] ? ceiling : verdict;
@@ -12997,11 +13102,11 @@ function explicitReview(repoDir, env) {
12997
13102
  if (flag && isOff(ev))
12998
13103
  return "off";
12999
13104
  for (const f of ["loki.yaml", "loki.yml"]) {
13000
- const p = join55(repoDir, f);
13105
+ const p = join56(repoDir, f);
13001
13106
  if (!existsSync34(p))
13002
13107
  continue;
13003
13108
  try {
13004
- const m = /^review:[ \t]*["']?([A-Za-z]+)["']?[ \t]*(?:#.*)?$/m.exec(readFileSync40(p, "utf8"));
13109
+ const m = /^review:[ \t]*["']?([A-Za-z]+)["']?[ \t]*(?:#.*)?$/m.exec(readFileSync41(p, "utf8"));
13005
13110
  const v = asProvider(m?.[1]);
13006
13111
  if (v)
13007
13112
  return v;
@@ -13211,16 +13316,41 @@ function recordRun(env, repoDir, model, verdict, usd, unmetered, wallS, cacheRoo
13211
13316
  return false;
13212
13317
  return appendRunOutcome(repoKey(readOriginUrl(repoDir), repoDir), { shape, executor: /haiku/i.test(model) ? "haiku" : "sonnet", verdict: "pass", owner: null, escalated: false, usd, wallS, wallKind: WALL_KIND }, cacheRoot);
13213
13318
  }
13214
- var NOT_RECORDED = "NOT RECORDED", previewOn = (env) => env["LOKI_COST_PREVIEW"] !== "0";
13319
+ var MIN_RUNS = 3, NOT_RECORDED = "NOT RECORDED", previewOn = (env) => env["LOKI_COST_PREVIEW"] !== "0", ESTIMATE_HELP;
13215
13320
  var init_cost_preview = __esm(() => {
13216
13321
  init_cache();
13322
+ init_session();
13217
13323
  init_history();
13218
13324
  init_engine_origin();
13325
+ ESTIMATE_HELP = `loki estimate - Show what a run is likely to cost
13326
+
13327
+ Usage: loki estimate [--model M] [--provider P] [--json]
13328
+
13329
+ Prints the same estimate line "loki start" prints before a run: the dollar and time
13330
+ range of this repo's prior verified runs of the same project shape. With fewer than
13331
+ ${MIN_RUNS} such runs it prints a rough per-model prior, or NOT AVAILABLE (reason).
13332
+ It never estimates from task text and never prints a number it did not measure.
13333
+
13334
+ Options:
13335
+ --model M Model whose rough prior to use when there is no history (default: the start model)
13336
+ --provider P Provider whose default model is used (default: LOKI_PROVIDER or claude)
13337
+ --json Machine-readable output (the estimate result object)
13338
+ --help, -h Show this help
13339
+
13340
+ Changed: --iterations is removed. The old iteration-based projection (tools/estimate-run.py)
13341
+ is replaced by this single estimator. LOKI_COST_PREVIEW=0 turns the estimate off.
13342
+
13343
+ Examples:
13344
+ loki estimate
13345
+ loki estimate --json
13346
+
13347
+ See also: loki cost --detail (what a run ALREADY spent)
13348
+ `;
13219
13349
  });
13220
13350
 
13221
13351
  // ../../loki-ts/src/features/contract.ts
13222
- import { existsSync as existsSync35, lstatSync as lstatSync12, mkdirSync as mkdirSync22, readFileSync as readFileSync41, rmSync as rmSync14, writeFileSync as writeFileSync24 } from "fs";
13223
- import { dirname as dirname24, join as join56 } from "path";
13352
+ import { existsSync as existsSync35, lstatSync as lstatSync12, mkdirSync as mkdirSync22, readFileSync as readFileSync42, rmSync as rmSync14, writeFileSync as writeFileSync24 } from "fs";
13353
+ import { dirname as dirname24, join as join57 } from "path";
13224
13354
  import { createHash as createHash13 } from "crypto";
13225
13355
  function contractEnabled(env = process.env) {
13226
13356
  return env["LOKI_CONTRACT"] !== "0";
@@ -13252,7 +13382,7 @@ function untracedLines(trace) {
13252
13382
  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)}`);
13253
13383
  }
13254
13384
  function contractPath(repoDir) {
13255
- return join56(repoDir, ".loki", "contract.json");
13385
+ return join57(repoDir, ".loki", "contract.json");
13256
13386
  }
13257
13387
  function readContract(repoDir) {
13258
13388
  const p = contractPath(repoDir);
@@ -13268,7 +13398,7 @@ function readContract(repoDir) {
13268
13398
  return { contract: null, notes: ["contract unreadable: too large"], sha256: null };
13269
13399
  let raw2;
13270
13400
  try {
13271
- raw2 = readFileSync41(p);
13401
+ raw2 = readFileSync42(p);
13272
13402
  } catch {
13273
13403
  return { contract: null, notes: ["contract unreadable: read failed"], sha256: null };
13274
13404
  }
@@ -13337,16 +13467,16 @@ var init_contract = __esm(() => {
13337
13467
  init_safe_git();
13338
13468
  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"]);
13339
13469
  MAX_CONTRACT_BYTES = 1024 * 1024;
13340
- REQ_MAP_REL = join56(".loki", "state", "requirements-map.json");
13470
+ REQ_MAP_REL = join57(".loki", "state", "requirements-map.json");
13341
13471
  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"]);
13342
13472
  });
13343
13473
 
13344
13474
  // ../../loki-ts/src/features/speed/seal_group.ts
13345
13475
  import { createHash as createHash14 } from "crypto";
13346
- import { existsSync as existsSync36, readdirSync as readdirSync17, readFileSync as readFileSync42, statSync as statSync17 } from "fs";
13347
- import { basename as basename19, dirname as dirname25, join as join57 } from "path";
13476
+ import { existsSync as existsSync36, mkdirSync as mkdirSync23, readdirSync as readdirSync18, readFileSync as readFileSync43, renameSync as renameSync9, statSync as statSync17, writeFileSync as writeFileSync25 } from "fs";
13477
+ import { basename as basename19, dirname as dirname25, join as join58 } from "path";
13348
13478
  function sealGroup(runDir, rh) {
13349
- const manifestPath = join57(runDir, "group", "manifest.json");
13479
+ const manifestPath = join58(runDir, "group", "manifest.json");
13350
13480
  if (!existsSync36(manifestPath))
13351
13481
  return { section: undefined, notProven: [], problems: 0, allUnitsPass: true };
13352
13482
  const notProven = [];
@@ -13371,10 +13501,10 @@ function sealGroup(runDir, rh) {
13371
13501
  return fail(`unit ${index2} has an invalid, duplicate or case-colliding id`);
13372
13502
  seen.add(id);
13373
13503
  seenLower.add(id.toLowerCase());
13374
- const dir = join57(unitsDir(runDir), id), rp = join57(dir, "receipt.json"), ep = join57(dir, "events.jsonl");
13504
+ const dir = join58(unitsDir(runDir), id), rp = join58(dir, "receipt.json"), ep = join58(dir, "events.jsonl");
13375
13505
  let bytes;
13376
13506
  try {
13377
- bytes = readFileSync42(rp);
13507
+ bytes = readFileSync43(rp);
13378
13508
  } catch {
13379
13509
  return fail(`unit ${id} sub-receipt missing`);
13380
13510
  }
@@ -13391,7 +13521,7 @@ function sealGroup(runDir, rh) {
13391
13521
  unit_id: id,
13392
13522
  sub_receipt_sha256: sha2(bytes),
13393
13523
  receipt_sha256: sub["receipt_sha256"],
13394
- events_file_sha256: existsSync36(ep) ? sha2(readFileSync42(ep)) : null,
13524
+ events_file_sha256: existsSync36(ep) ? sha2(readFileSync43(ep)) : null,
13395
13525
  verdict,
13396
13526
  goal: text2(u["goal"], 200),
13397
13527
  files: (Array.isArray(u["files"]) ? u["files"] : []).map((f) => text2(f, 200)).filter(Boolean).slice(0, 50),
@@ -13416,7 +13546,7 @@ async function verifyGroup(receiptPath, receipt, rh, verifyOne, deps = {}) {
13416
13546
  const bad = (reason) => ({ verdict: "TAMPERED", reason: `group: ${reason}` });
13417
13547
  const g = receipt["group"];
13418
13548
  if (g === undefined)
13419
- return existsSync36(join57(runDir, "group", "manifest.json")) ? bad("group directory present but the receipt has no group section") : null;
13549
+ return existsSync36(join58(runDir, "group", "manifest.json")) ? bad("group directory present but the receipt has no group section") : null;
13420
13550
  if (!isObj10(g) || !ID_RE.test(String(g["group_id"] ?? "")) || !Array.isArray(g["units"]) || g["units"].length === 0)
13421
13551
  return bad("group section malformed");
13422
13552
  const entries = g["units"];
@@ -13428,20 +13558,20 @@ async function verifyGroup(receiptPath, receipt, rh, verifyOne, deps = {}) {
13428
13558
  return bad("unit directories do not match the receipt (missing or extra unit)");
13429
13559
  let unchecked = null;
13430
13560
  for (let i = 0;i < entries.length; i++) {
13431
- const e = entries[i], id = ids[i], dir = join57(unitsDir(runDir), id), rp = join57(dir, "receipt.json"), ep = join57(dir, "events.jsonl");
13561
+ const e = entries[i], id = ids[i], dir = join58(unitsDir(runDir), id), rp = join58(dir, "receipt.json"), ep = join58(dir, "events.jsonl");
13432
13562
  if (e["index"] !== i)
13433
13563
  return bad(`unit ${id} is out of order (index ${String(e["index"])} at position ${i})`);
13434
13564
  let bytes;
13435
13565
  try {
13436
13566
  if (!statSync17(dir).isDirectory())
13437
13567
  return bad(`unit ${id} is not a directory`);
13438
- bytes = readFileSync42(rp);
13568
+ bytes = readFileSync43(rp);
13439
13569
  } catch {
13440
13570
  return bad(`unit ${id} sub-receipt missing`);
13441
13571
  }
13442
13572
  if (sha2(bytes) !== e["sub_receipt_sha256"])
13443
13573
  return bad(`unit ${id} sub-receipt does not match its recorded hash`);
13444
- const evSha = existsSync36(ep) ? sha2(readFileSync42(ep)) : null;
13574
+ const evSha = existsSync36(ep) ? sha2(readFileSync43(ep)) : null;
13445
13575
  if (evSha !== (e["events_file_sha256"] ?? null))
13446
13576
  return bad(`unit ${id} events.jsonl does not match its recorded hash`);
13447
13577
  const sub = readJson5(rp);
@@ -13461,8 +13591,8 @@ async function verifyGroup(receiptPath, receipt, rh, verifyOne, deps = {}) {
13461
13591
  }
13462
13592
  function compositeVerdict(childVerdicts) {
13463
13593
  const base = childVerdicts.includes("SPEC_CONFLICT") ? "SPEC_CONFLICT" : childVerdicts.length > 0 && childVerdicts.every((v) => v === "ALREADY_SATISFIED") ? "ALREADY_SATISFIED" : "VERIFIED";
13464
- const failed = childVerdicts.filter((v) => v === "FAILED" || !["VERIFIED", "ALREADY_SATISFIED", "PARTIAL", "SPEC_CONFLICT"].includes(v)).length;
13465
- return capGroupVerdict(base, { section: undefined, notProven: [], problems: failed, allUnitsPass: childVerdicts.every((v) => PASSING.has(v)) });
13594
+ const failed2 = childVerdicts.filter((v) => v === "FAILED" || !["VERIFIED", "ALREADY_SATISFIED", "PARTIAL", "SPEC_CONFLICT"].includes(v)).length;
13595
+ return capGroupVerdict(base, { section: undefined, notProven: [], problems: failed2, allUnitsPass: childVerdicts.every((v) => PASSING.has(v)) });
13466
13596
  }
13467
13597
  async function verifyComposite(receiptPath, receipt, rh, verifyOne, deps = {}) {
13468
13598
  const runDir = dirname25(receiptPath);
@@ -13473,13 +13603,13 @@ async function verifyComposite(receiptPath, receipt, rh, verifyOne, deps = {}) {
13473
13603
  return bad("body malformed");
13474
13604
  let ibytes;
13475
13605
  try {
13476
- ibytes = readFileSync42(join57(runDir, "integration.json"));
13606
+ ibytes = readFileSync43(join58(runDir, "integration.json"));
13477
13607
  } catch {
13478
13608
  return bad("integration.json missing");
13479
13609
  }
13480
13610
  if (sha2(ibytes) !== receipt["integration_sha256"])
13481
13611
  return bad("integration.json does not match its recorded hash");
13482
- const integ = readJson5(join57(runDir, "integration.json"));
13612
+ const integ = readJson5(join58(runDir, "integration.json"));
13483
13613
  if (!isObj10(integ) || !isObj10(integ["outcomes"]))
13484
13614
  return bad("integration.json has no outcomes");
13485
13615
  const heads = isObj10(integ["heads"]) ? integ["heads"] : {}, outcomes = integ["outcomes"];
@@ -13497,10 +13627,10 @@ async function verifyComposite(receiptPath, receipt, rh, verifyOne, deps = {}) {
13497
13627
  return bad(`child ${text2(repo, 80) || "?"} has an invalid receipt path`);
13498
13628
  if (outcomes[repo] !== "ok")
13499
13629
  return bad(`child ${text2(repo, 80)} did not finish ok in integration.json`);
13500
- const rp = join57(runDir, rel);
13630
+ const rp = join58(runDir, rel);
13501
13631
  let bytes;
13502
13632
  try {
13503
- bytes = readFileSync42(rp);
13633
+ bytes = readFileSync43(rp);
13504
13634
  } catch {
13505
13635
  return bad(`child ${repo} receipt missing`);
13506
13636
  }
@@ -13535,15 +13665,15 @@ function compositeHash(r) {
13535
13665
  const { composite_sha256: _c, verification: _v, ...body } = r;
13536
13666
  return sha2(canonicalJson(body));
13537
13667
  }
13538
- var ID_RE, PASSING, sha2 = (b) => createHash14("sha256").update(b).digest("hex"), isObj10 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), text2 = (v, cap) => typeof v === "string" ? v.replace(/[\x00-\x1f\x7f]+/g, " ").trim().slice(0, cap) : "", num4 = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : 0, unitsDir = (runDir) => join57(runDir, "group", "units"), readJson5 = (p) => {
13668
+ var ID_RE, PASSING, sha2 = (b) => createHash14("sha256").update(b).digest("hex"), isObj10 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), text2 = (v, cap) => typeof v === "string" ? v.replace(/[\x00-\x1f\x7f]+/g, " ").trim().slice(0, cap) : "", num4 = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : 0, unitsDir = (runDir) => join58(runDir, "group", "units"), readJson5 = (p) => {
13539
13669
  try {
13540
- return JSON.parse(readFileSync42(p, "utf8"));
13670
+ return JSON.parse(readFileSync43(p, "utf8"));
13541
13671
  } catch {
13542
13672
  return;
13543
13673
  }
13544
13674
  }, dirNames = (d) => {
13545
13675
  try {
13546
- return readdirSync17(d).filter((n2) => !n2.startsWith(".")).sort();
13676
+ return readdirSync18(d).filter((n2) => !n2.startsWith(".")).sort();
13547
13677
  } catch {
13548
13678
  return null;
13549
13679
  }
@@ -13555,8 +13685,8 @@ var init_seal_group = __esm(() => {
13555
13685
  });
13556
13686
 
13557
13687
  // ../../loki-ts/src/supply/supply_guard.ts
13558
- import { existsSync as existsSync37, readFileSync as readFileSync43, statSync as statSync18 } from "fs";
13559
- import { basename as basename20, join as join58 } from "path";
13688
+ import { existsSync as existsSync37, readFileSync as readFileSync44, statSync as statSync18 } from "fs";
13689
+ import { basename as basename20, join as join59 } from "path";
13560
13690
  function supplyEnabled(env) {
13561
13691
  return env["LOKI_SUPPLY_GUARD"] !== "0";
13562
13692
  }
@@ -13571,13 +13701,13 @@ function isManifestPath(path) {
13571
13701
  return MANIFESTS.test(basename20(path));
13572
13702
  }
13573
13703
  function readDeclared(repoDir) {
13574
- const p = join58(repoDir, ".loki", DECLARED_FILE);
13704
+ const p = join59(repoDir, ".loki", DECLARED_FILE);
13575
13705
  if (!existsSync37(p))
13576
13706
  return { deps: [], problem: null };
13577
13707
  try {
13578
13708
  if (statSync18(p).size > MAX_FILE_BYTES)
13579
13709
  return { deps: [], problem: "declaration file too large" };
13580
- const j = JSON.parse(readFileSync43(p, "utf8"));
13710
+ const j = JSON.parse(readFileSync44(p, "utf8"));
13581
13711
  if (!Array.isArray(j))
13582
13712
  return { deps: [], problem: "declaration is not a JSON array" };
13583
13713
  const deps = [];
@@ -13597,11 +13727,11 @@ function readDeclared(repoDir) {
13597
13727
  }
13598
13728
  }
13599
13729
  function readAllowlist(repoDir) {
13600
- const p = join58(repoDir, ".loki", "supply-allowlist");
13730
+ const p = join59(repoDir, ".loki", "supply-allowlist");
13601
13731
  if (!existsSync37(p))
13602
13732
  return new Set;
13603
13733
  try {
13604
- return new Set(readFileSync43(p, "utf8").split(`
13734
+ return new Set(readFileSync44(p, "utf8").split(`
13605
13735
  `).map((l) => l.replace(/#.*$/, "").trim()).filter(Boolean));
13606
13736
  } catch {
13607
13737
  return new Set;
@@ -13642,7 +13772,7 @@ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
13642
13772
  if (eco === "npm") {
13643
13773
  if (privateUrlList([env["npm_config_registry"] ?? "", env["NPM_CONFIG_REGISTRY"] ?? ""]))
13644
13774
  return true;
13645
- return files(join58(repoDir, ".npmrc"), home ? join58(home, ".npmrc") : "").some((t) => t.split(`
13775
+ return files(join59(repoDir, ".npmrc"), home ? join59(home, ".npmrc") : "").some((t) => t.split(`
13646
13776
  `).some((l) => {
13647
13777
  const m = /^\s*(?:(@[^:\s]+):)?registry\s*=\s*(\S+)/.exec(l);
13648
13778
  return !!m && privateUrl(m[2]) && (m[1] === undefined || name.startsWith(`${m[1]}/`));
@@ -13651,7 +13781,7 @@ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
13651
13781
  if (eco === "pypi") {
13652
13782
  if (privateUrlList([env["PIP_INDEX_URL"] ?? "", env["PIP_EXTRA_INDEX_URL"] ?? ""]))
13653
13783
  return true;
13654
- const cfg = [env["PIP_CONFIG_FILE"] ?? "", home ? join58(home, ".config", "pip", "pip.conf") : "", home ? join58(home, ".pip", "pip.conf") : "", join58(repoDir, "pip.conf")];
13784
+ const cfg = [env["PIP_CONFIG_FILE"] ?? "", home ? join59(home, ".config", "pip", "pip.conf") : "", home ? join59(home, ".pip", "pip.conf") : "", join59(repoDir, "pip.conf")];
13655
13785
  return files(...cfg).some((t) => t.split(`
13656
13786
  `).some((l) => {
13657
13787
  const m = /^\s*(?:extra-)?index-url\s*[=:]\s*(.+)$/.exec(l);
@@ -13661,7 +13791,7 @@ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
13661
13791
  if (eco === "cargo") {
13662
13792
  if (Object.keys(env).some((k) => /^CARGO_REGISTRIES_.+_INDEX$/.test(k) || /^CARGO_SOURCE_/.test(k)))
13663
13793
  return true;
13664
- 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));
13794
+ return files(join59(repoDir, ".cargo", "config.toml"), join59(repoDir, ".cargo", "config"), home ? join59(home, ".cargo", "config.toml") : "", home ? join59(home, ".cargo", "config") : "").some((t) => /^\s*\[(registries\.|source\.)/m.test(t) || /replace-with\s*=/.test(t));
13665
13795
  }
13666
13796
  if (eco === "go") {
13667
13797
  const gp = goEnv["GOPROXY"] ?? env["GOPROXY"] ?? "";
@@ -13784,7 +13914,7 @@ var MIN_AGE_DAYS = 7, DECLARED_FILE = "supply-declared.json", MAX_CHECKED = 50,
13784
13914
  }
13785
13915
  }, 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) => {
13786
13916
  try {
13787
- return statSync18(p).size <= MAX_FILE_BYTES ? readFileSync43(p, "utf8") : "";
13917
+ return statSync18(p).size <= MAX_FILE_BYTES ? readFileSync44(p, "utf8") : "";
13788
13918
  } catch {
13789
13919
  return "";
13790
13920
  }
@@ -13800,8 +13930,8 @@ var init_supply_guard = __esm(() => {
13800
13930
 
13801
13931
  // ../../loki-ts/src/engine10/stages/seal.ts
13802
13932
  import { createHash as createHash15 } from "crypto";
13803
- import { existsSync as existsSync38, readdirSync as readdirSync18, mkdirSync as mkdirSync23, readFileSync as readFileSync44, writeFileSync as writeFileSync25 } from "fs";
13804
- import { basename as basename21, isAbsolute as isAbsolute9, join as join59, relative as relative9 } from "path";
13933
+ import { existsSync as existsSync38, readdirSync as readdirSync19, mkdirSync as mkdirSync24, readFileSync as readFileSync45, writeFileSync as writeFileSync26 } from "fs";
13934
+ import { basename as basename21, isAbsolute as isAbsolute9, join as join60, relative as relative9 } from "path";
13805
13935
  function sanitizeReason(s) {
13806
13936
  const collapsed = s.replace(/[\x00-\x1f\x7f]+/g, " ").trim();
13807
13937
  const capped = collapsed.length > 500 ? `${collapsed.slice(0, 500)}...` : collapsed;
@@ -13876,7 +14006,7 @@ function renderReceiptMd(r) {
13876
14006
  `);
13877
14007
  }
13878
14008
  var DEEP_NOT_PROVEN, SIGNING_UNAVAILABLE = "receipt signing unavailable (no usable signing key: invalid key or unwritable ~/.loki/keys)", EXCLUDE_LOKI = ":(exclude).loki", sha2562 = (s) => createHash15("sha256").update(s).digest("hex"), str3 = (v) => typeof v === "string" && v !== "" ? v : null, strs2 = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string" && x !== "") : [], receiptRel = (ctx) => {
13879
- const r = relative9(ctx.repoDir, join59(ctx.runDir, "receipt.json"));
14009
+ const r = relative9(ctx.repoDir, join60(ctx.runDir, "receipt.json"));
13880
14010
  return r.startsWith("..") || isAbsolute9(r) ? `.loki/runs/${ctx.runId}/receipt.json` : r;
13881
14011
  }, commitStage, sealStage;
13882
14012
  var init_seal = __esm(() => {
@@ -13979,7 +14109,7 @@ var init_seal = __esm(() => {
13979
14109
  if (wallNotRun > 0) {
13980
14110
  try {
13981
14111
  const kept = new Set((Array.isArray(o.wall?.files) ? o.wall.files : []).map((f) => basename21(String(f.path))));
13982
- for (const n2 of readdirSync18(join59(ctx.runDir, "wall")).sort())
14112
+ for (const n2 of readdirSync19(join60(ctx.runDir, "wall")).sort())
13983
14113
  if (!kept.has(n2))
13984
14114
  notProven.add(`wall test discarded: ${n2} (not_run)`);
13985
14115
  } catch {}
@@ -14040,19 +14170,19 @@ var init_seal = __esm(() => {
14040
14170
  for (const [s, d] of Object.entries(o))
14041
14171
  if (typeof d?.duration_s === "number")
14042
14172
  stages[s] = d.duration_s;
14043
- 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;
14173
+ const T = hooks.time, time = T ? T.build(ctx, stages, T.firstEventMs(join60(ctx.runDir, "events.jsonl"))) : { wall_s: Object.values(stages).reduce((a, b) => a + (b ?? 0), 0), stages }, totalS = T?.reconciled(time) ?? null;
14044
14174
  const iterIds = Object.values(o).flatMap((d) => [...strs2(d?.iteration_ids), ...strs2([d?.iteration_id])]);
14045
14175
  if (iterIds.length === 0)
14046
14176
  notProven.add("cost not measured (no iteration ids recorded)");
14047
14177
  const cost = ctx.cost.read(ctx.repoDir, iterIds);
14048
14178
  if (cost.unmetered)
14049
14179
  notProven.add("cost unmetered (CLI invoker; recorded as 0)");
14050
- const eventsPath = join59(ctx.runDir, "events.jsonl");
14180
+ const eventsPath = join60(ctx.runDir, "events.jsonl");
14051
14181
  const wallFiles = Array.isArray(o.wall?.files) ? o.wall.files : [];
14052
14182
  const wallPassed = typeof o.verify?.wall_passed === "boolean" ? o.verify.wall_passed : null;
14053
14183
  if (wallFiles.length > 0 && wallPassed === null)
14054
14184
  notProven.add("wall result not recorded by verify");
14055
- 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);
14185
+ 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(join60(ctx.repoDir, ".loki"), iterIds).router : undefined), ctx.model);
14056
14186
  if (routeBlock)
14057
14187
  for (const l of routeNotProven(routeBlock))
14058
14188
  notProven.add(l);
@@ -14094,7 +14224,7 @@ var init_seal = __esm(() => {
14094
14224
  provider: ctx.provider,
14095
14225
  model: ctx.model,
14096
14226
  resumed: o.intake?.resumed === true,
14097
- events_sha256: sha2562(existsSync38(eventsPath) ? readFileSync44(eventsPath) : ""),
14227
+ events_sha256: sha2562(existsSync38(eventsPath) ? readFileSync45(eventsPath) : ""),
14098
14228
  ...await sealEvidence(ctx.repoDir, ctx.runDir, o, notProven, signal, ctx.emit),
14099
14229
  log_seal: true,
14100
14230
  ...receiptBlock(process.env, cost.usd, cost.unmetered === true, totalS),
@@ -14114,11 +14244,11 @@ var init_seal = __esm(() => {
14114
14244
  hash = receiptSha256(body);
14115
14245
  }
14116
14246
  const receipt = { ...body, receipt_sha256: hash, verification: { jwt: sig.jwt, kid: sig.kid } };
14117
- mkdirSync23(ctx.runDir, { recursive: true });
14118
- const path = join59(ctx.runDir, "receipt.json");
14119
- writeFileSync25(path, JSON.stringify(receipt, null, 2) + `
14247
+ mkdirSync24(ctx.runDir, { recursive: true });
14248
+ const path = join60(ctx.runDir, "receipt.json");
14249
+ writeFileSync26(path, JSON.stringify(receipt, null, 2) + `
14120
14250
  `);
14121
- writeFileSync25(join59(ctx.runDir, "receipt.md"), renderReceiptMd(receipt));
14251
+ writeFileSync26(join60(ctx.runDir, "receipt.md"), renderReceiptMd(receipt));
14122
14252
  recordRun(process.env, ctx.repoDir, ctx.model, verdict, cost.usd, cost.unmetered === true, totalS);
14123
14253
  const signed = sig.jwt !== null;
14124
14254
  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) } : {} };
@@ -14137,8 +14267,8 @@ var init_seal = __esm(() => {
14137
14267
  });
14138
14268
 
14139
14269
  // ../../loki-ts/src/features/receipt_dsse.ts
14140
- import { createPublicKey as createPublicKey3, sign as sign2, verify as verify2 } from "crypto";
14141
- import { readFileSync as readFileSync45 } from "fs";
14270
+ import { createPublicKey as createPublicKey3, sign as sign2, verify as verify3 } from "crypto";
14271
+ import { readFileSync as readFileSync46 } from "fs";
14142
14272
  function pae(payloadType, body) {
14143
14273
  const t = Buffer.from(payloadType, "utf8");
14144
14274
  return Buffer.concat([Buffer.from(`DSSEv1 ${t.length} `), t, Buffer.from(` ${body.length} `), body]);
@@ -14157,7 +14287,7 @@ function verifyEnvelope(env, pubFor) {
14157
14287
  continue;
14158
14288
  }
14159
14289
  known++;
14160
- if (verify2(null, pae(env.payloadType, body), pub, Buffer.from(s.sig, "base64"))) {
14290
+ if (verify3(null, pae(env.payloadType, body), pub, Buffer.from(s.sig, "base64"))) {
14161
14291
  kid = s.keyid;
14162
14292
  break;
14163
14293
  }
@@ -14215,7 +14345,7 @@ function verifyDsseReceipt(env, d) {
14215
14345
  }
14216
14346
  function runIdGuard(receiptPath, runId) {
14217
14347
  try {
14218
- return envelopeRunIdProblem(JSON.parse(readFileSync45(receiptPath, "utf8")), runId);
14348
+ return envelopeRunIdProblem(JSON.parse(readFileSync46(receiptPath, "utf8")), runId);
14219
14349
  } catch {
14220
14350
  return null;
14221
14351
  }
@@ -14229,16 +14359,16 @@ var init_keys_cmd = __esm(() => {
14229
14359
  });
14230
14360
 
14231
14361
  // ../../loki-ts/src/engine10/verify_cmd.ts
14232
- import { existsSync as existsSync39, readFileSync as readFileSync46, renameSync as renameSync8, statSync as statSync20, writeFileSync as writeFileSync26 } from "fs";
14233
- import { basename as basename22, dirname as dirname27, join as join60 } from "path";
14234
- import { createHash as createHash16, createPublicKey as createPublicKey4, verify as verify3 } from "crypto";
14362
+ import { existsSync as existsSync39, readFileSync as readFileSync47, renameSync as renameSync10, statSync as statSync20, writeFileSync as writeFileSync27 } from "fs";
14363
+ import { basename as basename22, dirname as dirname27, join as join61 } from "path";
14364
+ import { createHash as createHash16, createPublicKey as createPublicKey4, verify as verify4 } from "crypto";
14235
14365
  function pubFor(kid, given) {
14236
14366
  if (given)
14237
14367
  return kidOf2(given) === kid ? given : undefined;
14238
14368
  const active = loadSigningKey(false);
14239
14369
  const pubs = (process.env["LOKI_RECEIPT_RETIRED_PUBKEYS"] ?? "").split(":").map((f) => f.trim()).filter(Boolean).flatMap((f) => {
14240
14370
  try {
14241
- return [createPublicKey4(readFileSync46(f))];
14371
+ return [createPublicKey4(readFileSync47(f))];
14242
14372
  } catch {
14243
14373
  return [];
14244
14374
  }
@@ -14262,7 +14392,7 @@ function checkAttestation(jwt, expectedHash, given) {
14262
14392
  const pub = pubFor(header.kid, given);
14263
14393
  if (!pub)
14264
14394
  return { status: "unchecked", reason: `no key for kid ${String(header.kid)} on this machine (set LOKI_RECEIPT_SIGNING_KEY_FILE or LOKI_RECEIPT_RETIRED_PUBKEYS)` };
14265
- if (!verify3(null, Buffer.from(`${h}.${p}`), pub, Buffer.from(s, "base64url")))
14395
+ if (!verify4(null, Buffer.from(`${h}.${p}`), pub, Buffer.from(s, "base64url")))
14266
14396
  return bad("signature does not verify");
14267
14397
  return payload?.receipt_sha256 === expectedHash ? { status: "verified", reason: null } : bad("attestation binds a different receipt hash");
14268
14398
  }
@@ -14270,17 +14400,17 @@ function checkEventLog(receiptPath, receipt) {
14270
14400
  const bound = receipt["events_sha256"];
14271
14401
  if (typeof bound !== "string" || bound === createHash16("sha256").digest("hex"))
14272
14402
  return null;
14273
- const path = join60(dirname27(receiptPath), "events.jsonl");
14403
+ const path = join61(dirname27(receiptPath), "events.jsonl");
14274
14404
  if (!existsSync39(path))
14275
14405
  return "events.jsonl is missing";
14276
- const raw2 = readFileSync46(path, "utf8"), events2 = readEvents(path), lines = raw2.split(`
14406
+ const raw2 = readFileSync47(path, "utf8"), events2 = readEvents(path), lines2 = raw2.split(`
14277
14407
  `).filter((l) => l.trim() !== "");
14278
- if (events2.length !== lines.length || events2.some((e, i) => e.seq !== i))
14408
+ if (events2.length !== lines2.length || events2.some((e, i) => e.seq !== i))
14279
14409
  return "events.jsonl has a forged, edited or missing line";
14280
14410
  if (events2.some((e) => e.type === "tamper.detected"))
14281
14411
  return "the supervisor detected events.jsonl being modified during the run";
14282
14412
  const h = createHash16("sha256");
14283
- for (const l of lines) {
14413
+ for (const l of lines2) {
14284
14414
  if (h.copy().digest("hex") === bound)
14285
14415
  return null;
14286
14416
  h.update(l + `
@@ -14289,7 +14419,7 @@ function checkEventLog(receiptPath, receipt) {
14289
14419
  return h.digest("hex") === bound ? null : "events.jsonl does not match the hash recorded at seal";
14290
14420
  }
14291
14421
  function checkLogSeal(receiptPath, hash, kid, given) {
14292
- const path = join60(dirname27(receiptPath), "events.jsonl"), events2 = readEvents(path), done = events2.findIndex((e) => e.type === "run.completed");
14422
+ const path = join61(dirname27(receiptPath), "events.jsonl"), events2 = readEvents(path), done = events2.findIndex((e) => e.type === "run.completed");
14293
14423
  if (!events2.some((e) => e.type === "receipt.sealed" && e.data["receipt_sha256"] === hash))
14294
14424
  return { verdict: "TAMPERED", reason: "events.jsonl has no receipt.sealed event for this receipt" };
14295
14425
  if (done < 0)
@@ -14297,12 +14427,12 @@ function checkLogSeal(receiptPath, hash, kid, given) {
14297
14427
  const seal = events2[done + 1], d = seal?.type === "log.sealed" ? seal.data : null;
14298
14428
  if (!d)
14299
14429
  return { verdict: "TAMPERED", reason: "events.jsonl has no signed log.sealed line after run.completed" };
14300
- const lines = readFileSync46(path, "utf8").split(`
14301
- `).filter((l) => l.trim() !== ""), sha3 = createHash16("sha256").update(lines.slice(0, done + 1).join(`
14430
+ const lines2 = readFileSync47(path, "utf8").split(`
14431
+ `).filter((l) => l.trim() !== ""), sha3 = createHash16("sha256").update(lines2.slice(0, done + 1).join(`
14302
14432
  `) + `
14303
14433
  `).digest("hex");
14304
14434
  const pub = d["kid"] === kid ? pubFor(kid, given) : undefined;
14305
- if (!pub || d["events_sha256"] !== sha3 || d["tampered"] !== false || typeof d["sig"] !== "string" || !verify3(null, Buffer.from(`${sha3}:false`), pub, Buffer.from(d["sig"], "base64url")))
14435
+ if (!pub || d["events_sha256"] !== sha3 || d["tampered"] !== false || typeof d["sig"] !== "string" || !verify4(null, Buffer.from(`${sha3}:false`), pub, Buffer.from(d["sig"], "base64url")))
14306
14436
  return { verdict: "TAMPERED", reason: "log.sealed line is invalid, forged, or records a tamper" };
14307
14437
  return null;
14308
14438
  }
@@ -14311,7 +14441,7 @@ async function verifyReceipt(receiptPath, deps = {}) {
14311
14441
  return { verdict: "UNCHECKED", reasons: [`receipt not found: ${receiptPath}`] };
14312
14442
  let receipt;
14313
14443
  try {
14314
- receipt = JSON.parse((deps.read ?? ((p) => readFileSync46(p, "utf8")))(receiptPath));
14444
+ receipt = JSON.parse((deps.read ?? ((p) => readFileSync47(p, "utf8")))(receiptPath));
14315
14445
  } catch {
14316
14446
  return { verdict: "UNCHECKED", reasons: ["receipt.json is not valid JSON"] };
14317
14447
  }
@@ -14321,9 +14451,8 @@ async function verifyReceipt(receiptPath, deps = {}) {
14321
14451
  return verifyCompositeFile(receiptPath, receipt, deps);
14322
14452
  const recorded = receipt["receipt_sha256"];
14323
14453
  const computed = computeReceiptHash(receipt);
14324
- if (typeof recorded !== "string" || recorded !== computed) {
14454
+ if (typeof recorded !== "string" || recorded !== computed)
14325
14455
  return { verdict: "TAMPERED", reasons: [`receipt_sha256 mismatch: recorded ${JSON.stringify(recorded)}, computed ${computed}`] };
14326
- }
14327
14456
  const logProblem = checkEventLog(receiptPath, receipt);
14328
14457
  if (logProblem)
14329
14458
  return { verdict: "TAMPERED", reasons: [logProblem] };
@@ -14383,6 +14512,7 @@ async function verifyCompositeFile(receiptPath, receipt, deps) {
14383
14512
  var computeReceiptHash = (receipt) => receiptSha256(receipt);
14384
14513
  var init_verify_cmd = __esm(() => {
14385
14514
  init_paths();
14515
+ init_receipt_signer();
14386
14516
  init_run_status();
14387
14517
  init_events();
14388
14518
  init_seal();
@@ -14393,8 +14523,8 @@ var init_verify_cmd = __esm(() => {
14393
14523
  });
14394
14524
 
14395
14525
  // src/server/app.ts
14396
- import { existsSync as existsSync41, readFileSync as readFileSync49, statSync as statSync21 } from "fs";
14397
- import { join as join63, resolve as resolve15, sep as sep14 } from "path";
14526
+ import { existsSync as existsSync41, readFileSync as readFileSync50, statSync as statSync21 } from "fs";
14527
+ import { join as join64, resolve as resolve15, sep as sep14 } from "path";
14398
14528
 
14399
14529
  // node_modules/hono/dist/request/constants.js
14400
14530
  var GET_MATCH_RESULT = Symbol();
@@ -20166,6 +20296,9 @@ var SHA = /^[0-9a-f]{40,64}$/;
20166
20296
  var MAX_RECEIPT_BYTES = 1024 * 1024;
20167
20297
  var GIT_TIMEOUT_MS = 5000;
20168
20298
  var cache = new Map;
20299
+ var FAIL_TTL_MS = 60000;
20300
+ var failed = new Map;
20301
+ var diffStatGitRuns = { n: 0 };
20169
20302
  var gitEnv = () => ({ PATH: process.env.PATH ?? "", HOME: process.env.HOME ?? "", LC_ALL: "C", GIT_TERMINAL_PROMPT: "0", GIT_OPTIONAL_LOCKS: "0" });
20170
20303
  function parseNumstat(out) {
20171
20304
  const files = [];
@@ -20223,13 +20356,19 @@ function diffStatFor(db, source, run) {
20223
20356
  const base = typeof r?.base_sha === "string" ? r.base_sha : "", head = typeof r?.head_sha === "string" ? r.head_sha : "";
20224
20357
  if (!SHA.test(base) || !SHA.test(head))
20225
20358
  return null;
20359
+ const failKey = `${key}:${base}:${head}`;
20360
+ const failedAt = failed.get(failKey);
20361
+ if (failedAt !== undefined && Date.now() - failedAt < FAIL_TTL_MS)
20362
+ return null;
20226
20363
  try {
20364
+ diffStatGitRuns.n++;
20227
20365
  const out = execFileSync("git", ["-C", repoReal, "-c", "core.quotePath=false", "diff", "--numstat", "--no-renames", `${base}..${head}`, "--"], { env: gitEnv(), timeout: GIT_TIMEOUT_MS, maxBuffer: 8 * 1024 * 1024, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
20228
20366
  const files = parseNumstat(out);
20229
20367
  const stat = { base, head, files, added: files.reduce((n2, f) => n2 + (f.added ?? 0), 0), removed: files.reduce((n2, f) => n2 + (f.removed ?? 0), 0), source: "git" };
20230
20368
  cache.set(key, stat);
20231
20369
  return stat;
20232
20370
  } catch {
20371
+ failed.set(failKey, Date.now());
20233
20372
  return null;
20234
20373
  }
20235
20374
  }
@@ -20598,10 +20737,10 @@ function stopReason(evs, verdict) {
20598
20737
  return { reason: /[.!?]$/.test(reason) ? reason : `${reason}.`, ownRules: OWN_RULES.test(text2) };
20599
20738
  }
20600
20739
  if (verdict === "FAILED") {
20601
- const failed = [...evs].reverse().find((e) => e.type === "stage.failed");
20602
- const why = typeof failed?.data?.reason === "string" ? oneLine(failed.data.reason, 240) : "";
20603
- if (failed && failed.stage)
20604
- return { reason: `The run failed in the ${failed.stage} stage${why ? `: ${why}` : ""}.`, ownRules: false };
20740
+ const failed2 = [...evs].reverse().find((e) => e.type === "stage.failed");
20741
+ const why = typeof failed2?.data?.reason === "string" ? oneLine(failed2.data.reason, 240) : "";
20742
+ if (failed2 && failed2.stage)
20743
+ return { reason: `The run failed in the ${failed2.stage} stage${why ? `: ${why}` : ""}.`, ownRules: false };
20605
20744
  const bad = evs.filter((e) => e.type === "test.result" && e.data.result === "fail").length;
20606
20745
  return { reason: bad ? `The run failed: ${bad} check${bad === 1 ? "" : "s"} did not pass.` : "The run failed and did not record a reason.", ownRules: false };
20607
20746
  }
@@ -22191,6 +22330,7 @@ var isObj4 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
22191
22330
  var str2 = (v) => typeof v === "string" && v !== "" ? v : null;
22192
22331
  var SAFE_ID = /^[A-Za-z0-9_-]{1,128}$/;
22193
22332
  var MAX_CHECKPOINTS = 50;
22333
+ var ROLLBACK_ALLOW = new Set(["session.json", "dashboard-state.json", "CONTINUITY.md", "autonomy-state.json", "state", "queue"]);
22194
22334
  var validCheckpointId = (id) => SAFE_ID.test(id);
22195
22335
  var storeOf = (repoDir) => join17(repoDir, ".loki", "state", "checkpoints");
22196
22336
  var lokiOf = (repoDir) => join17(repoDir, ".loki");
@@ -22330,16 +22470,33 @@ function rollbackCheckpoint(repoDir, id, now2 = new Date) {
22330
22470
  `);
22331
22471
  let restored = 0;
22332
22472
  const errors = [];
22473
+ const skipped = (src) => src === join17(real2, "state", "checkpoints");
22333
22474
  for (const e of readdirSync4(real2, { withFileTypes: true })) {
22334
22475
  if (e.name === "metadata.json" || e.name === "worktree-snapshot.txt")
22335
22476
  continue;
22336
- const src = join17(real2, e.name);
22477
+ if (!ROLLBACK_ALLOW.has(e.name)) {
22478
+ errors.push(`${e.name}: not in the rollback allowlist, skipped`);
22479
+ continue;
22480
+ }
22481
+ const src = join17(real2, e.name), dst = join17(loki, e.name);
22337
22482
  try {
22338
22483
  if (lstatSync2(src).isSymbolicLink()) {
22339
22484
  errors.push(`${e.name}: symlink skipped`);
22340
22485
  continue;
22341
22486
  }
22342
- cpSync(src, join17(loki, e.name), { recursive: true, filter: (s) => s !== join17(real2, "state", "checkpoints") });
22487
+ if (existsSync8(dst) && lstatSync2(dst).isSymbolicLink()) {
22488
+ errors.push(`${e.name}: destination is a symlink, skipped`);
22489
+ continue;
22490
+ }
22491
+ cpSync(src, dst, { recursive: true, filter: (s) => {
22492
+ if (skipped(s))
22493
+ return false;
22494
+ if (lstatSync2(s).isSymbolicLink()) {
22495
+ errors.push(`${s.slice(real2.length + 1)}: nested symlink skipped`);
22496
+ return false;
22497
+ }
22498
+ return true;
22499
+ } });
22343
22500
  restored++;
22344
22501
  } catch (err) {
22345
22502
  errors.push(`${e.name}: ${err.message}`);
@@ -23561,8 +23718,8 @@ function tasksList(loki, status) {
23561
23718
  const out2 = order2.map((o) => ("ref" in o) ? byId.get(o.ref) : o);
23562
23719
  for (const t of out2) {
23563
23720
  if (t.type === "iteration" && !t.description) {
23564
- const ec = t.exitCode, failed = t._terminal_outcome === "failed";
23565
- const o = Number.isInteger(ec) && ec === 0 && !failed ? "completed cleanly (exit 0)" : Number.isInteger(ec) && ec !== 0 ? `failed (exit ${ec})` : failed ? "failed" : t._terminal_outcome === "completed" ? "completed" : t.status === "done" ? "finished" : null;
23721
+ const ec = t.exitCode, failed2 = t._terminal_outcome === "failed";
23722
+ const o = Number.isInteger(ec) && ec === 0 && !failed2 ? "completed cleanly (exit 0)" : Number.isInteger(ec) && ec !== 0 ? `failed (exit ${ec})` : failed2 ? "failed" : t._terminal_outcome === "completed" ? "completed" : t.status === "done" ? "finished" : null;
23566
23723
  if (o)
23567
23724
  t.description = `Iteration ${o}${t.provider ? `, built by ${t.provider}` : ""}.`;
23568
23725
  }
@@ -24569,7 +24726,7 @@ function mount19(ctx) {
24569
24726
  function computeStats(db, since) {
24570
24727
  const all = db.select().from(runs).all().filter((r) => !since || r.startedAt !== null && r.startedAt >= since);
24571
24728
  const by = {};
24572
- let finished = 0, running = 0, blocked = 0, verified = 0, unchecked = 0, failed = 0, satisfied = 0, other = 0;
24729
+ let finished = 0, running = 0, blocked = 0, verified = 0, unchecked = 0, failed2 = 0, satisfied = 0, other = 0;
24573
24730
  let mUsd = 0, mRuns = 0, pUsd = 0, pRuns = 0;
24574
24731
  for (const r of all) {
24575
24732
  if (r.endedAt)
@@ -24587,7 +24744,7 @@ function computeStats(db, since) {
24587
24744
  else if (verdict === "ALREADY_SATISFIED" || verdict === "ALREADY_SATISFIED (signature not checked)")
24588
24745
  satisfied++;
24589
24746
  else if (verdict === "FAILED" || verdict === "PARTIAL" || verdict === "TAMPERED")
24590
- failed++;
24747
+ failed2++;
24591
24748
  else
24592
24749
  other++;
24593
24750
  }
@@ -24619,8 +24776,8 @@ function computeStats(db, since) {
24619
24776
  runs_running: running,
24620
24777
  by_verdict: by,
24621
24778
  blocked_waiting: blocked,
24622
- verified_rate: verified + unchecked + failed ? verified / (verified + unchecked + failed) : null,
24623
- breakdown: { verified, failed, already_satisfied: satisfied, other },
24779
+ verified_rate: verified + unchecked + failed2 ? verified / (verified + unchecked + failed2) : null,
24780
+ breakdown: { verified, failed: failed2, already_satisfied: satisfied, other },
24624
24781
  verified_unchecked: unchecked,
24625
24782
  keys_configured: pubkeysFromEnv().configured === true,
24626
24783
  ...pubkeysFromEnv().reason ? { keys_reason: pubkeysFromEnv().reason } : {},
@@ -24644,9 +24801,9 @@ function mount20(ctx) {
24644
24801
  }
24645
24802
 
24646
24803
  // src/server/routes/verify.ts
24647
- import { readFileSync as readFileSync47, realpathSync as realpathSync20 } from "fs";
24804
+ import { readFileSync as readFileSync48, realpathSync as realpathSync20 } from "fs";
24648
24805
  import { createPublicKey as createPublicKey5 } from "crypto";
24649
- import { join as join61, sep as sep13 } from "path";
24806
+ import { join as join62, sep as sep13 } from "path";
24650
24807
  init_verify_cmd();
24651
24808
  init_seal();
24652
24809
  init_receipt_dsse();
@@ -24673,11 +24830,11 @@ function mount21(ctx) {
24673
24830
  return done(404, "receipt not available", "not_found");
24674
24831
  let runDir, file;
24675
24832
  try {
24676
- const root = realpathSync20(join61(repo.p, ".loki", "runs"));
24677
- runDir = realpathSync20(join61(root, run2));
24678
- if (runDir !== join61(root, run2))
24833
+ const root = realpathSync20(join62(repo.p, ".loki", "runs"));
24834
+ runDir = realpathSync20(join62(root, run2));
24835
+ if (runDir !== join62(root, run2))
24679
24836
  return done(404, "receipt not found", "not_found");
24680
- file = realpathSync20(join61(runDir, "receipt.json"));
24837
+ file = realpathSync20(join62(runDir, "receipt.json"));
24681
24838
  } catch {
24682
24839
  return done(404, "receipt not found", "not_found");
24683
24840
  }
@@ -24696,7 +24853,7 @@ function mount21(ctx) {
24696
24853
  sha3 = r.receiptSha256 ?? null;
24697
24854
  }
24698
24855
  try {
24699
- outcome = outcomeOf(JSON.parse(readFileSync47(file, "utf8")));
24856
+ outcome = outcomeOf(JSON.parse(readFileSync48(file, "utf8")));
24700
24857
  } catch {
24701
24858
  outcome = "UNREADABLE";
24702
24859
  }
@@ -24758,8 +24915,8 @@ function ttlCache(ttlMs = PROBE_CACHE_MS, now2 = Date.now) {
24758
24915
  }
24759
24916
 
24760
24917
  // src/server/legacy/shim.ts
24761
- import { existsSync as existsSync40, readFileSync as readFileSync48 } from "fs";
24762
- import { join as join62 } from "path";
24918
+ import { existsSync as existsSync40, readFileSync as readFileSync49 } from "fs";
24919
+ import { join as join63 } from "path";
24763
24920
 
24764
24921
  // src/server/legacy/routes.ts
24765
24922
  var LEGACY_ROUTES = [
@@ -25102,11 +25259,12 @@ function metricsMapped(repoDir) {
25102
25259
  // src/server/legacy/routes-control.ts
25103
25260
  function controlMapped(db, repoDir) {
25104
25261
  const loki = () => lokiDirOf(repoDir);
25262
+ const ctl = (action) => (c) => peerIsLoopback(c) && isLoopbackHost(c.req.header("host")) ? runControl(db, repoDir, action, c, "legacy") : c.json({ error: "loopback only" }, 403);
25105
25263
  return {
25106
- "POST /api/control/pause": (c) => runControl(db, repoDir, "pause", c, "legacy"),
25107
- "POST /api/control/resume": (c) => runControl(db, repoDir, "resume", c, "legacy"),
25108
- "POST /api/control/stop": (c) => runControl(db, repoDir, "stop", c, "legacy"),
25109
- "POST /api/council/force-review": (c) => runControl(db, repoDir, "council-review", c, "legacy"),
25264
+ "POST /api/control/pause": ctl("pause"),
25265
+ "POST /api/control/resume": ctl("resume"),
25266
+ "POST /api/control/stop": ctl("stop"),
25267
+ "POST /api/council/force-review": ctl("council-review"),
25110
25268
  "GET /api/council/state": (c) => c.json(councilState(loki())),
25111
25269
  "GET /api/council/verdicts": (c) => {
25112
25270
  const n2 = intQ(c.req.query("limit"), 1000);
@@ -25131,10 +25289,10 @@ var logged = new Set;
25131
25289
  var toHono = (p) => p.replace(/\{([A-Za-z_]+):path\}/g, ":$1{.+}").replace(/\{([A-Za-z_]+)\}/g, ":$1");
25132
25290
  var NOT_SUPPORTED = "not yet supported by the Control Plane";
25133
25291
  var repoVersion = () => {
25134
- for (const f of [join62(import.meta.dir, "../../../../../VERSION")]) {
25292
+ for (const f of [join63(import.meta.dir, "../../../../../VERSION")]) {
25135
25293
  try {
25136
25294
  if (existsSync40(f))
25137
- return readFileSync48(f, "utf8").trim();
25295
+ return readFileSync49(f, "utf8").trim();
25138
25296
  } catch {}
25139
25297
  }
25140
25298
  return "unknown";
@@ -25316,7 +25474,7 @@ function legacyShim(opts) {
25316
25474
 
25317
25475
  // src/server/app.ts
25318
25476
  var MAX_BODY2 = 1e6;
25319
- var defaultUiDir = () => [join63(import.meta.dir, "../../ui/dist"), join63(import.meta.dir, "../ui/dist")].find((d) => existsSync41(join63(d, "index.html")));
25477
+ var defaultUiDir = () => [join64(import.meta.dir, "../../ui/dist"), join64(import.meta.dir, "../ui/dist")].find((d) => existsSync41(join64(d, "index.html")));
25320
25478
  function createApp(opts) {
25321
25479
  const uiDir = opts.uiDir ?? defaultUiDir();
25322
25480
  const { db, sqlite } = openDb(opts.dbPath);
@@ -25345,10 +25503,10 @@ function createApp(opts) {
25345
25503
  await next();
25346
25504
  });
25347
25505
  const readInstalled = () => {
25348
- for (const f of [process.env.LOKI_VERSION_FILE, join63(import.meta.dir, "../../../../VERSION")]) {
25506
+ for (const f of [process.env.LOKI_VERSION_FILE, join64(import.meta.dir, "../../../../VERSION")]) {
25349
25507
  try {
25350
25508
  if (f)
25351
- return readFileSync49(f, "utf8").trim() || "unknown";
25509
+ return readFileSync50(f, "utf8").trim() || "unknown";
25352
25510
  } catch {}
25353
25511
  }
25354
25512
  return "unknown";
@@ -25463,7 +25621,7 @@ function createApp(opts) {
25463
25621
  return new Response(Bun.file(f));
25464
25622
  if (/\.[a-z0-9]+$/i.test(p))
25465
25623
  return c.json({ error: "not found" }, 404);
25466
- return new Response(Bun.file(join63(root, "index.html")));
25624
+ return new Response(Bun.file(join64(root, "index.html")));
25467
25625
  });
25468
25626
  return { app, db, close: () => {
25469
25627
  clearInterval(reconciler);