@humanbased/crosscheck 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (381) hide show
  1. package/AGENT.md +207 -0
  2. package/ISSUE.md +234 -0
  3. package/LICENSE +21 -0
  4. package/README.md +234 -0
  5. package/README.zh.md +169 -0
  6. package/assets/logo.png +0 -0
  7. package/assets/screenshot-watch-timing.png +0 -0
  8. package/assets/screenshot-watch-timing.svg +1 -0
  9. package/assets/screenshot-watch.png +0 -0
  10. package/crosscheck.config.example.yml +214 -0
  11. package/dist/__tests__/annotation.test.d.ts +2 -0
  12. package/dist/__tests__/annotation.test.d.ts.map +1 -0
  13. package/dist/__tests__/annotation.test.js +134 -0
  14. package/dist/__tests__/annotation.test.js.map +1 -0
  15. package/dist/__tests__/backtrace.test.d.ts +2 -0
  16. package/dist/__tests__/backtrace.test.d.ts.map +1 -0
  17. package/dist/__tests__/backtrace.test.js +280 -0
  18. package/dist/__tests__/backtrace.test.js.map +1 -0
  19. package/dist/__tests__/board.test.d.ts +2 -0
  20. package/dist/__tests__/board.test.d.ts.map +1 -0
  21. package/dist/__tests__/board.test.js +149 -0
  22. package/dist/__tests__/board.test.js.map +1 -0
  23. package/dist/__tests__/codex.test.d.ts +2 -0
  24. package/dist/__tests__/codex.test.d.ts.map +1 -0
  25. package/dist/__tests__/codex.test.js +92 -0
  26. package/dist/__tests__/codex.test.js.map +1 -0
  27. package/dist/__tests__/comment-bodies.test.d.ts +2 -0
  28. package/dist/__tests__/comment-bodies.test.d.ts.map +1 -0
  29. package/dist/__tests__/comment-bodies.test.js +75 -0
  30. package/dist/__tests__/comment-bodies.test.js.map +1 -0
  31. package/dist/__tests__/conflict-resolve.test.d.ts +2 -0
  32. package/dist/__tests__/conflict-resolve.test.d.ts.map +1 -0
  33. package/dist/__tests__/conflict-resolve.test.js +123 -0
  34. package/dist/__tests__/conflict-resolve.test.js.map +1 -0
  35. package/dist/__tests__/crosscheck-commit.test.d.ts +2 -0
  36. package/dist/__tests__/crosscheck-commit.test.d.ts.map +1 -0
  37. package/dist/__tests__/crosscheck-commit.test.js +13 -0
  38. package/dist/__tests__/crosscheck-commit.test.js.map +1 -0
  39. package/dist/__tests__/detector.test.d.ts +2 -0
  40. package/dist/__tests__/detector.test.d.ts.map +1 -0
  41. package/dist/__tests__/detector.test.js +112 -0
  42. package/dist/__tests__/detector.test.js.map +1 -0
  43. package/dist/__tests__/diagnose.test.d.ts +2 -0
  44. package/dist/__tests__/diagnose.test.d.ts.map +1 -0
  45. package/dist/__tests__/diagnose.test.js +164 -0
  46. package/dist/__tests__/diagnose.test.js.map +1 -0
  47. package/dist/__tests__/diff-hash.test.d.ts +2 -0
  48. package/dist/__tests__/diff-hash.test.d.ts.map +1 -0
  49. package/dist/__tests__/diff-hash.test.js +126 -0
  50. package/dist/__tests__/diff-hash.test.js.map +1 -0
  51. package/dist/__tests__/durations.test.d.ts +2 -0
  52. package/dist/__tests__/durations.test.d.ts.map +1 -0
  53. package/dist/__tests__/durations.test.js +26 -0
  54. package/dist/__tests__/durations.test.js.map +1 -0
  55. package/dist/__tests__/event-fields.test.d.ts +2 -0
  56. package/dist/__tests__/event-fields.test.d.ts.map +1 -0
  57. package/dist/__tests__/event-fields.test.js +50 -0
  58. package/dist/__tests__/event-fields.test.js.map +1 -0
  59. package/dist/__tests__/filter.test.d.ts +2 -0
  60. package/dist/__tests__/filter.test.d.ts.map +1 -0
  61. package/dist/__tests__/filter.test.js +21 -0
  62. package/dist/__tests__/filter.test.js.map +1 -0
  63. package/dist/__tests__/fix.test.d.ts +2 -0
  64. package/dist/__tests__/fix.test.d.ts.map +1 -0
  65. package/dist/__tests__/fix.test.js +124 -0
  66. package/dist/__tests__/fix.test.js.map +1 -0
  67. package/dist/__tests__/github-client.test.d.ts +2 -0
  68. package/dist/__tests__/github-client.test.d.ts.map +1 -0
  69. package/dist/__tests__/github-client.test.js +22 -0
  70. package/dist/__tests__/github-client.test.js.map +1 -0
  71. package/dist/__tests__/github-scan-client.test.d.ts +2 -0
  72. package/dist/__tests__/github-scan-client.test.d.ts.map +1 -0
  73. package/dist/__tests__/github-scan-client.test.js +100 -0
  74. package/dist/__tests__/github-scan-client.test.js.map +1 -0
  75. package/dist/__tests__/is-fresh-review-comment.test.d.ts +2 -0
  76. package/dist/__tests__/is-fresh-review-comment.test.d.ts.map +1 -0
  77. package/dist/__tests__/is-fresh-review-comment.test.js +86 -0
  78. package/dist/__tests__/is-fresh-review-comment.test.js.map +1 -0
  79. package/dist/__tests__/issue.test.d.ts +2 -0
  80. package/dist/__tests__/issue.test.d.ts.map +1 -0
  81. package/dist/__tests__/issue.test.js +259 -0
  82. package/dist/__tests__/issue.test.js.map +1 -0
  83. package/dist/__tests__/kickass.test.d.ts +2 -0
  84. package/dist/__tests__/kickass.test.d.ts.map +1 -0
  85. package/dist/__tests__/kickass.test.js +268 -0
  86. package/dist/__tests__/kickass.test.js.map +1 -0
  87. package/dist/__tests__/loader.test.d.ts +2 -0
  88. package/dist/__tests__/loader.test.d.ts.map +1 -0
  89. package/dist/__tests__/loader.test.js +180 -0
  90. package/dist/__tests__/loader.test.js.map +1 -0
  91. package/dist/__tests__/onboard-preservation.test.d.ts +2 -0
  92. package/dist/__tests__/onboard-preservation.test.d.ts.map +1 -0
  93. package/dist/__tests__/onboard-preservation.test.js +506 -0
  94. package/dist/__tests__/onboard-preservation.test.js.map +1 -0
  95. package/dist/__tests__/optimize.test.d.ts +2 -0
  96. package/dist/__tests__/optimize.test.d.ts.map +1 -0
  97. package/dist/__tests__/optimize.test.js +101 -0
  98. package/dist/__tests__/optimize.test.js.map +1 -0
  99. package/dist/__tests__/post-review-comment.test.d.ts +2 -0
  100. package/dist/__tests__/post-review-comment.test.d.ts.map +1 -0
  101. package/dist/__tests__/post-review-comment.test.js +44 -0
  102. package/dist/__tests__/post-review-comment.test.js.map +1 -0
  103. package/dist/__tests__/pr-lock.test.d.ts +2 -0
  104. package/dist/__tests__/pr-lock.test.d.ts.map +1 -0
  105. package/dist/__tests__/pr-lock.test.js +115 -0
  106. package/dist/__tests__/pr-lock.test.js.map +1 -0
  107. package/dist/__tests__/pr-picker.test.d.ts +2 -0
  108. package/dist/__tests__/pr-picker.test.d.ts.map +1 -0
  109. package/dist/__tests__/pr-picker.test.js +57 -0
  110. package/dist/__tests__/pr-picker.test.js.map +1 -0
  111. package/dist/__tests__/pr-status-scan.test.d.ts +2 -0
  112. package/dist/__tests__/pr-status-scan.test.d.ts.map +1 -0
  113. package/dist/__tests__/pr-status-scan.test.js +92 -0
  114. package/dist/__tests__/pr-status-scan.test.js.map +1 -0
  115. package/dist/__tests__/pr-status.test.d.ts +2 -0
  116. package/dist/__tests__/pr-status.test.d.ts.map +1 -0
  117. package/dist/__tests__/pr-status.test.js +346 -0
  118. package/dist/__tests__/pr-status.test.js.map +1 -0
  119. package/dist/__tests__/repo-picker.test.d.ts +2 -0
  120. package/dist/__tests__/repo-picker.test.d.ts.map +1 -0
  121. package/dist/__tests__/repo-picker.test.js +115 -0
  122. package/dist/__tests__/repo-picker.test.js.map +1 -0
  123. package/dist/__tests__/review-comment-body.test.d.ts +2 -0
  124. package/dist/__tests__/review-comment-body.test.d.ts.map +1 -0
  125. package/dist/__tests__/review-comment-body.test.js +54 -0
  126. package/dist/__tests__/review-comment-body.test.js.map +1 -0
  127. package/dist/__tests__/review-models.test.d.ts +2 -0
  128. package/dist/__tests__/review-models.test.d.ts.map +1 -0
  129. package/dist/__tests__/review-models.test.js +39 -0
  130. package/dist/__tests__/review-models.test.js.map +1 -0
  131. package/dist/__tests__/review-status.test.d.ts +2 -0
  132. package/dist/__tests__/review-status.test.d.ts.map +1 -0
  133. package/dist/__tests__/review-status.test.js +95 -0
  134. package/dist/__tests__/review-status.test.js.map +1 -0
  135. package/dist/__tests__/runner.test.d.ts +2 -0
  136. package/dist/__tests__/runner.test.d.ts.map +1 -0
  137. package/dist/__tests__/runner.test.js +204 -0
  138. package/dist/__tests__/runner.test.js.map +1 -0
  139. package/dist/__tests__/scan-cache.test.d.ts +2 -0
  140. package/dist/__tests__/scan-cache.test.d.ts.map +1 -0
  141. package/dist/__tests__/scan-cache.test.js +59 -0
  142. package/dist/__tests__/scan-cache.test.js.map +1 -0
  143. package/dist/__tests__/scan-client.test.d.ts +2 -0
  144. package/dist/__tests__/scan-client.test.d.ts.map +1 -0
  145. package/dist/__tests__/scan-client.test.js +30 -0
  146. package/dist/__tests__/scan-client.test.js.map +1 -0
  147. package/dist/__tests__/scan.test.d.ts +2 -0
  148. package/dist/__tests__/scan.test.d.ts.map +1 -0
  149. package/dist/__tests__/scan.test.js +115 -0
  150. package/dist/__tests__/scan.test.js.map +1 -0
  151. package/dist/__tests__/scopes.test.d.ts +2 -0
  152. package/dist/__tests__/scopes.test.d.ts.map +1 -0
  153. package/dist/__tests__/scopes.test.js +101 -0
  154. package/dist/__tests__/scopes.test.js.map +1 -0
  155. package/dist/__tests__/sha-cache.test.d.ts +2 -0
  156. package/dist/__tests__/sha-cache.test.d.ts.map +1 -0
  157. package/dist/__tests__/sha-cache.test.js +40 -0
  158. package/dist/__tests__/sha-cache.test.js.map +1 -0
  159. package/dist/__tests__/smart-switch.test.d.ts +2 -0
  160. package/dist/__tests__/smart-switch.test.d.ts.map +1 -0
  161. package/dist/__tests__/smart-switch.test.js +145 -0
  162. package/dist/__tests__/smart-switch.test.js.map +1 -0
  163. package/dist/ck.d.ts +3 -0
  164. package/dist/ck.d.ts.map +1 -0
  165. package/dist/ck.js +8 -0
  166. package/dist/ck.js.map +1 -0
  167. package/dist/cli.d.ts +3 -0
  168. package/dist/cli.d.ts.map +1 -0
  169. package/dist/cli.js +132 -0
  170. package/dist/cli.js.map +1 -0
  171. package/dist/commands/diagnose.d.ts +54 -0
  172. package/dist/commands/diagnose.d.ts.map +1 -0
  173. package/dist/commands/diagnose.js +294 -0
  174. package/dist/commands/diagnose.js.map +1 -0
  175. package/dist/commands/impact.d.ts +38 -0
  176. package/dist/commands/impact.d.ts.map +1 -0
  177. package/dist/commands/impact.js +210 -0
  178. package/dist/commands/impact.js.map +1 -0
  179. package/dist/commands/init.d.ts +12 -0
  180. package/dist/commands/init.d.ts.map +1 -0
  181. package/dist/commands/init.js +183 -0
  182. package/dist/commands/init.js.map +1 -0
  183. package/dist/commands/issue.d.ts +25 -0
  184. package/dist/commands/issue.d.ts.map +1 -0
  185. package/dist/commands/issue.js +445 -0
  186. package/dist/commands/issue.js.map +1 -0
  187. package/dist/commands/kickass.d.ts +59 -0
  188. package/dist/commands/kickass.d.ts.map +1 -0
  189. package/dist/commands/kickass.js +288 -0
  190. package/dist/commands/kickass.js.map +1 -0
  191. package/dist/commands/onboard.d.ts +70 -0
  192. package/dist/commands/onboard.d.ts.map +1 -0
  193. package/dist/commands/onboard.js +883 -0
  194. package/dist/commands/onboard.js.map +1 -0
  195. package/dist/commands/optimize.d.ts +16 -0
  196. package/dist/commands/optimize.d.ts.map +1 -0
  197. package/dist/commands/optimize.js +244 -0
  198. package/dist/commands/optimize.js.map +1 -0
  199. package/dist/commands/review.d.ts +2 -0
  200. package/dist/commands/review.d.ts.map +1 -0
  201. package/dist/commands/review.js +118 -0
  202. package/dist/commands/review.js.map +1 -0
  203. package/dist/commands/run.d.ts +13 -0
  204. package/dist/commands/run.d.ts.map +1 -0
  205. package/dist/commands/run.js +243 -0
  206. package/dist/commands/run.js.map +1 -0
  207. package/dist/commands/scan.d.ts +94 -0
  208. package/dist/commands/scan.d.ts.map +1 -0
  209. package/dist/commands/scan.js +276 -0
  210. package/dist/commands/scan.js.map +1 -0
  211. package/dist/commands/serve.d.ts +9 -0
  212. package/dist/commands/serve.d.ts.map +1 -0
  213. package/dist/commands/serve.js +402 -0
  214. package/dist/commands/serve.js.map +1 -0
  215. package/dist/commands/status.d.ts +2 -0
  216. package/dist/commands/status.d.ts.map +1 -0
  217. package/dist/commands/status.js +89 -0
  218. package/dist/commands/status.js.map +1 -0
  219. package/dist/commands/watch.d.ts +9 -0
  220. package/dist/commands/watch.d.ts.map +1 -0
  221. package/dist/commands/watch.js +902 -0
  222. package/dist/commands/watch.js.map +1 -0
  223. package/dist/config/loader.d.ts +47 -0
  224. package/dist/config/loader.d.ts.map +1 -0
  225. package/dist/config/loader.js +334 -0
  226. package/dist/config/loader.js.map +1 -0
  227. package/dist/config/schema.d.ts +814 -0
  228. package/dist/config/schema.d.ts.map +1 -0
  229. package/dist/config/schema.js +152 -0
  230. package/dist/config/schema.js.map +1 -0
  231. package/dist/github/client.d.ts +139 -0
  232. package/dist/github/client.d.ts.map +1 -0
  233. package/dist/github/client.js +711 -0
  234. package/dist/github/client.js.map +1 -0
  235. package/dist/github/detector.d.ts +12 -0
  236. package/dist/github/detector.d.ts.map +1 -0
  237. package/dist/github/detector.js +120 -0
  238. package/dist/github/detector.js.map +1 -0
  239. package/dist/github/merge.d.ts +9 -0
  240. package/dist/github/merge.d.ts.map +1 -0
  241. package/dist/github/merge.js +33 -0
  242. package/dist/github/merge.js.map +1 -0
  243. package/dist/github/review-status.d.ts +6 -0
  244. package/dist/github/review-status.d.ts.map +1 -0
  245. package/dist/github/review-status.js +51 -0
  246. package/dist/github/review-status.js.map +1 -0
  247. package/dist/github/webhook.d.ts +41 -0
  248. package/dist/github/webhook.d.ts.map +1 -0
  249. package/dist/github/webhook.js +50 -0
  250. package/dist/github/webhook.js.map +1 -0
  251. package/dist/lib/annotation.d.ts +23 -0
  252. package/dist/lib/annotation.d.ts.map +1 -0
  253. package/dist/lib/annotation.js +103 -0
  254. package/dist/lib/annotation.js.map +1 -0
  255. package/dist/lib/backtrace.d.ts +40 -0
  256. package/dist/lib/backtrace.d.ts.map +1 -0
  257. package/dist/lib/backtrace.js +169 -0
  258. package/dist/lib/backtrace.js.map +1 -0
  259. package/dist/lib/board.d.ts +74 -0
  260. package/dist/lib/board.d.ts.map +1 -0
  261. package/dist/lib/board.js +640 -0
  262. package/dist/lib/board.js.map +1 -0
  263. package/dist/lib/clone.d.ts +12 -0
  264. package/dist/lib/clone.d.ts.map +1 -0
  265. package/dist/lib/clone.js +30 -0
  266. package/dist/lib/clone.js.map +1 -0
  267. package/dist/lib/comment-bodies.d.ts +17 -0
  268. package/dist/lib/comment-bodies.d.ts.map +1 -0
  269. package/dist/lib/comment-bodies.js +51 -0
  270. package/dist/lib/comment-bodies.js.map +1 -0
  271. package/dist/lib/crosscheck-commit.d.ts +2 -0
  272. package/dist/lib/crosscheck-commit.d.ts.map +1 -0
  273. package/dist/lib/crosscheck-commit.js +4 -0
  274. package/dist/lib/crosscheck-commit.js.map +1 -0
  275. package/dist/lib/diff-hash.d.ts +16 -0
  276. package/dist/lib/diff-hash.d.ts.map +1 -0
  277. package/dist/lib/diff-hash.js +71 -0
  278. package/dist/lib/diff-hash.js.map +1 -0
  279. package/dist/lib/durations.d.ts +5 -0
  280. package/dist/lib/durations.d.ts.map +1 -0
  281. package/dist/lib/durations.js +39 -0
  282. package/dist/lib/durations.js.map +1 -0
  283. package/dist/lib/event-fields.d.ts +6 -0
  284. package/dist/lib/event-fields.d.ts.map +1 -0
  285. package/dist/lib/event-fields.js +20 -0
  286. package/dist/lib/event-fields.js.map +1 -0
  287. package/dist/lib/filter.d.ts +2 -0
  288. package/dist/lib/filter.d.ts.map +1 -0
  289. package/dist/lib/filter.js +4 -0
  290. package/dist/lib/filter.js.map +1 -0
  291. package/dist/lib/fortune.d.ts +2 -0
  292. package/dist/lib/fortune.d.ts.map +1 -0
  293. package/dist/lib/fortune.js +26 -0
  294. package/dist/lib/fortune.js.map +1 -0
  295. package/dist/lib/languages.d.ts +3 -0
  296. package/dist/lib/languages.d.ts.map +1 -0
  297. package/dist/lib/languages.js +26 -0
  298. package/dist/lib/languages.js.map +1 -0
  299. package/dist/lib/log-analysis.d.ts +17 -0
  300. package/dist/lib/log-analysis.d.ts.map +1 -0
  301. package/dist/lib/log-analysis.js +72 -0
  302. package/dist/lib/log-analysis.js.map +1 -0
  303. package/dist/lib/logger.d.ts +14 -0
  304. package/dist/lib/logger.d.ts.map +1 -0
  305. package/dist/lib/logger.js +84 -0
  306. package/dist/lib/logger.js.map +1 -0
  307. package/dist/lib/port.d.ts +2 -0
  308. package/dist/lib/port.d.ts.map +1 -0
  309. package/dist/lib/port.js +21 -0
  310. package/dist/lib/port.js.map +1 -0
  311. package/dist/lib/pr-lock.d.ts +4 -0
  312. package/dist/lib/pr-lock.d.ts.map +1 -0
  313. package/dist/lib/pr-lock.js +91 -0
  314. package/dist/lib/pr-lock.js.map +1 -0
  315. package/dist/lib/pr-picker.d.ts +10 -0
  316. package/dist/lib/pr-picker.d.ts.map +1 -0
  317. package/dist/lib/pr-picker.js +80 -0
  318. package/dist/lib/pr-picker.js.map +1 -0
  319. package/dist/lib/pr-status.d.ts +206 -0
  320. package/dist/lib/pr-status.d.ts.map +1 -0
  321. package/dist/lib/pr-status.js +613 -0
  322. package/dist/lib/pr-status.js.map +1 -0
  323. package/dist/lib/repo-picker.d.ts +23 -0
  324. package/dist/lib/repo-picker.d.ts.map +1 -0
  325. package/dist/lib/repo-picker.js +411 -0
  326. package/dist/lib/repo-picker.js.map +1 -0
  327. package/dist/lib/review-models.d.ts +7 -0
  328. package/dist/lib/review-models.d.ts.map +1 -0
  329. package/dist/lib/review-models.js +32 -0
  330. package/dist/lib/review-models.js.map +1 -0
  331. package/dist/lib/runner.d.ts +65 -0
  332. package/dist/lib/runner.d.ts.map +1 -0
  333. package/dist/lib/runner.js +710 -0
  334. package/dist/lib/runner.js.map +1 -0
  335. package/dist/lib/scan-cache.d.ts +31 -0
  336. package/dist/lib/scan-cache.d.ts.map +1 -0
  337. package/dist/lib/scan-cache.js +112 -0
  338. package/dist/lib/scan-cache.js.map +1 -0
  339. package/dist/lib/scopes.d.ts +16 -0
  340. package/dist/lib/scopes.d.ts.map +1 -0
  341. package/dist/lib/scopes.js +37 -0
  342. package/dist/lib/scopes.js.map +1 -0
  343. package/dist/lib/sha-cache.d.ts +7 -0
  344. package/dist/lib/sha-cache.d.ts.map +1 -0
  345. package/dist/lib/sha-cache.js +44 -0
  346. package/dist/lib/sha-cache.js.map +1 -0
  347. package/dist/lib/smart-switch.d.ts +44 -0
  348. package/dist/lib/smart-switch.d.ts.map +1 -0
  349. package/dist/lib/smart-switch.js +145 -0
  350. package/dist/lib/smart-switch.js.map +1 -0
  351. package/dist/lib/verdict.d.ts +9 -0
  352. package/dist/lib/verdict.d.ts.map +1 -0
  353. package/dist/lib/verdict.js +52 -0
  354. package/dist/lib/verdict.js.map +1 -0
  355. package/dist/lib/workflow.d.ts +85 -0
  356. package/dist/lib/workflow.d.ts.map +1 -0
  357. package/dist/lib/workflow.js +116 -0
  358. package/dist/lib/workflow.js.map +1 -0
  359. package/dist/reviewers/address.d.ts +5 -0
  360. package/dist/reviewers/address.d.ts.map +1 -0
  361. package/dist/reviewers/address.js +87 -0
  362. package/dist/reviewers/address.js.map +1 -0
  363. package/dist/reviewers/claude.d.ts +12 -0
  364. package/dist/reviewers/claude.d.ts.map +1 -0
  365. package/dist/reviewers/claude.js +78 -0
  366. package/dist/reviewers/claude.js.map +1 -0
  367. package/dist/reviewers/codex.d.ts +9 -0
  368. package/dist/reviewers/codex.d.ts.map +1 -0
  369. package/dist/reviewers/codex.js +121 -0
  370. package/dist/reviewers/codex.js.map +1 -0
  371. package/dist/reviewers/conflict-resolve.d.ts +15 -0
  372. package/dist/reviewers/conflict-resolve.d.ts.map +1 -0
  373. package/dist/reviewers/conflict-resolve.js +219 -0
  374. package/dist/reviewers/conflict-resolve.js.map +1 -0
  375. package/dist/reviewers/fix.d.ts +7 -0
  376. package/dist/reviewers/fix.d.ts.map +1 -0
  377. package/dist/reviewers/fix.js +197 -0
  378. package/dist/reviewers/fix.js.map +1 -0
  379. package/get-started.md +1271 -0
  380. package/get-started.zh.md +1208 -0
  381. package/package.json +75 -0
@@ -0,0 +1,126 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { execSync } from 'child_process';
3
+ import { mkdtempSync, rmSync, writeFileSync, readFileSync, existsSync } from 'fs';
4
+ import { tmpdir } from 'os';
5
+ import { join } from 'path';
6
+ import { computeDiffHash, PersistentDiffHashMap } from '../lib/diff-hash.js';
7
+ function git(args, cwd) {
8
+ return execSync(`git ${args}`, { cwd, stdio: ['ignore', 'pipe', 'pipe'], encoding: 'utf8' });
9
+ }
10
+ function setupRepo() {
11
+ const dir = mkdtempSync(join(tmpdir(), 'crosscheck-diff-test-'));
12
+ git('init --quiet -b main', dir);
13
+ git('config user.email test@test.local', dir);
14
+ git('config user.name Test', dir);
15
+ writeFileSync(join(dir, 'file.txt'), 'base content\n');
16
+ git('add .', dir);
17
+ git('commit --quiet -m base', dir);
18
+ // Create the "origin/main" remote-tracking ref that computeDiffHash expects
19
+ git('update-ref refs/remotes/origin/main HEAD', dir);
20
+ return { dir, baseRef: 'main' };
21
+ }
22
+ describe('computeDiffHash', () => {
23
+ let dir;
24
+ let baseRef;
25
+ beforeEach(() => {
26
+ ;
27
+ ({ dir, baseRef } = setupRepo());
28
+ });
29
+ afterEach(() => {
30
+ rmSync(dir, { recursive: true, force: true });
31
+ });
32
+ it('returns a stable hex digest for a given patch', () => {
33
+ writeFileSync(join(dir, 'file.txt'), 'modified content\n');
34
+ git('commit --quiet -am edit', dir);
35
+ const h1 = computeDiffHash(dir, baseRef);
36
+ const h2 = computeDiffHash(dir, baseRef);
37
+ expect(h1).toBe(h2);
38
+ expect(h1).toMatch(/^[0-9a-f]{64}$/);
39
+ });
40
+ it('returns identical hash when an amend produces the same patch under a new SHA', () => {
41
+ writeFileSync(join(dir, 'file.txt'), 'modified content\n');
42
+ git('commit --quiet -am edit', dir);
43
+ const shaBefore = git('rev-parse HEAD', dir).trim();
44
+ const hashBefore = computeDiffHash(dir, baseRef);
45
+ // Amend the commit message only — same tree, new SHA
46
+ git('commit --quiet --amend -m "edit (reworded)"', dir);
47
+ const shaAfter = git('rev-parse HEAD', dir).trim();
48
+ const hashAfter = computeDiffHash(dir, baseRef);
49
+ expect(shaAfter).not.toBe(shaBefore);
50
+ expect(hashAfter).toBe(hashBefore);
51
+ });
52
+ it('returns different hash when the diff content changes', () => {
53
+ writeFileSync(join(dir, 'file.txt'), 'first change\n');
54
+ git('commit --quiet -am one', dir);
55
+ const h1 = computeDiffHash(dir, baseRef);
56
+ writeFileSync(join(dir, 'file.txt'), 'second change\n');
57
+ git('commit --quiet -am two', dir);
58
+ const h2 = computeDiffHash(dir, baseRef);
59
+ expect(h1).not.toBe(h2);
60
+ });
61
+ it('returns the empty-diff hash when HEAD equals base', () => {
62
+ const h = computeDiffHash(dir, baseRef);
63
+ expect(h).toMatch(/^[0-9a-f]{64}$/);
64
+ // Hash of empty string sha256 — stable sentinel
65
+ expect(h).toBe('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855');
66
+ });
67
+ });
68
+ describe('PersistentDiffHashMap', () => {
69
+ let cacheFile;
70
+ beforeEach(() => {
71
+ cacheFile = join(mkdtempSync(join(tmpdir(), 'crosscheck-dhm-')), 'diff-hashes.json');
72
+ });
73
+ afterEach(() => {
74
+ if (existsSync(cacheFile))
75
+ rmSync(cacheFile);
76
+ });
77
+ it('upserts and reads back an entry', () => {
78
+ const m = new PersistentDiffHashMap(cacheFile);
79
+ m.upsert('owner/repo#1', { sha: 'abc123', hash: 'h1' });
80
+ expect(m.get('owner/repo#1')).toEqual({ sha: 'abc123', hash: 'h1' });
81
+ });
82
+ it('overwrites an existing entry for the same key', () => {
83
+ const m = new PersistentDiffHashMap(cacheFile);
84
+ m.upsert('owner/repo#1', { sha: 'abc', hash: 'h1' });
85
+ m.upsert('owner/repo#1', { sha: 'def', hash: 'h2' });
86
+ expect(m.get('owner/repo#1')).toEqual({ sha: 'def', hash: 'h2' });
87
+ });
88
+ it('persists across instances backed by the same file', () => {
89
+ const a = new PersistentDiffHashMap(cacheFile);
90
+ a.upsert('owner/repo#42', { sha: 'aaa', hash: 'hash-x' });
91
+ const b = new PersistentDiffHashMap(cacheFile);
92
+ expect(b.get('owner/repo#42')).toEqual({ sha: 'aaa', hash: 'hash-x' });
93
+ });
94
+ it('returns undefined for missing keys', () => {
95
+ const m = new PersistentDiffHashMap(cacheFile);
96
+ expect(m.get('nope')).toBeUndefined();
97
+ });
98
+ it('evicts oldest entries when exceeding the cap (FIFO)', () => {
99
+ const m = new PersistentDiffHashMap(cacheFile, /*maxEntries*/ 3);
100
+ m.upsert('a', { sha: '1', hash: 'h1' });
101
+ m.upsert('b', { sha: '2', hash: 'h2' });
102
+ m.upsert('c', { sha: '3', hash: 'h3' });
103
+ m.upsert('d', { sha: '4', hash: 'h4' }); // evicts 'a'
104
+ expect(m.get('a')).toBeUndefined();
105
+ expect(m.get('b')).toEqual({ sha: '2', hash: 'h2' });
106
+ expect(m.get('d')).toEqual({ sha: '4', hash: 'h4' });
107
+ });
108
+ it('upsert that overwrites does not count toward the cap', () => {
109
+ const m = new PersistentDiffHashMap(cacheFile, 2);
110
+ m.upsert('a', { sha: '1', hash: 'h1' });
111
+ m.upsert('b', { sha: '2', hash: 'h2' });
112
+ m.upsert('a', { sha: '1b', hash: 'h1b' }); // overwrite, not insert
113
+ expect(m.get('a')).toEqual({ sha: '1b', hash: 'h1b' });
114
+ expect(m.get('b')).toEqual({ sha: '2', hash: 'h2' });
115
+ });
116
+ it('tolerates a missing or malformed cache file', () => {
117
+ writeFileSync(cacheFile, 'not json');
118
+ const m = new PersistentDiffHashMap(cacheFile);
119
+ expect(m.get('any')).toBeUndefined();
120
+ m.upsert('x', { sha: '9', hash: 'h9' });
121
+ // Should have rewritten the file to valid JSON
122
+ const parsed = JSON.parse(readFileSync(cacheFile, 'utf8'));
123
+ expect(parsed['x']).toEqual({ sha: '9', hash: 'h9' });
124
+ });
125
+ });
126
+ //# sourceMappingURL=diff-hash.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-hash.test.js","sourceRoot":"","sources":["../../src/__tests__/diff-hash.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,IAAI,CAAA;AACjF,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAA;AAC3B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAE5E,SAAS,GAAG,CAAC,IAAY,EAAE,GAAW;IACpC,OAAO,QAAQ,CAAC,OAAO,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAA;AAC9F,CAAC;AAED,SAAS,SAAS;IAChB,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,uBAAuB,CAAC,CAAC,CAAA;IAChE,GAAG,CAAC,sBAAsB,EAAE,GAAG,CAAC,CAAA;IAChC,GAAG,CAAC,mCAAmC,EAAE,GAAG,CAAC,CAAA;IAC7C,GAAG,CAAC,uBAAuB,EAAE,GAAG,CAAC,CAAA;IACjC,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,gBAAgB,CAAC,CAAA;IACtD,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;IACjB,GAAG,CAAC,wBAAwB,EAAE,GAAG,CAAC,CAAA;IAClC,4EAA4E;IAC5E,GAAG,CAAC,0CAA0C,EAAE,GAAG,CAAC,CAAA;IACpD,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAA;AACjC,CAAC;AAED,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,IAAI,GAAW,CAAA;IACf,IAAI,OAAe,CAAA;IAEnB,UAAU,CAAC,GAAG,EAAE;QACd,CAAC;QAAA,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,SAAS,EAAE,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IAC/C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,oBAAoB,CAAC,CAAA;QAC1D,GAAG,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAA;QACnC,MAAM,EAAE,GAAG,eAAe,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;QACxC,MAAM,EAAE,GAAG,eAAe,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;QACxC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACnB,MAAM,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAA;IACtC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8EAA8E,EAAE,GAAG,EAAE;QACtF,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,oBAAoB,CAAC,CAAA;QAC1D,GAAG,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAA;QACnC,MAAM,SAAS,GAAG,GAAG,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAA;QACnD,MAAM,UAAU,GAAG,eAAe,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;QAEhD,qDAAqD;QACrD,GAAG,CAAC,6CAA6C,EAAE,GAAG,CAAC,CAAA;QACvD,MAAM,QAAQ,GAAG,GAAG,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAA;QAClD,MAAM,SAAS,GAAG,eAAe,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;QAE/C,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACpC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IACpC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,gBAAgB,CAAC,CAAA;QACtD,GAAG,CAAC,wBAAwB,EAAE,GAAG,CAAC,CAAA;QAClC,MAAM,EAAE,GAAG,eAAe,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;QACxC,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,iBAAiB,CAAC,CAAA;QACvD,GAAG,CAAC,wBAAwB,EAAE,GAAG,CAAC,CAAA;QAClC,MAAM,EAAE,GAAG,eAAe,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;QACxC,MAAM,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACzB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,CAAC,GAAG,eAAe,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;QACvC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAA;QACnC,gDAAgD;QAChD,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,kEAAkE,CAAC,CAAA;IACpF,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,IAAI,SAAiB,CAAA;IAErB,UAAU,CAAC,GAAG,EAAE;QACd,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,iBAAiB,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAA;IACtF,CAAC,CAAC,CAAA;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,MAAM,CAAC,SAAS,CAAC,CAAA;IAC9C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,GAAG,IAAI,qBAAqB,CAAC,SAAS,CAAC,CAAA;QAC9C,CAAC,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;QACvD,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IACtE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,CAAC,GAAG,IAAI,qBAAqB,CAAC,SAAS,CAAC,CAAA;QAC9C,CAAC,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;QACpD,CAAC,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;QACpD,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IACnE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,CAAC,GAAG,IAAI,qBAAqB,CAAC,SAAS,CAAC,CAAA;QAC9C,CAAC,CAAC,MAAM,CAAC,eAAe,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAA;QACzD,MAAM,CAAC,GAAG,IAAI,qBAAqB,CAAC,SAAS,CAAC,CAAA;QAC9C,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAA;IACxE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,CAAC,GAAG,IAAI,qBAAqB,CAAC,SAAS,CAAC,CAAA;QAC9C,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,EAAE,CAAA;IACvC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,CAAC,GAAG,IAAI,qBAAqB,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC,CAAC,CAAA;QAChE,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;QACvC,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;QACvC,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;QACvC,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA,CAAE,aAAa;QACtD,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,aAAa,EAAE,CAAA;QAClC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;QACpD,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IACtD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,CAAC,GAAG,IAAI,qBAAqB,CAAC,SAAS,EAAE,CAAC,CAAC,CAAA;QACjD,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;QACvC,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;QACvC,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA,CAAE,wBAAwB;QACnE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;QACtD,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IACtD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,aAAa,CAAC,SAAS,EAAE,UAAU,CAAC,CAAA;QACpC,MAAM,CAAC,GAAG,IAAI,qBAAqB,CAAC,SAAS,CAAC,CAAA;QAC9C,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,EAAE,CAAA;QACpC,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;QACvC,+CAA+C;QAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAA4B,CAAA;QACrF,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IACvD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=durations.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"durations.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/durations.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,26 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { formatDuration, parseDuration } from '../lib/durations.js';
3
+ describe('parseDuration', () => {
4
+ it('parses minutes, hours, and days', () => {
5
+ expect(parseDuration('30m')).toBe(30 * 60 * 1000);
6
+ expect(parseDuration('2h')).toBe(2 * 60 * 60 * 1000);
7
+ expect(parseDuration('1d')).toBe(24 * 60 * 60 * 1000);
8
+ });
9
+ it('accepts surrounding whitespace', () => {
10
+ expect(parseDuration(' 4h ')).toBe(4 * 60 * 60 * 1000);
11
+ });
12
+ it('rejects invalid durations', () => {
13
+ expect(() => parseDuration('')).toThrow('Invalid duration');
14
+ expect(() => parseDuration('10')).toThrow('Invalid duration');
15
+ expect(() => parseDuration('1w')).toThrow('Invalid duration');
16
+ expect(() => parseDuration('0m')).toThrow('Invalid duration');
17
+ });
18
+ });
19
+ describe('formatDuration', () => {
20
+ it('formats common whole units', () => {
21
+ expect(formatDuration(30 * 60 * 1000)).toBe('30m');
22
+ expect(formatDuration(2 * 60 * 60 * 1000)).toBe('2h');
23
+ expect(formatDuration(24 * 60 * 60 * 1000)).toBe('1d');
24
+ });
25
+ });
26
+ //# sourceMappingURL=durations.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"durations.test.js","sourceRoot":"","sources":["../../src/__tests__/durations.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAEnE,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;QACjD,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;QACpD,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;IACvD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAA;IAC1D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;QAC3D,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;QAC7D,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;QAC7D,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;IAC/D,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAClD,MAAM,CAAC,cAAc,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACrD,MAAM,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACxD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=event-fields.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-fields.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/event-fields.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,50 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { buildStepIdentityFields } from '../lib/event-fields.js';
3
+ describe('buildStepIdentityFields', () => {
4
+ // Effective type 'review' means this call is actually a fresh review,
5
+ // regardless of what the workflow step is named. The default workflow
6
+ // calls the initial step "review" but a user could rename it.
7
+ it('returns step_type=review when effectiveType is review', () => {
8
+ expect(buildStepIdentityFields('review', 'review')).toEqual({
9
+ step_type: 'review',
10
+ step_name: 'review',
11
+ });
12
+ });
13
+ it('preserves a custom step_name unchanged', () => {
14
+ expect(buildStepIdentityFields('review', 'initial-codex-pass')).toEqual({
15
+ step_type: 'review',
16
+ step_name: 'initial-codex-pass',
17
+ });
18
+ });
19
+ // Effective type 'recheck' is the case the field exists to disambiguate:
20
+ // today this is logged identically to a fresh review.
21
+ it('returns step_type=recheck when effectiveType is recheck', () => {
22
+ expect(buildStepIdentityFields('recheck', 'recheck')).toEqual({
23
+ step_type: 'recheck',
24
+ step_name: 'recheck',
25
+ });
26
+ });
27
+ // Coerced rechecks: runner.ts's getEffectiveStepType maps the workflow
28
+ // step typed 'review' to effectiveType 'recheck' when ctx.isRecheckRun.
29
+ // The step_name still reflects what's in workflow.yml (so analytics can
30
+ // group by workflow step), but step_type reflects what actually ran.
31
+ it('returns step_type=recheck even when the underlying workflow step is named "review"', () => {
32
+ expect(buildStepIdentityFields('recheck', 'review')).toEqual({
33
+ step_type: 'recheck',
34
+ step_name: 'review',
35
+ });
36
+ });
37
+ // Defensive: any other effectiveType value (shouldn't happen for the
38
+ // review_complete emit site, but the helper must not produce undefined).
39
+ it('falls back to step_type=review for any non-recheck effectiveType', () => {
40
+ expect(buildStepIdentityFields('fix', 'whatever')).toEqual({
41
+ step_type: 'review',
42
+ step_name: 'whatever',
43
+ });
44
+ expect(buildStepIdentityFields('', 'whatever')).toEqual({
45
+ step_type: 'review',
46
+ step_name: 'whatever',
47
+ });
48
+ });
49
+ });
50
+ //# sourceMappingURL=event-fields.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-fields.test.js","sourceRoot":"","sources":["../../src/__tests__/event-fields.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAA;AAEhE,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,sEAAsE;IACtE,sEAAsE;IACtE,8DAA8D;IAC9D,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,CAAC,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;YAC1D,SAAS,EAAE,QAAQ;YACnB,SAAS,EAAE,QAAQ;SACpB,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,CAAC,uBAAuB,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC,CAAC,OAAO,CAAC;YACtE,SAAS,EAAE,QAAQ;YACnB,SAAS,EAAE,oBAAoB;SAChC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,yEAAyE;IACzE,sDAAsD;IACtD,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,CAAC,uBAAuB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;YAC5D,SAAS,EAAE,SAAS;YACpB,SAAS,EAAE,SAAS;SACrB,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,uEAAuE;IACvE,wEAAwE;IACxE,wEAAwE;IACxE,qEAAqE;IACrE,EAAE,CAAC,oFAAoF,EAAE,GAAG,EAAE;QAC5F,MAAM,CAAC,uBAAuB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;YAC3D,SAAS,EAAE,SAAS;YACpB,SAAS,EAAE,QAAQ;SACpB,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,qEAAqE;IACrE,yEAAyE;IACzE,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,CAAC,uBAAuB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC;YACzD,SAAS,EAAE,QAAQ;YACnB,SAAS,EAAE,UAAU;SACtB,CAAC,CAAA;QACF,MAAM,CAAC,uBAAuB,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC;YACtD,SAAS,EAAE,QAAQ;YACnB,SAAS,EAAE,UAAU;SACtB,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=filter.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/filter.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { isAuthorAllowed } from '../lib/filter.js';
3
+ describe('isAuthorAllowed', () => {
4
+ it('allows any author when list is empty', () => {
5
+ expect(isAuthorAllowed([], 'alice')).toBe(true);
6
+ expect(isAuthorAllowed([], 'anyone')).toBe(true);
7
+ });
8
+ it('allows a listed author', () => {
9
+ expect(isAuthorAllowed(['alice', 'bob'], 'alice')).toBe(true);
10
+ expect(isAuthorAllowed(['alice', 'bob'], 'bob')).toBe(true);
11
+ });
12
+ it('blocks an unlisted author', () => {
13
+ expect(isAuthorAllowed(['alice'], 'bob')).toBe(false);
14
+ expect(isAuthorAllowed(['alice', 'bob'], 'carol')).toBe(false);
15
+ });
16
+ it('is case-sensitive', () => {
17
+ expect(isAuthorAllowed(['Alice'], 'alice')).toBe(false);
18
+ expect(isAuthorAllowed(['alice'], 'Alice')).toBe(false);
19
+ });
20
+ });
21
+ //# sourceMappingURL=filter.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter.test.js","sourceRoot":"","sources":["../../src/__tests__/filter.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAElD,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,eAAe,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC/C,MAAM,CAAC,eAAe,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAClD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC7D,MAAM,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC7D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACrD,MAAM,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAChE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;QAC3B,MAAM,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACvD,MAAM,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACzD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=fix.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fix.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/fix.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,124 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { mkdirSync, mkdtempSync, writeFileSync, readFileSync, rmSync } from 'fs';
3
+ import { tmpdir } from 'os';
4
+ import { join } from 'path';
5
+ import { applyEdit } from '../reviewers/fix.js';
6
+ describe('applyEdit', () => {
7
+ it('replaces exact match at start of file', () => {
8
+ const content = 'function foo() {\n return 1\n}\n';
9
+ const result = applyEdit(content, 'return 1', 'return 2');
10
+ expect(result).toBe('function foo() {\n return 2\n}\n');
11
+ });
12
+ it('returns null when old text is not found', () => {
13
+ const content = 'function foo() {\n return 1\n}\n';
14
+ expect(applyEdit(content, 'return 99', 'return 2')).toBeNull();
15
+ });
16
+ it('returns null when old text is ambiguous (appears more than once)', () => {
17
+ const content = 'a\na\na\n';
18
+ expect(applyEdit(content, 'a', 'b')).toBeNull();
19
+ });
20
+ it('handles multi-line old text', () => {
21
+ const content = 'line1\nline2\nline3\nline4\n';
22
+ const result = applyEdit(content, 'line2\nline3', 'replaced');
23
+ expect(result).toBe('line1\nreplaced\nline4\n');
24
+ });
25
+ it('can replace with empty string (deletion)', () => {
26
+ const content = 'before\ndelete me\nafter\n';
27
+ const result = applyEdit(content, 'delete me\n', '');
28
+ expect(result).toBe('before\nafter\n');
29
+ });
30
+ it('returns null on empty old text (ambiguous — matches everywhere)', () => {
31
+ // '' satisfies indexOf !== lastIndexOf, so the ambiguity guard rejects it.
32
+ // Callers handle new-file creation separately before invoking applyEdit.
33
+ expect(applyEdit('content', '', 'new')).toBeNull();
34
+ });
35
+ });
36
+ describe('fix step <edit> block parsing', () => {
37
+ let tmpDir;
38
+ beforeEach(() => {
39
+ tmpDir = mkdtempSync(join(tmpdir(), 'crosscheck-fix-test-'));
40
+ });
41
+ afterEach(() => {
42
+ rmSync(tmpDir, { force: true, recursive: true });
43
+ });
44
+ it('size guard: rejects <file> block when new content < 60% of original', async () => {
45
+ // Write a "large" original file (10 lines)
46
+ const filePath = join(tmpDir, 'src', 'large.ts');
47
+ const { mkdirSync } = await import('fs');
48
+ mkdirSync(join(tmpDir, 'src'), { recursive: true });
49
+ const original = Array.from({ length: 10 }, (_, i) => `line${i + 1}`).join('\n') + '\n';
50
+ writeFileSync(filePath, original);
51
+ // Simulate Claude outputting only 3 lines for a 10-line file (30% — below 60% threshold)
52
+ const truncated = 'line1\nline2\nline3\n';
53
+ // Directly test the guard logic: if newLines / origLines < 0.6, skip
54
+ const origLines = original.split('\n').length;
55
+ const newLines = truncated.split('\n').length;
56
+ expect(newLines / origLines).toBeLessThan(0.6);
57
+ // Confirm original is unchanged (guard would have skipped the write)
58
+ expect(readFileSync(filePath, 'utf8')).toBe(original);
59
+ });
60
+ it('size guard: accepts <file> block when new content >= 60% of original', () => {
61
+ const original = Array.from({ length: 10 }, (_, i) => `line${i + 1}`).join('\n') + '\n';
62
+ const replacement = Array.from({ length: 7 }, (_, i) => `replaced${i + 1}`).join('\n') + '\n';
63
+ const origLines = original.split('\n').length;
64
+ const newLines = replacement.split('\n').length;
65
+ expect(newLines / origLines).toBeGreaterThanOrEqual(0.6);
66
+ });
67
+ it('applyEdit composes correctly for multiple edits to same file', () => {
68
+ const content = 'a: 1\nb: 2\nc: 3\n';
69
+ const after1 = applyEdit(content, 'a: 1', 'a: 10');
70
+ expect(after1).not.toBeNull();
71
+ const after2 = applyEdit(after1, 'b: 2', 'b: 20');
72
+ expect(after2).not.toBeNull();
73
+ expect(after2).toBe('a: 10\nb: 20\nc: 3\n');
74
+ });
75
+ it('failed <old> match does not count as applied or write the unchanged file', () => {
76
+ // Regression for: file added to fileEdits during read step, then applyEdit returns null,
77
+ // but write loop still writes it and increments appliedCount.
78
+ const filePath = join(tmpDir, 'src.ts');
79
+ const original = 'export function foo() {\n return 1\n}\n';
80
+ writeFileSync(filePath, original);
81
+ // applyEdit with a non-matching old text returns null — file must not be touched
82
+ const result = applyEdit(original, 'does not exist in file', 'anything');
83
+ expect(result).toBeNull();
84
+ // File must be untouched on disk
85
+ expect(readFileSync(filePath, 'utf8')).toBe(original);
86
+ });
87
+ it('applyEdit: empty old text returns null (ambiguity guard catches it)', () => {
88
+ // Empty string satisfies indexOf('') !== lastIndexOf(''), so applyEdit rejects it.
89
+ // runFixStep handles new-file creation (empty <old> on missing file) before calling applyEdit.
90
+ expect(applyEdit('existing content', '', 'prepended ')).toBeNull();
91
+ });
92
+ });
93
+ describe('fix step new-file and empty-old guard', () => {
94
+ let tmpDir;
95
+ beforeEach(() => {
96
+ tmpDir = mkdtempSync(join(tmpdir(), 'crosscheck-fix-test-'));
97
+ });
98
+ afterEach(() => {
99
+ rmSync(tmpDir, { force: true, recursive: true });
100
+ });
101
+ it('empty <old> on existing file is rejected — does not prepend new text', () => {
102
+ mkdirSync(join(tmpDir, 'src'), { recursive: true });
103
+ const filePath = join(tmpDir, 'src', 'util.ts');
104
+ const original = 'export const x = 1\n';
105
+ writeFileSync(filePath, original);
106
+ // applyEdit('export const x = 1\n', '', 'prepended\n') would prepend if not guarded.
107
+ // The guard in runFixStep must block this — original must be unchanged.
108
+ // We verify the guard logic directly: empty oldText on existing file => skip.
109
+ const oldText = '';
110
+ const fileExists = true; // file was readable
111
+ const wouldBeGuarded = fileExists && oldText === '';
112
+ expect(wouldBeGuarded).toBe(true);
113
+ expect(readFileSync(filePath, 'utf8')).toBe(original);
114
+ });
115
+ it('empty <old> on non-existent file writes <new> as new file content', () => {
116
+ mkdirSync(join(tmpDir, 'src'), { recursive: true });
117
+ const newFilePath = join(tmpDir, 'src', 'new-module.ts');
118
+ // File does not exist — simulate the new-file path: write newText directly
119
+ const newContent = 'export const added = true\n';
120
+ writeFileSync(newFilePath, newContent); // as runFixStep would do for empty <old>
121
+ expect(readFileSync(newFilePath, 'utf8')).toBe(newContent);
122
+ });
123
+ });
124
+ //# sourceMappingURL=fix.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fix.test.js","sourceRoot":"","sources":["../../src/__tests__/fix.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=github-client.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-client.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/github-client.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,22 @@
1
+ import { afterEach, describe, expect, it, vi } from 'vitest';
2
+ import { listOpenPRs, listOrgRepos } from '../github/client.js';
3
+ afterEach(() => {
4
+ vi.unstubAllGlobals();
5
+ });
6
+ describe('github client listing failures', () => {
7
+ it('throws when listOpenPRs receives a non-OK response', async () => {
8
+ vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(JSON.stringify({ message: 'server error' }), {
9
+ status: 500,
10
+ statusText: 'Internal Server Error',
11
+ })));
12
+ await expect(listOpenPRs('acme', 'api', 'token')).rejects.toThrow('Failed to list open PRs for acme/api page 1 [500]: server error');
13
+ });
14
+ it('throws when listOrgRepos receives a non-OK response', async () => {
15
+ vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(JSON.stringify({ message: 'rate limited' }), {
16
+ status: 403,
17
+ statusText: 'Forbidden',
18
+ })));
19
+ await expect(listOrgRepos('acme', 'token')).rejects.toThrow('Failed to list org repos [403]: Forbidden');
20
+ });
21
+ });
22
+ //# sourceMappingURL=github-client.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-client.test.js","sourceRoot":"","sources":["../../src/__tests__/github-client.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAC5D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAE/D,SAAS,CAAC,GAAG,EAAE;IACb,EAAE,CAAC,gBAAgB,EAAE,CAAA;AACvB,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAC9C,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAC9C,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,EAAE;YACxD,MAAM,EAAE,GAAG;YACX,UAAU,EAAE,uBAAuB;SACpC,CAAC,CACH,CAAC,CAAA;QAEF,MAAM,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAC/D,iEAAiE,CAClE,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAC9C,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,EAAE;YACxD,MAAM,EAAE,GAAG;YACX,UAAU,EAAE,WAAW;SACxB,CAAC,CACH,CAAC,CAAA;QAEF,MAAM,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CACzD,2CAA2C,CAC5C,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=github-scan-client.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-scan-client.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/github-scan-client.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,100 @@
1
+ import { afterEach, describe, expect, it, vi } from 'vitest';
2
+ import { getLastCrossCheckReviewComment, listCheckRuns, listCommitStatuses, listIssueComments, listOpenPRs, listOrgRepos, listTimelineEvents, listUserRepos } from '../github/client.js';
3
+ afterEach(() => {
4
+ vi.restoreAllMocks();
5
+ });
6
+ function jsonResponse(body, status = 200) {
7
+ return new Response(JSON.stringify(body), {
8
+ status,
9
+ headers: { 'content-type': 'application/json' },
10
+ });
11
+ }
12
+ describe('scan GitHub client helpers', () => {
13
+ it('paginates check runs for a commit ref', async () => {
14
+ const firstPage = Array.from({ length: 100 }, (_, index) => ({
15
+ name: `check-${index}`,
16
+ status: 'completed',
17
+ conclusion: 'success',
18
+ completed_at: '2026-05-29T00:00:00.000Z',
19
+ started_at: null,
20
+ }));
21
+ const fetchSpy = vi.spyOn(globalThis, 'fetch')
22
+ .mockResolvedValueOnce(jsonResponse({ check_runs: firstPage }))
23
+ .mockResolvedValueOnce(jsonResponse({
24
+ check_runs: [{
25
+ name: 'check-100',
26
+ status: 'completed',
27
+ conclusion: 'success',
28
+ completed_at: '2026-05-29T00:01:00.000Z',
29
+ started_at: null,
30
+ }],
31
+ }));
32
+ const runs = await listCheckRuns('acme', 'web', 'abc123', 'token');
33
+ expect(runs).toHaveLength(101);
34
+ expect(fetchSpy).toHaveBeenCalledTimes(2);
35
+ expect(String(fetchSpy.mock.calls[1][0])).toContain('page=2');
36
+ });
37
+ it('paginates commit statuses for a commit ref', async () => {
38
+ const firstPage = Array.from({ length: 100 }, (_, index) => ({
39
+ context: `ci-${index}`,
40
+ state: 'success',
41
+ updated_at: '2026-05-29T00:00:00.000Z',
42
+ }));
43
+ const fetchSpy = vi.spyOn(globalThis, 'fetch')
44
+ .mockResolvedValueOnce(jsonResponse(firstPage))
45
+ .mockResolvedValueOnce(jsonResponse([{
46
+ context: 'ci-100',
47
+ state: 'pending',
48
+ updated_at: '2026-05-29T00:01:00.000Z',
49
+ }]));
50
+ const statuses = await listCommitStatuses('acme', 'web', 'abc123', 'token');
51
+ expect(statuses).toHaveLength(101);
52
+ expect(fetchSpy).toHaveBeenCalledTimes(2);
53
+ expect(String(fetchSpy.mock.calls[0][0])).toContain('/statuses?per_page=100&page=1');
54
+ });
55
+ it('throws for non-404 issue comment failures', async () => {
56
+ vi.spyOn(globalThis, 'fetch').mockResolvedValueOnce(jsonResponse({ message: 'rate limited' }, 429));
57
+ await expect(listIssueComments('acme', 'web', 7, 'token'))
58
+ .rejects.toThrow('GitHub API request failed');
59
+ });
60
+ it('treats missing issue comments as empty activity', async () => {
61
+ vi.spyOn(globalThis, 'fetch').mockResolvedValueOnce(jsonResponse({ message: 'not found' }, 404));
62
+ await expect(listIssueComments('acme', 'web', 7, 'token')).resolves.toEqual([]);
63
+ });
64
+ it('throws for non-404 open PR list failures', async () => {
65
+ vi.spyOn(globalThis, 'fetch').mockResolvedValueOnce(jsonResponse({ message: 'rate limited' }, 429));
66
+ await expect(listOpenPRs('acme', 'web', 'token'))
67
+ .rejects.toThrow('Failed to list open PRs for acme/web page 1 [429]: rate limited');
68
+ });
69
+ it('throws for non-404 repo scope list failures', async () => {
70
+ vi.spyOn(globalThis, 'fetch')
71
+ .mockResolvedValueOnce(jsonResponse({ message: 'forbidden' }, 403))
72
+ .mockResolvedValueOnce(jsonResponse({ message: 'forbidden' }, 403));
73
+ await expect(listOrgRepos('acme', 'token')).rejects.toThrow('GitHub API request failed');
74
+ await expect(listUserRepos('alice', 'token')).rejects.toThrow('GitHub API request failed');
75
+ });
76
+ it('treats missing open PR lists as empty scope', async () => {
77
+ vi.spyOn(globalThis, 'fetch').mockResolvedValueOnce(jsonResponse({ message: 'not found' }, 404));
78
+ await expect(listOpenPRs('acme', 'web', 'token')).resolves.toEqual([]);
79
+ });
80
+ it('uses the standard GitHub JSON media type for timeline events', async () => {
81
+ const fetchSpy = vi.spyOn(globalThis, 'fetch')
82
+ .mockResolvedValueOnce(jsonResponse([{ event: 'ready_for_review', created_at: '2026-05-29T00:00:00.000Z' }]));
83
+ await listTimelineEvents('acme', 'web', 7, 'token');
84
+ expect(fetchSpy.mock.calls[0]?.[1]).toEqual(expect.objectContaining({
85
+ headers: expect.objectContaining({ Accept: 'application/vnd.github+json' }),
86
+ }));
87
+ });
88
+ it('returns the latest fresh crosscheck review comment body and id', async () => {
89
+ vi.spyOn(globalThis, 'fetch').mockResolvedValueOnce(jsonResponse([
90
+ { id: 1, body: '<!-- crosscheck: origin=claude reviewer=codex verdict=BLOCK type=review -->' },
91
+ { id: 2, body: '<!-- crosscheck: fix_applied -->' },
92
+ { id: 3, body: '<!-- crosscheck: origin=claude reviewer=codex verdict=NEEDS_WORK type=review -->' },
93
+ ]));
94
+ await expect(getLastCrossCheckReviewComment('acme', 'web', 7, 'token')).resolves.toEqual({
95
+ id: 3,
96
+ body: '<!-- crosscheck: origin=claude reviewer=codex verdict=NEEDS_WORK type=review -->',
97
+ });
98
+ });
99
+ });
100
+ //# sourceMappingURL=github-scan-client.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-scan-client.test.js","sourceRoot":"","sources":["../../src/__tests__/github-scan-client.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=is-fresh-review-comment.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-fresh-review-comment.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/is-fresh-review-comment.test.ts"],"names":[],"mappings":""}