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,304 @@
1
+ /**
2
+ * Myers O(ND) with the linear-space divide-and-conquer refinement, common prefix and suffix
3
+ * trimmed at every level.
4
+ *
5
+ * `maxD` is a BUDGET over the whole recursion, not per call: a pathological pair (a file
6
+ * rewritten wholesale) would otherwise spend minutes proving what a single whole-file region
7
+ * says just as well. Returns `null` when the budget runs out — the caller degrades that file
8
+ * to one conflict spanning everything, which is honest and still resolvable.
9
+ */
10
+ export function diffTokens(a, b, maxD) {
11
+ const out = [];
12
+ const budget = { left: Math.max(1, maxD) };
13
+ if (!bisectInto(a, b, 0, a.length, 0, b.length, out, budget))
14
+ return null;
15
+ return coalesce(out);
16
+ }
17
+ /** Merge changes that touch, so the caller never sees two adjacent ranges with nothing
18
+ * between them. The recursion can produce those at a split point. */
19
+ function coalesce(changes) {
20
+ const out = [];
21
+ for (const c of changes) {
22
+ const prev = out[out.length - 1];
23
+ if (prev && prev.aEnd === c.aStart && prev.bEnd === c.bStart) {
24
+ prev.aEnd = c.aEnd;
25
+ prev.bEnd = c.bEnd;
26
+ continue;
27
+ }
28
+ out.push({ ...c });
29
+ }
30
+ return out.filter((c) => c.aEnd > c.aStart || c.bEnd > c.bStart);
31
+ }
32
+ function bisectInto(a, b, a0, a1, b0, b1, out, budget) {
33
+ // Trim the common prefix and suffix first: it is what keeps `d` small on a real edit, and
34
+ // it is also what makes the base cases below reachable at all.
35
+ while (a0 < a1 && b0 < b1 && a[a0] === b[b0]) {
36
+ a0++;
37
+ b0++;
38
+ }
39
+ while (a0 < a1 && b0 < b1 && a[a1 - 1] === b[b1 - 1]) {
40
+ a1--;
41
+ b1--;
42
+ }
43
+ if (a0 === a1 && b0 === b1)
44
+ return true;
45
+ if (a0 === a1 || b0 === b1) {
46
+ // Pure insertion or pure deletion — nothing left to align.
47
+ out.push({ aStart: a0, aEnd: a1, bStart: b0, bEnd: b1 });
48
+ return true;
49
+ }
50
+ const split = middleSnake(a, b, a0, a1, b0, b1, budget);
51
+ if (split.kind === 'budget')
52
+ return false;
53
+ if (split.kind === 'replace') {
54
+ // The frontiers never met inside `max`, which for a correct Myers should not happen.
55
+ // Falling back to a whole-range replacement is coarser than optimal but never WRONG,
56
+ // and it is a great deal better than reporting a wrong split.
57
+ out.push({ aStart: a0, aEnd: a1, bStart: b0, bEnd: b1 });
58
+ return true;
59
+ }
60
+ if (!bisectInto(a, b, a0, split.x, b0, split.y, out, budget))
61
+ return false;
62
+ if (!bisectInto(a, b, split.x, a1, split.y, b1, out, budget))
63
+ return false;
64
+ return true;
65
+ }
66
+ /**
67
+ * Find the middle snake of the optimal edit script (Myers §4b) — the forward and reverse
68
+ * frontiers advance one `d` at a time until they overlap, and the overlap point splits the
69
+ * problem in half with O(N+M) memory.
70
+ */
71
+ function middleSnake(a, b, a0, a1, b0, b1, budget) {
72
+ const n = a1 - a0;
73
+ const m = b1 - b0;
74
+ const max = Math.ceil((n + m) / 2);
75
+ const offset = max;
76
+ const len = 2 * max + 2;
77
+ const vf = new Int32Array(len).fill(-1);
78
+ const vr = new Int32Array(len).fill(-1);
79
+ vf[offset + 1] = 0;
80
+ vr[offset + 1] = 0;
81
+ const delta = n - m;
82
+ // When delta is odd the frontiers can only meet on a FORWARD step, and vice versa.
83
+ const front = (delta & 1) !== 0;
84
+ let k1start = 0;
85
+ let k1end = 0;
86
+ let k2start = 0;
87
+ let k2end = 0;
88
+ // ⚠ `d <= max`, not `d < max`. The frontiers meet at `d = ceil(D/2)` and `D` can be the
89
+ // full `n + m` — a one-token replacement is D = 2, max = 1, and a `d < max` loop never
90
+ // runs the step that finds it. That off-by-one turns every small edit into a whole-range
91
+ // replacement, which still merges correctly and reads as one enormous conflict on screen.
92
+ for (let d = 0; d <= max; d++) {
93
+ if (budget.left-- <= 0)
94
+ return { kind: 'budget' };
95
+ for (let k1 = -d + k1start; k1 <= d - k1end; k1 += 2) {
96
+ const k1off = offset + k1;
97
+ let x1;
98
+ if (k1 === -d || (k1 !== d && (vf[k1off - 1] ?? -1) < (vf[k1off + 1] ?? -1))) {
99
+ x1 = vf[k1off + 1] ?? 0;
100
+ }
101
+ else {
102
+ x1 = (vf[k1off - 1] ?? 0) + 1;
103
+ }
104
+ let y1 = x1 - k1;
105
+ while (x1 < n && y1 < m && a[a0 + x1] === b[b0 + y1]) {
106
+ x1++;
107
+ y1++;
108
+ }
109
+ vf[k1off] = x1;
110
+ if (x1 > n) {
111
+ k1end += 2;
112
+ }
113
+ else if (y1 > m) {
114
+ k1start += 2;
115
+ }
116
+ else if (front) {
117
+ const k2off = offset + delta - k1;
118
+ if (k2off >= 0 && k2off < len && (vr[k2off] ?? -1) !== -1) {
119
+ const x2 = n - (vr[k2off] ?? 0);
120
+ if (x1 >= x2)
121
+ return { kind: 'split', x: a0 + x1, y: b0 + y1 };
122
+ }
123
+ }
124
+ }
125
+ for (let k2 = -d + k2start; k2 <= d - k2end; k2 += 2) {
126
+ const k2off = offset + k2;
127
+ let x2;
128
+ if (k2 === -d || (k2 !== d && (vr[k2off - 1] ?? -1) < (vr[k2off + 1] ?? -1))) {
129
+ x2 = vr[k2off + 1] ?? 0;
130
+ }
131
+ else {
132
+ x2 = (vr[k2off - 1] ?? 0) + 1;
133
+ }
134
+ let y2 = x2 - k2;
135
+ while (x2 < n && y2 < m && a[a0 + n - x2 - 1] === b[b0 + m - y2 - 1]) {
136
+ x2++;
137
+ y2++;
138
+ }
139
+ vr[k2off] = x2;
140
+ if (x2 > n) {
141
+ k2end += 2;
142
+ }
143
+ else if (y2 > m) {
144
+ k2start += 2;
145
+ }
146
+ else if (!front) {
147
+ const k1off = offset + delta - k2;
148
+ if (k1off >= 0 && k1off < len && (vf[k1off] ?? -1) !== -1) {
149
+ const x1 = vf[k1off] ?? 0;
150
+ const y1 = x1 - (k1off - offset);
151
+ if (x1 >= n - x2)
152
+ return { kind: 'split', x: a0 + x1, y: b0 + y1 };
153
+ }
154
+ }
155
+ }
156
+ }
157
+ return { kind: 'replace' };
158
+ }
159
+ function toHunks(changes) {
160
+ return changes.map((c) => ({
161
+ baseStart: c.aStart,
162
+ baseEnd: c.aEnd,
163
+ sideStart: c.bStart,
164
+ sideEnd: c.bEnd,
165
+ }));
166
+ }
167
+ /**
168
+ * The classic diff3 chunker. Takes both sides' diffs AGAINST THE BASE and produces one
169
+ * ordered region list covering the base end to end.
170
+ *
171
+ * ⚠ ADJACENT CHANGES ABSORB INTO ONE REGION (`hunk.baseStart <= hi`, zero unchanged tokens
172
+ * between). Two edits that touch are one contested region: offering them separately lets the
173
+ * reader take ours from the first and theirs from the second and produce text neither author
174
+ * wrote.
175
+ *
176
+ * ⚠ `both_same` is a real kind and is NOT collapsed into `ours_only`. Collapsing it makes the
177
+ * wand's "what I did" count wrong — it settled nothing there, both authors already agreed.
178
+ */
179
+ export function threeWayChunks(base, ours, theirs, oursChanges, theirsChanges) {
180
+ const oursHunks = toHunks(oursChanges);
181
+ const theirsHunks = toHunks(theirsChanges);
182
+ const regions = [];
183
+ let i = 0;
184
+ let j = 0;
185
+ let basePos = 0;
186
+ while (i < oursHunks.length || j < theirsHunks.length) {
187
+ const nextOurs = oursHunks[i];
188
+ const nextTheirs = theirsHunks[j];
189
+ let lo;
190
+ if (nextOurs && nextTheirs)
191
+ lo = Math.min(nextOurs.baseStart, nextTheirs.baseStart);
192
+ else if (nextOurs)
193
+ lo = nextOurs.baseStart;
194
+ else if (nextTheirs)
195
+ lo = nextTheirs.baseStart;
196
+ else
197
+ break;
198
+ let hi = lo;
199
+ const groupOurs = [];
200
+ const groupTheirs = [];
201
+ // Absorb every hunk from either side that starts at or before the group's current end.
202
+ for (;;) {
203
+ const o = oursHunks[i];
204
+ const t = theirsHunks[j];
205
+ if (o && o.baseStart <= hi) {
206
+ groupOurs.push(o);
207
+ hi = Math.max(hi, o.baseEnd);
208
+ i++;
209
+ continue;
210
+ }
211
+ if (t && t.baseStart <= hi) {
212
+ groupTheirs.push(t);
213
+ hi = Math.max(hi, t.baseEnd);
214
+ j++;
215
+ continue;
216
+ }
217
+ break;
218
+ }
219
+ if (lo > basePos) {
220
+ regions.push(unchangedRegion(basePos, lo, oursHunks, theirsHunks));
221
+ }
222
+ const oursRange = mapRange(lo, hi, groupOurs, oursHunks);
223
+ const theirsRange = mapRange(lo, hi, groupTheirs, theirsHunks);
224
+ const kind = classify(base.slice(lo, hi), ours.slice(oursRange.start, oursRange.end), theirs.slice(theirsRange.start, theirsRange.end));
225
+ regions.push({
226
+ kind,
227
+ baseStart: lo,
228
+ baseEnd: hi,
229
+ oursStart: oursRange.start,
230
+ oursEnd: oursRange.end,
231
+ theirsStart: theirsRange.start,
232
+ theirsEnd: theirsRange.end,
233
+ });
234
+ basePos = hi;
235
+ }
236
+ if (basePos < base.length) {
237
+ regions.push(unchangedRegion(basePos, base.length, oursHunks, theirsHunks));
238
+ }
239
+ return regions;
240
+ }
241
+ function unchangedRegion(lo, hi, oursHunks, theirsHunks) {
242
+ const o = mapRange(lo, hi, [], oursHunks);
243
+ const t = mapRange(lo, hi, [], theirsHunks);
244
+ return {
245
+ kind: 'unchanged',
246
+ baseStart: lo,
247
+ baseEnd: hi,
248
+ oursStart: o.start,
249
+ oursEnd: o.end,
250
+ theirsStart: t.start,
251
+ theirsEnd: t.end,
252
+ };
253
+ }
254
+ /**
255
+ * Map a base range onto one side.
256
+ *
257
+ * With hunks in the group, the group's own first and last hunk anchor it: the run between
258
+ * `lo` and the first hunk's start is unchanged on this side, so it shifts by the same amount,
259
+ * and likewise at the tail. Without any, the whole range is unchanged on this side and the
260
+ * mapping is the cumulative offset of every hunk that ended before `lo`.
261
+ */
262
+ function mapRange(lo, hi, group, allHunks) {
263
+ const first = group[0];
264
+ const last = group[group.length - 1];
265
+ if (first && last) {
266
+ return {
267
+ start: first.sideStart - (first.baseStart - lo),
268
+ end: last.sideEnd + (hi - last.baseEnd),
269
+ };
270
+ }
271
+ let offset = 0;
272
+ for (const h of allHunks) {
273
+ if (h.baseEnd <= lo)
274
+ offset += h.sideEnd - h.sideStart - (h.baseEnd - h.baseStart);
275
+ else
276
+ break;
277
+ }
278
+ return { start: lo + offset, end: hi + offset };
279
+ }
280
+ function sameTokens(a, b) {
281
+ if (a.length !== b.length)
282
+ return false;
283
+ for (let k = 0; k < a.length; k++)
284
+ if (a[k] !== b[k])
285
+ return false;
286
+ return true;
287
+ }
288
+ /** Classify by CONTENT, not by which hunk lists contributed. After absorption a group can
289
+ * hold a hunk from a side whose net text is identical to the base's, and calling that a
290
+ * change would show the reader a choice between two identical things. */
291
+ function classify(base, ours, theirs) {
292
+ const oursSame = sameTokens(base, ours);
293
+ const theirsSame = sameTokens(base, theirs);
294
+ if (oursSame && theirsSame)
295
+ return 'unchanged';
296
+ if (theirsSame)
297
+ return 'ours_only';
298
+ if (oursSame)
299
+ return 'theirs_only';
300
+ if (sameTokens(ours, theirs))
301
+ return 'both_same';
302
+ return 'conflict';
303
+ }
304
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1,118 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ const execFileAsync = promisify(execFile);
4
+ /**
5
+ * The git environment for EVERY command the conflict resolver runs — discovery and landing
6
+ * alike. Stricter than `coding/merge.ts`'s GIT_ENV on purpose.
7
+ *
8
+ * A developer's global git config must not change what we COMPUTE or what we COMMIT:
9
+ * `merge.conflictStyle`, `diff.algorithm`, `diff.renames` and custom merge drivers all move
10
+ * the answer. MEASURED: the same `merge-tree` on the same two commits wrote tree 0bc8605
11
+ * with global config nulled and bf04533 with `merge.conflictStyle=zdiff3`.
12
+ *
13
+ * ⚠ EXPORTED because the land path seeds from merge-tree's tree — the user must not review
14
+ * one merge and push another. In-tree `.gitattributes` stays honoured on purpose: it is part
15
+ * of the repository, and turning it off would change how the repo's own owners merge.
16
+ */
17
+ export const CONFLICT_GIT_ENV = {
18
+ ...process.env,
19
+ GIT_TERMINAL_PROMPT: '0',
20
+ GIT_EDITOR: 'true',
21
+ GIT_CONFIG_GLOBAL: '/dev/null',
22
+ GIT_CONFIG_SYSTEM: '/dev/null',
23
+ GIT_ATTR_NOSYSTEM: '1',
24
+ GIT_OPTIONAL_LOCKS: '0',
25
+ GIT_ADVICE: '0',
26
+ };
27
+ // `merge-tree -z`, `diff-tree -z` and `cat-file --batch` are NUL-delimited and byte-oriented,
28
+ // and blobs are arbitrary bytes. Decoding stdout to a string anywhere in this pipeline is how
29
+ // a Latin-1 file becomes U+FFFD, so stdout is a Buffer the whole way down and only the strict
30
+ // UTF-8 gate in model.ts is allowed to turn bytes into text.
31
+ const MAX_BUFFER = 256 * 1024 * 1024;
32
+ const TIMEOUT_MS = 120_000;
33
+ /** Run git, throwing on a non-zero exit (for the commands that MUST succeed). */
34
+ export async function git(args, cwd, stdin, env) {
35
+ const res = await gitTry(args, cwd, stdin, env);
36
+ if (res.code !== 0) {
37
+ throw new Error(`git ${args.slice(0, 3).join(' ')} failed (${res.code}): ${res.stderr.slice(0, 500)}`);
38
+ }
39
+ return { stdout: res.stdout, stderr: res.stderr };
40
+ }
41
+ /**
42
+ * Run git WITHOUT throwing; returns the exit code plus output.
43
+ *
44
+ * `env` is MERGED OVER `CONFLICT_GIT_ENV`, for the two variables the land path needs and
45
+ * that have no command-line equivalent: `GIT_INDEX_FILE` (the scratch index every tree is
46
+ * built in, so the shared clone's own index is never touched) and `GIT_AUTHOR_*` (a rebased
47
+ * commit keeps the original author while the account is the committer).
48
+ *
49
+ * ⚠ Several commands here exit non-zero on complete success — `merge-tree` exits 1 when it
50
+ * finds conflicts, and the by-OID prefetch exits non-zero even when every object landed.
51
+ * Callers branch on the OUTPUT, never on the code alone.
52
+ */
53
+ export async function gitTry(args, cwd, stdin, env) {
54
+ return new Promise((resolve, reject) => {
55
+ const child = execFile('git', args, {
56
+ cwd,
57
+ // ⚠ The overrides go AFTER the constant, never before: `GIT_INDEX_FILE` and the
58
+ // `GIT_AUTHOR_*` ident the land path sets must be additions to the hardened env, not
59
+ // a replacement for it. A caller cannot re-open `GIT_CONFIG_GLOBAL` by accident, only
60
+ // deliberately, and nothing does.
61
+ env: env ? { ...CONFLICT_GIT_ENV, ...env } : CONFLICT_GIT_ENV,
62
+ timeout: TIMEOUT_MS,
63
+ maxBuffer: MAX_BUFFER,
64
+ encoding: 'buffer',
65
+ }, (err, stdout, stderr) => {
66
+ const out = Buffer.isBuffer(stdout) ? stdout : Buffer.from(String(stdout));
67
+ const errText = Buffer.isBuffer(stderr) ? stderr.toString('utf8') : String(stderr);
68
+ if (err) {
69
+ const code = err.code;
70
+ // A numeric `code` is git's exit status. A string one (ENOENT, ETIMEDOUT) means the
71
+ // process never ran or was killed, which is a real failure, not a git verdict.
72
+ if (typeof code === 'number') {
73
+ resolve({ code, stdout: out, stderr: errText });
74
+ return;
75
+ }
76
+ reject(err);
77
+ return;
78
+ }
79
+ resolve({ code: 0, stdout: out, stderr: errText });
80
+ });
81
+ if (stdin !== undefined) {
82
+ child.stdin?.end(stdin);
83
+ }
84
+ });
85
+ }
86
+ /**
87
+ * `git merge-tree --write-tree` needs git 2.38. Probed ONCE per process and memoised — the
88
+ * open route turns a false into `git_too_old` and the overlay prints it once.
89
+ *
90
+ * ⚠ This is NOT on `/api/me`. `MeResponse.conflictResolver` is `!config.isCloud` and shells
91
+ * out to nothing; probing git on every SPA boot to answer a question the open route can
92
+ * answer once is the trade this replaced.
93
+ */
94
+ let versionProbe = null;
95
+ export function gitSupportsMergeTree(cwd = process.cwd()) {
96
+ versionProbe ??= (async () => {
97
+ try {
98
+ const { stdout } = await gitTry(['--version'], cwd);
99
+ const m = /git version (\d+)\.(\d+)/.exec(stdout.toString('utf8'));
100
+ if (!m)
101
+ return false;
102
+ const major = Number(m[1]);
103
+ const minor = Number(m[2]);
104
+ if (!Number.isFinite(major) || !Number.isFinite(minor))
105
+ return false;
106
+ return major > 2 || (major === 2 && minor >= 38);
107
+ }
108
+ catch {
109
+ return false;
110
+ }
111
+ })();
112
+ return versionProbe;
113
+ }
114
+ /** Test seam only: forget the memoised probe. */
115
+ export function resetGitVersionProbe() {
116
+ versionProbe = null;
117
+ }
118
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1,73 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { CONFLICT_MODEL_VERSION } from '../shared/index.js';
3
+ /**
4
+ * The model hash. Echoed on the commit body; a mismatch is `ModelStale` and nothing is
5
+ * written, because a decision made against different bytes is not a decision.
6
+ *
7
+ * ⚠ `CONFLICT_MODEL_VERSION` IS FOLDED IN, so a change to the fold or the chunker
8
+ * self-invalidates every live session rather than landing bytes the user did not choose —
9
+ * the `PERIOD_METRICS_SCHEMA_VERSION` discipline.
10
+ *
11
+ * ⚠ ONLY MODEL FACTS GO IN. Nothing `Date.now()`-derived, nothing hydrated, nothing that
12
+ * depends on how the session was OPENED: `autoApply` changes which decision a region starts
13
+ * on, not what the region IS, and folding it in would make the same model hash two different
14
+ * values depending on a checkbox.
15
+ */
16
+ export function conflictModelHash(model) {
17
+ const h = createHash('sha256');
18
+ const put = (s) => {
19
+ h.update(s);
20
+ h.update('\0');
21
+ };
22
+ put(`v${CONFLICT_MODEL_VERSION}`);
23
+ put(model.headSha);
24
+ put(model.baseSha);
25
+ put(model.mergedTreeSha);
26
+ put(model.mergeBaseSha ?? '');
27
+ put(model.mergeBaseIsVirtual ? '1' : '0');
28
+ put(String(model.totalConflictedPaths));
29
+ put(model.truncated ? '1' : '0');
30
+ put(model.renameDetection);
31
+ for (const f of model.files) {
32
+ put(String(f.index));
33
+ put(f.path);
34
+ put(f.unsupported ?? '');
35
+ put(f.stage2Mode ?? '');
36
+ put(`${f.terminators.base ? 1 : 0}${f.terminators.ours ? 1 : 0}${f.terminators.theirs ? 1 : 0}`);
37
+ put(String(f.regions.length));
38
+ for (const r of f.regions) {
39
+ put(String(r.id));
40
+ put(r.kind);
41
+ // The fingerprint already covers all three sides' bytes, so hashing it rather than the
42
+ // lines keeps this linear in region count instead of in file size.
43
+ put(r.fingerprint);
44
+ put(r.wand?.decision ?? '');
45
+ put(r.wand?.reason ?? '');
46
+ put(r.mergedLines === null ? '' : regionMergeDigest(r));
47
+ }
48
+ }
49
+ return h.digest('hex');
50
+ }
51
+ function regionMergeDigest(region) {
52
+ const h = createHash('sha256');
53
+ for (const line of region.mergedLines ?? []) {
54
+ h.update(line);
55
+ h.update('\0');
56
+ }
57
+ return h.digest('hex');
58
+ }
59
+ /** sha256 of `base \0 ours \0 theirs`. The CONTENT pin the Pro suggestion route checks
60
+ * against the id's ADDRESS — a region can keep its id while its bytes move only if the
61
+ * whole model was rebuilt, and then this differs. */
62
+ export function regionFingerprint(base, ours, theirs) {
63
+ const h = createHash('sha256');
64
+ for (const side of [base, ours, theirs]) {
65
+ for (const line of side) {
66
+ h.update(line);
67
+ h.update('\n');
68
+ }
69
+ h.update('\0');
70
+ }
71
+ return h.digest('hex');
72
+ }
73
+ //# sourceMappingURL=hash.js.map