loki-mode 11.3.0 → 11.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. package/README.md +68 -650
  2. package/SKILL.md +4 -4
  3. package/VERSION +1 -1
  4. package/autonomy/completion-council.sh +2 -2
  5. package/autonomy/context-tracker.py +4 -4
  6. package/autonomy/council-v2.sh +1 -1
  7. package/autonomy/grill.sh +1 -1
  8. package/autonomy/lib/done-recognition.sh +1 -1
  9. package/autonomy/lib/prd-enrich.sh +1 -1
  10. package/autonomy/lib/voter-agents.sh +1 -1
  11. package/autonomy/loki +99 -75
  12. package/autonomy/run.sh +30 -18
  13. package/autonomy/sandbox.sh +1 -1
  14. package/autonomy/tui.sh +6 -5
  15. package/autonomy/verify.sh +1 -1
  16. package/bin/loki +166 -59
  17. package/completions/_loki +2 -0
  18. package/completions/loki.bash +2 -2
  19. package/dashboard/__init__.py +1 -1
  20. package/dashboard/server.py +25 -31
  21. package/docs/ARCHITECTURE.md +337 -0
  22. package/docs/BRANDING.md +124 -0
  23. package/docs/CLI-REFERENCE.md +7 -1
  24. package/docs/COMPONENTS.md +447 -0
  25. package/docs/DEPLOYMENT.md +9 -9
  26. package/docs/DOCKER.md +469 -0
  27. package/docs/INSTALLATION.md +67 -1045
  28. package/docs/KNOWN-ISSUES.md +11 -35
  29. package/docs/TESTING.md +161 -0
  30. package/docs/air-gapped.md +1 -2
  31. package/docs/alternative-installations.md +14 -24
  32. package/docs/architecture/DECISIONS.md +333 -0
  33. package/docs/audit-logging.md +7 -7
  34. package/docs/authentication.md +3 -3
  35. package/docs/authorization.md +1 -1
  36. package/docs/certification/04-production-deployment/lab.md +6 -6
  37. package/docs/certification/04-production-deployment/lesson.md +4 -4
  38. package/docs/certification/README.md +1 -1
  39. package/docs/control-plane-container.md +2 -2
  40. package/docs/dev/real-run.md +34 -0
  41. package/docs/dev/release-checklist.md +2 -2
  42. package/docs/exit-codes.md +3 -3
  43. package/docs/git-workflow.md +3 -3
  44. package/docs/metrics.md +37 -55
  45. package/docs/network-security.md +1 -1
  46. package/docs/siem-integration.md +5 -5
  47. package/docs/v10/CLI-MODERN.md +4 -3
  48. package/docs/v10/DECISIONS.md +44 -0
  49. package/docs/v10/DEPS.md +22 -22
  50. package/docs/v10/ENGINE.md +1 -1
  51. package/docs/v10/FAILURE-CLASSES.md +118 -1
  52. package/docs/v10/FOUNDER-QUEUE.md +1 -0
  53. package/docs/v10/GUARDS.md +13 -0
  54. package/docs/v10/LEGACY-REMOVAL.md +4 -6
  55. package/docs/v10/METRICS.md +2 -2
  56. package/docs/v10/MODERNIZE.md +1 -1
  57. package/docs/v10/OPERATING-MODEL.md +2 -1
  58. package/docs/v10/PROGRESS.md +29 -0
  59. package/docs/v11/COST-HALF.md +352 -0
  60. package/docs/v11/MARKET-SLICES.md +315 -0
  61. package/docs/v11/REGISTRIES.md +730 -0
  62. package/loki-ts/data/model-pricing.json +52 -24
  63. package/loki-ts/dist/loki.js +1036 -957
  64. package/mcp/__init__.py +1 -1
  65. package/package.json +1 -1
  66. package/packages/control-plane/dist/server.js +2467 -736
  67. package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
  68. package/src/protocols/mcp-client.js +6 -2
  69. package/src/protocols/mcp-server.js +13 -3
  70. package/tools/audit-docs.py +1 -1
  71. package/web-app/dist/assets/{AdminPage-D_e45uTw.js → AdminPage-CMkHNJbF.js} +1 -1
  72. package/web-app/dist/assets/{Avatar-T3nIpoaf.js → Avatar-BJyjV7Zi.js} +1 -1
  73. package/web-app/dist/assets/{Badge-BKqb59pP.js → Badge-D572l0uq.js} +1 -1
  74. package/web-app/dist/assets/{Button-DjVlkh8_.js → Button-T4BnOZgl.js} +1 -1
  75. package/web-app/dist/assets/{CockpitPage-DXJgLGmh.js → CockpitPage-Cj_GFsNn.js} +1 -1
  76. package/web-app/dist/assets/{ComparePage-BRP_eVc_.js → ComparePage-A8m4ZXak.js} +1 -1
  77. package/web-app/dist/assets/{ErrorBoundary-CLjpGLjC.js → ErrorBoundary-hugCg5yg.js} +1 -1
  78. package/web-app/dist/assets/{EvidenceReceiptPanel-DX-vb4Xy.js → EvidenceReceiptPanel-CuJKDC2G.js} +1 -1
  79. package/web-app/dist/assets/{GitHubIssuesPanel-214HVHtX.js → GitHubIssuesPanel-BYGKjarC.js} +1 -1
  80. package/web-app/dist/assets/{GitHubPRsPanel-BEiZKc4t.js → GitHubPRsPanel-c7sFIJlf.js} +1 -1
  81. package/web-app/dist/assets/{HomePage-VvMHS5ga.js → HomePage-A1MIkG2P.js} +2 -2
  82. package/web-app/dist/assets/{LoginPage-5WD-v7n3.js → LoginPage-8KQMRhtR.js} +1 -1
  83. package/web-app/dist/assets/{MagicPage-DUQT_Jye.js → MagicPage-C05QW2Lx.js} +1 -1
  84. package/web-app/dist/assets/{MetricsPage-lga-z79v.js → MetricsPage-Oukv5hme.js} +1 -1
  85. package/web-app/dist/assets/{NotFoundPage-CGhBX3G1.js → NotFoundPage-DKIwsawz.js} +1 -1
  86. package/web-app/dist/assets/{ProjectPage-CdzF2GzZ.js → ProjectPage-DwFRPLCG.js} +3 -3
  87. package/web-app/dist/assets/{ProjectsPage-DRG64N8s.js → ProjectsPage-CgY4YYDX.js} +1 -1
  88. package/web-app/dist/assets/{SettingsPage-5fzW9Frb.js → SettingsPage-BpfcSjUA.js} +1 -1
  89. package/web-app/dist/assets/{ShowcasePage-DrTdxO4y.js → ShowcasePage-BqBakC4K.js} +1 -1
  90. package/web-app/dist/assets/{SystemSettingsPage-C9Mqs6Rd.js → SystemSettingsPage-CZLu5VB0.js} +1 -1
  91. package/web-app/dist/assets/{TeamsPage-CUGPdSWo.js → TeamsPage-D55S1jKz.js} +1 -1
  92. package/web-app/dist/assets/{TemplatesPage-CNraDY0F.js → TemplatesPage-D3SydvxN.js} +1 -1
  93. package/web-app/dist/assets/{TerminalOutput-BIu_6Pea.js → TerminalOutput-hNg8G1-e.js} +1 -1
  94. package/web-app/dist/assets/{activity-Bk-kgqaf.js → activity-D2C0VagO.js} +1 -1
  95. package/web-app/dist/assets/{bell-BXmUdmo8.js → bell-CMvYi36w.js} +1 -1
  96. package/web-app/dist/assets/{bot-CiuzXxUR.js → bot-BvtQ6lmo.js} +1 -1
  97. package/web-app/dist/assets/{check-BEzjXppd.js → check-B13xkXed.js} +1 -1
  98. package/web-app/dist/assets/{chevron-left-AYWCXHf8.js → chevron-left-emu6r49E.js} +1 -1
  99. package/web-app/dist/assets/{circle-alert-BNg2uSRq.js → circle-alert-CExlwjuy.js} +1 -1
  100. package/web-app/dist/assets/{clock-DTj0kkGT.js → clock-D7Uas3oL.js} +1 -1
  101. package/web-app/dist/assets/{cloud-x4nTDBLT.js → cloud-CkB4S86C.js} +1 -1
  102. package/web-app/dist/assets/{code-xml-BVh_MLrk.js → code-xml-SL9IIWIn.js} +1 -1
  103. package/web-app/dist/assets/{database-DdfBaowG.js → database-BQFkd7t1.js} +1 -1
  104. package/web-app/dist/assets/{dollar-sign-XuYFmAOY.js → dollar-sign-qHmnNYsU.js} +1 -1
  105. package/web-app/dist/assets/{file-code-corner-D4cRnmeL.js → file-code-corner-C2YUDP0K.js} +1 -1
  106. package/web-app/dist/assets/{file-plus-CyoVlHc_.js → file-plus-C_ooIkDe.js} +1 -1
  107. package/web-app/dist/assets/{globe-Y6IK2RPW.js → globe-CQ-GL485.js} +1 -1
  108. package/web-app/dist/assets/{hammer-BKzr9VZI.js → hammer-U05L_D7V.js} +1 -1
  109. package/web-app/dist/assets/{index-B20cSx5G.js → index-CooHd7I-.js} +3 -3
  110. package/web-app/dist/assets/{layers-DebNOhGS.js → layers-Buo17rjW.js} +1 -1
  111. package/web-app/dist/assets/{loader-circle-DyGbrEgd.js → loader-circle-15vK3oV1.js} +1 -1
  112. package/web-app/dist/assets/{lock-BKPpyt20.js → lock-BeXLebuJ.js} +1 -1
  113. package/web-app/dist/assets/{package-egF5Wi4y.js → package-MVh_6-6R.js} +1 -1
  114. package/web-app/dist/assets/{plus-OiEgKIc-.js → plus-Dh_nd9vS.js} +1 -1
  115. package/web-app/dist/assets/{refresh-cw-CzKvrONq.js → refresh-cw-C9cBJEAT.js} +1 -1
  116. package/web-app/dist/assets/{rotate-ccw-Bu2mII0p.js → rotate-ccw-D3PAtzST.js} +1 -1
  117. package/web-app/dist/assets/{scroll-text-CSkiyax8.js → scroll-text-DZCoXQjo.js} +1 -1
  118. package/web-app/dist/assets/{server-DlPthJFw.js → server-OCOLI5J_.js} +1 -1
  119. package/web-app/dist/assets/{shield-alert-CbpHWQQX.js → shield-alert-oVhmf1_h.js} +1 -1
  120. package/web-app/dist/assets/{thumbs-up-DgGpZe-Q.js → thumbs-up-B-kbX4vN.js} +1 -1
  121. package/web-app/dist/assets/{trash-2-BV3GlCB-.js → trash-2-EL6moveW.js} +1 -1
  122. package/web-app/dist/assets/{trending-down-Y4TJtXhD.js → trending-down-Cl3kjpsx.js} +1 -1
  123. package/web-app/dist/assets/{trending-up-DsDNoHZY.js → trending-up-DST7I6M2.js} +1 -1
  124. package/web-app/dist/assets/{upload-gkThrc_I.js → upload-CUOT780G.js} +1 -1
  125. package/web-app/dist/assets/{usePolling-jpNSeNAe.js → usePolling-Djmt90eb.js} +1 -1
  126. package/web-app/dist/assets/{user-3Zez1WOK.js → user-BRBohA6J.js} +1 -1
  127. package/web-app/dist/index.html +1 -1
  128. package/docs/ARCHITECTURE-OVERVIEW.md +0 -209
  129. package/docs/AUTONOMI-ECOSYSTEM.md +0 -107
  130. package/docs/COCKPIT-SPEC.md +0 -72
  131. package/docs/COCKPIT-UX-MANDATE.md +0 -53
  132. package/docs/COMPETITIVE-ANALYSIS.md +0 -303
  133. package/docs/COMPETITIVE-NEXT-10.md +0 -316
  134. package/docs/COMPETITIVE-RALPH-ZEROSHOT-2026-07-08.md +0 -81
  135. package/docs/DASHBOARD-9.12-EVIDENCE.md +0 -97
  136. package/docs/DASHBOARD-ARCHITECTURE.md +0 -425
  137. package/docs/DASHBOARD_V2_CHECKLIST.md +0 -243
  138. package/docs/DEMOS.md +0 -63
  139. package/docs/ENTERPRISE-IDENTITY-ROADMAP.md +0 -206
  140. package/docs/EVIDENCE-RECEIPT-BUILD-APPLICABILITY.md +0 -79
  141. package/docs/FEAT-PRDREUSE-DOCKER-PLAN.md +0 -144
  142. package/docs/GATE-FAILURE-TRIAGE.md +0 -254
  143. package/docs/HANDOFF-2026-08-03.md +0 -439
  144. package/docs/LOOP-CANDIDATE-PROPOSAL-v1.md +0 -167
  145. package/docs/LOOP-HARNESS-AUDIT.md +0 -684
  146. package/docs/MERGE-DEDUP-MAP.md +0 -420
  147. package/docs/MERGE-ROUTE-MAP.md +0 -139
  148. package/docs/MODEL-REGISTRY-PLAN.md +0 -155
  149. package/docs/OUTCOME-FRONTIER.md +0 -536
  150. package/docs/P2-SPEC-ROBUSTNESS-PLAN.md +0 -192
  151. package/docs/PLANS-INDEX.md +0 -32
  152. package/docs/PRD-REUSE-DONE-RECOGNITION-PLAN.md +0 -536
  153. package/docs/PROMPT-ABLATION-RESULT.md +0 -97
  154. package/docs/R4-TRUST-TRAJECTORY-DESIGN.md +0 -127
  155. package/docs/R5-AUTO-WIKI-DESIGN.md +0 -137
  156. package/docs/R6-ROLLBACK-CHECKPOINT-PLAN.md +0 -107
  157. package/docs/R7-ZERO-CONFIG-FIRST-RUN-PLAN.md +0 -137
  158. package/docs/R8-SHAREABLE-TEAM-ASSETS-PLAN.md +0 -129
  159. package/docs/R9-OPEN-CORE-HOOKS-PLAN.md +0 -113
  160. package/docs/RARV-C-100X-PLAN.md +0 -286
  161. package/docs/RARV-C-LOOP-EFFICIENCY-PLAN.md +0 -470
  162. package/docs/SHAREABLE-PROOF-PLAN.md +0 -194
  163. package/docs/SONNET5-DEFAULT-PLAN.md +0 -157
  164. package/docs/SPEED-AND-FIRST-PASS-PLAN.md +0 -281
  165. package/docs/STALE-STATE-AUDIT.md +0 -174
  166. package/docs/SYNERGY-TASKS.md +0 -143
  167. package/docs/TASKLIST-ACCURACY-PLAN.md +0 -355
  168. package/docs/TOP-100-BACKLOG.md +0 -159
  169. package/docs/V8-ACCEPTANCE-TRIAGE-2026-07-24.md +0 -114
  170. package/docs/V8-COMPLEXITY-AUDIT-2026-07-24.md +0 -45
  171. package/docs/V8-MAJOR-RELEASE-PLAN.md +0 -137
  172. package/docs/V8-OVERNIGHT-PLAN-2026-07-25.md +0 -82
  173. package/docs/V8-SDK-RESEARCH-RAW.md +0 -129
  174. package/docs/WELCOME-OPENER-PLAN.md +0 -106
  175. package/docs/adoption-baseline-2026-07-31.md +0 -84
  176. package/docs/architecture/bmad-integration-epic.md +0 -271
  177. package/docs/architecture/bmad-integration-review.md +0 -86
  178. package/docs/architecture/bmad-integration-validation.md +0 -249
  179. package/docs/architecture/bmad-loki-voice-agent-council-analysis.md +0 -61
  180. package/docs/auto-claude-comparison.md +0 -250
  181. package/docs/bug-fixes/agent-01-cli-fixes.md +0 -101
  182. package/docs/bug-fixes/agent-02-purplelab-fixes.md +0 -88
  183. package/docs/bug-fixes/agent-03-dashboard-fixes.md +0 -119
  184. package/docs/bug-fixes/agent-04-memory-fixes.md +0 -105
  185. package/docs/bug-fixes/agent-05-provider-fixes.md +0 -86
  186. package/docs/bug-fixes/agent-06-integration-fixes.md +0 -101
  187. package/docs/bug-fixes/agent-07-dash-run-fixes.md +0 -101
  188. package/docs/bug-fixes/agent-08-docker-fixes.md +0 -164
  189. package/docs/bug-fixes/agent-09-e2e-build-fixes.md +0 -69
  190. package/docs/bug-fixes/agent-10-e2e-fullstack-fixes.md +0 -102
  191. package/docs/bug-fixes/agent-11-e2e-session-fixes.md +0 -70
  192. package/docs/bug-fixes/agent-12-scenario-fixes.md +0 -120
  193. package/docs/bug-fixes/agent-13-enterprise-fixes.md +0 -143
  194. package/docs/bug-fixes/agent-14-uat-newuser-fixes.md +0 -88
  195. package/docs/bug-fixes/agent-15-uat-poweruser-fixes.md +0 -132
  196. package/docs/bug-fixes/agent-19-code-review.md +0 -316
  197. package/docs/bug-fixes/agent-20-architecture-review.md +0 -331
  198. package/docs/competitive/bolt-new-analysis.md +0 -579
  199. package/docs/competitive/emergence-others-analysis.md +0 -605
  200. package/docs/competitive/replit-lovable-analysis.md +0 -622
  201. package/docs/dashboard-guide.md +0 -487
  202. package/docs/enterprise/migration.md +0 -265
  203. package/docs/history/one-run-audit.md +0 -304
  204. package/docs/plans/FORGE-AUTONOMOUS-QUEUE.md +0 -312
  205. package/docs/plans/ULTRAPLAN-FORGE-BAAS.md +0 -612
  206. package/docs/plans/UT2-6-LSP-DIAGNOSTIC-BROADCAST.md +0 -394
  207. package/docs/prd-purple-lab-ide.md +0 -152
  208. package/docs/prd-purple-lab-platform-v2.md +0 -223
  209. package/docs/prd-purple-lab-platform.md +0 -319
  210. package/docs/retrospectives/v7.5.15-fleet-postmortem.md +0 -325
  211. package/docs/retrospectives/v7.5.15-honesty-audit.md +0 -136
  212. package/docs/retrospectives/v7.5.15-llm-failure-modes.md +0 -49
  213. package/docs/show-hn-post.md +0 -46
  214. package/docs/test-scenarios/enterprise-scenarios.md +0 -732
  215. package/docs/thick2thin.md +0 -173
@@ -14,6 +14,7 @@ var __export = (target, all) => {
14
14
  set: __exportSetter.bind(all, name)
15
15
  });
16
16
  };
17
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
17
18
  var __require = import.meta.require;
18
19
 
19
20
  // node_modules/yaml/dist/nodes/identity.js
@@ -6958,9 +6959,292 @@ var require_public_api = __commonJS((exports) => {
6958
6959
  exports.stringify = stringify;
6959
6960
  });
6960
6961
 
6962
+ // ../../loki-ts/src/util/paths.ts
6963
+ import { resolve as resolve7, dirname as dirname6 } from "path";
6964
+ import { fileURLToPath } from "url";
6965
+ import { existsSync as existsSync14 } from "fs";
6966
+ import { homedir as homedir7 } from "os";
6967
+ function findRepoRoot() {
6968
+ let dir = HERE;
6969
+ for (let i = 0;i < 6; i++) {
6970
+ if (existsSync14(resolve7(dir, "VERSION")) && existsSync14(resolve7(dir, "autonomy/run.sh"))) {
6971
+ return dir;
6972
+ }
6973
+ const parent = dirname6(dir);
6974
+ if (parent === dir)
6975
+ break;
6976
+ dir = parent;
6977
+ }
6978
+ return resolve7(HERE, "..", "..", "..");
6979
+ }
6980
+ function homeLokiDir() {
6981
+ return resolve7(homedir7(), ".loki");
6982
+ }
6983
+ var HERE, REPO_ROOT;
6984
+ var init_paths = __esm(() => {
6985
+ HERE = dirname6(fileURLToPath(import.meta.url));
6986
+ REPO_ROOT = findRepoRoot();
6987
+ });
6988
+
6989
+ // ../../loki-ts/src/features/lean_prefix.ts
6990
+ var LEAN_PREFIX, STAGE_PREFIX;
6991
+ var init_lean_prefix = __esm(() => {
6992
+ LEAN_PREFIX = "You are Loki, an autonomous coding agent. Follow the task prompt exactly " + "and report only what you did.";
6993
+ STAGE_PREFIX = "You are Loki, an autonomous coding agent working one stage of a run. " + "Follow the stage prompt exactly, including the role it gives you and the rules it sets, " + "and report only what you did. " + "Stage-specific instructions and the task follow this block.";
6994
+ });
6995
+
6996
+ // ../../loki-ts/src/util/claude_model.ts
6997
+ var FAMILY_ALIASES;
6998
+ var init_claude_model = __esm(() => {
6999
+ init_paths();
7000
+ FAMILY_ALIASES = new Set(["haiku", "sonnet", "opus", "fable"]);
7001
+ });
7002
+
7003
+ // ../../loki-ts/src/runner/router/flag.ts
7004
+ function routerMode(env = process.env) {
7005
+ const v = (env.LOKI_ROUTER ?? "").trim().toLowerCase();
7006
+ if (v === "0" || v === "false" || v === "off")
7007
+ return "opt-out";
7008
+ if (v === "1" || v === "true" || v === "on")
7009
+ return "on";
7010
+ return "off";
7011
+ }
7012
+ var routerEnabled = (env = process.env) => routerMode(env) === "on";
7013
+
7014
+ // ../../loki-ts/src/engine10/cost.ts
7015
+ import { mkdirSync as mkdirSync6, readdirSync as readdirSync9, readFileSync as readFileSync19, writeFileSync as writeFileSync9 } from "fs";
7016
+ import { join as join27 } from "path";
7017
+ function routerTelemetryOn(env = process.env) {
7018
+ return routerEnabled(env);
7019
+ }
7020
+ function num3(v) {
7021
+ return typeof v === "number" && Number.isFinite(v) ? v : 0;
7022
+ }
7023
+ function resultCostPath(lokiRoot, iteration) {
7024
+ return join27(lokiRoot, "metrics", `result-cost-${iteration}.json`);
7025
+ }
7026
+ function sumResultCosts(lokiRoot, iterations) {
7027
+ const out2 = {
7028
+ usd: null,
7029
+ partialUsd: 0,
7030
+ measuredCount: 0,
7031
+ totalCount: iterations.length,
7032
+ input_tokens: 0,
7033
+ output_tokens: 0,
7034
+ cache_read_tokens: 0,
7035
+ cache_creation_tokens: 0,
7036
+ ...routerTelemetryOn() ? { router: {
7037
+ requests_total: 0,
7038
+ requests_over_100k: 0,
7039
+ over_100k_input_tokens: 0,
7040
+ over_100k_output_tokens: 0,
7041
+ advisor_calls: 0,
7042
+ advisor_input_tokens: 0,
7043
+ advisor_output_tokens: 0
7044
+ } } : {},
7045
+ model: null,
7046
+ source: "",
7047
+ missing: []
7048
+ };
7049
+ const sources2 = [];
7050
+ let usd = 0;
7051
+ for (const iter of iterations) {
7052
+ const path = resultCostPath(lokiRoot, iter);
7053
+ let rec;
7054
+ try {
7055
+ rec = JSON.parse(readFileSync19(path, "utf8"));
7056
+ } catch {
7057
+ out2.missing.push(iter);
7058
+ continue;
7059
+ }
7060
+ const inTok = num3(rec["input_tokens"]);
7061
+ const outTok = num3(rec["output_tokens"]);
7062
+ const cacheR = num3(rec["cache_read_tokens"]);
7063
+ const cacheC = num3(rec["cache_creation_tokens"]);
7064
+ out2.input_tokens += inTok;
7065
+ out2.output_tokens += outTok;
7066
+ out2.cache_read_tokens += cacheR;
7067
+ out2.cache_creation_tokens += cacheC;
7068
+ if (out2.router)
7069
+ out2.router["requests_total"] += num3(rec["requests_total"]);
7070
+ if (out2.router)
7071
+ out2.router["requests_over_100k"] += num3(rec["requests_over_100k"]);
7072
+ if (out2.router)
7073
+ out2.router["over_100k_input_tokens"] += num3(rec["over_100k_input_tokens"]);
7074
+ if (out2.router)
7075
+ out2.router["over_100k_output_tokens"] += num3(rec["over_100k_output_tokens"]);
7076
+ if (out2.router)
7077
+ out2.router["advisor_calls"] += num3(rec["advisor_calls"]);
7078
+ if (out2.router)
7079
+ out2.router["advisor_input_tokens"] += num3(rec["advisor_input_tokens"]);
7080
+ if (out2.router)
7081
+ out2.router["advisor_output_tokens"] += num3(rec["advisor_output_tokens"]);
7082
+ if (typeof rec["model"] === "string" && rec["model"])
7083
+ out2.model = rec["model"];
7084
+ sources2.push(path);
7085
+ const c = rec["total_cost_usd"];
7086
+ const unmetered = rec["source"] === UNMETERED;
7087
+ if (unmetered)
7088
+ out2.unmetered = true;
7089
+ const noUsage = !unmetered && inTok === 0 && outTok === 0 && cacheR === 0 && cacheC === 0;
7090
+ if (typeof c !== "number" || !Number.isFinite(c) || noUsage) {
7091
+ out2.missing.push(iter);
7092
+ continue;
7093
+ }
7094
+ usd += c;
7095
+ out2.partialUsd += c;
7096
+ out2.measuredCount++;
7097
+ }
7098
+ out2.source = sources2.join(",");
7099
+ if (iterations.length > 0 && out2.missing.length === 0)
7100
+ out2.usd = usd;
7101
+ return out2;
7102
+ }
7103
+ var UNMETERED = "cli-invoker-unmetered";
7104
+ var init_cost = () => {};
7105
+
7106
+ // ../../loki-ts/src/runner/budget.ts
7107
+ import { existsSync as existsSync16, mkdirSync as mkdirSync7, readdirSync as readdirSync10, readFileSync as readFileSync20, renameSync as renameSync4, writeFileSync as writeFileSync10 } from "fs";
7108
+ import { dirname as dirname8, join as join28, resolve as resolve9 } from "path";
7109
+ import { fileURLToPath as fileURLToPath2 } from "url";
7110
+ function _loadPricing() {
7111
+ try {
7112
+ const moduleDir = dirname8(fileURLToPath2(import.meta.url));
7113
+ const jsonPath = resolve9(moduleDir, "..", "..", "data", "model-pricing.json");
7114
+ if (!existsSync16(jsonPath))
7115
+ return _FALLBACK_PRICING;
7116
+ const raw2 = JSON.parse(readFileSync20(jsonPath, "utf8"));
7117
+ const pricing2 = raw2["pricing"];
7118
+ if (!pricing2 || typeof pricing2 !== "object")
7119
+ return _FALLBACK_PRICING;
7120
+ const out2 = {};
7121
+ for (const [key, value] of Object.entries(pricing2)) {
7122
+ if (value !== null && typeof value === "object" && typeof value.input === "number" && typeof value.output === "number") {
7123
+ const _e = value;
7124
+ out2[key] = {
7125
+ input: _e.input,
7126
+ output: _e.output,
7127
+ ...typeof _e.cache_read === "number" ? { cache_read: _e.cache_read } : {},
7128
+ ...typeof _e.cache_write === "number" ? { cache_write: _e.cache_write } : {},
7129
+ ...typeof _e.cache_write_5m === "number" ? { cache_write_5m: _e.cache_write_5m } : {},
7130
+ ...typeof _e.cache_write_1h === "number" ? { cache_write_1h: _e.cache_write_1h } : {},
7131
+ ..._e.over_100k && typeof _e.over_100k.input === "number" && typeof _e.over_100k.output === "number" ? { over_100k: _e.over_100k } : {}
7132
+ };
7133
+ }
7134
+ }
7135
+ for (const k of Object.keys(_FALLBACK_PRICING)) {
7136
+ if (!(k in out2))
7137
+ return _FALLBACK_PRICING;
7138
+ }
7139
+ return out2;
7140
+ } catch {
7141
+ return _FALLBACK_PRICING;
7142
+ }
7143
+ }
7144
+ var _FALLBACK_PRICING, PRICING;
7145
+ var init_budget = __esm(() => {
7146
+ init_paths();
7147
+ init_cost();
7148
+ _FALLBACK_PRICING = {
7149
+ fable: { input: 10, output: 50, cache_read: 0.25, cache_write: 12.5, cache_write_5m: 12.5, cache_write_1h: 20 },
7150
+ opus: { input: 4, output: 20, cache_read: 0.2, cache_write: 5, cache_write_5m: 5, cache_write_1h: 8 },
7151
+ sonnet: { input: 2, output: 10, cache_read: 0.1, cache_write: 2.5, cache_write_5m: 2.5, cache_write_1h: 4 },
7152
+ haiku: {
7153
+ input: 0.1,
7154
+ output: 0.5,
7155
+ cache_read: 0.01,
7156
+ cache_write: 0.125,
7157
+ cache_write_5m: 0.125,
7158
+ cache_write_1h: 0.2,
7159
+ over_100k: { input: 0.5, output: 2.5, cache_read: 0.05, cache_write: 0.625, cache_write_5m: 0.625, cache_write_1h: 1 }
7160
+ },
7161
+ "claude-haiku-4-5": { input: 1, output: 5, cache_read: 0.1, cache_write: 1.25, cache_write_5m: 1.25, cache_write_1h: 2 },
7162
+ "claude-haiku-5-5": {
7163
+ input: 0.1,
7164
+ output: 0.5,
7165
+ cache_read: 0.01,
7166
+ cache_write: 0.125,
7167
+ over_100k: { input: 0.5, output: 2.5, cache_read: 0.05, cache_write: 0.625 }
7168
+ },
7169
+ "gpt-5.3-codex": { input: 1.75, output: 14, cache_read: 0.175, cache_write: 2.1875 }
7170
+ };
7171
+ PRICING = Object.freeze(_loadPricing());
7172
+ });
7173
+
7174
+ // ../../loki-ts/src/util/shell.ts
7175
+ async function readStreamCapped(stream, maxBytes = MAX_STDOUT_BYTES) {
7176
+ const reader = stream.getReader();
7177
+ const decoder = new TextDecoder;
7178
+ let out2 = "";
7179
+ let total = 0;
7180
+ try {
7181
+ while (total < maxBytes) {
7182
+ const { done, value } = await reader.read();
7183
+ if (done)
7184
+ break;
7185
+ if (!value)
7186
+ continue;
7187
+ total += value.byteLength;
7188
+ if (total > maxBytes) {
7189
+ const keep = value.byteLength - (total - maxBytes);
7190
+ out2 += decoder.decode(value.subarray(0, keep), { stream: true });
7191
+ break;
7192
+ }
7193
+ out2 += decoder.decode(value, { stream: true });
7194
+ }
7195
+ out2 += decoder.decode();
7196
+ } finally {
7197
+ try {
7198
+ await reader.cancel();
7199
+ } catch {}
7200
+ reader.releaseLock();
7201
+ }
7202
+ return out2;
7203
+ }
7204
+ async function run(argv, opts = {}) {
7205
+ const proc = Bun.spawn({
7206
+ cmd: [...argv],
7207
+ stdout: "pipe",
7208
+ stderr: "pipe",
7209
+ env: opts.env ? { ...process.env, ...opts.env } : process.env,
7210
+ cwd: opts.cwd
7211
+ });
7212
+ let timer;
7213
+ let killTimer;
7214
+ if (opts.timeoutMs && opts.timeoutMs > 0) {
7215
+ timer = setTimeout(() => {
7216
+ try {
7217
+ proc.kill("SIGTERM");
7218
+ } catch {}
7219
+ killTimer = setTimeout(() => {
7220
+ try {
7221
+ proc.kill("SIGKILL");
7222
+ } catch {}
7223
+ }, 2000);
7224
+ }, opts.timeoutMs);
7225
+ }
7226
+ try {
7227
+ const [stdout, stderr, exitCode] = await Promise.all([
7228
+ readStreamCapped(proc.stdout),
7229
+ new Response(proc.stderr).text(),
7230
+ proc.exited
7231
+ ]);
7232
+ return { stdout, stderr, exitCode };
7233
+ } finally {
7234
+ if (timer)
7235
+ clearTimeout(timer);
7236
+ if (killTimer)
7237
+ clearTimeout(killTimer);
7238
+ }
7239
+ }
7240
+ var MAX_STDOUT_BYTES;
7241
+ var init_shell = __esm(() => {
7242
+ MAX_STDOUT_BYTES = 16 * 1024 * 1024;
7243
+ });
7244
+
6961
7245
  // src/server/app.ts
6962
- import { existsSync as existsSync24, readFileSync as readFileSync31, statSync as statSync15 } from "fs";
6963
- import { join as join40, resolve as resolve8, sep as sep14 } from "path";
7246
+ import { existsSync as existsSync33, readFileSync as readFileSync40, statSync as statSync17 } from "fs";
7247
+ import { join as join53, resolve as resolve12, sep as sep14 } from "path";
6964
7248
 
6965
7249
  // node_modules/hono/dist/request/constants.js
6966
7250
  var GET_MATCH_RESULT = Symbol();
@@ -17519,365 +17803,39 @@ function mount20(ctx) {
17519
17803
  }
17520
17804
 
17521
17805
  // src/server/routes/verify.ts
17522
- import { readFileSync as readFileSync29, realpathSync as realpathSync17 } from "fs";
17806
+ import { readFileSync as readFileSync38, realpathSync as realpathSync20 } from "fs";
17523
17807
  import { createPublicKey as createPublicKey5 } from "crypto";
17524
- import { join as join38, sep as sep13 } from "path";
17808
+ import { join as join51, sep as sep13 } from "path";
17525
17809
 
17526
17810
  // ../../loki-ts/src/engine10/verify_cmd.ts
17527
- import { existsSync as existsSync22, readdirSync as readdirSync13, readFileSync as readFileSync28, statSync as statSync14 } from "fs";
17528
- import { dirname as dirname14, join as join37 } from "path";
17529
- import { createHash as createHash10, createPublicKey as createPublicKey4, verify as verify3 } from "crypto";
17530
-
17531
- // ../../loki-ts/src/util/paths.ts
17532
- import { resolve as resolve7, dirname as dirname6 } from "path";
17533
- import { fileURLToPath } from "url";
17534
- import { existsSync as existsSync14 } from "fs";
17535
- var HERE = dirname6(fileURLToPath(import.meta.url));
17536
- function findRepoRoot() {
17537
- let dir = HERE;
17538
- for (let i = 0;i < 6; i++) {
17539
- if (existsSync14(resolve7(dir, "VERSION")) && existsSync14(resolve7(dir, "autonomy/run.sh"))) {
17540
- return dir;
17541
- }
17542
- const parent = dirname6(dir);
17543
- if (parent === dir)
17544
- break;
17545
- dir = parent;
17546
- }
17547
- return resolve7(HERE, "..", "..", "..");
17548
- }
17549
- var REPO_ROOT = findRepoRoot();
17811
+ init_paths();
17812
+ import { existsSync as existsSync31, readdirSync as readdirSync15, readFileSync as readFileSync37, statSync as statSync16 } from "fs";
17813
+ import { dirname as dirname22, join as join50 } from "path";
17814
+ import { createHash as createHash12, createPublicKey as createPublicKey4, verify as verify3 } from "crypto";
17550
17815
 
17551
17816
  // ../../loki-ts/src/engine10/stages/seal.ts
17552
- import { createHash as createHash9, randomBytes as randomBytes3, createPrivateKey, createPublicKey as createPublicKey2, generateKeyPairSync, sign } from "crypto";
17553
- import { chmodSync as chmodSync5, existsSync as existsSync21, readdirSync as readdirSync12, linkSync, mkdirSync as mkdirSync10, readFileSync as readFileSync26, statSync as statSync13, unlinkSync as unlinkSync4, writeFileSync as writeFileSync13 } from "fs";
17554
- import { homedir as homedir7 } from "os";
17555
- import { basename as basename11, dirname as dirname13, join as join36 } from "path";
17817
+ import { createHash as createHash11, randomBytes as randomBytes3, createPrivateKey, createPublicKey as createPublicKey2, generateKeyPairSync, sign } from "crypto";
17818
+ import { chmodSync as chmodSync5, existsSync as existsSync30, readdirSync as readdirSync14, linkSync, mkdirSync as mkdirSync17, readFileSync as readFileSync35, statSync as statSync15, unlinkSync as unlinkSync5, writeFileSync as writeFileSync18 } from "fs";
17819
+ import { homedir as homedir8 } from "os";
17820
+ import { basename as basename17, dirname as dirname21, join as join49 } from "path";
17556
17821
 
17557
- // ../../loki-ts/src/e10ext/assert_delta.ts
17558
- import { execFileSync as execFileSync4 } from "child_process";
17559
- import { mkdtempSync as mkdtempSync2, readFileSync as readFileSync18, rmSync as rmSync4 } from "fs";
17822
+ // ../../loki-ts/src/util/mutation_proof.ts
17823
+ import { existsSync as existsSync15, mkdirSync as mkdirSync5, mkdtempSync as mkdtempSync2, readFileSync as readFileSync18, rmSync as rmSync4, symlinkSync, writeFileSync as writeFileSync8 } from "fs";
17560
17824
  import { tmpdir as tmpdir3 } from "os";
17561
- import { join as join26 } from "path";
17562
- import { basename as basename8 } from "path";
17563
- var WEAKENED = { verdict: "weakened", changes: [] };
17564
- var PY = String.raw`
17565
- import ast, copy, io, json, re, sys, tokenize
17566
- d = json.load(sys.stdin)
17567
- bs, hs, task = d["base"], d["head"], d["task"]
17568
- def out(v, it=()):
17569
- print(json.dumps({"verdict": v, "items": list(it)}))
17570
- sys.exit(0)
17571
- if "\r" in bs or "\r" in hs or "\t" in bs or "\t" in hs:
17572
- out("weakened")
17573
- bt, ht = ast.parse(bs), ast.parse(hs)
17574
- # every byte outside a literal token (comments, blank lines, spacing, other code) must be identical
17575
- def template(src):
17576
- lines = src.split("\n")
17577
- starts, o = [], 0
17578
- for ln in lines:
17579
- starts.append(o)
17580
- o += len(ln) + 1
17581
- spans = [(starts[t.start[0] - 1] + t.start[1], starts[t.end[0] - 1] + t.end[1])
17582
- for t in tokenize.generate_tokens(io.StringIO(src).readline) if t.type in (tokenize.STRING, tokenize.NUMBER)]
17583
- r, pos = [], 0
17584
- for a, b in spans:
17585
- r.append(src[pos:a] + "\0")
17586
- pos = b
17587
- return "".join(r) + src[pos:]
17588
- if template(bs) != template(hs):
17589
- out("weakened")
17590
- class Norm(ast.NodeTransformer):
17591
- def visit_Constant(self, n):
17592
- return ast.copy_location(ast.Constant(value="<" + type(n.value).__name__ + ">"), n)
17593
- def norm(t):
17594
- return ast.dump(Norm().visit(copy.deepcopy(t)))
17595
- # only what pytest collects: module-level test functions and methods of Test* classes without __init__
17596
- def tests(t):
17597
- r = []
17598
- for n in t.body:
17599
- if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef)) and n.name.startswith("test"):
17600
- r.append(n)
17601
- elif isinstance(n, ast.ClassDef) and n.name.startswith("Test") \
17602
- and not any(isinstance(m, (ast.FunctionDef, ast.AsyncFunctionDef)) and m.name == "__init__" for m in n.body):
17603
- r += [m for m in n.body if isinstance(m, (ast.FunctionDef, ast.AsyncFunctionDef)) and m.name.startswith("test")]
17604
- return r
17605
- def direct(f):
17606
- return [a for a in f.body if isinstance(a, ast.Assert)]
17607
- def tables(t):
17608
- return [n.args[1] for n in ast.walk(t) if isinstance(n, ast.Call) and getattr(n.func, "attr", "") == "parametrize"
17609
- and len(n.args) > 1 and isinstance(n.args[1], (ast.List, ast.Tuple))]
17610
- def stripped(t):
17611
- c = copy.deepcopy(t)
17612
- for tb in tables(c):
17613
- tb.elts = []
17614
- return c
17615
- def consts(t):
17616
- return [n for n in ast.walk(t) if isinstance(n, ast.Constant)]
17617
- def shadowed(t):
17618
- for scope in [t] + [n for n in t.body if isinstance(n, ast.ClassDef)]:
17619
- names = [n.name for n in scope.body if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef)) and n.name.startswith("test")]
17620
- if len(names) != len(set(names)):
17621
- return True
17622
- return False
17623
- if shadowed(bt) or shadowed(ht):
17624
- out("weakened")
17625
- sb, sh = stripped(bt), stripped(ht)
17626
- if not tests(ht) or norm(sb) != norm(sh):
17627
- out("weakened")
17628
- for t in (bt, ht):
17629
- if any(isinstance(n, ast.Call) and isinstance(n.func, ast.Name) and n.func.id == "round" for n in ast.walk(t)):
17630
- out("weakened")
17631
- tb, th = tables(bt), tables(ht)
17632
- if any(len(x.elts) != len(y.elts) for x, y in zip(tb, th)):
17633
- out("weakened")
17634
- if any(norm(r) != norm(q) for x, y in zip(tb, th) for r, q in zip(x.elts, y.elts)):
17635
- out("weakened")
17636
- owner = {}
17637
- for f in tests(sh):
17638
- for n in ast.walk(f):
17639
- owner[id(n)] = f
17640
- pairs = [(b, h, owner.get(id(h))) for b, h in zip(consts(sb), consts(sh))]
17641
- fh = {}
17642
- for f in tests(ht):
17643
- for t in tables(f):
17644
- fh[id(t)] = f
17645
- for x, y in zip(tb, th):
17646
- for r, q in zip(x.elts, y.elts):
17647
- pairs += [(b, h, fh.get(id(y))) for b, h in zip(consts(r), consts(q))]
17648
- def eqs(f):
17649
- return [a.test for a in direct(f) if isinstance(a.test, ast.Compare) and len(a.test.ops) == 1 and isinstance(a.test.ops[0], ast.Eq)]
17650
- def dups(t):
17651
- r = {}
17652
- for f in tests(t):
17653
- ds = [ast.dump(a) for a in direct(f)]
17654
- r[f.name] = len(ds) - len(set(ds))
17655
- return r
17656
- dh, db = dups(ht), dups(bt)
17657
- ok = not any(v > db.get(k, 0) for k, v in dh.items())
17658
- # expected side = the right operand of a direct "assert X == Y"
17659
- exp = set()
17660
- for f in tests(sh):
17661
- exp |= {id(c.comparators[0]) for c in eqs(f) if isinstance(c.comparators[0], ast.Constant)}
17662
- for f in tests(ht):
17663
- rights = {id(c.comparators[0]) for c in eqs(f) if isinstance(c.comparators[0], ast.Name)}
17664
- for c in f.decorator_list:
17665
- if isinstance(c, ast.Call) and getattr(c.func, "attr", "") == "parametrize" and len(c.args) > 1 \
17666
- and isinstance(c.args[0], ast.Constant) and isinstance(c.args[0].value, str) and isinstance(c.args[1], (ast.List, ast.Tuple)):
17667
- cols = [x.strip() for x in c.args[0].value.split(",")]
17668
- # a column counts only if every use of its name in the body is the right operand of a direct eq assert
17669
- if any(kw.arg == "indirect" for kw in c.keywords):
17670
- continue
17671
- deco = {id(m) for dd in f.decorator_list for m in ast.walk(dd)}
17672
- uses = {k: [n for n in ast.walk(f) if isinstance(n, ast.Name) and n.id == k and id(n) not in deco] for k in cols}
17673
- # the column must be read at least once, and only as the right operand of a direct eq assert
17674
- solo = {k for k, u in uses.items() if u and all(id(n) in rights for n in u)}
17675
- for r in c.args[1].elts:
17676
- for i, e in enumerate(r.elts if isinstance(r, (ast.Tuple, ast.List)) else [r]):
17677
- if isinstance(e, ast.Constant) and i < len(cols) and cols[i] in solo:
17678
- exp.add(id(e))
17679
- def callees(f):
17680
- r = set()
17681
- for c in eqs(f):
17682
- for n in ast.walk(c.left):
17683
- if isinstance(n, ast.Call):
17684
- k = n.func.id if isinstance(n.func, ast.Name) else getattr(n.func, "attr", "")
17685
- if k:
17686
- r.add(k)
17687
- return r
17688
- def generic(v):
17689
- return v is None or isinstance(v, (bool, bytes)) or (isinstance(v, str) and len(v) <= 3) \
17690
- or (isinstance(v, (int, float)) and abs(v) < 10)
17691
- def in_task(v, f):
17692
- task0 = d["task"]
17693
- t = v if isinstance(v, str) else repr(v)
17694
- if t == "":
17695
- return False
17696
- # bounded by whitespace, string ends or ,;:()[]{}"' only; never glued to - + or a digit group separator
17697
- tok = r"(?<![^\s,;:()\[\]{}\"'])(?<!\d,)" + re.escape(t) + r"(?:(?=[\s,;:()\[\]{}\"']|$)(?!,\d)|\.(?=\s|$))"
17698
- task = re.sub(r"(?<=\d),(?=\d{3}\b)", "", task0)
17699
- if not generic(v):
17700
- return re.search(tok, task) is not None
17701
- # a generic value counts only right next to the identifier the test calls
17702
- return any(re.search(r"\b" + re.escape(k) + r"\b[^\n]{0,40}?" + tok, task) for k in (callees(f) if f else ()))
17703
- items = []
17704
- for b, h, f in pairs:
17705
- if (type(b.value), repr(b.value)) != (type(h.value), repr(h.value)):
17706
- hit = in_task(h.value, f)
17707
- ok = ok and id(h) in exp and hit
17708
- items.append({"line": h.lineno, "old": repr(b.value), "new": repr(h.value), "inTask": hit, "matched": "new"})
17709
- out("value-change" if ok and items else "weakened", items if ok else [])
17710
- `;
17711
- var okStr = (v) => typeof v === "string" && v.length <= 200 && !/[\x00-\x1f\x7f]/.test(v);
17712
- function classifyAssertDelta(inp) {
17713
- const f = basename8(inp.path);
17714
- if (!/^(test_.*|.*_test)\.py$/.test(f))
17715
- return WEAKENED;
17716
- if (inp.headCounts.run !== inp.baseCounts.run || inp.headCounts.skipped !== inp.baseCounts.skipped)
17717
- return WEAKENED;
17718
- let cwd = "";
17719
- try {
17720
- cwd = mkdtempSync2(join26(tmpdir3(), "loki-ad-"));
17721
- const raw2 = execFileSync4("python3", ["-I", "-c", PY], {
17722
- input: JSON.stringify({ path: inp.path, base: inp.base, head: inp.head, task: inp.task }),
17723
- cwd,
17724
- env: process.env,
17725
- stdio: ["pipe", "pipe", "ignore"],
17726
- encoding: "utf8",
17727
- timeout: 20000
17728
- });
17729
- const r = JSON.parse(raw2);
17730
- if (r.verdict !== "value-change" || !Array.isArray(r.items) || r.items.length === 0)
17731
- return WEAKENED;
17732
- const items = [];
17733
- for (const i of r.items) {
17734
- if (!i || typeof i !== "object" || !Number.isInteger(i["line"]) || i["line"] < 1 || !okStr(i["old"]) || !okStr(i["new"]) || i["inTask"] !== true || i["matched"] !== "new")
17735
- return WEAKENED;
17736
- items.push({ line: i["line"], old: i["old"], new: i["new"], matched: "new" });
17737
- }
17738
- return { verdict: "value-change", changes: items.map((i) => `${inp.path}:${i.line} ${i.old} -> ${i.new}`), items };
17739
- } catch {
17740
- return WEAKENED;
17741
- } finally {
17742
- if (cwd)
17743
- rmSync4(cwd, { recursive: true, force: true });
17744
- }
17745
- }
17746
- function assertDeltaNotes(repoDir, baseSha, headRef, path, task, baseCounts, headCounts) {
17747
- if (!baseCounts || !headCounts)
17748
- return null;
17749
- try {
17750
- const show = (ref) => execFileSync4("git", ["show", `${ref}:${path}`], { cwd: repoDir, encoding: "utf8", env: process.env, stdio: ["ignore", "pipe", "ignore"] });
17751
- const head = headRef ? show(headRef) : readFileSync18(join26(repoDir, path), "utf8");
17752
- const r = classifyTestEdit(path, show(baseSha), head, task, baseCounts, headCounts);
17753
- return r[0]?.kind === "literal-only" ? r.map((e) => `assertion value changed (not shown to be required by the task): ${e.file}:${e.line} ${e.old} -> ${e.new}`) : null;
17754
- } catch {
17755
- return null;
17756
- }
17757
- }
17758
- function classifyTestEdit(file, oldText, newText, taskText, baseCounts, headCounts) {
17759
- const weak = [{ kind: "weakened", file, line: 0, old: "", new: "", inTask: false }];
17760
- const r = classifyAssertDelta({ path: file, base: oldText, head: newText, task: taskText, baseCounts, headCounts });
17761
- if (r.verdict !== "value-change" || !r.items?.length)
17762
- return weak;
17763
- return r.items.map((i) => ({ kind: "literal-only", file, line: i.line, old: i.old, new: i.new, inTask: true }));
17764
- }
17765
-
17766
- // ../../loki-ts/src/e10ext/discard.ts
17767
- import { execFileSync as execFileSync5 } from "child_process";
17768
- import { chmodSync as chmodSync4, closeSync as closeSync5, lstatSync as lstatSync4, mkdirSync as mkdirSync5, openSync as openSync5, readFileSync as readFileSync19, realpathSync as realpathSync14, rmdirSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync8 } from "fs";
17769
- import { dirname as dirname7, join as join27, relative, sep as sep9 } from "path";
17770
- function safeRestore(repoDir, f, want, mode) {
17771
- const root = realpathSync14(repoDir), fp = join27(root, f), rel = relative(root, dirname7(fp));
17772
- if (rel.startsWith(".."))
17773
- throw new Error("outside repo");
17774
- let cur = root;
17775
- for (const part of rel === "" ? [] : rel.split(sep9)) {
17776
- cur = join27(cur, part);
17777
- let st2;
17778
- try {
17779
- st2 = lstatSync4(cur);
17780
- } catch {
17781
- mkdirSync5(cur);
17782
- continue;
17783
- }
17784
- if (!st2.isDirectory())
17785
- throw new Error("parent is not a real directory");
17786
- }
17787
- let st;
17788
- try {
17789
- st = lstatSync4(fp);
17790
- } catch {
17791
- st = null;
17792
- }
17793
- if (st?.isFile() && readFileSync19(fp).equals(want)) {
17794
- chmodSync4(fp, mode);
17795
- return;
17796
- }
17797
- if (st) {
17798
- if (st.isDirectory())
17799
- rmdirSync(fp);
17800
- else
17801
- unlinkSync3(fp);
17802
- }
17803
- const fd = openSync5(fp, "wx", mode);
17804
- try {
17805
- writeFileSync8(fd, want);
17806
- } finally {
17807
- closeSync5(fd);
17808
- }
17809
- chmodSync4(fp, mode);
17810
- }
17811
- function alreadySatisfied(o) {
17812
- const b = o.wall?.base_run ?? {};
17813
- return o.intake?.already_satisfied === true || o.implement?.exit === "already_done" || typeof b.pass === "number" && b.pass > 0 && b.fail === 0 && (b.not_run ?? 0) === 0;
17814
- }
17815
- async function discardIfSatisfied(git, base, o, staged, keep, repoDir) {
17816
- if (!alreadySatisfied(o))
17817
- return null;
17818
- const pre = Object.assign(Object.create(null), o.intake?.preexisting_dirty ?? {}), own = new Set([...Array.isArray(o.intake?.preexisting_untracked) ? o.intake.preexisting_untracked : [], ...Object.keys(o.intake?.preexisting_untracked_blobs ?? {})]);
17819
- const gone = staged.filter(({ f }) => !keep.has(f) && !own.has(f) && !Object.hasOwn(pre, f) && !f.startsWith(".loki/")), lit = ["--literal-pathspecs"];
17820
- const del = gone.filter(({ st }) => st === "A").map(({ f }) => f), back = gone.filter(({ st }) => st !== "A").map(({ f }) => f);
17821
- if (del.length > 0 && (await git([...lit, "rm", "-q", "-f", "--", ...del])).code !== 0 || back.length > 0 && (await git([...lit, "restore", `--source=${base}`, "--staged", "--worktree", "--", ...back])).code !== 0 || (await git(["reset", "-q", base])).code !== 0)
17822
- return { status: "failed", data: {}, reason: "already-satisfied discard failed" };
17823
- const notProven = [];
17824
- for (const [f, v] of Object.entries(o.intake?.preexisting_untracked_blobs ?? {})) {
17825
- const fp = join27(repoDir, f);
17826
- try {
17827
- if (v.startsWith("!")) {
17828
- const st = lstatSync4(fp);
17829
- if (`!${st.size}:${st.mtimeMs}:${st.ctimeMs}` !== v)
17830
- throw new Error("changed, not snapshotted");
17831
- continue;
17832
- }
17833
- const [sha2, mode] = v.split(" "), want = execFileSync5("git", ["cat-file", "blob", sha2], { cwd: repoDir, env: process.env, maxBuffer: 1 << 28 });
17834
- safeRestore(repoDir, f, want, parseInt(mode ?? "644", 8));
17835
- } catch {
17836
- notProven.push(f);
17837
- }
17838
- }
17839
- for (const f of Object.keys(pre))
17840
- if (staged.some((s) => s.f === f) && !keep.has(f)) {
17841
- try {
17842
- let m = 420;
17843
- try {
17844
- const l = lstatSync4(join27(repoDir, f));
17845
- if (l.isFile())
17846
- m = l.mode & 511;
17847
- } catch {}
17848
- safeRestore(repoDir, f, execFileSync5("git", ["cat-file", "blob", pre[f]], { cwd: repoDir, env: process.env, maxBuffer: 1 << 28 }), m);
17849
- } catch {
17850
- notProven.push(f);
17851
- }
17852
- }
17853
- return { status: "completed", data: { committed: false, discarded: gone.length, ...notProven.length > 0 ? { not_proven: notProven.map((f) => `pre-existing file not restored: ${f}`) } : {} } };
17854
- }
17855
-
17856
- // ../../loki-ts/src/e10ext/commit_filter.ts
17857
- import { dirname as dirname8 } from "path";
17858
-
17859
- // ../../loki-ts/src/e10ext/preexisting_dirty.ts
17860
- import { execFileSync as execFileSync6 } from "child_process";
17861
- var blob2 = (repoDir, path, env = process.env) => execFileSync6("git", ["hash-object", "-w", "--no-filters", "--", path], { cwd: repoDir, encoding: "utf8", env, stdio: ["ignore", "pipe", "ignore"] }).trim();
17862
- function untouchedSinceIntake(repoDir, recorded, env = process.env) {
17863
- if (!recorded || typeof recorded !== "object")
17864
- return [];
17865
- return Object.entries(recorded).filter(([p, h]) => {
17866
- try {
17867
- return blob2(repoDir, p, env) === h;
17868
- } catch {
17869
- return false;
17870
- }
17871
- }).map(([p]) => p);
17872
- }
17825
+ import { basename as basename8, dirname as dirname7, isAbsolute, join as join26, relative } from "path";
17873
17826
 
17874
17827
  // ../../loki-ts/src/util/safe_git.ts
17875
- import { execFileSync as execFileSync7, spawnSync } from "child_process";
17828
+ import { execFileSync as execFileSync4, spawnSync } from "child_process";
17876
17829
  var SAFE_GIT_CONFIG = ["-c", "core.fsmonitor=", "-c", "core.hooksPath=/dev/null", "-c", "core.sshCommand=", "-c", "protocol.ext.allow=never", "-c", "credential.helper="];
17877
17830
  var CREDENTIAL_CONFIG = ["-c", "core.fsmonitor=", "-c", "core.hooksPath=/dev/null", "-c", "protocol.ext.allow=never"];
17878
17831
  var DRIVER_CONFIG = ["-c", "diff.external=", "-c", "commit.gpgSign=false", "-c", "core.attributesFile=/dev/null"];
17832
+ var ATTRS_OFF = "core.attributesFile=/dev/null";
17833
+ var HOOKS_OFF = "core.hooksPath=/dev/null";
17834
+ var SIGN_OFF = "commit.gpgSign=false";
17879
17835
  var REPO_SCOPES = new Set(["local", "worktree", "command"]);
17880
- var DRIVER_KEY_RE = "^(filter\\..*\\.(clean|smudge|process)|diff\\..*\\.textconv)$";
17836
+ var DRIVER_KEY_RE = "^(filter\\..*\\.(clean|smudge|process)|diff\\..*\\.(textconv|command))$";
17837
+ var PATCH_CMDS = new Set(["diff", "show", "log", "whatchanged"]);
17838
+ var OPT_WITH_VALUE = new Set(["-C", "-c", "--git-dir", "--work-tree", "--namespace", "--exec-path", "--config-env", "--attr-source"]);
17881
17839
  var SECRET_VARS = ["GH_TOKEN", "GITHUB_TOKEN", "GH_ENTERPRISE_TOKEN", "GITHUB_ENTERPRISE_TOKEN", "SSH_AUTH_SOCK"];
17882
17840
  function tokenFreeEnv(env = process.env) {
17883
17841
  const out2 = { ...env };
@@ -17888,6 +17846,7 @@ function tokenFreeEnv(env = process.env) {
17888
17846
  var safeGitEnv = (base = process.env, allowToken = false) => {
17889
17847
  const env = { ...allowToken ? base : tokenFreeEnv(base), GIT_CONFIG_NOSYSTEM: "1" };
17890
17848
  delete env.GIT_ATTR_SOURCE;
17849
+ delete env.GIT_EXTERNAL_DIFF;
17891
17850
  return env;
17892
17851
  };
17893
17852
  function driverKeys(repoDir) {
@@ -17907,62 +17866,253 @@ function driverKeys(repoDir) {
17907
17866
  }
17908
17867
  return [...new Set(keys)];
17909
17868
  }
17910
- var safeGitArgs = (args, allowToken = false, repoDir) => [
17911
- ...allowToken ? CREDENTIAL_CONFIG : SAFE_GIT_CONFIG,
17912
- ...DRIVER_CONFIG,
17913
- ...repoDir ? driverKeys(repoDir).flatMap((k) => ["-c", `${k}=`]) : [],
17914
- ...args
17915
- ];
17916
- var safeGitArgv = (args, allowToken = false, repoDir) => ["git", ...safeGitArgs(args, allowToken, repoDir)];
17917
-
17918
- // ../../loki-ts/src/e10ext/commit_filter.ts
17919
- var parseStaged = (out2) => out2.split("\x00").reduce((a, t, i, all) => i % 2 === 0 && t ? [...a, { st: t, f: all[i + 1] }] : a, []);
17920
- function dropSet(repoDir, staged, preexistingDirty, env = process.env) {
17921
- 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) && dirname8(m) === dirname8(f)) && /(^|\/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|bun\.lockb?|poetry\.lock|Cargo\.lock|go\.sum)$/.test(f));
17869
+ function safeGitArgs(args, allowToken = false, repoDir, keep = {}) {
17870
+ if (keep.userHooks && allowToken)
17871
+ throw new Error("safeGit: userHooks with allowToken is refused (a hook would run holding the credential)");
17872
+ const off = new Set([...keep.repoDrivers ? [ATTRS_OFF] : [], ...keep.userHooks ? [HOOKS_OFF, SIGN_OFF] : []]);
17873
+ const cfg = [...allowToken ? CREDENTIAL_CONFIG : SAFE_GIT_CONFIG, ...DRIVER_CONFIG];
17874
+ const flags = cfg.flatMap((v, i) => i % 2 === 1 && !off.has(v) ? [cfg[i - 1], v] : []);
17875
+ return [...flags, ...repoDir && !keep.repoDrivers ? driverKeys(repoDir).flatMap((k) => ["-c", `${k}=`]) : [], ...noExtDiff(args)];
17876
+ }
17877
+ function noExtDiff(args) {
17878
+ let i = 0;
17879
+ while (i < args.length && args[i].startsWith("-"))
17880
+ i += OPT_WITH_VALUE.has(args[i]) ? 2 : 1;
17881
+ const cmd = args[i];
17882
+ if (cmd === undefined || !PATCH_CMDS.has(cmd))
17883
+ return [...args];
17884
+ const rest = args.slice(i + 1);
17885
+ const end = rest.indexOf("--");
17886
+ const opts = (end < 0 ? rest : rest.slice(0, end)).filter((a) => a !== "--ext-diff" && a !== "--textconv");
17887
+ return [...args.slice(0, i + 1), "--no-ext-diff", "--no-textconv", ...opts, ...end < 0 ? [] : rest.slice(end)];
17888
+ }
17889
+ function safeGit(repoDir, args, opts = {}) {
17890
+ const { env, allowToken, repoDrivers, userHooks, ...rest } = opts;
17891
+ const out2 = execFileSync4("git", safeGitArgs(args, allowToken, repoDir, { repoDrivers, userHooks }), { stdio: ["ignore", "pipe", "ignore"], ...rest, cwd: repoDir, env: safeGitEnv(env ?? process.env, allowToken), encoding: "utf8" });
17892
+ return typeof out2 === "string" ? out2 : "";
17893
+ }
17894
+ function safeGitSpawn(repoDir, args, opts = {}) {
17895
+ const { env, allowToken, repoDrivers, userHooks, ...rest } = opts;
17896
+ let argv;
17897
+ try {
17898
+ argv = safeGitArgs(args, allowToken, repoDir, { repoDrivers, userHooks });
17899
+ } catch (e) {
17900
+ return { pid: 0, output: [], stdout: "", stderr: "", status: null, signal: null, error: e };
17901
+ }
17902
+ return spawnSync("git", argv, { ...rest, cwd: repoDir, env: safeGitEnv(env ?? process.env, allowToken) });
17922
17903
  }
17923
-
17924
- // ../../loki-ts/src/e10ext/scope.ts
17925
- import { basename as basename10, dirname as dirname9 } from "path";
17926
-
17927
- // ../../loki-ts/src/engine10/testmap.ts
17928
- import { basename as basename9, extname, join as join30, relative as relative2, sep as sep11 } from "path";
17929
-
17930
- // ../../loki-ts/src/project_model/discover.ts
17931
- import { existsSync as existsSync16, mkdirSync as mkdirSync6, readFileSync as readFileSync20, rmSync as rmSync5, writeFileSync as writeFileSync9 } from "fs";
17932
- import { join as join29 } from "path";
17933
-
17934
- // ../../loki-ts/src/engine10/types.ts
17935
- var STAGE_BUDGETS = {
17936
- intake: { targetS: 15, limitS: 60 },
17937
- plan: { targetS: 45, limitS: 90 },
17938
- wall: { targetS: 45, limitS: 90 },
17939
- implement: { targetS: 180, limitS: 480 },
17940
- verify: { targetS: 60, limitS: 120 },
17941
- fix: { targetS: 90, limitS: 180 },
17942
- commit: { targetS: 5, limitS: 30 },
17904
+ async function safeGitRun(repoDir, args, opts = {}) {
17905
+ let argv;
17906
+ try {
17907
+ argv = safeGitArgs(args, opts.allowToken, repoDir, { repoDrivers: opts.repoDrivers, userHooks: opts.userHooks });
17908
+ } catch (e) {
17909
+ return { stdout: "", stderr: String(e), exitCode: 128 };
17910
+ }
17911
+ let proc;
17912
+ try {
17913
+ proc = Bun.spawn({ cmd: ["git", ...argv], cwd: repoDir, env: safeGitEnv(opts.env ?? process.env, opts.allowToken), stdin: "ignore", stdout: "pipe", stderr: "pipe", signal: opts.signal });
17914
+ } catch (e) {
17915
+ return { stdout: "", stderr: String(e), exitCode: 127 };
17916
+ }
17917
+ let timer;
17918
+ if (opts.timeoutMs && opts.timeoutMs > 0)
17919
+ timer = setTimeout(() => {
17920
+ try {
17921
+ proc.kill("SIGKILL");
17922
+ } catch {}
17923
+ }, opts.timeoutMs);
17924
+ try {
17925
+ const [stdout, stderr, exitCode] = await Promise.all([new Response(proc.stdout).text(), new Response(proc.stderr).text(), proc.exited]);
17926
+ return { stdout, stderr, exitCode };
17927
+ } finally {
17928
+ if (timer)
17929
+ clearTimeout(timer);
17930
+ }
17931
+ }
17932
+
17933
+ // ../../loki-ts/src/engine10/types.ts
17934
+ var STAGE_BUDGETS = {
17935
+ intake: { targetS: 15, limitS: 60 },
17936
+ plan: { targetS: 45, limitS: 90 },
17937
+ wall: { targetS: 45, limitS: 90 },
17938
+ implement: { targetS: 180, limitS: 480 },
17939
+ verify: { targetS: 60, limitS: 120 },
17940
+ fix: { targetS: 90, limitS: 180 },
17941
+ commit: { targetS: 5, limitS: 30 },
17943
17942
  seal: { targetS: 15, limitS: 60 },
17944
17943
  pr: { targetS: 15, limitS: 60 },
17945
17944
  deep: { targetS: null, limitS: 2700 }
17946
17945
  };
17947
17946
 
17947
+ // ../../loki-ts/src/util/run_cap.ts
17948
+ var MAX_SCOPE_BYTES = 256 * 1024;
17949
+
17950
+ // ../../loki-ts/src/util/mutation_proof.ts
17951
+ var mutationStrict = (env = process.env) => (env["LOKI_MUTATION_STRICT"] ?? "").trim() === "1";
17952
+ var mutationEnabled = (env = process.env) => (env["LOKI_MUTATION_PROOF"] ?? "").trim() !== "0";
17953
+ var LABEL = "test fails without the fix: ";
17954
+ var np = (reason) => ({ outcome: "inconclusive", line: `${LABEL}inconclusive (${reason})` });
17955
+ var MAX_TOTAL_S = 40;
17956
+ var DEP_DIRS = ["node_modules", ".venv", "venv"];
17957
+ var git = (cwd, args, timeout = 30000) => {
17958
+ try {
17959
+ safeGit(cwd, args, { timeout });
17960
+ return { status: 0 };
17961
+ } catch {
17962
+ return { status: 1 };
17963
+ }
17964
+ };
17965
+ function mutationProof(i) {
17966
+ const rels = i.wallFiles.map((f) => isAbsolute(f.path) ? relative(i.repoDir, f.path) : f.path);
17967
+ if (rels.length === 0)
17968
+ return np("no Wall tests");
17969
+ const tests = rels.flatMap((rel) => {
17970
+ const c = i.checks.find((k) => k.name.endsWith(`:${rel}`));
17971
+ const idx = c ? c.name.indexOf(":") : -1;
17972
+ return c && idx > 0 ? [{ runner: c.name.slice(0, idx), path: rel }] : [];
17973
+ });
17974
+ if (tests.length === 0)
17975
+ return np("no recorded Wall test command");
17976
+ if (tests.length !== rels.length)
17977
+ return np("a Wall file has no recorded test command");
17978
+ const budgetS = Math.min(i.timeoutS ?? (Number((i.env ?? process.env)["LOKI_MUTATION_PROOF_TIMEOUT_S"] ?? 30) || 30), MAX_TOTAL_S);
17979
+ const deadline = Date.now() + budgetS * 1000, remaining = () => deadline - Date.now();
17980
+ let parent = null, wt = null, added = false;
17981
+ try {
17982
+ parent = mkdtempSync2(join26(tmpdir3(), "loki-mutproof-"));
17983
+ wt = join26(parent, "wt");
17984
+ const add2 = git(i.repoDir, ["worktree", "add", "--detach", wt, i.baseSha], Math.max(1000, Math.min(30000, remaining())));
17985
+ added = existsSync15(wt) || add2.status === 0;
17986
+ if (add2.status !== 0)
17987
+ return np("could not create the base worktree");
17988
+ for (const rel of rels) {
17989
+ const sealed = join26(i.runDir, "wall", basename8(rel)), src = existsSync15(sealed) ? sealed : join26(i.repoDir, rel);
17990
+ if (!existsSync15(src))
17991
+ return np(`Wall file missing: ${rel}`);
17992
+ mkdirSync5(dirname7(join26(wt, rel)), { recursive: true });
17993
+ writeFileSync8(join26(wt, rel), readFileSync18(src));
17994
+ }
17995
+ for (const rel of rels) {
17996
+ const parts = rel.split("/").slice(0, -1);
17997
+ for (let n2 = 0;n2 <= parts.length; n2++) {
17998
+ const anc = parts.slice(0, n2).join("/");
17999
+ for (const d of DEP_DIRS) {
18000
+ const src = join26(i.repoDir, anc, d), dst = join26(wt, anc, d);
18001
+ if (existsSync15(src) && !existsSync15(dst)) {
18002
+ try {
18003
+ symlinkSync(src, dst);
18004
+ } catch {}
18005
+ }
18006
+ }
18007
+ }
18008
+ }
18009
+ let pass = 0, fail = 0, notRun = 0;
18010
+ for (const t of tests) {
18011
+ if (remaining() <= 0)
18012
+ return np("timeout");
18013
+ const r = (typeof i.runner === "function" ? i.runner(remaining()) : i.runner).run(wt, [t]);
18014
+ pass += r.pass;
18015
+ fail += r.fail;
18016
+ notRun += r.not_run ?? 0;
18017
+ }
18018
+ if (remaining() <= 0 && fail === 0)
18019
+ return np("timeout");
18020
+ if (fail > 0)
18021
+ return { outcome: "yes", line: `${LABEL}yes` };
18022
+ if (pass > 0 && notRun === 0)
18023
+ return { outcome: "no", line: `${LABEL}no (warning: the Wall tests also pass on the old code)` };
18024
+ return np("the Wall command did not execute to a result");
18025
+ } catch (e) {
18026
+ return np(`error: ${String(e?.message ?? e).replace(/\s+/g, " ").slice(0, 120)}`);
18027
+ } finally {
18028
+ if (wt && added)
18029
+ git(i.repoDir, ["worktree", "remove", "--force", wt]);
18030
+ if (parent)
18031
+ rmSync4(parent, { recursive: true, force: true });
18032
+ }
18033
+ }
18034
+
18035
+ // ../../loki-ts/src/engine10/stages/wall.ts
18036
+ import { spawnSync as spawnSync3 } from "child_process";
18037
+ import { existsSync as existsSync21, mkdirSync as mkdirSync9, mkdtempSync as mkdtempSync6, readFileSync as readFileSync25, readdirSync as readdirSync11, realpathSync as realpathSync17, rmSync as rmSync9, writeFileSync as writeFileSync12 } from "fs";
18038
+ import { dirname as dirname11, isAbsolute as isAbsolute5, join as join39, relative as relative5 } from "path";
18039
+ init_lean_prefix();
18040
+
18041
+ // ../../loki-ts/src/features/wall_manifest.ts
18042
+ var MODS = "(?:(?:public|private|protected|static|readonly|abstract|async|get|set|declare|override)\\s+)*";
18043
+ var MEMBER_GRAMMAR = new RegExp(`^(?:@[\\w$.]+(?:\\([^)]*\\))?\\s*)*${MODS}\\*?\\s*(?:[A-Za-z_$][\\w$]*|#[A-Za-z_$][\\w$]*|\\[[^\\]]*\\])\\s*[?!]?\\s*(?:[(<:=]|$)`);
18044
+ // ../../loki-ts/src/engine10/sizing.ts
18045
+ import { existsSync as existsSync17, readFileSync as readFileSync21 } from "fs";
18046
+ import { basename as basename9 } from "path";
18047
+
18048
+ // ../../loki-ts/src/engine10/cache.ts
18049
+ import { createHash as createHash6 } from "crypto";
18050
+ init_paths();
18051
+ import { resolve as resolve8 } from "path";
18052
+ function repoKey(originUrl, repoDir) {
18053
+ const basis = originUrl && originUrl.trim() !== "" ? originUrl : resolve8(repoDir);
18054
+ return createHash6("sha256").update(basis).digest("hex");
18055
+ }
18056
+ function defaultCacheRoot() {
18057
+ return resolve8(homeLokiDir(), "cache", "v10");
18058
+ }
18059
+ function repoCacheDir(key, cacheRoot = defaultCacheRoot()) {
18060
+ return resolve8(cacheRoot, key);
18061
+ }
18062
+
18063
+ // ../../loki-ts/src/engine10/sizing.ts
18064
+ init_claude_model();
18065
+
18066
+ // ../../loki-ts/src/engine10/session.ts
18067
+ init_cost();
18068
+ init_budget();
18069
+ var STDERR_TAIL_BYTES = 64 * 1024;
18070
+ var ADVISOR_MARKED_STAGES = new Set(["plan", "fix"]);
18071
+
18072
+ // ../../loki-ts/src/engine10/sizing.ts
18073
+ function namedFiles(task, map) {
18074
+ return (map?.files ?? []).filter((f) => task.toLowerCase().includes(basename9(f).toLowerCase()));
18075
+ }
18076
+ function loadRepoMap(repomapRef) {
18077
+ if (!repomapRef || !existsSync17(repomapRef))
18078
+ return null;
18079
+ try {
18080
+ return JSON.parse(readFileSync21(repomapRef, "utf8"));
18081
+ } catch {
18082
+ return null;
18083
+ }
18084
+ }
18085
+
18086
+ // ../../loki-ts/src/project_model/resolve.ts
18087
+ import { join as join33 } from "path";
18088
+
18089
+ // ../../loki-ts/src/project_model/discover.ts
18090
+ import { existsSync as existsSync19, mkdirSync as mkdirSync8, readFileSync as readFileSync23, rmSync as rmSync5, writeFileSync as writeFileSync11 } from "fs";
18091
+ import { join as join32 } from "path";
18092
+
18093
+ // ../../loki-ts/src/project_model/gather.ts
18094
+ import { createHash as createHash7 } from "crypto";
18095
+ import { closeSync as closeSync5, lstatSync as lstatSync5, openSync as openSync5, readFileSync as readFileSync22, readSync as readSync4 } from "fs";
18096
+ import { dirname as dirname9, join as join31 } from "path";
18097
+
17948
18098
  // ../../loki-ts/src/project_model/schema.ts
17949
- import { existsSync as existsSync15, lstatSync as lstatSync5, realpathSync as realpathSync15, statSync as statSync11 } from "fs";
17950
- import { isAbsolute, join as join28, normalize, sep as sep10 } from "path";
18099
+ import { existsSync as existsSync18, lstatSync as lstatSync4, realpathSync as realpathSync14, statSync as statSync11 } from "fs";
18100
+ import { isAbsolute as isAbsolute2, join as join30, normalize, sep as sep9 } from "path";
17951
18101
  var PROJECT_MODEL_SCHEMA = "loki.v10.project/1";
17952
18102
  var COMMAND_KINDS = ["test", "lint", "build", "start"];
17953
18103
  var isRec = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
17954
18104
  var isStr = (v) => typeof v === "string" && v.trim() !== "";
17955
18105
  function safeRel(p) {
17956
- const n2 = normalize(p.trim()).split(sep10).join("/").replace(/\/$/, "");
17957
- if (n2 === "" || isAbsolute(n2) || n2 === ".." || n2.startsWith("../"))
18106
+ const n2 = normalize(p.trim()).split(sep9).join("/").replace(/\/$/, "");
18107
+ if (n2 === "" || isAbsolute2(n2) || n2 === ".." || n2.startsWith("../"))
17958
18108
  return null;
17959
18109
  return n2;
17960
18110
  }
17961
18111
  function insideRepo(repoDir, rel) {
17962
18112
  try {
17963
- const real2 = realpathSync15(join28(repoDir, rel));
17964
- const base = realpathSync15(repoDir);
17965
- return real2 === base || real2.startsWith(base + sep10);
18113
+ const real2 = realpathSync14(join30(repoDir, rel));
18114
+ const base = realpathSync14(repoDir);
18115
+ return real2 === base || real2.startsWith(base + sep9);
17966
18116
  } catch {
17967
18117
  return false;
17968
18118
  }
@@ -17973,8 +18123,8 @@ function checkCitation(repoDir, raw2) {
17973
18123
  const rel = safeRel(raw2.replace(/:\d+(?:-\d+)?$/, ""));
17974
18124
  if (rel === null)
17975
18125
  return `citation "${raw2}" is not a repo-relative path`;
17976
- const abs = join28(repoDir, rel);
17977
- if (!existsSync15(abs) || !statSync11(abs).isFile() || !insideRepo(repoDir, rel))
18126
+ const abs = join30(repoDir, rel);
18127
+ if (!existsSync18(abs) || !statSync11(abs).isFile() || !insideRepo(repoDir, rel))
17978
18128
  return `citation "${raw2}" names a file that does not exist`;
17979
18129
  return null;
17980
18130
  }
@@ -17985,7 +18135,7 @@ function checkFingerprint(repoDir, raw2) {
17985
18135
  if (rel === null)
17986
18136
  return `fingerprint "${raw2}" is not a repo-relative path`;
17987
18137
  try {
17988
- if (!lstatSync5(join28(repoDir, rel)).isFile() || !insideRepo(repoDir, rel))
18138
+ if (!lstatSync4(join30(repoDir, rel)).isFile() || !insideRepo(repoDir, rel))
17989
18139
  return `fingerprint "${raw2}" is not a regular file inside the repo`;
17990
18140
  } catch {
17991
18141
  return `fingerprint "${raw2}" names a file that does not exist`;
@@ -18013,8 +18163,8 @@ function checkDir(repoDir, v, where, errs) {
18013
18163
  errs.push(`${where}: must be a repo-relative directory ("." for the repo root)`);
18014
18164
  return ".";
18015
18165
  }
18016
- const abs = join28(repoDir, rel);
18017
- if (!existsSync15(abs) || !statSync11(abs).isDirectory() || !insideRepo(repoDir, rel))
18166
+ const abs = join30(repoDir, rel);
18167
+ if (!existsSync18(abs) || !statSync11(abs).isDirectory() || !insideRepo(repoDir, rel))
18018
18168
  errs.push(`${where}: directory "${rel}" does not exist`);
18019
18169
  return rel;
18020
18170
  }
@@ -18121,6 +18271,62 @@ var GATHER_CAPS = {
18121
18271
  maxTreeLines: 300,
18122
18272
  maxHashBytes: 16 * 1024 * 1024
18123
18273
  };
18274
+ var depthOf = (p) => p.split("/").length;
18275
+ function listShallow(repoDir) {
18276
+ try {
18277
+ const out2 = safeGit(repoDir, ["ls-files", "-z"], { maxBuffer: 256 * 1024 * 1024 });
18278
+ return out2.split("\x00").filter((p) => p !== "").slice(0, GATHER_CAPS.maxListFiles).filter((p) => depthOf(p) <= GATHER_CAPS.maxDepth);
18279
+ } catch {
18280
+ return [];
18281
+ }
18282
+ }
18283
+ function shallowDirs(repoDir) {
18284
+ return [...new Set(listShallow(repoDir).map((p) => dirname9(p)))].sort();
18285
+ }
18286
+ var MODEL_REV = "model-rev:2";
18287
+ function computeKey(repoDir, fingerprintFiles, dirs, committedHash = null) {
18288
+ const h = createHash7("sha256");
18289
+ h.update(`${MODEL_REV}
18290
+ `);
18291
+ if (committedHash !== null)
18292
+ h.update(`committed:${committedHash}
18293
+ `);
18294
+ for (const f of [...fingerprintFiles].sort()) {
18295
+ h.update(`file:${f}
18296
+ `);
18297
+ try {
18298
+ if (checkFingerprint(repoDir, f) !== null)
18299
+ h.update("invalid");
18300
+ else {
18301
+ const abs = join31(repoDir, f);
18302
+ const size = lstatSync5(abs).size;
18303
+ h.update(size <= GATHER_CAPS.maxHashBytes ? readFileSync22(abs) : `too-large:${size}`);
18304
+ }
18305
+ } catch {
18306
+ h.update("missing");
18307
+ }
18308
+ h.update(`
18309
+ `);
18310
+ }
18311
+ for (const d of dirs)
18312
+ h.update(`dir:${d}
18313
+ `);
18314
+ return h.digest("hex");
18315
+ }
18316
+ function isGitTracked(repoDir, relPath) {
18317
+ try {
18318
+ const out2 = safeGit(repoDir, ["ls-files", "--error-unmatch", "--", relPath], { timeout: 1e4 });
18319
+ return out2.trim() !== "";
18320
+ } catch {
18321
+ return false;
18322
+ }
18323
+ }
18324
+ function committedModelHash(raw2) {
18325
+ if (typeof raw2 !== "object" || raw2 === null || Array.isArray(raw2))
18326
+ return null;
18327
+ const { key: _key, expiresAt: _exp, ...rest } = raw2;
18328
+ return createHash7("sha256").update(JSON.stringify(rest)).digest("hex");
18329
+ }
18124
18330
 
18125
18331
  // ../../loki-ts/src/project_model/discover.ts
18126
18332
  function projectModelEnabled(env = process.env) {
@@ -18130,11 +18336,36 @@ var PROJECT_FILE = ".loki/project.json";
18130
18336
  var UNKNOWN_TTL_MS = 60 * 60 * 1000;
18131
18337
  function loadCached(repoDir, now2 = Date.now()) {
18132
18338
  try {
18133
- return parseCached(repoDir, JSON.parse(readFileSync20(join29(repoDir, PROJECT_FILE), "utf8")), now2);
18339
+ return parseCached(repoDir, JSON.parse(readFileSync23(join32(repoDir, PROJECT_FILE), "utf8")), now2);
18134
18340
  } catch {
18135
18341
  return null;
18136
18342
  }
18137
18343
  }
18344
+ function loadCommitted(repoDir) {
18345
+ if (!isGitTracked(repoDir, PROJECT_FILE))
18346
+ return null;
18347
+ const ignore = (why) => {
18348
+ process.stderr.write(`loki: ignoring committed ${PROJECT_FILE}: ${why}; falling back to discovery
18349
+ `);
18350
+ return null;
18351
+ };
18352
+ let raw2;
18353
+ try {
18354
+ raw2 = JSON.parse(readFileSync23(join32(repoDir, PROJECT_FILE), "utf8"));
18355
+ } catch (e) {
18356
+ return ignore(`unreadable JSON (${e instanceof Error ? e.message : String(e)})`);
18357
+ }
18358
+ const hash = committedModelHash(raw2);
18359
+ if (hash === null)
18360
+ return ignore("not a JSON object");
18361
+ const r = raw2;
18362
+ if (r["schema"] !== PROJECT_MODEL_SCHEMA || r["status"] !== "ok")
18363
+ return ignore(`needs schema "${PROJECT_MODEL_SCHEMA}" and status "ok"`);
18364
+ const v = validateAnswer(repoDir, raw2);
18365
+ if (!v.ok)
18366
+ return ignore(v.errors.slice(0, 3).join("; "));
18367
+ return { model: { ...v.model, key: "" }, hash };
18368
+ }
18138
18369
 
18139
18370
  // ../../loki-ts/src/project_model/api.ts
18140
18371
  import { posix } from "path";
@@ -18201,48 +18432,1235 @@ function loadProjectApi(repoDir, env = process.env) {
18201
18432
  function isMultiRoot(api) {
18202
18433
  return !!api && api.known() && api.packages().some((p) => p.root !== ".");
18203
18434
  }
18435
+ function siteFor(api, repoDir, file) {
18436
+ if (!isMultiRoot(api))
18437
+ return null;
18438
+ const pkg = api.packageOf(file);
18439
+ const rel = api.relativeToRoot(file);
18440
+ if (!pkg || pkg.root === "." || rel === null)
18441
+ return null;
18442
+ return { pkg, root: pkg.root, cwd: join33(repoDir, pkg.root), file: rel };
18443
+ }
18444
+ function groupByPackage(api, repoDir, files) {
18445
+ const out2 = new Map;
18446
+ for (const f of files) {
18447
+ const s = siteFor(api, repoDir, f);
18448
+ const root = s?.root ?? ".";
18449
+ const g = out2.get(root) ?? { root, cwd: s?.cwd ?? repoDir, files: [], rel: [] };
18450
+ g.files.push(f);
18451
+ g.rel.push(s?.file ?? f);
18452
+ out2.set(root, g);
18453
+ }
18454
+ return [...out2.values()];
18455
+ }
18204
18456
 
18205
18457
  // ../../loki-ts/src/project_model/scope.ts
18206
18458
  var apis = new WeakMap;
18207
18459
  var imports = new WeakMap;
18208
18460
  var dropped = new WeakMap;
18461
+ function scopedOutOf(map) {
18462
+ return [...dropped.get(map) ?? []].sort();
18463
+ }
18209
18464
 
18210
- // ../../loki-ts/src/engine10/testmap.ts
18211
- var SKIP_DIRS = new Set([
18212
- ".git",
18213
- "node_modules",
18214
- "dist",
18215
- "build",
18216
- "target",
18217
- "coverage",
18218
- ".venv",
18219
- "venv",
18220
- "__pycache__",
18221
- ".tox",
18222
- ".pytest_cache",
18223
- ".loki",
18224
- ".next"
18225
- ]);
18226
- var JS_TEST_RE = /\.(test|spec)\.[cm]?[jt]sx?$/;
18227
- var PY_TEST_RE = /^(test_.+|.+_test)\.py$/;
18228
- var GO_TEST_RE = /_test\.go$/;
18229
- function isTestFile(rel) {
18230
- const name = basename9(rel);
18231
- return JS_TEST_RE.test(name) || PY_TEST_RE.test(name) || GO_TEST_RE.test(name);
18465
+ // ../../loki-ts/src/engine10/stages/verify.ts
18466
+ import { existsSync as existsSync20, mkdtempSync as mkdtempSync5, realpathSync as realpathSync16, rmSync as rmSync8 } from "fs";
18467
+ import { tmpdir as tmpdir6 } from "os";
18468
+ import { dirname as dirname10, isAbsolute as isAbsolute4, join as join38, relative as relative4 } from "path";
18469
+
18470
+ // ../../loki-ts/src/e10ext/assert_delta.ts
18471
+ import { execFileSync as execFileSync5 } from "child_process";
18472
+ import { mkdtempSync as mkdtempSync3, readFileSync as readFileSync24, rmSync as rmSync6 } from "fs";
18473
+ import { tmpdir as tmpdir4 } from "os";
18474
+ import { join as join34 } from "path";
18475
+ import { basename as basename10 } from "path";
18476
+ var WEAKENED = { verdict: "weakened", changes: [] };
18477
+ var PY = String.raw`
18478
+ import ast, copy, io, json, re, sys, tokenize
18479
+ d = json.load(sys.stdin)
18480
+ bs, hs, task = d["base"], d["head"], d["task"]
18481
+ def out(v, it=()):
18482
+ print(json.dumps({"verdict": v, "items": list(it)}))
18483
+ sys.exit(0)
18484
+ if "\r" in bs or "\r" in hs or "\t" in bs or "\t" in hs:
18485
+ out("weakened")
18486
+ bt, ht = ast.parse(bs), ast.parse(hs)
18487
+ # every byte outside a literal token (comments, blank lines, spacing, other code) must be identical
18488
+ def template(src):
18489
+ lines = src.split("\n")
18490
+ starts, o = [], 0
18491
+ for ln in lines:
18492
+ starts.append(o)
18493
+ o += len(ln) + 1
18494
+ spans = [(starts[t.start[0] - 1] + t.start[1], starts[t.end[0] - 1] + t.end[1])
18495
+ for t in tokenize.generate_tokens(io.StringIO(src).readline) if t.type in (tokenize.STRING, tokenize.NUMBER)]
18496
+ r, pos = [], 0
18497
+ for a, b in spans:
18498
+ r.append(src[pos:a] + "\0")
18499
+ pos = b
18500
+ return "".join(r) + src[pos:]
18501
+ if template(bs) != template(hs):
18502
+ out("weakened")
18503
+ class Norm(ast.NodeTransformer):
18504
+ def visit_Constant(self, n):
18505
+ return ast.copy_location(ast.Constant(value="<" + type(n.value).__name__ + ">"), n)
18506
+ def norm(t):
18507
+ return ast.dump(Norm().visit(copy.deepcopy(t)))
18508
+ # only what pytest collects: module-level test functions and methods of Test* classes without __init__
18509
+ def tests(t):
18510
+ r = []
18511
+ for n in t.body:
18512
+ if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef)) and n.name.startswith("test"):
18513
+ r.append(n)
18514
+ elif isinstance(n, ast.ClassDef) and n.name.startswith("Test") \
18515
+ and not any(isinstance(m, (ast.FunctionDef, ast.AsyncFunctionDef)) and m.name == "__init__" for m in n.body):
18516
+ r += [m for m in n.body if isinstance(m, (ast.FunctionDef, ast.AsyncFunctionDef)) and m.name.startswith("test")]
18517
+ return r
18518
+ def direct(f):
18519
+ return [a for a in f.body if isinstance(a, ast.Assert)]
18520
+ def tables(t):
18521
+ return [n.args[1] for n in ast.walk(t) if isinstance(n, ast.Call) and getattr(n.func, "attr", "") == "parametrize"
18522
+ and len(n.args) > 1 and isinstance(n.args[1], (ast.List, ast.Tuple))]
18523
+ def stripped(t):
18524
+ c = copy.deepcopy(t)
18525
+ for tb in tables(c):
18526
+ tb.elts = []
18527
+ return c
18528
+ def consts(t):
18529
+ return [n for n in ast.walk(t) if isinstance(n, ast.Constant)]
18530
+ def shadowed(t):
18531
+ for scope in [t] + [n for n in t.body if isinstance(n, ast.ClassDef)]:
18532
+ names = [n.name for n in scope.body if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef)) and n.name.startswith("test")]
18533
+ if len(names) != len(set(names)):
18534
+ return True
18535
+ return False
18536
+ if shadowed(bt) or shadowed(ht):
18537
+ out("weakened")
18538
+ sb, sh = stripped(bt), stripped(ht)
18539
+ if not tests(ht) or norm(sb) != norm(sh):
18540
+ out("weakened")
18541
+ for t in (bt, ht):
18542
+ if any(isinstance(n, ast.Call) and isinstance(n.func, ast.Name) and n.func.id == "round" for n in ast.walk(t)):
18543
+ out("weakened")
18544
+ tb, th = tables(bt), tables(ht)
18545
+ if any(len(x.elts) != len(y.elts) for x, y in zip(tb, th)):
18546
+ out("weakened")
18547
+ if any(norm(r) != norm(q) for x, y in zip(tb, th) for r, q in zip(x.elts, y.elts)):
18548
+ out("weakened")
18549
+ owner = {}
18550
+ for f in tests(sh):
18551
+ for n in ast.walk(f):
18552
+ owner[id(n)] = f
18553
+ pairs = [(b, h, owner.get(id(h))) for b, h in zip(consts(sb), consts(sh))]
18554
+ fh = {}
18555
+ for f in tests(ht):
18556
+ for t in tables(f):
18557
+ fh[id(t)] = f
18558
+ for x, y in zip(tb, th):
18559
+ for r, q in zip(x.elts, y.elts):
18560
+ pairs += [(b, h, fh.get(id(y))) for b, h in zip(consts(r), consts(q))]
18561
+ def eqs(f):
18562
+ return [a.test for a in direct(f) if isinstance(a.test, ast.Compare) and len(a.test.ops) == 1 and isinstance(a.test.ops[0], ast.Eq)]
18563
+ def dups(t):
18564
+ r = {}
18565
+ for f in tests(t):
18566
+ ds = [ast.dump(a) for a in direct(f)]
18567
+ r[f.name] = len(ds) - len(set(ds))
18568
+ return r
18569
+ dh, db = dups(ht), dups(bt)
18570
+ ok = not any(v > db.get(k, 0) for k, v in dh.items())
18571
+ # expected side = the right operand of a direct "assert X == Y"
18572
+ exp = set()
18573
+ for f in tests(sh):
18574
+ exp |= {id(c.comparators[0]) for c in eqs(f) if isinstance(c.comparators[0], ast.Constant)}
18575
+ for f in tests(ht):
18576
+ rights = {id(c.comparators[0]) for c in eqs(f) if isinstance(c.comparators[0], ast.Name)}
18577
+ for c in f.decorator_list:
18578
+ if isinstance(c, ast.Call) and getattr(c.func, "attr", "") == "parametrize" and len(c.args) > 1 \
18579
+ and isinstance(c.args[0], ast.Constant) and isinstance(c.args[0].value, str) and isinstance(c.args[1], (ast.List, ast.Tuple)):
18580
+ cols = [x.strip() for x in c.args[0].value.split(",")]
18581
+ # a column counts only if every use of its name in the body is the right operand of a direct eq assert
18582
+ if any(kw.arg == "indirect" for kw in c.keywords):
18583
+ continue
18584
+ deco = {id(m) for dd in f.decorator_list for m in ast.walk(dd)}
18585
+ uses = {k: [n for n in ast.walk(f) if isinstance(n, ast.Name) and n.id == k and id(n) not in deco] for k in cols}
18586
+ # the column must be read at least once, and only as the right operand of a direct eq assert
18587
+ solo = {k for k, u in uses.items() if u and all(id(n) in rights for n in u)}
18588
+ for r in c.args[1].elts:
18589
+ for i, e in enumerate(r.elts if isinstance(r, (ast.Tuple, ast.List)) else [r]):
18590
+ if isinstance(e, ast.Constant) and i < len(cols) and cols[i] in solo:
18591
+ exp.add(id(e))
18592
+ def callees(f):
18593
+ r = set()
18594
+ for c in eqs(f):
18595
+ for n in ast.walk(c.left):
18596
+ if isinstance(n, ast.Call):
18597
+ k = n.func.id if isinstance(n.func, ast.Name) else getattr(n.func, "attr", "")
18598
+ if k:
18599
+ r.add(k)
18600
+ return r
18601
+ def generic(v):
18602
+ return v is None or isinstance(v, (bool, bytes)) or (isinstance(v, str) and len(v) <= 3) \
18603
+ or (isinstance(v, (int, float)) and abs(v) < 10)
18604
+ def in_task(v, f):
18605
+ task0 = d["task"]
18606
+ t = v if isinstance(v, str) else repr(v)
18607
+ if t == "":
18608
+ return False
18609
+ # bounded by whitespace, string ends or ,;:()[]{}"' only; never glued to - + or a digit group separator
18610
+ tok = r"(?<![^\s,;:()\[\]{}\"'])(?<!\d,)" + re.escape(t) + r"(?:(?=[\s,;:()\[\]{}\"']|$)(?!,\d)|\.(?=\s|$))"
18611
+ task = re.sub(r"(?<=\d),(?=\d{3}\b)", "", task0)
18612
+ if not generic(v):
18613
+ return re.search(tok, task) is not None
18614
+ # a generic value counts only right next to the identifier the test calls
18615
+ return any(re.search(r"\b" + re.escape(k) + r"\b[^\n]{0,40}?" + tok, task) for k in (callees(f) if f else ()))
18616
+ items = []
18617
+ for b, h, f in pairs:
18618
+ if (type(b.value), repr(b.value)) != (type(h.value), repr(h.value)):
18619
+ hit = in_task(h.value, f)
18620
+ ok = ok and id(h) in exp and hit
18621
+ items.append({"line": h.lineno, "old": repr(b.value), "new": repr(h.value), "inTask": hit, "matched": "new"})
18622
+ out("value-change" if ok and items else "weakened", items if ok else [])
18623
+ `;
18624
+ var okStr = (v) => typeof v === "string" && v.length <= 200 && !/[\x00-\x1f\x7f]/.test(v);
18625
+ function classifyAssertDelta(inp) {
18626
+ const f = basename10(inp.path);
18627
+ if (!/^(test_.*|.*_test)\.py$/.test(f))
18628
+ return WEAKENED;
18629
+ if (inp.headCounts.run !== inp.baseCounts.run || inp.headCounts.skipped !== inp.baseCounts.skipped)
18630
+ return WEAKENED;
18631
+ let cwd = "";
18632
+ try {
18633
+ cwd = mkdtempSync3(join34(tmpdir4(), "loki-ad-"));
18634
+ const raw2 = execFileSync5("python3", ["-I", "-c", PY], {
18635
+ input: JSON.stringify({ path: inp.path, base: inp.base, head: inp.head, task: inp.task }),
18636
+ cwd,
18637
+ env: process.env,
18638
+ stdio: ["pipe", "pipe", "ignore"],
18639
+ encoding: "utf8",
18640
+ timeout: 20000
18641
+ });
18642
+ const r = JSON.parse(raw2);
18643
+ if (r.verdict !== "value-change" || !Array.isArray(r.items) || r.items.length === 0)
18644
+ return WEAKENED;
18645
+ const items = [];
18646
+ for (const i of r.items) {
18647
+ if (!i || typeof i !== "object" || !Number.isInteger(i["line"]) || i["line"] < 1 || !okStr(i["old"]) || !okStr(i["new"]) || i["inTask"] !== true || i["matched"] !== "new")
18648
+ return WEAKENED;
18649
+ items.push({ line: i["line"], old: i["old"], new: i["new"], matched: "new" });
18650
+ }
18651
+ return { verdict: "value-change", changes: items.map((i) => `${inp.path}:${i.line} ${i.old} -> ${i.new}`), items };
18652
+ } catch {
18653
+ return WEAKENED;
18654
+ } finally {
18655
+ if (cwd)
18656
+ rmSync6(cwd, { recursive: true, force: true });
18657
+ }
18658
+ }
18659
+ function assertDeltaNotes(repoDir, baseSha, headRef, path, task, baseCounts, headCounts) {
18660
+ if (!baseCounts || !headCounts)
18661
+ return null;
18662
+ try {
18663
+ const show = (ref) => safeGit(repoDir, ["show", `${ref}:${path}`]);
18664
+ const head = headRef ? show(headRef) : readFileSync24(join34(repoDir, path), "utf8");
18665
+ const r = classifyTestEdit(path, show(baseSha), head, task, baseCounts, headCounts);
18666
+ return r[0]?.kind === "literal-only" ? r.map((e) => `assertion value changed (not shown to be required by the task): ${e.file}:${e.line} ${e.old} -> ${e.new}`) : null;
18667
+ } catch {
18668
+ return null;
18669
+ }
18670
+ }
18671
+ function classifyTestEdit(file, oldText, newText, taskText, baseCounts, headCounts) {
18672
+ const weak = [{ kind: "weakened", file, line: 0, old: "", new: "", inTask: false }];
18673
+ const r = classifyAssertDelta({ path: file, base: oldText, head: newText, task: taskText, baseCounts, headCounts });
18674
+ if (r.verdict !== "value-change" || !r.items?.length)
18675
+ return weak;
18676
+ return r.items.map((i) => ({ kind: "literal-only", file, line: i.line, old: i.old, new: i.new, inTask: true }));
18677
+ }
18678
+
18679
+ // ../../loki-ts/src/engine10/failures.ts
18680
+ var ID_LINE = /^(?:(?:FAILED|ERROR)\s+(\S+::\S*)(?:\s.*)?|\u25cf\s+(?!Console|Test suite failed)(.+)|not ok \d+ - (.+?)(?:\s+#.*)?|\u2716\s+(?!failing tests:)(.+?)(?:\s+\([\d.]+ms\))?|(?:FAIL|\u00d7)\s+(.+))$/;
18681
+ function failCount(out2) {
18682
+ const n2 = (s, re) => +(s.match(re)?.[1] ?? 0);
18683
+ const l = out2.split(`
18684
+ `).reverse().map((x) => x.trim()).find((x) => /^(?:=+ )?\d+ \w+.* in [\d.]+s|^Tests?:?\s+\d/.test(x)), m = /^(?:#|\u2139) fail (\d+)$/m.exec(out2);
18685
+ return l ? n2(l, /(\d+) failed/) + n2(l, /(\d+) errors?/) : m ? +m[1] : null;
18686
+ }
18687
+ function failIds(output) {
18688
+ const ids = [...new Set(output.split(`
18689
+ `).map((l) => ID_LINE.exec(l.trim())).flatMap((m) => m ? [(m.slice(1).find(Boolean) ?? "").trim()] : []).filter(Boolean))];
18690
+ const c = failCount(output);
18691
+ return c && ids.length >= c ? ids : [];
18692
+ }
18693
+
18694
+ // ../../loki-ts/src/runner/load_owner.ts
18695
+ import { spawnSync as spawnSync2 } from "child_process";
18696
+ import { mkdtempSync as mkdtempSync4, realpathSync as realpathSync15, rmSync as rmSync7 } from "fs";
18697
+ import { tmpdir as tmpdir5 } from "os";
18698
+ import { basename as basename11, extname, join as join35 } from "path";
18699
+
18700
+ // ../../loki-ts/src/runner/runner_errors.ts
18701
+ function hasRealTestFailure(out2) {
18702
+ 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);
18703
+ }
18704
+ var LOAD_PATTERNS = [
18705
+ [/Failed Suites\s+[1-9]/, "test suite failed to load"],
18706
+ [/Test suite failed to run/, "test suite failed to run"],
18707
+ [/Failed to load (?:url|config)|failed to load config|Failed to resolve (?:import|entry)/i, "runner config or import could not be loaded"],
18708
+ [/^\s*(?:\w*Error: )?Cannot find (?:module|package) '[^']+'/m, "module not found while loading tests"],
18709
+ [/ERR_MODULE_NOT_FOUND/, "module not found while loading tests"],
18710
+ [/Interrupted: \d+ errors? during collection/, "collection error"],
18711
+ [/^_+ ERROR collecting /m, "collection error"],
18712
+ [/ImportError while importing test module/, "test module import error"],
18713
+ [/^ERROR: (?:file or directory not found|not found:)/m, "test path not found by the runner"],
18714
+ [/No test files found, exiting with code [1-9]/, "runner found no test files (wrong cwd or path)"],
18715
+ [/\[setup failed\]|cannot find package|no required module provides package/, "go package could not be set up"],
18716
+ [/could not determine executable to run/i, "test runner executable not found"],
18717
+ [/^(?:\S+: )?(?:line \d+: )?[\w.-]+: command not found$/m, "test runner executable not found"]
18718
+ ];
18719
+ function firstLoadLine(out2) {
18720
+ const lines = out2.split(`
18721
+ `).map((l2) => l2.trim()).filter(Boolean);
18722
+ const l = lines.find((x) => /^(?:E\s+)?(?:Error|\w*Error|ERROR|Failed|FAIL)\b|Cannot find|Interrupted:|No test files found/.test(x)) ?? lines[0] ?? "";
18723
+ return l.replace(/\s+/g, " ").slice(0, 160);
18724
+ }
18725
+ function classifyRunnerOutput(out2) {
18726
+ if (!hasRealTestFailure(out2)) {
18727
+ for (const [re, why] of LOAD_PATTERNS) {
18728
+ if (re.test(out2))
18729
+ return { kind: "load_error", owner: "harness", reason: `runner could not load: ${why}: ${firstLoadLine(out2)}` };
18730
+ }
18731
+ }
18732
+ return { kind: "test_failure", owner: "code" };
18733
+ }
18734
+
18735
+ // ../../loki-ts/src/runner/load_owner.ts
18736
+ var esc = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
18737
+ var suffixes = (segs, min) => segs.map((_, k) => segs.slice(k).join("/")).filter((x) => x.split("/").length >= min);
18738
+ var bounded = (out2, tok, tail) => new RegExp(`(?<![\\w.-])${esc(tok)}${tail}`).test(out2);
18739
+ function changedFilesNamed(out2, repoDir, changed) {
18740
+ return changed.filter((f) => {
18741
+ if (out2.includes(f) || out2.includes(join35(repoDir, f)))
18742
+ return true;
18743
+ const segs = f.split("/");
18744
+ if (suffixes(segs, 2).some((x) => x !== f && bounded(out2, x, "(?![\\w-])")))
18745
+ return true;
18746
+ if (extname(f) === ".go" && segs.length > 1 && suffixes(segs.slice(0, -1), 1).some((d) => new RegExp(`(?<=[\\w-])/${esc(d)}(?![\\w./-])`).test(out2)))
18747
+ return true;
18748
+ const stem = basename11(f, extname(f));
18749
+ if (stem.length < 2 || stem === "index" || stem === "__init__")
18750
+ return false;
18751
+ return new RegExp(`(?<![\\w-])${esc(stem)}(?![\\w-])`).test(out2);
18752
+ });
18753
+ }
18754
+ function loadSignature(out2, roots) {
18755
+ let o = out2;
18756
+ for (const r of roots.flatMap((x) => {
18757
+ try {
18758
+ return [x, realpathSync15(x)];
18759
+ } catch {
18760
+ return [x];
18761
+ }
18762
+ }).sort((a, b) => b.length - a.length))
18763
+ o = o.split(r).join("<repo>");
18764
+ const keys = new Set;
18765
+ for (const m of o.matchAll(/Cannot find (?:module|package) '([^']+)'/g))
18766
+ keys.add(`mod:${m[1]}`);
18767
+ for (const m of o.matchAll(/([\w.-]+): command not found/g))
18768
+ keys.add(`cmd:${m[1]}`);
18769
+ return { keys, reason: (classifyRunnerOutput(o).reason ?? "").replace(/:\d+(?::\d+)?/g, "") };
18770
+ }
18771
+ function sameLoadError(head, base, headRoots, baseRoots) {
18772
+ const h = loadSignature(head, headRoots), b = loadSignature(base, baseRoots);
18773
+ if (b.keys.size)
18774
+ return h.keys.size > 0 && [...b.keys].every((k) => h.keys.has(k));
18775
+ return h.keys.size === 0 && h.reason === b.reason;
18776
+ }
18777
+ function killTree(pid) {
18778
+ const all = [pid];
18779
+ for (let k = 0;k < all.length; k++) {
18780
+ const kids = spawnSync2("pgrep", ["-P", String(all[k])], { encoding: "utf8", env: process.env }).stdout.split(/\s+/).filter(Boolean).map(Number);
18781
+ all.push(...kids.filter((x) => Number.isInteger(x) && !all.includes(x)));
18782
+ }
18783
+ try {
18784
+ if (Number.isInteger(pid) && pid > 1)
18785
+ process.kill(-pid, "SIGKILL");
18786
+ } catch {}
18787
+ for (const p of all.reverse()) {
18788
+ try {
18789
+ process.kill(p, "SIGKILL");
18790
+ } catch {}
18791
+ }
18792
+ }
18793
+ async function runOnBase(i, dir) {
18794
+ const sub = (s) => s.split(i.repoDir).join(dir);
18795
+ const stop = AbortSignal.any([i.signal, AbortSignal.timeout(i.timeoutMs ?? 60000)]);
18796
+ try {
18797
+ const proc = Bun.spawn([sub(i.cmd), ...i.args.map(sub)], {
18798
+ cwd: sub(i.cwd ?? i.repoDir),
18799
+ stdin: "ignore",
18800
+ stdout: "pipe",
18801
+ stderr: "pipe",
18802
+ detached: true,
18803
+ env: { ...process.env, ...i.env ?? {} }
18804
+ });
18805
+ let tail = "";
18806
+ const rs = [proc.stdout, proc.stderr].map((x) => x.getReader());
18807
+ const pumps = rs.map(async (r) => {
18808
+ const d = new TextDecoder;
18809
+ for (;; ) {
18810
+ const c = await r.read().catch(() => ({ done: true, value: undefined }));
18811
+ if (c.done)
18812
+ return;
18813
+ tail = (tail + d.decode(c.value, { stream: true })).slice(-65536);
18814
+ }
18815
+ });
18816
+ const cut = new Promise((res) => {
18817
+ if (stop.aborted)
18818
+ res(null);
18819
+ else
18820
+ stop.addEventListener("abort", () => res(null), { once: true });
18821
+ });
18822
+ const code = await Promise.race([proc.exited, cut]);
18823
+ if (code === null) {
18824
+ killTree(proc.pid);
18825
+ return null;
18826
+ }
18827
+ await Promise.race([Promise.all(pumps), new Promise((r) => setTimeout(r, 300))]);
18828
+ rs.forEach((r) => r.cancel().catch(() => {}));
18829
+ return stop.aborted || code === 0 ? null : tail;
18830
+ } catch {
18831
+ return null;
18832
+ }
18833
+ }
18834
+ function changedSince(repoDir, baseSha) {
18835
+ const g = (a) => safeGit(repoDir, a).split(`
18836
+ `).map((l) => l.trim()).filter(Boolean);
18837
+ return [...new Set([...g(["diff", "--name-only", baseSha]), ...g(["ls-files", "--others", "--exclude-standard"])])].filter((f) => !f.startsWith(".loki/"));
18838
+ }
18839
+ async function loadErrorIsHarnessOwned(i) {
18840
+ if (i.protect || !i.baseSha || i.signal.aborted)
18841
+ return false;
18842
+ let changed;
18843
+ try {
18844
+ changed = changedSince(i.repoDir, i.baseSha);
18845
+ } catch {
18846
+ return false;
18847
+ }
18848
+ if (changedFilesNamed(i.out, i.repoDir, changed).length > 0)
18849
+ return false;
18850
+ if (i.args.some((a) => changed.includes(a.replace(/^\.\//, ""))))
18851
+ return false;
18852
+ const dir = mkdtempSync4(join35(tmpdir5(), "e10-loadown-"));
18853
+ const git2 = (args) => {
18854
+ safeGit(i.repoDir, args, { stdio: "ignore" });
18855
+ };
18856
+ try {
18857
+ git2(["worktree", "add", "--detach", dir, i.baseSha]);
18858
+ const base = await runOnBase(i, dir);
18859
+ return base !== null && classifyRunnerOutput(base).kind === "load_error" && sameLoadError(i.out, base, [i.repoDir, ...i.cwd ? [i.cwd] : []], [dir]);
18860
+ } catch {
18861
+ return false;
18862
+ } finally {
18863
+ try {
18864
+ git2(["worktree", "remove", "--force", dir]);
18865
+ } catch {}
18866
+ rmSync7(dir, { recursive: true, force: true });
18867
+ try {
18868
+ git2(["worktree", "prune"]);
18869
+ } catch {}
18870
+ }
18871
+ }
18872
+ async function harnessLoadReason(i) {
18873
+ const c = classifyRunnerOutput(i.out);
18874
+ return c.kind === "load_error" && await loadErrorIsHarnessOwned(i) ? c.reason : undefined;
18875
+ }
18876
+
18877
+ // ../../loki-ts/src/engine10/testmap.ts
18878
+ import { basename as basename12, extname as extname2, join as join36, relative as relative2, sep as sep10 } from "path";
18879
+ var SKIP_DIRS = new Set([
18880
+ ".git",
18881
+ "node_modules",
18882
+ "dist",
18883
+ "build",
18884
+ "target",
18885
+ "coverage",
18886
+ ".venv",
18887
+ "venv",
18888
+ "__pycache__",
18889
+ ".tox",
18890
+ ".pytest_cache",
18891
+ ".loki",
18892
+ ".next"
18893
+ ]);
18894
+ var JS_TEST_RE = /\.(test|spec)\.[cm]?[jt]sx?$/;
18895
+ var PY_TEST_RE = /^(test_.+|.+_test)\.py$/;
18896
+ var GO_TEST_RE = /_test\.go$/;
18897
+ function isTestFile(rel) {
18898
+ const name = basename12(rel);
18899
+ return JS_TEST_RE.test(name) || PY_TEST_RE.test(name) || GO_TEST_RE.test(name);
18900
+ }
18901
+
18902
+ // ../../loki-ts/src/util/check_result.ts
18903
+ import { basename as basename13 } from "path";
18904
+ var NO_TESTS_REASON = "no tests executed";
18905
+ var 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)";
18906
+ var UNCONFIRMED_REASON = "test count could not be confirmed";
18907
+ var FAIL_EVIDENCE = /\[(?:build|setup) failed\]|^--- FAIL|^[\w./-]+\.go:\d+:\d+: \S|\b[1-9]\d* (?:failed|errors?)\b/m;
18908
+ var GO_FAIL_EVIDENCE = /^FAIL\t\S+\t[\d.]+s$|^panic: /m;
18909
+ var UNMEASURED_REASON = "executed count unmeasured (Loki could not parse the runner summary, harness-owned)";
18910
+ function ran(raw2, path, ok) {
18911
+ const out2 = stripAnsi(raw2);
18912
+ const n2 = (s, re) => +(s.match(re)?.[1] ?? 0);
18913
+ const blk = out2.trimEnd().match(/(?:^|\n)((?:(?:#|\u2139) \w+ [\d.]+(?:\n|$)){5,})$/)?.[1];
18914
+ if (blk) {
18915
+ const c = n2(blk, /(?:#|\u2139) pass (\d+)/) + n2(blk, /(?:#|\u2139) fail (\d+)/);
18916
+ const nm = out2.match(/^(?:ok \d+ - |\u2714 )(\S+\.[cm]?[jt]s)(?: \(|$)/m)?.[1];
18917
+ return c === 1 && nm && (!path || basename13(nm) === basename13(path)) ? 0 : c;
18918
+ }
18919
+ const cg = cargoTrailer(out2);
18920
+ if (cg.length)
18921
+ return cg.reduce((t, l2) => t + n2(l2, /(\d+) passed/) + n2(l2, /(\d+) failed/), 0);
18922
+ const g = goCount(out2, ok);
18923
+ if (g !== undefined)
18924
+ return g;
18925
+ const tail = tailLines(out2);
18926
+ const l = tail.filter((x) => /^(?:=+ )?(?:\d+ \w+.*|no tests ran) in [\d.]+s|^\s*Tests?:?\s+\d|^No tests found/.test(x) && (!/^\s*Tests?:?\s+\d/.test(x) || tail.some((y) => /^\s*Test (?:Files|Suites):?\s+\d/.test(y)))).pop();
18927
+ if (!l)
18928
+ return null;
18929
+ return /^(?:=+ )?no tests (?:ran|found)|^No tests found|skipped/i.test(l) || /\d+ (?:passed|failed|errors?)/.test(l) ? n2(l, /(\d+) passed/) + n2(l, /(\d+) failed/) + n2(l, /(\d+) errors?/) : null;
18930
+ }
18931
+ var stripAnsi = (s) => s.replace(/\u001b\][^\u0007\u001b]*(?:\u0007|\u001b\\)/g, "").replace(/(?:\u001b\[|\u009b)[0-9;?]*[ -\/]*[@-~]/g, "").replace(/\r\n?/g, `
18932
+ `);
18933
+ var tailLines = (out2) => out2.split(`
18934
+ `).filter((x) => x.trim()).slice(-12);
18935
+ function cargoTrailer(out2) {
18936
+ const ls = out2.split(`
18937
+ `).filter((x) => x.trim());
18938
+ while (ls.length && /^error: /.test(ls[ls.length - 1]))
18939
+ ls.pop();
18940
+ const segs = [];
18941
+ for (const l of ls) {
18942
+ if (/^running \d+ tests?\b/.test(l))
18943
+ segs.push([]);
18944
+ else if (segs.length && !/^\s*(?:Running |Doc-tests |Doctest)/.test(l))
18945
+ segs[segs.length - 1].push(l);
18946
+ }
18947
+ const lastOf = (g) => g[g.length - 1]?.startsWith("test result: ") ? g[g.length - 1] : undefined;
18948
+ if (!segs.length) {
18949
+ const g = [];
18950
+ for (let k = ls.length - 1;k >= 0 && ls[k].startsWith("test result: "); k--)
18951
+ g.push(ls[k]);
18952
+ return g;
18953
+ }
18954
+ if (!lastOf(segs[segs.length - 1]))
18955
+ return [];
18956
+ return segs.flatMap((g) => lastOf(g) ?? []);
18957
+ }
18958
+ function bunCount(out2) {
18959
+ const ls = out2.split(`
18960
+ `).filter((x) => x.trim());
18961
+ if (!/^Ran \d+ tests? across \d+ files?\./.test(ls[ls.length - 1] ?? ""))
18962
+ return null;
18963
+ const blk = ls.slice(-9, -1);
18964
+ const last = (k) => +(blk.map((x) => x.match(new RegExp(`^\\s*(\\d+) ${k}\\s*$`))?.[1]).filter(Boolean).pop() ?? 0);
18965
+ return last("pass") + last("fail");
18966
+ }
18967
+ function unittestCount(out2, ok) {
18968
+ const ls = out2.split(`
18969
+ `).filter((x) => x.trim()), v = ls[ls.length - 1] ?? "", r = ls[ls.length - 2]?.match(/^Ran (\d+) tests? in [\d.]+s$/);
18970
+ if (!r || !/^(?:OK|FAILED)\b/.test(v))
18971
+ return null;
18972
+ if (ls.filter((x) => /^Ran \d+ tests? in [\d.]+s$/.test(x)).length > 1)
18973
+ return null;
18974
+ if (ok === true && v.startsWith("FAILED") || ok === false && v.startsWith("OK"))
18975
+ return null;
18976
+ return Math.max(0, +r[1] - +(v.match(/skipped=(\d+)/)?.[1] ?? 0) - +(v.match(/expected failures=(\d+)/)?.[1] ?? 0));
18977
+ }
18978
+ var GO_PKG_RE = /^(?:ok|FAIL|\?)\s+\S+\s+(?:\(cached\)|[\d.]+s\b|\[(?:no test files|build failed|setup failed)\])/;
18979
+ function goCount(out2, ok) {
18980
+ const lines = out2.split(`
18981
+ `);
18982
+ if (!lines.some((x) => GO_PKG_RE.test(x)))
18983
+ return;
18984
+ const last = new Map, seen = new Set, skip = new Set, failPkg = ok !== true && lines.some((x) => /^FAIL\s+\S+\s+[\d.]+s\b/.test(x));
18985
+ for (const x of lines) {
18986
+ const r = x.match(/^=== RUN\s+(\S+)/), m = x.match(/^--- (PASS|FAIL|SKIP): (\S+)/);
18987
+ if (r)
18988
+ seen.add(r[1]);
18989
+ else if (m && (seen.has(m[2]) || m[1] === "FAIL" && failPkg)) {
18990
+ last.set(m[2], m[1]);
18991
+ if (m[1] === "SKIP")
18992
+ skip.add(m[2]);
18993
+ }
18994
+ }
18995
+ for (const k of skip)
18996
+ last.set(k, "SKIP");
18997
+ if (ok === true && [...last.values()].includes("FAIL"))
18998
+ return null;
18999
+ const t = [...last.values()].filter((v) => v !== "SKIP").length;
19000
+ if (t > 0)
19001
+ return t;
19002
+ if (lines.some((x) => /^(?:=== RUN|PASS$|FAIL$|testing: warning: no tests to run)/.test(x)))
19003
+ return 0;
19004
+ return lines.filter((x) => GO_PKG_RE.test(x)).every((x) => /\[no tests? (?:files|to run)\]/.test(x)) ? 0 : null;
19005
+ }
19006
+ function goRunner(cmd, args) {
19007
+ const segs = args ? [[cmd, ...args]] : cmd.split(/&&|\|\||[;|\n]/).map((x) => x.trim().split(/\s+/).filter(Boolean));
19008
+ for (const t0 of segs) {
19009
+ const t = t0.map((x) => x.replace(/^["']|["']$/g, ""));
19010
+ let k = 0;
19011
+ for (;k < t.length; k++) {
19012
+ const x = t[k];
19013
+ if (/^[A-Za-z_]\w*=/.test(x) || /^(?:env|command|exec|time|nohup)$/.test(basename13(x)))
19014
+ continue;
19015
+ if (/^-/.test(x) && k > 0 && basename13(t[k - 1]) === "env") {
19016
+ if (x === "-u" || x === "-C" || x === "-S")
19017
+ k++;
19018
+ continue;
19019
+ }
19020
+ break;
19021
+ }
19022
+ if (t[k] !== undefined && basename13(t[k]) === "go")
19023
+ return { runner: "go" };
19024
+ }
19025
+ return {};
19026
+ }
19027
+ function goJson(out2) {
19028
+ let any = false, failed = false;
19029
+ for (const x of out2.split(`
19030
+ `)) {
19031
+ if (!x.trim() || /^go: /.test(x))
19032
+ continue;
19033
+ let e;
19034
+ try {
19035
+ e = JSON.parse(x);
19036
+ } catch {
19037
+ return null;
19038
+ }
19039
+ if (!e || typeof e !== "object" || typeof e.Action !== "string")
19040
+ return null;
19041
+ any = true;
19042
+ if (e.Action === "fail")
19043
+ failed = true;
19044
+ }
19045
+ return any ? { failed } : null;
19046
+ }
19047
+ function skipped(raw2) {
19048
+ return stripAnsi(raw2).split(`
19049
+ `).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((u, m) => u + +(m[1] ?? m[2]), 0), 0);
19050
+ }
19051
+ function testCount(raw2, path, ok) {
19052
+ const out2 = stripAnsi(raw2);
19053
+ const bu = bunCount(out2), ut = unittestCount(out2, ok);
19054
+ if (bu !== null)
19055
+ return bu;
19056
+ if (ut !== null)
19057
+ return ut;
19058
+ if (/^\s*(?:Test Files\s+0\b|No test files found)/m.test(out2) && !/^\s*Tests?\s+\d/m.test(out2))
19059
+ return 0;
19060
+ const r = ran(out2, path, ok);
19061
+ if (r !== null)
19062
+ return r;
19063
+ const tl = tailLines(out2);
19064
+ const pw = tl.filter((x) => /^\s*\d+ (?:passed|failed|flaky)\b/.test(x));
19065
+ if (pw.length && tl.some((x) => /^\s*\d+ passed \([\d.]+m?s\)/.test(x) || /^\s*\d+ failed$/.test(x)))
19066
+ return pw.reduce((t, x) => t + +x.trim().split(" ")[0], 0);
19067
+ const lastNum = (re) => {
19068
+ const m = [...out2.matchAll(re)].pop();
19069
+ return m ? +m[1] : null;
19070
+ };
19071
+ const mp = lastNum(/^\s*(\d+) passing\b/gm), mf = lastNum(/^\s*(\d+) failing\b/gm);
19072
+ if (mp !== null || mf !== null)
19073
+ return (mp ?? 0) + (mf ?? 0);
19074
+ return null;
19075
+ }
19076
+ function classifyCheck(i) {
19077
+ if (i.missing)
19078
+ return { result: "not_run", reason: "tool not found on PATH" };
19079
+ if (i.cut)
19080
+ return { result: "not_run", reason: "timed out or aborted" };
19081
+ if (i.kind === "static")
19082
+ return { result: i.ok ? "pass" : "fail" };
19083
+ const text2 = stripAnsi(i.out);
19084
+ if (i.runner === "go") {
19085
+ if (i.ok)
19086
+ return { result: "not_run", reason: GO_EXIT0_REASON };
19087
+ const j = goJson(text2);
19088
+ if (j)
19089
+ return j.failed ? { result: "fail" } : { result: "not_run", reason: UNCONFIRMED_REASON };
19090
+ return FAIL_EVIDENCE.test(text2) || GO_FAIL_EVIDENCE.test(text2) ? { result: "fail" } : { result: "not_run", reason: UNCONFIRMED_REASON };
19091
+ }
19092
+ const n2 = testCount(i.out, i.path, i.ok);
19093
+ if (!i.ok && FAIL_EVIDENCE.test(text2))
19094
+ return { result: "fail", ...n2 !== null ? { n: n2 } : {} };
19095
+ if (n2 === 0)
19096
+ return { result: "not_run", n: 0, reason: `${NO_TESTS_REASON} (ran 0 tests, empty or all skipped)` };
19097
+ if (!i.ok)
19098
+ return { result: "fail", ...n2 !== null ? { n: n2 } : {} };
19099
+ if (n2 === null)
19100
+ return { result: "not_run", reason: UNMEASURED_REASON };
19101
+ return { result: "pass", n: n2 };
19102
+ }
19103
+ var isExecutedProof = (c) => c.result === "pass" && typeof c.n === "number" && c.n > 0;
19104
+ var hasExecutedProof = (checks) => checks.some(isExecutedProof);
19105
+
19106
+ // ../../loki-ts/src/util/wall_owned.ts
19107
+ import { isAbsolute as isAbsolute3, join as join37, relative as relative3 } from "path";
19108
+ var WALL_COMPILE_REASON = "wall test did not compile under the package config";
19109
+ var ANSI2 = /\u001b\[[0-9;?]*[ -/]*[@-~]/g;
19110
+ function failingLocations(raw2, cwd, repoDir) {
19111
+ const out2 = raw2.replace(ANSI2, "").replace(/\r\n?/g, `
19112
+ `), files = new Set;
19113
+ let located = 0, errors2 = 0, header = null;
19114
+ for (const line2 of out2.split(`
19115
+ `)) {
19116
+ const m = /^(.+?)\(\d+,\d+\): error TS\d+:/.exec(line2) ?? /^(.+?):\d+:\d+ - error TS\d+:/.exec(line2) ?? /^(.+?):\d+:\d+: .*\berror\b/.exec(line2);
19117
+ if (m) {
19118
+ files.add(m[1]);
19119
+ located++;
19120
+ errors2++;
19121
+ continue;
19122
+ }
19123
+ if (/\berror TS\d+:/.test(line2)) {
19124
+ errors2++;
19125
+ continue;
19126
+ }
19127
+ if (/^\S/.test(line2) && /^[^\s:]+\.[cm]?[jt]sx?$/.test(line2.trim())) {
19128
+ header = line2.trim();
19129
+ continue;
19130
+ }
19131
+ if (/^\s+\d+:\d+\s+error\b/.test(line2)) {
19132
+ errors2++;
19133
+ if (header) {
19134
+ files.add(header);
19135
+ located++;
19136
+ }
19137
+ }
19138
+ }
19139
+ if (errors2 === 0 || located !== errors2)
19140
+ return null;
19141
+ return [...files].map((f) => relative3(repoDir, isAbsolute3(f) ? f : join37(cwd, f)));
19142
+ }
19143
+ function wallOwnedFailure(raw2, cwd, repoDir, wall) {
19144
+ const locs = failingLocations(raw2, cwd, repoDir);
19145
+ return !!locs && locs.length > 0 && locs.every((l) => wall.has(l));
19146
+ }
19147
+
19148
+ // ../../loki-ts/src/engine10/stages/verify.ts
19149
+ var CHECK_TIMEOUT_MS = 60000;
19150
+ function resolveTool(repoDir, bin, fallback, lastResort = fallback) {
19151
+ const inRepo = (p) => {
19152
+ try {
19153
+ const r = relative4(realpathSync16(repoDir), realpathSync16(p));
19154
+ return r !== "" && !r.startsWith("..") && !isAbsolute4(r);
19155
+ } catch {
19156
+ return false;
19157
+ }
19158
+ };
19159
+ const venvEnv = process.env["VIRTUAL_ENV"];
19160
+ const project = [join38(repoDir, ".venv", "bin", bin), join38(repoDir, "venv", "bin", bin), ...venvEnv && inRepo(venvEnv) ? [join38(venvEnv, "bin", bin)] : []].find(existsSync20);
19161
+ return project ? [project, "project"] : [Bun.which(fallback) ? fallback : lastResort, "system"];
19162
+ }
19163
+ function runnerCmd(t, repoDir) {
19164
+ switch (t.runner) {
19165
+ case "pytest": {
19166
+ const [cmd, interpreter] = resolveTool(repoDir, "python", "python3", "python");
19167
+ return [cmd, ["-m", "pytest", "-q", t.path], interpreter];
19168
+ }
19169
+ case "vitest":
19170
+ return ["npx", ["vitest", "run", t.path]];
19171
+ case "jest":
19172
+ return ["npx", ["jest", t.path]];
19173
+ case "bun":
19174
+ return ["bun", ["test", t.path]];
19175
+ case "node":
19176
+ return ["node", ["--test", `./${t.path}`]];
19177
+ case "npm":
19178
+ return ["npm", ["test", "--silent"]];
19179
+ case "go":
19180
+ return ["go", ["test", "-json", `./${dirname10(t.path)}`]];
19181
+ case "cargo":
19182
+ return ["cargo", ["test"]];
19183
+ }
19184
+ }
19185
+ function commandFor(t, repoDir, api) {
19186
+ const site = siteFor(api, repoDir, t.path);
19187
+ const [cmd, args, interpreter] = runnerCmd(site ? { runner: t.runner, path: site.file } : t, repoDir);
19188
+ return { cwd: site?.cwd ?? repoDir, cmd, args, argv: [cmd, ...args], ...interpreter ? { interpreter } : {}, pkgRoot: site?.root ?? "." };
19189
+ }
19190
+ var dedupeTests = (tests) => [...new Map(tests.map((t) => [`${t.runner}:${t.path}`, t])).values()];
19191
+ function changedFiles(repoDir, baseSha) {
19192
+ const run = (args) => safeGit(repoDir, args).split(`
19193
+ `).map((l) => l.trim()).filter(Boolean);
19194
+ const tracked = run(["diff", "--name-only", baseSha]);
19195
+ const untracked = run(["ls-files", "--others", "--exclude-standard"]);
19196
+ return [...new Set([...tracked, ...untracked])].filter((f) => !f.startsWith(".loki/"));
19197
+ }
19198
+ var CODE_EXT = /\.(?:[cm]?[jt]sx?|py|go)$/;
19199
+ var CFG_ALWAYS = /(^|\/)(conftest\.py|\.?pytest\.(?:ini|toml)|tox\.ini|jest\.config\.[\w.]+|vitest\.config\.[\w.]+|\.mocharc[\w.]*)$/;
19200
+ var CFG_SHARED = /(^|\/)(setup\.cfg|pyproject\.toml|package\.json)$/;
19201
+ var CFG_LINE = /^[+-].*(pytest|jest|mocha|vitest|"test"\s*:|addopts|testpaths)/im;
19202
+ function testConfigChanged(repoDir, baseSha, changed) {
19203
+ const diff = (f) => safeGit(repoDir, ["diff", "-U0", baseSha, "--", f]);
19204
+ return changed.filter((f) => CFG_ALWAYS.test(f) || CFG_SHARED.test(f) && (() => {
19205
+ const d = diff(f);
19206
+ return !d || CFG_LINE.test(d);
19207
+ })());
19208
+ }
19209
+ async function runOnce(cmd, args, cwd, signal, opts) {
19210
+ if (!Bun.which(cmd, { PATH: opts.path ?? process.env["PATH"] ?? "" }))
19211
+ return { ok: false, missing: true, cut: false, out: "" };
19212
+ const timeout = AbortSignal.timeout(opts.timeoutMs ?? CHECK_TIMEOUT_MS);
19213
+ const proc = Bun.spawn([cmd, ...args], {
19214
+ cwd,
19215
+ stdin: opts.stdin !== undefined ? Buffer.from(opts.stdin) : "ignore",
19216
+ stdout: "pipe",
19217
+ stderr: "pipe",
19218
+ signal: AbortSignal.any([signal, timeout]),
19219
+ env: opts.path ? { ...process.env, PATH: opts.path } : process.env
19220
+ });
19221
+ let tail = "";
19222
+ const rs = [proc.stdout, proc.stderr].map((s) => s.getReader());
19223
+ const pumps = rs.map(async (r) => {
19224
+ const d = new TextDecoder;
19225
+ for (;; ) {
19226
+ const c = await r.read().catch(() => ({ done: true, value: undefined }));
19227
+ if (c.done)
19228
+ return;
19229
+ tail = (tail + d.decode(c.value, { stream: true })).slice(-65536);
19230
+ }
19231
+ });
19232
+ const exitCode = await proc.exited;
19233
+ await Promise.race([Promise.all(pumps), new Promise((r) => setTimeout(r, 300))]);
19234
+ rs.forEach((r) => r.cancel().catch(() => {}));
19235
+ const cut = timeout.aborted || signal.aborted;
19236
+ return { ok: exitCode === 0 && !cut, missing: false, cut, out: cut ? "" : tail };
19237
+ }
19238
+ function firstError(out2) {
19239
+ const goOut = (l2) => {
19240
+ try {
19241
+ const e = JSON.parse(l2);
19242
+ return typeof e.Action === "string" ? e.Action === "output" || e.Action === "build-output" ? e.Output ?? "" : "" : l2;
19243
+ } catch {
19244
+ return l2;
19245
+ }
19246
+ };
19247
+ const lines = out2.slice(-65536).split(`
19248
+ `).map((l2) => (l2.startsWith("{") ? goOut(l2) : l2).trim()).filter(Boolean), l = lines.find((x) => /^(FAILED\s|\u25cf\s.*\u203a|not ok\s|_{3,}\s.+\s_{3,}$)/.test(x)) ?? lines.find((x) => /^[\w./-]+\.go:\d+:\d+: \S/.test(x)) ?? lines.find((x) => /fail|error/i.test(x) && !/^(=|\u2713|ok\b|PASS)/.test(x)) ?? "";
19249
+ return l.replace(/\d{4}-\d\d-\d\dT[\d:.]+Z?/g, "").replace(/(^|\s)\/(?:[\w.@-]+\/)*[\w.@-]+/g, "$1<path>").replace(/:\d+(?::\d+)?/g, "").replace(/\[?\d+(?:\.\d+)?m?s\]?/g, "").replace(/\s+/g, " ").slice(0, 160);
19250
+ }
19251
+ async function runCheck(ctx, name, cmd, args, signal, checks, opts = {}) {
19252
+ const started = Date.now();
19253
+ const cmdStr = [cmd, ...args].join(" ");
19254
+ const kind = opts.kind ?? "test";
19255
+ const cwd = opts.cwd ?? ctx.repoDir;
19256
+ const one = async (a) => {
19257
+ let c2 = classifyCheck({ kind, ok: a.ok, cut: a.cut, missing: a.missing, out: a.out, ...goRunner(cmd, args), path: /\.[cm]?[jt]s$/.test(args[args.length - 1] ?? "") ? args[args.length - 1] : undefined });
19258
+ const lr = kind === "test" && !a.ok && !a.cut && !a.missing ? await harnessLoadReason({ repoDir: ctx.repoDir, baseSha: ctx.baseSha, out: a.out, cmd, args, signal, cwd, protect: opts.protect, ...opts.path ? { env: { PATH: opts.path } } : {} }) : undefined;
19259
+ if (lr)
19260
+ c2 = { result: "not_run", reason: lr, owner: "harness" };
19261
+ if (!lr && kind === "static" && !a.ok && !a.cut && !a.missing && opts.wall?.size && wallOwnedFailure(a.out, cwd, ctx.repoDir, opts.wall))
19262
+ c2 = { result: "not_run", reason: WALL_COMPILE_REASON, owner: "harness" };
19263
+ const reason2 = a.missing ? `${cmd} not found on PATH` : a.cut ? signal.aborted ? "aborted" : `timed out after ${(opts.timeoutMs ?? CHECK_TIMEOUT_MS) / 1000}s` : c2.reason;
19264
+ return { ...c2, ...reason2 ? { reason: reason2 } : {} };
19265
+ };
19266
+ let attempt = await runOnce(cmd, args, cwd, signal, opts);
19267
+ let c = await one(attempt);
19268
+ let result = c.result;
19269
+ if (c.result === "fail") {
19270
+ attempt = await runOnce(cmd, args, cwd, signal, opts);
19271
+ c = await one(attempt);
19272
+ result = c.result === "not_run" ? "not_run" : c.result === "pass" ? "flaky" : "fail";
19273
+ }
19274
+ const reason = c.reason;
19275
+ const check = { name, cmd: cmdStr, result, duration_s: (Date.now() - started) / 1000, ...result === "fail" ? { first_error: firstError(attempt.out), ids: failIds(attempt.out) } : result === "pass" && kind === "test" ? { n: c.n ?? 0, sk: skipped(attempt.out) } : {}, ...reason ? { reason } : {}, ...c.owner ? { owner: "harness" } : {}, ...opts.interpreter ? { interpreter: opts.interpreter } : {} };
19276
+ checks.push(check);
19277
+ ctx.emit("test.result", "verify", { ...check });
19278
+ return check;
19279
+ }
19280
+ async function subtractBase(ctx, api, checks, tests, changed, wall, rel, signal) {
19281
+ const out2 = { ids: [], names: [], weak: [], cnt: {} };
19282
+ const pairs = checks.flatMap((c) => {
19283
+ const t = tests.find((x) => `${x.runner}:${x.path}` === c.name);
19284
+ return t ? [{ c, t }] : [];
19285
+ });
19286
+ const un = pairs.filter(({ t }) => !changed.includes(t.path));
19287
+ const sus = pairs.filter(({ c }) => rel.has(c.name) && c.result === "pass");
19288
+ if (!(un.some(({ c }) => c.result === "fail" && c.ids?.length) || sus.length) || signal.aborted)
19289
+ return out2;
19290
+ const dir = mkdtempSync5(join38(tmpdir6(), "e10-base-"));
19291
+ const git2 = (args) => {
19292
+ safeGit(ctx.repoDir, args, { stdio: "ignore", repoDrivers: true });
19293
+ };
19294
+ try {
19295
+ git2(["-c", "core.hooksPath=/dev/null", "worktree", "add", "--detach", dir, ctx.baseSha]);
19296
+ const base = new Map;
19297
+ for (const { c, t } of new Set([...un, ...sus])) {
19298
+ const bc = commandFor(t, dir, api), b = await runOnce(bc.cmd, bc.args, bc.cwd, signal, {});
19299
+ base.set(c, { red: !b.ok && !b.cut ? failIds(b.out) : [], n: ran(b.out) ?? ["pass", "fail"].reduce((t2, k) => t2 + +([...b.out.matchAll(new RegExp(`^(?:#|\\u2139) ${k} (\\d+)$`, "gm"))].pop()?.[1] ?? 0), 0), sk: skipped(b.out) });
19300
+ }
19301
+ out2.weak = sus.filter(({ c }) => (c.sk ?? 0) > base.get(c).sk || (c.n ?? 0) < base.get(c).n).map(({ c }) => c.name);
19302
+ for (const { c } of sus)
19303
+ out2.cnt[c.name] = { b: { run: base.get(c).n, skipped: base.get(c).sk }, h: { run: c.n ?? 0, skipped: c.sk ?? 0 } };
19304
+ const progress = checks.some((c) => wall.has(c.name) && c.result === "pass") || sus.some(({ c }) => !out2.weak.includes(c.name) && base.get(c).red.length > 0 && (c.n ?? 0) >= base.get(c).n);
19305
+ if (progress) {
19306
+ for (const { c } of un) {
19307
+ if (!rel.has(c.name) && c.result === "fail" && c.ids?.length && c.ids.every((i) => base.get(c).red.includes(i))) {
19308
+ out2.names.push(c.name);
19309
+ out2.ids.push(...c.ids);
19310
+ }
19311
+ }
19312
+ }
19313
+ } catch {} finally {
19314
+ try {
19315
+ git2(["worktree", "remove", "--force", dir]);
19316
+ } catch {}
19317
+ rmSync8(dir, { recursive: true, force: true });
19318
+ try {
19319
+ git2(["worktree", "prune"]);
19320
+ } catch {}
19321
+ }
19322
+ return out2;
19323
+ }
19324
+ function isLokiModeRepo(repoDir) {
19325
+ return existsSync20(join38(repoDir, "scripts", "select-tests.sh"));
19326
+ }
19327
+ var ESLINT_CONFIGS = [".eslintrc", ".eslintrc.json", ".eslintrc.js", ".eslintrc.cjs", "eslint.config.js", "eslint.config.mjs", "eslint.config.cjs"];
19328
+ async function runLintChecks(ctx, changed, signal, checks, opts = {}) {
19329
+ const { api, ...runOpts } = opts;
19330
+ opts = runOpts;
19331
+ const py = changed.filter((f) => f.endsWith(".py"));
19332
+ if (py.length) {
19333
+ const [ruffCmd, interpreter] = resolveTool(ctx.repoDir, "ruff", "ruff");
19334
+ await runCheck(ctx, "lint:ruff", ruffCmd, ["check", ...py], signal, checks, { ...opts, interpreter, kind: "static" });
19335
+ }
19336
+ const sh = changed.filter((f) => f.endsWith(".sh"));
19337
+ if (sh.length) {
19338
+ await runCheck(ctx, "lint:bash-n", "bash", ["-c", 'for f in "$@"; do bash -n "$f" || exit 1; done', "_", ...sh], signal, checks, { ...opts, kind: "static" });
19339
+ await runCheck(ctx, "lint:shellcheck", "shellcheck", sh, signal, checks, { ...opts, kind: "static" });
19340
+ }
19341
+ for (const g of groupByPackage(api, ctx.repoDir, changed.filter((f) => /\.(ts|tsx|js|jsx)$/.test(f)))) {
19342
+ const sfx = g.root === "." ? "" : `:${g.root}`, co = g.root === "." ? opts : { ...opts, cwd: g.cwd };
19343
+ if (existsSync20(join38(g.cwd, "tsconfig.json")))
19344
+ await runCheck(ctx, `lint:tsc${sfx}`, "npx", ["tsc", "--noEmit", "-p", "."], signal, checks, { ...co, kind: "static" });
19345
+ if (ESLINT_CONFIGS.some((f) => existsSync20(join38(g.cwd, f))))
19346
+ await runCheck(ctx, `lint:eslint${sfx}`, "npx", ["eslint", ...g.rel], signal, checks, { ...co, kind: "static" });
19347
+ }
19348
+ }
19349
+ var verifyStage = {
19350
+ name: "verify",
19351
+ targetS: STAGE_BUDGETS.verify.targetS,
19352
+ limitS: STAGE_BUDGETS.verify.limitS,
19353
+ async run(ctx, signal) {
19354
+ let changed;
19355
+ try {
19356
+ changed = changedFiles(ctx.repoDir, ctx.baseSha);
19357
+ } catch (err) {
19358
+ return { status: "failed", data: {}, reason: `git diff against base failed: ${err.message}` };
19359
+ }
19360
+ if (changed.length === 0) {
19361
+ const implementExit = ctx.outputs().implement?.exit;
19362
+ if (implementExit === "already_done") {
19363
+ return { status: "completed", data: { already_satisfied: true, checks: [], flaky: [], failures_grouped: [], changed_files: [] } };
19364
+ }
19365
+ return { status: "failed", data: { changed_files: [] }, reason: "empty diff without an already_done marker" };
19366
+ }
19367
+ const checks = [];
19368
+ const api = loadProjectApi(ctx.repoDir);
19369
+ const map = await ctx.tests.detect(ctx.repoDir);
19370
+ const impacted = ctx.tests.impacted(map, changed);
19371
+ const changedTestFiles = map.tests.filter((t) => changed.includes(t.path));
19372
+ const wall = ctx.outputs().wall ?? {};
19373
+ const wallPaths = new Set((wall.files ?? []).map((f) => isAbsolute4(f.path) ? relative4(ctx.repoDir, f.path) : f.path));
19374
+ const wallTests = map.tests.filter((t) => wallPaths.has(t.path));
19375
+ const intake = ctx.outputs().intake, relevant = ctx.tests.impacted(map, namedFiles(intake?.task ?? "", loadRepoMap(intake?.repomap_ref)));
19376
+ const tests = dedupeTests([...impacted, ...changedTestFiles, ...wallTests, ...relevant]);
19377
+ const scopedOut = scopedOutOf(map);
19378
+ if (scopedOut.length)
19379
+ ctx.emit("test.scoped_out", "verify", { tests: scopedOut });
19380
+ for (const t of tests) {
19381
+ if (signal.aborted)
19382
+ break;
19383
+ const tc = commandFor(t, ctx.repoDir, api);
19384
+ await runCheck(ctx, `${t.runner}:${t.path}`, tc.cmd, tc.args, signal, checks, { ...tc.interpreter ? { interpreter: tc.interpreter } : {}, protect: [...wallTests, ...relevant].includes(t), ...tc.pkgRoot !== "." ? { cwd: tc.cwd } : {} });
19385
+ }
19386
+ const targetNames = new Set([...wallTests, ...relevant].map((t) => `${t.runner}:${t.path}`));
19387
+ const preRed = await subtractBase(ctx, api, checks, tests, changed, new Set(wallTests.map((t) => `${t.runner}:${t.path}`)), new Set(relevant.map((t) => `${t.runner}:${t.path}`)), signal);
19388
+ if (!signal.aborted) {
19389
+ await runLintChecks(ctx, changed, signal, checks, { api, wall: wallPaths });
19390
+ if (isLokiModeRepo(ctx.repoDir)) {
19391
+ await runCheck(ctx, "select-tests", "bash", ["scripts/select-tests.sh", "--files", "-", "--run"], signal, checks, {
19392
+ kind: "static",
19393
+ stdin: changed.join(`
19394
+ `) + `
19395
+ `
19396
+ });
19397
+ }
19398
+ }
19399
+ const cfgChanged = testConfigChanged(ctx.repoDir, ctx.baseSha, changed);
19400
+ const covered = (f) => ctx.tests.impacted(map, [f]).some((t) => checks.some((c) => c.name === `${t.runner}:${t.path}` && hasExecutedProof([c])));
19401
+ const uncoveredChanged = changed.filter((f) => CODE_EXT.test(f) && !isTestFile(f) && !wallPaths.has(f) && !cfgChanged.includes(f) && !covered(f));
19402
+ const flaky = checks.filter((c) => c.result === "flaky").map((c) => c.name);
19403
+ const failuresGrouped = checks.filter((c) => c.result === "fail" && !preRed.names.includes(c.name)).map((c) => ({ signature: c.first_error ? `${c.name} ${c.first_error}` : c.name, count: 1, sample: c.cmd }));
19404
+ const inBase = (f) => {
19405
+ try {
19406
+ safeGit(ctx.repoDir, ["cat-file", "-e", `${ctx.baseSha}:${f}`], { stdio: "ignore" });
19407
+ return true;
19408
+ } catch {
19409
+ return false;
19410
+ }
19411
+ };
19412
+ const testCounts = {};
19413
+ const modifiedRel = relevant.filter((t) => changed.includes(t.path) && inBase(t.path)).flatMap((t) => {
19414
+ const k = preRed.cnt[`${t.runner}:${t.path}`];
19415
+ if (k)
19416
+ testCounts[t.path] = k;
19417
+ return [`weakened test: ${t.path}`, ...assertDeltaNotes(ctx.repoDir, ctx.baseSha, null, t.path, intake?.task ?? "", k?.b, k?.h) ?? []];
19418
+ });
19419
+ const weakened = [...modifiedRel, ...cfgChanged.map((f) => `test configuration changed: ${f}`), ...preRed.weak.map((n2) => `skipped or fewer tests than base: ${n2}`)];
19420
+ const notProven = [...weakened, ...checks.filter((c) => c.owner === "harness").map((c) => `${c.reason} (${c.name}; harness-owned, no fix rounds)`), ...new Set(checks.filter((c) => c.interpreter === "system" && c.result !== "not_run").map((c) => c.name.startsWith("lint:") ? "lint ran on the system ruff" : "tests ran on the system interpreter"))];
19421
+ return { status: "completed", data: { checks, flaky, failures_grouped: failuresGrouped, changed_files: changed, not_proven: notProven, pre_red: preRed.ids, pre_red_checks: preRed.names, test_counts: testCounts, uncovered_changed: uncoveredChanged, target_checks: checks.filter((c) => c.result === "pass" && targetNames.has(c.name)).map((c) => c.name) } };
19422
+ }
19423
+ };
19424
+
19425
+ // ../../loki-ts/src/engine10/stages/wall.ts
19426
+ var BASE_RUN_TIMEOUT_MS = 60000;
19427
+ function pytestCollectionIsRed(output, repoDir) {
19428
+ if (/ModuleNotFoundError/.test(output))
19429
+ return false;
19430
+ const real2 = (p) => {
19431
+ try {
19432
+ return realpathSync17(isAbsolute5(p) ? p : join39(repoDir, p));
19433
+ } catch {
19434
+ return null;
19435
+ }
19436
+ };
19437
+ const repoReal = real2(repoDir);
19438
+ const under = (p) => {
19439
+ const r = real2(p);
19440
+ return !!repoReal && !!r && (r === repoReal || r.startsWith(`${repoReal}/`));
19441
+ };
19442
+ const imp = /ImportError: cannot import name .* from ['"][\w.]+['"] \(([^)]+)\)/.exec(output);
19443
+ if (imp)
19444
+ return under(imp[1]);
19445
+ const hdr = [...output.matchAll(/^=+ short test summary info =+$/gm)].pop();
19446
+ if (!hdr)
19447
+ return false;
19448
+ const cls = [...output.slice(hdr.index).matchAll(/^ERROR \S+ - (\w+Error): /gm)].pop()?.[1];
19449
+ if (cls !== "AttributeError" && cls !== "NameError")
19450
+ return false;
19451
+ const start = output.search(/^_+ ERROR collecting /m);
19452
+ if (start < 0 || start > hdr.index)
19453
+ return false;
19454
+ const block = output.slice(start, hdr.index).split(/^-+ Captured .*$/m)[0];
19455
+ const eLines = [...block.matchAll(new RegExp(`^E {3}${cls}: (.*)$`, "gm"))];
19456
+ const eLine = eLines[eLines.length - 1];
19457
+ if (!eLine)
19458
+ return false;
19459
+ if (cls === "AttributeError") {
19460
+ const m = /^module ['"]([\w.]+)['"] has no attribute/.exec(eLine[1]);
19461
+ return !!m && moduleUnderRepo(repoDir, m[1]);
19462
+ }
19463
+ const frames = [...block.slice(0, eLine.index).matchAll(/^(.+?):\d+: in \S+\n\s*(.*)$/gm)];
19464
+ const last = frames[frames.length - 1];
19465
+ return !!last && under(last[1]) && !/^\s*(import\s|from\s\S+\s+import\b)/.test(last[2] ?? "");
19466
+ }
19467
+ function moduleUnderRepo(repoDir, name) {
19468
+ const rel = name.replace(/\./g, "/");
19469
+ return existsSync21(join39(repoDir, `${rel}.py`)) || existsSync21(join39(repoDir, rel, "__init__.py"));
19470
+ }
19471
+ function pytestExit1IsRed(output) {
19472
+ if (/^!+ _pytest\.outcomes\.Exit\b/m.test(output))
19473
+ return false;
19474
+ if (/^=*\s*(\d+ \w+(, )?)*\d+ failed\b.* in [\d.]+s/.test(output.trimEnd().split(`
19475
+ `).pop() ?? ""))
19476
+ return true;
19477
+ const hdr = [...output.matchAll(/^=+ short test summary info =+$/gm)].pop();
19478
+ return !!hdr && /^FAILED \S+/m.test(output.slice(hdr.index));
19479
+ }
19480
+ function parsedFailCount(runner, output) {
19481
+ const m = runner === "bun" ? /^\s*(\d+)\s+fail\s*$/m.exec(output) : runner === "jest" ? /Tests:\s*(\d+)\s+failed/i.exec(output) : runner === "vitest" ? /Tests\s+(\d+)\s+failed/i.exec(output) : null;
19482
+ return m ? Number(m[1]) : 0;
19483
+ }
19484
+ function nodeIsRed(f, raw2) {
19485
+ const o = raw2.replace(/^# (?!(?:tests|suites|pass|fail|cancelled|skipped|todo|duration_ms|Subtest)\b)/gm, "");
19486
+ const mod = /^Error(?: \[\w+\])?: Cannot find (?:module|package) '([^']+)'(?:(?!\u2716)[\s\S])*?\nNode\.js v/m.exec(o), top = /^(\S+):\d+\n.*\n.*\n\n?(?:ReferenceError|SyntaxError)\b/m.exec(o);
19487
+ const named = [...o.matchAll(/^(?:\u2716|\s*not ok \d+ -) (?!failing tests:)(.+?)(?: \(|$)/gm)].some((m) => !f.path.endsWith(m[1]) && !m[1].endsWith(f.path)), blk = o.split("failing tests:")[1] ?? "", esm = /^SyntaxError: The requested module '([^']+)' does not provide an export named/m.exec(o), errs = [...blk.matchAll(/^ {2}(\w+Error): .*\n\s+at (?:.*\()?([^\s()]+?):\d+:\d+/gm), ...o.matchAll(/^ +name: '(\w+Error)'\n(?:.*\n)*? +stack: \|-\n\s+(?:.*\()?([^\s()]+?):\d+:\d+/gm)];
19488
+ return /^(?:#|\u2139) fail [1-9]/m.test(raw2) && (/^ {2}AssertionError\b/m.test(blk) || /^ +name: 'AssertionError'/m.test(o) || (mod && !named ? /^[./]/.test(mod[1]) : esm ? /^[./]/.test(esm[1]) : top ? !top[1].endsWith(f.path) : !errs.length || errs.some((e) => !/^(?:Reference|Syntax)Error$/.test(e[1]) || !(e[2].startsWith("node:") || e[2].endsWith(f.path)))));
19489
+ }
19490
+ function classify(f, status, output, repoDir, interpreter) {
19491
+ if (interpreter === "system")
19492
+ return "not_run";
19493
+ if (status === null || status === 126 || status === 127)
19494
+ return "not_run";
19495
+ if (status === 0)
19496
+ return classifyCheck({ kind: "test", ok: true, out: output, path: f.path, ...f.runner === "go" ? { runner: "go" } : {} }).result === "pass" ? "pass" : "not_run";
19497
+ if (f.runner === "pytest")
19498
+ return status === 1 ? pytestExit1IsRed(output) ? "fail" : "not_run" : status === 2 ? pytestCollectionIsRed(output, repoDir) ? "fail" : "not_run" : "not_run";
19499
+ if (f.runner === "jest" || f.runner === "vitest" || f.runner === "bun")
19500
+ return parsedFailCount(f.runner, output) > 0 ? "fail" : "not_run";
19501
+ return f.runner === "node" && nodeIsRed(f, output) ? "fail" : "not_run";
19502
+ }
19503
+
19504
+ class RealBaseTestRunner {
19505
+ api;
19506
+ timeoutMs;
19507
+ constructor(api, timeoutMs = BASE_RUN_TIMEOUT_MS) {
19508
+ this.api = api;
19509
+ this.timeoutMs = timeoutMs;
19510
+ }
19511
+ run(repoDir, files) {
19512
+ let pass = 0, fail = 0, not_run = 0;
19513
+ const api = this.api === undefined ? loadProjectApi(repoDir) : this.api;
19514
+ for (const f of files) {
19515
+ const { cmd, args, interpreter, cwd } = commandFor(f, repoDir, api);
19516
+ const r = spawnSync3(cmd, f.runner === "pytest" ? [...args, "-rfE"] : args, { cwd, encoding: "utf8", timeout: Math.max(1000, this.timeoutMs), env: process.env });
19517
+ const status = r.error ? null : r.status;
19518
+ const result = classify(f, status, `${r.stdout ?? ""}
19519
+ ${r.stderr ?? ""}`, repoDir, interpreter);
19520
+ if (result === "pass")
19521
+ pass++;
19522
+ else if (result === "fail")
19523
+ fail++;
19524
+ else
19525
+ not_run++;
19526
+ }
19527
+ return { pass, fail, not_run };
19528
+ }
19529
+ }
19530
+
19531
+ // ../../loki-ts/src/e10ext/discard.ts
19532
+ import { chmodSync as chmodSync4, closeSync as closeSync6, lstatSync as lstatSync6, mkdirSync as mkdirSync10, openSync as openSync6, readFileSync as readFileSync26, realpathSync as realpathSync18, rmdirSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync13 } from "fs";
19533
+ import { dirname as dirname12, join as join40, relative as relative6, sep as sep11 } from "path";
19534
+ function safeRestore(repoDir, f, want, mode) {
19535
+ const root = realpathSync18(repoDir), fp = join40(root, f), rel = relative6(root, dirname12(fp));
19536
+ if (rel.startsWith(".."))
19537
+ throw new Error("outside repo");
19538
+ let cur = root;
19539
+ for (const part of rel === "" ? [] : rel.split(sep11)) {
19540
+ cur = join40(cur, part);
19541
+ let st2;
19542
+ try {
19543
+ st2 = lstatSync6(cur);
19544
+ } catch {
19545
+ mkdirSync10(cur);
19546
+ continue;
19547
+ }
19548
+ if (!st2.isDirectory())
19549
+ throw new Error("parent is not a real directory");
19550
+ }
19551
+ let st;
19552
+ try {
19553
+ st = lstatSync6(fp);
19554
+ } catch {
19555
+ st = null;
19556
+ }
19557
+ if (st?.isFile() && readFileSync26(fp).equals(want)) {
19558
+ chmodSync4(fp, mode);
19559
+ return;
19560
+ }
19561
+ if (st) {
19562
+ if (st.isDirectory())
19563
+ rmdirSync(fp);
19564
+ else
19565
+ unlinkSync3(fp);
19566
+ }
19567
+ const fd = openSync6(fp, "wx", mode);
19568
+ try {
19569
+ writeFileSync13(fd, want);
19570
+ } finally {
19571
+ closeSync6(fd);
19572
+ }
19573
+ chmodSync4(fp, mode);
19574
+ }
19575
+ function alreadySatisfied(o) {
19576
+ const b = o.wall?.base_run ?? {};
19577
+ return o.intake?.already_satisfied === true || o.implement?.exit === "already_done" || typeof b.pass === "number" && b.pass > 0 && b.fail === 0 && (b.not_run ?? 0) === 0;
19578
+ }
19579
+ function catBlob(repoDir, sha2) {
19580
+ const r = safeGitSpawn(repoDir, ["cat-file", "blob", sha2], { maxBuffer: 1 << 28 });
19581
+ if (r.error || r.status !== 0)
19582
+ throw r.error ?? new Error(`git cat-file blob ${sha2} failed`);
19583
+ return r.stdout;
19584
+ }
19585
+ async function discardIfSatisfied(git2, base, o, staged, keep, repoDir) {
19586
+ if (!alreadySatisfied(o))
19587
+ return null;
19588
+ const pre = Object.assign(Object.create(null), o.intake?.preexisting_dirty ?? {}), own = new Set([...Array.isArray(o.intake?.preexisting_untracked) ? o.intake.preexisting_untracked : [], ...Object.keys(o.intake?.preexisting_untracked_blobs ?? {})]);
19589
+ const gone = staged.filter(({ f }) => !keep.has(f) && !own.has(f) && !Object.hasOwn(pre, f) && !f.startsWith(".loki/")), lit = ["--literal-pathspecs"];
19590
+ const del = gone.filter(({ st }) => st === "A").map(({ f }) => f), back = gone.filter(({ st }) => st !== "A").map(({ f }) => f);
19591
+ if (del.length > 0 && (await git2([...lit, "rm", "-q", "-f", "--", ...del])).code !== 0 || back.length > 0 && (await git2([...lit, "restore", `--source=${base}`, "--staged", "--worktree", "--", ...back])).code !== 0 || (await git2(["reset", "-q", base])).code !== 0)
19592
+ return { status: "failed", data: {}, reason: "already-satisfied discard failed" };
19593
+ const notProven = [];
19594
+ for (const [f, v] of Object.entries(o.intake?.preexisting_untracked_blobs ?? {})) {
19595
+ const fp = join40(repoDir, f);
19596
+ try {
19597
+ if (v.startsWith("!")) {
19598
+ const st = lstatSync6(fp);
19599
+ if (`!${st.size}:${st.mtimeMs}:${st.ctimeMs}` !== v)
19600
+ throw new Error("changed, not snapshotted");
19601
+ continue;
19602
+ }
19603
+ const [sha2, mode] = v.split(" "), want = catBlob(repoDir, sha2);
19604
+ safeRestore(repoDir, f, want, parseInt(mode ?? "644", 8));
19605
+ } catch {
19606
+ notProven.push(f);
19607
+ }
19608
+ }
19609
+ for (const f of Object.keys(pre))
19610
+ if (staged.some((s) => s.f === f) && !keep.has(f)) {
19611
+ try {
19612
+ let m = 420;
19613
+ try {
19614
+ const l = lstatSync6(join40(repoDir, f));
19615
+ if (l.isFile())
19616
+ m = l.mode & 511;
19617
+ } catch {}
19618
+ safeRestore(repoDir, f, catBlob(repoDir, pre[f]), m);
19619
+ } catch {
19620
+ notProven.push(f);
19621
+ }
19622
+ }
19623
+ return { status: "completed", data: { committed: false, discarded: gone.length, ...notProven.length > 0 ? { not_proven: notProven.map((f) => `pre-existing file not restored: ${f}`) } : {} } };
19624
+ }
19625
+
19626
+ // ../../loki-ts/src/e10ext/commit_filter.ts
19627
+ import { dirname as dirname13 } from "path";
19628
+
19629
+ // ../../loki-ts/src/e10ext/preexisting_dirty.ts
19630
+ var blob2 = (repoDir, path, env = process.env) => safeGit(repoDir, ["hash-object", "-w", "--no-filters", "--", path], { env }).trim();
19631
+ function untouchedSinceIntake(repoDir, recorded, env = process.env) {
19632
+ if (!recorded || typeof recorded !== "object")
19633
+ return [];
19634
+ return Object.entries(recorded).filter(([p, h]) => {
19635
+ try {
19636
+ return blob2(repoDir, p, env) === h;
19637
+ } catch {
19638
+ return false;
19639
+ }
19640
+ }).map(([p]) => p);
19641
+ }
19642
+
19643
+ // ../../loki-ts/src/e10ext/commit_filter.ts
19644
+ var parseStaged = (out2) => out2.split("\x00").reduce((a, t, i, all) => i % 2 === 0 && t ? [...a, { st: t, f: all[i + 1] }] : a, []);
19645
+ function dropSet(repoDir, staged, preexistingDirty, env = process.env) {
19646
+ 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) && dirname13(m) === dirname13(f)) && /(^|\/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|bun\.lockb?|poetry\.lock|Cargo\.lock|go\.sum)$/.test(f));
18232
19647
  }
18233
19648
 
19649
+ // ../../loki-ts/src/e10ext/scope.ts
19650
+ import { basename as basename15, dirname as dirname14 } from "path";
19651
+
18234
19652
  // ../../loki-ts/src/features/speed/unit_mode.ts
18235
- import { closeSync as closeSync6, constants, fstatSync as fstatSync4, lstatSync as lstatSync6, openSync as openSync6, readSync as readSync4, realpathSync as realpathSync16 } from "fs";
19653
+ import { closeSync as closeSync7, constants, fstatSync as fstatSync4, lstatSync as lstatSync7, openSync as openSync7, readSync as readSync5, realpathSync as realpathSync19 } from "fs";
18236
19654
  var MAX_SPEC_BYTES = 1024 * 1024;
18237
19655
  var MAX_TOKEN_BUDGET = 1e9;
18238
19656
  var norm2 = (p) => p.replace(/^\.\//, "");
18239
19657
  var CTRL = /[\x00-\x1f\x7f]/;
18240
19658
  var strs = (v) => Array.isArray(v) && v.every((x) => typeof x === "string" && !CTRL.test(x)) ? v.map(norm2) : null;
18241
19659
  function readBounded(path) {
18242
- const l = lstatSync6(path);
19660
+ const l = lstatSync7(path);
18243
19661
  if (l.isSymbolicLink() || !l.isFile() || l.size > MAX_SPEC_BYTES)
18244
19662
  return null;
18245
- const fd = openSync6(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
19663
+ const fd = openSync7(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
18246
19664
  try {
18247
19665
  const st = fstatSync4(fd);
18248
19666
  if (!st.isFile() || st.size > MAX_SPEC_BYTES)
@@ -18250,7 +19668,7 @@ function readBounded(path) {
18250
19668
  const buf = Buffer.alloc(st.size + 1);
18251
19669
  let n2 = 0;
18252
19670
  for (;; ) {
18253
- const r = readSync4(fd, buf, n2, buf.length - n2, null);
19671
+ const r = readSync5(fd, buf, n2, buf.length - n2, null);
18254
19672
  if (r <= 0)
18255
19673
  break;
18256
19674
  n2 += r;
@@ -18259,7 +19677,7 @@ function readBounded(path) {
18259
19677
  }
18260
19678
  return buf.subarray(0, n2).toString("utf8");
18261
19679
  } finally {
18262
- closeSync6(fd);
19680
+ closeSync7(fd);
18263
19681
  }
18264
19682
  }
18265
19683
  function parseText(txt) {
@@ -18300,8 +19718,8 @@ function unitFlags(staged, env = process.env, pre = {}) {
18300
19718
  // ../../loki-ts/src/e10ext/scope.ts
18301
19719
  var SCOPE_UNDETERMINED = "scope not determined; all edits committed";
18302
19720
  var outsideNote = (f) => `outside stated scope: ${f}`;
18303
- var esc = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
18304
- var mentions = (text2, name) => new RegExp(`(?<![\\w./-])${esc(name)}(?![\\w-]|\\.\\w)`).test(text2);
19721
+ var esc2 = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
19722
+ var mentions = (text2, name) => new RegExp(`(?<![\\w./-])${esc2(name)}(?![\\w-]|\\.\\w)`).test(text2);
18305
19723
  var STOP = new Set(["the", "and", "for", "with", "that", "this", "all", "any", "src", "from", "into", "each", "across", "apply", "add", "use", "make"]);
18306
19724
  var stem = (w) => w.length > 3 && w.endsWith("s") ? w.slice(0, -1) : w;
18307
19725
  var surfaceTokens = (text2) => new Set((text2.toLowerCase().match(/[a-z][a-z0-9_-]{2,}/g) ?? []).filter((w) => !STOP.has(w)).map(stem));
@@ -18319,8 +19737,8 @@ function outsideScope(o, staged) {
18319
19737
  const text2 = `${plan}
18320
19738
  ${typeof o.intake?.task === "string" ? o.intake.task : ""}
18321
19739
  ${contractText(o)}`, pre = o.intake?.preexisting_dirty ?? {};
18322
- const toks = surfaceTokens(text2), plannedDirs = new Set(rel.map((r) => dirname9(r)).filter((d) => d !== "."));
18323
- return staged.filter(({ st, f }) => st !== "A" && !isTestFile(f) && !Object.hasOwn(pre, f) && !rel.includes(f) && !mentions(text2, f) && !mentions(text2, basename10(f)) && !plannedDirs.has(dirname9(f)) && !dirSegs(f).some((d) => toks.has(d))).map(({ f }) => f);
19740
+ const toks = surfaceTokens(text2), plannedDirs = new Set(rel.map((r) => dirname14(r)).filter((d) => d !== "."));
19741
+ return staged.filter(({ st, f }) => st !== "A" && !isTestFile(f) && !Object.hasOwn(pre, f) && !rel.includes(f) && !mentions(text2, f) && !mentions(text2, basename15(f)) && !plannedDirs.has(dirname14(f)) && !dirSegs(f).some((d) => toks.has(d))).map(({ f }) => f);
18324
19742
  }
18325
19743
  function flagOutsideScope(o, staged) {
18326
19744
  const unit = unitFlags(staged, process.env, o.intake?.preexisting_dirty ?? {});
@@ -18331,80 +19749,96 @@ function flagOutsideScope(o, staged) {
18331
19749
  // ../../loki-ts/src/util/receipt_signer.ts
18332
19750
  var RECEIPT_SIGNER_BASENAME = "receipt-ed25519.pem";
18333
19751
 
18334
- // ../../loki-ts/src/util/shell.ts
18335
- var MAX_STDOUT_BYTES = 16 * 1024 * 1024;
18336
- async function readStreamCapped(stream, maxBytes = MAX_STDOUT_BYTES) {
18337
- const reader = stream.getReader();
18338
- const decoder = new TextDecoder;
18339
- let out2 = "";
18340
- let total = 0;
19752
+ // ../../loki-ts/src/util/pr_lessons.ts
19753
+ import { existsSync as existsSync22, mkdirSync as mkdirSync12, readFileSync as readFileSync27 } from "fs";
19754
+ import { dirname as dirname16, join as join41 } from "path";
19755
+
19756
+ // ../../loki-ts/src/util/atomic.ts
19757
+ import {
19758
+ closeSync as closeSync8,
19759
+ fstatSync as fstatSync5,
19760
+ fsyncSync as fsyncSync2,
19761
+ lstatSync as lstatSync8,
19762
+ mkdirSync as mkdirSync11,
19763
+ openSync as openSync8,
19764
+ readSync as readSync6,
19765
+ renameSync as renameSync5,
19766
+ rmSync as rmSync10,
19767
+ statSync as statSync12,
19768
+ unlinkSync as unlinkSync4,
19769
+ writeSync as writeSync3
19770
+ } from "fs";
19771
+ import { dirname as dirname15 } from "path";
19772
+ var _tmpCounter = 0;
19773
+ function durableWriteThenRename(target, body) {
19774
+ mkdirSync11(dirname15(target), { recursive: true });
19775
+ const tmp = `${target}.tmp.${process.pid}.${++_tmpCounter}`;
19776
+ const fd = openSync8(tmp, "w");
18341
19777
  try {
18342
- while (total < maxBytes) {
18343
- const { done, value } = await reader.read();
18344
- if (done)
18345
- break;
18346
- if (!value)
18347
- continue;
18348
- total += value.byteLength;
18349
- if (total > maxBytes) {
18350
- const keep = value.byteLength - (total - maxBytes);
18351
- out2 += decoder.decode(value.subarray(0, keep), { stream: true });
18352
- break;
18353
- }
18354
- out2 += decoder.decode(value, { stream: true });
18355
- }
18356
- out2 += decoder.decode();
19778
+ writeSync3(fd, body);
19779
+ fsyncSync2(fd);
18357
19780
  } finally {
18358
- try {
18359
- await reader.cancel();
18360
- } catch {}
18361
- reader.releaseLock();
19781
+ closeSync8(fd);
18362
19782
  }
18363
- return out2;
19783
+ renameSync5(tmp, target);
19784
+ fsyncParentDir(target);
18364
19785
  }
18365
- async function run(argv, opts = {}) {
18366
- const proc = Bun.spawn({
18367
- cmd: [...argv],
18368
- stdout: "pipe",
18369
- stderr: "pipe",
18370
- env: opts.env ? { ...process.env, ...opts.env } : process.env,
18371
- cwd: opts.cwd
18372
- });
18373
- let timer;
18374
- let killTimer;
18375
- if (opts.timeoutMs && opts.timeoutMs > 0) {
18376
- timer = setTimeout(() => {
19786
+ function fsyncParentDir(target) {
19787
+ let dfd = null;
19788
+ try {
19789
+ dfd = openSync8(dirname15(target), "r");
19790
+ fsyncSync2(dfd);
19791
+ } catch {} finally {
19792
+ if (dfd !== null) {
18377
19793
  try {
18378
- proc.kill("SIGTERM");
19794
+ closeSync8(dfd);
18379
19795
  } catch {}
18380
- killTimer = setTimeout(() => {
18381
- try {
18382
- proc.kill("SIGKILL");
18383
- } catch {}
18384
- }, 2000);
18385
- }, opts.timeoutMs);
19796
+ }
18386
19797
  }
19798
+ }
19799
+ function atomicWriteJson(target, data) {
19800
+ durableWriteThenRename(target, `${JSON.stringify(data, null, 2)}
19801
+ `);
19802
+ }
19803
+ var _appendChains = new Map;
19804
+
19805
+ // ../../loki-ts/src/util/pr_lessons.ts
19806
+ var lessonsPath = (repoDir) => join41(repoDir, ".loki", "memory", "semantic", "pr-lessons.json");
19807
+ function loadLessons(repoDir) {
19808
+ const p = lessonsPath(repoDir);
19809
+ if (!existsSync22(p))
19810
+ return [];
18387
19811
  try {
18388
- const [stdout, stderr, exitCode] = await Promise.all([
18389
- readStreamCapped(proc.stdout),
18390
- new Response(proc.stderr).text(),
18391
- proc.exited
18392
- ]);
18393
- return { stdout, stderr, exitCode };
18394
- } finally {
18395
- if (timer)
18396
- clearTimeout(timer);
18397
- if (killTimer)
18398
- clearTimeout(killTimer);
19812
+ const j = JSON.parse(readFileSync27(p, "utf-8"));
19813
+ return Array.isArray(j.lessons) ? j.lessons : [];
19814
+ } catch {
19815
+ return [];
18399
19816
  }
18400
19817
  }
19818
+ function save(repoDir, lessons) {
19819
+ const p = lessonsPath(repoDir);
19820
+ mkdirSync12(dirname16(p), { recursive: true });
19821
+ atomicWriteJson(p, { version: 1, lessons });
19822
+ }
19823
+ function recordRunVerdict(repoDir, runId, verdict) {
19824
+ const lessons = loadLessons(repoDir);
19825
+ let dirty = false;
19826
+ for (const l of lessons)
19827
+ for (const u of l.uses)
19828
+ if (u.run_id === runId && u.verdict === null) {
19829
+ u.verdict = verdict;
19830
+ dirty = true;
19831
+ }
19832
+ if (dirty)
19833
+ save(repoDir, lessons);
19834
+ }
18401
19835
 
18402
19836
  // ../../loki-ts/src/features/visual_evidence.ts
18403
19837
  import { spawn as spawn7 } from "child_process";
18404
- import { createHash as createHash6, randomBytes as randomBytes2 } from "crypto";
18405
- import { existsSync as existsSync17, lstatSync as lstatSync7, mkdirSync as mkdirSync7, readdirSync as readdirSync9, readFileSync as readFileSync21, writeFileSync as writeFileSync10 } from "fs";
19838
+ import { createHash as createHash8, randomBytes as randomBytes2 } from "crypto";
19839
+ import { existsSync as existsSync23, lstatSync as lstatSync9, mkdirSync as mkdirSync13, readdirSync as readdirSync12, readFileSync as readFileSync28, writeFileSync as writeFileSync14 } from "fs";
18406
19840
  import { createServer } from "net";
18407
- import { dirname as dirname10, isAbsolute as isAbsolute2, join as join31, normalize as normalize2, relative as relative3, sep as sep12 } from "path";
19841
+ import { dirname as dirname17, isAbsolute as isAbsolute6, join as join42, normalize as normalize2, relative as relative7, sep as sep12 } from "path";
18408
19842
  var visualEvidenceEnabled = (env = process.env) => env["LOKI_VISUAL_EVIDENCE"] !== "0";
18409
19843
  var PAGE_RE = /^(?:.*\/)?(?:app|pages|src|public)\/.*\.(?:html|jsx|tsx|vue|svelte)$/;
18410
19844
  var isPageFile = (p) => PAGE_RE.test(p);
@@ -18414,12 +19848,12 @@ function routeFor(file) {
18414
19848
  return `/${r}`.replace(/\/+/g, "/");
18415
19849
  }
18416
19850
  var screenName = (route) => (route === "/" ? "index" : route.slice(1).replace(/[^A-Za-z0-9._-]+/g, "_")) || "index";
18417
- var sha256File = (p) => createHash6("sha256").update(readFileSync21(p)).digest("hex");
19851
+ var sha256File = (p) => createHash8("sha256").update(readFileSync28(p)).digest("hex");
18418
19852
  function hashScreens(runDir, rels) {
18419
19853
  const out2 = [];
18420
19854
  for (const rel of rels) {
18421
19855
  try {
18422
- out2.push({ path: rel, sha256: sha256File(join31(runDir, rel)) });
19856
+ out2.push({ path: rel, sha256: sha256File(join42(runDir, rel)) });
18423
19857
  } catch {}
18424
19858
  }
18425
19859
  return out2;
@@ -18430,16 +19864,16 @@ function checkScreens(runDir, screens) {
18430
19864
  for (const s of screens) {
18431
19865
  if (typeof s?.path !== "string" || typeof s.sha256 !== "string")
18432
19866
  return "evidence_screens entry is malformed";
18433
- if (isAbsolute2(s.path) || normalize2(s.path).startsWith(".."))
19867
+ if (isAbsolute6(s.path) || normalize2(s.path).startsWith(".."))
18434
19868
  return `evidence screenshot path escapes the evidence dir: ${s.path}`;
18435
- const file = join31(runDir, s.path);
19869
+ const file = join42(runDir, s.path);
18436
19870
  let cur = runDir;
18437
19871
  for (const seg of normalize2(s.path).split(sep12)) {
18438
- cur = join31(cur, seg);
19872
+ cur = join42(cur, seg);
18439
19873
  if (isSymlink(cur))
18440
19874
  return `evidence screenshot path is a symlink: ${s.path}`;
18441
19875
  }
18442
- if (!existsSync17(file))
19876
+ if (!existsSync23(file))
18443
19877
  return `evidence screenshot is missing: ${s.path}`;
18444
19878
  if (!isRegularFile(file))
18445
19879
  return `evidence screenshot is not a regular file: ${s.path}`;
@@ -18481,16 +19915,16 @@ async function waitUp(url, ms, signal) {
18481
19915
  return false;
18482
19916
  }
18483
19917
  var playwrightBin = (repoDir) => {
18484
- const bin = join31(repoDir, "node_modules", ".bin", "playwright");
18485
- return existsSync17(bin) ? bin : null;
19918
+ const bin = join42(repoDir, "node_modules", ".bin", "playwright");
19919
+ return existsSync23(bin) ? bin : null;
18486
19920
  };
18487
19921
  function openapiPaths(repoDir) {
18488
19922
  for (const f of ["openapi.json", "openapi.yaml", "openapi.yml", "swagger.json"]) {
18489
- const p = join31(repoDir, f);
18490
- if (!existsSync17(p))
19923
+ const p = join42(repoDir, f);
19924
+ if (!existsSync23(p))
18491
19925
  continue;
18492
19926
  try {
18493
- const txt = readFileSync21(p, "utf8");
19927
+ const txt = readFileSync28(p, "utf8");
18494
19928
  const paths = f.endsWith(".json") ? Object.keys(JSON.parse(txt).paths ?? {}) : [...txt.matchAll(/^ {2}(\/[^\s:]*):\s*$/gm)].map((m) => m[1]);
18495
19929
  return paths.filter((x) => !x.includes("{")).slice(0, 10);
18496
19930
  } catch {
@@ -18500,8 +19934,8 @@ function openapiPaths(repoDir) {
18500
19934
  return [];
18501
19935
  }
18502
19936
  var playwrightTestPkg = (repoDir) => {
18503
- const d = join31(repoDir, "node_modules", "@playwright", "test");
18504
- return existsSync17(join31(d, "package.json")) ? d : null;
19937
+ const d = join42(repoDir, "node_modules", "@playwright", "test");
19938
+ return existsSync23(join42(d, "package.json")) ? d : null;
18505
19939
  };
18506
19940
  var e2eSpecSource = (pkgDir, base, routes) => `const { test } = require(${JSON.stringify(pkgDir)});
18507
19941
  test("loki e2e walkthrough", async ({ page }) => {
@@ -18513,24 +19947,24 @@ async function recordE2eMedia(repoDir, runDir, relDir, base, routes, ms, signal)
18513
19947
  if (!pw || !pkg)
18514
19948
  return { rels: [], skipped: "playwright e2e video and trace skipped: @playwright/test is not installed in the repo" };
18515
19949
  try {
18516
- const dir = join31(runDir, relDir, "e2e");
18517
- mkdirSync7(dir, { recursive: true });
18518
- writeFileSync10(join31(dir, "walk.spec.cjs"), e2eSpecSource(pkg, base, routes));
18519
- writeFileSync10(join31(dir, "playwright.config.cjs"), `module.exports = { testDir: ".", testMatch: "walk.spec.cjs", outputDir: "./out", reporter: "null", use: { video: "on", trace: "on" } };
19950
+ const dir = join42(runDir, relDir, "e2e");
19951
+ mkdirSync13(dir, { recursive: true });
19952
+ writeFileSync14(join42(dir, "walk.spec.cjs"), e2eSpecSource(pkg, base, routes));
19953
+ writeFileSync14(join42(dir, "playwright.config.cjs"), `module.exports = { testDir: ".", testMatch: "walk.spec.cjs", outputDir: "./out", reporter: "null", use: { video: "on", trace: "on" } };
18520
19954
  `);
18521
- if (!await shoot(pw, ["test", "--config", join31(dir, "playwright.config.cjs")], repoDir, ms, signal))
19955
+ if (!await shoot(pw, ["test", "--config", join42(dir, "playwright.config.cjs")], repoDir, ms, signal))
18522
19956
  return { rels: [], skipped: "playwright e2e video and trace skipped: the run failed or timed out" };
18523
19957
  const rels = [];
18524
19958
  const walk = (d) => {
18525
- for (const e of readdirSync9(d, { withFileTypes: true })) {
18526
- const full = join31(d, e.name);
19959
+ for (const e of readdirSync12(d, { withFileTypes: true })) {
19960
+ const full = join42(d, e.name);
18527
19961
  if (e.isDirectory())
18528
19962
  walk(full);
18529
19963
  else if (e.isFile() && /\.(webm|zip)$/.test(e.name))
18530
- rels.push(join31(relDir, "e2e", relative3(dir, full)));
19964
+ rels.push(join42(relDir, "e2e", relative7(dir, full)));
18531
19965
  }
18532
19966
  };
18533
- walk(join31(dir, "out"));
19967
+ walk(join42(dir, "out"));
18534
19968
  return rels.length > 0 ? { rels, skipped: null } : { rels, skipped: "playwright e2e video and trace skipped: no video or trace was produced" };
18535
19969
  } catch (e) {
18536
19970
  return { rels: [], skipped: `playwright e2e video and trace skipped: ${String(e?.message ?? e).slice(0, 120)}` };
@@ -18568,14 +20002,14 @@ function shoot(pw, args, cwd, ms, signal) {
18568
20002
  }
18569
20003
  var isSymlink = (p) => {
18570
20004
  try {
18571
- return lstatSync7(p).isSymbolicLink();
20005
+ return lstatSync9(p).isSymbolicLink();
18572
20006
  } catch {
18573
20007
  return false;
18574
20008
  }
18575
20009
  };
18576
20010
  var isRegularFile = (p) => {
18577
20011
  try {
18578
- return lstatSync7(p).isFile();
20012
+ return lstatSync9(p).isFile();
18579
20013
  } catch {
18580
20014
  return false;
18581
20015
  }
@@ -18624,13 +20058,13 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
18624
20058
  if (!visualEvidenceEnabled(opts.env))
18625
20059
  return skip("LOKI_VISUAL_EVIDENCE is 0");
18626
20060
  const api = loadProjectApi(repoDir), boot = isMultiRoot(api) ? api.uiBoot() : null;
18627
- const appDir = boot ? join31(repoDir, boot.boot.cwd) : repoDir;
18628
- const pkgPath = join31(appDir, "package.json");
20061
+ const appDir = boot ? join42(repoDir, boot.boot.cwd) : repoDir;
20062
+ const pkgPath = join42(appDir, "package.json");
18629
20063
  let script = null;
18630
20064
  if (!boot) {
18631
- if (!existsSync17(pkgPath))
20065
+ if (!existsSync23(pkgPath))
18632
20066
  return skip("no package.json");
18633
- script = pickScript(JSON.parse(readFileSync21(pkgPath, "utf8")));
20067
+ script = pickScript(JSON.parse(readFileSync28(pkgPath, "utf8")));
18634
20068
  if (!script)
18635
20069
  return skip("no dev, preview or start script");
18636
20070
  }
@@ -18657,20 +20091,20 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
18657
20091
  }
18658
20092
  if (!await waitUp(base, left(), signal))
18659
20093
  return skip(aborted() ? "aborted" : `${script} server did not answer within ${Math.round(budget / 1000)}s`);
18660
- const evRoot = join31(runDir, "evidence");
20094
+ const evRoot = join42(runDir, "evidence");
18661
20095
  if (isSymlink(evRoot))
18662
20096
  return skip("evidence dir is a symlink");
18663
- mkdirSync7(evRoot, { recursive: true });
20097
+ mkdirSync13(evRoot, { recursive: true });
18664
20098
  if (pages.length > 0) {
18665
- const rel0 = join31("evidence", randomBytes2(6).toString("hex"));
18666
- mkdirSync7(join31(runDir, rel0));
20099
+ const rel0 = join42("evidence", randomBytes2(6).toString("hex"));
20100
+ mkdirSync13(join42(runDir, rel0));
18667
20101
  const rels = [];
18668
20102
  for (const route of [...new Set(pages.map(routeFor))].slice(0, opts.maxRoutes ?? MAX_ROUTES)) {
18669
20103
  if (aborted() || left() <= 0)
18670
20104
  break;
18671
- const rel = join31(rel0, `${screenName(route)}.png`);
18672
- const ok = await shoot(pw, ["screenshot", `${base}${route}`, join31(runDir, rel)], appDir, left(), signal);
18673
- if (ok && !aborted() && !isSymlink(join31(runDir, rel)) && existsSync17(join31(runDir, rel)))
20105
+ const rel = join42(rel0, `${screenName(route)}.png`);
20106
+ const ok = await shoot(pw, ["screenshot", `${base}${route}`, join42(runDir, rel)], appDir, left(), signal);
20107
+ if (ok && !aborted() && !isSymlink(join42(runDir, rel)) && existsSync23(join42(runDir, rel)))
18674
20108
  rels.push(rel);
18675
20109
  }
18676
20110
  if (aborted())
@@ -18695,9 +20129,9 @@ async function captureVisualEvidence(repoDir, runDir, changed, opts = {}) {
18695
20129
  }
18696
20130
  if (aborted())
18697
20131
  return skip("aborted");
18698
- const hdir = join31(evRoot, randomBytes2(6).toString("hex"));
18699
- mkdirSync7(hdir);
18700
- writeFileSync10(join31(hdir, "http.json"), JSON.stringify(rows, null, 2) + `
20132
+ const hdir = join42(evRoot, randomBytes2(6).toString("hex"));
20133
+ mkdirSync13(hdir);
20134
+ writeFileSync14(join42(hdir, "http.json"), JSON.stringify(rows, null, 2) + `
18701
20135
  `);
18702
20136
  return { screens: [], http: true, skipped: null };
18703
20137
  } catch (e) {
@@ -18720,12 +20154,13 @@ async function sealEvidence(repoDir, runDir, o, notProven, signal, emit) {
18720
20154
  return ev.screens.length > 0 ? { evidence_screens: ev.screens } : {};
18721
20155
  }
18722
20156
  function receiptScreensProblem(receiptPath, receipt) {
18723
- return receipt["evidence_screens"] === undefined ? null : checkScreens(dirname10(receiptPath), receipt["evidence_screens"]);
20157
+ return receipt["evidence_screens"] === undefined ? null : checkScreens(dirname17(receiptPath), receipt["evidence_screens"]);
18724
20158
  }
18725
20159
 
18726
20160
  // ../../loki-ts/src/engine10/stages/xreview.ts
18727
- import { existsSync as existsSync18, readFileSync as readFileSync22 } from "fs";
18728
- import { join as join32 } from "path";
20161
+ init_shell();
20162
+ import { existsSync as existsSync24, readFileSync as readFileSync29 } from "fs";
20163
+ import { join as join43 } from "path";
18729
20164
  var RANK2 = { FAILED: 0, SPEC_CONFLICT: 0, PARTIAL: 1, ALREADY_SATISFIED: 2, VERIFIED: 2 };
18730
20165
  var TIMEOUT_MS = 300000;
18731
20166
  var MAX_DIFF = 60000;
@@ -18743,11 +20178,11 @@ function reviewProvider(repoDir, env = process.env) {
18743
20178
  if (e)
18744
20179
  return e;
18745
20180
  for (const f of ["loki.yaml", "loki.yml"]) {
18746
- const p = join32(repoDir, f);
18747
- if (!existsSync18(p))
20181
+ const p = join43(repoDir, f);
20182
+ if (!existsSync24(p))
18748
20183
  continue;
18749
20184
  try {
18750
- const m = /^review:[ \t]*["']?([A-Za-z]+)["']?[ \t]*(?:#.*)?$/m.exec(readFileSync22(p, "utf8"));
20185
+ const m = /^review:[ \t]*["']?([A-Za-z]+)["']?[ \t]*(?:#.*)?$/m.exec(readFileSync29(p, "utf8"));
18751
20186
  const v = asProvider(m?.[1]);
18752
20187
  if (v)
18753
20188
  return v;
@@ -18775,7 +20210,7 @@ async function crossReview(ctx, verdict, head) {
18775
20210
  return null;
18776
20211
  if (verdict !== "VERIFIED" && verdict !== "ALREADY_SATISFIED")
18777
20212
  return null;
18778
- const d = await run(safeGitArgv(["diff", "--no-ext-diff", "--no-color", ctx.baseSha, head, "--", ".", ":(exclude).loki"], false, ctx.repoDir), { cwd: ctx.repoDir, env: safeGitEnv(), timeoutMs: 20000 }).catch(() => null);
20213
+ const d = await safeGitRun(ctx.repoDir, ["diff", "--no-color", ctx.baseSha, head, "--", ".", ":(exclude).loki"], { timeoutMs: 20000 }).catch(() => null);
18779
20214
  if (!d || d.exitCode !== 0)
18780
20215
  return { provider: p, level: "not_run", notes: [`cross-review not run: diff unavailable for ${p}`] };
18781
20216
  const prompt = [
@@ -18797,17 +20232,6 @@ async function crossReview(ctx, verdict, head) {
18797
20232
  }
18798
20233
  }
18799
20234
 
18800
- // ../../loki-ts/src/runner/router/flag.ts
18801
- function routerMode(env = process.env) {
18802
- const v = (env.LOKI_ROUTER ?? "").trim().toLowerCase();
18803
- if (v === "0" || v === "false" || v === "off")
18804
- return "opt-out";
18805
- if (v === "1" || v === "true" || v === "on")
18806
- return "on";
18807
- return "off";
18808
- }
18809
- var routerEnabled = (env = process.env) => routerMode(env) === "on";
18810
-
18811
20235
  // ../../loki-ts/src/runner/router/route_block.ts
18812
20236
  var ALIAS = { haiku: "haiku-5.5", sonnet: "sonnet-5.5", opus: "opus-5.5" };
18813
20237
  var modelLabel = (m) => ALIAS[m] ?? m;
@@ -18824,13 +20248,14 @@ var nN = (v) => typeof v === "number" && Number.isFinite(v) ? v : null;
18824
20248
  var rec = (v) => v === null ? "not recorded" : String(v);
18825
20249
  var s0 = (v) => typeof v === "string" && v.trim() ? v.trim() : null;
18826
20250
  function toEsc(raw2) {
18827
- const esc2 = Array.isArray(raw2) ? raw2 : [];
18828
- return esc2.map((e) => ({ trigger: s0(e["trigger"]) ?? "unknown", from: modelLabel(s0(e["from"]) ?? "?"), to: modelLabel(s0(e["to"]) ?? "?"), evidence: s0(e["evidence"]) ?? "none recorded" }));
20251
+ const esc3 = Array.isArray(raw2) ? raw2 : [];
20252
+ return esc3.map((e) => ({ trigger: s0(e["trigger"]) ?? "unknown", from: modelLabel(s0(e["from"]) ?? "?"), to: modelLabel(s0(e["to"]) ?? "?"), evidence: s0(e["evidence"]) ?? "none recorded" }));
18829
20253
  }
18830
20254
  var assignedBy = (src, explicit) => s0(explicit) ?? (src === null || src === "opus" ? "opus" : src);
18831
- function buildRouteBlock(env, provider, route, telemetry) {
20255
+ function buildRouteBlock(env, provider, route, telemetry, runModel) {
18832
20256
  if (!routerEnabled(env))
18833
20257
  return null;
20258
+ const applied = route?.["applied"] !== false;
18834
20259
  const executor = s0(route?.["executor"]);
18835
20260
  const unavailable = s0(route?.["advisor_unavailable_reason"]) ?? advisorUnavailableReason(env, provider);
18836
20261
  const total = nN(telemetry?.requests_total);
@@ -18840,11 +20265,11 @@ function buildRouteBlock(env, provider, route, telemetry) {
18840
20265
  const source = s0(route?.["source"]);
18841
20266
  const reason = s0(route?.["reason"]) ?? (executor ? "no reason recorded" : "no route recorded by implement");
18842
20267
  const rawUnits = Array.isArray(route?.["units"]) ? route["units"] : [];
18843
- const units = rawUnits.length > 0 ? rawUnits.map((u, i) => ({ id: s0(u["id"]) ?? String(i + 1), executor: modelLabel(s0(u["executor"]) ?? "unknown"), assigned_by: assignedBy(s0(u["source"]) ?? source, u["assigned_by"]), reason: s0(u["reason"]) ?? "no reason recorded", escalations: toEsc(u["escalations"]) })) : executor ? [{ id: "run", executor: modelLabel(executor), assigned_by: assignedBy(source, route?.["assigned_by"]), reason, escalations }] : [];
20268
+ const units = rawUnits.length > 0 ? rawUnits.map((u, i) => ({ id: s0(u["id"]) ?? String(i + 1), executor: modelLabel(s0(u["executor"]) ?? "unknown"), applied, assigned_by: assignedBy(s0(u["source"]) ?? source, u["assigned_by"]), reason: s0(u["reason"]) ?? "no reason recorded", escalations: toEsc(u["escalations"]) })) : executor && route?.["routed"] !== false ? [{ id: "run", executor: modelLabel(executor), applied, assigned_by: assignedBy(source, route?.["assigned_by"]), reason, escalations }] : [];
18844
20269
  return {
18845
- routed: executor !== null || units.length > 0,
20270
+ routed: route?.["routed"] === false ? false : executor !== null || units.length > 0,
18846
20271
  units,
18847
- executor: executor ? modelLabel(executor) : units[0]?.executor ?? null,
20272
+ executor: !applied ? `${runModel ? modelLabel(runModel) : "run model"} (per-unit assignment not applied)` : executor ? modelLabel(executor) : units[0]?.executor ?? null,
18848
20273
  advisor: unavailable ? null : modelLabel(s0(route?.["advisor"]) ?? "opus"),
18849
20274
  advisor_unavailable_reason: unavailable,
18850
20275
  reason,
@@ -18857,7 +20282,11 @@ function buildRouteBlock(env, provider, route, telemetry) {
18857
20282
  over_100k_share: total !== null && over !== null && total > 0 ? Math.round(over / total * 1e4) / 1e4 : null,
18858
20283
  advisor_calls: nN(telemetry?.advisor_calls),
18859
20284
  advisor_input_tokens: nN(telemetry?.advisor_input_tokens),
18860
- advisor_output_tokens: nN(telemetry?.advisor_output_tokens)
20285
+ advisor_output_tokens: nN(telemetry?.advisor_output_tokens),
20286
+ plan_model: s0(route?.["plan_model"]),
20287
+ applied,
20288
+ run_model: runModel ?? null,
20289
+ not_proven: Array.isArray(route?.["route_not_proven"]) ? route["route_not_proven"].filter((x) => typeof x === "string") : []
18861
20290
  };
18862
20291
  }
18863
20292
  var over = (r, unit) => r.requests_total === null || r.requests_over_100k === null ? "not recorded" : `${r.requests_over_100k} of ${r.requests_total}${unit} (${pct(r)})`;
@@ -18876,119 +20305,154 @@ function routeReceiptLines(r) {
18876
20305
  `- Route shape_key: ${r.shape_key ?? "unknown"} shape_parity: ${r.shape_parity}`,
18877
20306
  `- Route escalations: ${r.escalations.length === 0 ? "none" : r.escalations.map((e) => `${e.from} -> ${e.to} (${e.trigger}; evidence ${e.evidence})`).join("; ")}`,
18878
20307
  `- Route advisor: ${rec(r.advisor_calls)} calls, ${rec(r.advisor_input_tokens)} in / ${rec(r.advisor_output_tokens)} out tokens`,
18879
- ...r.units.map((u) => `- Route unit ${u.id}: executor ${u.executor}, assigned by ${u.assigned_by}: ${u.reason}; escalation: ${u.escalations.length === 0 ? "none" : u.escalations.map((e) => `${e.from} -> ${e.to} (${e.trigger})`).join(", ")}`),
20308
+ ...r.units.map((u) => `- Route unit ${u.id}: executor ${u.applied ? u.executor : `not applied (assigned ${u.executor})`}, assigned by ${u.assigned_by}: ${u.reason}; escalation: ${u.escalations.length === 0 ? "none" : u.escalations.map((e) => `${e.from} -> ${e.to} (${e.trigger})`).join(", ")}`),
18880
20309
  `- Route requests over 100K: ${over(r, "")}`
18881
20310
  ];
18882
20311
  }
18883
20312
  function routeNotProven(r) {
18884
20313
  return [
18885
20314
  ...r.advisor_unavailable_reason ? [`advisor: NOT PROVEN (owner provider): ${r.advisor_unavailable_reason}`] : [],
18886
- `route.shape_parity: ${r.shape_parity}`
20315
+ `route.shape_parity: ${r.shape_parity}`,
20316
+ ...r.applied ? [] : [`route.executor: NOT PROVEN (owner engine): per-unit executor assignment is not applied (R1-11); every stage ran ${r.run_model ?? "the run model"}`],
20317
+ ...r.not_proven
18887
20318
  ];
18888
20319
  }
18889
20320
 
18890
- // ../../loki-ts/src/engine10/cost.ts
18891
- import { mkdirSync as mkdirSync8, readdirSync as readdirSync10, readFileSync as readFileSync23, writeFileSync as writeFileSync11 } from "fs";
18892
- import { join as join33 } from "path";
18893
- var UNMETERED = "cli-invoker-unmetered";
18894
- function routerTelemetryOn(env = process.env) {
18895
- return routerEnabled(env);
20321
+ // ../../loki-ts/src/runner/router/route_record.ts
20322
+ import { existsSync as existsSync25, lstatSync as lstatSync10, mkdirSync as mkdirSync14, readFileSync as readFileSync30, writeFileSync as writeFileSync15 } from "fs";
20323
+ import { join as join44 } from "path";
20324
+ var ROUTE_RECORD_FILE = "route.json";
20325
+ function loadRouteRecord(runDir) {
20326
+ try {
20327
+ const p = join44(runDir, ROUTE_RECORD_FILE);
20328
+ if (!existsSync25(p) || !lstatSync10(p).isFile())
20329
+ return;
20330
+ const v = JSON.parse(readFileSync30(p, "utf8"));
20331
+ return typeof v === "object" && v !== null && !Array.isArray(v) ? v : undefined;
20332
+ } catch {
20333
+ return;
20334
+ }
18896
20335
  }
18897
- function num3(v) {
18898
- return typeof v === "number" && Number.isFinite(v) ? v : 0;
20336
+
20337
+ // ../../loki-ts/src/runner/router/history.ts
20338
+ import { dirname as dirname18, join as join45, resolve as resolve11 } from "path";
20339
+ import { fileURLToPath as fileURLToPath3 } from "url";
20340
+
20341
+ // ../../loki-ts/src/runner/router/history_store.ts
20342
+ import { existsSync as existsSync26, mkdirSync as mkdirSync15, readFileSync as readFileSync31, renameSync as renameSync6, rmSync as rmSync11, writeFileSync as writeFileSync16 } from "fs";
20343
+ import { resolve as resolve10 } from "path";
20344
+ var HISTORY_FILE = "router_history.json";
20345
+ var HISTORY_CAP = 200;
20346
+ var EXECUTORS = ["haiku", "sonnet"];
20347
+ var VERDICTS = ["pass", "fail", "error", "not_proven"];
20348
+ var OWNERS = ["code", "harness", "env", "provider"];
20349
+ function validRun(v) {
20350
+ if (typeof v !== "object" || v === null)
20351
+ return false;
20352
+ const r = v;
20353
+ return typeof r["shape"] === "string" && typeof r["executor"] === "string" && EXECUTORS.includes(r["executor"]) && typeof r["verdict"] === "string" && VERDICTS.includes(r["verdict"]) && (r["owner"] === null || typeof r["owner"] === "string" && OWNERS.includes(r["owner"])) && typeof r["escalated"] === "boolean" && typeof r["usd"] === "number" && Number.isFinite(r["usd"]) && typeof r["wallS"] === "number" && Number.isFinite(r["wallS"]);
18899
20354
  }
18900
- function resultCostPath(lokiRoot, iteration) {
18901
- return join33(lokiRoot, "metrics", `result-cost-${iteration}.json`);
20355
+ function historyPath(key, cacheRoot) {
20356
+ return resolve10(repoCacheDir(key, cacheRoot), HISTORY_FILE);
18902
20357
  }
18903
- function sumResultCosts(lokiRoot, iterations) {
18904
- const out2 = {
18905
- usd: null,
18906
- partialUsd: 0,
18907
- measuredCount: 0,
18908
- totalCount: iterations.length,
18909
- input_tokens: 0,
18910
- output_tokens: 0,
18911
- cache_read_tokens: 0,
18912
- cache_creation_tokens: 0,
18913
- ...routerTelemetryOn() ? { router: {
18914
- requests_total: 0,
18915
- requests_over_100k: 0,
18916
- over_100k_input_tokens: 0,
18917
- over_100k_output_tokens: 0,
18918
- advisor_calls: 0,
18919
- advisor_input_tokens: 0,
18920
- advisor_output_tokens: 0
18921
- } } : {},
18922
- model: null,
18923
- source: "",
18924
- missing: []
18925
- };
18926
- const sources2 = [];
18927
- let usd = 0;
18928
- for (const iter of iterations) {
18929
- const path = resultCostPath(lokiRoot, iter);
18930
- let rec2;
20358
+ function readRunHistory(key, cacheRoot) {
20359
+ const path = historyPath(key, cacheRoot);
20360
+ if (!existsSync26(path))
20361
+ return [];
20362
+ try {
20363
+ const parsed = JSON.parse(readFileSync31(path, "utf8"));
20364
+ const runs2 = parsed?.runs;
20365
+ return Array.isArray(runs2) ? runs2.filter(validRun) : [];
20366
+ } catch {
20367
+ return [];
20368
+ }
20369
+ }
20370
+ function appendRunOutcome(key, outcome, cacheRoot) {
20371
+ try {
20372
+ const runs2 = [...readRunHistory(key, cacheRoot), outcome].slice(-HISTORY_CAP);
20373
+ mkdirSync15(repoCacheDir(key, cacheRoot), { recursive: true });
20374
+ const target = historyPath(key, cacheRoot);
20375
+ const tmp = `${target}.${process.pid}.tmp`;
18931
20376
  try {
18932
- rec2 = JSON.parse(readFileSync23(path, "utf8"));
18933
- } catch {
18934
- out2.missing.push(iter);
18935
- continue;
18936
- }
18937
- const inTok = num3(rec2["input_tokens"]);
18938
- const outTok = num3(rec2["output_tokens"]);
18939
- const cacheR = num3(rec2["cache_read_tokens"]);
18940
- const cacheC = num3(rec2["cache_creation_tokens"]);
18941
- out2.input_tokens += inTok;
18942
- out2.output_tokens += outTok;
18943
- out2.cache_read_tokens += cacheR;
18944
- out2.cache_creation_tokens += cacheC;
18945
- if (out2.router)
18946
- out2.router["requests_total"] += num3(rec2["requests_total"]);
18947
- if (out2.router)
18948
- out2.router["requests_over_100k"] += num3(rec2["requests_over_100k"]);
18949
- if (out2.router)
18950
- out2.router["over_100k_input_tokens"] += num3(rec2["over_100k_input_tokens"]);
18951
- if (out2.router)
18952
- out2.router["over_100k_output_tokens"] += num3(rec2["over_100k_output_tokens"]);
18953
- if (out2.router)
18954
- out2.router["advisor_calls"] += num3(rec2["advisor_calls"]);
18955
- if (out2.router)
18956
- out2.router["advisor_input_tokens"] += num3(rec2["advisor_input_tokens"]);
18957
- if (out2.router)
18958
- out2.router["advisor_output_tokens"] += num3(rec2["advisor_output_tokens"]);
18959
- if (typeof rec2["model"] === "string" && rec2["model"])
18960
- out2.model = rec2["model"];
18961
- sources2.push(path);
18962
- const c = rec2["total_cost_usd"];
18963
- const unmetered = rec2["source"] === UNMETERED;
18964
- if (unmetered)
18965
- out2.unmetered = true;
18966
- const noUsage = !unmetered && inTok === 0 && outTok === 0 && cacheR === 0 && cacheC === 0;
18967
- if (typeof c !== "number" || !Number.isFinite(c) || noUsage) {
18968
- out2.missing.push(iter);
18969
- continue;
20377
+ writeFileSync16(tmp, JSON.stringify({ runs: runs2 }));
20378
+ renameSync6(tmp, target);
20379
+ } catch (e) {
20380
+ rmSync11(tmp, { force: true, recursive: false });
20381
+ throw e;
18970
20382
  }
18971
- usd += c;
18972
- out2.partialUsd += c;
18973
- out2.measuredCount++;
20383
+ return true;
20384
+ } catch {
20385
+ return false;
20386
+ }
20387
+ }
20388
+ // ../../loki-ts/src/runner/router/history.ts
20389
+ var SHAPE_DEFAULTS_FILE = resolve11(dirname18(fileURLToPath3(import.meta.url)), "..", "..", "..", "data", "router-shape-defaults.json");
20390
+ function shapeKey(model) {
20391
+ if (!model || model.status !== "ok")
20392
+ return null;
20393
+ const runners = new Set(model.packages.map((p) => (p.runner ?? "").trim().toLowerCase() || "none"));
20394
+ return `${model.workspaceKind}:${[...runners].sort().join("+")}`;
20395
+ }
20396
+ function shapeKeyForRepo(repoDir) {
20397
+ try {
20398
+ const dirs = shallowDirs(repoDir);
20399
+ const committed = loadCommitted(repoDir);
20400
+ if (committed)
20401
+ return shapeKey({ ...committed.model, key: computeKey(repoDir, committed.model.fingerprintFiles, dirs, committed.hash) });
20402
+ const cached = loadCached(repoDir);
20403
+ if (!cached || computeKey(repoDir, cached.fingerprintFiles, dirs) !== cached.key)
20404
+ return null;
20405
+ return shapeKey(cached);
20406
+ } catch {
20407
+ return null;
18974
20408
  }
18975
- out2.source = sources2.join(",");
18976
- if (iterations.length > 0 && out2.missing.length === 0)
18977
- out2.usd = usd;
18978
- return out2;
18979
20409
  }
18980
20410
 
18981
- // ../../loki-ts/src/util/check_result.ts
18982
- var NO_TESTS_REASON = "no tests executed";
18983
- var UNCONFIRMED_REASON = "test count could not be confirmed";
18984
- var UNMEASURED_REASON = "executed count unmeasured (Loki could not parse the runner summary, harness-owned)";
18985
- var isExecutedProof = (c) => c.result === "pass" && typeof c.n === "number" && c.n > 0;
18986
- var hasExecutedProof = (checks) => checks.some(isExecutedProof);
20411
+ // ../../loki-ts/src/util/engine_origin.ts
20412
+ function readOriginUrl(repoDir) {
20413
+ try {
20414
+ const url = safeGit(repoDir, ["config", "--get", "remote.origin.url"]).trim();
20415
+ return url || null;
20416
+ } catch {
20417
+ return null;
20418
+ }
20419
+ }
20420
+
20421
+ // ../../loki-ts/src/runner/router/cost_preview.ts
20422
+ var NOT_RECORDED = "NOT RECORDED";
20423
+ var previewOn = (env) => env["LOKI_COST_PREVIEW"] !== "0";
20424
+ function receiptBlock(env, usd, unmetered, wallS) {
20425
+ if (!previewOn(env))
20426
+ return {};
20427
+ let r = { ok: false, reason: "no estimate carried from the run start" };
20428
+ try {
20429
+ const raw2 = env["LOKI_E10_COST_ESTIMATE"];
20430
+ if (raw2)
20431
+ r = JSON.parse(raw2);
20432
+ } catch {}
20433
+ const source = r.ok === true ? "history" : r.prior ? "rough_prior" : null;
20434
+ return { cost_preview: {
20435
+ ...source ? { estimate_source: source } : {},
20436
+ estimate: !r.ok && r.prior ? { usd_low: r.prior.usd[0], usd_high: r.prior.usd[1], tier: r.prior.tier, size_class: r.prior.size_class } : r.ok === true ? { usd_low: r.est.usd[0], usd_high: r.est.usd[1], wall_low_s: r.est.wall_s[0], wall_high_s: r.est.wall_s[1], prior_runs: r.est.runs, shape: r.est.shape } : `NOT AVAILABLE (${r.reason ?? "unreadable estimate"})`,
20437
+ actual: { usd: usd === null || unmetered ? NOT_RECORDED : usd, wall_s: wallS === null || wallS <= 0 ? NOT_RECORDED : wallS }
20438
+ } };
20439
+ }
20440
+ function recordRun(env, repoDir, model, verdict, usd, unmetered, wallS, cacheRoot) {
20441
+ if (!previewOn(env) || verdict !== "VERIFIED" || usd === null || unmetered || wallS <= 0)
20442
+ return false;
20443
+ const shape = shapeKeyForRepo(repoDir);
20444
+ if (shape === null)
20445
+ return false;
20446
+ return appendRunOutcome(repoKey(readOriginUrl(repoDir), repoDir), { shape, executor: /haiku/i.test(model) ? "haiku" : "sonnet", verdict: "pass", owner: null, escalated: false, usd, wallS }, cacheRoot);
20447
+ }
20448
+
20449
+ // ../../loki-ts/src/engine10/stages/seal.ts
20450
+ init_cost();
18987
20451
 
18988
20452
  // ../../loki-ts/src/features/contract.ts
18989
- import { existsSync as existsSync19, lstatSync as lstatSync8, mkdirSync as mkdirSync9, readFileSync as readFileSync24, writeFileSync as writeFileSync12 } from "fs";
18990
- import { dirname as dirname11, join as join34 } from "path";
18991
- import { createHash as createHash7 } from "crypto";
20453
+ import { existsSync as existsSync27, lstatSync as lstatSync11, mkdirSync as mkdirSync16, readFileSync as readFileSync32, writeFileSync as writeFileSync17 } from "fs";
20454
+ import { dirname as dirname19, join as join46 } from "path";
20455
+ import { createHash as createHash9 } from "crypto";
18992
20456
  var MAX_CRITERIA = 50;
18993
20457
  var MAX_TEXT = 500;
18994
20458
  function contractEnabled(env = process.env) {
@@ -19002,11 +20466,11 @@ function overlaps(criterionWords, target) {
19002
20466
  const tw = new Set(words(target));
19003
20467
  return criterionWords.some((w) => tw.has(w) || w.length > 4 && w.endsWith("s") && tw.has(w.slice(0, -1)));
19004
20468
  }
19005
- function traceContract(contract, changedFiles, checkNames) {
20469
+ function traceContract(contract, changedFiles2, checkNames) {
19006
20470
  return {
19007
20471
  criteria: contract.criteria.map((c) => {
19008
20472
  const cw = words(c.text);
19009
- const files = changedFiles.filter((f) => overlaps(cw, f));
20473
+ const files = changedFiles2.filter((f) => overlaps(cw, f));
19010
20474
  const checks = checkNames.filter((n2) => overlaps(cw, n2));
19011
20475
  const traced = files.length > 0;
19012
20476
  return { id: c.id, text: c.text, files, checks: traced ? checks : [], status: traced ? "keyword_match" : "no_match" };
@@ -19022,14 +20486,14 @@ function untracedLines(trace) {
19022
20486
  return trace.criteria.filter((c) => c.status === "no_match").map((c) => `contract ${sanitizeCriterion(c.id)} untraced (no keyword match in changed files): ${sanitizeCriterion(c.text)}`);
19023
20487
  }
19024
20488
  function contractPath(repoDir) {
19025
- return join34(repoDir, ".loki", "contract.json");
20489
+ return join46(repoDir, ".loki", "contract.json");
19026
20490
  }
19027
20491
  var MAX_CONTRACT_BYTES = 1024 * 1024;
19028
20492
  function readContract(repoDir) {
19029
20493
  const p = contractPath(repoDir);
19030
20494
  let st;
19031
20495
  try {
19032
- st = lstatSync8(p);
20496
+ st = lstatSync11(p);
19033
20497
  } catch {
19034
20498
  return { contract: null, notes: [], sha256: null };
19035
20499
  }
@@ -19039,19 +20503,19 @@ function readContract(repoDir) {
19039
20503
  return { contract: null, notes: ["contract unreadable: too large"], sha256: null };
19040
20504
  let raw2;
19041
20505
  try {
19042
- raw2 = readFileSync24(p);
20506
+ raw2 = readFileSync32(p);
19043
20507
  } catch {
19044
20508
  return { contract: null, notes: ["contract unreadable: read failed"], sha256: null };
19045
20509
  }
19046
- const sha2562 = createHash7("sha256").update(raw2).digest("hex");
20510
+ const sha2563 = createHash9("sha256").update(raw2).digest("hex");
19047
20511
  let j;
19048
20512
  try {
19049
20513
  j = JSON.parse(raw2.toString("utf8"));
19050
20514
  } catch {
19051
- return { contract: null, notes: ["contract unreadable: invalid JSON"], sha256: sha2562 };
20515
+ return { contract: null, notes: ["contract unreadable: invalid JSON"], sha256: sha2563 };
19052
20516
  }
19053
20517
  if (!Array.isArray(j?.criteria))
19054
- return { contract: null, notes: [], sha256: sha2562 };
20518
+ return { contract: null, notes: [], sha256: sha2563 };
19055
20519
  const criteria = [];
19056
20520
  let malformed = 0;
19057
20521
  for (const c of j.criteria) {
@@ -19065,7 +20529,7 @@ function readContract(repoDir) {
19065
20529
  criteria.push({ id: o.id.slice(0, 40), text: o.text.slice(0, MAX_TEXT), source_line: typeof o.source_line === "number" ? o.source_line : 0 });
19066
20530
  }
19067
20531
  const notes = malformed > 0 ? [`contract: ${malformed} malformed criteria dropped`] : [];
19068
- return { contract: { source: typeof j.source === "string" ? j.source : "", criteria }, notes, sha256: sha2562 };
20532
+ return { contract: { source: typeof j.source === "string" ? j.source : "", criteria }, notes, sha256: sha2563 };
19069
20533
  }
19070
20534
  function sealContract(repoDir, body, rawDiff, checks, env = process.env, snap) {
19071
20535
  if (!contractEnabled(env))
@@ -19074,7 +20538,7 @@ function sealContract(repoDir, body, rawDiff, checks, env = process.env, snap) {
19074
20538
  const live2 = readContract(repoDir);
19075
20539
  let exists2 = true;
19076
20540
  try {
19077
- lstatSync8(contractPath(repoDir));
20541
+ lstatSync11(contractPath(repoDir));
19078
20542
  } catch {
19079
20543
  exists2 = false;
19080
20544
  }
@@ -19102,33 +20566,33 @@ function sealContract(repoDir, body, rawDiff, checks, env = process.env, snap) {
19102
20566
  }
19103
20567
 
19104
20568
  // ../../loki-ts/src/features/speed/seal_group.ts
19105
- import { createHash as createHash8 } from "crypto";
19106
- import { existsSync as existsSync20, readdirSync as readdirSync11, readFileSync as readFileSync25, statSync as statSync12 } from "fs";
19107
- import { dirname as dirname12, join as join35 } from "path";
20569
+ import { createHash as createHash10 } from "crypto";
20570
+ import { existsSync as existsSync28, readdirSync as readdirSync13, readFileSync as readFileSync33, statSync as statSync13 } from "fs";
20571
+ import { dirname as dirname20, join as join47 } from "path";
19108
20572
  var ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
19109
20573
  var PASSING = new Set(["VERIFIED", "ALREADY_SATISFIED"]);
19110
- var sha2 = (b) => createHash8("sha256").update(b).digest("hex");
20574
+ var sha2 = (b) => createHash10("sha256").update(b).digest("hex");
19111
20575
  var isObj10 = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
19112
20576
  var text2 = (v, cap) => typeof v === "string" ? v.replace(/[\x00-\x1f\x7f]+/g, " ").trim().slice(0, cap) : "";
19113
20577
  var num4 = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : 0;
19114
- var unitsDir = (runDir) => join35(runDir, "group", "units");
20578
+ var unitsDir = (runDir) => join47(runDir, "group", "units");
19115
20579
  var readJson3 = (p) => {
19116
20580
  try {
19117
- return JSON.parse(readFileSync25(p, "utf8"));
20581
+ return JSON.parse(readFileSync33(p, "utf8"));
19118
20582
  } catch {
19119
20583
  return;
19120
20584
  }
19121
20585
  };
19122
20586
  var dirNames = (d) => {
19123
20587
  try {
19124
- return readdirSync11(d).filter((n2) => !n2.startsWith(".")).sort();
20588
+ return readdirSync13(d).filter((n2) => !n2.startsWith(".")).sort();
19125
20589
  } catch {
19126
20590
  return null;
19127
20591
  }
19128
20592
  };
19129
20593
  function sealGroup(runDir, rh) {
19130
- const manifestPath = join35(runDir, "group", "manifest.json");
19131
- if (!existsSync20(manifestPath))
20594
+ const manifestPath = join47(runDir, "group", "manifest.json");
20595
+ if (!existsSync28(manifestPath))
19132
20596
  return { section: undefined, notProven: [], problems: 0, allUnitsPass: true };
19133
20597
  const notProven = [];
19134
20598
  let problems = 0;
@@ -19152,10 +20616,10 @@ function sealGroup(runDir, rh) {
19152
20616
  return fail(`unit ${index2} has an invalid, duplicate or case-colliding id`);
19153
20617
  seen.add(id);
19154
20618
  seenLower.add(id.toLowerCase());
19155
- const dir = join35(unitsDir(runDir), id), rp = join35(dir, "receipt.json"), ep = join35(dir, "events.jsonl");
20619
+ const dir = join47(unitsDir(runDir), id), rp = join47(dir, "receipt.json"), ep = join47(dir, "events.jsonl");
19156
20620
  let bytes;
19157
20621
  try {
19158
- bytes = readFileSync25(rp);
20622
+ bytes = readFileSync33(rp);
19159
20623
  } catch {
19160
20624
  return fail(`unit ${id} sub-receipt missing`);
19161
20625
  }
@@ -19172,7 +20636,7 @@ function sealGroup(runDir, rh) {
19172
20636
  unit_id: id,
19173
20637
  sub_receipt_sha256: sha2(bytes),
19174
20638
  receipt_sha256: sub["receipt_sha256"],
19175
- events_file_sha256: existsSync20(ep) ? sha2(readFileSync25(ep)) : null,
20639
+ events_file_sha256: existsSync28(ep) ? sha2(readFileSync33(ep)) : null,
19176
20640
  verdict,
19177
20641
  goal: text2(u["goal"], 200),
19178
20642
  files: (Array.isArray(u["files"]) ? u["files"] : []).map((f) => text2(f, 200)).filter(Boolean).slice(0, 50),
@@ -19192,12 +20656,12 @@ function capGroupVerdict(v, g) {
19192
20656
  return !g.allUnitsPass && (v === "VERIFIED" || v === "ALREADY_SATISFIED") ? "PARTIAL" : v;
19193
20657
  }
19194
20658
  async function verifyGroup(receiptPath, receipt, rh, verifyOne, deps = {}) {
19195
- const runDir = dirname12(receiptPath);
20659
+ const runDir = dirname20(receiptPath);
19196
20660
  const signed = isObj10(receipt["verification"]) && typeof receipt["verification"]["jwt"] === "string";
19197
20661
  const bad = (reason) => ({ verdict: "TAMPERED", reason: `group: ${reason}` });
19198
20662
  const g = receipt["group"];
19199
20663
  if (g === undefined)
19200
- return existsSync20(join35(runDir, "group", "manifest.json")) ? bad("group directory present but the receipt has no group section") : null;
20664
+ return existsSync28(join47(runDir, "group", "manifest.json")) ? bad("group directory present but the receipt has no group section") : null;
19201
20665
  if (!isObj10(g) || !ID_RE.test(String(g["group_id"] ?? "")) || !Array.isArray(g["units"]) || g["units"].length === 0)
19202
20666
  return bad("group section malformed");
19203
20667
  const entries = g["units"];
@@ -19209,20 +20673,20 @@ async function verifyGroup(receiptPath, receipt, rh, verifyOne, deps = {}) {
19209
20673
  return bad("unit directories do not match the receipt (missing or extra unit)");
19210
20674
  let unchecked = null;
19211
20675
  for (let i = 0;i < entries.length; i++) {
19212
- const e = entries[i], id = ids[i], dir = join35(unitsDir(runDir), id), rp = join35(dir, "receipt.json"), ep = join35(dir, "events.jsonl");
20676
+ const e = entries[i], id = ids[i], dir = join47(unitsDir(runDir), id), rp = join47(dir, "receipt.json"), ep = join47(dir, "events.jsonl");
19213
20677
  if (e["index"] !== i)
19214
20678
  return bad(`unit ${id} is out of order (index ${String(e["index"])} at position ${i})`);
19215
20679
  let bytes;
19216
20680
  try {
19217
- if (!statSync12(dir).isDirectory())
20681
+ if (!statSync13(dir).isDirectory())
19218
20682
  return bad(`unit ${id} is not a directory`);
19219
- bytes = readFileSync25(rp);
20683
+ bytes = readFileSync33(rp);
19220
20684
  } catch {
19221
20685
  return bad(`unit ${id} sub-receipt missing`);
19222
20686
  }
19223
20687
  if (sha2(bytes) !== e["sub_receipt_sha256"])
19224
20688
  return bad(`unit ${id} sub-receipt does not match its recorded hash`);
19225
- const evSha = existsSync20(ep) ? sha2(readFileSync25(ep)) : null;
20689
+ const evSha = existsSync28(ep) ? sha2(readFileSync33(ep)) : null;
19226
20690
  if (evSha !== (e["events_file_sha256"] ?? null))
19227
20691
  return bad(`unit ${id} events.jsonl does not match its recorded hash`);
19228
20692
  const sub = readJson3(rp);
@@ -19241,11 +20705,263 @@ async function verifyGroup(receiptPath, receipt, rh, verifyOne, deps = {}) {
19241
20705
  return unchecked ? { verdict: "UNCHECKED", reason: `group: ${unchecked}` } : null;
19242
20706
  }
19243
20707
 
20708
+ // ../../loki-ts/src/supply/supply_guard.ts
20709
+ init_shell();
20710
+ import { existsSync as existsSync29, readFileSync as readFileSync34, statSync as statSync14 } from "fs";
20711
+ import { basename as basename16, join as join48 } from "path";
20712
+ var MIN_AGE_DAYS = 7;
20713
+ var DECLARED_FILE = "supply-declared.json";
20714
+ var MAX_CHECKED = 50;
20715
+ var MAX_DECLARED = 200;
20716
+ var MAX_FILE_BYTES = 64 * 1024;
20717
+ var DAY_MS = 86400000;
20718
+ var MANIFESTS = /^(package\.json|package-lock\.json|npm-shrinkwrap\.json|yarn\.lock|pnpm-lock\.yaml|bun\.lockb?|requirements.*\.txt|pyproject\.toml|poetry\.lock|uv\.lock|Pipfile|Pipfile\.lock|go\.mod|go\.sum|Cargo\.toml|Cargo\.lock|Gemfile|Gemfile\.lock|composer\.json|composer\.lock|pom\.xml|build\.gradle(\.kts)?)$/;
20719
+ function supplyEnabled(env) {
20720
+ return env["LOKI_SUPPLY_GUARD"] !== "0";
20721
+ }
20722
+ function failAgeDays(env) {
20723
+ const n2 = Number(env["LOKI_SUPPLY_MIN_AGE_DAYS"]);
20724
+ return Number.isFinite(n2) && n2 > 0 ? n2 : null;
20725
+ }
20726
+ function supplyVerdict(verdict, r) {
20727
+ return r.blocked && verdict === "VERIFIED" ? "FAILED" : verdict;
20728
+ }
20729
+ function isManifestPath(path) {
20730
+ return MANIFESTS.test(basename16(path));
20731
+ }
20732
+ var ECO = { npm: "npm", node: "npm", pypi: "pypi", pip: "pypi", python: "pypi", cargo: "cargo", crates: "cargo", go: "go", golang: "go" };
20733
+ var NAME2 = /^[A-Za-z0-9@][A-Za-z0-9@._/~+-]{0,213}$/;
20734
+ function readDeclared(repoDir) {
20735
+ const p = join48(repoDir, ".loki", DECLARED_FILE);
20736
+ if (!existsSync29(p))
20737
+ return { deps: [], problem: null };
20738
+ try {
20739
+ if (statSync14(p).size > MAX_FILE_BYTES)
20740
+ return { deps: [], problem: "declaration file too large" };
20741
+ const j = JSON.parse(readFileSync34(p, "utf8"));
20742
+ if (!Array.isArray(j))
20743
+ return { deps: [], problem: "declaration is not a JSON array" };
20744
+ const deps = [];
20745
+ for (const o of j.slice(0, MAX_DECLARED)) {
20746
+ if (!o || typeof o !== "object")
20747
+ continue;
20748
+ const r = o;
20749
+ const eco = ECO[String(r["ecosystem"] ?? "").toLowerCase()] ?? String(r["ecosystem"] ?? "").toLowerCase().slice(0, 30);
20750
+ const name = String(r["name"] ?? "");
20751
+ if (!eco || !NAME2.test(name))
20752
+ continue;
20753
+ deps.push({ ecosystem: eco, name, version_spec: String(r["version_spec"] ?? "").slice(0, 100), registry: String(r["registry"] ?? "default").slice(0, 200) });
20754
+ }
20755
+ return { deps, problem: null };
20756
+ } catch {
20757
+ return { deps: [], problem: "declaration unreadable" };
20758
+ }
20759
+ }
20760
+ function readAllowlist(repoDir) {
20761
+ const p = join48(repoDir, ".loki", "supply-allowlist");
20762
+ if (!existsSync29(p))
20763
+ return new Set;
20764
+ try {
20765
+ return new Set(readFileSync34(p, "utf8").split(`
20766
+ `).map((l) => l.replace(/#.*$/, "").trim()).filter(Boolean));
20767
+ } catch {
20768
+ return new Set;
20769
+ }
20770
+ }
20771
+ function classify2(eco, name, exitCode, stdout, stderr) {
20772
+ const err = `${stderr}
20773
+ ${stdout}`;
20774
+ if (eco === "npm") {
20775
+ if (exitCode === 0) {
20776
+ const m = /"?(\d{4}-\d\d-\d\dT[\d:.]+Z)"?/.exec(stdout);
20777
+ return m ? { status: "exists", firstPublish: Date.parse(m[1]) } : { status: "exists" };
20778
+ }
20779
+ return /E404|404 Not Found|is not in this registry/i.test(err) ? { status: "missing" } : { status: "unproven" };
20780
+ }
20781
+ if (eco === "pypi") {
20782
+ if (exitCode === 0)
20783
+ return /Available versions/i.test(stdout) ? { status: "exists" } : { status: "unproven" };
20784
+ return /No matching distribution|from versions: none/i.test(err) ? { status: "missing" } : { status: "unproven" };
20785
+ }
20786
+ if (eco === "cargo") {
20787
+ if (exitCode !== 0)
20788
+ return { status: "unproven" };
20789
+ const norm3 = (x) => x.toLowerCase().replace(/_/g, "-");
20790
+ return stdout.split(`
20791
+ `).some((l) => norm3(l).startsWith(`${norm3(name)} = `)) ? { status: "exists" } : { status: "missing" };
20792
+ }
20793
+ if (eco === "go") {
20794
+ if (exitCode === 0)
20795
+ return { status: "exists" };
20796
+ return /no matching versions|not found|404|410/i.test(err) && !/dial tcp|timeout|no such host|connection/i.test(err) ? { status: "missing" } : { status: "unproven" };
20797
+ }
20798
+ return { status: "unproven" };
20799
+ }
20800
+ var defaultResolver = async (dep, cwd) => {
20801
+ const argv = {
20802
+ npm: ["npm", "view", dep.name, "time.created", "--json"],
20803
+ pypi: ["pip", "index", "versions", "--pre", "--ignore-requires-python", dep.name],
20804
+ cargo: ["cargo", "search", dep.name, "--limit", "5"],
20805
+ go: ["go", "list", "-m", "-json", `${dep.name}@latest`]
20806
+ };
20807
+ const cmd = argv[dep.ecosystem];
20808
+ if (!cmd || dep.name.startsWith("-"))
20809
+ return { status: "unproven" };
20810
+ try {
20811
+ const r = await run(cmd, { cwd, timeoutMs: 1e4 });
20812
+ return classify2(dep.ecosystem, dep.name, r.exitCode, r.stdout, r.stderr);
20813
+ } catch {
20814
+ return { status: "unproven" };
20815
+ }
20816
+ };
20817
+ var PUBLIC_HOSTS = new Set(["registry.npmjs.org", "registry.npmjs.com", "registry.yarnpkg.com", "npmjs.com", "npmjs.org", "pypi.org", "pypi.python.org", "files.pythonhosted.org", "crates.io", "index.crates.io", "static.crates.io", "proxy.golang.org", "golang.org", "pkg.go.dev"]);
20818
+ var hostOf = (u) => u.trim().toLowerCase().replace(/^[a-z][a-z0-9+.-]*:\/\//, "").replace(/^www\./, "").split(/[/?#\s]/)[0].replace(/^[^@]*@/, "").replace(/:\d+$/, "");
20819
+ var privateUrl = (u) => /[a-z0-9]/i.test(u) && !PUBLIC_HOSTS.has(hostOf(u));
20820
+ var readSmall = (p) => {
20821
+ try {
20822
+ return statSync14(p).size <= MAX_FILE_BYTES ? readFileSync34(p, "utf8") : "";
20823
+ } catch {
20824
+ return "";
20825
+ }
20826
+ };
20827
+ function userConfigPrivate(eco, repoDir, env, goEnv = {}, name = "") {
20828
+ const home = env["HOME"] ?? "";
20829
+ const files = (...p) => p.filter((x) => x !== "").map((x) => readSmall(x));
20830
+ if (eco === "npm") {
20831
+ if (privateUrlList([env["npm_config_registry"] ?? "", env["NPM_CONFIG_REGISTRY"] ?? ""]))
20832
+ return true;
20833
+ return files(join48(repoDir, ".npmrc"), home ? join48(home, ".npmrc") : "").some((t) => t.split(`
20834
+ `).some((l) => {
20835
+ const m = /^\s*(?:(@[^:\s]+):)?registry\s*=\s*(\S+)/.exec(l);
20836
+ return !!m && privateUrl(m[2]) && (m[1] === undefined || name.startsWith(`${m[1]}/`));
20837
+ }));
20838
+ }
20839
+ if (eco === "pypi") {
20840
+ if (privateUrlList([env["PIP_INDEX_URL"] ?? "", env["PIP_EXTRA_INDEX_URL"] ?? ""]))
20841
+ return true;
20842
+ const cfg = [env["PIP_CONFIG_FILE"] ?? "", home ? join48(home, ".config", "pip", "pip.conf") : "", home ? join48(home, ".pip", "pip.conf") : "", join48(repoDir, "pip.conf")];
20843
+ return files(...cfg).some((t) => t.split(`
20844
+ `).some((l) => {
20845
+ const m = /^\s*(?:extra-)?index-url\s*[=:]\s*(.+)$/.exec(l);
20846
+ return !!m && m[1].split(/\s+/).some(privateUrl);
20847
+ }));
20848
+ }
20849
+ if (eco === "cargo") {
20850
+ if (Object.keys(env).some((k) => /^CARGO_REGISTRIES_.+_INDEX$/.test(k) || /^CARGO_SOURCE_/.test(k)))
20851
+ return true;
20852
+ return files(join48(repoDir, ".cargo", "config.toml"), join48(repoDir, ".cargo", "config"), home ? join48(home, ".cargo", "config.toml") : "", home ? join48(home, ".cargo", "config") : "").some((t) => /^\s*\[(registries\.|source\.)/m.test(t) || /replace-with\s*=/.test(t));
20853
+ }
20854
+ if (eco === "go") {
20855
+ const gp = goEnv["GOPROXY"] ?? env["GOPROXY"] ?? "";
20856
+ return gp.split(/[,|]/).map((x) => x.trim()).filter((x) => x && x !== "direct" && x !== "off").some(privateUrl);
20857
+ }
20858
+ return false;
20859
+ }
20860
+ var privateUrlList = (v) => v.some((x) => x.split(/\s+/).some((u) => u !== "" && privateUrl(u)));
20861
+ function goPrivate(d, env) {
20862
+ if (d.ecosystem !== "go")
20863
+ return false;
20864
+ const pats = `${env["GOPRIVATE"] ?? ""},${env["GONOPROXY"] ?? ""}`.split(",").map((x) => x.trim()).filter(Boolean);
20865
+ const parts = d.name.split("/");
20866
+ return pats.some((pat) => {
20867
+ const n2 = pat.split("/").length;
20868
+ const re = new RegExp(`^${pat.split("/").map((seg) => seg.replace(/[.+^${}()|\\[\]]/g, "\\$&").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]")).join("/")}$`);
20869
+ return re.test(parts.slice(0, n2).join("/"));
20870
+ });
20871
+ }
20872
+ async function readGoEnv(cwd) {
20873
+ try {
20874
+ const r = await run(["go", "env", "-json", "GOPRIVATE", "GONOPROXY", "GOPROXY"], { cwd, timeoutMs: 1e4 });
20875
+ const j = JSON.parse(r.stdout);
20876
+ return Object.fromEntries(Object.entries(j).map(([k, v]) => [k, String(v)]));
20877
+ } catch {
20878
+ return {};
20879
+ }
20880
+ }
20881
+ var injected = null;
20882
+ async function supplyGuard(repoDir, changedFiles2, declared, env, opts = {}) {
20883
+ const none = { block: null, notProven: [], blocked: false };
20884
+ if (!supplyEnabled(env))
20885
+ return none;
20886
+ const touched = changedFiles2.filter(isManifestPath);
20887
+ if (touched.length === 0)
20888
+ return none;
20889
+ const resolver = opts.resolver ?? injected ?? defaultResolver, now2 = opts.now ?? Date.now(), failAge = failAgeDays(env);
20890
+ const goEnv = opts.goEnv ?? (declared.deps.some((x) => x.ecosystem === "go") && !opts.resolver && !injected ? await readGoEnv(repoDir) : {});
20891
+ const notProven = [];
20892
+ let blocked = false;
20893
+ if (declared.problem)
20894
+ notProven.push(`supply guard NOT PROVEN: ${declared.problem}`);
20895
+ if (declared.deps.length === 0) {
20896
+ if (!declared.problem)
20897
+ notProven.push(`supply guard WARNING: dependencies changed (${[...new Set(touched)].slice(0, 5).join(", ")}) but none declared; not checked`);
20898
+ return { block: { guard: "v2", warn_age_days: MIN_AGE_DAYS, fail_age_days: failAge, declared: 0, entries: [] }, notProven, blocked: false };
20899
+ }
20900
+ const allow = readAllowlist(repoDir), cache2 = new Map;
20901
+ let checked = 0;
20902
+ const entries = [];
20903
+ for (const d of declared.deps) {
20904
+ const base = { ecosystem: d.ecosystem, name: d.name, version_spec: d.version_spec, registry: d.registry };
20905
+ if (!["npm", "pypi", "cargo", "go"].includes(d.ecosystem)) {
20906
+ entries.push({ ...base, status: "unsupported" });
20907
+ continue;
20908
+ }
20909
+ if (allow.has(d.name)) {
20910
+ entries.push({ ...base, status: "allowlisted" });
20911
+ continue;
20912
+ }
20913
+ if (++checked > MAX_CHECKED) {
20914
+ entries.push({ ...base, status: "capped" });
20915
+ continue;
20916
+ }
20917
+ const key = `${d.ecosystem}:${d.name}`;
20918
+ let h = cache2.get(key);
20919
+ if (!h) {
20920
+ h = resolver(d, repoDir, env).catch(() => ({ status: "unproven" }));
20921
+ cache2.set(key, h);
20922
+ }
20923
+ let res = await h;
20924
+ if (res.status === "missing" && (userConfigPrivate(d.ecosystem, repoDir, env, goEnv, d.name) || goPrivate(d, { ...env, ...goEnv })))
20925
+ res = { status: "unproven" };
20926
+ if (res.status === "missing")
20927
+ entries.push({ ...base, status: "nonexistent" });
20928
+ else if (res.status === "unproven")
20929
+ entries.push({ ...base, status: "unreachable" });
20930
+ else if (res.firstPublish === undefined || !Number.isFinite(res.firstPublish))
20931
+ entries.push({ ...base, status: "ok" });
20932
+ else {
20933
+ const age = Math.floor((now2 - res.firstPublish) / DAY_MS);
20934
+ entries.push({ ...base, status: age < MIN_AGE_DAYS || failAge !== null && age < failAge ? "too_new" : "ok", age_days: age });
20935
+ }
20936
+ }
20937
+ for (const e of entries) {
20938
+ const id = `${e.ecosystem}:${e.name}`;
20939
+ if (e.status === "nonexistent") {
20940
+ blocked = true;
20941
+ notProven.push(`supply guard FAILED: declared dependency ${id} does not resolve in the registry (possible hallucinated package)`);
20942
+ } else if (e.status === "too_new") {
20943
+ if (failAge !== null && (e.age_days ?? 0) < failAge) {
20944
+ blocked = true;
20945
+ notProven.push(`supply guard FAILED: ${id} first published ${e.age_days} days ago (LOKI_SUPPLY_MIN_AGE_DAYS=${failAge}); allowlist in .loki/supply-allowlist to accept`);
20946
+ } else
20947
+ notProven.push(`supply guard WARNING: ${id} first published ${e.age_days} days ago (under ${MIN_AGE_DAYS}); verdict unchanged`);
20948
+ } else if (e.status === "unreachable")
20949
+ notProven.push(`supply guard NOT PROVEN: resolver could not answer for ${id}`);
20950
+ else if (e.status === "capped")
20951
+ notProven.push(`supply guard: not checked: cap ${MAX_CHECKED} exceeded: ${id}`);
20952
+ else if (e.status === "unsupported")
20953
+ notProven.push(`supply guard: not checked (ecosystem unsupported in v1): ${id}`);
20954
+ else if (e.status === "allowlisted")
20955
+ notProven.push(`supply guard: allowlisted, not checked: ${id}`);
20956
+ }
20957
+ return { block: { guard: "v2", warn_age_days: MIN_AGE_DAYS, fail_age_days: failAge, declared: declared.deps.length, entries }, notProven, blocked };
20958
+ }
20959
+
19244
20960
  // ../../loki-ts/src/engine10/stages/seal.ts
19245
20961
  var DEEP_NOT_PROVEN = ["full suite", "app boot", "council", "security scan"];
19246
20962
  var SIGNING_UNAVAILABLE = "receipt signing unavailable (no usable signing key: invalid key or unwritable ~/.loki/keys)";
19247
20963
  var EXCLUDE_LOKI = ":(exclude).loki";
19248
- var sha2562 = (s) => createHash9("sha256").update(s).digest("hex");
20964
+ var sha2562 = (s) => createHash11("sha256").update(s).digest("hex");
19249
20965
  var str3 = (v) => typeof v === "string" && v !== "" ? v : null;
19250
20966
  var strs2 = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string" && x !== "") : [];
19251
20967
  function sanitizeReason(s) {
@@ -19270,37 +20986,37 @@ function receiptSha256(r) {
19270
20986
  return sha2562(canonicalJson(body));
19271
20987
  }
19272
20988
  var b64u = (b) => Buffer.from(b).toString("base64url");
19273
- var kidOf2 = (pub) => b64u(createHash9("sha256").update(`{"crv":"Ed25519","kty":"OKP","x":"${pub.export({ format: "jwk" }).x}"}`).digest());
20989
+ var kidOf2 = (pub) => b64u(createHash11("sha256").update(`{"crv":"Ed25519","kty":"OKP","x":"${pub.export({ format: "jwk" }).x}"}`).digest());
19274
20990
  function loadSigningKey(generate = true) {
19275
20991
  try {
19276
20992
  const inline = process.env["LOKI_RECEIPT_SIGNING_KEY"]?.trim();
19277
20993
  let pem = inline ?? "";
19278
20994
  if (!inline) {
19279
20995
  const given = process.env["LOKI_RECEIPT_SIGNING_KEY_FILE"]?.trim();
19280
- const file = given || join36(process.env["HOME"] || homedir7(), ".loki", "keys", RECEIPT_SIGNER_BASENAME);
20996
+ const file = given || join49(process.env["HOME"] || homedir8(), ".loki", "keys", RECEIPT_SIGNER_BASENAME);
19281
20997
  try {
19282
- pem = readFileSync26(file);
20998
+ pem = readFileSync35(file);
19283
20999
  if (!given) {
19284
- for (const [f, m] of [[file, 384], [dirname13(file), 448]])
19285
- if (statSync13(f).mode & 63)
21000
+ for (const [f, m] of [[file, 384], [dirname21(file), 448]])
21001
+ if (statSync15(f).mode & 63)
19286
21002
  chmodSync5(f, m);
19287
21003
  }
19288
21004
  } catch (e) {
19289
21005
  if (e.code !== "ENOENT" || !generate)
19290
21006
  return null;
19291
- mkdirSync10(dirname13(dirname13(file)), { recursive: true, mode: 448 });
19292
- mkdirSync10(dirname13(file), { recursive: true, mode: 448 });
21007
+ mkdirSync17(dirname21(dirname21(file)), { recursive: true, mode: 448 });
21008
+ mkdirSync17(dirname21(file), { recursive: true, mode: 448 });
19293
21009
  const tmp = `${file}.${randomBytes3(6).toString("hex")}.tmp`;
19294
- writeFileSync13(tmp, generateKeyPairSync("ed25519").privateKey.export({ type: "pkcs8", format: "pem" }), { flag: "wx", mode: 384 });
21010
+ writeFileSync18(tmp, generateKeyPairSync("ed25519").privateKey.export({ type: "pkcs8", format: "pem" }), { flag: "wx", mode: 384 });
19295
21011
  try {
19296
21012
  linkSync(tmp, file);
19297
21013
  } catch (l) {
19298
21014
  if (l.code !== "EEXIST")
19299
21015
  throw l;
19300
21016
  } finally {
19301
- unlinkSync4(tmp);
21017
+ unlinkSync5(tmp);
19302
21018
  }
19303
- pem = readFileSync26(file);
21019
+ pem = readFileSync35(file);
19304
21020
  }
19305
21021
  }
19306
21022
  const k = createPrivateKey(pem);
@@ -19317,37 +21033,37 @@ function signReceipt(runId, hash) {
19317
21033
  const input = `${b64u(canonicalJson({ alg: "EdDSA", typ: "JWT", kid }))}.${b64u(canonicalJson({ job_id: runId, run_id: runId, receipt_sha256: hash, iat: Math.floor(Date.now() / 1000) }))}`;
19318
21034
  return { jwt: `${input}.${b64u(sign(null, Buffer.from(input), key))}`, kid };
19319
21035
  }
19320
- async function git(ctx, args) {
19321
- const r = await run(["git", ...args], { cwd: ctx.repoDir, timeoutMs: 20000 });
21036
+ async function git2(ctx, args, keep = {}) {
21037
+ const r = await safeGitRun(ctx.repoDir, args, { timeoutMs: 20000, ...keep });
19322
21038
  return { out: r.stdout, code: r.exitCode };
19323
21039
  }
19324
21040
  var commitStage = {
19325
21041
  name: "commit",
19326
21042
  ...STAGE_BUDGETS.commit,
19327
21043
  async run(ctx) {
19328
- if (!ctx.baseSha || (await git(ctx, ["rev-parse", "--verify", "-q", `${ctx.baseSha}^{commit}`])).code !== 0)
21044
+ if (!ctx.baseSha || (await git2(ctx, ["rev-parse", "--verify", "-q", `${ctx.baseSha}^{commit}`])).code !== 0)
19329
21045
  return { status: "failed", data: {}, reason: "base commit not resolvable" };
19330
- if ((await git(ctx, ["add", "-A", "--", "."])).code !== 0)
21046
+ if ((await git2(ctx, ["add", "-A", "--", "."], { repoDrivers: true })).code !== 0)
19331
21047
  return { status: "failed", data: {}, reason: "git add failed" };
19332
- const sd = await git(ctx, ["diff", "--cached", "--name-status", "--no-renames", "-z", ctx.baseSha]);
21048
+ const sd = await git2(ctx, ["diff", "--cached", "--name-status", "--no-renames", "-z", ctx.baseSha]);
19333
21049
  if (sd.code !== 0)
19334
21050
  return { status: "failed", data: {}, reason: "git diff against base failed" };
19335
21051
  const staged = parseStaged(sd.out);
19336
21052
  const drop = dropSet(ctx.repoDir, staged, ctx.outputs().intake?.preexisting_dirty);
19337
- const sat = await discardIfSatisfied((a) => git(ctx, a), ctx.baseSha, ctx.outputs(), staged, new Set(drop.filter(({ st }) => st === "L").map(({ f }) => f)), ctx.repoDir);
21053
+ const sat = await discardIfSatisfied((a) => git2(ctx, a), ctx.baseSha, ctx.outputs(), staged, new Set(drop.filter(({ st }) => st === "L").map(({ f }) => f)), ctx.repoDir);
19338
21054
  if (sat)
19339
21055
  return sat;
19340
- if (drop.length > 0 && (await git(ctx, ["--literal-pathspecs", "reset", "-q", ctx.baseSha, "--", ...drop.map(({ f }) => f)])).code !== 0)
21056
+ if (drop.length > 0 && (await git2(ctx, ["--literal-pathspecs", "reset", "-q", ctx.baseSha, "--", ...drop.map(({ f }) => f)])).code !== 0)
19341
21057
  return { status: "failed", data: {}, reason: "git reset failed" };
19342
21058
  const dropped2 = new Set(drop.map(({ f }) => f)), notes = flagOutsideScope(ctx.outputs(), staged.filter(({ f }) => !dropped2.has(f)));
19343
- if ((await git(ctx, ["diff", "--cached", "--quiet"])).code === 0)
21059
+ if ((await git2(ctx, ["diff", "--cached", "--quiet"])).code === 0)
19344
21060
  return { status: "completed", data: { committed: false, scope_notes: notes } };
19345
21061
  const title = (str3(ctx.outputs().intake?.title) ?? `run ${ctx.runId}`).split(`
19346
21062
  `)[0].slice(0, 72);
19347
- const c = await git(ctx, ["commit", "-q", "-m", `loki: ${title}`, "-m", `Loki-Run: ${ctx.runId}`]);
21063
+ const c = await git2(ctx, ["commit", "-q", "-m", `loki: ${title}`, "-m", `Loki-Run: ${ctx.runId}`], { repoDrivers: true, userHooks: true });
19348
21064
  if (c.code !== 0)
19349
21065
  return { status: "failed", data: {}, reason: "git commit failed" };
19350
- return { status: "completed", data: { committed: true, head_sha: (await git(ctx, ["rev-parse", "HEAD"])).out.trim(), scope_notes: notes } };
21066
+ return { status: "completed", data: { committed: true, head_sha: (await git2(ctx, ["rev-parse", "HEAD"])).out.trim(), scope_notes: notes } };
19351
21067
  }
19352
21068
  };
19353
21069
  function verdictOf2(o, checks, emptyDiff, verifyNotProven, wallGreenOnBase, proof, targetProof = false, uncovered = []) {
@@ -19396,6 +21112,7 @@ function renderReceiptMd(r) {
19396
21112
  `- receipt_sha256: ${r.receipt_sha256}`,
19397
21113
  `- Signature: ${sig}`,
19398
21114
  `- Provider: ${r.provider} (${r.model}) Cost: ${usd} Wall: ${r.time.wall_s}s`,
21115
+ ...r.mutation_proof ? [`- ${r.mutation_proof}`] : [],
19399
21116
  ...r.route ? routeReceiptLines(r.route) : [],
19400
21117
  "",
19401
21118
  "### Checks",
@@ -19413,9 +21130,9 @@ var sealStage = {
19413
21130
  ...STAGE_BUDGETS.seal,
19414
21131
  async run(ctx, signal) {
19415
21132
  const o = ctx.outputs();
19416
- const head = (await git(ctx, ["rev-parse", "HEAD"])).out.trim();
19417
- const tree = (await git(ctx, ["rev-parse", "HEAD^{tree}"])).out.trim();
19418
- const diff = await run(["git", "diff-tree", "-r", "-z", "--raw", "--no-renames", "--no-abbrev", "-O/dev/null", ctx.baseSha, head, "--", ".", EXCLUDE_LOKI], { cwd: ctx.repoDir, timeoutMs: 20000 });
21133
+ const head = (await git2(ctx, ["rev-parse", "HEAD"])).out.trim();
21134
+ const tree = (await git2(ctx, ["rev-parse", "HEAD^{tree}"])).out.trim();
21135
+ const diff = await safeGitRun(ctx.repoDir, ["diff-tree", "-r", "-z", "--raw", "--no-renames", "--no-abbrev", "-O/dev/null", ctx.baseSha, head, "--", ".", EXCLUDE_LOKI], { timeoutMs: 20000 });
19419
21136
  const diffOk = diff.exitCode === 0 && /^[0-9a-f]{40,64}$/.test(head);
19420
21137
  const checks = checksOf(o.verify?.checks);
19421
21138
  const verifyNotProven = strs2(o.verify?.not_proven);
@@ -19432,8 +21149,12 @@ var sealStage = {
19432
21149
  const proof = wallGreenOnBase || hasExecutedProof(Array.isArray(o.verify?.checks) ? o.verify.checks : []);
19433
21150
  const uncoveredAfterLimit = o.implement?.exit === "killed" ? strs2(o.verify?.uncovered_changed) : [];
19434
21151
  const verdict0 = capGroupVerdict(verdictOf2(o, checks.filter((c) => !(c.result === "fail" && preRedChecks.includes(c.name))), !diffOk || diff.stdout === "", verifyNotProven.length > 0 || weakTests.length > 0, wallGreenOnBase, proof, targetProofOf(o.verify), uncoveredAfterLimit), grp);
19435
- const xr = await crossReview(ctx, verdict0, head), verdict = minVerdict(verdict0, xr);
19436
- const notProven = new Set([...DEEP_NOT_PROVEN, ...grp.notProven, ...xr?.notes ?? []]);
21152
+ const supply = await supplyGuard(ctx.repoDir, rawDiff.filter((_, i) => i % 2 === 1), readDeclared(ctx.repoDir), process.env);
21153
+ const verdict1 = supplyVerdict(verdict0, supply);
21154
+ const xr = await crossReview(ctx, verdict1, head), verdict2 = minVerdict(verdict1, xr);
21155
+ const mp = verdict2 === "VERIFIED" && mutationEnabled() ? mutationProof({ repoDir: ctx.repoDir, baseSha: ctx.baseSha, runDir: ctx.runDir, wallFiles: Array.isArray(o.wall?.files) ? o.wall.files : [], checks: Array.isArray(o.verify?.checks) ? o.verify.checks : [], runner: (ms) => new RealBaseTestRunner(undefined, ms) }) : null;
21156
+ const verdict = mp?.outcome === "no" && mutationStrict() && o.plan?.behavior_change === true ? "PARTIAL" : verdict2;
21157
+ const notProven = new Set([...DEEP_NOT_PROVEN, ...supply.notProven, ...grp.notProven, ...xr?.notes ?? []]);
19437
21158
  if (!proof && (verdict === "PARTIAL" || verdict === "VERIFIED" || verdict === "ALREADY_SATISFIED")) {
19438
21159
  const vc = Array.isArray(o.verify?.checks) ? o.verify.checks : [];
19439
21160
  notProven.add(vc.length > 0 && vc.every((c) => c.n !== 0 && String(c.reason ?? "").startsWith(UNMEASURED_REASON)) ? UNMEASURED_REASON : vc.length > 0 && vc.every((c) => c.n !== 0 && String(c.reason ?? "").startsWith(UNCONFIRMED_REASON)) ? UNCONFIRMED_REASON : NO_TESTS_REASON);
@@ -19444,8 +21165,8 @@ var sealStage = {
19444
21165
  notProven.add(`wall test discarded: ${String(d.file)} (${String(d.reason)})`);
19445
21166
  if (wallNotRun > 0) {
19446
21167
  try {
19447
- const kept = new Set((Array.isArray(o.wall?.files) ? o.wall.files : []).map((f) => basename11(String(f.path))));
19448
- for (const n2 of readdirSync12(join36(ctx.runDir, "wall")).sort())
21168
+ const kept = new Set((Array.isArray(o.wall?.files) ? o.wall.files : []).map((f) => basename17(String(f.path))));
21169
+ for (const n2 of readdirSync14(join49(ctx.runDir, "wall")).sort())
19449
21170
  if (!kept.has(n2))
19450
21171
  notProven.add(`wall test discarded: ${n2} (not_run)`);
19451
21172
  } catch {}
@@ -19494,6 +21215,8 @@ var sealStage = {
19494
21215
  if (source !== "text" && source !== "issue")
19495
21216
  notProven.add("task source not recorded by intake");
19496
21217
  const repo = str3(o.intake?.repo);
21218
+ if (mp?.outcome === "no")
21219
+ notProven.add(`Wall tests passed without the fix (mutation proof)${verdict !== verdict2 ? "; verdict downgraded to PARTIAL (LOKI_MUTATION_STRICT=1, declared behavior change)" : ""}`);
19497
21220
  if (repo === null)
19498
21221
  notProven.add("repo not recorded by intake");
19499
21222
  if (typeof o.intake?.resumed !== "boolean")
@@ -19508,12 +21231,12 @@ var sealStage = {
19508
21231
  const cost = ctx.cost.read(ctx.repoDir, iterIds);
19509
21232
  if (cost.unmetered)
19510
21233
  notProven.add("cost unmetered (CLI invoker; recorded as 0)");
19511
- const eventsPath = join36(ctx.runDir, "events.jsonl");
21234
+ const eventsPath = join49(ctx.runDir, "events.jsonl");
19512
21235
  const wallFiles = Array.isArray(o.wall?.files) ? o.wall.files : [];
19513
21236
  const wallPassed = typeof o.verify?.wall_passed === "boolean" ? o.verify.wall_passed : null;
19514
21237
  if (wallFiles.length > 0 && wallPassed === null)
19515
21238
  notProven.add("wall result not recorded by verify");
19516
- const routeBlock = buildRouteBlock(process.env, ctx.provider, o.implement?.route, cost.router ?? (routerEnabled(process.env) ? sumResultCosts(join36(ctx.repoDir, ".loki"), iterIds).router : undefined));
21239
+ const routeBlock = buildRouteBlock(process.env, ctx.provider, o.implement?.route ?? o.plan?.route_record ?? (routerEnabled(process.env) ? loadRouteRecord(ctx.runDir) : undefined), cost.router ?? (routerEnabled(process.env) ? sumResultCosts(join49(ctx.repoDir, ".loki"), iterIds).router : undefined), ctx.model);
19517
21240
  if (routeBlock)
19518
21241
  for (const l of routeNotProven(routeBlock))
19519
21242
  notProven.add(l);
@@ -19532,6 +21255,7 @@ var sealStage = {
19532
21255
  verdict,
19533
21256
  ...typeof o.implement?.limit_s === "number" ? { implement_limit: { limit_s: o.implement.limit_s, elapsed_s: typeof o.implement.elapsed_s === "number" ? o.implement.elapsed_s : 0 } } : {},
19534
21257
  ...grp.section ? { group: grp.section } : {},
21258
+ ...ctx.failovers && ctx.failovers().length > 0 ? { failover: ctx.failovers() } : {},
19535
21259
  ...str3(o.implement?.spec_conflict_reason) !== null ? { spec_conflict_reason: sanitizeReason(str3(o.implement?.spec_conflict_reason)) } : {},
19536
21260
  evidence: strs2(o.intake?.evidence),
19537
21261
  ...o.intake?.preexisting_dirty ? { pre_existing_dirty: Object.keys(o.intake.preexisting_dirty) } : {},
@@ -19549,10 +21273,13 @@ var sealStage = {
19549
21273
  provider: ctx.provider,
19550
21274
  model: ctx.model,
19551
21275
  resumed: o.intake?.resumed === true,
19552
- events_sha256: sha2562(existsSync21(eventsPath) ? readFileSync26(eventsPath) : ""),
21276
+ events_sha256: sha2562(existsSync30(eventsPath) ? readFileSync35(eventsPath) : ""),
19553
21277
  ...await sealEvidence(ctx.repoDir, ctx.runDir, o, notProven, signal, ctx.emit),
19554
21278
  log_seal: true,
19555
- ...routeBlock ? { route: routeBlock } : {}
21279
+ ...receiptBlock(process.env, cost.usd, cost.unmetered === true, Object.values(stages).reduce((a, b) => a + (b ?? 0), 0)),
21280
+ ...mp ? { mutation_proof: mp.line, mutation_outcome: mp.outcome } : {},
21281
+ ...routeBlock ? { route: routeBlock } : {},
21282
+ ...supply.block ? { supply: supply.block } : {}
19556
21283
  };
19557
21284
  for (const l of sealContract(ctx.repoDir, body, rawDiff, checks, process.env, o.intake?.contract_snapshot))
19558
21285
  notProven.add(l);
@@ -19564,13 +21291,17 @@ var sealStage = {
19564
21291
  hash = receiptSha256(body);
19565
21292
  }
19566
21293
  const receipt = { ...body, receipt_sha256: hash, verification: { jwt: sig.jwt, kid: sig.kid } };
19567
- mkdirSync10(ctx.runDir, { recursive: true });
19568
- const path = join36(ctx.runDir, "receipt.json");
19569
- writeFileSync13(path, JSON.stringify(receipt, null, 2) + `
21294
+ mkdirSync17(ctx.runDir, { recursive: true });
21295
+ const path = join49(ctx.runDir, "receipt.json");
21296
+ writeFileSync18(path, JSON.stringify(receipt, null, 2) + `
19570
21297
  `);
19571
- writeFileSync13(join36(ctx.runDir, "receipt.md"), renderReceiptMd(receipt));
21298
+ writeFileSync18(join49(ctx.runDir, "receipt.md"), renderReceiptMd(receipt));
21299
+ recordRun(process.env, ctx.repoDir, ctx.model, verdict, cost.usd, cost.unmetered === true, receipt.time.wall_s);
19572
21300
  const signed = sig.jwt !== null;
19573
- const data = { receipt_path: path, receipt_sha256: hash, signed, kid: sig.kid, verdict, not_proven: receipt.not_proven, ...routeBlock ? { route_line: routePrLine(routeBlock) } : {} };
21301
+ const data = { receipt_path: path, receipt_sha256: hash, signed, kid: sig.kid, verdict, not_proven: receipt.not_proven, ...mp ? { mutation_line: mp.line } : {}, ...routeBlock ? { route_line: routePrLine(routeBlock) } : {} };
21302
+ try {
21303
+ recordRunVerdict(ctx.repoDir, ctx.runId, verdict);
21304
+ } catch {}
19574
21305
  ctx.emit("receipt.sealed", "seal", { path, receipt_sha256: hash, signed, kid: sig.kid, verdict, not_proven: receipt.not_proven, ...routeBlock ? { route_line: routePrLine(routeBlock) } : {} });
19575
21306
  return { status: "completed", data: { ...data, summary: `${verdict} receipt ${hash.slice(0, 12)} ${signed ? `SIGNED kid ${sig.kid}` : "UNSIGNED"}` } };
19576
21307
  }
@@ -19578,7 +21309,7 @@ var sealStage = {
19578
21309
 
19579
21310
  // ../../loki-ts/src/features/receipt_dsse.ts
19580
21311
  import { createPublicKey as createPublicKey3, sign as sign2, verify as verify2 } from "crypto";
19581
- import { readFileSync as readFileSync27 } from "fs";
21312
+ import { readFileSync as readFileSync36 } from "fs";
19582
21313
  var DSSE_PAYLOAD_TYPE = "application/vnd.in-toto+json";
19583
21314
  var STATEMENT_TYPE = "https://in-toto.io/Statement/v1";
19584
21315
  var PREDICATE_TYPE = "https://autonomi.dev/loki/receipt/v10";
@@ -19659,7 +21390,7 @@ function verifyDsseReceipt(env, d) {
19659
21390
  }
19660
21391
  function runIdGuard(receiptPath, runId) {
19661
21392
  try {
19662
- return envelopeRunIdProblem(JSON.parse(readFileSync27(receiptPath, "utf8")), runId);
21393
+ return envelopeRunIdProblem(JSON.parse(readFileSync36(receiptPath, "utf8")), runId);
19663
21394
  } catch {
19664
21395
  return null;
19665
21396
  }
@@ -19673,7 +21404,7 @@ function pubFor(kid, given) {
19673
21404
  const active = loadSigningKey(false);
19674
21405
  const pubs = (process.env["LOKI_RECEIPT_RETIRED_PUBKEYS"] ?? "").split(":").map((f) => f.trim()).filter(Boolean).flatMap((f) => {
19675
21406
  try {
19676
- return [createPublicKey4(readFileSync28(f))];
21407
+ return [createPublicKey4(readFileSync37(f))];
19677
21408
  } catch {
19678
21409
  return [];
19679
21410
  }
@@ -19703,18 +21434,18 @@ function checkAttestation(jwt, expectedHash, given) {
19703
21434
  }
19704
21435
  function checkEventLog(receiptPath, receipt) {
19705
21436
  const bound = receipt["events_sha256"];
19706
- if (typeof bound !== "string" || bound === createHash10("sha256").digest("hex"))
21437
+ if (typeof bound !== "string" || bound === createHash12("sha256").digest("hex"))
19707
21438
  return null;
19708
- const path = join37(dirname14(receiptPath), "events.jsonl");
19709
- if (!existsSync22(path))
21439
+ const path = join50(dirname22(receiptPath), "events.jsonl");
21440
+ if (!existsSync31(path))
19710
21441
  return "events.jsonl is missing";
19711
- const raw2 = readFileSync28(path, "utf8"), events2 = readEvents(path), lines = raw2.split(`
21442
+ const raw2 = readFileSync37(path, "utf8"), events2 = readEvents(path), lines = raw2.split(`
19712
21443
  `).filter((l) => l.trim() !== "");
19713
21444
  if (events2.length !== lines.length || events2.some((e, i) => e.seq !== i))
19714
21445
  return "events.jsonl has a forged, edited or missing line";
19715
21446
  if (events2.some((e) => e.type === "tamper.detected"))
19716
21447
  return "the supervisor detected events.jsonl being modified during the run";
19717
- const h = createHash10("sha256");
21448
+ const h = createHash12("sha256");
19718
21449
  for (const l of lines) {
19719
21450
  if (h.copy().digest("hex") === bound)
19720
21451
  return null;
@@ -19724,7 +21455,7 @@ function checkEventLog(receiptPath, receipt) {
19724
21455
  return h.digest("hex") === bound ? null : "events.jsonl does not match the hash recorded at seal";
19725
21456
  }
19726
21457
  function checkLogSeal(receiptPath, hash, kid, given) {
19727
- const path = join37(dirname14(receiptPath), "events.jsonl"), events2 = readEvents(path), done = events2.findIndex((e) => e.type === "run.completed");
21458
+ const path = join50(dirname22(receiptPath), "events.jsonl"), events2 = readEvents(path), done = events2.findIndex((e) => e.type === "run.completed");
19728
21459
  if (!events2.some((e) => e.type === "receipt.sealed" && e.data["receipt_sha256"] === hash))
19729
21460
  return { verdict: "TAMPERED", reason: "events.jsonl has no receipt.sealed event for this receipt" };
19730
21461
  if (done < 0)
@@ -19732,8 +21463,8 @@ function checkLogSeal(receiptPath, hash, kid, given) {
19732
21463
  const seal = events2[done + 1], d = seal?.type === "log.sealed" ? seal.data : null;
19733
21464
  if (!d)
19734
21465
  return { verdict: "TAMPERED", reason: "events.jsonl has no signed log.sealed line after run.completed" };
19735
- const lines = readFileSync28(path, "utf8").split(`
19736
- `).filter((l) => l.trim() !== ""), sha3 = createHash10("sha256").update(lines.slice(0, done + 1).join(`
21466
+ const lines = readFileSync37(path, "utf8").split(`
21467
+ `).filter((l) => l.trim() !== ""), sha3 = createHash12("sha256").update(lines.slice(0, done + 1).join(`
19737
21468
  `) + `
19738
21469
  `).digest("hex");
19739
21470
  const pub = d["kid"] === kid ? pubFor(kid, given) : undefined;
@@ -19742,11 +21473,11 @@ function checkLogSeal(receiptPath, hash, kid, given) {
19742
21473
  return null;
19743
21474
  }
19744
21475
  async function verifyReceipt(receiptPath, deps = {}) {
19745
- if (!existsSync22(receiptPath))
21476
+ if (!existsSync31(receiptPath))
19746
21477
  return { verdict: "UNCHECKED", reasons: [`receipt not found: ${receiptPath}`] };
19747
21478
  let receipt;
19748
21479
  try {
19749
- receipt = JSON.parse((deps.read ?? ((p) => readFileSync28(p, "utf8")))(receiptPath));
21480
+ receipt = JSON.parse((deps.read ?? ((p) => readFileSync37(p, "utf8")))(receiptPath));
19750
21481
  } catch {
19751
21482
  return { verdict: "UNCHECKED", reasons: ["receipt.json is not valid JSON"] };
19752
21483
  }
@@ -19814,11 +21545,11 @@ function mount21(ctx) {
19814
21545
  return done(404, "receipt not available", "not_found");
19815
21546
  let runDir, file;
19816
21547
  try {
19817
- const root = realpathSync17(join38(repo.p, ".loki", "runs"));
19818
- runDir = realpathSync17(join38(root, run2));
19819
- if (runDir !== join38(root, run2))
21548
+ const root = realpathSync20(join51(repo.p, ".loki", "runs"));
21549
+ runDir = realpathSync20(join51(root, run2));
21550
+ if (runDir !== join51(root, run2))
19820
21551
  return done(404, "receipt not found", "not_found");
19821
- file = realpathSync17(join38(runDir, "receipt.json"));
21552
+ file = realpathSync20(join51(runDir, "receipt.json"));
19822
21553
  } catch {
19823
21554
  return done(404, "receipt not found", "not_found");
19824
21555
  }
@@ -19837,7 +21568,7 @@ function mount21(ctx) {
19837
21568
  sha3 = r.receiptSha256 ?? null;
19838
21569
  }
19839
21570
  try {
19840
- outcome = outcomeOf(JSON.parse(readFileSync29(file, "utf8")));
21571
+ outcome = outcomeOf(JSON.parse(readFileSync38(file, "utf8")));
19841
21572
  } catch {
19842
21573
  outcome = "UNREADABLE";
19843
21574
  }
@@ -19899,8 +21630,8 @@ function ttlCache(ttlMs = PROBE_CACHE_MS, now2 = Date.now) {
19899
21630
  }
19900
21631
 
19901
21632
  // src/server/legacy/shim.ts
19902
- import { existsSync as existsSync23, readFileSync as readFileSync30 } from "fs";
19903
- import { join as join39 } from "path";
21633
+ import { existsSync as existsSync32, readFileSync as readFileSync39 } from "fs";
21634
+ import { join as join52 } from "path";
19904
21635
 
19905
21636
  // src/server/legacy/routes.ts
19906
21637
  var LEGACY_ROUTES = [
@@ -20272,10 +22003,10 @@ var logged = new Set;
20272
22003
  var toHono = (p) => p.replace(/\{([A-Za-z_]+):path\}/g, ":$1{.+}").replace(/\{([A-Za-z_]+)\}/g, ":$1");
20273
22004
  var NOT_SUPPORTED = "not yet supported by the Control Plane";
20274
22005
  var repoVersion = () => {
20275
- for (const f of [join39(import.meta.dir, "../../../../../VERSION")]) {
22006
+ for (const f of [join52(import.meta.dir, "../../../../../VERSION")]) {
20276
22007
  try {
20277
- if (existsSync23(f))
20278
- return readFileSync30(f, "utf8").trim();
22008
+ if (existsSync32(f))
22009
+ return readFileSync39(f, "utf8").trim();
20279
22010
  } catch {}
20280
22011
  }
20281
22012
  return "unknown";
@@ -20457,7 +22188,7 @@ function legacyShim(opts) {
20457
22188
 
20458
22189
  // src/server/app.ts
20459
22190
  var MAX_BODY2 = 1e6;
20460
- var defaultUiDir = () => [join40(import.meta.dir, "../../ui/dist"), join40(import.meta.dir, "../ui/dist")].find((d) => existsSync24(join40(d, "index.html")));
22191
+ var defaultUiDir = () => [join53(import.meta.dir, "../../ui/dist"), join53(import.meta.dir, "../ui/dist")].find((d) => existsSync33(join53(d, "index.html")));
20461
22192
  function createApp(opts) {
20462
22193
  const uiDir = opts.uiDir ?? defaultUiDir();
20463
22194
  const { db, sqlite } = openDb(opts.dbPath);
@@ -20486,10 +22217,10 @@ function createApp(opts) {
20486
22217
  await next();
20487
22218
  });
20488
22219
  const readInstalled = () => {
20489
- for (const f of [process.env.LOKI_VERSION_FILE, join40(import.meta.dir, "../../../../VERSION")]) {
22220
+ for (const f of [process.env.LOKI_VERSION_FILE, join53(import.meta.dir, "../../../../VERSION")]) {
20490
22221
  try {
20491
22222
  if (f)
20492
- return readFileSync31(f, "utf8").trim() || "unknown";
22223
+ return readFileSync40(f, "utf8").trim() || "unknown";
20493
22224
  } catch {}
20494
22225
  }
20495
22226
  return "unknown";
@@ -20598,13 +22329,13 @@ function createApp(opts) {
20598
22329
  }
20599
22330
  if (!uiDir || p.startsWith("/v1/"))
20600
22331
  return c.json({ error: "not found" }, 404);
20601
- const root = resolve8(uiDir);
20602
- const f = resolve8(root, `.${p}`);
20603
- if (f.startsWith(root + sep14) && existsSync24(f) && statSync15(f).isFile())
22332
+ const root = resolve12(uiDir);
22333
+ const f = resolve12(root, `.${p}`);
22334
+ if (f.startsWith(root + sep14) && existsSync33(f) && statSync17(f).isFile())
20604
22335
  return new Response(Bun.file(f));
20605
22336
  if (/\.[a-z0-9]+$/i.test(p))
20606
22337
  return c.json({ error: "not found" }, 404);
20607
- return new Response(Bun.file(join40(root, "index.html")));
22338
+ return new Response(Bun.file(join53(root, "index.html")));
20608
22339
  });
20609
22340
  return { app, db, close: () => {
20610
22341
  clearInterval(reconciler);