@coldtea/abide 0.0.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 (370) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -0
  3. package/dist/abide-hook.d.ts +2 -0
  4. package/dist/abide-hook.d.ts.map +1 -0
  5. package/dist/abide-hook.js +23 -0
  6. package/dist/abide-hook.js.map +1 -0
  7. package/dist/bin.d.ts +3 -0
  8. package/dist/bin.d.ts.map +1 -0
  9. package/dist/bin.js +64 -0
  10. package/dist/bin.js.map +1 -0
  11. package/dist/commands/audit.d.ts +3 -0
  12. package/dist/commands/audit.d.ts.map +1 -0
  13. package/dist/commands/audit.js +79 -0
  14. package/dist/commands/audit.js.map +1 -0
  15. package/dist/commands/bench.d.ts +3 -0
  16. package/dist/commands/bench.d.ts.map +1 -0
  17. package/dist/commands/bench.js +206 -0
  18. package/dist/commands/bench.js.map +1 -0
  19. package/dist/commands/calibrate.d.ts +3 -0
  20. package/dist/commands/calibrate.d.ts.map +1 -0
  21. package/dist/commands/calibrate.js +159 -0
  22. package/dist/commands/calibrate.js.map +1 -0
  23. package/dist/commands/check.d.ts +3 -0
  24. package/dist/commands/check.d.ts.map +1 -0
  25. package/dist/commands/check.js +106 -0
  26. package/dist/commands/check.js.map +1 -0
  27. package/dist/commands/compile.d.ts +3 -0
  28. package/dist/commands/compile.d.ts.map +1 -0
  29. package/dist/commands/compile.js +116 -0
  30. package/dist/commands/compile.js.map +1 -0
  31. package/dist/commands/init.d.ts +4 -0
  32. package/dist/commands/init.d.ts.map +1 -0
  33. package/dist/commands/init.js +93 -0
  34. package/dist/commands/init.js.map +1 -0
  35. package/dist/commands/login.d.ts +3 -0
  36. package/dist/commands/login.d.ts.map +1 -0
  37. package/dist/commands/login.js +58 -0
  38. package/dist/commands/login.js.map +1 -0
  39. package/dist/commands/replay.d.ts +4 -0
  40. package/dist/commands/replay.d.ts.map +1 -0
  41. package/dist/commands/replay.js +118 -0
  42. package/dist/commands/replay.js.map +1 -0
  43. package/dist/commands/report.d.ts +5 -0
  44. package/dist/commands/report.d.ts.map +1 -0
  45. package/dist/commands/report.js +78 -0
  46. package/dist/commands/report.js.map +1 -0
  47. package/dist/commands/rubric.d.ts +3 -0
  48. package/dist/commands/rubric.d.ts.map +1 -0
  49. package/dist/commands/rubric.js +40 -0
  50. package/dist/commands/rubric.js.map +1 -0
  51. package/dist/commands/uninstall.d.ts +2 -0
  52. package/dist/commands/uninstall.d.ts.map +1 -0
  53. package/dist/commands/uninstall.js +31 -0
  54. package/dist/commands/uninstall.js.map +1 -0
  55. package/dist/hooks/postToolUse.d.ts +3 -0
  56. package/dist/hooks/postToolUse.d.ts.map +1 -0
  57. package/dist/hooks/postToolUse.js +145 -0
  58. package/dist/hooks/postToolUse.js.map +1 -0
  59. package/dist/hooks/sessionStart.d.ts +11 -0
  60. package/dist/hooks/sessionStart.d.ts.map +1 -0
  61. package/dist/hooks/sessionStart.js +83 -0
  62. package/dist/hooks/sessionStart.js.map +1 -0
  63. package/dist/hooks/stop.d.ts +26 -0
  64. package/dist/hooks/stop.d.ts.map +1 -0
  65. package/dist/hooks/stop.js +227 -0
  66. package/dist/hooks/stop.js.map +1 -0
  67. package/dist/hooks/turnStart.d.ts +8 -0
  68. package/dist/hooks/turnStart.d.ts.map +1 -0
  69. package/dist/hooks/turnStart.js +40 -0
  70. package/dist/hooks/turnStart.js.map +1 -0
  71. package/dist/lib/applyPatch.d.ts +22 -0
  72. package/dist/lib/applyPatch.d.ts.map +1 -0
  73. package/dist/lib/applyPatch.js +63 -0
  74. package/dist/lib/applyPatch.js.map +1 -0
  75. package/dist/lib/audit.d.ts +40 -0
  76. package/dist/lib/audit.d.ts.map +1 -0
  77. package/dist/lib/audit.js +215 -0
  78. package/dist/lib/audit.js.map +1 -0
  79. package/dist/lib/band.d.ts +20 -0
  80. package/dist/lib/band.d.ts.map +1 -0
  81. package/dist/lib/band.js +40 -0
  82. package/dist/lib/band.js.map +1 -0
  83. package/dist/lib/calibration.d.ts +13 -0
  84. package/dist/lib/calibration.d.ts.map +1 -0
  85. package/dist/lib/calibration.js +25 -0
  86. package/dist/lib/calibration.js.map +1 -0
  87. package/dist/lib/checkRunner.d.ts +34 -0
  88. package/dist/lib/checkRunner.d.ts.map +1 -0
  89. package/dist/lib/checkRunner.js +76 -0
  90. package/dist/lib/checkRunner.js.map +1 -0
  91. package/dist/lib/claude.d.ts +4 -0
  92. package/dist/lib/claude.d.ts.map +1 -0
  93. package/dist/lib/claude.js +28 -0
  94. package/dist/lib/claude.js.map +1 -0
  95. package/dist/lib/compilePrompt.d.ts +22 -0
  96. package/dist/lib/compilePrompt.d.ts.map +1 -0
  97. package/dist/lib/compilePrompt.js +33 -0
  98. package/dist/lib/compilePrompt.js.map +1 -0
  99. package/dist/lib/constants.d.ts +33 -0
  100. package/dist/lib/constants.d.ts.map +1 -0
  101. package/dist/lib/constants.js +33 -0
  102. package/dist/lib/constants.js.map +1 -0
  103. package/dist/lib/coverage.d.ts +7 -0
  104. package/dist/lib/coverage.d.ts.map +1 -0
  105. package/dist/lib/coverage.js +17 -0
  106. package/dist/lib/coverage.js.map +1 -0
  107. package/dist/lib/credentials.d.ts +27 -0
  108. package/dist/lib/credentials.d.ts.map +1 -0
  109. package/dist/lib/credentials.js +89 -0
  110. package/dist/lib/credentials.js.map +1 -0
  111. package/dist/lib/diff.d.ts +30 -0
  112. package/dist/lib/diff.d.ts.map +1 -0
  113. package/dist/lib/diff.js +139 -0
  114. package/dist/lib/diff.js.map +1 -0
  115. package/dist/lib/events.d.ts +5 -0
  116. package/dist/lib/events.d.ts.map +1 -0
  117. package/dist/lib/events.js +38 -0
  118. package/dist/lib/events.js.map +1 -0
  119. package/dist/lib/git.d.ts +37 -0
  120. package/dist/lib/git.d.ts.map +1 -0
  121. package/dist/lib/git.js +163 -0
  122. package/dist/lib/git.js.map +1 -0
  123. package/dist/lib/hookRunner.d.ts +10 -0
  124. package/dist/lib/hookRunner.d.ts.map +1 -0
  125. package/dist/lib/hookRunner.js +52 -0
  126. package/dist/lib/hookRunner.js.map +1 -0
  127. package/dist/lib/hosts.d.ts +20 -0
  128. package/dist/lib/hosts.d.ts.map +1 -0
  129. package/dist/lib/hosts.js +101 -0
  130. package/dist/lib/hosts.js.map +1 -0
  131. package/dist/lib/jev.d.ts +24 -0
  132. package/dist/lib/jev.d.ts.map +1 -0
  133. package/dist/lib/jev.js +169 -0
  134. package/dist/lib/jev.js.map +1 -0
  135. package/dist/lib/lintConfig.d.ts +3 -0
  136. package/dist/lib/lintConfig.d.ts.map +1 -0
  137. package/dist/lib/lintConfig.js +55 -0
  138. package/dist/lib/lintConfig.js.map +1 -0
  139. package/dist/lib/loadRules.d.ts +12 -0
  140. package/dist/lib/loadRules.d.ts.map +1 -0
  141. package/dist/lib/loadRules.js +31 -0
  142. package/dist/lib/loadRules.js.map +1 -0
  143. package/dist/lib/opencodePlugin.d.ts +10 -0
  144. package/dist/lib/opencodePlugin.d.ts.map +1 -0
  145. package/dist/lib/opencodePlugin.js +36 -0
  146. package/dist/lib/opencodePlugin.js.map +1 -0
  147. package/dist/lib/output.d.ts +6 -0
  148. package/dist/lib/output.d.ts.map +1 -0
  149. package/dist/lib/output.js +35 -0
  150. package/dist/lib/output.js.map +1 -0
  151. package/dist/lib/packageRoot.d.ts +12 -0
  152. package/dist/lib/packageRoot.d.ts.map +1 -0
  153. package/dist/lib/packageRoot.js +50 -0
  154. package/dist/lib/packageRoot.js.map +1 -0
  155. package/dist/lib/paths.d.ts +24 -0
  156. package/dist/lib/paths.d.ts.map +1 -0
  157. package/dist/lib/paths.js +75 -0
  158. package/dist/lib/paths.js.map +1 -0
  159. package/dist/lib/reason.d.ts +11 -0
  160. package/dist/lib/reason.d.ts.map +1 -0
  161. package/dist/lib/reason.js +31 -0
  162. package/dist/lib/reason.js.map +1 -0
  163. package/dist/lib/regularFile.d.ts +26 -0
  164. package/dist/lib/regularFile.d.ts.map +1 -0
  165. package/dist/lib/regularFile.js +77 -0
  166. package/dist/lib/regularFile.js.map +1 -0
  167. package/dist/lib/replay.d.ts +74 -0
  168. package/dist/lib/replay.d.ts.map +1 -0
  169. package/dist/lib/replay.js +250 -0
  170. package/dist/lib/replay.js.map +1 -0
  171. package/dist/lib/replayCodex.d.ts +6 -0
  172. package/dist/lib/replayCodex.d.ts.map +1 -0
  173. package/dist/lib/replayCodex.js +132 -0
  174. package/dist/lib/replayCodex.js.map +1 -0
  175. package/dist/lib/replayOpencode.d.ts +15 -0
  176. package/dist/lib/replayOpencode.d.ts.map +1 -0
  177. package/dist/lib/replayOpencode.js +154 -0
  178. package/dist/lib/replayOpencode.js.map +1 -0
  179. package/dist/lib/rubricFile.d.ts +31 -0
  180. package/dist/lib/rubricFile.d.ts.map +1 -0
  181. package/dist/lib/rubricFile.js +75 -0
  182. package/dist/lib/rubricFile.js.map +1 -0
  183. package/dist/lib/scope.d.ts +4 -0
  184. package/dist/lib/scope.d.ts.map +1 -0
  185. package/dist/lib/scope.js +14 -0
  186. package/dist/lib/scope.js.map +1 -0
  187. package/dist/lib/session.d.ts +48 -0
  188. package/dist/lib/session.d.ts.map +1 -0
  189. package/dist/lib/session.js +182 -0
  190. package/dist/lib/session.js.map +1 -0
  191. package/dist/lib/settings.d.ts +26 -0
  192. package/dist/lib/settings.d.ts.map +1 -0
  193. package/dist/lib/settings.js +104 -0
  194. package/dist/lib/settings.js.map +1 -0
  195. package/dist/lib/sources.d.ts +28 -0
  196. package/dist/lib/sources.d.ts.map +1 -0
  197. package/dist/lib/sources.js +137 -0
  198. package/dist/lib/sources.js.map +1 -0
  199. package/dist/lib/stdin.d.ts +3 -0
  200. package/dist/lib/stdin.d.ts.map +1 -0
  201. package/dist/lib/stdin.js +24 -0
  202. package/dist/lib/stdin.js.map +1 -0
  203. package/dist/lib/transcript.d.ts +3 -0
  204. package/dist/lib/transcript.d.ts.map +1 -0
  205. package/dist/lib/transcript.js +57 -0
  206. package/dist/lib/transcript.js.map +1 -0
  207. package/dist/lib/ui.d.ts +8 -0
  208. package/dist/lib/ui.d.ts.map +1 -0
  209. package/dist/lib/ui.js +34 -0
  210. package/dist/lib/ui.js.map +1 -0
  211. package/dist/ui/components/Buckets.d.ts +6 -0
  212. package/dist/ui/components/Buckets.d.ts.map +1 -0
  213. package/dist/ui/components/Buckets.js +11 -0
  214. package/dist/ui/components/Buckets.js.map +1 -0
  215. package/dist/ui/components/Callout.d.ts +11 -0
  216. package/dist/ui/components/Callout.d.ts.map +1 -0
  217. package/dist/ui/components/Callout.js +10 -0
  218. package/dist/ui/components/Callout.js.map +1 -0
  219. package/dist/ui/components/Checklist.d.ts +10 -0
  220. package/dist/ui/components/Checklist.d.ts.map +1 -0
  221. package/dist/ui/components/Checklist.js +8 -0
  222. package/dist/ui/components/Checklist.js.map +1 -0
  223. package/dist/ui/components/Columns.d.ts +28 -0
  224. package/dist/ui/components/Columns.d.ts.map +1 -0
  225. package/dist/ui/components/Columns.js +20 -0
  226. package/dist/ui/components/Columns.js.map +1 -0
  227. package/dist/ui/components/Header.d.ts +9 -0
  228. package/dist/ui/components/Header.d.ts.map +1 -0
  229. package/dist/ui/components/Header.js +7 -0
  230. package/dist/ui/components/Header.js.map +1 -0
  231. package/dist/ui/components/Live.d.ts +16 -0
  232. package/dist/ui/components/Live.d.ts.map +1 -0
  233. package/dist/ui/components/Live.js +40 -0
  234. package/dist/ui/components/Live.js.map +1 -0
  235. package/dist/ui/components/RuleTable.d.ts +15 -0
  236. package/dist/ui/components/RuleTable.d.ts.map +1 -0
  237. package/dist/ui/components/RuleTable.js +81 -0
  238. package/dist/ui/components/RuleTable.js.map +1 -0
  239. package/dist/ui/components/Section.d.ts +10 -0
  240. package/dist/ui/components/Section.d.ts.map +1 -0
  241. package/dist/ui/components/Section.js +8 -0
  242. package/dist/ui/components/Section.js.map +1 -0
  243. package/dist/ui/components/Verdicts.d.ts +9 -0
  244. package/dist/ui/components/Verdicts.d.ts.map +1 -0
  245. package/dist/ui/components/Verdicts.js +12 -0
  246. package/dist/ui/components/Verdicts.js.map +1 -0
  247. package/dist/ui/render.d.ts +20 -0
  248. package/dist/ui/render.d.ts.map +1 -0
  249. package/dist/ui/render.js +32 -0
  250. package/dist/ui/render.js.map +1 -0
  251. package/dist/ui/theme.d.ts +37 -0
  252. package/dist/ui/theme.d.ts.map +1 -0
  253. package/dist/ui/theme.js +63 -0
  254. package/dist/ui/theme.js.map +1 -0
  255. package/dist/ui/views/AuditView.d.ts +18 -0
  256. package/dist/ui/views/AuditView.d.ts.map +1 -0
  257. package/dist/ui/views/AuditView.js +48 -0
  258. package/dist/ui/views/AuditView.js.map +1 -0
  259. package/dist/ui/views/BenchView.d.ts +33 -0
  260. package/dist/ui/views/BenchView.d.ts.map +1 -0
  261. package/dist/ui/views/BenchView.js +19 -0
  262. package/dist/ui/views/BenchView.js.map +1 -0
  263. package/dist/ui/views/CalibrateView.d.ts +26 -0
  264. package/dist/ui/views/CalibrateView.d.ts.map +1 -0
  265. package/dist/ui/views/CalibrateView.js +42 -0
  266. package/dist/ui/views/CalibrateView.js.map +1 -0
  267. package/dist/ui/views/CheckView.d.ts +19 -0
  268. package/dist/ui/views/CheckView.d.ts.map +1 -0
  269. package/dist/ui/views/CheckView.js +15 -0
  270. package/dist/ui/views/CheckView.js.map +1 -0
  271. package/dist/ui/views/ErrorView.d.ts +4 -0
  272. package/dist/ui/views/ErrorView.d.ts.map +1 -0
  273. package/dist/ui/views/ErrorView.js +26 -0
  274. package/dist/ui/views/ErrorView.js.map +1 -0
  275. package/dist/ui/views/HelpView.d.ts +2 -0
  276. package/dist/ui/views/HelpView.d.ts.map +1 -0
  277. package/dist/ui/views/HelpView.js +25 -0
  278. package/dist/ui/views/HelpView.js.map +1 -0
  279. package/dist/ui/views/InitView.d.ts +27 -0
  280. package/dist/ui/views/InitView.d.ts.map +1 -0
  281. package/dist/ui/views/InitView.js +24 -0
  282. package/dist/ui/views/InitView.js.map +1 -0
  283. package/dist/ui/views/ReplayView.d.ts +16 -0
  284. package/dist/ui/views/ReplayView.d.ts.map +1 -0
  285. package/dist/ui/views/ReplayView.js +44 -0
  286. package/dist/ui/views/ReplayView.js.map +1 -0
  287. package/dist/ui/views/ReportView.d.ts +14 -0
  288. package/dist/ui/views/ReportView.d.ts.map +1 -0
  289. package/dist/ui/views/ReportView.js +86 -0
  290. package/dist/ui/views/ReportView.js.map +1 -0
  291. package/dist/ui/views/RubricView.d.ts +18 -0
  292. package/dist/ui/views/RubricView.d.ts.map +1 -0
  293. package/dist/ui/views/RubricView.js +18 -0
  294. package/dist/ui/views/RubricView.js.map +1 -0
  295. package/opencode/abide.mjs +246 -0
  296. package/package.json +50 -0
  297. package/skills/abide-compile/SKILL.md +173 -0
  298. package/src/abide-hook.ts +23 -0
  299. package/src/bin.ts +64 -0
  300. package/src/commands/audit.ts +97 -0
  301. package/src/commands/bench.ts +226 -0
  302. package/src/commands/calibrate.ts +165 -0
  303. package/src/commands/check.ts +114 -0
  304. package/src/commands/compile.ts +127 -0
  305. package/src/commands/init.ts +109 -0
  306. package/src/commands/login.ts +61 -0
  307. package/src/commands/replay.ts +148 -0
  308. package/src/commands/report.ts +83 -0
  309. package/src/commands/rubric.ts +45 -0
  310. package/src/commands/uninstall.ts +33 -0
  311. package/src/hooks/postToolUse.ts +171 -0
  312. package/src/hooks/sessionStart.ts +100 -0
  313. package/src/hooks/stop.ts +275 -0
  314. package/src/hooks/turnStart.ts +36 -0
  315. package/src/lib/applyPatch.ts +75 -0
  316. package/src/lib/audit.ts +265 -0
  317. package/src/lib/band.ts +49 -0
  318. package/src/lib/calibration.ts +35 -0
  319. package/src/lib/checkRunner.ts +124 -0
  320. package/src/lib/claude.ts +35 -0
  321. package/src/lib/compilePrompt.ts +67 -0
  322. package/src/lib/constants.ts +39 -0
  323. package/src/lib/coverage.ts +21 -0
  324. package/src/lib/credentials.ts +104 -0
  325. package/src/lib/diff.ts +209 -0
  326. package/src/lib/events.ts +34 -0
  327. package/src/lib/git.ts +206 -0
  328. package/src/lib/hookRunner.ts +55 -0
  329. package/src/lib/hosts.ts +112 -0
  330. package/src/lib/jev.ts +223 -0
  331. package/src/lib/lintConfig.ts +53 -0
  332. package/src/lib/loadRules.ts +39 -0
  333. package/src/lib/opencodePlugin.ts +38 -0
  334. package/src/lib/output.ts +44 -0
  335. package/src/lib/packageRoot.ts +48 -0
  336. package/src/lib/paths.ts +96 -0
  337. package/src/lib/reason.ts +46 -0
  338. package/src/lib/regularFile.ts +96 -0
  339. package/src/lib/replay.ts +314 -0
  340. package/src/lib/replayCodex.ts +130 -0
  341. package/src/lib/replayOpencode.ts +186 -0
  342. package/src/lib/rubricFile.ts +99 -0
  343. package/src/lib/scope.ts +18 -0
  344. package/src/lib/session.ts +223 -0
  345. package/src/lib/settings.ts +112 -0
  346. package/src/lib/sources.ts +154 -0
  347. package/src/lib/stdin.ts +23 -0
  348. package/src/lib/transcript.ts +49 -0
  349. package/src/lib/ui.ts +38 -0
  350. package/src/ui/components/Buckets.tsx +30 -0
  351. package/src/ui/components/Callout.tsx +26 -0
  352. package/src/ui/components/Checklist.tsx +29 -0
  353. package/src/ui/components/Columns.tsx +62 -0
  354. package/src/ui/components/Header.tsx +35 -0
  355. package/src/ui/components/Live.tsx +73 -0
  356. package/src/ui/components/RuleTable.tsx +94 -0
  357. package/src/ui/components/Section.tsx +24 -0
  358. package/src/ui/components/Verdicts.tsx +40 -0
  359. package/src/ui/render.tsx +51 -0
  360. package/src/ui/theme.ts +65 -0
  361. package/src/ui/views/AuditView.tsx +140 -0
  362. package/src/ui/views/BenchView.tsx +87 -0
  363. package/src/ui/views/CalibrateView.tsx +108 -0
  364. package/src/ui/views/CheckView.tsx +56 -0
  365. package/src/ui/views/ErrorView.tsx +32 -0
  366. package/src/ui/views/HelpView.tsx +51 -0
  367. package/src/ui/views/InitView.tsx +103 -0
  368. package/src/ui/views/ReplayView.tsx +100 -0
  369. package/src/ui/views/ReportView.tsx +225 -0
  370. package/src/ui/views/RubricView.tsx +82 -0
@@ -0,0 +1,227 @@
1
+ import { existsSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { createBlobId, isAbideError, stopInputSchema, turnIdOf, } from "@coldtea/abide-schema";
4
+ import { mergeOutcomes, runCheck } from "../lib/checkRunner.js";
5
+ import { MAX_STOP_CHECKS_PER_TURN, STOP_FALLBACK_DIFF_TIMEOUT_MS, STOP_GIT_TIMEOUT_MS, TURN_CHECK_TIMEOUT_MS, } from "../lib/constants.js";
6
+ import { editsCoverFile } from "../lib/coverage.js";
7
+ import { boundState, remainingMs, unifiedDiff } from "../lib/diff.js";
8
+ import { appendEvent } from "../lib/events.js";
9
+ import { blobIdsAt, diffTrees, snapshotTree, splitDiff } from "../lib/git.js";
10
+ import { hasApiKey } from "../lib/credentials.js";
11
+ import { loadRules } from "../lib/loadRules.js";
12
+ import { debug } from "../lib/output.js";
13
+ import { findRepoRoot, isExcludedPath, relativeToRoot } from "../lib/paths.js";
14
+ import { readRegularFile, readRegularText } from "../lib/regularFile.js";
15
+ import { flagNotice, repairReason } from "../lib/reason.js";
16
+ import { clearTurn, hasTurnState, incrementStopChecks, readBaseline, readBlockedFiles, readBaselineStatus, readChecked, readFileStarts, readPrompt, stopCheckCount, turnDir, } from "../lib/session.js";
17
+ import { lastUserPrompt } from "../lib/transcript.js";
18
+ /**
19
+ * Everything the turn changed. With a baseline from turn-start it is the git
20
+ * diff between then and now, whichever tool made the change. Without one it
21
+ * is each file's start-of-turn content against the disk, which sees only what
22
+ * Edit and Write touched. Every diff here shares one budget, and a turn that
23
+ * did not fit in it is reported as incomplete rather than checked in part.
24
+ */
25
+ export const turnDiff = (root, dir) => {
26
+ const status = readBaselineStatus(dir);
27
+ if (status === "failed" || status === "pending") {
28
+ return {
29
+ kind: "incomplete",
30
+ reason: "git could not snapshot the working tree at turn start",
31
+ missing: [],
32
+ };
33
+ }
34
+ const baseline = readBaseline(dir);
35
+ if (baseline !== undefined) {
36
+ const started = performance.now();
37
+ const now = snapshotTree(root, path.join(dir, "index"), STOP_GIT_TIMEOUT_MS);
38
+ const left = Math.floor(STOP_GIT_TIMEOUT_MS - (performance.now() - started));
39
+ const patch = now === undefined || left <= 0 ? undefined : diffTrees(root, baseline, now, left);
40
+ if (patch === undefined)
41
+ return {
42
+ kind: "incomplete",
43
+ reason: "git could not snapshot the working tree in time",
44
+ missing: [],
45
+ };
46
+ const fileDiffs = splitDiff(patch);
47
+ const files = fileDiffs.map((f) => f.file);
48
+ const stillLeft = Math.floor(STOP_GIT_TIMEOUT_MS - (performance.now() - started));
49
+ const ids = stillLeft <= 0 ? undefined : blobIdsAt(root, baseline, files, stillLeft);
50
+ return {
51
+ kind: "complete",
52
+ files,
53
+ fileDiffs,
54
+ source: "git",
55
+ startIds: ids === undefined ? undefined : new Map(files.map((f) => [f, ids.get(f) ?? null])),
56
+ };
57
+ }
58
+ const deadline = performance.now() + STOP_FALLBACK_DIFF_TIMEOUT_MS;
59
+ const fileDiffs = [];
60
+ const missing = [];
61
+ const startIds = new Map();
62
+ for (const start of readFileStarts(dir)) {
63
+ const relative = relativeToRoot(root, start.path);
64
+ if (relative.startsWith("..") || isExcludedPath(relative))
65
+ continue;
66
+ const after = readRegularText(start.path) ?? null;
67
+ if (after === null && existsSync(start.path)) {
68
+ missing.push(relative);
69
+ continue;
70
+ }
71
+ if (start.original === after)
72
+ continue;
73
+ const patch = unifiedDiff(relative, start.original ?? "", after ?? "", remainingMs(deadline));
74
+ if (patch === undefined) {
75
+ missing.push(relative);
76
+ continue;
77
+ }
78
+ fileDiffs.push(...splitDiff(patch));
79
+ startIds.set(relative, start.original === null ? null : createBlobId(start.original));
80
+ }
81
+ if (missing.length > 0) {
82
+ return {
83
+ kind: "incomplete",
84
+ reason: "some files changed this turn could not be diffed in time",
85
+ missing,
86
+ };
87
+ }
88
+ return {
89
+ kind: "complete",
90
+ files: fileDiffs.map((f) => f.file),
91
+ fileDiffs,
92
+ source: "files",
93
+ startIds,
94
+ };
95
+ };
96
+ export const handleStop = async (raw) => {
97
+ const parsed = stopInputSchema.safeParse(raw);
98
+ if (!parsed.success)
99
+ return { kind: "silent" };
100
+ const input = parsed.data;
101
+ const started = performance.now();
102
+ const at = new Date().toISOString();
103
+ const root = findRepoRoot(input.cwd);
104
+ const dir = turnDir(input.session_id, turnIdOf(input));
105
+ const finish = (output) => {
106
+ if (output.kind !== "block")
107
+ clearTurn(dir);
108
+ return output;
109
+ };
110
+ if (!hasTurnState(dir))
111
+ return finish({ kind: "silent" });
112
+ if (stopCheckCount(dir) >= MAX_STOP_CHECKS_PER_TURN)
113
+ return finish({ kind: "silent" });
114
+ const loaded = loadRules(root);
115
+ for (const problem of loaded.problems)
116
+ debug(problem);
117
+ if (loaded.rules.length === 0)
118
+ return finish({ kind: "silent" });
119
+ const turn = turnDiff(root, dir);
120
+ if (turn.kind === "incomplete") {
121
+ appendEvent(root, {
122
+ kind: "skip",
123
+ at,
124
+ phase: "turn",
125
+ sessionId: input.session_id,
126
+ reason: `turn diff incomplete: ${turn.reason}`,
127
+ files: turn.missing,
128
+ });
129
+ return finish({ kind: "silent" });
130
+ }
131
+ const { files, fileDiffs } = turn;
132
+ if (files.length === 0)
133
+ return finish({ kind: "silent" });
134
+ const bounded = fileDiffs.map((f) => ({
135
+ file: f.file,
136
+ text: boundState(f.text, 8_000).text,
137
+ }));
138
+ if (!hasApiKey(root)) {
139
+ appendEvent(root, {
140
+ kind: "skip",
141
+ at,
142
+ phase: "turn",
143
+ sessionId: input.session_id,
144
+ reason: "no api key",
145
+ files,
146
+ });
147
+ }
148
+ incrementStopChecks(dir);
149
+ // Edit-phase rules rerun on files the edit checks did not see whole, and on
150
+ // blocked ones: a block the agent ignored must not end the turn quietly.
151
+ const checked = readChecked(dir);
152
+ const blocked = readBlockedFiles(dir);
153
+ const covered = (file) => {
154
+ if (turn.startIds === undefined || blocked.has(file))
155
+ return false;
156
+ const now = readRegularFile(path.join(root, file));
157
+ if (now === undefined)
158
+ return false;
159
+ const start = turn.startIds.get(file) ?? null;
160
+ return editsCoverFile(start, checked.filter((e) => e.path === file), createBlobId(now));
161
+ };
162
+ const unchecked = bounded.filter((f) => !covered(f.file));
163
+ const task = lastUserPrompt(input.transcript_path ?? undefined) ?? readPrompt(dir);
164
+ let outcome;
165
+ try {
166
+ const turnOutcome = await runCheck({
167
+ phase: "turn",
168
+ fileDiffs: bounded,
169
+ task,
170
+ rules: loaded.rules,
171
+ thresholds: loaded.thresholds,
172
+ timeoutMs: TURN_CHECK_TIMEOUT_MS,
173
+ });
174
+ const editOutcomes = await Promise.all(unchecked.map((f) => runCheck({
175
+ phase: "edit",
176
+ fileDiffs: [f],
177
+ task,
178
+ rules: loaded.rules,
179
+ thresholds: loaded.thresholds,
180
+ timeoutMs: TURN_CHECK_TIMEOUT_MS,
181
+ })));
182
+ outcome = mergeOutcomes([turnOutcome, ...editOutcomes]);
183
+ }
184
+ catch (error) {
185
+ appendEvent(root, {
186
+ kind: "error",
187
+ at,
188
+ phase: "turn",
189
+ sessionId: input.session_id,
190
+ code: isAbideError(error) ? error.code : "CHECK_FAILED",
191
+ message: error instanceof Error ? error.message : String(error),
192
+ latencyMs: Math.round(performance.now() - started),
193
+ });
194
+ return finish({ kind: "silent" });
195
+ }
196
+ const byId = new Map(loaded.rules.map((r) => [r.id, r]));
197
+ const pairs = (band) => outcome.verdicts.flatMap((verdict) => {
198
+ const rule = byId.get(verdict.ruleId);
199
+ return rule !== undefined && verdict.band === band ? [{ rule, verdict }] : [];
200
+ });
201
+ const acting = pairs("act");
202
+ const flagged = pairs("flag");
203
+ appendEvent(root, {
204
+ kind: "check",
205
+ at,
206
+ phase: "turn",
207
+ sessionId: input.session_id,
208
+ promptId: turnIdOf(input),
209
+ files,
210
+ rules: outcome.modelRules.length,
211
+ latencyMs: Math.round(performance.now() - started),
212
+ modelLatencyMs: outcome.modelLatencyMs,
213
+ usage: outcome.usage,
214
+ verdicts: outcome.verdicts,
215
+ blocked: acting.length > 0,
216
+ });
217
+ const systemMessage = flagged.length > 0 ? flagNotice("turn", flagged, files) : undefined;
218
+ if (acting.length > 0) {
219
+ return finish({
220
+ kind: "block",
221
+ reason: repairReason("turn", acting, files),
222
+ ...(systemMessage === undefined ? {} : { systemMessage }),
223
+ });
224
+ }
225
+ return finish(systemMessage === undefined ? { kind: "silent" } : { kind: "notice", systemMessage });
226
+ };
227
+ //# sourceMappingURL=stop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stop.js","sourceRoot":"","sources":["../../src/hooks/stop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { type HookOutput } from "@coldtea/abide-schema";
2
+ /**
3
+ * The turn is about to begin: remember what the working tree looks like now,
4
+ * so the Stop check can diff the whole turn, whichever tool made the changes.
5
+ * Prints nothing: on this event plain stdout would become context.
6
+ */
7
+ export declare const handleTurnStart: (raw: unknown) => Promise<HookOutput>;
8
+ //# sourceMappingURL=turnStart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turnStart.d.ts","sourceRoot":"","sources":["../../src/hooks/turnStart.ts"],"names":[],"mappings":"AACA,OAAO,EAAkC,KAAK,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAMxF;;;;GAIG;AACH,eAAO,MAAM,eAAe,QAAe,OAAO,KAAG,OAAO,CAAC,UAAU,CAuBtE,CAAC"}
@@ -0,0 +1,40 @@
1
+ import path from "node:path";
2
+ import { turnIdOf, turnStartInputSchema } from "@coldtea/abide-schema";
3
+ import { TURN_START_TIMEOUT_MS } from "../lib/constants.js";
4
+ import { isGitRepo, snapshotTree } from "../lib/git.js";
5
+ import { findRepoRoot } from "../lib/paths.js";
6
+ import { clearTurn, markBaseline, turnDir, writeBaseline, writePrompt } from "../lib/session.js";
7
+ /**
8
+ * The turn is about to begin: remember what the working tree looks like now,
9
+ * so the Stop check can diff the whole turn, whichever tool made the changes.
10
+ * Prints nothing: on this event plain stdout would become context.
11
+ */
12
+ export const handleTurnStart = async (raw) => {
13
+ const parsed = turnStartInputSchema.safeParse(raw);
14
+ if (!parsed.success)
15
+ return { kind: "silent" };
16
+ const input = parsed.data;
17
+ const root = findRepoRoot(input.cwd);
18
+ const turnId = turnIdOf(input);
19
+ const dir = turnDir(input.session_id, turnId);
20
+ // Without a turn id every turn shares one directory, so the last turn's
21
+ // records go before this one's start.
22
+ if (turnId === undefined)
23
+ clearTurn(dir);
24
+ if (input.prompt !== undefined)
25
+ writePrompt(dir, input.prompt);
26
+ if (!isGitRepo(root))
27
+ return { kind: "silent" };
28
+ // Written before the attempt: a hook that dies mid-snapshot leaves "pending"
29
+ // behind, and the Stop check reads that as a turn it cannot see whole.
30
+ markBaseline(dir, "pending");
31
+ const tree = snapshotTree(root, path.join(dir, "index"), TURN_START_TIMEOUT_MS);
32
+ if (tree === undefined) {
33
+ markBaseline(dir, "failed");
34
+ return { kind: "silent" };
35
+ }
36
+ writeBaseline(dir, tree);
37
+ markBaseline(dir, "ok");
38
+ return { kind: "silent" };
39
+ };
40
+ //# sourceMappingURL=turnStart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turnStart.js","sourceRoot":"","sources":["../../src/hooks/turnStart.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAmB,MAAM,uBAAuB,CAAC;AACxF,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEjG;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAAE,GAAY,EAAuB,EAAE;IACzE,MAAM,MAAM,GAAG,oBAAoB,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IACnD,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAC/C,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC;IAC1B,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC/B,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAC9C,wEAAwE;IACxE,sCAAsC;IACtC,IAAI,MAAM,KAAK,SAAS;QAAE,SAAS,CAAC,GAAG,CAAC,CAAC;IACzC,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;QAAE,WAAW,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/D,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAChD,6EAA6E;IAC7E,uEAAuE;IACvE,YAAY,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,qBAAqB,CAAC,CAAC;IAChF,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QAC5B,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAC5B,CAAC;IACD,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACzB,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACxB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAC5B,CAAC,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Codex edits files through `apply_patch`, whose input is its own patch
3
+ * dialect: one `*** Begin Patch` block holding `*** Add File:`,
4
+ * `*** Update File:` (optionally followed by `*** Move to:`) and
5
+ * `*** Delete File:` sections. Update sections carry hunks that are already
6
+ * diff-shaped, so the text the judge sees is the section itself.
7
+ */
8
+ export type PatchedFile = {
9
+ kind: "add";
10
+ path: string;
11
+ text: string;
12
+ } | {
13
+ kind: "update";
14
+ path: string;
15
+ text: string;
16
+ movedTo?: string;
17
+ } | {
18
+ kind: "delete";
19
+ path: string;
20
+ };
21
+ export declare const parseApplyPatch: (command: string) => PatchedFile[];
22
+ //# sourceMappingURL=applyPatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applyPatch.d.ts","sourceRoot":"","sources":["../../src/lib/applyPatch.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAChE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAYrC,eAAO,MAAM,eAAe,YAAa,MAAM,KAAG,WAAW,EAoD5D,CAAC"}
@@ -0,0 +1,63 @@
1
+ const ADD = "*** Add File: ";
2
+ const UPDATE = "*** Update File: ";
3
+ const DELETE = "*** Delete File: ";
4
+ const MOVE = "*** Move to: ";
5
+ const hunkHeader = (line) => {
6
+ const context = line.slice(2).trim();
7
+ return context === "" ? "@@" : `@@ ${context}`;
8
+ };
9
+ export const parseApplyPatch = (command) => {
10
+ const files = [];
11
+ let open;
12
+ const close = () => {
13
+ if (open === undefined)
14
+ return;
15
+ const text = open.lines.join("\n");
16
+ files.push(open.kind === "add"
17
+ ? { kind: "add", path: open.path, text }
18
+ : {
19
+ kind: "update",
20
+ path: open.path,
21
+ text,
22
+ ...(open.movedTo === undefined ? {} : { movedTo: open.movedTo }),
23
+ });
24
+ open = undefined;
25
+ };
26
+ for (const line of command.split("\n")) {
27
+ if (line === "*** Begin Patch" || line === "*** End Patch") {
28
+ close();
29
+ continue;
30
+ }
31
+ if (line.startsWith(ADD)) {
32
+ close();
33
+ open = { kind: "add", path: line.slice(ADD.length).trim(), lines: [] };
34
+ continue;
35
+ }
36
+ if (line.startsWith(UPDATE)) {
37
+ close();
38
+ open = { kind: "update", path: line.slice(UPDATE.length).trim(), lines: [] };
39
+ continue;
40
+ }
41
+ if (line.startsWith(DELETE)) {
42
+ close();
43
+ files.push({ kind: "delete", path: line.slice(DELETE.length).trim() });
44
+ continue;
45
+ }
46
+ if (open === undefined)
47
+ continue;
48
+ if (line.startsWith(MOVE)) {
49
+ open.movedTo = line.slice(MOVE.length).trim();
50
+ continue;
51
+ }
52
+ if (line.startsWith("@@")) {
53
+ open.lines.push(hunkHeader(line));
54
+ continue;
55
+ }
56
+ if (line === "*** End of File")
57
+ continue;
58
+ open.lines.push(open.kind === "add" && !line.startsWith("+") ? `+${line}` : line);
59
+ }
60
+ close();
61
+ return files;
62
+ };
63
+ //# sourceMappingURL=applyPatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applyPatch.js","sourceRoot":"","sources":["../../src/lib/applyPatch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import type { Rule, Thresholds, Verdict } from "@coldtea/abide-schema";
2
+ /** Every tracked or untracked-but-not-ignored file under the given paths, repo-relative. */
3
+ export declare const listRepoFiles: (root: string, paths: readonly string[]) => string[];
4
+ /** The files at least one active edit-phase model rule applies to; audits judge nothing else. */
5
+ export declare const auditableFiles: (root: string, files: readonly string[], rules: readonly Rule[]) => {
6
+ files: string[];
7
+ skipped: {
8
+ tooBig: string[];
9
+ outOfScope: number;
10
+ };
11
+ };
12
+ /** A whole file as one hunk of added lines: how an audit shows a judge a file that was never "changed". */
13
+ export declare const fileAsAdded: (content: string) => string;
14
+ /** Lines per chunk. A judge asked about a 900 line file answers about the average of it; asked about 150 lines it answers about those lines. */
15
+ export declare const AUDIT_CHUNK_LINES = 150;
16
+ /** A file as consecutive hunks of added lines, each small enough to be judged on its own. */
17
+ export declare const fileAsChunks: (content: string, size?: number) => string[];
18
+ export type AuditFileResult = {
19
+ file: string;
20
+ verdicts: Verdict[];
21
+ rules: number;
22
+ latencyMs: number;
23
+ costUsd: number;
24
+ /** Chunks the gateway never answered, so the file was judged in part or not at all. */
25
+ chunksFailed?: number;
26
+ chunks?: number;
27
+ error?: string;
28
+ };
29
+ export type AuditProgress = (done: number, total: number, spendUsd: number) => void;
30
+ export declare const pool: <T>(items: readonly T[], size: number, work: (item: T) => Promise<void>) => Promise<void>;
31
+ export declare const auditFiles: (root: string, files: readonly string[], rules: readonly Rule[], thresholds: Thresholds, concurrency: number, progress: AuditProgress) => Promise<AuditFileResult[]>;
32
+ export type RuleTally = {
33
+ ruleId: string;
34
+ broken: string[];
35
+ flagged: string[];
36
+ checked: number;
37
+ };
38
+ /** Per rule: which files break it, which are uncertain, how many it saw. Loudest first. */
39
+ export declare const tallyByRule: (results: readonly AuditFileResult[]) => RuleTally[];
40
+ //# sourceMappingURL=audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/lib/audit.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAcvE,4FAA4F;AAC5F,eAAO,MAAM,aAAa,SAAU,MAAM,SAAS,SAAS,MAAM,EAAE,KAAG,MAAM,EAoB5E,CAAC;AAeF,iGAAiG;AACjG,eAAO,MAAM,cAAc,SACnB,MAAM,SACL,SAAS,MAAM,EAAE,SACjB,SAAS,IAAI,EAAE,KACrB;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAA;CA2BtE,CAAC;AAEF,2GAA2G;AAC3G,eAAO,MAAM,WAAW,YAAa,MAAM,KAAG,MAI7C,CAAC;AAEF,gJAAgJ;AAChJ,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAErC,6FAA6F;AAC7F,eAAO,MAAM,YAAY,YAAa,MAAM,oBAA6B,MAAM,EAU9E,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,uFAAuF;IACvF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;AAEpF,eAAO,MAAM,IAAI,GAAU,CAAC,SACnB,SAAS,CAAC,EAAE,QACb,MAAM,QACN,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,KAC/B,OAAO,CAAC,IAAI,CAYd,CAAC;AAkDF,eAAO,MAAM,UAAU,SACf,MAAM,SACL,SAAS,MAAM,EAAE,SACjB,SAAS,IAAI,EAAE,cACV,UAAU,eACT,MAAM,YACT,aAAa,KACtB,OAAO,CAAC,eAAe,EAAE,CA6C3B,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjG,2FAA2F;AAC3F,eAAO,MAAM,WAAW,YAAa,SAAS,eAAe,EAAE,KAAG,SAAS,EAiB1E,CAAC"}
@@ -0,0 +1,215 @@
1
+ import { lstatSync, realpathSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { spawnSync } from "node:child_process";
4
+ import { loudestVerdicts, runCheck } from "./checkRunner.js";
5
+ import { MAX_DIFF_INPUT_CHARS } from "./constants.js";
6
+ import { isExcludedPath, relativeToRoot } from "./paths.js";
7
+ import { readRegularText } from "./regularFile.js";
8
+ /** An audit is not on the agent's clock: a call may wait out a rate limit rather than count as a miss. */
9
+ const AUDIT_CALL_TIMEOUT_MS = 30_000;
10
+ import { isModelRule } from "./jev.js";
11
+ import { ruleAppliesTo } from "./scope.js";
12
+ const SKIP_FILE = /(^|\/)(package-lock\.json|pnpm-lock\.yaml|yarn\.lock|bun\.lockb?|Cargo\.lock|go\.sum)$|\.(min\.js|min\.css|map|svg|png|jpg|jpeg|gif|ico|woff2?|ttf|pdf|lock|snap|jsonl)$/;
13
+ /** Every tracked or untracked-but-not-ignored file under the given paths, repo-relative. */
14
+ export const listRepoFiles = (root, paths) => {
15
+ const args = [
16
+ "ls-files",
17
+ "--cached",
18
+ "--others",
19
+ "--exclude-standard",
20
+ "-z",
21
+ "--",
22
+ ...(paths.length ? paths : ["."]),
23
+ ];
24
+ const result = spawnSync("git", args, {
25
+ cwd: root,
26
+ encoding: "utf8",
27
+ maxBuffer: 64 * 1024 * 1024,
28
+ timeout: 20_000,
29
+ });
30
+ if (result.status !== 0)
31
+ return [];
32
+ return result.stdout
33
+ .split("\0")
34
+ .filter((f) => f !== "" && !SKIP_FILE.test(f) && !isExcludedPath(f));
35
+ };
36
+ /** Real path of a file, or nothing if any link on the way leads out of the repo or to an excluded file. */
37
+ const insideRepo = (root, file) => {
38
+ if (isExcludedPath(file))
39
+ return undefined;
40
+ try {
41
+ const base = realpathSync(root);
42
+ const real = realpathSync(path.join(root, file));
43
+ if (!real.startsWith(`${base}${path.sep}`))
44
+ return undefined;
45
+ return isExcludedPath(relativeToRoot(base, real)) ? undefined : real;
46
+ }
47
+ catch {
48
+ return undefined;
49
+ }
50
+ };
51
+ /** The files at least one active edit-phase model rule applies to; audits judge nothing else. */
52
+ export const auditableFiles = (root, files, rules) => {
53
+ const editRules = rules.filter((r) => isModelRule(r) && r.status === "active" && r.when === "edit");
54
+ const kept = [];
55
+ const tooBig = [];
56
+ let outOfScope = 0;
57
+ for (const file of files) {
58
+ if (!editRules.some((r) => ruleAppliesTo(r, file))) {
59
+ outOfScope += 1;
60
+ continue;
61
+ }
62
+ const real = insideRepo(root, file);
63
+ if (real === undefined)
64
+ continue;
65
+ try {
66
+ const stat = lstatSync(real);
67
+ if (!stat.isFile())
68
+ continue;
69
+ if (stat.size > MAX_DIFF_INPUT_CHARS) {
70
+ tooBig.push(file);
71
+ continue;
72
+ }
73
+ }
74
+ catch {
75
+ continue;
76
+ }
77
+ kept.push(file);
78
+ }
79
+ return { files: kept, skipped: { tooBig, outOfScope } };
80
+ };
81
+ /** A whole file as one hunk of added lines: how an audit shows a judge a file that was never "changed". */
82
+ export const fileAsAdded = (content) => {
83
+ const lines = content.split("\n");
84
+ if (lines.at(-1) === "")
85
+ lines.pop();
86
+ return `@@ -0,0 +1,${lines.length} @@\n${lines.map((l) => `+${l}`).join("\n")}`;
87
+ };
88
+ /** Lines per chunk. A judge asked about a 900 line file answers about the average of it; asked about 150 lines it answers about those lines. */
89
+ export const AUDIT_CHUNK_LINES = 150;
90
+ /** A file as consecutive hunks of added lines, each small enough to be judged on its own. */
91
+ export const fileAsChunks = (content, size = AUDIT_CHUNK_LINES) => {
92
+ const lines = content.split("\n");
93
+ if (lines.at(-1) === "")
94
+ lines.pop();
95
+ if (lines.length === 0)
96
+ return [];
97
+ const chunks = [];
98
+ for (let start = 0; start < lines.length; start += size) {
99
+ const part = lines.slice(start, start + size);
100
+ chunks.push(`@@ -0,0 +${start + 1},${part.length} @@\n${part.map((l) => `+${l}`).join("\n")}`);
101
+ }
102
+ return chunks;
103
+ };
104
+ export const pool = async (items, size, work) => {
105
+ let next = 0;
106
+ const workers = Array.from({ length: Math.max(1, Math.min(size, items.length)) }, async () => {
107
+ for (;;) {
108
+ const index = next;
109
+ next += 1;
110
+ const item = items[index];
111
+ if (item === undefined)
112
+ return;
113
+ await work(item);
114
+ }
115
+ });
116
+ await Promise.all(workers);
117
+ };
118
+ const judge = async (file, chunks, rules, thresholds) => {
119
+ const outs = [];
120
+ const failed = [];
121
+ for (const text of chunks) {
122
+ try {
123
+ outs.push(await runCheck({
124
+ phase: "edit",
125
+ fileDiffs: [{ file, text }],
126
+ rules,
127
+ thresholds,
128
+ timeoutMs: AUDIT_CALL_TIMEOUT_MS,
129
+ retries: 3,
130
+ }));
131
+ }
132
+ catch (error) {
133
+ failed.push({ text, error: error instanceof Error ? error.message : String(error) });
134
+ }
135
+ }
136
+ return { outs, failed, chunks: chunks.length };
137
+ };
138
+ const summarize = (file, judged) => {
139
+ const costUsd = judged.outs.reduce((s, o) => s + (o.usage.costUsd ?? 0), 0);
140
+ const last = judged.failed.at(-1);
141
+ return {
142
+ file,
143
+ verdicts: loudestVerdicts(judged.outs.flatMap((o) => o.verdicts)),
144
+ rules: judged.outs[0]?.modelRules.length ?? 0,
145
+ latencyMs: judged.outs.reduce((s, o) => s + o.modelLatencyMs, 0),
146
+ costUsd,
147
+ chunks: judged.chunks,
148
+ ...(judged.failed.length > 0
149
+ ? {
150
+ chunksFailed: judged.failed.length,
151
+ error: `${judged.failed.length} of ${judged.chunks} chunks not judged: ${last?.error ?? "unknown"}`,
152
+ }
153
+ : {}),
154
+ };
155
+ };
156
+ export const auditFiles = async (root, files, rules, thresholds, concurrency, progress) => {
157
+ const judgedByFile = new Map();
158
+ const unreadable = [];
159
+ let done = 0;
160
+ let spendUsd = 0;
161
+ await pool(files, concurrency, async (file) => {
162
+ const real = insideRepo(root, file);
163
+ const content = real === undefined ? undefined : readRegularText(real, { followSymlinks: false });
164
+ if (content === undefined) {
165
+ unreadable.push({
166
+ file,
167
+ verdicts: [],
168
+ rules: 0,
169
+ latencyMs: 0,
170
+ costUsd: 0,
171
+ error: "not a regular file inside the repository, or could not be read",
172
+ });
173
+ return;
174
+ }
175
+ const judged = await judge(file, fileAsChunks(content), rules, thresholds);
176
+ judgedByFile.set(file, judged);
177
+ spendUsd += judged.outs.reduce((s, o) => s + (o.usage.costUsd ?? 0), 0);
178
+ done += 1;
179
+ progress(done, files.length, spendUsd);
180
+ });
181
+ // A second pass, one at a time, for chunks the gateway turned away while it
182
+ // was busy with the rest of the pool. Most of them go through on their own.
183
+ for (const [file, judged] of judgedByFile) {
184
+ if (judged.failed.length === 0)
185
+ continue;
186
+ const retried = await judge(file, judged.failed.map((f) => f.text), rules, thresholds);
187
+ judged.outs.push(...retried.outs);
188
+ judged.failed = retried.failed;
189
+ spendUsd += retried.outs.reduce((s, o) => s + (o.usage.costUsd ?? 0), 0);
190
+ progress(done, files.length, spendUsd);
191
+ }
192
+ return [
193
+ ...unreadable,
194
+ ...[...judgedByFile].map(([file, judged]) => summarize(file, judged)),
195
+ ].sort((a, b) => a.file.localeCompare(b.file));
196
+ };
197
+ /** Per rule: which files break it, which are uncertain, how many it saw. Loudest first. */
198
+ export const tallyByRule = (results) => {
199
+ const byRule = new Map();
200
+ for (const r of results) {
201
+ for (const v of r.verdicts) {
202
+ const t = byRule.get(v.ruleId) ?? { ruleId: v.ruleId, broken: [], flagged: [], checked: 0 };
203
+ t.checked += 1;
204
+ if (v.band === "act")
205
+ t.broken.push(r.file);
206
+ else if (v.band === "flag")
207
+ t.flagged.push(r.file);
208
+ byRule.set(v.ruleId, t);
209
+ }
210
+ }
211
+ return [...byRule.values()].sort((a, b) => b.broken.length - a.broken.length ||
212
+ b.flagged.length - a.flagged.length ||
213
+ a.ruleId.localeCompare(b.ruleId));
214
+ };
215
+ //# sourceMappingURL=audit.js.map