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