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,288 @@
1
+ import { claudeExecutableOptions, loadAgentSdk } from '../ai/runtime.js';
2
+ import { config } from '../config.js';
3
+ import { getAccessToken } from '../auth/account.js';
4
+ import { applyClaudeReviewAuth } from '../review/auth.js';
5
+ import { cleanupCloneCache, prepWorktree, removeWorktreeLocked, } from '../review/clone-manager.js';
6
+ import { sdkModelOptions } from '../review/model-options.js';
7
+ import { estimateCostUsd } from '../review/pricing.js';
8
+ import { recordUsage, sumModelUsage, sumUsageMap, } from '../review/usage.js';
9
+ import { submitFixShape } from './schema.js';
10
+ import { captureWorktreeDiff } from './git.js';
11
+ import { describeAssistantBlocks } from './activity.js';
12
+ // The WRITE tool surface for the fixer: Read/Glob/Grep to explore, Write/Edit/MultiEdit to
13
+ // make the change, and the submit_fix MCP tool for the prose summary. NO SHELL.
14
+ //
15
+ // ---- Bash is deliberately ABSENT (this used to include it) ----
16
+ //
17
+ // Two independent reasons, either sufficient on its own.
18
+ //
19
+ // SAFETY — the argument the comment above `WORKTREE_TOOLS` in review/agent.ts already makes at
20
+ // length, for the identical input shape. Everything this agent reads (the PR title, the description, the diff, the review
21
+ // comments — and on the `'comments'` seed, NOTHING BUT review comments) was written by whoever
22
+ // opened the pull request. Pair that with `permissionMode:'bypassPermissions'` and
23
+ // `settingSources:[]` below, which is to say nothing else was constraining the shell either, and
24
+ // a stranger's PR text becomes a remote-code-execution path on the developer's own machine. The
25
+ // blocklist that used to sit here — `Bash(rm *)`, `Bash(sudo *)`, `Bash(git push *)`,
26
+ // `Bash(git commit *)`, `Bash(git config *)` — stopped five literal prefixes and nothing else:
27
+ // "A blocklist cannot enumerate the badness of a shell."
28
+ //
29
+ // ⚠ THOSE `Bash(git …)` ENTRIES WERE ALSO THE MECHANICAL HALF OF "THE HOST OWNS THE COMMIT, NOT
30
+ // THE AGENT", and that rule is unchanged — a denied shell cannot run git at all, so a bare
31
+ // 'Bash' guarantees it strictly harder. What is gone is the grep-able evidence, so it is written
32
+ // here instead: the agent leaves its edits in the working tree, `captureWorktreeDiff` turns them
33
+ // into a patch, and coding/git-ops.ts commits and pushes THAT — after the reader picks a target.
34
+ // The prompt still says it too (WORKTREE_RULES in the plugin's ai-fix/prompts.ts).
35
+ //
36
+ // SPEED — the shell's real use here was running builds and tests, and nothing downstream ever
37
+ // read the answer: runCodingAgent's success criterion is a captured diff under
38
+ // `aiFixPatchMaxBytes`, and no column on the fix row records whether anything was verified. The
39
+ // cost was real: a suite runs against `aiFixMaxTurns` (40) and `aiFixBudgetUsd` ($5) with NO
40
+ // wall-clock limit, returns its output as a tool_result billed as input on the next turn, and
41
+ // holds the single global job slot (MAX_CONCURRENT = 1, packages/pro/src/ai-fix/manager.ts) that
42
+ // every other account's fix queues behind.
43
+ //
44
+ // ⚠ What this costs, stated plainly: a fix that wanted a codegen step, a formatter, or `git log`
45
+ // for context must now write the edit by hand or decline. That is the accepted trade — Claude
46
+ // Review made the identical one. The way back is a container/VM boundary, or `canUseTool` under a
47
+ // non-bypass permission mode — NOT re-adding 'Bash' with a longer blocklist.
48
+ const FIX_TOOLS = [
49
+ 'Read',
50
+ 'Glob',
51
+ 'Grep',
52
+ 'Write',
53
+ 'Edit',
54
+ 'MultiEdit',
55
+ 'mcp__fix__submit_fix',
56
+ ];
57
+ // Denied OUTRIGHT rather than by command pattern, for the reasons above. Belt and braces: Bash is
58
+ // also absent from the allow list, so there are two independent reasons it cannot run.
59
+ const DISALLOWED_TOOLS = ['Bash', 'NotebookEdit'];
60
+ // Per-model effort + thinking options: ONE table in review/model-options.ts, shared with the
61
+ // review agent (Haiku 4.5 rejects `effort`; Opus 5.5 gets explicit adaptive thinking and 400s on
62
+ // disabled thinking / a thinking budget / a forced tool_choice, none of which is sent here).
63
+ const ACTIVITY_LOG_CAP = 25;
64
+ function emptyUsage() {
65
+ return {
66
+ inputTokens: 0,
67
+ outputTokens: 0,
68
+ cacheReadTokens: 0,
69
+ cacheCreationTokens: 0,
70
+ };
71
+ }
72
+ /**
73
+ * The Claude Agent SDK run core behind the fixer (runCodingAgent): it OWNS the sandbox
74
+ * config (`permissionMode:'bypassPermissions'`, `settingSources:[]`, budget/turn caps,
75
+ * whitelisted tools) and streams activity, but knows nothing about worktree prep, diff
76
+ * capture, or git — the caller owns those. (It also used to run AI Fix's agentic conflict
77
+ * resolver; that path was removed with the rest of AI Fix's trunk reconciliation.)
78
+ *
79
+ * Auth: prefers the ambient Claude session, else falls back to the user's local BYO
80
+ * Anthropic key — the SAME advanced-AI credential policy as Claude Review
81
+ * (applyClaudeReviewAuth), restored in `finally`. AI-Fix jobs are concurrency 1; the env
82
+ * mutation only bites when there's no ambient auth (a BYO-key-only setup), where it and a
83
+ * concurrent review would set the identical key.
84
+ */
85
+ export async function runAgentInWorktree(opts) {
86
+ const model = opts.model;
87
+ const usageByUuid = new Map();
88
+ let result = null;
89
+ const maxTurns = opts.maxTurns;
90
+ // 'worktree' ⇒ config.reviewEffort, exactly the effort this path always used.
91
+ const modelOptions = sdkModelOptions(model, 'worktree');
92
+ // Advanced-AI credential: ambient session preferred, else the local BYO key. Restored below.
93
+ const restoreEnv = applyClaudeReviewAuth(true);
94
+ try {
95
+ // From the AI runtime (ai/runtime.ts) — downloaded on first use for an npm install.
96
+ const { query } = await loadAgentSdk();
97
+ const q = query({
98
+ prompt: opts.prompt,
99
+ options: {
100
+ model,
101
+ ...modelOptions,
102
+ ...(opts.systemPrompt ? { systemPrompt: opts.systemPrompt } : {}),
103
+ cwd: opts.worktreePath,
104
+ permissionMode: 'bypassPermissions',
105
+ allowedTools: opts.allowedTools,
106
+ disallowedTools: opts.disallowedTools,
107
+ maxTurns,
108
+ maxBudgetUsd: opts.maxBudgetUsd,
109
+ settingSources: [],
110
+ mcpServers: opts.mcpServers,
111
+ abortController: opts.abortController,
112
+ // LIMN_CLAUDE_PATH → the user's own `claude` instead of the SDK's bundled binary.
113
+ ...claudeExecutableOptions(),
114
+ },
115
+ });
116
+ const activity = [];
117
+ const pushActivity = (line) => {
118
+ const trimmed = line.trim();
119
+ if (!trimmed)
120
+ return;
121
+ activity.push(trimmed);
122
+ if (activity.length > ACTIVITY_LOG_CAP)
123
+ activity.shift();
124
+ };
125
+ for await (const message of q) {
126
+ if (message.type === 'assistant') {
127
+ try {
128
+ recordUsage(usageByUuid, message);
129
+ }
130
+ catch {
131
+ /* usage shape varies — never let it break the run */
132
+ }
133
+ try {
134
+ for (const line of describeAssistantBlocks(message))
135
+ pushActivity(line);
136
+ }
137
+ catch {
138
+ /* never let progress derivation break the run */
139
+ }
140
+ const live = sumUsageMap(usageByUuid);
141
+ opts.onActivity?.([...activity], {
142
+ ...live,
143
+ estCostUsd: estimateCostUsd(model, live),
144
+ });
145
+ }
146
+ else if (message.type === 'result') {
147
+ result = message;
148
+ }
149
+ }
150
+ if (opts.abortController.signal.aborted) {
151
+ return {
152
+ result,
153
+ usage: emptyUsage(),
154
+ costUsd: null,
155
+ numTurns: null,
156
+ aborted: true,
157
+ };
158
+ }
159
+ const usage = sumModelUsage(result) ?? sumUsageMap(usageByUuid);
160
+ const hasUsage = usage.inputTokens + usage.outputTokens + usage.cacheReadTokens > 0;
161
+ const costUsd = result?.total_cost_usd ?? (hasUsage ? estimateCostUsd(model, usage) : null);
162
+ return {
163
+ result,
164
+ usage: {
165
+ inputTokens: usage.inputTokens,
166
+ outputTokens: usage.outputTokens,
167
+ cacheReadTokens: usage.cacheReadTokens,
168
+ cacheCreationTokens: usage.cacheCreationTokens,
169
+ },
170
+ costUsd,
171
+ numTurns: result?.num_turns ?? null,
172
+ aborted: false,
173
+ };
174
+ }
175
+ finally {
176
+ restoreEnv();
177
+ }
178
+ }
179
+ /**
180
+ * Run the write-capable coding agent against a PR's head in an ephemeral worktree and
181
+ * return the captured changeset (a binary-safe unified diff) + a prose summary. This
182
+ * is the implementation behind ctx.coding.generateFix; it owns the worktree prep +
183
+ * diff capture + teardown, and delegates the sandboxed SDK run to runAgentInWorktree.
184
+ * Never commits or pushes — the host's git-ops does that later from the STORED patch.
185
+ */
186
+ export async function runCodingAgent(args) {
187
+ const { owner, name, prNumber, baseSha, abortController, onProgress } = args;
188
+ const model = args.model;
189
+ const token = await getAccessToken(args.accountId);
190
+ let repoCloneDir = null;
191
+ let worktreePath = null;
192
+ try {
193
+ onProgress({ phase: 'cloning' });
194
+ ({ repoCloneDir, worktreePath } = await prepWorktree(owner, name, prNumber, baseSha, token));
195
+ const { createSdkMcpServer, tool } = await loadAgentSdk();
196
+ const fixShape = await submitFixShape();
197
+ let captured = null;
198
+ const server = createSdkMcpServer({
199
+ name: 'fix',
200
+ version: '1.0.0',
201
+ tools: [
202
+ tool('submit_fix', 'Report the fix you applied. Call this EXACTLY once, at the very end, after editing files.', fixShape, async (a) => {
203
+ const p = a;
204
+ captured = {
205
+ summary: p.summary,
206
+ commitMessage: p.commitMessage,
207
+ // Passed through verbatim; the AI Fix manager validates refs + clips text.
208
+ changes: p.changes,
209
+ unaddressed: p.unaddressed,
210
+ };
211
+ return { content: [{ type: 'text', text: 'Fix recorded.' }] };
212
+ }),
213
+ ],
214
+ });
215
+ onProgress({ phase: 'fixing' });
216
+ const outcome = await runAgentInWorktree({
217
+ worktreePath,
218
+ model,
219
+ systemPrompt: args.systemPrompt,
220
+ prompt: args.prompt,
221
+ allowedTools: FIX_TOOLS,
222
+ disallowedTools: DISALLOWED_TOOLS,
223
+ mcpServers: { fix: server },
224
+ maxTurns: args.maxTurns ?? config.aiFixMaxTurns,
225
+ maxBudgetUsd: args.maxBudgetUsd ?? config.aiFixBudgetUsd,
226
+ abortController,
227
+ onActivity: (activity, usage) => onProgress({ phase: 'fixing', recentActivity: activity, usage }),
228
+ });
229
+ // A user cancel aborts the SDK iterator; surface a clean aborted result (the
230
+ // manager marks the row cancelled — no worktree changes are captured).
231
+ if (outcome.aborted || abortController.signal.aborted) {
232
+ return {
233
+ summary: '',
234
+ commitMessage: '',
235
+ patch: '',
236
+ filesChanged: [],
237
+ baseSha,
238
+ usage: emptyUsage(),
239
+ costUsd: null,
240
+ numTurns: null,
241
+ aborted: true,
242
+ };
243
+ }
244
+ onProgress({ phase: 'capturing' });
245
+ const { patch, filesChanged } = await captureWorktreeDiff(worktreePath);
246
+ if (patch.length > config.aiFixPatchMaxBytes) {
247
+ throw new Error(`fix patch too large (${patch.length} bytes > ${config.aiFixPatchMaxBytes})`);
248
+ }
249
+ // A cast so the closure-assigned `captured` reads back as its declared union.
250
+ // (TS flow-narrows it to `null` because its only assignment is inside the tool
251
+ // callback, which it can't prove ran — a plain annotation wouldn't break that.)
252
+ const fix = captured;
253
+ return {
254
+ summary: fix?.summary ??
255
+ (filesChanged.length
256
+ ? `Applied changes to ${filesChanged.length} file(s).`
257
+ : 'The agent made no changes.'),
258
+ commitMessage: fix?.commitMessage ?? 'AI fix',
259
+ // Absent when the agent never called submit_fix (or reported neither list).
260
+ report: fix && (fix.changes || fix.unaddressed)
261
+ ? { changes: fix.changes, unaddressed: fix.unaddressed }
262
+ : undefined,
263
+ patch,
264
+ filesChanged,
265
+ baseSha,
266
+ usage: outcome.usage,
267
+ costUsd: outcome.costUsd,
268
+ numTurns: outcome.numTurns,
269
+ aborted: false,
270
+ };
271
+ }
272
+ finally {
273
+ if (repoCloneDir && worktreePath) {
274
+ await removeWorktreeLocked(owner, name, repoCloneDir, worktreePath).catch(() => { });
275
+ }
276
+ if (repoCloneDir) {
277
+ setImmediate(() => {
278
+ try {
279
+ cleanupCloneCache();
280
+ }
281
+ catch {
282
+ /* advisory cleanup — never surface */
283
+ }
284
+ });
285
+ }
286
+ }
287
+ }
288
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1,212 @@
1
+ // AUTO FIX — after an AUTO Claude review succeeds on the reader's OWN pull request, start ONE
2
+ // review-seeded AI Fix (CORE, free, local-only, like the rest of the agentic surface).
3
+ //
4
+ // THE GATE, in order (the first that fails decides; every skip is logged and kept in memory for the
5
+ // Claude Review tab's one line, `autoFixOutcomeFor`):
6
+ // 0. the PR's author IS the account's own GitHub user (pull_requests.author_id → users.github_login
7
+ // vs accounts.github_login, case-insensitive). Anyone else's PR: nothing happens and nothing is
8
+ // recorded — fixing someone else's branch is never automatic;
9
+ // 1. `nothing_to_fix` — the review's seed is empty (the same refusal as the button's NothingToFix);
10
+ // 2. `head_moved` — the PR's synced head is no longer the reviewed one (the next review decides);
11
+ // 3. `fix_in_progress` — a fix for this PR (auto or manual) is queued or running;
12
+ // 4. `fix_waiting` — a finished fix with changes, never pushed, sits on the PR's CURRENT head
13
+ // (the synced head, the REVIEWED head, or — only when an unpushed fix sits
14
+ // on neither — the LIVE head, so a lagging sync cannot hide one);
15
+ // 5. `cap` — AUTO_FIX_DAILY_CAP auto fixes already started on this PR in the last 24h;
16
+ // 6. `already_tried` — the latest auto fix AT THIS HEAD reported every item this review would
17
+ // send as not addressed (nobody has pushed since, so nothing changed).
18
+ // Then `startReviewFix(…, trigger: 'auto')` — the same queue, slot and worktree as the button.
19
+ //
20
+ // ⚠ NOTHING IS PUSHED. A fix waits for a person's Push like any other.
21
+ // ⚠ LOOP SAFETY. A pushed fix makes a new head, which earns an auto re-review, which may earn
22
+ // another fix. The chain needs a PERSON pressing Push at every turn (an unpushed fix blocks the next
23
+ // one, rule 4), and is bounded anyway by rule 5. Rule 6 stops the one loop that needs no push: a
24
+ // fix that changed nothing, re-tried at the same head on every comment-triggered review. Item
25
+ // identity across reviews is (kind, thread / story index, path, title) — a finding re-worded by a
26
+ // later review counts as new, so rule 6 can miss it; rule 5 still bounds it.
27
+ // ⚠ Never throws: an auto fix failing must never touch the review.
28
+ import { and, desc, eq, gte } from 'drizzle-orm';
29
+ import { AUTO_FIX_DAILY_CAP, CLAUDE_REVIEW_MODELS, DEFAULT_AI_FIX_MODEL, } from '../../shared/index.js';
30
+ import { isFixRunning, loadReviewSeed, startReviewFix } from './manager.js';
31
+ import { parseChangeReport, parseReviewItems } from './persist.js';
32
+ import { getFixPrContext } from './pr-context.js';
33
+ // At most AUTO_FIX_DAILY_CAP (shared) AUTO fixes per PR in any rolling AUTO_FIX_WINDOW_MS.
34
+ export { AUTO_FIX_DAILY_CAP };
35
+ export const AUTO_FIX_WINDOW_MS = 24 * 60 * 60 * 1000;
36
+ // reviewId → the outcome, with its owner. Bounded: the oldest entry goes first.
37
+ const OUTCOMES_MAX = 500;
38
+ const outcomes = new Map();
39
+ function record(accountId, outcome) {
40
+ outcomes.delete(outcome.reviewId);
41
+ outcomes.set(outcome.reviewId, { accountId, outcome });
42
+ while (outcomes.size > OUTCOMES_MAX) {
43
+ const first = outcomes.keys().next().value;
44
+ if (first === undefined)
45
+ break;
46
+ outcomes.delete(first);
47
+ }
48
+ }
49
+ /** The recorded auto-fix outcome of one review, for its owner only. */
50
+ export function autoFixOutcomeFor(reviewId, accountId) {
51
+ const o = outcomes.get(reviewId);
52
+ return o && o.accountId === accountId ? o.outcome : null;
53
+ }
54
+ /** Test hook. */
55
+ export function _resetAutoFixForTest() {
56
+ outcomes.clear();
57
+ }
58
+ /** Is the PR's author the account's own GitHub user? Unknown on either side ⇒ false. */
59
+ export async function prAuthorIsAccount(ctx, accountId, prId) {
60
+ const { pullRequests: prs, users, accounts } = ctx.schema;
61
+ const [author, account] = await Promise.all([
62
+ ctx.db
63
+ .select({ login: users.githubLogin })
64
+ .from(prs)
65
+ .innerJoin(users, eq(users.id, prs.authorId))
66
+ .where(and(eq(prs.id, prId), eq(prs.accountId, accountId)))
67
+ .limit(1)
68
+ .execute(),
69
+ ctx.db
70
+ .select({ login: accounts.githubLogin })
71
+ .from(accounts)
72
+ .where(eq(accounts.id, accountId))
73
+ .limit(1)
74
+ .execute(),
75
+ ]);
76
+ const a = author[0]?.login;
77
+ const b = account[0]?.login;
78
+ return !!a && !!b && a.toLowerCase() === b.toLowerCase();
79
+ }
80
+ /** One review item's identity ACROSS reviews (refs and finding ids are per review). */
81
+ export function autoFixItemKey(i) {
82
+ const kind = i.kind === 'earlier_finding' ? 'finding' : i.kind;
83
+ return [
84
+ kind,
85
+ i.threadId ?? '',
86
+ i.ticketIndex ?? '',
87
+ i.path ?? '',
88
+ i.title.trim().replace(/\s+/g, ' ').toLowerCase(),
89
+ ].join('|');
90
+ }
91
+ const toMs = (v) => v == null ? 0 : v instanceof Date ? v.getTime() : Number(v) * (Number(v) < 1e12 ? 1000 : 1);
92
+ /** One `GET /pulls/{n}`. Never throws (a failed read is "unknown", never "no fix waiting"). */
93
+ async function liveHeadSha(ctx, accountId, prId) {
94
+ try {
95
+ const pr = await getFixPrContext(ctx, accountId, prId);
96
+ if (!pr)
97
+ return null;
98
+ return (await ctx.github.fetchPrHeadInfo(accountId, pr.owner, pr.name, pr.number)).headSha ?? null;
99
+ }
100
+ catch {
101
+ return null;
102
+ }
103
+ }
104
+ const defaultDeps = { startReviewFix, loadReviewSeed, isFixRunning, liveHeadSha };
105
+ /**
106
+ * Called once per SUCCEEDED auto review (manager.ts). Returns what it did; never throws.
107
+ */
108
+ export async function maybeStartAutoFix(ctx, input, deps = defaultDeps, nowMs = Date.now()) {
109
+ const { accountId, prId, reviewId } = input;
110
+ const skip = (reason) => {
111
+ const outcome = { reviewId, status: 'skipped', reason };
112
+ record(accountId, outcome);
113
+ ctx.log.info(`auto fix pr ${prId} (review ${reviewId}) skipped: ${reason}`);
114
+ return outcome;
115
+ };
116
+ try {
117
+ if (!(await prAuthorIsAccount(ctx, accountId, prId)))
118
+ return { status: 'not_own' };
119
+ const loaded = await deps.loadReviewSeed(ctx, { accountId, prId, reviewId });
120
+ if (!loaded)
121
+ return skip('not_started');
122
+ if (loaded.seed.sentRefs.length === 0)
123
+ return skip('nothing_to_fix');
124
+ const { pullRequests: prs, aiFixes: af } = ctx.schema;
125
+ const prRow = (await ctx.db
126
+ .select({ headSha: prs.headSha })
127
+ .from(prs)
128
+ .where(and(eq(prs.id, prId), eq(prs.accountId, accountId)))
129
+ .limit(1)
130
+ .execute())[0];
131
+ const head = prRow?.headSha ?? null;
132
+ if (head && head !== loaded.review.headSha)
133
+ return skip('head_moved');
134
+ // The manager's in-memory claim is the authority (a queued/running ROW it no longer holds is an
135
+ // orphan the next boot reconciles).
136
+ if (deps.isFixRunning(prId))
137
+ return skip('fix_in_progress');
138
+ const fixes = (await ctx.db
139
+ .select({
140
+ id: af.id,
141
+ status: af.status,
142
+ baseSha: af.baseSha,
143
+ patch: af.patch,
144
+ pushedAt: af.pushedAt,
145
+ trigger: af.trigger,
146
+ createdAt: af.createdAt,
147
+ reviewItems: af.reviewItems,
148
+ changeReport: af.changeReport,
149
+ })
150
+ .from(af)
151
+ .where(and(eq(af.accountId, accountId), eq(af.prId, prId)))
152
+ .orderBy(desc(af.id))
153
+ .execute());
154
+ // "Nobody has pushed since": the fix was built on the head the PR still has. The SYNCED head
155
+ // can lag (or be unsynced) while the fixer builds on the LIVE head, so the reviewed head counts
156
+ // too, and the live head is asked for — once, only when an unpushed fix sits on neither.
157
+ const heads = new Set();
158
+ if (head)
159
+ heads.add(head);
160
+ if (loaded.review.headSha)
161
+ heads.add(loaded.review.headSha);
162
+ const atHead = (f) => heads.has(f.baseSha);
163
+ const waiting = fixes.filter((f) => f.status === 'succeeded' && f.pushedAt == null && (f.patch ?? '').trim() !== '');
164
+ if (waiting.length > 0 && !waiting.some(atHead) && deps.liveHeadSha) {
165
+ const live = await deps.liveHeadSha(ctx, accountId, prId);
166
+ if (live)
167
+ heads.add(live);
168
+ }
169
+ if (waiting.some(atHead))
170
+ return skip('fix_waiting');
171
+ const since = nowMs - AUTO_FIX_WINDOW_MS;
172
+ const recentAuto = fixes.filter((f) => f.trigger === 'auto' && toMs(f.createdAt) >= since);
173
+ if (recentAuto.length >= AUTO_FIX_DAILY_CAP)
174
+ return skip('cap');
175
+ // Rule 6: the latest auto fix at this head said "not addressed" to everything we would send.
176
+ const lastAutoHere = fixes.find((f) => f.trigger === 'auto' && f.status === 'succeeded' && atHead(f));
177
+ if (lastAutoHere) {
178
+ const items = parseReviewItems(lastAutoHere.reviewItems) ?? [];
179
+ const report = parseChangeReport(lastAutoHere.changeReport);
180
+ const byRef = new Map(items.map((i) => [i.ref, i]));
181
+ const refused = new Set((report?.unaddressed ?? []).flatMap((u) => {
182
+ const i = byRef.get(u.ref);
183
+ return i ? [autoFixItemKey(i)] : [];
184
+ }));
185
+ const sent = new Set(loaded.seed.sentRefs);
186
+ const now = loaded.seed.items.filter((i) => sent.has(i.ref)).map(autoFixItemKey);
187
+ if (now.length > 0 && now.every((k) => refused.has(k)))
188
+ return skip('already_tried');
189
+ }
190
+ const model = CLAUDE_REVIEW_MODELS.includes(loaded.review.model)
191
+ ? loaded.review.model
192
+ : DEFAULT_AI_FIX_MODEL;
193
+ const r = await deps.startReviewFix(ctx, { accountId, prId, reviewId, model, trigger: 'auto' });
194
+ if (r.status === 'queued') {
195
+ const outcome = { reviewId, status: 'started', fixId: r.fixId };
196
+ record(accountId, outcome);
197
+ ctx.log.info(`auto fix pr ${prId} (review ${reviewId}) started: fix ${r.fixId}`);
198
+ return outcome;
199
+ }
200
+ if (r.status === 'nothing_to_fix')
201
+ return skip('nothing_to_fix');
202
+ if (r.status === 'already_running')
203
+ return skip('fix_in_progress');
204
+ ctx.log.info(`auto fix pr ${prId} (review ${reviewId}) not started: ${r.status}`);
205
+ return skip('not_started');
206
+ }
207
+ catch (err) {
208
+ ctx.log.warn(`auto fix pr ${prId} (review ${reviewId}) failed to start: ${err instanceof Error ? err.message : String(err)}`);
209
+ return skip('not_started');
210
+ }
211
+ }
212
+ //# sourceMappingURL=auto-fix.js.map