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,36 @@
|
|
|
1
|
+
import { and, eq } from 'drizzle-orm';
|
|
2
|
+
import { db, schema } from './client.js';
|
|
3
|
+
import { blastSignalsFor } from './blast-radius.js';
|
|
4
|
+
import { hubReadingFor, loadRepoCoupling } from './file-coupling.js';
|
|
5
|
+
// The one-PR blast-radius read, for the Pro `impact` annotation's grounding (ctx.queries
|
|
6
|
+
// .getBlastSignals). Deliberately NOT in queries.ts: that file contains literal NUL bytes around
|
|
7
|
+
// offset 132k, so `rg`/`grep` silently under-report matches in it, and a seam the plugin depends
|
|
8
|
+
// on should be greppable.
|
|
9
|
+
//
|
|
10
|
+
// ⚠ OWNERSHIP-SCOPED, and the scope is on the PR row itself (`pullRequests.accountId`), not a
|
|
11
|
+
// join to repos — an id from a request body reaching a foreign PR here would let a caller spend
|
|
12
|
+
// their own credits describing someone else's diff. A foreign or unknown id resolves to null and
|
|
13
|
+
// the caller 404s, the same rule every id-addressed getter in this app follows.
|
|
14
|
+
export async function getBlastSignalsForPr(accountId, prId) {
|
|
15
|
+
const { pullRequests } = schema;
|
|
16
|
+
const rows = await db
|
|
17
|
+
.select({
|
|
18
|
+
repoId: pullRequests.repoId,
|
|
19
|
+
files: pullRequests.files,
|
|
20
|
+
additions: pullRequests.additions,
|
|
21
|
+
deletions: pullRequests.deletions,
|
|
22
|
+
changedFiles: pullRequests.changedFiles,
|
|
23
|
+
})
|
|
24
|
+
.from(pullRequests)
|
|
25
|
+
.where(and(eq(pullRequests.accountId, accountId), eq(pullRequests.id, prId)))
|
|
26
|
+
.limit(1)
|
|
27
|
+
.execute();
|
|
28
|
+
const pr = rows[0];
|
|
29
|
+
if (!pr)
|
|
30
|
+
return null;
|
|
31
|
+
const coupling = await loadRepoCoupling(accountId, [pr.repoId]);
|
|
32
|
+
// ⚠ null here is the SAME "we never measured this pull request" the chip renders nothing for.
|
|
33
|
+
// The caller must skip rather than describe a diff nobody measured.
|
|
34
|
+
return blastSignalsFor(pr, hubReadingFor(pr.files, coupling.get(pr.repoId)));
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=blast-radius-query.js.map
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { codeLocFor, isNonCodeFile, PR_FILES_PAGE_CAP } from './code-loc.js';
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// BLAST RADIUS — how far a pull request can REACH, folded from its stored files
|
|
4
|
+
// ============================================================================
|
|
5
|
+
//
|
|
6
|
+
// The second, ORTHOGONAL reading beside the large-PR flag. Size is a weak proxy for risk: a
|
|
7
|
+
// 2,000-line lockfile bump is trivial and a four-line change to a database migration is not.
|
|
8
|
+
// This module produces the EVIDENCE VECTOR; it never decides a level. The level is decided by
|
|
9
|
+
// exactly one function, `blastRadius()` in the SPA's `lib/ui.ts`, so that changing the
|
|
10
|
+
// sensitivity dial in Settings repaints every surface with no cache invalidation anywhere.
|
|
11
|
+
//
|
|
12
|
+
// ---- WHY THIS IS NOT THE CLAUDE REVIEW ROUTER ------------------------------
|
|
13
|
+
//
|
|
14
|
+
// `decideReviewMode` (packages/pro/src/claude-review/routing.ts) asks a genuinely similar
|
|
15
|
+
// question — "can this be reviewed from the diff alone?" — and its SHAPE is the ancestor of the
|
|
16
|
+
// arms below (file / line / directory / subsystem ceilings, a contract-touch signal,
|
|
17
|
+
// `allFilesNew`). It cannot be CALLED here, for three structural reasons:
|
|
18
|
+
//
|
|
19
|
+
// 1. It runs on the DIFF BODY — `analyzeDiff` over the noise-stripped unified diff that
|
|
20
|
+
// `review/prepare.ts` fetches through the `gh` CLI. That is a GitHub call per pull request,
|
|
21
|
+
// and NOTHING ON THE PENDING BOARD MAY FETCH ON MOUNT (fifty cards would be ~150 calls to
|
|
22
|
+
// paint a screen). This module reads columns that are already on the row.
|
|
23
|
+
// 2. Claude Review is LOCAL-ONLY and force-disabled in cloud. Blast radius works in both modes.
|
|
24
|
+
// 3. Its gate is deliberately OVER-conservative — any ambiguity routes to `worktree` — because
|
|
25
|
+
// over-routing there only costs money. Over-routing HERE marks everything `high` and the
|
|
26
|
+
// feature stops meaning anything.
|
|
27
|
+
//
|
|
28
|
+
// ⚠ FOR THE SAME REASONS IT MUST NOT IMPORT `NOISE_GLOBS` OR `API_PATH_PATTERNS`. Both live in
|
|
29
|
+
// `review/prepare.ts` and both are tuned for a paid agent's diff budget, where over-matching is
|
|
30
|
+
// SAFE. Over-matching here is a false claim on screen. Editing either to suit this feature would
|
|
31
|
+
// silently change what Claude Review reviews, with no test to catch it.
|
|
32
|
+
//
|
|
33
|
+
// ---- THE FOUR PATH CLASSIFIERS, AND WHY NONE MAY BE FOLDED INTO ANOTHER -----
|
|
34
|
+
//
|
|
35
|
+
// `db/code-loc.ts` documents the first three. This is the fourth, and the same rule applies:
|
|
36
|
+
// they answer four different questions and are NOT meant to agree.
|
|
37
|
+
//
|
|
38
|
+
// 1. `NOISE_GLOBS` (review/prepare.ts) — "strip this from the diff the paid AGENT reads?"
|
|
39
|
+
// 2. `isLockFile` (frontend lib/diff) — "start this file's diff COLLAPSED?"
|
|
40
|
+
// 3. `isNonCodeFile` (db/code-loc.ts) — "does this churn count as CODE a human must read?"
|
|
41
|
+
// 4. `BLAST_SURFACES` + `isTestFile` (HERE) — "do this file's CONSUMERS LIVE OUTSIDE THE DIFF?"
|
|
42
|
+
//
|
|
43
|
+
// Number 4 is the only one asking about REACH rather than volume or presentation, which is why
|
|
44
|
+
// it is a list of contract shapes rather than a list of things to ignore. It sits ON TOP of
|
|
45
|
+
// number 3: `isNonCodeFile` is reused verbatim to split code from prose/config, and this file
|
|
46
|
+
// adds only the two judgements code-loc has no opinion about — is it a test, and is it a
|
|
47
|
+
// contract.
|
|
48
|
+
//
|
|
49
|
+
// ---- CALIBRATION -----------------------------------------------------------
|
|
50
|
+
//
|
|
51
|
+
// Measured over 1,405 open pull requests with a usable measurement, across 22 real repositories:
|
|
52
|
+
// low 34.3% / medium 35.1% / high 29.7% / unknown 0.8%. Arm fire counts: dirs 230, hub 174,
|
|
53
|
+
// files 165, lines 160, subsystems 57 — none redundant. Surface frequency: deps 222, schema 55,
|
|
54
|
+
// ci 43, dts 2, migration 2, sql 2. That last row is why `deps` and `ci` are carried but are NOT
|
|
55
|
+
// high arms (see `BlastSurface` in packages/shared for each one's argument), and why migrations
|
|
56
|
+
// and IDL are rare-but-decisive rather than common.
|
|
57
|
+
/** Path shapes whose consumers live OUTSIDE the diff. Ordered most-consequential first; the
|
|
58
|
+
* emitted `surfaces[]` preserves this order so a rendered list needs no client-side sort.
|
|
59
|
+
*
|
|
60
|
+
* ⚠ Matched CASE-INSENSITIVELY on the normalised path, like `isNonCodeFile` and unlike the
|
|
61
|
+
* agent's `NOISE_GLOBS` — a `Migrations/` directory is still a migrations directory. */
|
|
62
|
+
const BLAST_SURFACES = [
|
|
63
|
+
// A migrations directory. The one change on this list that is genuinely hard to undo.
|
|
64
|
+
['db_migration', /(^|\/)migrations?\//],
|
|
65
|
+
// A schema or models tree, or a `schema.*` module. ⚠ THE KNOWN FALSE-POSITIVE SHAPE: in a repo
|
|
66
|
+
// whose PRODUCT is an ORM, its own `src/**/schema/**` source tree trips a rule that means
|
|
67
|
+
// "this pull request changes the database". Measured: 55 hits, almost all one such repo. That
|
|
68
|
+
// is what `surfacesOff` in the account's config exists to switch off, and it is why the chip
|
|
69
|
+
// always NAMES the surface rather than asserting a bare level.
|
|
70
|
+
['db_schema', /(^|\/)(schema|schemas|models)\/|(^|\/)schemas?\.[a-z0-9]+$/],
|
|
71
|
+
['sql', /\.sql$/],
|
|
72
|
+
['public_types', /\.d\.ts$/],
|
|
73
|
+
['idl', /\.(proto|thrift|graphql|gql)$/],
|
|
74
|
+
['openapi', /(^|\/)(openapi|swagger)[^/]*\.(ya?ml|json)$/],
|
|
75
|
+
['infra', /\.(tf|tfvars)$|(^|\/)(helm|charts|k8s|kubernetes)\//],
|
|
76
|
+
['auth', /(^|\/)(auth|authz|authn|security|permissions?|acl|crypto)\//],
|
|
77
|
+
// MEDIUM, never high — see the BlastSurface doc.
|
|
78
|
+
['ci', /(^|\/)\.github\/workflows\//],
|
|
79
|
+
// Narration only, never an arm — see the BlastSurface doc.
|
|
80
|
+
[
|
|
81
|
+
'deps',
|
|
82
|
+
/(^|\/)(package\.json|requirements\.txt|go\.mod|go\.sum|cargo\.toml|gemfile|pyproject\.toml|build\.gradle|pom\.xml|pnpm-lock\.yaml|package-lock\.json|yarn\.lock|poetry\.lock|composer\.json)$/,
|
|
83
|
+
],
|
|
84
|
+
];
|
|
85
|
+
function normalize(path) {
|
|
86
|
+
let p = path.replace(/\\/g, '/');
|
|
87
|
+
if (p.startsWith('./'))
|
|
88
|
+
p = p.slice(2);
|
|
89
|
+
if (p.startsWith('/'))
|
|
90
|
+
p = p.slice(1);
|
|
91
|
+
return p.toLowerCase();
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Is this path a TEST?
|
|
95
|
+
*
|
|
96
|
+
* Tests are code — `isNonCodeFile` correctly counts them, because a reviewer does read them —
|
|
97
|
+
* but they are code whose blast radius is bounded by construction: a broken test fails CI rather
|
|
98
|
+
* than production. So they are counted APART, and "every code file here is a test" is one of the
|
|
99
|
+
* two ways a pull request earns `low`.
|
|
100
|
+
*
|
|
101
|
+
* ⚠ Deliberately does NOT match a bare `test`/`tests` BASENAME, only a directory segment or a
|
|
102
|
+
* conventional suffix. `scripts/test` is an executable and `test.go` in a package root is
|
|
103
|
+
* ambiguous enough to leave counted — the same "directory segments only" trap `isNonCodeFile`
|
|
104
|
+
* documents, where treating a basename as a directory silently uncounts a hand-written file.
|
|
105
|
+
*/
|
|
106
|
+
export function isTestFile(path) {
|
|
107
|
+
const p = normalize(path);
|
|
108
|
+
if (/(^|\/)(tests?|__tests__|specs?|e2e|testing)\//.test(p))
|
|
109
|
+
return true;
|
|
110
|
+
if (/\.(test|spec)\.[a-z0-9]+$/.test(p))
|
|
111
|
+
return true;
|
|
112
|
+
if (/_test\.[a-z0-9]+$/.test(p))
|
|
113
|
+
return true;
|
|
114
|
+
if (/(^|\/)test_[^/]+\.py$/.test(p))
|
|
115
|
+
return true;
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
/** The contract surfaces this path matches, if any. Exported for the fixture tests. */
|
|
119
|
+
export function surfacesForPath(path) {
|
|
120
|
+
const p = normalize(path);
|
|
121
|
+
const out = [];
|
|
122
|
+
for (const [surface, re] of BLAST_SURFACES)
|
|
123
|
+
if (re.test(p))
|
|
124
|
+
out.push(surface);
|
|
125
|
+
return out;
|
|
126
|
+
}
|
|
127
|
+
function dirOf(path) {
|
|
128
|
+
const i = path.lastIndexOf('/');
|
|
129
|
+
return i === -1 ? '.' : path.slice(0, i);
|
|
130
|
+
}
|
|
131
|
+
function subsystemOf(path) {
|
|
132
|
+
const i = path.indexOf('/');
|
|
133
|
+
return i === -1 ? path : path.slice(0, i);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The change shape, but only when it still describes the CURRENT head.
|
|
137
|
+
*
|
|
138
|
+
* ⚠ RETURNS null ON ANY MISMATCH OR ABSENCE, and null never demotes anything. Three separate
|
|
139
|
+
* things land here and all three are the same answer: never classified, classified at a head
|
|
140
|
+
* that has since moved, or classified with no sha recorded at all.
|
|
141
|
+
*/
|
|
142
|
+
function contentKindFor(pr) {
|
|
143
|
+
if (pr.contentKind == null)
|
|
144
|
+
return null;
|
|
145
|
+
if (pr.contentKindSha == null || pr.headSha == null)
|
|
146
|
+
return null;
|
|
147
|
+
return pr.contentKindSha === pr.headSha ? pr.contentKind : null;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Fold one stored pull-request row into its blast-radius signal vector.
|
|
151
|
+
*
|
|
152
|
+
* Returns `null` for every UNKNOWN — and it does not re-derive what "unknown" means, it calls
|
|
153
|
+
* `codeLocFor` and inherits all four of its data traps (`files IS NULL` at 18.5% of the corpus,
|
|
154
|
+
* a never-observed size at 18.8%, the overloaded `files = []` sentinel, and the page cap). One
|
|
155
|
+
* definition of "we did not measure this pull request", used by both features.
|
|
156
|
+
*
|
|
157
|
+
* ⚠ `null` IS NOT "low". Roughly a tenth of open pull requests land here and every surface must
|
|
158
|
+
* render nothing for them — a reader who can tell an unmeasured pull request from a small one is
|
|
159
|
+
* reading a claim we did not make.
|
|
160
|
+
*/
|
|
161
|
+
export function blastSignalsFor(pr, hub) {
|
|
162
|
+
const { codeLoc, codeLocIsLowerBound } = codeLocFor(pr);
|
|
163
|
+
// Unknown size or no per-file breakdown → nothing honest to say about reach either.
|
|
164
|
+
if (codeLoc == null)
|
|
165
|
+
return null;
|
|
166
|
+
const files = pr.files ?? [];
|
|
167
|
+
let testFiles = 0;
|
|
168
|
+
let nonCodeFiles = 0;
|
|
169
|
+
let allNew = true;
|
|
170
|
+
const codePaths = [];
|
|
171
|
+
const surfaces = new Set();
|
|
172
|
+
for (const f of files) {
|
|
173
|
+
if (typeof f?.path !== 'string')
|
|
174
|
+
continue;
|
|
175
|
+
// ⚠ SURFACES ARE COLLECTED OVER EVERY FILE, code or not. An OpenAPI document and a Terraform
|
|
176
|
+
// plan are `isNonCodeFile` (structured config, correctly excluded from the LINE count) and
|
|
177
|
+
// are exactly the contracts this feature exists to catch. Restricting the scan to code files
|
|
178
|
+
// would make `openapi` and half of `infra` unreachable.
|
|
179
|
+
for (const s of surfacesForPath(f.path))
|
|
180
|
+
surfaces.add(s);
|
|
181
|
+
if (isNonCodeFile(f.path)) {
|
|
182
|
+
nonCodeFiles += 1;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (isTestFile(f.path)) {
|
|
186
|
+
testFiles += 1;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
codePaths.push(normalize(f.path));
|
|
190
|
+
// A file with no additions and no deletions is a pure rename/mode change; it cannot be the
|
|
191
|
+
// reason a PR is "all new", so it does not vote either way.
|
|
192
|
+
if (f.deletions > 0)
|
|
193
|
+
allNew = false;
|
|
194
|
+
}
|
|
195
|
+
// ⚠ `allNew` is only meaningful when there IS code. An empty code list would otherwise report
|
|
196
|
+
// `true` and claim "nothing existing can break" about a pull request with nothing in it.
|
|
197
|
+
if (codePaths.length === 0)
|
|
198
|
+
allNew = false;
|
|
199
|
+
return {
|
|
200
|
+
codeFiles: codePaths.length,
|
|
201
|
+
testFiles,
|
|
202
|
+
nonCodeFiles,
|
|
203
|
+
dirs: new Set(codePaths.map(dirOf)).size,
|
|
204
|
+
subsystems: new Set(codePaths.map(subsystemOf)).size,
|
|
205
|
+
// Emitted in BLAST_SURFACES order (most-consequential first) rather than insertion order, so
|
|
206
|
+
// the chip's sentence leads with the migration and not with whichever file GitHub listed first.
|
|
207
|
+
surfaces: BLAST_SURFACES.map(([s]) => s).filter((s) => surfaces.has(s)),
|
|
208
|
+
allNew,
|
|
209
|
+
hubDegree: hub?.degree ?? null,
|
|
210
|
+
hubBar: hub?.bar ?? null,
|
|
211
|
+
hubPath: hub?.path ?? null,
|
|
212
|
+
// The same fact `codeLocIsLowerBound` reports, re-stated for the reach vector because it
|
|
213
|
+
// governs a DIFFERENT rule here: over there it forbids asserting "small", here it forbids
|
|
214
|
+
// asserting "low". Both come from the one page-cap test in `codeLocFor`.
|
|
215
|
+
truncated: codeLocIsLowerBound,
|
|
216
|
+
// ⚠ THE STALENESS TEST LIVES HERE, ONCE. A diff read is only true of the commit it read, so a
|
|
217
|
+
// verdict stored against an older head describes code that may no longer be there — and a
|
|
218
|
+
// stale "comments only" would keep a level capped after a force-push added a schema change.
|
|
219
|
+
// Every surface reads the fold, so no surface has to remember this comparison.
|
|
220
|
+
contentKind: contentKindFor(pr),
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
/** Re-exported so a caller folding both features reads one import. The page cap is the single
|
|
224
|
+
* fact behind `codeLocIsLowerBound` and `BlastSignals.truncated` alike. */
|
|
225
|
+
export { PR_FILES_PAGE_CAP };
|
|
226
|
+
//# sourceMappingURL=blast-radius.js.map
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// ── "Is this bot dormant?" — ONE predicate, ONE window, CORE ─────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// The Bots → ROI table has always been able to say a reviewer is DORMANT: it is still classified,
|
|
4
|
+
// still (perhaps) paid for, and it did nothing inside the window being read. Two OTHER surfaces —
|
|
5
|
+
// the Bots → Benchmark tab and the Bot Tuning Advisor — used to keep rendering those reviewers, so
|
|
6
|
+
// one screen said "dormant" while the next two placed the same bot against a peer cohort and
|
|
7
|
+
// offered tuning advice for it. This module is the one fact both of those surfaces now hide on.
|
|
8
|
+
//
|
|
9
|
+
// ⚠ THE WINDOW IS FIXED AT 30 DAYS AND MUST STAY FIXED. The three surfaces disagreed about time
|
|
10
|
+
// before this existed: ROI defaults to a trailing 14 days that the USER FLIPS with a chip, the
|
|
11
|
+
// Advisor is pinned to `rolling_30`, and the benchmark fold has no time window at all. Adopting the
|
|
12
|
+
// ROI chip's value would make a workspace's peer placement appear and disappear because somebody
|
|
13
|
+
// flipped a selector on a different tab — a fact about a bot must not be a function of another
|
|
14
|
+
// screen's view state. 30 days is the Advisor's existing pin, so no surface changed its own window
|
|
15
|
+
// to gain this gate.
|
|
16
|
+
//
|
|
17
|
+
// ⚠ CONSEQUENCE, STATED RATHER THAN HIDDEN: a bot with nothing in the last 14 days but something in
|
|
18
|
+
// the last 30 reads "dormant" on the ROI table (relative to the view) and still appears on the
|
|
19
|
+
// Benchmark and the Advisor (it is not dormant as a fact). That is deliberate. The ROI table's
|
|
20
|
+
// window chip and its "widen the window to see them counted" affordance are about the CURRENT VIEW;
|
|
21
|
+
// this predicate is about the BOT.
|
|
22
|
+
//
|
|
23
|
+
// ⚠ THE GRAIN IS THE WORKSPACE, NEVER A REPO. The Advisor cannot narrow by repository at all (the
|
|
24
|
+
// SPA sends only `?workspace=`), and a `?repoIds=`-narrowed benchmark request deliberately builds no
|
|
25
|
+
// rollup — so a repo-grained gate has nowhere to land on two of the three surfaces. The repository
|
|
26
|
+
// set below is therefore the workspace's MEMBERSHIP and never a caller's `repoIds` narrowing, the
|
|
27
|
+
// same rule `workspaceHumanSeatCount` follows for the same reason: the answer must not shrink
|
|
28
|
+
// because a reader filtered a chart.
|
|
29
|
+
//
|
|
30
|
+
// ⚠ THE EVIDENCE IS EXACTLY THE ROI TABLE'S, DELIBERATELY. `getBotAnalytics` calls a reviewer
|
|
31
|
+
// dormant when it has NO window activity, where activity is: a review THREAD it opened, a review
|
|
32
|
+
// COMMENT it left, or a submitted REVIEW (body-only "nothing to flag" passes included — that is a
|
|
33
|
+
// bot doing its job and saying so). Three tables, unioned. The Advisor's own emission gate is
|
|
34
|
+
// narrower (threads-or-ML-labels), so a bot can already be absent from the Advisor while ROI calls
|
|
35
|
+
// it live; widening THIS predicate to match the Advisor instead would hide bots the ROI table shows
|
|
36
|
+
// as working, which is the opposite of what a reader asked for. The union is the safe direction:
|
|
37
|
+
// any observed work at all keeps a reviewer visible.
|
|
38
|
+
//
|
|
39
|
+
// The predicate is CORE because both consumers must not be able to disagree: the Advisor filter
|
|
40
|
+
// lives in `getAdvisorFindings` (`db/queries.ts`), and the benchmark reaches this through the
|
|
41
|
+
// OPTIONAL `ProHostQueries.dormantBotUserIds` seam (apiVersion stays 21 — the `getWorkPlan` /
|
|
42
|
+
// `workspaceHumanSeatCount` precedent; an older host simply hides nothing).
|
|
43
|
+
//
|
|
44
|
+
// ⚠ IT DELIBERATELY IMPORTS NOTHING FROM `queries.ts`. That file imports this one (the Advisor
|
|
45
|
+
// filter lives inside `getAdvisorFindings`), and a cycle between the two would be a hazard nobody
|
|
46
|
+
// wants in the app's largest module. The membership read below is the two lines of
|
|
47
|
+
// `getWorkspaceRepoIds` this needs, minus the render ordering a set does not care about; the
|
|
48
|
+
// candidate ids are the CALLER's, which is also what stops this module owning a second opinion
|
|
49
|
+
// about who is a bot.
|
|
50
|
+
import { and, eq, gte, inArray, ne } from 'drizzle-orm';
|
|
51
|
+
import { db, schema } from './client.js';
|
|
52
|
+
/** The ONE dormancy window, in days. See the header: fixed on purpose, and equal to the Advisor's
|
|
53
|
+
* existing `rolling_30` pin so no surface moved its own window to gain this gate. */
|
|
54
|
+
export const DORMANCY_WINDOW_DAYS = 30;
|
|
55
|
+
const { pullRequests, reviewComments, reviewThreads, reviews, workspaceRepos } = schema;
|
|
56
|
+
/**
|
|
57
|
+
* The automated reviewers that produced NO observable work in this workspace over the fixed
|
|
58
|
+
* dormancy window.
|
|
59
|
+
*
|
|
60
|
+
* `candidateUserIds` IS THE CALLER'S OWN LINEUP and is required: the Advisor passes the automated
|
|
61
|
+
* set it already resolved, the benchmark passes the review vendors it is about. Nothing here
|
|
62
|
+
* re-decides who is a bot — a second classifier is how a benchmark ends up disagreeing with the
|
|
63
|
+
* Timeline about a login. The result is always a SUBSET of the candidates, so a caller can treat it
|
|
64
|
+
* as a plain "hide these" set.
|
|
65
|
+
*
|
|
66
|
+
* ⚠ An empty workspace (no repos) yields NO dormant ids rather than "all of them". Dormancy is a
|
|
67
|
+
* claim about observed silence, and a workspace whose data we hold none of has observed nothing —
|
|
68
|
+
* hiding every bot there would be an absence rendered as a judgement.
|
|
69
|
+
*/
|
|
70
|
+
export async function dormantBotUserIds(accountId, workspaceId, candidateUserIds) {
|
|
71
|
+
const candidates = [...new Set(candidateUserIds)];
|
|
72
|
+
if (candidates.length === 0)
|
|
73
|
+
return [];
|
|
74
|
+
// ⚠ MEMBERSHIP, NOT A NARROWING — see the header. Account-scoped on both columns, so a foreign or
|
|
75
|
+
// unknown workspace id yields no repos and therefore no dormant ids (never another tenant's).
|
|
76
|
+
const memberRows = await db
|
|
77
|
+
.select({ repoId: workspaceRepos.repoId })
|
|
78
|
+
.from(workspaceRepos)
|
|
79
|
+
.where(and(eq(workspaceRepos.accountId, accountId), eq(workspaceRepos.workspaceId, workspaceId)))
|
|
80
|
+
.execute();
|
|
81
|
+
const repoIds = memberRows.map((r) => r.repoId);
|
|
82
|
+
if (repoIds.length === 0)
|
|
83
|
+
return [];
|
|
84
|
+
const since = new Date(Date.now() - DORMANCY_WINDOW_DAYS * 86_400_000);
|
|
85
|
+
const repoScope = inArray(pullRequests.repoId, repoIds);
|
|
86
|
+
const [threadRows, commentRows, reviewRows] = await Promise.all([
|
|
87
|
+
db
|
|
88
|
+
.selectDistinct({ userId: reviewThreads.originalCommenterId })
|
|
89
|
+
.from(reviewThreads)
|
|
90
|
+
.innerJoin(pullRequests, eq(pullRequests.id, reviewThreads.prId))
|
|
91
|
+
.where(and(eq(pullRequests.accountId, accountId), inArray(reviewThreads.originalCommenterId, candidates), gte(reviewThreads.createdAt, since), repoScope))
|
|
92
|
+
.execute(),
|
|
93
|
+
db
|
|
94
|
+
.selectDistinct({ userId: reviewComments.authorId })
|
|
95
|
+
.from(reviewComments)
|
|
96
|
+
.innerJoin(pullRequests, eq(pullRequests.id, reviewComments.prId))
|
|
97
|
+
.where(and(eq(pullRequests.accountId, accountId), inArray(reviewComments.authorId, candidates), gte(reviewComments.createdAt, since), repoScope))
|
|
98
|
+
.execute(),
|
|
99
|
+
// A body-only review IS activity — the ROI table counts it for exactly this decision, and a
|
|
100
|
+
// reviewer that reads a PR and says "nothing to flag" is working.
|
|
101
|
+
db
|
|
102
|
+
.selectDistinct({ userId: reviews.authorId })
|
|
103
|
+
.from(reviews)
|
|
104
|
+
.innerJoin(pullRequests, eq(pullRequests.id, reviews.prId))
|
|
105
|
+
.where(and(eq(pullRequests.accountId, accountId), inArray(reviews.authorId, candidates), ne(reviews.state, 'pending'), gte(reviews.submittedAt, since), repoScope))
|
|
106
|
+
.execute(),
|
|
107
|
+
]);
|
|
108
|
+
const active = new Set();
|
|
109
|
+
for (const rows of [threadRows, commentRows, reviewRows])
|
|
110
|
+
for (const r of rows)
|
|
111
|
+
if (r.userId != null)
|
|
112
|
+
active.add(r.userId);
|
|
113
|
+
return candidates.filter((id) => !active.has(id));
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=bot-dormancy.js.map
|