loki-mode 11.17.39 → 11.17.41

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 (74) hide show
  1. package/SKILL.md +2 -2
  2. package/VERSION +1 -1
  3. package/autonomy/lib/secure-scan.py +51 -1
  4. package/autonomy/loki +46 -36
  5. package/completions/_loki +1 -0
  6. package/completions/loki.bash +1 -1
  7. package/dashboard/__init__.py +1 -1
  8. package/docs/CLI-REFERENCE.md +1 -1
  9. package/docs/INSTALLATION.md +1 -1
  10. package/docs/v10/BOARD.md +26 -24
  11. package/docs/v10/FAILURE-CLASSES.md +7 -0
  12. package/docs/v10/PROGRESS.md +6 -0
  13. package/loki-ts/dist/loki.js +1156 -1119
  14. package/mcp/__init__.py +1 -1
  15. package/package.json +2 -2
  16. package/packages/control-plane/dist/server.js +188 -55
  17. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  18. package/web-app/dist/assets/{AdminPage-sMRXVp8V.js → AdminPage-BSR_64u1.js} +1 -1
  19. package/web-app/dist/assets/{Avatar-sqshsKDj.js → Avatar-CnSNZSx6.js} +1 -1
  20. package/web-app/dist/assets/{Badge-DVLT6AZl.js → Badge-C7p_bqIO.js} +1 -1
  21. package/web-app/dist/assets/{Button-CUGOx2F-.js → Button-5CI0TYxR.js} +1 -1
  22. package/web-app/dist/assets/{CockpitPage-_5XpWSyB.js → CockpitPage-CeiR5rfl.js} +1 -1
  23. package/web-app/dist/assets/{ComparePage-CHybAwF6.js → ComparePage-Cwh3wcqg.js} +1 -1
  24. package/web-app/dist/assets/{ErrorBoundary-yws0dvvJ.js → ErrorBoundary-VZcsEDJl.js} +1 -1
  25. package/web-app/dist/assets/{EvidenceReceiptPanel-DQPXKaYq.js → EvidenceReceiptPanel-Cf5DXTqo.js} +1 -1
  26. package/web-app/dist/assets/{GitHubIssuesPanel-CDnklfFn.js → GitHubIssuesPanel-C8pxgZhD.js} +1 -1
  27. package/web-app/dist/assets/{GitHubPRsPanel-F1H3q6Mg.js → GitHubPRsPanel-Dfrm9QTz.js} +1 -1
  28. package/web-app/dist/assets/{HomePage-Donxu3UG.js → HomePage-Be-Hq5wb.js} +2 -2
  29. package/web-app/dist/assets/{LoginPage-vabZaQ4T.js → LoginPage-DijL2orB.js} +1 -1
  30. package/web-app/dist/assets/{MagicPage-zJiSFKm6.js → MagicPage-x-KpX3Zk.js} +1 -1
  31. package/web-app/dist/assets/{MetricsPage-tW1d9Pc4.js → MetricsPage-uoMG8P0x.js} +1 -1
  32. package/web-app/dist/assets/{NotFoundPage-DfL2kcAp.js → NotFoundPage-DmW2a7pG.js} +1 -1
  33. package/web-app/dist/assets/{ProjectPage-Bnx3Slii.js → ProjectPage-zpARxbll.js} +3 -3
  34. package/web-app/dist/assets/{ProjectsPage-C74jNljb.js → ProjectsPage-5dTAn3K7.js} +1 -1
  35. package/web-app/dist/assets/{SettingsPage-FA9_6XvR.js → SettingsPage-ptKy_Tbu.js} +1 -1
  36. package/web-app/dist/assets/{ShowcasePage-CUYKoPB0.js → ShowcasePage-BkM5b-6b.js} +1 -1
  37. package/web-app/dist/assets/{SystemSettingsPage-ClEk_OL-.js → SystemSettingsPage-BbaZ8aqC.js} +1 -1
  38. package/web-app/dist/assets/{TeamsPage-CZod1nxw.js → TeamsPage-CBgDSDWj.js} +1 -1
  39. package/web-app/dist/assets/{TemplatesPage-ftxcEJ5S.js → TemplatesPage-IdBOifb1.js} +1 -1
  40. package/web-app/dist/assets/{TerminalOutput-C-ztoDne.js → TerminalOutput-iLcaELwj.js} +1 -1
  41. package/web-app/dist/assets/{activity-ClWb6nuh.js → activity-Di09VZ-C.js} +1 -1
  42. package/web-app/dist/assets/{bell-DSdTj9Kf.js → bell-CuHhohwY.js} +1 -1
  43. package/web-app/dist/assets/{bot-DX8ebhTj.js → bot-pGvyFisf.js} +1 -1
  44. package/web-app/dist/assets/{check-6OAuuO_W.js → check-DYPycZns.js} +1 -1
  45. package/web-app/dist/assets/{chevron-left-DTdjxSL_.js → chevron-left-lKRP1pKT.js} +1 -1
  46. package/web-app/dist/assets/{circle-alert-B40DtHik.js → circle-alert-D1rDQ9mD.js} +1 -1
  47. package/web-app/dist/assets/{clock-cVEP2obv.js → clock-BGhPbAAa.js} +1 -1
  48. package/web-app/dist/assets/{cloud-CmG80ODy.js → cloud-WsT8-0Fu.js} +1 -1
  49. package/web-app/dist/assets/{code-xml-uDISZWZx.js → code-xml-DtutBX9b.js} +1 -1
  50. package/web-app/dist/assets/{database-BBjrBzZH.js → database-LiEeNmyC.js} +1 -1
  51. package/web-app/dist/assets/{dollar-sign-QuSiEBvi.js → dollar-sign-adGlfVLa.js} +1 -1
  52. package/web-app/dist/assets/{file-code-corner-DaYWw_54.js → file-code-corner-DY5GkQGM.js} +1 -1
  53. package/web-app/dist/assets/{file-plus-DBrjgfG0.js → file-plus-RLd_hPU8.js} +1 -1
  54. package/web-app/dist/assets/{globe-yLg95rUG.js → globe-CQvcGE8E.js} +1 -1
  55. package/web-app/dist/assets/{hammer-Cm_tQ3f7.js → hammer-BWOWu2Hf.js} +1 -1
  56. package/web-app/dist/assets/{index-WwgJyEgR.js → index-BBV2psih.js} +3 -3
  57. package/web-app/dist/assets/{layers-CVu0QAr_.js → layers-C_cj_ShX.js} +1 -1
  58. package/web-app/dist/assets/{loader-circle-C1ByA4HR.js → loader-circle-BpyfPEFt.js} +1 -1
  59. package/web-app/dist/assets/{lock-COFCj4kU.js → lock-Bivqy2kG.js} +1 -1
  60. package/web-app/dist/assets/{package-DPdWCR4l.js → package-DvDJIgWs.js} +1 -1
  61. package/web-app/dist/assets/{plus-CP2Oh8yP.js → plus-CVjTmPiU.js} +1 -1
  62. package/web-app/dist/assets/{refresh-cw-CR9Wf9cI.js → refresh-cw-DPEeU-0s.js} +1 -1
  63. package/web-app/dist/assets/{rotate-ccw-jJugFDir.js → rotate-ccw-DZX_aED8.js} +1 -1
  64. package/web-app/dist/assets/{scroll-text-BiJUO5k9.js → scroll-text-BBMfK4J7.js} +1 -1
  65. package/web-app/dist/assets/{server-US70f4RI.js → server-Bq18pHWE.js} +1 -1
  66. package/web-app/dist/assets/{shield-alert-C7ig1ziQ.js → shield-alert-Dc5xbnOx.js} +1 -1
  67. package/web-app/dist/assets/{thumbs-up-D3SDwx7o.js → thumbs-up-4nFvjqQ-.js} +1 -1
  68. package/web-app/dist/assets/{trash-2-CikJqAs_.js → trash-2-SjUKL3ek.js} +1 -1
  69. package/web-app/dist/assets/{trending-down-Bcyok37Q.js → trending-down-B7_1Kuct.js} +1 -1
  70. package/web-app/dist/assets/{trending-up-CFJbw392.js → trending-up-DgRWrCNb.js} +1 -1
  71. package/web-app/dist/assets/{upload-BvhLwHkC.js → upload-Cs07lSfb.js} +1 -1
  72. package/web-app/dist/assets/{usePolling-Bck_ydy1.js → usePolling-BAUxt1Nu.js} +1 -1
  73. package/web-app/dist/assets/{user-BpuwYFeB.js → user-DC2T8RYB.js} +1 -1
  74. package/web-app/dist/index.html +1 -1
@@ -135,7 +135,7 @@ var init_events = __esm(() => {
135
135
  });
136
136
 
137
137
  // ../../loki-ts/src/util/redact.ts
138
- var RULES, redactSecrets = (s) => RULES.reduce((a, [re, to]) => a.replace(re, to), s);
138
+ var RULES, QUERY_SEGMENT, SECRET_PARAM, redactQuery = (s) => s.replace(QUERY_SEGMENT, (q) => q.replace(SECRET_PARAM, "$1[REDACTED]")), redactSecrets = (s) => redactQuery(RULES.reduce((a, [re, to]) => a.replace(re, to), s));
139
139
  var init_redact = __esm(() => {
140
140
  RULES = [
141
141
  [/sk-ant-[A-Za-z0-9_-]{20,}/g, "[REDACTED:ANTHROPIC_KEY]"],
@@ -145,11 +145,18 @@ var init_redact = __esm(() => {
145
145
  [/AKIA[0-9A-Z]{16}/g, "[REDACTED:AWS_KEY]"],
146
146
  [/eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g, "[REDACTED:JWT]"],
147
147
  [/AI[a-zA-Z0-9_-]{30,}/g, "[REDACTED:GOOGLE_KEY]"],
148
+ [/glpat-[A-Za-z0-9_-]{20,}/g, "[REDACTED:GITLAB_TOKEN]"],
149
+ [/npm_[A-Za-z0-9]{36}/g, "[REDACTED:NPM_TOKEN]"],
150
+ [/hf_[A-Za-z0-9]{30,}/g, "[REDACTED:HF_TOKEN]"],
151
+ [/[sr]k_live_[A-Za-z0-9]{16,}/g, "[REDACTED:STRIPE_KEY]"],
152
+ [/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?(?:-----END [A-Z ]*PRIVATE KEY-----|$)/g, "[REDACTED:PRIVATE_KEY]"],
148
153
  [/sk-[A-Za-z0-9_-]{20,}/g, "[REDACTED:OPENAI_KEY]"],
149
154
  [/(Bearer\s+)[A-Za-z0-9._~+/=-]{20,}/g, "$1[REDACTED]"],
150
155
  [/(\b[a-z][a-z0-9+.-]*:\/\/)[^\s/?#@]+@/gi, "$1[REDACTED]@"],
151
156
  [/(\bAuthorization\s*[:=]\s*)(?:Basic|Bearer|Token|Digest)?\s*[^\s,;"']+/gi, "$1[REDACTED]"]
152
157
  ];
158
+ QUERY_SEGMENT = /\?[^\s#"'<>]+/g;
159
+ SECRET_PARAM = /([?&](?:access_token|token|api_key|apikey|password|secret|sig)=)[^&\s#"']*/gi;
153
160
  });
154
161
 
155
162
  // ../../loki-ts/src/util/credential_env.ts
@@ -10018,7 +10025,41 @@ function summaryOf(a) {
10018
10025
  }
10019
10026
  function markExecuted(a, executed) {
10020
10027
  const checks_deferred = deferredOf(a.tier, a.checks_selected, executed);
10021
- return { ...a, checks_deferred, summary: summaryOf({ ...a, checks_deferred }) };
10028
+ return { ...a, checks_deferred, summary: summaryOf({ ...a, checks_deferred }) + (a.advisories?.length ? `; advisory: ${a.advisories.join(", ")}` : "") };
10029
+ }
10030
+ function manifestDepsChanged(path, oldText, newText, patch) {
10031
+ if (/(^|\/)package\.json$/.test(path)) {
10032
+ try {
10033
+ const o = oldText.trim() ? JSON.parse(oldText) : {}, n2 = newText.trim() ? JSON.parse(newText) : {};
10034
+ return PKG_DEP_KEYS.some((k) => JSON.stringify(o?.[k] ?? {}) !== JSON.stringify(n2?.[k] ?? {}));
10035
+ } catch {
10036
+ return true;
10037
+ }
10038
+ }
10039
+ const changed = patch.split(`
10040
+ `).filter((l) => /^[+-]/.test(l) && !/^(\+\+\+|---)/.test(l));
10041
+ if (/(^|\/)go\.mod$/.test(path))
10042
+ return changed.some((l) => {
10043
+ const b = l.slice(1).trim();
10044
+ return b !== "" && !b.startsWith("//") && !/^(module|go|toolchain)\b/.test(b);
10045
+ });
10046
+ return changed.some((l) => {
10047
+ const b = l.slice(1).trim();
10048
+ if (/^"[A-Za-z][\w.-]*(\[[\w,.-]+\])?\s*([<>=~!]|;|@|"\s*,?\s*$)/.test(b))
10049
+ return true;
10050
+ const m = /^([A-Za-z][\w.-]*)\s*=\s*("[\^~<>=!*\d]|\{[^}]*version)/.exec(b);
10051
+ return !!m && !PYPROJECT_NONDEP.test(m[1]);
10052
+ });
10053
+ }
10054
+ function manifestsWithoutLock(files) {
10055
+ return files.filter((f) => f.deps && f.status !== "deleted").flatMap((f) => {
10056
+ const pair = MANIFEST_LOCKS.find(([m]) => m.test(f.path));
10057
+ if (!pair)
10058
+ return [];
10059
+ const d = dirOf(f.path);
10060
+ const locked = files.some((g) => pair[1].test(g.path) && (dirOf(g.path) === "" || d === dirOf(g.path) || d.startsWith(dirOf(g.path) + "/")));
10061
+ return locked ? [] : [f.path];
10062
+ });
10022
10063
  }
10023
10064
  function classifyRisk(files, env = process.env) {
10024
10065
  const lines = files.reduce((n2, f) => n2 + f.added + f.deleted, 0);
@@ -10063,7 +10104,8 @@ function classifyRisk(files, env = process.env) {
10063
10104
  ignored = `LOKI_RISK_TIER=${asked} ignored: lowering from ${computed} needs LOKI_RISK_OVERRIDE_REASON`;
10064
10105
  }
10065
10106
  const plan = PLAN[tier], checks_deferred = deferredOf(tier, plan.selected, []);
10066
- const summary = summaryOf({ tier, computed, reasons, ...override ? { override } : {}, checks_deferred });
10107
+ const advisories = manifestsWithoutLock(files).map((p) => `manifest changed without lockfile: ${p}`);
10108
+ const summary = summaryOf({ tier, computed, reasons, ...override ? { override } : {}, checks_deferred }) + (advisories.length ? `; advisory: ${advisories.join(", ")}` : "");
10067
10109
  return {
10068
10110
  version: 1,
10069
10111
  tier,
@@ -10074,6 +10116,7 @@ function classifyRisk(files, env = process.env) {
10074
10116
  checks_deferred,
10075
10117
  ...override ? { override } : {},
10076
10118
  ...ignored ? { override_ignored: ignored } : {},
10119
+ ...advisories.length ? { advisories } : {},
10077
10120
  summary
10078
10121
  };
10079
10122
  }
@@ -10098,7 +10141,7 @@ function diffFiles(repoDir, baseSha) {
10098
10141
  if (f)
10099
10142
  f.status = s?.startsWith("A") ? "added" : s?.startsWith("D") ? "deleted" : "modified";
10100
10143
  }
10101
- return paths.map((path) => {
10144
+ const out2 = paths.map((path) => {
10102
10145
  const f = stat.get(path);
10103
10146
  if (f)
10104
10147
  return f;
@@ -10109,6 +10152,20 @@ function diffFiles(repoDir, baseSha) {
10109
10152
  } catch {}
10110
10153
  return { path, added: n2, deleted: 0, status: "added" };
10111
10154
  });
10155
+ for (const f of out2) {
10156
+ if (f.status === "deleted" || !MANIFEST_LOCKS.some(([m]) => m.test(f.path)))
10157
+ continue;
10158
+ try {
10159
+ const oldText = f.status === "added" ? "" : safeGit(repoDir, ["show", `${baseSha}:${f.path}`]);
10160
+ const newText = readFileSync29(join38(repoDir, f.path), "utf8");
10161
+ const patch = f.status === "added" ? newText.split(`
10162
+ `).map((l) => `+${l}`).join(`
10163
+ `) : safeGit(repoDir, ["diff", "-U0", baseSha, "--", f.path]);
10164
+ if (manifestDepsChanged(f.path, oldText, newText, patch))
10165
+ f.deps = true;
10166
+ } catch {}
10167
+ }
10168
+ return out2;
10112
10169
  }
10113
10170
  function recordRisk(repoDir, a) {
10114
10171
  try {
@@ -10251,7 +10308,7 @@ function classify(f, status, output, repoDir, interpreter) {
10251
10308
  }
10252
10309
  var NO_TESTS_REASON = "no tests executed", GO_EXIT0_REASON = "test count could not be confirmed: go test output is produced by the code under test and cannot confirm execution (a Go exit 0 is never a pass)", UNCONFIRMED_REASON = "test count could not be confirmed", FAIL_EVIDENCE, GO_FAIL_EVIDENCE, UNMEASURED_REASON = "executed count unmeasured (Loki could not parse the runner summary, harness-owned)", stripAnsi = (s) => s.replace(/\u001b\][^\u0007\u001b]*(?:\u0007|\u001b\\)/g, "").replace(/(?:\u001b\[|\u009b)[0-9;?]*[ -\/]*[@-~]/g, "").replace(/\r\n?/g, `
10253
10310
  `), tailLines = (out2) => out2.split(`
10254
- `).filter((x) => x.trim()).slice(-12), GO_PKG_RE, isExecutedProof = (c) => c.result === "pass" && typeof c.n === "number" && c.n > 0, hasExecutedProof = (checks) => checks.some(isExecutedProof), LLM_JUDGES, NON_RUNNER, normPath = (p) => p.replace(/^(?:\.\/)+/, ""), hasExogenousProof = (checks, ctx) => checks.some((c) => isExecutedProof(c) && ((p) => p !== "agent_authored" && p !== "llm_judge")(checkProvenance(c.name ?? "", ctx))), SENSITIVE, API, TEST_CFG, RANK2, FILES_MEDIUM = 4, FILES_HIGH = 15, LINES_MEDIUM = 100, LINES_HIGH = 500, RAN_ALWAYS, PLAN, LOW_SKIPPED, deferredOf = (tier, selected, executed) => (tier === "low" ? LOW_SKIPPED : selected).filter((c) => !RAN_ALWAYS.includes(c) && !executed.includes(c)), EXCERPT_GROUP_CAP = 1500, EXCERPT_TOTAL_CAP = 6144;
10311
+ `).filter((x) => x.trim()).slice(-12), GO_PKG_RE, isExecutedProof = (c) => c.result === "pass" && typeof c.n === "number" && c.n > 0, hasExecutedProof = (checks) => checks.some(isExecutedProof), LLM_JUDGES, NON_RUNNER, normPath = (p) => p.replace(/^(?:\.\/)+/, ""), hasExogenousProof = (checks, ctx) => checks.some((c) => isExecutedProof(c) && ((p) => p !== "agent_authored" && p !== "llm_judge")(checkProvenance(c.name ?? "", ctx))), SENSITIVE, API, TEST_CFG, RANK2, FILES_MEDIUM = 4, FILES_HIGH = 15, LINES_MEDIUM = 100, LINES_HIGH = 500, RAN_ALWAYS, PLAN, LOW_SKIPPED, deferredOf = (tier, selected, executed) => (tier === "low" ? LOW_SKIPPED : selected).filter((c) => !RAN_ALWAYS.includes(c) && !executed.includes(c)), MANIFEST_LOCKS, dirOf = (p) => p.includes("/") ? p.slice(0, p.lastIndexOf("/")) : "", PKG_DEP_KEYS, PYPROJECT_NONDEP, EXCERPT_GROUP_CAP = 1500, EXCERPT_TOTAL_CAP = 6144;
10255
10312
  var init_check_result = __esm(() => {
10256
10313
  init_testmap();
10257
10314
  init_safe_git();
@@ -10281,6 +10338,13 @@ var init_check_result = __esm(() => {
10281
10338
  high: { selected: [...RAN_ALWAYS, "full test command", "full suite", "council", "security scan"] }
10282
10339
  };
10283
10340
  LOW_SKIPPED = ["full test command", "reviewer", "council", "security scan"];
10341
+ MANIFEST_LOCKS = [
10342
+ [/(^|\/)package\.json$/, /(^|\/)(package-lock\.json|npm-shrinkwrap\.json|pnpm-lock\.yaml|yarn\.lock|bun\.lockb?)$/],
10343
+ [/(^|\/)pyproject\.toml$/, /(^|\/)(poetry\.lock|uv\.lock|pdm\.lock|Pipfile\.lock)$/],
10344
+ [/(^|\/)go\.mod$/, /(^|\/)go\.sum$/]
10345
+ ];
10346
+ PKG_DEP_KEYS = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"];
10347
+ PYPROJECT_NONDEP = /^(name|version|description|readme|license|requires-python|python|authors|maintainers|keywords|classifiers|homepage|repository|documentation|packages|include|exclude)$/;
10284
10348
  });
10285
10349
 
10286
10350
  // ../../loki-ts/src/runner/state.ts
@@ -10301,8 +10365,45 @@ var init_state = __esm(() => {
10301
10365
  });
10302
10366
 
10303
10367
  // ../../loki-ts/src/runner/repo_profile.ts
10304
- import { existsSync as existsSync24, readFileSync as readFileSync30, mkdirSync as mkdirSync14, readdirSync as readdirSync14, renameSync as renameSync9, rmSync as rmSync8, writeFileSync as writeFileSync17 } from "fs";
10368
+ import { spawnSync as spawnSync2 } from "child_process";
10369
+ import { existsSync as existsSync24, lstatSync as lstatSync9, readFileSync as readFileSync30, mkdirSync as mkdirSync14, readdirSync as readdirSync14, renameSync as renameSync9, rmSync as rmSync8, writeFileSync as writeFileSync17 } from "fs";
10305
10370
  import { basename as basename12, join as join39, resolve as resolve13, isAbsolute as isAbsolute4 } from "path";
10371
+ function detectFormatters(repoDir) {
10372
+ const out2 = [];
10373
+ const has = (...fs2) => fs2.some((f) => existsSync24(join39(repoDir, f)));
10374
+ const pp = read(join39(repoDir, "pyproject.toml")), pj = read(join39(repoDir, "package.json"));
10375
+ if (/\[tool\.ruff/.test(pp) || has("ruff.toml", ".ruff.toml"))
10376
+ out2.push({ tool: "ruff", argv: ["ruff", "format"], exts: /\.pyi?$/ });
10377
+ let prettierKey = false;
10378
+ try {
10379
+ prettierKey = pj !== "" && "prettier" in JSON.parse(pj);
10380
+ } catch {}
10381
+ const local = join39(repoDir, "node_modules", ".bin", "prettier");
10382
+ if ((prettierKey || readdirSync14(repoDir).some((f) => /^(\.prettierrc(\.[a-z0-9]+)?|prettier\.config\.[cm]?[jt]s)$/.test(f))) && existsSync24(local))
10383
+ out2.push({ tool: "prettier", argv: [local, "--write"], exts: /\.(?:[cm]?[jt]sx?|json|css|scss|md|ya?ml|html)$/ });
10384
+ if (has("go.mod"))
10385
+ out2.push({ tool: "gofmt", argv: ["gofmt", "-w"], exts: /\.go$/ });
10386
+ if (has("rustfmt.toml", ".rustfmt.toml")) {
10387
+ const ed = /^\s*edition\s*=\s*"(\d+)"/m.exec(read(join39(repoDir, "Cargo.toml")))?.[1];
10388
+ out2.push({ tool: "rustfmt", argv: ["rustfmt", ...ed ? ["--edition", ed] : []], exts: /\.rs$/ });
10389
+ }
10390
+ return out2;
10391
+ }
10392
+ function runFormatters(repoDir, files, env) {
10393
+ const fmts = detectFormatters(repoDir);
10394
+ const mine = fmts.length ? files.filter((f) => {
10395
+ try {
10396
+ return lstatSync9(join39(repoDir, f)).isFile();
10397
+ } catch {
10398
+ return false;
10399
+ }
10400
+ }) : [];
10401
+ return fmts.flatMap((fm) => {
10402
+ const own = mine.filter((f) => fm.exts.test(f));
10403
+ const r = own.length ? spawnSync2(fm.argv[0], [...fm.argv.slice(1), ...own.map((f) => `./${f}`)], { cwd: repoDir, env, stdio: "ignore", timeout: 30000 }) : null;
10404
+ return r && !r.error && r.status === 0 ? own : [];
10405
+ });
10406
+ }
10306
10407
  function loadProfile(repoDir) {
10307
10408
  try {
10308
10409
  const p = JSON.parse(readFileSync30(commandProfilePath(repoDir), "utf8"));
@@ -10396,7 +10497,13 @@ async function staticPreExisting(tool, prefix, files, io) {
10396
10497
  }
10397
10498
  return attributeStatic(tool, head.out, baseOut, 1).preExisting;
10398
10499
  }
10399
- var commandProfilePath = (repoDir) => join39(repoDir, ".loki", "state", "repo-profile.json"), STATIC_DIAG, STATIC_NOISE, STATIC_SUMMARY;
10500
+ var commandProfilePath = (repoDir) => join39(repoDir, ".loki", "state", "repo-profile.json"), read = (p) => {
10501
+ try {
10502
+ return readFileSync30(p, "utf8");
10503
+ } catch {
10504
+ return "";
10505
+ }
10506
+ }, STATIC_DIAG, STATIC_NOISE, STATIC_SUMMARY;
10400
10507
  var init_repo_profile = __esm(() => {
10401
10508
  init_failures();
10402
10509
  init_check_result();
@@ -10438,7 +10545,7 @@ var init_context = __esm(() => {
10438
10545
  });
10439
10546
 
10440
10547
  // ../../loki-ts/src/util/steer.ts
10441
- import { appendFileSync as appendFileSync2, closeSync as closeSync8, constants as constants2, fstatSync as fstatSync6, readdirSync as readdirSync15, lstatSync as lstatSync9, mkdirSync as mkdirSync15, linkSync as linkSync2, openSync as openSync8, readFileSync as readFileSync31, readSync as readSync7, renameSync as renameSync10, statSync as statSync15, lutimesSync, rmSync as rmSync9, unlinkSync as unlinkSync5, writeFileSync as writeFileSync18, existsSync as existsSync25 } from "fs";
10548
+ import { appendFileSync as appendFileSync2, closeSync as closeSync8, constants as constants2, fstatSync as fstatSync6, readdirSync as readdirSync15, lstatSync as lstatSync10, mkdirSync as mkdirSync15, linkSync as linkSync2, openSync as openSync8, readFileSync as readFileSync31, readSync as readSync7, renameSync as renameSync10, statSync as statSync15, lutimesSync, rmSync as rmSync9, unlinkSync as unlinkSync5, writeFileSync as writeFileSync18, existsSync as existsSync25 } from "fs";
10442
10549
  import { createHash as createHash9, randomBytes as randomBytes4 } from "crypto";
10443
10550
  import { basename as basename13, join as join40 } from "path";
10444
10551
  function archiveTo(logs, prefix, src, link = linkSync2, onLinked) {
@@ -10465,7 +10572,7 @@ function archiveTo(logs, prefix, src, link = linkSync2, onLinked) {
10465
10572
  }
10466
10573
  }
10467
10574
  function orphanAlreadyArchived(logs, claim) {
10468
- const c = lstatSync9(claim);
10575
+ const c = lstatSync10(claim);
10469
10576
  if (!c.isFile())
10470
10577
  return false;
10471
10578
  for (const a of readdirSync15(logs)) {
@@ -10567,7 +10674,7 @@ function consumeSteer(repoDir, env = process.env, now2 = () => new Date, sink, h
10567
10674
  hooks2?.beforeRestore?.();
10568
10675
  let restored = false;
10569
10676
  try {
10570
- if (lstatSync9(claimed).isDirectory())
10677
+ if (lstatSync10(claimed).isDirectory())
10571
10678
  renameSync10(claimed, f);
10572
10679
  else
10573
10680
  (hooks2?.link ?? linkSync2)(claimed, f);
@@ -10576,7 +10683,7 @@ function consumeSteer(repoDir, env = process.env, now2 = () => new Date, sink, h
10576
10683
  if (!restored)
10577
10684
  return reject("NOTFILE", "not a regular file");
10578
10685
  try {
10579
- if (!lstatSync9(claimed, { throwIfNoEntry: false })?.isDirectory())
10686
+ if (!lstatSync10(claimed, { throwIfNoEntry: false })?.isDirectory())
10580
10687
  unlinkSync5(claimed);
10581
10688
  } catch {}
10582
10689
  claimed = "";
@@ -10586,7 +10693,7 @@ function consumeSteer(repoDir, env = process.env, now2 = () => new Date, sink, h
10586
10693
  try {
10587
10694
  fd = openSync8(claimed, constants2.O_RDONLY | constants2.O_NOFOLLOW | constants2.O_NONBLOCK);
10588
10695
  } catch (e) {
10589
- const l = lstatSync9(claimed, { throwIfNoEntry: false });
10696
+ const l = lstatSync10(claimed, { throwIfNoEntry: false });
10590
10697
  if (!l)
10591
10698
  throw e;
10592
10699
  if (l.isSymbolicLink() || e.code === "ELOOP") {
@@ -10641,7 +10748,7 @@ function consumeSteer(repoDir, env = process.env, now2 = () => new Date, sink, h
10641
10748
  }
10642
10749
  } else
10643
10750
  try {
10644
- if (lstatSync9(f, { throwIfNoEntry: false }))
10751
+ if (lstatSync10(f, { throwIfNoEntry: false }))
10645
10752
  unapplied("logs dir unwritable or file unreadable");
10646
10753
  } catch {}
10647
10754
  return null;
@@ -10991,7 +11098,7 @@ var init_shell = __esm(() => {
10991
11098
 
10992
11099
  // ../../loki-ts/src/util/python.ts
10993
11100
  import { accessSync, constants as constants3, existsSync as existsSync27, mkdtempSync as mkdtempSync4, readFileSync as readFileSync33, realpathSync as realpathSync18, rmSync as rmSync11, statSync as statSync16 } from "fs";
10994
- import { spawnSync as spawnSync2 } from "child_process";
11101
+ import { spawnSync as spawnSync3 } from "child_process";
10995
11102
  import { tmpdir as tmpdir5 } from "os";
10996
11103
  async function findPython3() {
10997
11104
  if (_pythonCache !== undefined)
@@ -11028,7 +11135,7 @@ function pySignatures(src) {
11028
11135
  const py = resolvePython3();
11029
11136
  if (!py)
11030
11137
  return [];
11031
- const r = spawnSync2(py, ["-I", "-S", "-c", PY_SCRIPT], {
11138
+ const r = spawnSync3(py, ["-I", "-S", "-c", PY_SCRIPT], {
11032
11139
  input: src.replace(/\r\n?/g, `
11033
11140
  `),
11034
11141
  cwd: tmpdir5(),
@@ -11248,14 +11355,14 @@ function importsNamed(path, raw2, stems, importStems = stems, hits = () => false
11248
11355
  for (const m of py.matchAll(/(?:^|:)[ \t\f]*import[ \t\f]+([^\n#;]+?)[ \t\f]*(?:#.*)?$/gm))
11249
11356
  specs.push(...names(m[1]));
11250
11357
  }
11251
- const dir = dirOf(path);
11358
+ const dir = dirOf2(path);
11252
11359
  if (specs.some((s) => s.trim().startsWith(".") && hits(resolveRel(dir, s.trim()))))
11253
11360
  return true;
11254
11361
  for (const py of views)
11255
11362
  for (const m of py.matchAll(/(?:^|:)[ \t\f]*from[ \t\f]+(\.+)([\w.]*?)[ \t\f]*\bimport\b[ \t\f]*(?:\(([^)]*)\)|([^\n]*))/gm)) {
11256
11363
  let base = dir;
11257
11364
  for (let i = 1;i < m[1].length; i++)
11258
- base = dirOf(base);
11365
+ base = dirOf2(base);
11259
11366
  const r = resolveRel(base, (m[2] ?? "").replace(/\./g, "/"));
11260
11367
  if (hits(r) || names(m[3] ?? m[4] ?? "").some((n2) => hits(resolveRel(r, n2))))
11261
11368
  return true;
@@ -11293,13 +11400,13 @@ function buildWallManifest(files, taskModules, alsoNamed = []) {
11293
11400
  const s = stemsOfTarget(m);
11294
11401
  return s.length > 1 ? s.slice(1) : s;
11295
11402
  }));
11296
- const info = excl.map((m) => ({ noext: m.replace(/\.[^./]*$/, "").toLowerCase(), dir: dirOf(m).toLowerCase(), mod: !!dirOf(m) && ["index", "__init__", "mod", "main"].includes(stemOf(m).toLowerCase()), src: !TEST_FILE.test(m) }));
11403
+ const info = excl.map((m) => ({ noext: m.replace(/\.[^./]*$/, "").toLowerCase(), dir: dirOf2(m).toLowerCase(), mod: !!dirOf2(m) && ["index", "__init__", "mod", "main"].includes(stemOf(m).toLowerCase()), src: !TEST_FILE.test(m) }));
11297
11404
  const hits = (r) => {
11298
11405
  const low = r.toLowerCase().replace(/\.(?:[cm]?[jt]sx?|py)$/, "");
11299
11406
  return [low, low.replace(/\/(?:index|__init__|mod|main)$/, "")].some((v) => info.some((t) => v === t.noext || t.mod && v === t.dir || v === "" || t.noext.startsWith(`${v}/`)));
11300
11407
  };
11301
11408
  const inTargetArea = (p) => {
11302
- const d = dirOf(p).toLowerCase();
11409
+ const d = dirOf2(p).toLowerCase();
11303
11410
  return info.some((t) => t.src && (d === t.dir || t.mod && d.startsWith(`${t.dir}/`)));
11304
11411
  };
11305
11412
  const backstop = [...stems].filter((s) => !GENERIC_STEMS.includes(s));
@@ -11321,7 +11428,7 @@ function buildWallManifest(files, taskModules, alsoNamed = []) {
11321
11428
  var MANIFEST_MAX_LINES = 400, MAX_EXAMPLES = 2, EXAMPLE_LINES = 40, MAX_LAYOUT = 60, TEST_PATH, TEST_FILE, EXAMPLE_EXT, baseOf = (p) => p.split("/").pop() ?? p, normStem = (s) => s.toLowerCase().replace(/[._-]+/g, ".").replace(/^\.|\.$/g, ""), GENERIC_STEMS, mentionsStem = (content, stems) => {
11322
11429
  const c = content.toLowerCase().replace(/[._-]+/g, ".");
11323
11430
  return stems.some((s) => new RegExp(`(?<![a-z0-9])${s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![a-z0-9])`).test(c));
11324
- }, dirOf = (p) => p.includes("/") ? p.slice(0, p.lastIndexOf("/")) : "", resolveRel = (dir, spec) => {
11431
+ }, dirOf2 = (p) => p.includes("/") ? p.slice(0, p.lastIndexOf("/")) : "", resolveRel = (dir, spec) => {
11325
11432
  const out2 = dir ? dir.split("/") : [];
11326
11433
  for (const seg of spec.split("/")) {
11327
11434
  if (seg === "" || seg === ".")
@@ -12125,6 +12232,21 @@ out("value-change" if ok and items else "weakened", items if ok else [])
12125
12232
  `;
12126
12233
  });
12127
12234
 
12235
+ // ../../loki-ts/src/e10ext/select.ts
12236
+ function refName(t) {
12237
+ return `${t.runner}:${t.path}`;
12238
+ }
12239
+ function failedFirst(tests, prior) {
12240
+ const red = new Set((prior ?? []).filter((c) => c.result === "fail" && typeof c.name === "string").map((c) => c.name));
12241
+ if (red.size === 0)
12242
+ return tests;
12243
+ return [...tests.filter((t) => red.has(refName(t))), ...tests.filter((t) => !red.has(refName(t)))];
12244
+ }
12245
+ var PYTEST_COLLECTION_EXITS;
12246
+ var init_select = __esm(() => {
12247
+ PYTEST_COLLECTION_EXITS = new Set([2, 3, 4, 5]);
12248
+ });
12249
+
12128
12250
  // ../../loki-ts/src/runner/runner_errors.ts
12129
12251
  function hasRealTestFailure(out2) {
12130
12252
  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);
@@ -12164,7 +12286,7 @@ var init_runner_errors = __esm(() => {
12164
12286
  });
12165
12287
 
12166
12288
  // ../../loki-ts/src/runner/load_owner.ts
12167
- import { spawnSync as spawnSync3 } from "child_process";
12289
+ import { spawnSync as spawnSync4 } from "child_process";
12168
12290
  import { mkdtempSync as mkdtempSync6, realpathSync as realpathSync19, rmSync as rmSync14 } from "fs";
12169
12291
  import { tmpdir as tmpdir8 } from "os";
12170
12292
  import { basename as basename18, extname as extname2, join as join46 } from "path";
@@ -12209,7 +12331,7 @@ function sameLoadError(head, base, headRoots, baseRoots) {
12209
12331
  function killTree(pid) {
12210
12332
  const all = [pid];
12211
12333
  for (let k = 0;k < all.length; k++) {
12212
- const kids = spawnSync3("pgrep", ["-P", String(all[k])], { encoding: "utf8", env: process.env }).stdout.split(/\s+/).filter(Boolean).map(Number);
12334
+ const kids = spawnSync4("pgrep", ["-P", String(all[k])], { encoding: "utf8", env: process.env }).stdout.split(/\s+/).filter(Boolean).map(Number);
12213
12335
  all.push(...kids.filter((x) => Number.isInteger(x) && !all.includes(x)));
12214
12336
  }
12215
12337
  try {
@@ -12357,7 +12479,7 @@ var init_wall_owned = __esm(() => {
12357
12479
  });
12358
12480
 
12359
12481
  // ../../loki-ts/src/util/app_probe.ts
12360
- import { spawnSync as spawnSync4 } from "child_process";
12482
+ import { spawnSync as spawnSync5 } from "child_process";
12361
12483
  import { existsSync as existsSync29, mkdirSync as mkdirSync18, readFileSync as readFileSync37, renameSync as renameSync11, writeFileSync as writeFileSync21 } from "fs";
12362
12484
  import { join as join48 } from "path";
12363
12485
  function readJson4(p) {
@@ -12372,7 +12494,7 @@ function stopApp(repoDir, opts = {}) {
12372
12494
  const runner = opts.runnerPath ?? join48(REPO_ROOT, "autonomy", "app-runner.sh");
12373
12495
  if (!existsSync29(runner) || !existsSync29(join48(repoDir, ".loki", "app-runner", "app.pid")))
12374
12496
  return;
12375
- spawnSync4("bash", ["-c", STOP, "app-probe", repoDir, runner], { cwd: repoDir, env: plainTestEnv(), timeout: opts.timeoutMs ?? 60000, killSignal: "SIGKILL", stdio: "ignore" });
12497
+ spawnSync5("bash", ["-c", STOP, "app-probe", repoDir, runner], { cwd: repoDir, env: plainTestEnv(), timeout: opts.timeoutMs ?? 60000, killSignal: "SIGKILL", stdio: "ignore" });
12376
12498
  }
12377
12499
  async function appProbe(repoDir, lokiDir2, opts = {}) {
12378
12500
  const timeoutMs = opts.timeoutMs ?? 60000, runner = opts.runnerPath ?? join48(REPO_ROOT, "autonomy", "app-runner.sh");
@@ -12380,7 +12502,7 @@ async function appProbe(repoDir, lokiDir2, opts = {}) {
12380
12502
  const t0 = Date.now();
12381
12503
  const mk2 = (name, result, reason) => ({ name, cmd: "autonomy/app-runner.sh", result, duration_s: (Date.now() - t0) / 1000, reason });
12382
12504
  const sh = (script) => {
12383
- const r = spawnSync4("bash", ["-c", script, "app-probe", repoDir, runner], { cwd: repoDir, env: { ...plainTestEnv(), ...opts.env ?? {} }, encoding: "utf8", timeout: timeoutMs, killSignal: "SIGKILL", stdio: ["ignore", "pipe", "ignore"] });
12505
+ const r = spawnSync5("bash", ["-c", script, "app-probe", repoDir, runner], { cwd: repoDir, env: { ...plainTestEnv(), ...opts.env ?? {} }, encoding: "utf8", timeout: timeoutMs, killSignal: "SIGKILL", stdio: ["ignore", "pipe", "ignore"] });
12384
12506
  return { out: r.stdout ?? "", status: r.error ? null : r.status };
12385
12507
  };
12386
12508
  let pid = null, url = null;
@@ -12425,7 +12547,7 @@ async function functionalVerify(opts, url, dir, lokiDir2, timeoutMs) {
12425
12547
  return res("not_run", "python3 or functional-verify.py unavailable");
12426
12548
  const specFile = join48(dir, "spec.txt");
12427
12549
  writeFileSync21(specFile, opts.specText ?? "");
12428
- const r = spawnSync4(py, ["-I", script, specFile, url], { env: plainTestEnv(), encoding: "utf8", timeout: timeoutMs, killSignal: "SIGKILL", stdio: ["ignore", "pipe", "ignore"] });
12550
+ const r = spawnSync5(py, ["-I", script, specFile, url], { env: plainTestEnv(), encoding: "utf8", timeout: timeoutMs, killSignal: "SIGKILL", stdio: ["ignore", "pipe", "ignore"] });
12429
12551
  let out2 = null;
12430
12552
  try {
12431
12553
  const v = JSON.parse(r.stdout ?? "");
@@ -12497,13 +12619,18 @@ async function runSecureScan(targetDir, opts = {}) {
12497
12619
  const findings = obj.findings;
12498
12620
  if (res.exitCode === 1 !== findings.length > 0)
12499
12621
  return fail(`secure-scan exit ${res.exitCode} disagrees with ${findings.length} findings`);
12622
+ const summary = obj.summary && typeof obj.summary === "object" ? obj.summary : undefined;
12623
+ const filesScanned = typeof summary?.["files_scanned"] === "number" ? summary["files_scanned"] : undefined;
12624
+ if (filesScanned === 0 && findings.length === 0)
12625
+ return { ok: false, findings: [], error: "secure-scan scanned 0 files (not_run)", filesScanned: 0, notRun: true };
12626
+ const meta = filesScanned === undefined ? {} : { filesScanned };
12500
12627
  if (opts.secretsEverywhere || opts.diffBase === false)
12501
- return { ok: true, findings };
12628
+ return { ok: true, findings, ...meta };
12502
12629
  const added = await scanAddedLines(targetDir, { ...opts, scriptPath: script, timeoutMs });
12503
12630
  if (!added.ok)
12504
12631
  return added;
12505
12632
  const seen = new Set(findings.map((f) => `${f.file}|${f.line}`));
12506
- return { ok: true, findings: [...findings, ...added.findings.filter((f) => !seen.has(`${f.file}|${f.line}`))] };
12633
+ return { ok: true, findings: [...findings, ...added.findings.filter((f) => !seen.has(`${f.file}|${f.line}`))], ...meta };
12507
12634
  }
12508
12635
  if (res.exitCode !== 0 && res.exitCode !== 1 && res.exitCode !== 2 && elapsed >= timeoutMs) {
12509
12636
  return fail(`secure-scan timed out after ${timeoutMs}ms`);
@@ -12811,7 +12938,7 @@ var init_route_block = __esm(() => {
12811
12938
  // ../../loki-ts/src/features/visual_evidence.ts
12812
12939
  import { spawn as spawn7 } from "child_process";
12813
12940
  import { createHash as createHash13, randomBytes as randomBytes5 } from "crypto";
12814
- import { existsSync as existsSync31, lstatSync as lstatSync10, mkdirSync as mkdirSync20, readdirSync as readdirSync16, readFileSync as readFileSync39, writeFileSync as writeFileSync23 } from "fs";
12941
+ import { existsSync as existsSync31, lstatSync as lstatSync11, mkdirSync as mkdirSync20, readdirSync as readdirSync16, readFileSync as readFileSync39, writeFileSync as writeFileSync23 } from "fs";
12815
12942
  import { createServer } from "net";
12816
12943
  import { dirname as dirname17, isAbsolute as isAbsolute8, join as join50, normalize as normalize3, relative as relative6, sep as sep12 } from "path";
12817
12944
  function routeFor(file) {
@@ -13123,13 +13250,13 @@ test("loki e2e walkthrough", async ({ page }) => {
13123
13250
  });
13124
13251
  `, DEFAULT_BUDGET_MS = 25000, MAX_ROUTES = 5, isSymlink = (p) => {
13125
13252
  try {
13126
- return lstatSync10(p).isSymbolicLink();
13253
+ return lstatSync11(p).isSymbolicLink();
13127
13254
  } catch {
13128
13255
  return false;
13129
13256
  }
13130
13257
  }, isRegularFile = (p) => {
13131
13258
  try {
13132
- return lstatSync10(p).isFile();
13259
+ return lstatSync11(p).isFile();
13133
13260
  } catch {
13134
13261
  return false;
13135
13262
  }
@@ -13240,12 +13367,6 @@ var init_pr_lessons = __esm(() => {
13240
13367
  KINDS = new Set(["pr", "receipt", "ticket", "rejected"]);
13241
13368
  });
13242
13369
 
13243
- // ../../loki-ts/src/e10ext/select.ts
13244
- var PYTEST_COLLECTION_EXITS;
13245
- var init_select = __esm(() => {
13246
- PYTEST_COLLECTION_EXITS = new Set([2, 3, 4, 5]);
13247
- });
13248
-
13249
13370
  // ../../loki-ts/src/e10ext/treeswap.ts
13250
13371
  var init_treeswap = __esm(() => {
13251
13372
  init_safe_git();
@@ -13402,12 +13523,12 @@ var init_providers = __esm(() => {
13402
13523
  });
13403
13524
 
13404
13525
  // ../../loki-ts/src/runner/router/route_record.ts
13405
- import { existsSync as existsSync34, lstatSync as lstatSync11, mkdirSync as mkdirSync22, readFileSync as readFileSync42, writeFileSync as writeFileSync25 } from "fs";
13526
+ import { existsSync as existsSync34, lstatSync as lstatSync12, mkdirSync as mkdirSync22, readFileSync as readFileSync42, writeFileSync as writeFileSync25 } from "fs";
13406
13527
  import { join as join53 } from "path";
13407
13528
  function loadRouteRecord(runDir) {
13408
13529
  try {
13409
13530
  const p = join53(runDir, ROUTE_RECORD_FILE);
13410
- if (!existsSync34(p) || !lstatSync11(p).isFile())
13531
+ if (!existsSync34(p) || !lstatSync12(p).isFile())
13411
13532
  return;
13412
13533
  const v = JSON.parse(readFileSync42(p, "utf8"));
13413
13534
  return typeof v === "object" && v !== null && !Array.isArray(v) ? v : undefined;
@@ -13592,7 +13713,7 @@ __export(exports_deep, {
13592
13713
  DEFAULT_SECRET_SCAN_SH: () => DEFAULT_SECRET_SCAN_SH,
13593
13714
  DEFAULT_PUSH_SH: () => DEFAULT_PUSH_SH2
13594
13715
  });
13595
- import { copyFileSync as copyFileSync3, existsSync as existsSync35, lstatSync as lstatSync12, mkdirSync as mkdirSync23, mkdtempSync as mkdtempSync9, rmSync as rmSync17, writeFileSync as writeFileSync26 } from "fs";
13716
+ import { copyFileSync as copyFileSync3, existsSync as existsSync35, lstatSync as lstatSync13, mkdirSync as mkdirSync23, mkdtempSync as mkdtempSync9, rmSync as rmSync17, writeFileSync as writeFileSync26 } from "fs";
13596
13717
  import { tmpdir as tmpdir10 } from "os";
13597
13718
  import { dirname as dirname20, join as join55 } from "path";
13598
13719
  function sessionCouncil(sessions) {
@@ -13714,7 +13835,7 @@ async function secureScanChanged(repoDir, changed, opts) {
13714
13835
  const dir = mkdtempSync9(join55(tmpdir10(), "loki-deep-secure-"));
13715
13836
  try {
13716
13837
  for (const f of changed)
13717
- if (existsSync35(join55(repoDir, f)) && lstatSync12(join55(repoDir, f)).isFile()) {
13838
+ if (existsSync35(join55(repoDir, f)) && lstatSync13(join55(repoDir, f)).isFile()) {
13718
13839
  mkdirSync23(dirname20(join55(dir, f)), { recursive: true });
13719
13840
  copyFileSync3(join55(repoDir, f), join55(dir, f));
13720
13841
  }
@@ -14091,6 +14212,7 @@ var init_verify = __esm(() => {
14091
14212
  init_runner_config();
14092
14213
  init_assert_delta();
14093
14214
  init_failures();
14215
+ init_select();
14094
14216
  init_load_owner();
14095
14217
  init_sizing();
14096
14218
  init_testmap();
@@ -14143,7 +14265,7 @@ var init_verify = __esm(() => {
14143
14265
  const wallPaths = new Set((wall.files ?? []).map((f) => isAbsolute9(f.path) ? relative7(ctx.repoDir, f.path) : f.path));
14144
14266
  const wallTests = map.tests.filter((t) => wallPaths.has(t.path));
14145
14267
  const intake = ctx.outputs().intake, relevant2 = ctx.tests.impacted(map, namedFiles(intake?.task ?? "", loadRepoMap(intake?.repomap_ref)));
14146
- const tests = dedupeTests([...impacted, ...changedTestFiles, ...wallTests, ...relevant2]);
14268
+ const tests = failedFirst(dedupeTests([...impacted, ...changedTestFiles, ...wallTests, ...relevant2]), ctx.outputs().verify?.checks);
14147
14269
  const scopedOut = scopedOutOf(map);
14148
14270
  if (scopedOut.length)
14149
14271
  ctx.emit("test.scoped_out", "verify", { tests: scopedOut });
@@ -14331,7 +14453,7 @@ var readJson5 = (p) => {
14331
14453
  var init_conventions = () => {};
14332
14454
 
14333
14455
  // ../../loki-ts/src/engine10/stages/wall.ts
14334
- import { spawnSync as spawnSync5 } from "child_process";
14456
+ import { spawnSync as spawnSync6 } from "child_process";
14335
14457
  import { existsSync as existsSync38, mkdirSync as mkdirSync24, mkdtempSync as mkdtempSync11, readFileSync as readFileSync44, readdirSync as readdirSync18, rmSync as rmSync19, writeFileSync as writeFileSync27 } from "fs";
14336
14458
  import { tmpdir as tmpdir12 } from "os";
14337
14459
  import { dirname as dirname23, join as join58, relative as relative8 } from "path";
@@ -14351,7 +14473,7 @@ class RealBaseTestRunner {
14351
14473
  const api = this.api === undefined ? loadProjectApi(repoDir) : this.api;
14352
14474
  for (const f of files) {
14353
14475
  const { cmd, args, interpreter, cwd } = commandFor(f, repoDir, api);
14354
- const r = spawnSync5(cmd, f.runner === "pytest" ? [...args, "-rfE"] : args, { cwd, encoding: "utf8", timeout: Math.max(1000, this.timeoutMs), env: plainTestEnv() });
14476
+ const r = spawnSync6(cmd, f.runner === "pytest" ? [...args, "-rfE"] : args, { cwd, encoding: "utf8", timeout: Math.max(1000, this.timeoutMs), env: plainTestEnv() });
14355
14477
  const status = r.error ? null : r.status;
14356
14478
  const result = classify(f, status, stripAnsi(`${r.stdout ?? ""}
14357
14479
  ${r.stderr ?? ""}`), repoDir, interpreter);
@@ -14573,7 +14695,7 @@ var init_wall = __esm(() => {
14573
14695
  });
14574
14696
 
14575
14697
  // ../../loki-ts/src/e10ext/discard.ts
14576
- import { chmodSync as chmodSync5, closeSync as closeSync9, lstatSync as lstatSync13, mkdirSync as mkdirSync25, openSync as openSync9, readFileSync as readFileSync45, realpathSync as realpathSync23, rmdirSync, unlinkSync as unlinkSync6, writeFileSync as writeFileSync28 } from "fs";
14698
+ import { chmodSync as chmodSync5, closeSync as closeSync9, lstatSync as lstatSync14, mkdirSync as mkdirSync25, openSync as openSync9, readFileSync as readFileSync45, realpathSync as realpathSync23, rmdirSync, unlinkSync as unlinkSync6, writeFileSync as writeFileSync28 } from "fs";
14577
14699
  import { dirname as dirname24, join as join59, relative as relative9, sep as sep13 } from "path";
14578
14700
  function safeRestore(repoDir, f, want, mode) {
14579
14701
  const root = realpathSync23(repoDir), fp = join59(root, f), rel = relative9(root, dirname24(fp));
@@ -14584,7 +14706,7 @@ function safeRestore(repoDir, f, want, mode) {
14584
14706
  cur = join59(cur, part);
14585
14707
  let st2;
14586
14708
  try {
14587
- st2 = lstatSync13(cur);
14709
+ st2 = lstatSync14(cur);
14588
14710
  } catch {
14589
14711
  mkdirSync25(cur);
14590
14712
  continue;
@@ -14594,7 +14716,7 @@ function safeRestore(repoDir, f, want, mode) {
14594
14716
  }
14595
14717
  let st;
14596
14718
  try {
14597
- st = lstatSync13(fp);
14719
+ st = lstatSync14(fp);
14598
14720
  } catch {
14599
14721
  st = null;
14600
14722
  }
@@ -14639,7 +14761,7 @@ async function discardIfSatisfied(git4, base, o, staged, keep, repoDir) {
14639
14761
  const fp = join59(repoDir, f);
14640
14762
  try {
14641
14763
  if (v.startsWith("!")) {
14642
- const st = lstatSync13(fp);
14764
+ const st = lstatSync14(fp);
14643
14765
  if (`!${st.size}:${st.mtimeMs}:${st.ctimeMs}` !== v)
14644
14766
  throw new Error("changed, not snapshotted");
14645
14767
  continue;
@@ -14655,7 +14777,7 @@ async function discardIfSatisfied(git4, base, o, staged, keep, repoDir) {
14655
14777
  try {
14656
14778
  let m = 420;
14657
14779
  try {
14658
- const l = lstatSync13(join59(repoDir, f));
14780
+ const l = lstatSync14(join59(repoDir, f));
14659
14781
  if (l.isFile())
14660
14782
  m = l.mode & 511;
14661
14783
  } catch {}
@@ -14692,9 +14814,10 @@ import { dirname as dirname25 } from "path";
14692
14814
  function dropSet(repoDir, staged, preexistingDirty, env = process.env) {
14693
14815
  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) && dirname25(m) === dirname25(f)) && /(^|\/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|bun\.lockb?|poetry\.lock|Cargo\.lock|go\.sum)$/.test(f));
14694
14816
  }
14695
- var parseStaged = (out2) => out2.split("\x00").reduce((a, t, i, all) => i % 2 === 0 && t ? [...a, { st: t, f: all[i + 1] }] : a, []);
14817
+ var parseStaged = (out2) => out2.split("\x00").reduce((a, t, i, all) => i % 2 === 0 && t ? [...a, { st: t, f: all[i + 1] }] : a, []), formatChanged = (repoDir, staged, dropped2, env = process.env) => runFormatters(repoDir, staged.filter(({ st, f }) => (st === "A" || st === "M") && !dropped2.has(f) && !f.startsWith(".loki/")).map(({ f }) => f), tokenFreeEnv(env));
14696
14818
  var init_commit_filter = __esm(() => {
14697
14819
  init_preexisting_dirty();
14820
+ init_repo_profile();
14698
14821
  init_safe_git();
14699
14822
  });
14700
14823
 
@@ -15053,7 +15176,7 @@ See also: loki cost --detail (what a run ALREADY spent)
15053
15176
  });
15054
15177
 
15055
15178
  // ../../loki-ts/src/features/contract.ts
15056
- import { existsSync as existsSync42, lstatSync as lstatSync14, mkdirSync as mkdirSync28, readFileSync as readFileSync49, rmSync as rmSync20, writeFileSync as writeFileSync30 } from "fs";
15179
+ import { existsSync as existsSync42, lstatSync as lstatSync15, mkdirSync as mkdirSync28, readFileSync as readFileSync49, rmSync as rmSync20, writeFileSync as writeFileSync30 } from "fs";
15057
15180
  import { dirname as dirname27, join as join64 } from "path";
15058
15181
  import { createHash as createHash15 } from "crypto";
15059
15182
  function contractEnabled(env = process.env) {
@@ -15092,7 +15215,7 @@ function readContract(repoDir) {
15092
15215
  const p = contractPath(repoDir);
15093
15216
  let st;
15094
15217
  try {
15095
- st = lstatSync14(p);
15218
+ st = lstatSync15(p);
15096
15219
  } catch {
15097
15220
  return { contract: null, notes: [], sha256: null };
15098
15221
  }
@@ -15137,7 +15260,7 @@ function sealContract(repoDir, body, rawDiff, checks, env = process.env, snap) {
15137
15260
  const live2 = readContract(repoDir);
15138
15261
  let exists2 = true;
15139
15262
  try {
15140
- lstatSync14(contractPath(repoDir));
15263
+ lstatSync15(contractPath(repoDir));
15141
15264
  } catch {
15142
15265
  exists2 = false;
15143
15266
  }
@@ -15692,7 +15815,10 @@ var init_seal = __esm(() => {
15692
15815
  return sat;
15693
15816
  if (drop.length > 0 && (await git4(ctx, ["--literal-pathspecs", "reset", "-q", ctx.baseSha, "--", ...drop.map(({ f }) => f)])).code !== 0)
15694
15817
  return { status: "failed", data: {}, reason: "git reset failed" };
15695
- const dropped2 = new Set(drop.map(({ f }) => f)), notes = flagOutsideScope(ctx.outputs(), staged.filter(({ f }) => !dropped2.has(f)));
15818
+ const dropped2 = new Set(drop.map(({ f }) => f)), fmt = formatChanged(ctx.repoDir, staged, dropped2);
15819
+ if (fmt.length > 0)
15820
+ await git4(ctx, ["--literal-pathspecs", "add", "--", ...fmt], { repoDrivers: true });
15821
+ const notes = flagOutsideScope(ctx.outputs(), staged.filter(({ f }) => !dropped2.has(f)));
15696
15822
  if ((await git4(ctx, ["diff", "--cached", "--quiet"])).code === 0)
15697
15823
  return { status: "completed", data: { committed: false, scope_notes: notes } };
15698
15824
  const title = (str3(ctx.outputs().intake?.title) ?? `run ${ctx.runId}`).split(`
@@ -16052,6 +16178,11 @@ async function verifyComposite(receiptPath, receipt, rh, verifyOne, deps = {}) {
16052
16178
  const lprob = logProblem(runDir, integ);
16053
16179
  if (lprob)
16054
16180
  return bad(lprob);
16181
+ if (receipt["toolchain"] !== undefined) {
16182
+ const tp = toolchainProblem(receipt["toolchain"]);
16183
+ if (tp)
16184
+ return bad(tp);
16185
+ }
16055
16186
  const heads = isObj10(integ["heads"]) ? integ["heads"] : {}, outcomes = integ["outcomes"];
16056
16187
  const stated = receipt["integration"];
16057
16188
  if (stated !== undefined) {
@@ -16113,10 +16244,12 @@ function compositeHash(r) {
16113
16244
  const { composite_sha256: _c, verification: _v, ...body } = r;
16114
16245
  return sha3(canonicalJson(body));
16115
16246
  }
16116
- var COMPOSITE_SCHEMA = "loki.v10.composite/1", slugOf = (repo) => repo.replace(/\//g, "__"), isComposite = (r) => r["schema"] === COMPOSITE_SCHEMA, relOk = (p) => p !== "" && !p.startsWith("/") && !p.split("/").includes("..");
16247
+ var COMPOSITE_SCHEMA = "loki.v10.composite/1", TOOLCHAIN_KEYS, toolchainProblem = (t) => isObj10(t) && Object.keys(t).length === TOOLCHAIN_KEYS.length && TOOLCHAIN_KEYS.every((k) => t[k] === null || typeof t[k] === "string") ? null : "toolchain section is malformed", slugOf = (repo) => repo.replace(/\//g, "__"), isComposite = (r) => r["schema"] === COMPOSITE_SCHEMA, relOk = (p) => p !== "" && !p.startsWith("/") && !p.split("/").includes("..");
16117
16248
  var init_composite_seal = __esm(() => {
16118
16249
  init_receipt_signer();
16250
+ init_check_result();
16119
16251
  init_seal_group();
16252
+ TOOLCHAIN_KEYS = ["bun", "node", "python3", "git"];
16120
16253
  });
16121
16254
 
16122
16255
  // ../../loki-ts/src/engine10/keys_cmd.ts
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "loki-mode",
4
4
  "displayName": "Loki Mode",
5
- "version": "11.17.39",
5
+ "version": "11.17.41",
6
6
  "description": "Autonomous spec-to-product build system with a built-in trust layer (RARV-C closure loop, 8 quality gates, completion council). Ships Loki's spec-hardening, drift-detection, and deterministic PR verification commands plus the Loki MCP server.",
7
7
  "author": {
8
8
  "name": "Autonomi",