loki-mode 11.82.0 → 11.83.0

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 (69) hide show
  1. package/SKILL.md +2 -2
  2. package/VERSION +1 -1
  3. package/autonomy/lib/telemetry-schema.json +1 -1
  4. package/autonomy/telemetry.sh +1 -1
  5. package/dashboard/__init__.py +1 -1
  6. package/docs/CLI-REFERENCE.md +1 -1
  7. package/docs/INSTALLATION.md +1 -1
  8. package/loki-ts/dist/loki.js +1383 -1366
  9. package/mcp/__init__.py +1 -1
  10. package/package.json +2 -2
  11. package/packages/control-plane/dist/server.js +202 -27
  12. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  13. package/web-app/dist/assets/{AdminPage-BDwJkrfT.js → AdminPage-DpWNKWhs.js} +1 -1
  14. package/web-app/dist/assets/{Avatar-Bjb7tmLG.js → Avatar-BjGfE5Z2.js} +1 -1
  15. package/web-app/dist/assets/{Badge-BYWNt-lF.js → Badge-BZzQgc5L.js} +1 -1
  16. package/web-app/dist/assets/{Button-CEKS68UU.js → Button-B4UFBoKo.js} +1 -1
  17. package/web-app/dist/assets/{CockpitPage-fAeYAB91.js → CockpitPage-HrjOxPcp.js} +1 -1
  18. package/web-app/dist/assets/{ComparePage-DRiaB5aq.js → ComparePage-rDB52mbC.js} +1 -1
  19. package/web-app/dist/assets/{ErrorBoundary-C_ts0y6d.js → ErrorBoundary-BnGTHBD5.js} +1 -1
  20. package/web-app/dist/assets/{EvidenceReceiptPanel-CAM2bOHh.js → EvidenceReceiptPanel-EWQ-AUvr.js} +1 -1
  21. package/web-app/dist/assets/{GitHubIssuesPanel-eTpdboWA.js → GitHubIssuesPanel-COCm9cnv.js} +1 -1
  22. package/web-app/dist/assets/{GitHubPRsPanel-ufk1eqQm.js → GitHubPRsPanel-ZYNmFQAR.js} +1 -1
  23. package/web-app/dist/assets/{HomePage-D8Cg8c0d.js → HomePage-CJXtxNhl.js} +2 -2
  24. package/web-app/dist/assets/{LoginPage-DWVzDN9I.js → LoginPage-CXG5HrnH.js} +1 -1
  25. package/web-app/dist/assets/{MagicPage-bmS03_51.js → MagicPage-D_1k-qFR.js} +1 -1
  26. package/web-app/dist/assets/{MetricsPage-ffCkhsSV.js → MetricsPage-Bh2OOgQW.js} +1 -1
  27. package/web-app/dist/assets/{NotFoundPage-CqluOiCR.js → NotFoundPage-DYtJqd7q.js} +1 -1
  28. package/web-app/dist/assets/{ProjectPage-D5XbTRQt.js → ProjectPage-C0_lqGnI.js} +3 -3
  29. package/web-app/dist/assets/{ProjectsPage-BK4mJziQ.js → ProjectsPage-C3ZDOF-i.js} +1 -1
  30. package/web-app/dist/assets/{SettingsPage-BoH4mS-n.js → SettingsPage-DNLBBiFb.js} +1 -1
  31. package/web-app/dist/assets/{ShowcasePage-B7xHXyht.js → ShowcasePage-jxMrHvDJ.js} +1 -1
  32. package/web-app/dist/assets/{SystemSettingsPage-BFyzSmVR.js → SystemSettingsPage-C2ZPx8uP.js} +1 -1
  33. package/web-app/dist/assets/{TeamsPage-DkuTf7Pm.js → TeamsPage-CmSWv2WS.js} +1 -1
  34. package/web-app/dist/assets/{TemplatesPage-DqC4qY5U.js → TemplatesPage-Cqcz3jC1.js} +1 -1
  35. package/web-app/dist/assets/{TerminalOutput-CiERRLAB.js → TerminalOutput-Cfy74R8E.js} +1 -1
  36. package/web-app/dist/assets/{activity-BBdRZTad.js → activity-DvB2Cewz.js} +1 -1
  37. package/web-app/dist/assets/{bell-CvIl2nxi.js → bell-DFPKTgoZ.js} +1 -1
  38. package/web-app/dist/assets/{bot-CWMB2JQE.js → bot-Bf5xNfiN.js} +1 -1
  39. package/web-app/dist/assets/{check-CSVvxOtd.js → check-BdqIiGKJ.js} +1 -1
  40. package/web-app/dist/assets/{chevron-left-B7MXj-CB.js → chevron-left-Q2RMHGjD.js} +1 -1
  41. package/web-app/dist/assets/{circle-alert-DlegpSSz.js → circle-alert-CSsLxjNX.js} +1 -1
  42. package/web-app/dist/assets/{clock-CO7alYth.js → clock-SUq-A-Pc.js} +1 -1
  43. package/web-app/dist/assets/{cloud-CmCwC9tD.js → cloud-1Qu-bH4o.js} +1 -1
  44. package/web-app/dist/assets/{code-xml-CttGX_KN.js → code-xml-B8tVFMMA.js} +1 -1
  45. package/web-app/dist/assets/{database-BFoEsl1d.js → database-BqqcDq2C.js} +1 -1
  46. package/web-app/dist/assets/{dollar-sign-CsX8E6iv.js → dollar-sign-D3Q2UCG0.js} +1 -1
  47. package/web-app/dist/assets/{file-code-corner-AD_LP7Sr.js → file-code-corner-CRIBFOW5.js} +1 -1
  48. package/web-app/dist/assets/{file-plus-D1lrSELb.js → file-plus-Bv-fZPBA.js} +1 -1
  49. package/web-app/dist/assets/{globe-BO79vdlK.js → globe-C4B7SAB9.js} +1 -1
  50. package/web-app/dist/assets/{hammer-ByRAYTmN.js → hammer-y0Ikysax.js} +1 -1
  51. package/web-app/dist/assets/{index-Dhf-7-HA.js → index-dNruR__0.js} +3 -3
  52. package/web-app/dist/assets/{layers-Ch8twnaQ.js → layers-EgGWmhHw.js} +1 -1
  53. package/web-app/dist/assets/{loader-circle-jCLtMahM.js → loader-circle-Bt5dIF0I.js} +1 -1
  54. package/web-app/dist/assets/{lock-DYipaQub.js → lock-BGuyekU7.js} +1 -1
  55. package/web-app/dist/assets/{package-DTU2eDJk.js → package-BkYbeAX3.js} +1 -1
  56. package/web-app/dist/assets/{plus-Dwtg85R2.js → plus-BzcgCbLN.js} +1 -1
  57. package/web-app/dist/assets/{refresh-cw-B2BZn7xv.js → refresh-cw-Dm5Jp3fH.js} +1 -1
  58. package/web-app/dist/assets/{rotate-ccw-BnDgsF2l.js → rotate-ccw-BwCcLLQd.js} +1 -1
  59. package/web-app/dist/assets/{scroll-text-CHcWlkC1.js → scroll-text-ZdYcnYoT.js} +1 -1
  60. package/web-app/dist/assets/{server-DGbuh4v5.js → server-BKLLV1vh.js} +1 -1
  61. package/web-app/dist/assets/{shield-alert-BGxG6i1x.js → shield-alert-BmdJ5RUP.js} +1 -1
  62. package/web-app/dist/assets/{thumbs-up-C4_XsjwR.js → thumbs-up-BkgThloL.js} +1 -1
  63. package/web-app/dist/assets/{trash-2-CXkZKiJ3.js → trash-2-CEGx8Si2.js} +1 -1
  64. package/web-app/dist/assets/{trending-down-Ca8gOfqE.js → trending-down-bDEP2c-J.js} +1 -1
  65. package/web-app/dist/assets/{trending-up-BwTtd3Ft.js → trending-up-BTZtHq6z.js} +1 -1
  66. package/web-app/dist/assets/{upload-DK47bkj8.js → upload-CU4BNteU.js} +1 -1
  67. package/web-app/dist/assets/{usePolling-CrEvFOnC.js → usePolling-uzQ6JTcy.js} +1 -1
  68. package/web-app/dist/assets/{user-Ck5fqwRB.js → user-Bz1t2qnf.js} +1 -1
  69. package/web-app/dist/index.html +1 -1
package/mcp/__init__.py CHANGED
@@ -75,4 +75,4 @@ try:
75
75
  except ImportError:
76
76
  __all__ = ['mcp']
77
77
 
78
- __version__ = '11.82.0'
78
+ __version__ = '11.83.0'
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "loki-mode",
3
3
  "mcpName": "io.github.asklokesh/loki-mode",
4
- "version": "11.82.0",
4
+ "version": "11.83.0",
5
5
  "description": "An autonomous software factory that knows what it is supposed to deliver, and proves it did.",
6
6
  "keywords": [
7
7
  "agent",
@@ -160,5 +160,5 @@
160
160
  "dependencies": {
161
161
  "@resvg/resvg-wasm": "^2.6.2"
162
162
  },
163
- "gitHead": "762731007b7478d6d1f5fdb705df746e959c0116"
163
+ "gitHead": "a7c2f43a6e6110b09c08f280605a9e6704c28415"
164
164
  }
@@ -258,7 +258,7 @@ var ASSIGNMENT, RULES, QUERY_SEGMENT, SECRET_PARAM, redactQuery = (s) => s.repla
258
258
  if (!keep || !data || typeof data !== "object" || Array.isArray(data))
259
259
  return redactDeep(data);
260
260
  return Object.fromEntries(Object.entries(data).map(([k, v]) => typeof v === "string" && keep.get(k)?.test(v) ? [k, v] : [redactSecrets(k), redactDeep(v)]));
261
- }, redactEnvelope = (e) => Object.fromEntries(Object.entries(e).map(([k, v]) => [redactSecrets(k), k === "data" ? redactEventData(e.type, v) : redactDeep(v)]));
261
+ }, redactEnvelope = (e) => Object.fromEntries(Object.entries(e).map(([k, v]) => [redactSecrets(k), k === "data" ? redactEventData(e.type, v) : redactDeep(v)])), UNSAFE_TERMINAL_CHARS_RE;
262
262
  var init_redact = __esm(() => {
263
263
  ASSIGNMENT = /((?<![A-Za-z0-9_.-])[_.-]*(?:[A-Za-z0-9]+[_.-]+)*(?:password|passwd|secret|token|api[_-]?key|apikey)["']?\s*[:=]\s*)((?:"(?!\[REDACTED)(?:\\.|[^"\\\n])+")|(?:'(?!\[REDACTED)(?:\\.|[^'\\\n])+')|(?!["']|\[REDACTED)[^\s"',;&]+)/gi;
264
264
  RULES = [
@@ -300,6 +300,7 @@ var init_redact = __esm(() => {
300
300
  ["log.sealed", new Map([["kid", B64(43)], ["sig", B64(86)], ["events_sha256", HEX64]])],
301
301
  ["receipt.sealed", new Map([["kid", B64(43)], ["receipt_sha256", HEX64], ["events_sha256", HEX64]])]
302
302
  ]);
303
+ UNSAFE_TERMINAL_CHARS_RE = /[\x00-\x1f\x7f-\x9f\u00ad\u061c\u200b-\u200f\u2028-\u202e\u2060-\u2064\u2066-\u2069\ufeff]/g;
303
304
  });
304
305
 
305
306
  // ../../loki-ts/src/util/credential_env.ts
@@ -55777,6 +55778,7 @@ var init_test_file_text = __esm(() => {
55777
55778
  var exports_testmap = {};
55778
55779
  __export(exports_testmap, {
55779
55780
  projectInterpreter: () => projectInterpreter,
55781
+ missingJavaTool: () => missingJavaTool,
55780
55782
  isTestFile: () => isTestFile,
55781
55783
  impactedRefs: () => impactedRefs,
55782
55784
  harnessRunners: () => harnessRunners,
@@ -55796,6 +55798,10 @@ function pytestPython(root) {
55796
55798
  }
55797
55799
  return "python";
55798
55800
  }
55801
+ function missingJavaTool(files, env = process.env, root) {
55802
+ const want = files.some((f) => /(?:^|\/)pom\.xml$/.test(f)) ? "maven" : files.some((f) => /(?:^|\/)(?:build|settings)\.gradle(?:\.kts)?$|(?:^|\/)gradlew$/.test(f)) ? "gradle" : files.some((f) => /\.java$/.test(f)) ? "javac" : null;
55803
+ return want && !javaToolOk(want, env, root) ? JAVA_TOOLS[want].tool : null;
55804
+ }
55799
55805
  function guessRunner(fileName, runners, relPath) {
55800
55806
  if (fileName.endsWith(".py"))
55801
55807
  return runners.includes("unittest") && !runners.includes("pytest") ? "unittest" : "pytest";
@@ -55803,6 +55809,8 @@ function guessRunner(fileName, runners, relPath) {
55803
55809
  return "go";
55804
55810
  if (fileName.endsWith(".rs"))
55805
55811
  return runners.includes("cargo") && relPath !== undefined && CARGO_TEST_FILE_RE.test(relPath) ? "cargo" : null;
55812
+ if (fileName.endsWith(".java"))
55813
+ return ["maven", "gradle", "javac"].find((r) => runners.includes(r)) ?? null;
55806
55814
  return /\.[cm]?[jt]sx?$/.test(fileName) ? ["vitest", "jest", "bun", "node"].find((r) => runners.includes(r)) ?? null : null;
55807
55815
  }
55808
55816
  function projectInterpreter(root) {
@@ -55851,6 +55859,10 @@ function buildTestMap(root) {
55851
55859
  mark("go", rel);
55852
55860
  else if (name === "Cargo.toml")
55853
55861
  mark("cargo", rel);
55862
+ else if (name === "pom.xml")
55863
+ mark("maven", rel);
55864
+ else if (/^(?:build|settings)\.gradle(?:\.kts)?$/.test(name) || name === "gradlew")
55865
+ mark("gradle", rel);
55854
55866
  }
55855
55867
  const jsRunner = evidence["vitest"] ? "vitest" : evidence["jest"] ? "jest" : evidence["bun"] ? "bun" : evidence["node"] ? "node" : null;
55856
55868
  const tests = [];
@@ -55919,7 +55931,10 @@ class RealTestMapProvider {
55919
55931
  return impactedRefs(map, changedFiles);
55920
55932
  }
55921
55933
  }
55922
- var RUNNER_ORDER, COMMANDS, STDLIB_RUNNERS, FOREIGN_SOURCE_RE, harnessRunners = (runners, files = [], env = process.env, root, focus2 = []) => {
55934
+ var RUNNER_ORDER, COMMANDS, STDLIB_RUNNERS, FOREIGN_SOURCE_RE, JAVA_TOOLS, javaToolOk = (r, env, root) => {
55935
+ const t = JAVA_TOOLS[r];
55936
+ return !t || !!Bun.which(t.tool, { PATH: env.PATH ?? "" }) || !!t.wrapper && !!root && existsSync36(join53(root, t.wrapper));
55937
+ }, harnessRunners = (runners, files = [], env = process.env, root, focus2 = []) => pickHarnessRunners(runners, files, env, root, focus2).filter((r) => javaToolOk(r, env, root)), pickHarnessRunners = (runners, files, env, root, focus2) => {
55923
55938
  const onPath = (tool) => !!Bun.which(tool, { PATH: env.PATH ?? "" }), w = languageBytes(root, files, (f) => STDLIB_RUNNERS.find((r) => r.ext.test(f))?.runner ?? (/\.[cm]?[jt]sx?$/i.test(f) ? "js" : FOREIGN_SOURCE_RE.test(f) ? "other" : null)), at2 = (k3) => w.get(k3) ?? 0, js = at2("js"), top = STDLIB_RUNNERS.reduce((a, r) => at2(r.runner) > at2(a.runner) ? r : a), bun = env.LOKI_WALL_HARNESS_RUNNER !== "0" && onPath("bun") ? ["bun"] : toolchainRunner(files, focus2);
55924
55939
  const t = at2(top.runner), o = at2("other");
55925
55940
  return runners.length > 0 ? runners : js >= t && js >= o ? js === 0 && w.size > 0 ? [] : bun : t > o ? onPath(top.tool) ? [top.runner] : toolchainRunner(files, focus2) : [];
@@ -55939,7 +55954,7 @@ var init_testmap = __esm(() => {
55939
55954
  init_linguist();
55940
55955
  init_scope();
55941
55956
  init_test_file_text();
55942
- RUNNER_ORDER = ["pytest", "vitest", "jest", "bun", "node", "npm", "go", "cargo"];
55957
+ RUNNER_ORDER = ["pytest", "vitest", "jest", "bun", "node", "npm", "go", "cargo", "maven", "gradle", "javac"];
55943
55958
  COMMANDS = {
55944
55959
  pytest: { cmd: "python -m pytest -q <files>", coarse: false },
55945
55960
  unittest: { cmd: "python3 -m unittest <files>", coarse: false },
@@ -55949,11 +55964,15 @@ var init_testmap = __esm(() => {
55949
55964
  node: { cmd: "node --test <files>", coarse: false },
55950
55965
  npm: { cmd: "npm test --silent", coarse: true },
55951
55966
  go: { cmd: "go test ./<pkg dirs>", coarse: false },
55952
- cargo: { cmd: "cargo test", coarse: true }
55967
+ cargo: { cmd: "cargo test", coarse: true },
55968
+ maven: { cmd: "mvn test -Dtest=<class>", coarse: false },
55969
+ gradle: { cmd: "gradle cleanTest test --tests <class>", coarse: false },
55970
+ javac: { cmd: "javac + java <test class>", coarse: false }
55953
55971
  };
55954
- STDLIB_RUNNERS = [{ ext: /\.py$/, runner: "unittest", tool: "python3" }, { ext: /\.go$/, runner: "go", tool: "go" }, { ext: /\.rs$/, runner: "cargo", tool: "cargo" }];
55972
+ STDLIB_RUNNERS = [{ ext: /\.py$/, runner: "unittest", tool: "python3" }, { ext: /\.go$/, runner: "go", tool: "go" }, { ext: /\.rs$/, runner: "cargo", tool: "cargo" }, { ext: /\.java$/, runner: "javac", tool: "javac" }];
55955
55973
  FOREIGN_SOURCE_RE = /\.(?:py|go|rs|java|kt|kts|scala|rb|php|cs|c|cc|cpp|cxx|h|hpp|swift|m|mm|ex|exs|erl|hs|clj|lua|pl|dart|r|jl|zig)$/i;
55956
- TOOLCHAINS = [[/(?:^|\/)package\.json$/, "node", /\.[cm]?[jt]sx?$/], [/(?:^|\/)go\.mod$/, "go", /\.go$/], [/(?:^|\/)Cargo\.toml$/, "cargo", /\.rs$/], [/(?:^|\/)(?:pyproject\.toml|setup\.py|setup\.cfg|requirements(?:[-_.][\w.-]+)?\.txt|tox\.ini|pytest\.ini)$/, "pytest", /\.py$/]];
55974
+ JAVA_TOOLS = { maven: { tool: "mvn", wrapper: "mvnw" }, gradle: { tool: "gradle", wrapper: "gradlew" }, javac: { tool: "javac" } };
55975
+ TOOLCHAINS = [[/(?:^|\/)package\.json$/, "node", /\.[cm]?[jt]sx?$/], [/(?:^|\/)go\.mod$/, "go", /\.go$/], [/(?:^|\/)Cargo\.toml$/, "cargo", /\.rs$/], [/(?:^|\/)pom\.xml$/, "maven", /\.java$/], [/(?:^|\/)(?:build|settings)\.gradle(?:\.kts)?$|(?:^|\/)gradlew$/, "gradle", /\.java$/], [/(?:^|\/)(?:pyproject\.toml|setup\.py|setup\.cfg|requirements(?:[-_.][\w.-]+)?\.txt|tox\.ini|pytest\.ini)$/, "pytest", /\.py$/]];
55957
55976
  CARGO_TEST_FILE_RE = /(?:^|\/)tests\/[^/]+\.rs$/;
55958
55977
  });
55959
55978
 
@@ -56129,6 +56148,50 @@ function skipped(raw2) {
56129
56148
  return stripAnsi(raw2).split(`
56130
56149
  `).filter((l) => /^(?:=+ )?\d+ \w+.* in [\d.]+s|^\s*Tests?:?\s+\d|^(?:#|\u2139) skipped \d/.test(l.trim())).reduce((t, l) => t + [...l.matchAll(/(\d+) (?:skipped|deselected|xfailed)|skipped (\d+)/g)].reduce((u10, m) => u10 + +(m[1] ?? m[2]), 0), 0);
56131
56150
  }
56151
+ function javaSummary(raw2) {
56152
+ const ls2 = stripAnsi(raw2).split(`
56153
+ `).map((l) => l.trimEnd()), tail2 = ls2.filter((l) => l.trim()).slice(-40), ok2 = (re2) => {
56154
+ const m = tail2.map((l) => re2.exec(l)).filter(Boolean).pop();
56155
+ return m ? m[1] === "SUCCESS" || m[1] === "SUCCESSFUL" : null;
56156
+ };
56157
+ const wrap = ls2.filter((l) => l.trim()).slice(-1)[0]?.match(/^LOKI_JAVA_TESTS: (\d+) run, (\d+) failed$/);
56158
+ if (wrap) {
56159
+ const ids = ls2.flatMap((l) => l.match(/^FAIL (.+)$/)?.[1] ?? []), failed2 = +wrap[2];
56160
+ return +wrap[1] > 0 && ids.length === failed2 && ls2.filter((l) => /^(?:PASS|FAIL) /.test(l)).length === +wrap[1] ? { executed: +wrap[1], failed: failed2, ids } : null;
56161
+ }
56162
+ const mv2 = ok2(/^\[(?:INFO|ERROR)\] BUILD (SUCCESS|FAILURE)$/), gr2 = ok2(/^BUILD (SUCCESSFUL|FAILED)\b/);
56163
+ if (mv2 !== null) {
56164
+ let executed = 0, failed2 = 0, seen = false;
56165
+ ls2.forEach((l, i) => {
56166
+ if (/^\[(?:INFO|ERROR)\] Results:$/.test(l)) {
56167
+ const m = ls2.slice(i + 1, i + 40).map((x3) => /^\[(?:INFO|WARNING|ERROR)\] Tests run: (\d+), Failures: (\d+), Errors: (\d+), Skipped: (\d+)$/.exec(x3)).find(Boolean);
56168
+ if (m) {
56169
+ seen = true;
56170
+ executed += +m[1] - +m[4];
56171
+ failed2 += +m[2] + +m[3];
56172
+ }
56173
+ }
56174
+ });
56175
+ const ids = [...new Set(ls2.flatMap((l) => {
56176
+ const m = /^\[ERROR\] (?:(\S+)\(([\w.$]+)\)|([\w.$]+\.[\w$]+)(?:\[[^\]]*\])?) .*<<< (?:FAILURE|ERROR)!$/.exec(l);
56177
+ return m ? [m[3] ?? `${m[2]}.${m[1]}`] : [];
56178
+ }))];
56179
+ return seen && executed > 0 && (mv2 ? failed2 === 0 : failed2 > 0) ? { executed, failed: failed2, ids } : null;
56180
+ }
56181
+ if (gr2 !== null) {
56182
+ const ev2 = ls2.flatMap((l) => {
56183
+ const m = /^\s*(\S.*?) > (\S.*?) (PASSED|FAILED|SKIPPED)$/.exec(l);
56184
+ return m ? [{ id: `${m[1]}.${m[2]}`, s: m[3] }] : [];
56185
+ }), bad = ev2.filter((e10) => e10.s === "FAILED");
56186
+ const executed = ev2.filter((e10) => e10.s !== "SKIPPED").length;
56187
+ return executed > 0 && (gr2 ? bad.length === 0 : bad.length > 0) ? { executed, failed: bad.length, ids: [...new Set(bad.map((e10) => e10.id))] } : null;
56188
+ }
56189
+ return null;
56190
+ }
56191
+ function javaTestClass(path) {
56192
+ const m = /^(.*?)\/?src\/test\/java\/(.+)\.java$/.exec(path), cls = (m ? m[2] : basename12(path, ".java")).split("/").join(".");
56193
+ return { root: m?.[1] || ".", cls, rel: m ? `src/test/java/${m[2]}.java` : path };
56194
+ }
56132
56195
  function testCount(raw2, path, ok2) {
56133
56196
  const out3 = stripAnsi(raw2);
56134
56197
  const bu2 = bunCount(out3), ut = unittestCount(out3, ok2);
@@ -56136,6 +56199,9 @@ function testCount(raw2, path, ok2) {
56136
56199
  return bu2;
56137
56200
  if (ut !== null)
56138
56201
  return ut;
56202
+ const jv = javaSummary(out3);
56203
+ if (jv)
56204
+ return jv.executed;
56139
56205
  if (/^\s*(?:Test Files\s+0\b|No test files found)/m.test(out3) && !/^\s*Tests?\s+\d/m.test(out3))
56140
56206
  return 0;
56141
56207
  const r = ran(out3, path, ok2);
@@ -56202,6 +56268,9 @@ function classifyCheck(i) {
56202
56268
  return { result: "fail", ...n10 !== null ? { n: n10 } : {} };
56203
56269
  if (n10 === null)
56204
56270
  return { result: "not_run", reason: UNMEASURED_REASON };
56271
+ const jv = javaSummary(text3);
56272
+ if (jv && jv.failed > 0)
56273
+ return { result: "fail", n: n10 };
56205
56274
  return { result: "pass", n: n10 };
56206
56275
  }
56207
56276
  function checkProvenance(name, ctx) {
@@ -56715,6 +56784,10 @@ function classify(f, status, output, repoDir, interpreter) {
56715
56784
  return status === 1 ? pytestExit1IsRed(output) ? "fail" : "not_run" : status === 2 ? pytestCollectionIsRed(output, repoDir) ? "fail" : "not_run" : "not_run";
56716
56785
  if (f.runner === "jest" || f.runner === "vitest" || f.runner === "bun")
56717
56786
  return parsedFailCount(f.runner, output) > 0 ? "fail" : "not_run";
56787
+ if (f.runner === "maven" || f.runner === "gradle" || f.runner === "javac") {
56788
+ const j10 = javaSummary(output);
56789
+ return j10 && j10.failed > 0 ? "fail" : "not_run";
56790
+ }
56718
56791
  return f.runner === "node" && nodeIsRed(f, output) ? "fail" : "not_run";
56719
56792
  }
56720
56793
  function baseJobs() {
@@ -56809,11 +56882,27 @@ function runnerCmd(t, repoDir) {
56809
56882
  const names = goTestNames(join54(repoDir, t.path));
56810
56883
  return ["go", ["test", "-json", ...names.length ? ["-run", `^(${names.join("|")})$`] : [], `./${dirname23(t.path)}`]];
56811
56884
  }
56885
+ case "maven": {
56886
+ const j10 = javaTestClass(t.path);
56887
+ return [wrapperOr(repoDir, "mvnw", "mvn"), ["-B", "test", `-Dtest=${j10.cls.split(".").pop()}`, "-Dsurefire.failIfNoSpecifiedTests=false", "-DfailIfNoTests=false"]];
56888
+ }
56889
+ case "gradle": {
56890
+ const j10 = javaTestClass(t.path);
56891
+ return [wrapperOr(repoDir, "gradlew", "gradle"), ["cleanTest", "test", "--tests", j10.cls, "-i", "--console=plain"]];
56892
+ }
56893
+ case "javac": {
56894
+ const j10 = javaTestClass(t.path);
56895
+ return ["bash", ["-c", JAVAC_WRAPPER, "loki-javac", j10.root, j10.cls, j10.rel]];
56896
+ }
56812
56897
  case "cargo":
56813
56898
  return CARGO_TEST_FILE_RE.test(t.path) ? ["cargo", ["test", "--test", basename12(t.path, ".rs")]] : ["cargo", ["test"]];
56814
56899
  }
56815
56900
  }
56816
56901
  function fullSuiteCmd(runner, repoDir) {
56902
+ if (runner === "maven" || runner === "gradle") {
56903
+ const s = FULL_SUITE_STATIC[runner];
56904
+ return { ...s, cmd: wrapperOr(repoDir, runner === "maven" ? "mvnw" : "gradlew", s.cmd) };
56905
+ }
56817
56906
  if (runner !== "pytest" && runner !== "unittest")
56818
56907
  return FULL_SUITE_STATIC[runner];
56819
56908
  const [cmd, interpreter, pre2] = resolveTool(repoDir, "python", "python3", "python");
@@ -56896,7 +56985,23 @@ function firstFileLineAnchor(desc2) {
56896
56985
  }
56897
56986
  var NO_TESTS_REASON = "no tests executed", NO_RUNNER_REASON = "no runner of this repo runs this file", harnessSkipCode = (env = process.env) => env.LOKI_WALL_HARNESS_RUNNER === "0" ? "harness_runner_disabled" : Bun.which("bun", { PATH: env.PATH ?? "" }) ? "no_toolchain" : "bun_not_on_path", 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, `
56898
56987
  `), tailLines = (out3) => out3.split(`
56899
- `).filter((x3) => x3.trim()).slice(-12), GO_PKG_RE, EXIT_CODED_COUNT = "n/a (exit-coded check, not a test runner)", FRAMEWORK_RE, SCRIPT_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))), CODE_FILE_EXT, DECL_RE, VAR_DECL_RE, stripComments = (src) => src.replace(/\/\*[\s\S]*?\*\//g, " ").split(`
56988
+ `).filter((x3) => x3.trim()).slice(-12), GO_PKG_RE, JAVAC_WRAPPER = `set -u
56989
+ root="$1"; cls="$2"; shift 2; cd "$root" || exit 70
56990
+ if [ "$cls" = "-" ]; then
56991
+ set -- $(find src/test/java -name '*Test.java' 2>/dev/null | sort); cls=""
56992
+ for f in "$@"; do c="\${f#src/test/java/}"; c="\${c%.java}"; cls="$cls \${c//\\//.}"; done
56993
+ fi
56994
+ out="$(mktemp -d "\${TMPDIR:-/tmp}/loki-javac.XXXXXX")" || exit 70
56995
+ trap 'rm -rf -- "\${out:?}"' EXIT
56996
+ find src/main/java -name '*.java' 2>/dev/null > "$out/srcs"
56997
+ javac -nowarn -d "$out" @"$out/srcs" "$@" || exit 1
56998
+ st=0; : > "$out/run.log"
56999
+ for c in $cls; do java -cp "$out" "$c" >> "$out/run.log" 2>&1 || st=$?; done
57000
+ cat "$out/run.log"
57001
+ p=$(grep -c '^PASS ' "$out/run.log"); f=$(grep -c '^FAIL ' "$out/run.log")
57002
+ echo "LOKI_JAVA_TESTS: $((p + f)) run, $f failed"
57003
+ [ "$f" -gt 0 ] && st=1
57004
+ exit $st`, wrapperOr = (repoDir, w, bare) => existsSync37(join54(repoDir, w)) ? `./${w}` : bare, EXIT_CODED_COUNT = "n/a (exit-coded check, not a test runner)", FRAMEWORK_RE, SCRIPT_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))), CODE_FILE_EXT, DECL_RE, VAR_DECL_RE, stripComments = (src) => src.replace(/\/\*[\s\S]*?\*\//g, " ").split(`
56900
57005
  `).map((l) => /^\s*\*/.test(l) ? "" : l.replace(/\/\/.*$/, "").replace(/(^|\s)#.*$/, "$1")).join(`
56901
57006
  `), GO_METHOD_RE, METHOD_RE, NOT_A_NAME, declNames = (line2) => {
56902
57007
  const out3 = [];
@@ -56911,7 +57016,7 @@ var NO_TESTS_REASON = "no tests executed", NO_RUNNER_REASON = "no runner of this
56911
57016
  if (m)
56912
57017
  out3.push(m[1]);
56913
57018
  return out3.filter((n10) => !NOT_A_NAME.has(n10));
56914
- }, printable = (s) => s.replace(/[\x00-\x1f\x7f]/g, "?"), SENSITIVE, API, TEST_CFG, RANK3, FILES_MEDIUM = 4, FILES_HIGH = 15, LINES_MEDIUM = 100, LINES_HIGH = 500, RAN_ALWAYS, REVIEWER_ITEM = "one reviewer", PLAN, LOW_SKIPPED, deferredOf = (tier, selected, executed) => (tier === "low" ? LOW_SKIPPED : selected).filter((c) => !RAN_ALWAYS.includes(c) && !executed.includes(c)), DEEP_ITEMS, NOT_SELECTED = "not selected by risk tier: ", MANIFEST_LOCKS, dirOf = (p) => p.includes("/") ? p.slice(0, p.lastIndexOf("/")) : "", PKG_DEP_KEYS, PYPROJECT_NONDEP, SEM_RULES, DOC_FILE, readOr = (p) => {
57019
+ }, printable = (s) => s.replace(UNSAFE_TERMINAL_CHARS_RE, "?"), SENSITIVE, API, TEST_CFG, RANK3, FILES_MEDIUM = 4, FILES_HIGH = 15, LINES_MEDIUM = 100, LINES_HIGH = 500, RAN_ALWAYS, REVIEWER_ITEM = "one reviewer", PLAN, LOW_SKIPPED, deferredOf = (tier, selected, executed) => (tier === "low" ? LOW_SKIPPED : selected).filter((c) => !RAN_ALWAYS.includes(c) && !executed.includes(c)), DEEP_ITEMS, NOT_SELECTED = "not selected by risk tier: ", MANIFEST_LOCKS, dirOf = (p) => p.includes("/") ? p.slice(0, p.lastIndexOf("/")) : "", PKG_DEP_KEYS, PYPROJECT_NONDEP, SEM_RULES, DOC_FILE, readOr = (p) => {
56915
57020
  try {
56916
57021
  return readFileSync49(p, "utf8");
56917
57022
  } catch {
@@ -56990,7 +57095,10 @@ var init_check_result = __esm(() => {
56990
57095
  node: { cmd: "node", args: ["--test"] },
56991
57096
  npm: { cmd: "npm", args: ["test", "--silent"] },
56992
57097
  go: { cmd: "go", args: ["test", "-json", "./..."] },
56993
- cargo: { cmd: "cargo", args: ["test"] }
57098
+ cargo: { cmd: "cargo", args: ["test"] },
57099
+ maven: { cmd: "mvn", args: ["-B", "test"] },
57100
+ gradle: { cmd: "gradle", args: ["cleanTest", "test", "-i", "--console=plain"] },
57101
+ javac: { cmd: "bash", args: ["-c", JAVAC_WRAPPER, "loki-javac", ".", "-"] }
56994
57102
  };
56995
57103
  URL_RE = /\b[a-z][a-z0-9+.-]{0,63}:\/\/\S+/gi;
56996
57104
  ANCHOR_RE = /(?<![\w./@-])([\w./@-]{1,512})[`'"]?(?::L?|#L|\s*\(line\s+)([1-9]\d*)(?!\d)/g;
@@ -59186,6 +59294,9 @@ function failIds(raw2) {
59186
59294
  const output = stripAnsi(raw2), gc2 = goCargoIds(output);
59187
59295
  if (gc2)
59188
59296
  return gc2;
59297
+ const jv = javaSummary(output);
59298
+ if (jv)
59299
+ return jv.failed > 0 && jv.ids.length >= jv.failed ? jv.ids : [];
59189
59300
  const ids = [...new Set(output.split(`
59190
59301
  `).map((l) => ID_LINE.exec(l.trim())).flatMap((m) => m ? [(m.slice(1).find(Boolean) ?? "").trim()] : []).filter(Boolean))];
59191
59302
  const c = failCount(output);
@@ -64503,7 +64614,10 @@ class TestName(unittest.TestCase):
64503
64614
  def test_it(self): self.assertEqual(fn(1), 2)
64504
64615
  Run: python3 -m unittest <file>.`,
64505
64616
  go: `${COMMANDS.go.cmd.replace(" ./<pkg dirs>", "")}. Write a _test.go file in the package under test. Example: func TestName(t *testing.T) { if got := Fn(1); got != 2 { t.Fatalf("got %v", got) } } Run: ${COMMANDS.go.cmd.replace("<pkg dirs>", "<dir>")}.`,
64506
- cargo: `${COMMANDS.cargo.cmd}. Write an integration test file directly under tests/ that calls the crate's public API. Example: #[test] fn name() { assert_eq!(my_crate::f(1), 2); } Run: ${COMMANDS.cargo.cmd} --test <stem>.`
64617
+ cargo: `${COMMANDS.cargo.cmd}. Write an integration test file directly under tests/ that calls the crate's public API. Example: #[test] fn name() { assert_eq!(my_crate::f(1), 2); } Run: ${COMMANDS.cargo.cmd} --test <stem>.`,
64618
+ maven: `Maven + JUnit (use the JUnit version already declared in the build file). Put the file in src/test/java/ (add a package line only if the code under test is in a package). The file name must end in Test.java and the public class name must equal the file name without .java, so surefire picks it up. Example: import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; public class loki_wall_LeapTest { @Test void leap() { assertTrue(Leap.is(2000)); } } Run: ${COMMANDS.maven.cmd.replace("<class>", "<ClassName>")}.`,
64619
+ gradle: `Gradle + JUnit (use the JUnit version already declared in the build file). Put the file in src/test/java/. The public class name must equal the file name without .java and the file name must end in Test.java. Example: import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; public class loki_wall_LeapTest { @Test void leap() { assertTrue(Leap.is(2000)); } } Run: ${COMMANDS.gradle.cmd.replace("<class>", "<ClassName>")}.`,
64620
+ javac: 'Plain Java 8+ with NO test framework and NO build tool (do not import org.junit). Put the file in src/test/java/. The file name must end in Test.java and the public class name must equal the file name without .java. The class has public static void main. For every check print exactly one line, `PASS <name>` or `FAIL <name>` (name on the same line), and at the end System.exit(1) if any check failed. Catch exceptions per check so one failure does not hide the rest. Example: static void check(String n, boolean ok) { System.out.println((ok ? "PASS " : "FAIL ") + n); if (!ok) failed = true; } Run: javac the sources under src/main/java plus the file, then java <ClassName>.'
64507
64621
  };
64508
64622
  });
64509
64623
 
@@ -69001,8 +69115,10 @@ function loadTaskText(ctx, fromPrior) {
69001
69115
  }
69002
69116
  return process.env.LOKI_E10_TASK_TEXT ?? "";
69003
69117
  }
69004
- function wallTargetDir(repoDir, existingTests) {
69118
+ function wallTargetDir(repoDir, existingTests, runners = []) {
69005
69119
  const first = existingTests[0];
69120
+ if (!first && runners.some((r) => r === "maven" || r === "gradle" || r === "javac"))
69121
+ return join98(repoDir, "src", "test", "java");
69006
69122
  return first ? join98(repoDir, dirname39(first.path)) : join98(repoDir, "tests");
69007
69123
  }
69008
69124
  async function wallAuthor(ctx, signal, retry) {
@@ -69022,13 +69138,15 @@ async function wallAuthor(ctx, signal, retry) {
69022
69138
  if (!ctx.externalPatch && planMode() !== "always" && smallTaskPath(sz2.size, hasRelevantTests(task, repoMap, testMap, ctx.tests.impacted)) === "lean") {
69023
69139
  return done({ status: "skipped", data: { size: sz2.size }, reason: "small task with a relevant test: cascade skips Wall" });
69024
69140
  }
69025
- if (testMap && runners.length === 0)
69026
- return done({ status: "skipped", data: { size: sz2.size, files: [], no_runner: true, skip_code: harnessSkipCode(), not_proven: ["Wall skipped: no runnable test command for this stack"] }, reason: "no runnable test command detected: the Wall cannot write a runnable check" });
69141
+ if (testMap && runners.length === 0) {
69142
+ const miss = missingJavaTool(repoMap?.files ?? [], process.env, ctx.repoDir);
69143
+ return done({ status: "skipped", data: { size: sz2.size, files: [], no_runner: true, skip_code: harnessSkipCode(), not_proven: [miss ? `Wall not run: ${miss} is not installed on this machine, so this Java repo could not be tested (harness-owned)` : "Wall skipped: no runnable test command for this stack"] }, reason: miss ? `${miss} is not installed: the Wall cannot run Java tests (harness-owned, not proven)` : "no runnable test command detected: the Wall cannot write a runnable check" });
69144
+ }
69027
69145
  if (testMap && runners.every((r) => r === "pytest") && projectInterpreter(ctx.repoDir) === "system" && wallHoldoutRatio() === 0)
69028
69146
  return done({ status: "skipped", data: { size: sz2.size, files: [], no_interpreter: true, not_proven: ["Wall skipped: no project test interpreter"] }, reason: "Wall skipped: no project test interpreter" });
69029
69147
  const tree = prior.intake?.tree;
69030
69148
  const repomapText = repoMapText(ctx.repoDir, tree, repomapRef, WALL_MAP_MAX_LINES);
69031
- const targetDir = wallTargetDir(ctx.repoDir, existingTests), pkg = loadProjectApi(ctx.repoDir)?.packageOf(`${relative22(ctx.repoDir, targetDir)}/x`);
69149
+ const targetDir = wallTargetDir(ctx.repoDir, existingTests, runners), pkg = loadProjectApi(ctx.repoDir)?.packageOf(`${relative22(ctx.repoDir, targetDir)}/x`);
69032
69150
  const conv2 = readPackageConventions(join98(ctx.repoDir, pkg?.root ?? "."), pkg?.runner ?? null);
69033
69151
  const cwd = mkdtempSync14(join98(tmpdir17(), "loki-e15-wall-"));
69034
69152
  const wm2 = wallManifestFor(ctx.repoDir, tree, task);
@@ -71659,9 +71777,21 @@ var init_provider = __esm(() => {
71659
71777
  });
71660
71778
 
71661
71779
  // ../../loki-ts/src/util/funnel.ts
71780
+ function blockerOf(v3) {
71781
+ return typeof v3 === "string" && PREFLIGHT_BLOCKERS.includes(v3) ? v3 : null;
71782
+ }
71783
+ function noteRefusal(b) {
71784
+ if (b)
71785
+ refusal = b;
71786
+ }
71787
+ function noteRefusalFromEvents(events2) {
71788
+ noteRefusal(blockerOf(events2.find((e10) => e10.type === "stage.failed" && e10.stage === "intake")?.data["blocker"]));
71789
+ }
71790
+ var PREFLIGHT_BLOCKERS, refusal = null;
71662
71791
  var init_funnel = __esm(() => {
71663
71792
  init_paths();
71664
71793
  init_safe_git();
71794
+ PREFLIGHT_BLOCKERS = ["not_a_repo", "git_identity", "dirty_tracked_tree", "no_provider", "not_logged_in", "prd_missing", "unsupported_flag", "disk", "other"];
71665
71795
  });
71666
71796
 
71667
71797
  // ../../loki-ts/src/cockpit/capability.ts
@@ -71896,18 +72026,19 @@ async function checkPreflight(o) {
71896
72026
  pinErr = `${e10.message}; set a valid value or unset it (the run would otherwise drop the pin and use the provider default model)`;
71897
72027
  }
71898
72028
  }
71899
- const fatal = wt.exitCode !== 0 || wt.stdout.trim() !== "true" ? initFatal ?? NOT_A_REPO(o.repoDir) : !name.stdout.trim() || !email.stdout.trim() ? `git identity is not set; run: git config user.name "you" && git config user.email "you@example.com"` : !envVar ? `the v10 engine has no ${o.provider} invoker yet` : o.provider !== "claude" && truthy(env["LOKI_HOST_GUARD"]) ? `LOKI_HOST_GUARD=1 is set but provider '${o.provider}' has no enforced PreToolUse hook; unset LOKI_HOST_GUARD or use --provider claude` : pinErr ? pinErr : !cliOk ? `provider CLI '${cli}' is not on PATH; install it or set ${envVar} to its path${requirementFix(o.provider) ? `. Fix: ${requirementFix(o.provider)}` : ""}` : head.exitCode !== 0 ? "repository has no commits; run: git add . && git commit -m init" : null;
71900
- if (fatal)
71901
- return { fatal, warnings };
72029
+ const refuse = (b, f) => [b, f];
72030
+ const hit = wt.exitCode !== 0 || wt.stdout.trim() !== "true" ? refuse("not_a_repo", initFatal ?? NOT_A_REPO(o.repoDir)) : !name.stdout.trim() || !email.stdout.trim() ? refuse("git_identity", `git identity is not set; run: git config user.name "you" && git config user.email "you@example.com"`) : !envVar ? refuse("unsupported_flag", `the v10 engine has no ${o.provider} invoker yet`) : o.provider !== "claude" && truthy(env["LOKI_HOST_GUARD"]) ? refuse("other", `LOKI_HOST_GUARD=1 is set but provider '${o.provider}' has no enforced PreToolUse hook; unset LOKI_HOST_GUARD or use --provider claude`) : pinErr ? refuse("other", pinErr) : !cliOk ? refuse("no_provider", `provider CLI '${cli}' is not on PATH; install it or set ${envVar} to its path${requirementFix(o.provider) ? `. Fix: ${requirementFix(o.provider)}` : ""}`) : head.exitCode !== 0 ? refuse("other", "repository has no commits; run: git add . && git commit -m init") : null;
72031
+ if (hit)
72032
+ return { fatal: hit[1], warnings, blocker: hit[0] };
71902
72033
  try {
71903
72034
  accessSync3(o.repoDir, fsc2.W_OK);
71904
72035
  } catch {
71905
- return { fatal: `${o.repoDir} is not writable; run: chmod u+w "${o.repoDir}" (or run loki from a writable checkout)`, warnings };
72036
+ return { fatal: `${o.repoDir} is not writable; run: chmod u+w "${o.repoDir}" (or run loki from a writable checkout)`, warnings, blocker: "other" };
71906
72037
  }
71907
72038
  const free = freeMb(o.repoDir, o.statfs ?? statfsSync2);
71908
72039
  const minMb = Number(env["LOKI_MIN_FREE_MB"]) > 0 ? Number(env["LOKI_MIN_FREE_MB"]) : 200;
71909
72040
  if (free !== null && free < minMb)
71910
- return { fatal: `only ${Math.floor(free)} MB free on the volume holding ${o.repoDir} (need ${minMb} MB); free disk space, or lower LOKI_MIN_FREE_MB`, warnings };
72041
+ return { fatal: `only ${Math.floor(free)} MB free on the volume holding ${o.repoDir} (need ${minMb} MB); free disk space, or lower LOKI_MIN_FREE_MB`, warnings, blocker: "disk" };
71911
72042
  if (free !== null && free < Math.max(2048, minMb))
71912
72043
  warnings.push(`low disk: ${Math.floor(free)} MB free on the volume holding ${o.repoDir}; a long run may fail mid-way (warns under 2 GB)`);
71913
72044
  const auth_path = providerAuthPath(o.provider, env);
@@ -71943,11 +72074,11 @@ async function checkPreflight(o) {
71943
72074
  } catch {}
71944
72075
  }
71945
72076
  if (authFatal)
71946
- return { fatal: authFatal, warnings };
72077
+ return { fatal: authFatal, warnings, blocker: "not_logged_in" };
71947
72078
  if (o.pr && GITHUB_ORIGIN_RE.test((await git10(["config", "--get", "remote.origin.url"])).stdout.trim())) {
71948
72079
  const ghOk = await ghAuthProbeCached(env, async () => (await sh3(["gh", "--version"], { env, timeoutMs: 5000 })).exitCode === 0 && (await sh3(["gh", "auth", "status"], { env, timeoutMs: 1e4 })).exitCode === 0);
71949
72080
  if (!ghOk)
71950
- return { fatal: `gh (GitHub CLI) is missing or not authenticated; run gh auth login, or pass --no-pr`, warnings };
72081
+ return { fatal: `gh (GitHub CLI) is missing or not authenticated; run gh auth login, or pass --no-pr`, warnings, blocker: "other" };
71951
72082
  const plan = await probePublish((await git10(["config", "--get", "remote.origin.url"])).stdout.trim(), env);
71952
72083
  if (plan) {
71953
72084
  if (plan.warning)
@@ -71964,7 +72095,7 @@ async function assertPreflight(o) {
71964
72095
  process.stderr.write(`${w}
71965
72096
  `);
71966
72097
  if (r.fatal)
71967
- throw new PreflightError(r.fatal);
72098
+ throw new PreflightError(r.fatal, r.blocker);
71968
72099
  }
71969
72100
  var CLI_ENV_VAR, GITHUB_ORIGIN_RE, PreflightError;
71970
72101
  var init_preflight = __esm(() => {
@@ -71975,9 +72106,15 @@ var init_preflight = __esm(() => {
71975
72106
  init_first_run_repo();
71976
72107
  init_engine_origin();
71977
72108
  init_shell();
72109
+ init_funnel();
71978
72110
  CLI_ENV_VAR = { claude: "LOKI_CLAUDE_CLI", codex: "LOKI_CODEX_CLI", cline: "LOKI_CLINE_CLI", aider: "LOKI_AIDER_CLI", opencode: "LOKI_OPENCODE_CLI" };
71979
72111
  GITHUB_ORIGIN_RE = /^(?:https:\/\/(?:[^@/]+@)?github\.com\/|git@github\.com:|ssh:\/\/git@github\.com\/)/;
71980
72112
  PreflightError = class PreflightError extends Error {
72113
+ blocker;
72114
+ constructor(message, blocker = "other") {
72115
+ super(message);
72116
+ this.blocker = blocker;
72117
+ }
71981
72118
  };
71982
72119
  });
71983
72120
 
@@ -74713,6 +74850,7 @@ async function main4(args) {
74713
74850
  if (v3 === undefined || v3 === "" || v3.startsWith("-")) {
74714
74851
  process.stderr.write(`engine10: --max-cost needs a value
74715
74852
  `);
74853
+ noteRefusal("unsupported_flag");
74716
74854
  return 2;
74717
74855
  }
74718
74856
  maxCost = v3;
@@ -74724,6 +74862,7 @@ async function main4(args) {
74724
74862
  if (v3 === undefined || v3 === "" || v3.startsWith("-")) {
74725
74863
  process.stderr.write(`engine10: --provider needs a value
74726
74864
  `);
74865
+ noteRefusal("unsupported_flag");
74727
74866
  return 2;
74728
74867
  }
74729
74868
  provider = v3;
@@ -74733,6 +74872,7 @@ async function main4(args) {
74733
74872
  if (v3 === undefined || v3 === "" || v3.startsWith("-")) {
74734
74873
  process.stderr.write(`engine10: --spec needs a value
74735
74874
  `);
74875
+ noteRefusal("unsupported_flag");
74736
74876
  return 2;
74737
74877
  }
74738
74878
  specFile = v3;
@@ -74748,6 +74888,7 @@ async function main4(args) {
74748
74888
  if (v3 === undefined || v3 === "" || v3.startsWith("-")) {
74749
74889
  process.stderr.write(`engine10: --seal-existing needs a patch file
74750
74890
  `);
74891
+ noteRefusal("unsupported_flag");
74751
74892
  return 2;
74752
74893
  }
74753
74894
  sealPatch = resolve36(v3);
@@ -74759,6 +74900,7 @@ async function main4(args) {
74759
74900
  process.stderr.write(`engine10: unknown flag ${a}
74760
74901
  usage: loki "<task>" [--no-pr] [--deep] [--json] [--verbose] [--quiet] [--max-cost N] [--provider P] [--spec F] [--seal-existing PATCH] [--resume] [--fresh] [-- <task>]
74761
74902
  `);
74903
+ noteRefusal("unsupported_flag");
74762
74904
  return 2;
74763
74905
  } else
74764
74906
  words3.push(a);
@@ -74773,6 +74915,7 @@ usage: loki "<task>" [--no-pr] [--deep] [--json] [--verbose] [--quiet] [--max-co
74773
74915
  } catch (e10) {
74774
74916
  process.stderr.write(`engine10: ${e10.message}
74775
74917
  `);
74918
+ noteRefusal("prd_missing");
74776
74919
  return 2;
74777
74920
  }
74778
74921
  if (!task)
@@ -74789,6 +74932,7 @@ usage: loki "<task>" [--no-pr] [--deep] [--json] [--verbose] [--quiet] [--max-co
74789
74932
  if (!task) {
74790
74933
  process.stderr.write(`engine10: no task given
74791
74934
  `);
74935
+ noteRefusal("prd_missing");
74792
74936
  return 2;
74793
74937
  }
74794
74938
  let repoDir;
@@ -74799,6 +74943,7 @@ usage: loki "<task>" [--no-pr] [--deep] [--json] [--verbose] [--quiet] [--max-co
74799
74943
  if (!i.notice) {
74800
74944
  process.stderr.write(`engine10: ${i.fatal ?? "not inside a git repository"}
74801
74945
  `);
74946
+ noteRefusal("not_a_repo");
74802
74947
  return 2;
74803
74948
  }
74804
74949
  process.stderr.write(`engine10: ${i.notice}
@@ -74808,6 +74953,7 @@ usage: loki "<task>" [--no-pr] [--deep] [--json] [--verbose] [--quiet] [--max-co
74808
74953
  } catch {
74809
74954
  process.stderr.write(`engine10: not inside a git repository
74810
74955
  `);
74956
+ noteRefusal("not_a_repo");
74811
74957
  return 2;
74812
74958
  }
74813
74959
  }
@@ -74969,6 +75115,7 @@ usage: loki "<task>" [--no-pr] [--deep] [--json] [--verbose] [--quiet] [--max-co
74969
75115
  if (e10.type === "stage.completed" && e10.stage === "plan")
74970
75116
  statusStep();
74971
75117
  }, { intervalMs: 500 }) : () => {};
75118
+ let refusedAs = "other";
74972
75119
  const res = await runSupervisor({
74973
75120
  runId: runId2,
74974
75121
  repoDir,
@@ -75037,6 +75184,7 @@ ${prUrl ? "One question" : "Reason"}: ${reason}
75037
75184
  throw e10;
75038
75185
  process.stderr.write(`${e10.message}
75039
75186
  `);
75187
+ refusedAs = e10.blocker;
75040
75188
  return null;
75041
75189
  });
75042
75190
  clearInterval(tailTimer);
@@ -75044,12 +75192,14 @@ ${prUrl ? "One question" : "Reason"}: ${reason}
75044
75192
  if (!res) {
75045
75193
  stopTail();
75046
75194
  liveStop();
75195
+ noteRefusal(refusedAs);
75047
75196
  return 2;
75048
75197
  }
75049
75198
  await new Promise((r) => setTimeout(r, 300));
75050
75199
  stopTail();
75051
75200
  liveStop();
75052
75201
  const events2 = readEvents(eventsPath), f = fold(events2);
75202
+ noteRefusalFromEvents(events2);
75053
75203
  const sawCost = events2.some((e10) => e10.type === "cost"), cli = process.env.LOKI_E10_INVOKER === "cli";
75054
75204
  const { usd, pc: pc2 } = summaryCost(events2, res.tampered);
75055
75205
  const out3 = json2 ? `${JSON.stringify({ ok: EXIT[res.outcome] === 0, outcome: res.outcome, stop: res.stop, run_id: runId2, receipt_sha256: res.receiptSha })}
@@ -75123,6 +75273,7 @@ var init_supervisor = __esm(() => {
75123
75273
  init_worker_proc();
75124
75274
  init_intent_card();
75125
75275
  init_preflight();
75276
+ init_funnel();
75126
75277
  init_session();
75127
75278
  init_failure_memory();
75128
75279
  init_model_downgrades();
@@ -75833,7 +75984,7 @@ async function runIntakeBody(ctx, signal, opts, held) {
75833
75984
  return { status: "failed", data: {}, reason: "aborted before intake started" };
75834
75985
  const { blocking: dirty, preexisting } = splitDirty(ctx.repoDir, dirtyTrackedFiles(ctx.repoDir));
75835
75986
  if (dirty.length > 0)
75836
- return { status: "failed", data: {}, reason: `dirty tracked tree: ${dirty.join(", ")}` };
75987
+ return { status: "failed", data: { blocker: "dirty_tracked_tree" }, reason: `dirty tracked tree: ${dirty.join(", ")}` };
75837
75988
  let baseSha = git13(ctx.repoDir, ["rev-parse", "HEAD"]);
75838
75989
  const startBranch = git13(ctx.repoDir, ["symbolic-ref", "-q", "--short", "HEAD"]);
75839
75990
  let stacked = stackedOnLokiRun(ctx.repoDir);
@@ -80359,6 +80510,17 @@ function sealDrift(given, r, env = process.env) {
80359
80510
  }
80360
80511
  return null;
80361
80512
  }
80513
+ function wallNotComparedNote(receiptPath) {
80514
+ try {
80515
+ const r = JSON.parse(readFileSync119(receiptPath, "utf8"));
80516
+ if (r["schema"] !== "loki.v10.receipt/1")
80517
+ return null;
80518
+ const files = r["wall"]?.files;
80519
+ return Array.isArray(files) && files.length > 0 && !existsSync94(join136(dirname51(receiptPath), "wall")) ? "sealed Wall copies not present: not compared" : null;
80520
+ } catch {
80521
+ return null;
80522
+ }
80523
+ }
80362
80524
  var EMPTY_SHA, sha6 = (s) => createHash38("sha256").update(s).digest("hex");
80363
80525
  var init_seal_drift = __esm(() => {
80364
80526
  init_safe_git();
@@ -80802,6 +80964,14 @@ function independentLine(receiptPath) {
80802
80964
  const k3 = pass.filter((c) => isExecutedProof(c) && (c.provenance === "exogenous" || c.provenance === "independent")).length, m = pass.filter((c) => c.provenance === "agent_authored" || c.provenance === "llm_judge").length;
80803
80965
  return { line: `agent-independent: ${k3} of ${pass.length} passing checks (wall/holdout/pre-existing/static/probe); advisory: ${m}`, k: k3, of: pass.length };
80804
80966
  }
80967
+ function signedRunIdProblem(receiptPath, runId2) {
80968
+ try {
80969
+ const r = JSON.parse(readFileSync121(receiptPath, "utf8")), s = r["run_id"];
80970
+ return isEnvelope(r) || typeof s !== "string" || s === runId2 ? null : `receipt run_id ${JSON.stringify(printable(s).slice(0, 128))} does not match the run id ${JSON.stringify(runId2)} it was found under (a sealed run copied under another id)`;
80971
+ } catch {
80972
+ return null;
80973
+ }
80974
+ }
80805
80975
  async function verifyMain(args, deps, rec2) {
80806
80976
  const allowUnsigned = args.includes("--allow-unsigned") || process.env["LOKI_VERIFY_ALLOW_UNSIGNED"] === "1";
80807
80977
  const exportDsse = args.includes("--export-dsse"), requireExo = args.includes("--require-exogenous") || process.env["LOKI_VERIFY_REQUIRE_EXOGENOUS"] === "1";
@@ -80862,7 +81032,7 @@ ${/^(unknown option|expected at most one)/.test(pk2.error) ? `Usage: loki verify
80862
81032
  rec2.receiptPath = receiptPath;
80863
81033
  if (exportDsse)
80864
81034
  return exportDsseReceipt({ receiptPath, runId: byRunId ? runId2 : null, deps, verify: verifyReceipt, key: loadSigningKey(false), kidOf: kidOf2 });
80865
- const bad = byRunId ? runIdGuard(receiptPath, runId2) : null;
81035
+ const bad = byRunId ? runIdGuard(receiptPath, runId2) ?? signedRunIdProblem(receiptPath, runId2) : null;
80866
81036
  if (bad)
80867
81037
  return rec2.verdict = "TAMPERED", rec2.reasons = [bad], process.stdout.write(`run: ${runId2}
80868
81038
  verdict: TAMPERED
@@ -80917,6 +81087,11 @@ verdict: NOT VERIFIED (run outcome ${outcome}; receipt integrity ${result.verdic
80917
81087
  return 4;
80918
81088
  }
80919
81089
  }
81090
+ if (result.verdict === "VERIFIED" || result.verdict === "UNSIGNED") {
81091
+ const note = wallNotComparedNote(receiptPath);
81092
+ if (note)
81093
+ result = { ...result, reasons: [...result.reasons, note] };
81094
+ }
80920
81095
  rec2.verdict = result.verdict;
80921
81096
  rec2.reasons = result.reasons;
80922
81097
  rec2.receiptSha256 = result.receiptSha256 ?? null;
@@ -92136,9 +92311,9 @@ function createApp(opts) {
92136
92311
  }
92137
92312
 
92138
92313
  // src/server/serve.ts
92139
- var refusal = bindRefusal(process.env);
92140
- if (refusal) {
92141
- console.error(refusal);
92314
+ var refusal2 = bindRefusal(process.env);
92315
+ if (refusal2) {
92316
+ console.error(refusal2);
92142
92317
  process.exit(2);
92143
92318
  }
92144
92319
  var warning = insecureBindWarning(process.env);
@@ -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.82.0",
5
+ "version": "11.83.0",
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",
@@ -1,4 +1,4 @@
1
- import{c as L,r as x,j as e,w as re,Z as ne,m as le,h as ie,p as P,F as ye,U as I,X as ce,L as de,x as oe,M as Ae,T as Z,S as we,l as xe,k as me,y as Ce,E as Fe,a0 as Se,a as U,a2 as he}from"./index-Dhf-7-HA.js";import{B as C}from"./Button-CEKS68UU.js";import{T as $e}from"./trending-up-BwTtd3Ft.js";import{C as z}from"./clock-CO7alYth.js";import{A as Be,U as ue,M as De}from"./Avatar-Bjb7tmLG.js";import{A as J}from"./activity-BBdRZTad.js";import{R as pe}from"./refresh-cw-B2BZn7xv.js";import{G as ze}from"./globe-BO79vdlK.js";import{C as Le}from"./chevron-left-B7MXj-CB.js";import{C as je}from"./check-CSVvxOtd.js";import{D as Y}from"./dollar-sign-CsX8E6iv.js";import{U as Te}from"./user-Ck5fqwRB.js";import{D as Me}from"./database-BFoEsl1d.js";import{L as Ue}from"./lock-DYipaQub.js";import{S as Re}from"./scroll-text-CHcWlkC1.js";import{S as Ie}from"./shield-alert-BGxG6i1x.js";/**
1
+ import{c as L,r as x,j as e,w as re,Z as ne,m as le,h as ie,p as P,F as ye,U as I,X as ce,L as de,x as oe,M as Ae,T as Z,S as we,l as xe,k as me,y as Ce,E as Fe,a0 as Se,a as U,a2 as he}from"./index-dNruR__0.js";import{B as C}from"./Button-B4UFBoKo.js";import{T as $e}from"./trending-up-BTZtHq6z.js";import{C as z}from"./clock-SUq-A-Pc.js";import{A as Be,U as ue,M as De}from"./Avatar-BjGfE5Z2.js";import{A as J}from"./activity-DvB2Cewz.js";import{R as pe}from"./refresh-cw-Dm5Jp3fH.js";import{G as ze}from"./globe-C4B7SAB9.js";import{C as Le}from"./chevron-left-Q2RMHGjD.js";import{C as je}from"./check-BdqIiGKJ.js";import{D as Y}from"./dollar-sign-D3Q2UCG0.js";import{U as Te}from"./user-Bz1t2qnf.js";import{D as Me}from"./database-BqqcDq2C.js";import{L as Ue}from"./lock-BGuyekU7.js";import{S as Re}from"./scroll-text-ZdYcnYoT.js";import{S as Ie}from"./shield-alert-BmdJ5RUP.js";/**
2
2
  * @license lucide-react v0.577.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1,4 +1,4 @@
1
- import{c as l,j as s}from"./index-Dhf-7-HA.js";/**
1
+ import{c as l,j as s}from"./index-dNruR__0.js";/**
2
2
  * @license lucide-react v0.577.0 - ISC
3
3
  *
4
4
  * This source code is licensed under the ISC license.
@@ -1 +1 @@
1
- import{j as e}from"./index-Dhf-7-HA.js";import{C as r}from"./clock-CO7alYth.js";import{C as a}from"./circle-alert-DlegpSSz.js";import{C as l}from"./check-CSVvxOtd.js";const i={completed:"bg-[#1FC5A8]/10 text-[#1FC5A8]",running:"bg-[#553DE9]/10 text-[#553DE9]",failed:"bg-[#C45B5B]/10 text-[#C45B5B]",started:"bg-[#D4A03C]/10 text-[#D4A03C]",empty:"bg-[#F8F4F0] text-[#6B6960]",version:"bg-[#553DE9]/10 text-[#553DE9]"};function o({status:t}){switch(t){case"completed":return e.jsx(l,{size:12});case"running":return e.jsxs("span",{className:"relative flex h-2 w-2",children:[e.jsx("span",{className:"animate-ping motion-reduce:animate-none absolute inline-flex h-full w-full rounded-full bg-current opacity-75"}),e.jsx("span",{className:"relative inline-flex rounded-full h-2 w-2 bg-current"})]});case"failed":return e.jsx(a,{size:12});case"started":return e.jsx(r,{size:12});default:return null}}function f({status:t,children:n,className:s=""}){return e.jsxs("span",{className:["inline-flex items-center gap-1 rounded-btn px-2.5 py-0.5 text-xs font-semibold",i[t],s].filter(Boolean).join(" "),children:[e.jsx(o,{status:t}),n]})}export{f as B};
1
+ import{j as e}from"./index-dNruR__0.js";import{C as r}from"./clock-SUq-A-Pc.js";import{C as a}from"./circle-alert-CSsLxjNX.js";import{C as l}from"./check-BdqIiGKJ.js";const i={completed:"bg-[#1FC5A8]/10 text-[#1FC5A8]",running:"bg-[#553DE9]/10 text-[#553DE9]",failed:"bg-[#C45B5B]/10 text-[#C45B5B]",started:"bg-[#D4A03C]/10 text-[#D4A03C]",empty:"bg-[#F8F4F0] text-[#6B6960]",version:"bg-[#553DE9]/10 text-[#553DE9]"};function o({status:t}){switch(t){case"completed":return e.jsx(l,{size:12});case"running":return e.jsxs("span",{className:"relative flex h-2 w-2",children:[e.jsx("span",{className:"animate-ping motion-reduce:animate-none absolute inline-flex h-full w-full rounded-full bg-current opacity-75"}),e.jsx("span",{className:"relative inline-flex rounded-full h-2 w-2 bg-current"})]});case"failed":return e.jsx(a,{size:12});case"started":return e.jsx(r,{size:12});default:return null}}function f({status:t,children:n,className:s=""}){return e.jsxs("span",{className:["inline-flex items-center gap-1 rounded-btn px-2.5 py-0.5 text-xs font-semibold",i[t],s].filter(Boolean).join(" "),children:[e.jsx(o,{status:t}),n]})}export{f as B};