limn-review 0.1.123

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 (474) hide show
  1. package/LICENSE +110 -0
  2. package/README.md +133 -0
  3. package/dist/ai/runtime.js +535 -0
  4. package/dist/api/plugins/auth.js +169 -0
  5. package/dist/api/plugins/error-handler.js +114 -0
  6. package/dist/api/plugins/rate-limit.js +855 -0
  7. package/dist/api/plugins/security.js +321 -0
  8. package/dist/api/routes/activity.js +103 -0
  9. package/dist/api/routes/ai-runtime.js +67 -0
  10. package/dist/api/routes/auth.js +194 -0
  11. package/dist/api/routes/billing.js +209 -0
  12. package/dist/api/routes/bot-triage.js +1289 -0
  13. package/dist/api/routes/conflicts.js +730 -0
  14. package/dist/api/routes/contact.js +318 -0
  15. package/dist/api/routes/daily-brief.js +58 -0
  16. package/dist/api/routes/flow.js +71 -0
  17. package/dist/api/routes/health.js +7 -0
  18. package/dist/api/routes/insights.js +200 -0
  19. package/dist/api/routes/me.js +458 -0
  20. package/dist/api/routes/mentions.js +22 -0
  21. package/dist/api/routes/mergers.js +8 -0
  22. package/dist/api/routes/ml-labels.js +109 -0
  23. package/dist/api/routes/open-prs.js +35 -0
  24. package/dist/api/routes/prs.js +1633 -0
  25. package/dist/api/routes/reactions.js +217 -0
  26. package/dist/api/routes/repos.js +563 -0
  27. package/dist/api/routes/search.js +41 -0
  28. package/dist/api/routes/threads.js +118 -0
  29. package/dist/api/routes/timeline.js +150 -0
  30. package/dist/api/routes/users.js +67 -0
  31. package/dist/api/routes/webhooks.js +181 -0
  32. package/dist/api/routes/workspaces.js +322 -0
  33. package/dist/app.js +274 -0
  34. package/dist/ascii.js +19 -0
  35. package/dist/auth/account.js +482 -0
  36. package/dist/auth/crypto.js +46 -0
  37. package/dist/bot-triage/resolve.js +59 -0
  38. package/dist/cli.js +388 -0
  39. package/dist/coding/activity.js +80 -0
  40. package/dist/coding/agent.js +288 -0
  41. package/dist/coding/ai-fix/auto-fix.js +212 -0
  42. package/dist/coding/ai-fix/manager.js +370 -0
  43. package/dist/coding/ai-fix/persist.js +213 -0
  44. package/dist/coding/ai-fix/pr-context.js +58 -0
  45. package/dist/coding/ai-fix/prompts.js +138 -0
  46. package/dist/coding/ai-fix/review-seed.js +357 -0
  47. package/dist/coding/ai-fix/routes.js +425 -0
  48. package/dist/coding/git-ops.js +321 -0
  49. package/dist/coding/git.js +184 -0
  50. package/dist/coding/merge.js +262 -0
  51. package/dist/coding/safe-path.js +75 -0
  52. package/dist/coding/schema.js +43 -0
  53. package/dist/config.js +648 -0
  54. package/dist/conflict/diff.js +304 -0
  55. package/dist/conflict/git.js +118 -0
  56. package/dist/conflict/hash.js +73 -0
  57. package/dist/conflict/janitor.js +218 -0
  58. package/dist/conflict/land.js +675 -0
  59. package/dist/conflict/model-types.js +2 -0
  60. package/dist/conflict/model.js +1081 -0
  61. package/dist/conflict/parse.js +142 -0
  62. package/dist/conflict/seam.js +136 -0
  63. package/dist/conflict/session.js +532 -0
  64. package/dist/conflict/suggestion.js +398 -0
  65. package/dist/conflict/tokens.js +72 -0
  66. package/dist/data-dir.js +112 -0
  67. package/dist/db/actor-lanes.js +213 -0
  68. package/dist/db/automation-ids.js +97 -0
  69. package/dist/db/automation-output.js +349 -0
  70. package/dist/db/blast-radius-query.js +36 -0
  71. package/dist/db/blast-radius.js +226 -0
  72. package/dist/db/bot-dormancy.js +115 -0
  73. package/dist/db/bot-overlap.js +579 -0
  74. package/dist/db/bot-volume.js +722 -0
  75. package/dist/db/bot-window.js +35 -0
  76. package/dist/db/branch-queries.js +310 -0
  77. package/dist/db/change-shape.js +243 -0
  78. package/dist/db/changepoint.js +75 -0
  79. package/dist/db/cleanup.js +36 -0
  80. package/dist/db/client.js +102 -0
  81. package/dist/db/code-loc.js +388 -0
  82. package/dist/db/credits.js +79 -0
  83. package/dist/db/daily-brief.js +406 -0
  84. package/dist/db/dependency-cards.js +145 -0
  85. package/dist/db/erase-account.js +255 -0
  86. package/dist/db/export-account.js +189 -0
  87. package/dist/db/failing-checks.js +124 -0
  88. package/dist/db/file-coupling.js +197 -0
  89. package/dist/db/flow-detail.js +661 -0
  90. package/dist/db/flow-pointers.js +197 -0
  91. package/dist/db/flow-settings.js +67 -0
  92. package/dist/db/forecast.js +114 -0
  93. package/dist/db/line-overlap.js +81 -0
  94. package/dist/db/merge-queue.js +189 -0
  95. package/dist/db/migrate.js +17 -0
  96. package/dist/db/migrations/0000_purple_ben_grimm.sql +155 -0
  97. package/dist/db/migrations/0001_colorful_ozymandias.sql +31 -0
  98. package/dist/db/migrations/0002_famous_sersi.sql +9 -0
  99. package/dist/db/migrations/0003_clever_shinobi_shaw.sql +3 -0
  100. package/dist/db/migrations/0004_pale_scalphunter.sql +1 -0
  101. package/dist/db/migrations/0005_daffy_guardian.sql +2 -0
  102. package/dist/db/migrations/0006_cute_violations.sql +45 -0
  103. package/dist/db/migrations/0007_dark_anthem.sql +2 -0
  104. package/dist/db/migrations/0008_multitenant_accounts.sql +44 -0
  105. package/dist/db/migrations/0009_lean_bodies.sql +13 -0
  106. package/dist/db/migrations/0010_lean_bodies_nullable.sql +56 -0
  107. package/dist/db/migrations/0011_pr_diff_size.sql +10 -0
  108. package/dist/db/migrations/0012_findings_included_default.sql +7 -0
  109. package/dist/db/migrations/0013_review_routing.sql +9 -0
  110. package/dist/db/migrations/0014_account_last_active.sql +6 -0
  111. package/dist/db/migrations/0015_repos_inbox_watch.sql +9 -0
  112. package/dist/db/migrations/0016_repo_viewer_permission.sql +7 -0
  113. package/dist/db/migrations/0017_account_display_name.sql +7 -0
  114. package/dist/db/migrations/0018_finding_comment_kind.sql +7 -0
  115. package/dist/db/migrations/0019_finding_file_in_diff.sql +7 -0
  116. package/dist/db/migrations/0020_claude_review_cost_telemetry.sql +11 -0
  117. package/dist/db/migrations/0021_account_feed_last_seen.sql +7 -0
  118. package/dist/db/migrations/0022_ci_status_events.sql +21 -0
  119. package/dist/db/migrations/0023_ai_usage.sql +21 -0
  120. package/dist/db/migrations/0024_pr_head_ref_name.sql +6 -0
  121. package/dist/db/migrations/0025_account_billing.sql +7 -0
  122. package/dist/db/migrations/0026_ai_credit_allowance.sql +5 -0
  123. package/dist/db/migrations/0027_user_github_type.sql +6 -0
  124. package/dist/db/migrations/0028_bot_review_classification.sql +21 -0
  125. package/dist/db/migrations/0029_bot_mute_rules.sql +19 -0
  126. package/dist/db/migrations/0030_teams.sql +32 -0
  127. package/dist/db/migrations/0031_events_pr_idx.sql +7 -0
  128. package/dist/db/migrations/0032_benchmark_contributions.sql +29 -0
  129. package/dist/db/migrations/0033_thread_addressed_confidence.sql +9 -0
  130. package/dist/db/migrations/0034_thread_resolved_at.sql +6 -0
  131. package/dist/db/migrations/0035_pr_first_review_requested_at.sql +5 -0
  132. package/dist/db/migrations/0036_search_index.sql +25 -0
  133. package/dist/db/migrations/0037_author_indexes.sql +15 -0
  134. package/dist/db/migrations/0038_auto_merge_requests.sql +37 -0
  135. package/dist/db/migrations/0039_branch_status.sql +44 -0
  136. package/dist/db/migrations/0040_pr_review_decision.sql +10 -0
  137. package/dist/db/migrations/0041_branch_commit_detail.sql +38 -0
  138. package/dist/db/migrations/0042_repo_reviewers.sql +176 -0
  139. package/dist/db/migrations/0043_account_reviewers.sql +131 -0
  140. package/dist/db/migrations/0044_workspaces.sql +138 -0
  141. package/dist/db/migrations/0045_workspace_reviewers.sql +180 -0
  142. package/dist/db/migrations/0046_drop_inbox_watch.sql +25 -0
  143. package/dist/db/migrations/0047_ml_comment_labels.sql +40 -0
  144. package/dist/db/migrations/0048_ml_vendor_severity.sql +31 -0
  145. package/dist/db/migrations/0049_seat_pricing_repo_description.sql +21 -0
  146. package/dist/db/migrations/0050_users_app_slug.sql +12 -0
  147. package/dist/db/migrations/0051_auto_merge_queue.sql +17 -0
  148. package/dist/db/migrations/0052_trunk_ci_status_events.sql +43 -0
  149. package/dist/db/migrations/0053_automation_roles.sql +79 -0
  150. package/dist/db/migrations/0054_automation_vendor_kinds.sql +514 -0
  151. package/dist/db/migrations/0055_auto_merge_phase.sql +12 -0
  152. package/dist/db/migrations/0056_pr_mentions.sql +22 -0
  153. package/dist/db/migrations/0057_large_pr_threshold.sql +14 -0
  154. package/dist/db/migrations/0058_pending_mute.sql +53 -0
  155. package/dist/db/migrations/0059_merge_queue_state.sql +33 -0
  156. package/dist/db/migrations/0060_drop_my_turn_dismissals.sql +33 -0
  157. package/dist/db/migrations/0061_auto_merge_durable_anchors.sql +27 -0
  158. package/dist/db/migrations/0062_blast_radius_config.sql +21 -0
  159. package/dist/db/migrations/0063_repo_file_coupling.sql +33 -0
  160. package/dist/db/migrations/0064_pr_content_kind.sql +21 -0
  161. package/dist/db/migrations/0065_workspace_flow_settings.sql +13 -0
  162. package/dist/db/migrations/0066_review_request_events.sql +31 -0
  163. package/dist/db/migrations/0067_pr_security_signals.sql +86 -0
  164. package/dist/db/migrations/0068_my_turn_settings.sql +18 -0
  165. package/dist/db/migrations/0069_my_turn_dismissals.sql +41 -0
  166. package/dist/db/migrations/0070_claude_review_follow_up_ticket.sql +22 -0
  167. package/dist/db/migrations/0071_claude_review_trigger.sql +11 -0
  168. package/dist/db/migrations/0072_commit_message_headline.sql +13 -0
  169. package/dist/db/migrations/0073_claude_review_chat.sql +31 -0
  170. package/dist/db/migrations/0074_adopt_agentic_tables.sql +98 -0
  171. package/dist/db/migrations/0075_review_lens_drop_learnings.sql +15 -0
  172. package/dist/db/migrations/0076_claude_review_threads.sql +17 -0
  173. package/dist/db/migrations/0077_claude_review_ci_failures.sql +10 -0
  174. package/dist/db/migrations/0078_ai_fix_change_report.sql +17 -0
  175. package/dist/db/migrations/0079_claude_finding_story.sql +16 -0
  176. package/dist/db/migrations/meta/0000_snapshot.json +1116 -0
  177. package/dist/db/migrations/meta/0001_snapshot.json +1321 -0
  178. package/dist/db/migrations/meta/0002_snapshot.json +1375 -0
  179. package/dist/db/migrations/meta/0003_snapshot.json +1396 -0
  180. package/dist/db/migrations/meta/0004_snapshot.json +1416 -0
  181. package/dist/db/migrations/meta/0005_snapshot.json +1430 -0
  182. package/dist/db/migrations/meta/0006_snapshot.json +1745 -0
  183. package/dist/db/migrations/meta/0007_snapshot.json +1759 -0
  184. package/dist/db/migrations/meta/_journal.json +566 -0
  185. package/dist/db/migrations-pg/0000_tired_alex_power.sql +268 -0
  186. package/dist/db/migrations-pg/0001_dizzy_mockingbird.sql +3 -0
  187. package/dist/db/migrations-pg/0002_glorious_ikaris.sql +4 -0
  188. package/dist/db/migrations-pg/0003_melted_secret_warriors.sql +2 -0
  189. package/dist/db/migrations-pg/0004_numerous_triton.sql +1 -0
  190. package/dist/db/migrations-pg/0005_thick_blockbuster.sql +2 -0
  191. package/dist/db/migrations-pg/0006_majestic_dracula.sql +1 -0
  192. package/dist/db/migrations-pg/0007_same_human_torch.sql +2 -0
  193. package/dist/db/migrations-pg/0008_slimy_toxin.sql +1 -0
  194. package/dist/db/migrations-pg/0009_fuzzy_jubilee.sql +4 -0
  195. package/dist/db/migrations-pg/0010_late_hammerhead.sql +1 -0
  196. package/dist/db/migrations-pg/0011_happy_leech.sql +16 -0
  197. package/dist/db/migrations-pg/0012_woozy_captain_midlands.sql +16 -0
  198. package/dist/db/migrations-pg/0013_yielding_nicolaos.sql +1 -0
  199. package/dist/db/migrations-pg/0014_wakeful_bill_hollister.sql +2 -0
  200. package/dist/db/migrations-pg/0015_aspiring_black_tom.sql +1 -0
  201. package/dist/db/migrations-pg/0016_cute_ghost_rider.sql +30 -0
  202. package/dist/db/migrations-pg/0017_far_changeling.sql +24 -0
  203. package/dist/db/migrations-pg/0018_fancy_miss_america.sql +1 -0
  204. package/dist/db/migrations-pg/0019_benchmark_contributions.sql +22 -0
  205. package/dist/db/migrations-pg/0020_majestic_edwin_jarvis.sql +3 -0
  206. package/dist/db/migrations-pg/0021_green_salo.sql +1 -0
  207. package/dist/db/migrations-pg/0022_wise_baron_strucker.sql +1 -0
  208. package/dist/db/migrations-pg/0023_search_index.sql +19 -0
  209. package/dist/db/migrations-pg/0024_author_indexes.sql +9 -0
  210. package/dist/db/migrations-pg/0025_auto_merge_requests.sql +26 -0
  211. package/dist/db/migrations-pg/0026_branch_status.sql +32 -0
  212. package/dist/db/migrations-pg/0027_pr_review_decision.sql +5 -0
  213. package/dist/db/migrations-pg/0028_branch_commit_detail.sql +9 -0
  214. package/dist/db/migrations-pg/0029_repo_reviewers.sql +127 -0
  215. package/dist/db/migrations-pg/0030_account_reviewers.sql +77 -0
  216. package/dist/db/migrations-pg/0031_workspaces.sql +131 -0
  217. package/dist/db/migrations-pg/0032_workspace_reviewers.sql +165 -0
  218. package/dist/db/migrations-pg/0033_drop_inbox_watch.sql +14 -0
  219. package/dist/db/migrations-pg/0034_ml_comment_labels.sql +33 -0
  220. package/dist/db/migrations-pg/0035_ml_vendor_severity.sql +16 -0
  221. package/dist/db/migrations-pg/0036_seat_pricing_repo_description.sql +12 -0
  222. package/dist/db/migrations-pg/0037_users_app_slug.sql +9 -0
  223. package/dist/db/migrations-pg/0038_auto_merge_queue.sql +10 -0
  224. package/dist/db/migrations-pg/0039_trunk_ci_status_events.sql +27 -0
  225. package/dist/db/migrations-pg/0040_automation_roles.sql +63 -0
  226. package/dist/db/migrations-pg/0041_automation_vendor_kinds.sql +488 -0
  227. package/dist/db/migrations-pg/0042_auto_merge_phase.sql +8 -0
  228. package/dist/db/migrations-pg/0043_pr_mentions.sql +19 -0
  229. package/dist/db/migrations-pg/0044_large_pr_threshold.sql +6 -0
  230. package/dist/db/migrations-pg/0045_pending_mute.sql +26 -0
  231. package/dist/db/migrations-pg/0046_merge_queue_state.sql +18 -0
  232. package/dist/db/migrations-pg/0047_drop_my_turn_dismissals.sql +21 -0
  233. package/dist/db/migrations-pg/0048_auto_merge_durable_anchors.sql +27 -0
  234. package/dist/db/migrations-pg/0049_blast_radius_config.sql +8 -0
  235. package/dist/db/migrations-pg/0050_repo_file_coupling.sql +13 -0
  236. package/dist/db/migrations-pg/0051_pr_content_kind.sql +6 -0
  237. package/dist/db/migrations-pg/0052_workspace_flow_settings.sql +4 -0
  238. package/dist/db/migrations-pg/0053_review_request_events.sql +18 -0
  239. package/dist/db/migrations-pg/0054_pr_security_signals.sql +59 -0
  240. package/dist/db/migrations-pg/0055_my_turn_settings.sql +6 -0
  241. package/dist/db/migrations-pg/0056_my_turn_dismissals.sql +21 -0
  242. package/dist/db/migrations-pg/0057_claude_review_follow_up_ticket.sql +8 -0
  243. package/dist/db/migrations-pg/0058_claude_review_trigger.sql +4 -0
  244. package/dist/db/migrations-pg/0059_commit_message_headline.sql +3 -0
  245. package/dist/db/migrations-pg/0060_claude_review_chat.sql +24 -0
  246. package/dist/db/migrations-pg/0061_adopt_agentic_tables.sql +79 -0
  247. package/dist/db/migrations-pg/0062_review_lens_drop_learnings.sql +5 -0
  248. package/dist/db/migrations-pg/0063_claude_review_threads.sql +7 -0
  249. package/dist/db/migrations-pg/0064_claude_review_ci_failures.sql +4 -0
  250. package/dist/db/migrations-pg/0065_ai_fix_change_report.sql +9 -0
  251. package/dist/db/migrations-pg/0066_claude_finding_story.sql +7 -0
  252. package/dist/db/migrations-pg/meta/0000_snapshot.json +2137 -0
  253. package/dist/db/migrations-pg/meta/0001_snapshot.json +2143 -0
  254. package/dist/db/migrations-pg/meta/0002_snapshot.json +2170 -0
  255. package/dist/db/migrations-pg/meta/0003_snapshot.json +2182 -0
  256. package/dist/db/migrations-pg/meta/0004_snapshot.json +2188 -0
  257. package/dist/db/migrations-pg/meta/0005_snapshot.json +2201 -0
  258. package/dist/db/migrations-pg/meta/0006_snapshot.json +2207 -0
  259. package/dist/db/migrations-pg/meta/0007_snapshot.json +2219 -0
  260. package/dist/db/migrations-pg/meta/0008_snapshot.json +2226 -0
  261. package/dist/db/migrations-pg/meta/0009_snapshot.json +2250 -0
  262. package/dist/db/migrations-pg/meta/0010_snapshot.json +2256 -0
  263. package/dist/db/migrations-pg/meta/0011_snapshot.json +2412 -0
  264. package/dist/db/migrations-pg/meta/0012_snapshot.json +2528 -0
  265. package/dist/db/migrations-pg/meta/0013_snapshot.json +2534 -0
  266. package/dist/db/migrations-pg/meta/0014_snapshot.json +2547 -0
  267. package/dist/db/migrations-pg/meta/0015_snapshot.json +2553 -0
  268. package/dist/db/migrations-pg/meta/0016_snapshot.json +2774 -0
  269. package/dist/db/migrations-pg/meta/0017_snapshot.json +2999 -0
  270. package/dist/db/migrations-pg/meta/0018_snapshot.json +3020 -0
  271. package/dist/db/migrations-pg/meta/0020_snapshot.json +3228 -0
  272. package/dist/db/migrations-pg/meta/0021_snapshot.json +3234 -0
  273. package/dist/db/migrations-pg/meta/0022_snapshot.json +3240 -0
  274. package/dist/db/migrations-pg/meta/_journal.json +475 -0
  275. package/dist/db/ml-labels.js +1666 -0
  276. package/dist/db/my-turn-dismissals.js +343 -0
  277. package/dist/db/my-turn-settings.js +34 -0
  278. package/dist/db/pending-classify.js +46 -0
  279. package/dist/db/pending-mute.js +171 -0
  280. package/dist/db/pending-tabs.js +238 -0
  281. package/dist/db/period-metrics.js +820 -0
  282. package/dist/db/person-period.js +763 -0
  283. package/dist/db/pr-intervals.js +930 -0
  284. package/dist/db/pr-liveness.js +240 -0
  285. package/dist/db/pr-mentions.js +279 -0
  286. package/dist/db/pr-merge-queue-stamp.js +91 -0
  287. package/dist/db/queries.js +14631 -0
  288. package/dist/db/reaction-targets.js +94 -0
  289. package/dist/db/repo-activity.js +171 -0
  290. package/dist/db/retention.js +138 -0
  291. package/dist/db/review-threads-for-review.js +240 -0
  292. package/dist/db/run-migrations.js +24 -0
  293. package/dist/db/schema.pg.js +1220 -0
  294. package/dist/db/schema.sqlite.js +1801 -0
  295. package/dist/db/search.js +317 -0
  296. package/dist/db/security-alerts.js +218 -0
  297. package/dist/db/synthesis-input.js +565 -0
  298. package/dist/db/triage.js +320 -0
  299. package/dist/db/usage.js +63 -0
  300. package/dist/db/work-plan.js +1086 -0
  301. package/dist/db/working-hours.js +161 -0
  302. package/dist/feed/my-turn.js +122 -0
  303. package/dist/github/actions-logs.js +397 -0
  304. package/dist/github/auth.js +86 -0
  305. package/dist/github/branch-queries.js +229 -0
  306. package/dist/github/client.js +454 -0
  307. package/dist/github/codeowners.js +221 -0
  308. package/dist/github/commit-checks.js +105 -0
  309. package/dist/github/compare.js +110 -0
  310. package/dist/github/diff-anchor.js +227 -0
  311. package/dist/github/mutations.js +706 -0
  312. package/dist/github/pr-file-content.js +254 -0
  313. package/dist/github/pr-liveness.js +161 -0
  314. package/dist/github/queries.js +875 -0
  315. package/dist/github/rate-budget.js +129 -0
  316. package/dist/github/reactions.js +161 -0
  317. package/dist/github/reviewer-suggest.js +104 -0
  318. package/dist/github/team-reviewers.js +96 -0
  319. package/dist/index.js +184 -0
  320. package/dist/merge/auto-merge-runner.js +960 -0
  321. package/dist/ml/severity-client.js +218 -0
  322. package/dist/pr/detail-enricher.js +26 -0
  323. package/dist/pro/bind.js +302 -0
  324. package/dist/pro/contract.js +37 -0
  325. package/dist/pro/migrate.js +64 -0
  326. package/dist/review/agent-context.js +127 -0
  327. package/dist/review/agent.js +385 -0
  328. package/dist/review/agentic.js +59 -0
  329. package/dist/review/auth.js +94 -0
  330. package/dist/review/chat-agent.js +179 -0
  331. package/dist/review/claude-review/ai-ready.js +16 -0
  332. package/dist/review/claude-review/auto-settings.js +139 -0
  333. package/dist/review/claude-review/auto.js +244 -0
  334. package/dist/review/claude-review/chat.js +489 -0
  335. package/dist/review/claude-review/ci-failures.js +350 -0
  336. package/dist/review/claude-review/follow-up.js +310 -0
  337. package/dist/review/claude-review/manager.js +686 -0
  338. package/dist/review/claude-review/persist.js +996 -0
  339. package/dist/review/claude-review/prompts.js +357 -0
  340. package/dist/review/claude-review/routes.js +518 -0
  341. package/dist/review/claude-review/routing.js +61 -0
  342. package/dist/review/claude-review/specialists.js +190 -0
  343. package/dist/review/claude-review/threads.js +265 -0
  344. package/dist/review/claude-review/ticket.js +282 -0
  345. package/dist/review/clone-hygiene.js +380 -0
  346. package/dist/review/clone-manager.js +367 -0
  347. package/dist/review/llm.js +113 -0
  348. package/dist/review/model-options.js +48 -0
  349. package/dist/review/plugin-providers.js +12 -0
  350. package/dist/review/post-review.js +216 -0
  351. package/dist/review/post-seam.js +161 -0
  352. package/dist/review/prepare.js +168 -0
  353. package/dist/review/pricing.js +17 -0
  354. package/dist/review/schema.js +156 -0
  355. package/dist/review/submit-map.js +41 -0
  356. package/dist/review/usage.js +90 -0
  357. package/dist/shared/claude-review.js +335 -0
  358. package/dist/shared/conflict-fold.js +151 -0
  359. package/dist/shared/conflicts.js +30 -0
  360. package/dist/shared/flow-settings.js +191 -0
  361. package/dist/shared/index.js +8 -0
  362. package/dist/shared/my-turn-settings.js +238 -0
  363. package/dist/shared/pending-rules.js +281 -0
  364. package/dist/shared/product.js +54 -0
  365. package/dist/shared/types.js +896 -0
  366. package/dist/status.js +386 -0
  367. package/dist/sync/adaptive.js +185 -0
  368. package/dist/sync/app-attribution.js +66 -0
  369. package/dist/sync/auth-notices.js +36 -0
  370. package/dist/sync/backfill-ci-history.js +315 -0
  371. package/dist/sync/backfill-commit-headlines.js +136 -0
  372. package/dist/sync/backfill-pr-security.js +175 -0
  373. package/dist/sync/backfill-review-requests.js +97 -0
  374. package/dist/sync/benchmark-rollup.js +50 -0
  375. package/dist/sync/bot-detection.js +309 -0
  376. package/dist/sync/bot-resolution-markers.js +30 -0
  377. package/dist/sync/branch-status.js +634 -0
  378. package/dist/sync/classify-change-shape.js +150 -0
  379. package/dist/sync/commit-files.js +74 -0
  380. package/dist/sync/derive-thread-state.js +99 -0
  381. package/dist/sync/drain-review-threads.js +212 -0
  382. package/dist/sync/hydrate-detail.js +482 -0
  383. package/dist/sync/mention-scan.js +89 -0
  384. package/dist/sync/ml-enrichment.js +478 -0
  385. package/dist/sync/pr-change-signal.js +96 -0
  386. package/dist/sync/pr-liveness-sweep.js +139 -0
  387. package/dist/sync/pr-settle.js +381 -0
  388. package/dist/sync/refresh-pr.js +163 -0
  389. package/dist/sync/reparse-vendor-badges.js +495 -0
  390. package/dist/sync/resync-after-write.js +280 -0
  391. package/dist/sync/review-fingerprint.js +117 -0
  392. package/dist/sync/reviewer-behavior.js +103 -0
  393. package/dist/sync/reviewer-classify.js +503 -0
  394. package/dist/sync/routing-files.js +97 -0
  395. package/dist/sync/scheduled-jobs.js +12 -0
  396. package/dist/sync/scheduler.js +159 -0
  397. package/dist/sync/security-detect.js +521 -0
  398. package/dist/sync/sync-manager.js +750 -0
  399. package/dist/sync/sync-one-pr.js +205 -0
  400. package/dist/sync/sync-repo.js +400 -0
  401. package/dist/sync/unsettled-prs.js +506 -0
  402. package/dist/sync/upsert.js +1190 -0
  403. package/package.json +56 -0
  404. package/public/apple-touch-icon.png +0 -0
  405. package/public/assets/AiFixTab-CQP6PT5u.js +2 -0
  406. package/public/assets/ClaudeReviewTab-DQJ-58ZA.js +8 -0
  407. package/public/assets/PrBotBehaviourTab-CCnFrWbC.js +1 -0
  408. package/public/assets/archivo-latin-600-BN-JkNrl.woff2 +0 -0
  409. package/public/assets/highlight-BEHUn5zE.css +10 -0
  410. package/public/assets/highlight-CIIZLa6Z.js +12 -0
  411. package/public/assets/index-BDnYs6zg.js +73 -0
  412. package/public/assets/index-mCuI--RC.css +1 -0
  413. package/public/assets/markdown-I_JLLVAZ.js +32 -0
  414. package/public/assets/perfProbe-Da13EhTE.js +1 -0
  415. package/public/assets/tanstack-5qsxxaLe.js +17 -0
  416. package/public/assets/vis-C3BCkP5U.js +1280 -0
  417. package/public/assets/vis-ziCVehMy.css +1 -0
  418. package/public/favicon-16.png +0 -0
  419. package/public/favicon-32.png +0 -0
  420. package/public/favicon-48.png +0 -0
  421. package/public/favicon.svg +5 -0
  422. package/public/index.html +41 -0
  423. package/public-landing/apple-touch-icon.png +0 -0
  424. package/public-landing/assets/archivo-latin-500-BWmvx2Mg.woff2 +0 -0
  425. package/public-landing/assets/archivo-latin-600-BN-JkNrl.woff2 +0 -0
  426. package/public-landing/assets/index-CA3eEGXO.js +40 -0
  427. package/public-landing/assets/index-naQrQ6Fe.css +1 -0
  428. package/public-landing/assets/jetbrains-mono-latin-400-RruCX7RW.woff2 +0 -0
  429. package/public-landing/assets/newsreader-latin-400-DExrRRrN.woff2 +0 -0
  430. package/public-landing/assets/newsreader-latin-400-italic-b0I-AwbV.woff2 +0 -0
  431. package/public-landing/bots/index.html +156 -0
  432. package/public-landing/contact/index.html +156 -0
  433. package/public-landing/cookies/index.html +156 -0
  434. package/public-landing/demo/limn-walkthrough-poster.jpg +0 -0
  435. package/public-landing/demo/limn-walkthrough.cues.json +44 -0
  436. package/public-landing/demo/limn-walkthrough.mp4 +0 -0
  437. package/public-landing/favicon-16.png +0 -0
  438. package/public-landing/favicon-32.png +0 -0
  439. package/public-landing/favicon-48.png +0 -0
  440. package/public-landing/favicon.svg +5 -0
  441. package/public-landing/features/index.html +156 -0
  442. package/public-landing/for-developers/index.html +156 -0
  443. package/public-landing/for-managers/index.html +156 -0
  444. package/public-landing/how-it-works/index.html +156 -0
  445. package/public-landing/how-we-measure/index.html +156 -0
  446. package/public-landing/icon-192.png +0 -0
  447. package/public-landing/icon-512.png +0 -0
  448. package/public-landing/index.html +156 -0
  449. package/public-landing/insights/index.html +156 -0
  450. package/public-landing/og-image.png +0 -0
  451. package/public-landing/pricing/index.html +156 -0
  452. package/public-landing/privacy/index.html +156 -0
  453. package/public-landing/pro/index.html +156 -0
  454. package/public-landing/reviews/index.html +156 -0
  455. package/public-landing/robots.txt +8 -0
  456. package/public-landing/shots/benchmark.png +0 -0
  457. package/public-landing/shots/bot-roi.png +0 -0
  458. package/public-landing/shots/bot-settings.png +0 -0
  459. package/public-landing/shots/chronology.png +0 -0
  460. package/public-landing/shots/feed.png +0 -0
  461. package/public-landing/shots/flow-metrics.png +0 -0
  462. package/public-landing/shots/free-reports.png +0 -0
  463. package/public-landing/shots/pending-board.png +0 -0
  464. package/public-landing/shots/pending-card.png +0 -0
  465. package/public-landing/shots/period-report.png +0 -0
  466. package/public-landing/shots/pr-detail.png +0 -0
  467. package/public-landing/shots/pr-threads.png +0 -0
  468. package/public-landing/shots/reach.png +0 -0
  469. package/public-landing/shots/repo-rows.png +0 -0
  470. package/public-landing/shots/severity-findings.png +0 -0
  471. package/public-landing/shots/severity-strip.png +0 -0
  472. package/public-landing/site.webmanifest +14 -0
  473. package/public-landing/sitemap.xml +51 -0
  474. package/public-landing/terms/index.html +156 -0
@@ -0,0 +1,105 @@
1
+ import { checkRunsFrom } from '../sync/upsert.js';
2
+ import { getGraphqlClientFor, ghRestGetFor, graphqlTolerant, isRateLimitError } from './client.js';
3
+ import { isLimited, noteLimited } from './rate-budget.js';
4
+ const SHA_RE = /^[0-9a-fA-F]{7,64}$/;
5
+ export const COMMIT_CHECKS_QUERY = /* GraphQL */ `
6
+ query CommitChecks($owner: String!, $name: String!, $oid: GitObjectID!) {
7
+ repository(owner: $owner, name: $name) {
8
+ object(oid: $oid) {
9
+ __typename
10
+ ... on Commit {
11
+ oid
12
+ statusCheckRollup {
13
+ state
14
+ contexts(first: 100) {
15
+ nodes {
16
+ __typename
17
+ ... on CheckRun {
18
+ name
19
+ status
20
+ conclusion
21
+ detailsUrl
22
+ }
23
+ ... on StatusContext {
24
+ context
25
+ state
26
+ targetUrl
27
+ }
28
+ }
29
+ }
30
+ }
31
+ }
32
+ }
33
+ }
34
+ }
35
+ `;
36
+ /** The checks on one commit. Never throws. */
37
+ export async function fetchCommitChecks(token, args) {
38
+ if (!SHA_RE.test(args.sha))
39
+ return { ok: false, reason: 'bad_sha' };
40
+ if (args.accountId != null && isLimited(args.accountId))
41
+ return { ok: false, reason: 'rate_limited' };
42
+ try {
43
+ let partial = false;
44
+ const data = await graphqlTolerant(getGraphqlClientFor(token), COMMIT_CHECKS_QUERY, { owner: args.owner, name: args.name, oid: args.sha }, () => {
45
+ partial = true;
46
+ });
47
+ const obj = data?.repository?.object ?? null;
48
+ if (!obj || obj.__typename !== 'Commit')
49
+ return { ok: false, reason: 'not_found' };
50
+ const rollup = obj.statusCheckRollup ?? null;
51
+ // ⚠ A PARTIAL answer is not "no checks": a token that cannot read checks (a GitHub App without
52
+ // checks:read) gets the rollup NULLED with an error beside it. Only a clean null means none.
53
+ if (rollup == null)
54
+ return partial ? { ok: false, reason: 'no_check_access' } : { ok: true, rollupState: null, checks: [] };
55
+ if (rollup.contexts == null && partial)
56
+ return { ok: false, reason: 'no_check_access' };
57
+ const nodes = (rollup.contexts?.nodes ?? []).filter((n) => n != null);
58
+ const checks = checkRunsFrom({
59
+ oid: obj.oid ?? args.sha,
60
+ statusCheckRollup: { state: rollup.state ?? '', contexts: { nodes } },
61
+ });
62
+ return { ok: true, rollupState: rollup.state ?? null, checks };
63
+ }
64
+ catch (err) {
65
+ const rl = isRateLimitError(err);
66
+ if (rl.limited) {
67
+ if (args.accountId != null)
68
+ noteLimited(args.accountId, rl.resumeAt);
69
+ return { ok: false, reason: 'rate_limited' };
70
+ }
71
+ return { ok: false, reason: 'error' };
72
+ }
73
+ }
74
+ /**
75
+ * The name of the FIRST failed step of a GitHub Actions job, from GitHub's own step list
76
+ * (`GET /repos/{o}/{r}/actions/jobs/{id}`). null when none failed by GitHub's record, or on any
77
+ * error. Never throws.
78
+ */
79
+ export async function fetchActionsJobFailedStep(token, args) {
80
+ if (!Number.isSafeInteger(args.jobId) || args.jobId <= 0)
81
+ return null;
82
+ if (args.accountId != null && isLimited(args.accountId))
83
+ return null;
84
+ try {
85
+ const job = await ghRestGetFor(token, `/repos/${args.owner}/${args.name}/actions/jobs/${args.jobId}`);
86
+ return failedStepName(job);
87
+ }
88
+ catch (err) {
89
+ const rl = isRateLimitError(err);
90
+ if (rl.limited && args.accountId != null)
91
+ noteLimited(args.accountId, rl.resumeAt);
92
+ return null;
93
+ }
94
+ }
95
+ const FAILED_STEP = new Set(['failure', 'timed_out', 'startup_failure']);
96
+ /** Pure: the first failed step of a REST job payload (by step number). Exported for tests. */
97
+ export function failedStepName(job) {
98
+ const steps = Array.isArray(job?.steps) ? job.steps : [];
99
+ const failed = steps
100
+ .filter((s) => typeof s?.conclusion === 'string' && FAILED_STEP.has(s.conclusion))
101
+ .sort((a, b) => (Number(a.number) || 0) - (Number(b.number) || 0));
102
+ const name = failed[0]?.name;
103
+ return typeof name === 'string' && name.trim() ? name.trim() : null;
104
+ }
105
+ //# sourceMappingURL=commit-checks.js.map
@@ -0,0 +1,110 @@
1
+ // Two-sha COMPARE primitive (CORE). One REST call to
2
+ // `GET /repos/{owner}/{name}/compare/{base}...{head}` returning the per-file unified patches
3
+ // between two commits, optionally narrowed to a set of paths.
4
+ //
5
+ // WHY IT LIVES IN CORE. Every diff primitive does, by standing policy (see the PreparedReview
6
+ // note in src/pro/contract.ts): the plugin holds no GitHub token and must never assemble
7
+ // patches itself. This module is the one the `addressed` annotation is grounded on — "what
8
+ // actually changed between the commit the thread was last discussed at and the PR head" — and
9
+ // it is reached from the plugin through `ProContext.github.fetchCompareDiff`.
10
+ //
11
+ // IT NEVER THROWS. A missing/forbidden/rate-limited compare must degrade the judgement that
12
+ // asked for it to "no diff evidence available", never turn a working feature into an error.
13
+ // Every failure comes back as `{ ok: false, reason }`.
14
+ //
15
+ // KNOWN GITHUB LIMITS, all modelled rather than hidden:
16
+ // * `files[]` is capped at 300 entries — past that a path's ABSENCE is not proof it was
17
+ // untouched, hence `filesTruncated`;
18
+ // * `patch` is OMITTED for binary and oversized files (the entry still appears with its
19
+ // add/delete counts), hence a `null` patch with a real `status`;
20
+ // * a sha that has been force-pushed away 404s — an ordinary outcome, not an error;
21
+ // * 403/429 are classified through `isRateLimitError` (the SEPARATE classifier — do NOT
22
+ // widen `isRetryableGithubError`, whose 403/429 exclusion is pinned by a test) and fed to
23
+ // the per-account budget so the rest of the process backs off too.
24
+ import { ghRestGetFor, isRateLimitError, withGithubRetry } from './client.js';
25
+ import { noteLimited } from './rate-budget.js';
26
+ /** Per-file clamp on the returned patch. A grounding hunk, not a whole-file dump. */
27
+ export const DEFAULT_MAX_PATCH_CHARS = 20_000;
28
+ /** GitHub's own ceiling on `files[]` in one compare response. */
29
+ const GITHUB_COMPARE_FILE_CAP = 300;
30
+ /** Shas arrive from stored data; keep them out of the URL path unless they look like shas. */
31
+ const SHA_RE = /^[0-9a-fA-F]{7,64}$/;
32
+ const asString = (v) => (typeof v === 'string' ? v : null);
33
+ const asCount = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : 0);
34
+ function empty(baseSha, headSha, reason, ok) {
35
+ return { ok, baseSha, headSha, files: [], filesChanged: 0, filesTruncated: false, reason };
36
+ }
37
+ function statusOf(err) {
38
+ const s = err?.status;
39
+ return typeof s === 'number' ? s : null;
40
+ }
41
+ /**
42
+ * The per-file patches between two commits of one repo.
43
+ *
44
+ * `paths` narrows the RESULT, not the request — GitHub's compare endpoint has no server-side
45
+ * path filter, so the whole file list comes back either way and is filtered here. That is also
46
+ * why one call covers every path a caller cares about: coalesce by (baseSha, headSha) rather
47
+ * than issuing one request per file.
48
+ *
49
+ * A file that was RENAMED matches on either name, so a thread anchored to the old path still
50
+ * finds its change.
51
+ */
52
+ export async function fetchCompareDiff(token, args) {
53
+ const { owner, name, baseSha, headSha } = args;
54
+ const maxPatchChars = args.maxPatchChars ?? DEFAULT_MAX_PATCH_CHARS;
55
+ if (!SHA_RE.test(baseSha) || !SHA_RE.test(headSha)) {
56
+ return empty(baseSha, headSha, 'bad_sha', false);
57
+ }
58
+ // Nothing can have changed between a commit and itself — and a request would still cost a
59
+ // point of GitHub quota to say so.
60
+ if (baseSha === headSha)
61
+ return empty(baseSha, headSha, 'identical', true);
62
+ let raw;
63
+ try {
64
+ raw = await withGithubRetry(() => ghRestGetFor(token, `/repos/${owner}/${name}/compare/${baseSha}...${headSha}`));
65
+ }
66
+ catch (err) {
67
+ const rl = isRateLimitError(err);
68
+ if (rl.limited) {
69
+ if (args.accountId != null)
70
+ noteLimited(args.accountId, rl.resumeAt);
71
+ return empty(baseSha, headSha, 'rate_limited', false);
72
+ }
73
+ const status = statusOf(err);
74
+ const reason = status === 404 ? 'not_found' : status === 403 ? 'forbidden' : 'error';
75
+ return empty(baseSha, headSha, reason, false);
76
+ }
77
+ const all = Array.isArray(raw.files) ? raw.files : [];
78
+ const want = args.paths != null ? new Set(args.paths) : null;
79
+ const files = [];
80
+ for (const f of all) {
81
+ const path = asString(f.filename);
82
+ if (path == null)
83
+ continue;
84
+ const previousPath = asString(f.previous_filename);
85
+ if (want != null && !want.has(path) && !(previousPath != null && want.has(previousPath))) {
86
+ continue;
87
+ }
88
+ const patchRaw = asString(f.patch);
89
+ const patchTruncated = patchRaw != null && patchRaw.length > maxPatchChars;
90
+ files.push({
91
+ path,
92
+ previousPath,
93
+ status: asString(f.status) ?? 'modified',
94
+ additions: asCount(f.additions),
95
+ deletions: asCount(f.deletions),
96
+ patch: patchRaw == null ? null : patchTruncated ? patchRaw.slice(0, maxPatchChars) : patchRaw,
97
+ patchTruncated,
98
+ });
99
+ }
100
+ return {
101
+ ok: true,
102
+ baseSha,
103
+ headSha,
104
+ files,
105
+ filesChanged: all.length,
106
+ filesTruncated: all.length >= GITHUB_COMPARE_FILE_CAP,
107
+ reason: null,
108
+ };
109
+ }
110
+ //# sourceMappingURL=compare.js.map
@@ -0,0 +1,227 @@
1
+ // Pure unified-diff anchoring helpers, shared between the Claude-review posting
2
+ // path (review/post-review.ts) and the on-demand Changes-tab / inline-comment
3
+ // path (the PR write actions). All functions here are side-effect-free string
4
+ // parsers — no GitHub I/O, no DB — so they're trivially testable and reusable.
5
+ export const HUNK_RE = /^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/;
6
+ // Parse a unified diff into per-file maps of addable line numbers. We track the
7
+ // new-file line counter (RIGHT) and old-file line counter (LEFT) as we walk each
8
+ // hunk: context lines advance both, `+` advances RIGHT, `-` advances LEFT.
9
+ export function buildAnchorIndex(diff) {
10
+ const index = new Map();
11
+ let current = null;
12
+ let newLine = 0;
13
+ let oldLine = 0;
14
+ for (const raw of diff.split('\n')) {
15
+ if (raw.startsWith('diff --git')) {
16
+ current = null;
17
+ continue;
18
+ }
19
+ // `+++ b/path` names the new-side file; strip the `b/` prefix. GitHub keys
20
+ // comments by this path. `/dev/null` (deletions) yields no anchors.
21
+ if (raw.startsWith('+++ ')) {
22
+ const path = parseDiffPath(raw.slice(4));
23
+ if (path) {
24
+ current = {
25
+ right: new Set(),
26
+ left: new Set(),
27
+ firstAdded: null,
28
+ firstRemoved: null,
29
+ };
30
+ index.set(path, current);
31
+ }
32
+ else {
33
+ current = null;
34
+ }
35
+ continue;
36
+ }
37
+ if (raw.startsWith('--- '))
38
+ continue;
39
+ const hunk = HUNK_RE.exec(raw);
40
+ if (hunk) {
41
+ oldLine = Number(hunk[1]);
42
+ newLine = Number(hunk[2]);
43
+ continue;
44
+ }
45
+ if (!current)
46
+ continue;
47
+ const marker = raw[0];
48
+ if (marker === '+') {
49
+ current.right.add(newLine);
50
+ if (current.firstAdded == null)
51
+ current.firstAdded = newLine;
52
+ newLine += 1;
53
+ }
54
+ else if (marker === '-') {
55
+ current.left.add(oldLine);
56
+ if (current.firstRemoved == null)
57
+ current.firstRemoved = oldLine;
58
+ oldLine += 1;
59
+ }
60
+ else if (marker === ' ') {
61
+ current.right.add(newLine);
62
+ current.left.add(oldLine);
63
+ newLine += 1;
64
+ oldLine += 1;
65
+ }
66
+ // `` and blank trailing lines advance nothing.
67
+ }
68
+ return index;
69
+ }
70
+ // Parse a SINGLE GitHub REST per-file patch into its FileAnchors. REST per-file
71
+ // patches (from `GET /pulls/{n}/files`) are header-LESS — they start straight at
72
+ // the first `@@ … @@` hunk, with no `diff --git` / `+++ b/path` line that
73
+ // `buildAnchorIndex` keys on. We synthesize that `+++ b/<filename>` header so the
74
+ // shared walker produces an index, then pull the one entry back out.
75
+ //
76
+ // A null/empty patch (binary files, or files with no textual diff) yields empty
77
+ // anchor sets so callers treat every line as unanchorable.
78
+ export function buildFileAnchors(filename, patch) {
79
+ const empty = {
80
+ right: new Set(),
81
+ left: new Set(),
82
+ firstAdded: null,
83
+ firstRemoved: null,
84
+ };
85
+ if (!patch)
86
+ return empty;
87
+ const synthesized = `+++ b/${filename}\n${patch}`;
88
+ // The synthesized diff has exactly one file, so take the sole entry rather than
89
+ // looking it up by `filename` — buildAnchorIndex may trim the key, which would
90
+ // miss for a filename with surrounding whitespace.
91
+ const [only] = buildAnchorIndex(synthesized).values();
92
+ return only ?? empty;
93
+ }
94
+ // `+++ b/src/foo.ts` → `src/foo.ts`; `+++ /dev/null` → null. Trailing tab-info
95
+ // (rename/mode) is already excluded by GitHub's diff format on this line.
96
+ function parseDiffPath(rest) {
97
+ const trimmed = rest.trim();
98
+ if (trimmed === '/dev/null')
99
+ return null;
100
+ return trimmed.startsWith('b/') ? trimmed.slice(2) : trimmed;
101
+ }
102
+ // Split a unified diff into per-file segments (each starting at a `diff --git`
103
+ // header). The path prefers the new-side (`+++ b/…`) name, falling back to the
104
+ // header. Used to drop noise files before the agent sees the diff.
105
+ export function splitDiffByFile(diff) {
106
+ const segments = [];
107
+ let curLines = [];
108
+ let curPath = null;
109
+ const flush = () => {
110
+ if (curLines.length > 0 && curPath) {
111
+ segments.push({ path: curPath, text: curLines.join('\n') });
112
+ }
113
+ curLines = [];
114
+ curPath = null;
115
+ };
116
+ for (const line of diff.split('\n')) {
117
+ if (line.startsWith('diff --git ')) {
118
+ flush();
119
+ curLines = [line];
120
+ curPath = parseGitHeaderPath(line);
121
+ }
122
+ else {
123
+ if (line.startsWith('+++ ')) {
124
+ const p = parseDiffPath(line.slice(4));
125
+ if (p)
126
+ curPath = p;
127
+ }
128
+ curLines.push(line);
129
+ }
130
+ }
131
+ flush();
132
+ return segments;
133
+ }
134
+ // `diff --git a/foo b/foo` → `foo` (new path). Null if unparseable.
135
+ function parseGitHeaderPath(line) {
136
+ const m = /^diff --git a\/(.+) b\/(.+)$/.exec(line);
137
+ return m ? (m[2] ?? null) : null;
138
+ }
139
+ // A finding is anchorable inline only if its (path, line, side) lands on an
140
+ // addable diff line for that side.
141
+ export function isFindingAnchored(index, path, line, side) {
142
+ if (line == null)
143
+ return false;
144
+ const anchors = index.get(path);
145
+ if (!anchors)
146
+ return false;
147
+ return side === 'LEFT' ? anchors.left.has(line) : anchors.right.has(line);
148
+ }
149
+ // Where to anchor a finding whose own (line, side) isn't addable: the file's
150
+ // FIRST added line (RIGHT), preferred over its first removed line (LEFT). null
151
+ // when the file isn't in the diff at all (nothing to attach to → stays skipped).
152
+ export function fallbackAnchor(index, path) {
153
+ const anchors = index.get(path);
154
+ if (!anchors)
155
+ return null;
156
+ if (anchors.firstAdded != null)
157
+ return { line: anchors.firstAdded, side: 'RIGHT' };
158
+ if (anchors.firstRemoved != null)
159
+ return { line: anchors.firstRemoved, side: 'LEFT' };
160
+ return null;
161
+ }
162
+ // Extract a small unified-diff window around a finding's (path, line, side), to
163
+ // show the covered code in context. Walks the diff like buildAnchorIndex,
164
+ // tracking new/old line counters, then slices ±ctx body lines around the match
165
+ // and prepends the containing hunk header. Returns null if the line isn't found.
166
+ export function extractHunk(diff, path, line, side, ctx = 3) {
167
+ if (line == null)
168
+ return null;
169
+ let inFile = false;
170
+ let newLine = 0;
171
+ let oldLine = 0;
172
+ let hunkHeader = '';
173
+ let targetHunkHeader = '';
174
+ const body = [];
175
+ let targetIdx = -1;
176
+ for (const raw of diff.split('\n')) {
177
+ if (raw.startsWith('diff --git')) {
178
+ inFile = false;
179
+ continue;
180
+ }
181
+ if (raw.startsWith('+++ ')) {
182
+ inFile = parseDiffPath(raw.slice(4)) === path;
183
+ continue;
184
+ }
185
+ if (raw.startsWith('--- '))
186
+ continue;
187
+ if (!inFile)
188
+ continue;
189
+ const hunk = HUNK_RE.exec(raw);
190
+ if (hunk) {
191
+ oldLine = Number(hunk[1]);
192
+ newLine = Number(hunk[2]);
193
+ hunkHeader = raw;
194
+ continue;
195
+ }
196
+ const marker = raw[0];
197
+ let matches = false;
198
+ if (marker === '+')
199
+ matches = side === 'RIGHT' && newLine === line;
200
+ else if (marker === '-')
201
+ matches = side === 'LEFT' && oldLine === line;
202
+ else if (marker === ' ') {
203
+ matches =
204
+ (side === 'RIGHT' && newLine === line) ||
205
+ (side === 'LEFT' && oldLine === line);
206
+ }
207
+ body.push(raw);
208
+ if (matches && targetIdx === -1) {
209
+ targetIdx = body.length - 1;
210
+ targetHunkHeader = hunkHeader;
211
+ }
212
+ if (marker === '+')
213
+ newLine += 1;
214
+ else if (marker === '-')
215
+ oldLine += 1;
216
+ else if (marker === ' ') {
217
+ newLine += 1;
218
+ oldLine += 1;
219
+ }
220
+ }
221
+ if (targetIdx === -1)
222
+ return null;
223
+ const start = Math.max(0, targetIdx - ctx);
224
+ const end = Math.min(body.length, targetIdx + ctx + 1);
225
+ return [targetHunkHeader, ...body.slice(start, end)].filter(Boolean).join('\n');
226
+ }
227
+ //# sourceMappingURL=diff-anchor.js.map