limn-review 0.1.129 → 0.1.130
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 +91 -74
- package/README.md +19 -7
- package/dist/ai/credentials.js +113 -0
- package/dist/api/plugins/auth.js +17 -161
- package/dist/api/plugins/error-handler.js +12 -74
- package/dist/api/plugins/rate-limit.js +21 -88
- package/dist/api/plugins/security.js +19 -99
- package/dist/api/routes/ai-runtime.js +3 -3
- package/dist/api/routes/bot-triage.js +16 -272
- package/dist/api/routes/flow.js +5 -43
- package/dist/api/routes/insights.js +7 -32
- package/dist/api/routes/me.js +12 -136
- package/dist/api/routes/ml-labels.js +2 -3
- package/dist/api/routes/ml-runtime.js +3 -3
- package/dist/api/routes/prs.js +3 -26
- package/dist/app.js +44 -124
- package/dist/auth/account.js +13 -143
- package/dist/auth/crypto.js +8 -9
- package/dist/cli.js +21 -68
- package/dist/coding/agent.js +4 -2
- package/dist/coding/ai-fix/manager.js +0 -6
- package/dist/coding/ai-fix/routes.js +1 -12
- package/dist/coding/ai-resolve/routes.js +0 -2
- package/dist/coding/ai-resolve/run.js +0 -2
- package/dist/config.js +49 -288
- package/dist/conflict/git.js +1 -1
- package/dist/conflict/suggestion.js +1 -1
- package/dist/db/blast-radius.js +1 -1
- package/dist/db/bot-window.js +1 -1
- package/dist/db/client.js +39 -79
- package/dist/db/flow-detail.js +1 -1
- package/dist/db/flow-pointers.js +1 -1
- package/dist/db/migrate.js +0 -2
- package/dist/db/period-metrics.js +1 -2
- package/dist/db/pr-intervals.js +1 -1
- package/dist/db/queries.js +7 -334
- package/dist/db/repo-activity.js +1 -1
- package/dist/db/run-migrations.js +5 -20
- package/dist/db/schema.sqlite.js +8 -16
- package/dist/db/synthesis-input.js +0 -230
- package/dist/github/client.js +2 -2
- package/dist/index.js +13 -19
- package/dist/merge/arm-intent.js +2 -3
- package/dist/merge/auto-merge-runner.js +3 -3
- package/dist/platform/activity-digest/schema.sqlite.js +33 -0
- package/dist/platform/advisor/discovery/tier2.js +88 -0
- package/dist/platform/advisor/discovery/tier3.js +57 -0
- package/dist/platform/advisor/emitters/adapter.js +5 -0
- package/dist/platform/advisor/emitters/coderabbit.js +175 -0
- package/dist/platform/advisor/emitters/copilot-prose.js +118 -0
- package/dist/platform/advisor/emitters/greptile.js +176 -0
- package/dist/platform/advisor/emitters/lint.js +37 -0
- package/dist/platform/advisor/emitters/manifest.js +239 -0
- package/dist/platform/advisor/emitters/prose.js +183 -0
- package/dist/platform/advisor/emitters/registry.js +20 -0
- package/dist/platform/advisor/emitters/yaml-doc.js +95 -0
- package/dist/platform/advisor/evidence.js +79 -0
- package/dist/platform/advisor/findings.js +15 -0
- package/dist/platform/advisor/intents.js +269 -0
- package/dist/platform/advisor/measure/effect.js +18 -0
- package/dist/platform/advisor/outputs/brief.js +68 -0
- package/dist/platform/advisor/outputs/config-pr.js +156 -0
- package/dist/platform/advisor/refine/diff-guard.js +38 -0
- package/dist/platform/advisor/refine/refine.js +35 -0
- package/dist/platform/advisor/retro-check.js +98 -0
- package/dist/platform/advisor/routes.js +648 -0
- package/dist/platform/advisor/schema.sqlite.js +107 -0
- package/dist/platform/advisor/store.js +321 -0
- package/dist/platform/advisor/taxonomy.js +67 -0
- package/dist/platform/ai-fix/schema.sqlite.js +32 -0
- package/dist/platform/annotations/prompts.js +84 -0
- package/dist/platform/annotations/routes.js +86 -0
- package/dist/platform/annotations/runner.js +234 -0
- package/dist/platform/annotations/schema.sqlite.js +57 -0
- package/dist/platform/annotations/targets.js +203 -0
- package/dist/platform/bot-themes/build.js +222 -0
- package/dist/platform/bot-themes/prompt.js +218 -0
- package/dist/platform/bot-themes/routes.js +307 -0
- package/dist/platform/bot-themes/schema.sqlite.js +36 -0
- package/dist/platform/bots/behaviour-routes.js +65 -0
- package/dist/platform/bots/benchmark/anomalies.js +140 -0
- package/dist/platform/bots/benchmark/artifact.js +214 -0
- package/dist/platform/bots/benchmark/collect.js +571 -0
- package/dist/platform/bots/benchmark/cost.js +658 -0
- package/dist/platform/bots/benchmark/fold.js +513 -0
- package/dist/platform/bots/benchmark/map.js +374 -0
- package/dist/platform/bots/benchmark/percentile.js +101 -0
- package/dist/platform/bots/benchmark/place.js +184 -0
- package/dist/platform/bots/benchmark/placement-routes.js +742 -0
- package/dist/platform/bots/benchmark/rollup.js +670 -0
- package/dist/platform/bots/benchmark-routes.js +153 -0
- package/dist/{pro/bind.js → platform/context.js} +22 -111
- package/dist/platform/contract.js +2 -0
- package/dist/platform/data/benchmark/benchmark-fit.json +1 -0
- package/dist/platform/db.js +51 -0
- package/dist/{pro → platform}/event-hooks.js +2 -3
- package/dist/platform/flow-pointers/hash.js +84 -0
- package/dist/platform/flow-pointers/prompt.js +244 -0
- package/dist/platform/flow-pointers/routes.js +277 -0
- package/dist/platform/flow-pointers/schema.sqlite.js +41 -0
- package/dist/platform/human-themes/schema.sqlite.js +32 -0
- package/dist/platform/index.js +84 -0
- package/dist/platform/insights/grounded-figures.js +162 -0
- package/dist/platform/insights/period-questions.js +235 -0
- package/dist/platform/insights/period-report.js +1871 -0
- package/dist/platform/insights/period-routes.js +237 -0
- package/dist/platform/insights/period-schema.sqlite.js +112 -0
- package/dist/platform/insights/pr-refs.js +107 -0
- package/dist/platform/insights/pr-token.js +22 -0
- package/dist/platform/insights/routes.js +71 -0
- package/dist/platform/insights/schema.sqlite.js +122 -0
- package/dist/platform/insights/sprint-report.js +605 -0
- package/dist/platform/insights/workspace-request.js +64 -0
- package/dist/platform/insights/workspace-scope.js +77 -0
- package/dist/platform/llm/gate.js +22 -0
- package/dist/platform/llm/seam.js +156 -0
- package/dist/platform/migrate.js +15 -0
- package/dist/platform/migration-files.js +36 -0
- package/dist/platform/migrations/0001_init.sql +23 -0
- package/dist/platform/migrations/0002_ai_fix.sql +25 -0
- package/dist/platform/migrations/0003_ai_fix_resolve.sql +19 -0
- package/dist/platform/migrations/0004_sprint_report.sql +19 -0
- package/dist/platform/migrations/0005_pro_settings.sql +26 -0
- package/dist/platform/migrations/0006_issue_project_keys.sql +7 -0
- package/dist/platform/migrations/0007_comparison_mode.sql +8 -0
- package/dist/platform/migrations/0008_retro_report.sql +19 -0
- package/dist/platform/migrations/0009_bot_settings.sql +17 -0
- package/dist/platform/migrations/0010_team_scope.sql +33 -0
- package/dist/platform/migrations/0011_comment_assess.sql +22 -0
- package/dist/platform/migrations/0012_resolution_check.sql +23 -0
- package/dist/platform/migrations/0013_pinned_prompts.sql +19 -0
- package/dist/platform/migrations/0014_bot_themes.sql +24 -0
- package/dist/platform/migrations/0015_human_themes.sql +23 -0
- package/dist/platform/migrations/0016_sprint_chat_history.sql +24 -0
- package/dist/platform/migrations/0017_pr_comment_annotations.sql +63 -0
- package/dist/platform/migrations/0018_drop_retro_reports.sql +19 -0
- package/dist/platform/migrations/0019_bot_cost_to_account_reviewers.sql +258 -0
- package/dist/platform/migrations/0020_workspace_scope_keys.sql +235 -0
- package/dist/platform/migrations/0021_bot_advisor.sql +82 -0
- package/dist/platform/migrations/0022_annotation_evidence.sql +32 -0
- package/dist/platform/migrations/0023_chat_answer_window.sql +30 -0
- package/dist/platform/migrations/0024_ai_fix_comment_seed.sql +44 -0
- package/dist/platform/migrations/0025_period_reports.sql +100 -0
- package/dist/platform/migrations/0026_period_lanes.sql +19 -0
- package/dist/platform/migrations/0027_synthesis.sql +57 -0
- package/dist/platform/migrations/0028_work_plan.sql +66 -0
- package/dist/platform/migrations/0029_workspace_sprint_cadence.sql +73 -0
- package/dist/platform/migrations/0030_workspace_slack_targets.sql +127 -0
- package/dist/platform/migrations/0031_workspace_issue_tracker.sql +116 -0
- package/dist/platform/migrations/0032_workspace_comparison_mode.sql +77 -0
- package/dist/platform/migrations/0033_slack_target_bot_digest.sql +47 -0
- package/dist/platform/migrations/0034_flow_pointers.sql +32 -0
- package/dist/platform/migrations/0035_workspace_jira_api.sql +28 -0
- package/dist/platform/migrations/0036_workspace_auto_review.sql +19 -0
- package/dist/platform/migrations/0037_auto_review_to_core.sql +31 -0
- package/dist/platform/migrations/0038_pr_jira_tickets.sql +13 -0
- package/dist/platform/migrations/0039_jira_ticket_peers.sql +8 -0
- package/dist/platform/migrations/0040_slack_event_signals.sql +24 -0
- package/dist/platform/resolution-check/schema.sqlite.js +35 -0
- package/dist/platform/retention.js +157 -0
- package/dist/platform/review-assess/schema.sqlite.js +32 -0
- package/dist/platform/settings/routes.js +172 -0
- package/dist/platform/settings/schema.sqlite.js +259 -0
- package/dist/platform/settings/store.js +505 -0
- package/dist/platform/slack/cron.js +190 -0
- package/dist/platform/slack/format.js +335 -0
- package/dist/platform/slack/links.js +124 -0
- package/dist/platform/slack/pending-blocks.js +212 -0
- package/dist/platform/slack/report.js +224 -0
- package/dist/platform/slack/routes.js +127 -0
- package/dist/platform/slack/schema.sqlite.js +24 -0
- package/dist/platform/slack/send.js +32 -0
- package/dist/platform/slack/signals.js +195 -0
- package/dist/platform/slack/targets.js +237 -0
- package/dist/platform/synthesis/hash.js +44 -0
- package/dist/platform/synthesis/prompt.js +110 -0
- package/dist/platform/synthesis/routes.js +299 -0
- package/dist/platform/synthesis/schema.sqlite.js +47 -0
- package/dist/platform/synthesis/scope.js +159 -0
- package/dist/platform/themes/resolve.js +90 -0
- package/dist/platform/work-plan/hash.js +99 -0
- package/dist/platform/work-plan/prompt.js +209 -0
- package/dist/platform/work-plan/routes.js +344 -0
- package/dist/platform/work-plan/schema.sqlite.js +74 -0
- package/dist/reference-docs/agent.js +3 -0
- package/dist/reference-docs/chat-quotes.js +229 -0
- package/dist/reference-docs/chat.js +6 -39
- package/dist/reference-docs/context.js +1 -1
- package/dist/reference-docs/prompts.js +1 -0
- package/dist/reference-docs/render.js +5 -1
- package/dist/reference-docs/review-refs.js +3 -35
- package/dist/reference-docs/routes.js +0 -3
- package/dist/reference-docs/store.js +2 -1
- package/dist/reference-docs/url-fetch.js +1 -1
- package/dist/review/agent-context.js +2 -26
- package/dist/review/agent.js +2 -0
- package/dist/review/agentic.js +3 -10
- package/dist/review/auth.js +27 -59
- package/dist/review/chat-agent.js +2 -0
- package/dist/review/ci-review/agent.js +2 -0
- package/dist/review/ci-review/routes.js +0 -4
- package/dist/review/ci-review/sweep.js +0 -2
- package/dist/review/claude-review/auto-post.js +312 -89
- package/dist/review/claude-review/auto.js +1 -9
- package/dist/review/claude-review/chat.js +1 -9
- package/dist/review/claude-review/manager.js +3 -9
- package/dist/review/claude-review/persist.js +3 -2
- package/dist/review/claude-review/routes.js +1 -9
- package/dist/review/claude-review/thread-check-agent.js +2 -0
- package/dist/review/claude-review/thread-check-routes.js +0 -4
- package/dist/review/diagrams/agent.js +2 -0
- package/dist/review/diagrams/routes.js +0 -4
- package/dist/review/diagrams/trigger.js +1 -1
- package/dist/review/llm.js +35 -48
- package/dist/review/post-seam.js +3 -2
- package/dist/review/sprint-paths/agent.js +2 -0
- package/dist/review/story-docs/agent.js +2 -0
- package/dist/review/story-docs/routes.js +0 -3
- package/dist/review/story-labels/routes.js +4 -19
- package/dist/review/ticket-review/agent.js +2 -0
- package/dist/review/ticket-review/auto-post.js +31 -38
- package/dist/review/ticket-review/post-item.js +187 -104
- package/dist/review/ticket-review/prepass.js +2 -0
- package/dist/review/ticket-review/routes.js +20 -19
- package/dist/review/ticket-review/sprint-checks.js +1 -4
- package/dist/review/ticket-review/sweep.js +0 -2
- package/dist/shared/index.js +1 -0
- package/dist/shared/reference-docs-quote.js +144 -0
- package/dist/shared/reference-docs.js +20 -0
- package/dist/shared/types.js +4 -27
- package/dist/sonar/comment.js +85 -7
- package/dist/sonar/index.js +0 -1
- package/dist/sonar/post.js +104 -10
- package/dist/sonar/routes.js +34 -36
- package/dist/sync/auth-notices.js +3 -5
- package/dist/sync/hydrate-detail.js +2 -2
- package/dist/sync/mention-scan.js +2 -9
- package/dist/sync/ml-enrichment.js +2 -8
- package/dist/sync/reviewer-classify.js +1 -1
- package/dist/sync/scheduler.js +0 -14
- package/dist/sync/sync-manager.js +3 -17
- package/dist/sync/upsert.js +1 -1
- package/dist/tracker/calls.js +3 -1
- package/dist/tracker/legacy-import.js +1 -25
- package/dist/tracker/manual-links.js +0 -1
- package/dist/tracker/routes.js +2 -3
- package/dist/tracker/runtime.js +4 -6
- package/dist/tracker/sprint/read.js +1 -2
- package/dist/tracker/stories.js +0 -1
- package/dist/tracker/worker.js +1 -1
- package/package.json +3 -6
- package/public/assets/AiFixTab-BRFh4rBA.js +3 -0
- package/public/assets/ClaudeReviewTab-D2GE3Lpe.js +20 -0
- package/public/assets/{PrBotBehaviourTab-BJelm30R.js → PrBotBehaviourTab-CEBLkCG5.js} +1 -1
- package/public/assets/{highlight-CIIZLa6Z.js → highlight-DIEV0qGG.js} +1 -1
- package/public/assets/index-hgG9aujx.css +1 -0
- package/public/assets/index-jmnLc1R-.js +79 -0
- package/public/assets/{markdown-I_JLLVAZ.js → markdown-CcoLFczy.js} +1 -1
- package/public/assets/tanstack-BnbsafB1.js +17 -0
- package/public/index.html +5 -5
- package/dist/api/routes/auth.js +0 -194
- package/dist/api/routes/billing.js +0 -209
- package/dist/api/routes/contact.js +0 -318
- package/dist/api/routes/mentions.js +0 -22
- package/dist/api/routes/webhooks.js +0 -181
- package/dist/db/automation-output.js +0 -349
- package/dist/db/credits.js +0 -79
- package/dist/db/migrations-pg/0000_tired_alex_power.sql +0 -268
- package/dist/db/migrations-pg/0001_dizzy_mockingbird.sql +0 -3
- package/dist/db/migrations-pg/0002_glorious_ikaris.sql +0 -4
- package/dist/db/migrations-pg/0003_melted_secret_warriors.sql +0 -2
- package/dist/db/migrations-pg/0004_numerous_triton.sql +0 -1
- package/dist/db/migrations-pg/0005_thick_blockbuster.sql +0 -2
- package/dist/db/migrations-pg/0006_majestic_dracula.sql +0 -1
- package/dist/db/migrations-pg/0007_same_human_torch.sql +0 -2
- package/dist/db/migrations-pg/0008_slimy_toxin.sql +0 -1
- package/dist/db/migrations-pg/0009_fuzzy_jubilee.sql +0 -4
- package/dist/db/migrations-pg/0010_late_hammerhead.sql +0 -1
- package/dist/db/migrations-pg/0011_happy_leech.sql +0 -16
- package/dist/db/migrations-pg/0012_woozy_captain_midlands.sql +0 -16
- package/dist/db/migrations-pg/0013_yielding_nicolaos.sql +0 -1
- package/dist/db/migrations-pg/0014_wakeful_bill_hollister.sql +0 -2
- package/dist/db/migrations-pg/0015_aspiring_black_tom.sql +0 -1
- package/dist/db/migrations-pg/0016_cute_ghost_rider.sql +0 -30
- package/dist/db/migrations-pg/0017_far_changeling.sql +0 -24
- package/dist/db/migrations-pg/0018_fancy_miss_america.sql +0 -1
- package/dist/db/migrations-pg/0019_benchmark_contributions.sql +0 -22
- package/dist/db/migrations-pg/0020_majestic_edwin_jarvis.sql +0 -3
- package/dist/db/migrations-pg/0021_green_salo.sql +0 -1
- package/dist/db/migrations-pg/0022_wise_baron_strucker.sql +0 -1
- package/dist/db/migrations-pg/0023_search_index.sql +0 -19
- package/dist/db/migrations-pg/0024_author_indexes.sql +0 -9
- package/dist/db/migrations-pg/0025_auto_merge_requests.sql +0 -26
- package/dist/db/migrations-pg/0026_branch_status.sql +0 -32
- package/dist/db/migrations-pg/0027_pr_review_decision.sql +0 -5
- package/dist/db/migrations-pg/0028_branch_commit_detail.sql +0 -9
- package/dist/db/migrations-pg/0029_repo_reviewers.sql +0 -127
- package/dist/db/migrations-pg/0030_account_reviewers.sql +0 -77
- package/dist/db/migrations-pg/0031_workspaces.sql +0 -131
- package/dist/db/migrations-pg/0032_workspace_reviewers.sql +0 -165
- package/dist/db/migrations-pg/0033_drop_inbox_watch.sql +0 -14
- package/dist/db/migrations-pg/0034_ml_comment_labels.sql +0 -33
- package/dist/db/migrations-pg/0035_ml_vendor_severity.sql +0 -16
- package/dist/db/migrations-pg/0036_seat_pricing_repo_description.sql +0 -12
- package/dist/db/migrations-pg/0037_users_app_slug.sql +0 -9
- package/dist/db/migrations-pg/0038_auto_merge_queue.sql +0 -10
- package/dist/db/migrations-pg/0039_trunk_ci_status_events.sql +0 -27
- package/dist/db/migrations-pg/0040_automation_roles.sql +0 -63
- package/dist/db/migrations-pg/0041_automation_vendor_kinds.sql +0 -488
- package/dist/db/migrations-pg/0042_auto_merge_phase.sql +0 -8
- package/dist/db/migrations-pg/0043_pr_mentions.sql +0 -19
- package/dist/db/migrations-pg/0044_large_pr_threshold.sql +0 -6
- package/dist/db/migrations-pg/0045_pending_mute.sql +0 -26
- package/dist/db/migrations-pg/0046_merge_queue_state.sql +0 -18
- package/dist/db/migrations-pg/0047_drop_my_turn_dismissals.sql +0 -21
- package/dist/db/migrations-pg/0048_auto_merge_durable_anchors.sql +0 -27
- package/dist/db/migrations-pg/0049_blast_radius_config.sql +0 -8
- package/dist/db/migrations-pg/0050_repo_file_coupling.sql +0 -13
- package/dist/db/migrations-pg/0051_pr_content_kind.sql +0 -6
- package/dist/db/migrations-pg/0052_workspace_flow_settings.sql +0 -4
- package/dist/db/migrations-pg/0053_review_request_events.sql +0 -18
- package/dist/db/migrations-pg/0054_pr_security_signals.sql +0 -59
- package/dist/db/migrations-pg/0055_my_turn_settings.sql +0 -6
- package/dist/db/migrations-pg/0056_my_turn_dismissals.sql +0 -21
- package/dist/db/migrations-pg/0057_claude_review_follow_up_ticket.sql +0 -8
- package/dist/db/migrations-pg/0058_claude_review_trigger.sql +0 -4
- package/dist/db/migrations-pg/0059_commit_message_headline.sql +0 -3
- package/dist/db/migrations-pg/0060_claude_review_chat.sql +0 -24
- package/dist/db/migrations-pg/0061_adopt_agentic_tables.sql +0 -79
- package/dist/db/migrations-pg/0062_review_lens_drop_learnings.sql +0 -5
- package/dist/db/migrations-pg/0063_claude_review_threads.sql +0 -7
- package/dist/db/migrations-pg/0064_claude_review_ci_failures.sql +0 -4
- package/dist/db/migrations-pg/0065_ai_fix_change_report.sql +0 -9
- package/dist/db/migrations-pg/0066_claude_finding_story.sql +0 -7
- package/dist/db/migrations-pg/0067_ticket_reviews.sql +0 -79
- package/dist/db/migrations-pg/0068_review_request_requester.sql +0 -14
- package/dist/db/migrations-pg/0069_ci_reviews.sql +0 -65
- package/dist/db/migrations-pg/0070_workspace_auto_fix.sql +0 -3
- package/dist/db/migrations-pg/0071_auto_fix_off_by_default.sql +0 -5
- package/dist/db/migrations-pg/0072_auto_review_daily_cap.sql +0 -3
- package/dist/db/migrations-pg/0073_ticket_review_pr_cards.sql +0 -17
- package/dist/db/migrations-pg/0074_auto_post.sql +0 -14
- package/dist/db/migrations-pg/0075_issue_tracker.sql +0 -77
- package/dist/db/migrations-pg/0076_github_issue_links.sql +0 -6
- package/dist/db/migrations-pg/0077_linear_links.sql +0 -8
- package/dist/db/migrations-pg/0078_auto_post_verdict_resolve_fix.sql +0 -11
- package/dist/db/migrations-pg/0079_finding_pushback.sql +0 -3
- package/dist/db/migrations-pg/0080_dependency_auto_merge.sql +0 -16
- package/dist/db/migrations-pg/0081_repo_uses_github_issues.sql +0 -7
- package/dist/db/migrations-pg/0082_review_chat_explain.sql +0 -5
- package/dist/db/migrations-pg/0083_workspace_setting_events.sql +0 -13
- package/dist/db/migrations-pg/0084_story_reports.sql +0 -28
- package/dist/db/migrations-pg/0085_tracker_ticket_dates.sql +0 -5
- package/dist/db/migrations-pg/0086_story_labels.sql +0 -19
- package/dist/db/migrations-pg/0087_sprint_stories.sql +0 -121
- package/dist/db/migrations-pg/0088_sprint_reads_api_root.sql +0 -3
- package/dist/db/migrations-pg/0089_workspace_sprint_checks.sql +0 -3
- package/dist/db/migrations-pg/0090_sprint_statuses_and_blockers.sql +0 -14
- package/dist/db/migrations-pg/0091_sprint_ticket_repos_saved.sql +0 -4
- package/dist/db/migrations-pg/0092_sprint_assessment_mode.sql +0 -4
- package/dist/db/migrations-pg/0093_sprint_ref_tickets.sql +0 -21
- package/dist/db/migrations-pg/0094_sprint_graph.sql +0 -38
- package/dist/db/migrations-pg/0095_sprint_themes.sql +0 -19
- package/dist/db/migrations-pg/0096_sprint_story.sql +0 -18
- package/dist/db/migrations-pg/0097_finding_reminder.sql +0 -3
- package/dist/db/migrations-pg/0098_sprint_dates_story_attempt.sql +0 -12
- package/dist/db/migrations-pg/0099_sprint_view_snapshots.sql +0 -15
- package/dist/db/migrations-pg/0100_ai_fix_plan.sql +0 -13
- package/dist/db/migrations-pg/0101_sonarcloud.sql +0 -31
- package/dist/db/migrations-pg/0102_sequence_diagrams.sql +0 -32
- package/dist/db/migrations-pg/0103_reference_docs.sql +0 -51
- package/dist/db/migrations-pg/0104_review_doc_references.sql +0 -5
- package/dist/db/migrations-pg/0105_sequence_diagram_runs.sql +0 -5
- package/dist/db/migrations-pg/0106_design_diagrams.sql +0 -3
- package/dist/db/migrations-pg/0107_sprint_paths.sql +0 -26
- package/dist/db/migrations-pg/0108_story_docs_alignments.sql +0 -34
- package/dist/db/migrations-pg/0109_claude_thread_checks.sql +0 -31
- package/dist/db/migrations-pg/0110_sprint_brief_one_liner.sql +0 -3
- package/dist/db/migrations-pg/0111_reference_doc_crawl.sql +0 -3
- package/dist/db/migrations-pg/meta/0000_snapshot.json +0 -2137
- package/dist/db/migrations-pg/meta/0001_snapshot.json +0 -2143
- package/dist/db/migrations-pg/meta/0002_snapshot.json +0 -2170
- package/dist/db/migrations-pg/meta/0003_snapshot.json +0 -2182
- package/dist/db/migrations-pg/meta/0004_snapshot.json +0 -2188
- package/dist/db/migrations-pg/meta/0005_snapshot.json +0 -2201
- package/dist/db/migrations-pg/meta/0006_snapshot.json +0 -2207
- package/dist/db/migrations-pg/meta/0007_snapshot.json +0 -2219
- package/dist/db/migrations-pg/meta/0008_snapshot.json +0 -2226
- package/dist/db/migrations-pg/meta/0009_snapshot.json +0 -2250
- package/dist/db/migrations-pg/meta/0010_snapshot.json +0 -2256
- package/dist/db/migrations-pg/meta/0011_snapshot.json +0 -2412
- package/dist/db/migrations-pg/meta/0012_snapshot.json +0 -2528
- package/dist/db/migrations-pg/meta/0013_snapshot.json +0 -2534
- package/dist/db/migrations-pg/meta/0014_snapshot.json +0 -2547
- package/dist/db/migrations-pg/meta/0015_snapshot.json +0 -2553
- package/dist/db/migrations-pg/meta/0016_snapshot.json +0 -2774
- package/dist/db/migrations-pg/meta/0017_snapshot.json +0 -2999
- package/dist/db/migrations-pg/meta/0018_snapshot.json +0 -3020
- package/dist/db/migrations-pg/meta/0020_snapshot.json +0 -3228
- package/dist/db/migrations-pg/meta/0021_snapshot.json +0 -3234
- package/dist/db/migrations-pg/meta/0022_snapshot.json +0 -3240
- package/dist/db/migrations-pg/meta/_journal.json +0 -790
- package/dist/db/schema.pg.js +0 -2197
- package/dist/pro/contract.js +0 -36
- package/dist/pro/migrate.js +0 -64
- package/dist/sync/benchmark-rollup.js +0 -50
- package/public/assets/AiFixTab-IKfiwwnd.js +0 -3
- package/public/assets/ClaudeReviewTab-DlefFnYI.js +0 -20
- package/public/assets/index-CB4YyNHK.css +0 -1
- package/public/assets/index-Cm0XoYfd.js +0 -79
- package/public/assets/tanstack-5qsxxaLe.js +0 -17
- 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-D3DGTvPS.js +0 -40
- package/public-landing/assets/index-naQrQ6Fe.css +0 -1
- 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 +0 -156
- package/public-landing/contact/index.html +0 -156
- package/public-landing/cookies/index.html +0 -156
- package/public-landing/demo/limn-walkthrough-poster.jpg +0 -0
- package/public-landing/demo/limn-walkthrough.cues.json +0 -44
- 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 +0 -5
- package/public-landing/features/index.html +0 -156
- package/public-landing/for-developers/index.html +0 -156
- package/public-landing/for-managers/index.html +0 -156
- package/public-landing/how-it-works/index.html +0 -156
- package/public-landing/how-we-measure/index.html +0 -156
- package/public-landing/icon-192.png +0 -0
- package/public-landing/icon-512.png +0 -0
- package/public-landing/index.html +0 -156
- package/public-landing/insights/index.html +0 -156
- package/public-landing/og-image.png +0 -0
- package/public-landing/pricing/index.html +0 -156
- package/public-landing/privacy/index.html +0 -156
- package/public-landing/pro/index.html +0 -156
- package/public-landing/reviews/index.html +0 -156
- package/public-landing/robots.txt +0 -8
- 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 +0 -14
- package/public-landing/sitemap.xml +0 -51
- package/public-landing/terms/index.html +0 -156
package/LICENSE
CHANGED
|
@@ -1,110 +1,127 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Limn License 1.0
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Copyright 2026 Alex Wakeman
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## 1. Acceptance
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
In order to get any license under these terms, you must agree to them as both
|
|
8
|
+
strict obligations and conditions to all your licenses.
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
## 2. Copyright License
|
|
11
|
+
|
|
12
|
+
The licensor grants you a copyright license for the software to do everything
|
|
13
|
+
you might do with the software that would otherwise infringe the licensor's
|
|
14
|
+
copyright in it for any permitted purpose. However, you may only distribute the
|
|
15
|
+
software according to section 5 (Distribution License) and make changes or new
|
|
16
|
+
works based on the software according to section 6 (Changes and New Works
|
|
17
|
+
License).
|
|
18
|
+
|
|
19
|
+
## 3. Permitted Purposes
|
|
10
20
|
|
|
11
|
-
|
|
21
|
+
Any purpose is a permitted purpose for:
|
|
12
22
|
|
|
13
|
-
|
|
23
|
+
(a) an individual using the software for themselves; and
|
|
14
24
|
|
|
15
|
-
|
|
25
|
+
(b) an organization in which no more than three (3) individuals use the
|
|
26
|
+
software, counting the organization together with all of its affiliates.
|
|
16
27
|
|
|
17
|
-
|
|
28
|
+
Any other use, including use within an organization in which more than three
|
|
29
|
+
(3) individuals use the software, is not a permitted purpose. That use needs a
|
|
30
|
+
separate commercial license from the licensor, which you can ask for through
|
|
31
|
+
the contact form at https://limn-review.com/contact.
|
|
18
32
|
|
|
19
|
-
|
|
20
|
-
these Terms and Conditions, as indicated by our inclusion of these Terms and
|
|
21
|
-
Conditions with the Software.
|
|
33
|
+
## 4. No Competing Use
|
|
22
34
|
|
|
23
|
-
|
|
35
|
+
No purpose is a permitted purpose if it is a competing use. A competing use is
|
|
36
|
+
making the software, or any product or service substantially similar to it or
|
|
37
|
+
built from it, available to others as a commercial product or service, whether
|
|
38
|
+
as installable software, a hosted service or any other form.
|
|
24
39
|
|
|
25
|
-
|
|
26
|
-
Redistribution and Trademark clauses below, we hereby grant you the right to
|
|
27
|
-
use, copy, modify, create derivative works, publicly perform, publicly display
|
|
28
|
-
and redistribute the Software for any Permitted Purpose identified below.
|
|
40
|
+
## 5. Distribution License
|
|
29
41
|
|
|
30
|
-
|
|
42
|
+
The licensor grants you an additional copyright license to distribute copies of
|
|
43
|
+
the software. Your license to distribute covers distributing the software with
|
|
44
|
+
changes and new works permitted by section 6 (Changes and New Works License).
|
|
31
45
|
|
|
32
|
-
|
|
33
|
-
means making the Software available to others in a commercial product or
|
|
34
|
-
service that:
|
|
46
|
+
## 6. Changes and New Works License
|
|
35
47
|
|
|
36
|
-
|
|
48
|
+
The licensor grants you an additional copyright license to make changes and new
|
|
49
|
+
works based on the software for any permitted purpose.
|
|
37
50
|
|
|
38
|
-
|
|
39
|
-
that exists as of the date we make the Software available; or
|
|
51
|
+
## 7. Notices
|
|
40
52
|
|
|
41
|
-
|
|
53
|
+
You must ensure that anyone who gets a copy of any part of the software from
|
|
54
|
+
you also gets a copy of these terms, together with the copyright notice above.
|
|
55
|
+
Anyone who gets a copy from you gets it under these terms only, and no other
|
|
56
|
+
terms. If you modify the software, you must include in any modified copies of
|
|
57
|
+
the software a prominent notice stating that you have modified the software.
|
|
42
58
|
|
|
43
|
-
|
|
59
|
+
## 8. Patent License
|
|
44
60
|
|
|
45
|
-
|
|
61
|
+
The licensor grants you a patent license for the software that covers patent
|
|
62
|
+
claims the licensor can license, or becomes able to license, that you would
|
|
63
|
+
infringe by using the software for a permitted purpose.
|
|
46
64
|
|
|
47
|
-
|
|
65
|
+
## 9. Fair Use
|
|
48
66
|
|
|
49
|
-
|
|
67
|
+
You may have "fair use" rights for the software under the law. These terms do
|
|
68
|
+
not limit them.
|
|
50
69
|
|
|
51
|
-
|
|
52
|
-
using the Software in accordance with these Terms and Conditions.
|
|
70
|
+
## 10. No Other Rights
|
|
53
71
|
|
|
54
|
-
|
|
72
|
+
These terms do not allow you to sublicense or transfer any of your licenses to
|
|
73
|
+
anyone else, or prevent the licensor from granting licenses to anyone else.
|
|
74
|
+
These terms do not imply any other licenses. The licensor will not convert
|
|
75
|
+
these terms, or any version of the software released under them, to the MIT
|
|
76
|
+
License or to any other license by the passing of time.
|
|
55
77
|
|
|
56
|
-
|
|
57
|
-
patents, the license grant above includes a license under our patents. If you
|
|
58
|
-
make a claim against any party that the Software infringes or contributes to
|
|
59
|
-
the infringement of any patent, then your patent license to the Software ends
|
|
60
|
-
immediately.
|
|
78
|
+
## 11. Patent Defense
|
|
61
79
|
|
|
62
|
-
|
|
80
|
+
If you make any written claim that the software infringes or contributes to
|
|
81
|
+
infringement of any patent, your patent license for the software granted under
|
|
82
|
+
these terms ends immediately. If your company makes such a claim, your patent
|
|
83
|
+
license ends immediately for work on behalf of your company.
|
|
63
84
|
|
|
64
|
-
|
|
65
|
-
the Software.
|
|
85
|
+
## 12. Violations
|
|
66
86
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
87
|
+
The first time you are notified in writing that you have violated any of these
|
|
88
|
+
terms, or done anything with the software not covered by your licenses, your
|
|
89
|
+
licenses can nonetheless continue if you come into full compliance with these
|
|
90
|
+
terms, and take practical steps to correct past violations, within 32 days of
|
|
91
|
+
receiving notice. Otherwise, all your licenses end immediately.
|
|
70
92
|
|
|
71
|
-
|
|
93
|
+
## 13. No Liability
|
|
72
94
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
95
|
+
***As far as the law allows, the software comes as is, without any warranty or
|
|
96
|
+
condition, and the licensor will not be liable to you for any damages arising
|
|
97
|
+
out of these terms or the use or nature of the software, under any kind of
|
|
98
|
+
legal claim.***
|
|
76
99
|
|
|
77
|
-
|
|
78
|
-
SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
|
|
79
|
-
EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
|
|
100
|
+
## 14. Definitions
|
|
80
101
|
|
|
81
|
-
|
|
102
|
+
The **licensor** is Alex Wakeman, the individual offering these terms, and the
|
|
103
|
+
**software** is the software the licensor makes available under these terms,
|
|
104
|
+
including any version of it.
|
|
82
105
|
|
|
83
|
-
|
|
84
|
-
the Software, you have no right under these Terms and Conditions to use our
|
|
85
|
-
trademarks, trade names, service marks or product names.
|
|
106
|
+
**You** refers to the individual or entity agreeing to these terms.
|
|
86
107
|
|
|
87
|
-
|
|
108
|
+
**Your company** is any legal entity, sole proprietorship, or other kind of
|
|
109
|
+
organization that you work for, plus all organizations that have control over,
|
|
110
|
+
are under the control of, or are under common control with that organization.
|
|
88
111
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
112
|
+
An **organization** includes any company, firm, partnership, government body,
|
|
113
|
+
charity, team or other group of people working together, and **affiliates** of
|
|
114
|
+
an organization are all organizations that have control over, are under the
|
|
115
|
+
control of, or are under common control with it. **Control** means ownership of
|
|
116
|
+
substantially all the assets of an entity, or the power to direct its
|
|
117
|
+
management and policies by vote, contract, or otherwise. Control can be direct
|
|
118
|
+
or indirect.
|
|
93
119
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
98
|
-
of the Software, and to permit persons to whom the Software is furnished to do
|
|
99
|
-
so, subject to the following conditions:
|
|
120
|
+
An individual **uses** the software within an organization if they run it, or
|
|
121
|
+
work with it directly, in the course of their work for, or on behalf of, that
|
|
122
|
+
organization.
|
|
100
123
|
|
|
101
|
-
|
|
102
|
-
|
|
124
|
+
**Your licenses** are all the licenses granted to you for the software under
|
|
125
|
+
these terms.
|
|
103
126
|
|
|
104
|
-
|
|
105
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
106
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
107
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
108
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
109
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
110
|
-
SOFTWARE.
|
|
127
|
+
**Use** means anything you do with the software requiring one of your licenses.
|
package/README.md
CHANGED
|
@@ -9,6 +9,12 @@ There's no hosted backend, no database server, and no stored credentials. It
|
|
|
9
9
|
authenticates by shelling out to your already-logged-in `gh` CLI, syncs activity
|
|
10
10
|
into a local SQLite file, and serves the dashboard from a single local process.
|
|
11
11
|
|
|
12
|
+
**100% free.** Every feature, no paid tier, no sign-up (see [License](#license)
|
|
13
|
+
for the one limit, on large organisations).
|
|
14
|
+
|
|
15
|
+
**Try it first:** the [live demo](https://limn-review.com/demo/) is the real
|
|
16
|
+
app on sample data, in your browser. No install, no sign-in.
|
|
17
|
+
|
|
12
18
|
> **Renamed.** This package used to be `pierre-review`. The command is now `limn`
|
|
13
19
|
> (the `pierre-review` package now only forwards to this one, and says so). On first start, an existing
|
|
14
20
|
> `~/.pierre-review` is moved to `~/.limn` — your database, settings and clones
|
|
@@ -32,9 +38,11 @@ limn
|
|
|
32
38
|
## Review and fix with Claude — free, on your own Claude
|
|
33
39
|
|
|
34
40
|
Claude Review (a code review of any PR, follow-ups, a check against a user
|
|
35
|
-
story you paste, and a chat about the review) and AI Fix are free.
|
|
36
|
-
your
|
|
37
|
-
|
|
41
|
+
story you paste, and a chat about the review) and AI Fix are free. By default
|
|
42
|
+
they use your local Claude Code login: if you are signed in to Claude Code,
|
|
43
|
+
there is nothing to set up. An Anthropic API key is the alternative: set
|
|
44
|
+
`ANTHROPIC_API_KEY`. Limn stores no key and charges nothing for it. Codex
|
|
45
|
+
support is coming soon.
|
|
38
46
|
|
|
39
47
|
- **First use downloads the AI runtime, once (about 110 MB).** Press
|
|
40
48
|
**Set up AI** in the app, or run `limn ai install`. It goes to
|
|
@@ -45,6 +53,8 @@ your own Claude Code or Anthropic API key: sign in to Claude Code, or set
|
|
|
45
53
|
- The reviewer reads code. It cannot edit files, run commands or reach the web.
|
|
46
54
|
- The fixer edits files. It has no shell, and builds and tests nothing.
|
|
47
55
|
- Nothing is posted or pushed until you press the button.
|
|
56
|
+
- `LIMN_AI_USE_API_KEY=true` uses `ANTHROPIC_API_KEY` even when you are signed
|
|
57
|
+
in to Claude Code.
|
|
48
58
|
- `LIMN_AI_DISABLED=true` turns every AI feature off.
|
|
49
59
|
|
|
50
60
|
## Prerequisites
|
|
@@ -125,9 +135,11 @@ locally instead — a larger database, but PR detail then works fully offline.
|
|
|
125
135
|
|
|
126
136
|
## License
|
|
127
137
|
|
|
128
|
-
Source-available under the **
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
138
|
+
Source-available under the **Limn License 1.0** — see [LICENSE](./LICENSE).
|
|
139
|
+
Limn is free for individuals, and for organisations where no more than 3 people
|
|
140
|
+
use it (affiliates count together). More users than that need a licence — ask
|
|
141
|
+
through the [contact form](https://limn-review.com/contact?topic=licence). You may
|
|
142
|
+
**not** offer Limn, or a product built from it, as a competing commercial
|
|
143
|
+
product or service.
|
|
132
144
|
The AI runtime Limn downloads on first use is Anthropic's, under Anthropic's own
|
|
133
145
|
terms; it is not part of this package.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// THE ONE CREDENTIAL LADDER for every model call Limn makes — the agentic runs (Claude Review, AI
|
|
2
|
+
// Fix, the ticket / CI reviews, diagrams, sprint paths, the docs build and chat, resolve with
|
|
3
|
+
// Claude, every chat) AND the one-shot completions (review/llm.ts `cheapComplete`, which the
|
|
4
|
+
// sprint briefs/themes, story labels, docs ranking, sprint Ask Claude and every platform feature —
|
|
5
|
+
// reports, synthesis, work-plan wording, pointers, bot themes, the impact note, the advisor's
|
|
6
|
+
// refine, the Slack report — all go through).
|
|
7
|
+
//
|
|
8
|
+
// 1. THE LOCAL CLAUDE CODE LOGIN (default) — a `claude` session on disk or
|
|
9
|
+
// CLAUDE_CODE_OAUTH_TOKEN, used through the Agent SDK. Any ANTHROPIC_API_KEY in the
|
|
10
|
+
// environment is HIDDEN from that run, or the SDK would prefer it and silently meter it.
|
|
11
|
+
// 2. ANTHROPIC_API_KEY from the environment — the alternative when there is no login. Agent runs
|
|
12
|
+
// hand it to the Agent SDK; one-shot completions call the Anthropic API directly with it
|
|
13
|
+
// (the SDK loaded through ai/runtime.ts `loadAnthropicSdk`, never imported here).
|
|
14
|
+
//
|
|
15
|
+
// LIMN_AI_USE_API_KEY=true flips the order when a key is set: the key first, the login ignored.
|
|
16
|
+
// LIMN_AI_DISABLED=true (config.aiEnabled) turns every model call off; that switch is checked by
|
|
17
|
+
// the callers, not here, because this module answers only "which credential", never "may we".
|
|
18
|
+
//
|
|
19
|
+
// Nothing is stored. Detection of the login reads the disk (a credentials file, or `oauthAccount`
|
|
20
|
+
// recorded in the Claude config — see hasClaudeLogin); a wrong
|
|
21
|
+
// guess surfaces as the SDK's own auth error on the first real call.
|
|
22
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
23
|
+
import { homedir } from 'node:os';
|
|
24
|
+
import { join } from 'node:path';
|
|
25
|
+
/** The opt-in that makes ANTHROPIC_API_KEY win over a Claude Code login. */
|
|
26
|
+
export const USE_API_KEY_ENV = 'LIMN_AI_USE_API_KEY';
|
|
27
|
+
function envApiKey(env) {
|
|
28
|
+
const k = env.ANTHROPIC_API_KEY?.trim();
|
|
29
|
+
return k ? k : undefined;
|
|
30
|
+
}
|
|
31
|
+
/** Does the reader prefer the API key over the login (`LIMN_AI_USE_API_KEY=true`)? */
|
|
32
|
+
export function prefersApiKey(env = process.env) {
|
|
33
|
+
return env[USE_API_KEY_ENV]?.trim().toLowerCase() === 'true';
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Does this Claude Code config file record a signed-in account? The CLI writes a non-empty
|
|
37
|
+
* `oauthAccount` object on sign-in and removes it on logout — on macOS, where the token itself is
|
|
38
|
+
* in the Keychain, it is the only on-disk signal. A missing, unreadable or unparseable file is no.
|
|
39
|
+
*/
|
|
40
|
+
function configRecordsLogin(path) {
|
|
41
|
+
try {
|
|
42
|
+
if (!existsSync(path))
|
|
43
|
+
return false;
|
|
44
|
+
const parsed = JSON.parse(readFileSync(path, 'utf8'));
|
|
45
|
+
if (!parsed || typeof parsed !== 'object')
|
|
46
|
+
return false;
|
|
47
|
+
const account = parsed.oauthAccount;
|
|
48
|
+
return !!account && typeof account === 'object' && Object.keys(account).length > 0;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Is a Claude Code login available (an OAuth token, or a logged-in session on disk)? Deliberately
|
|
56
|
+
* ignores API keys: it answers "can this run on the reader's own Claude, not a meter?".
|
|
57
|
+
*
|
|
58
|
+
* ⚠ A BARE `~/.claude` DIRECTORY OR `~/.claude.json` IS NOT A LOGIN. Merely running Claude Code —
|
|
59
|
+
* including the Agent SDK on the API-key route — creates both, so counting them moved a key-only
|
|
60
|
+
* reader onto the login route after their first run and stripped their key from every later one.
|
|
61
|
+
* Only a credentials file, CLAUDE_CODE_OAUTH_TOKEN, or a config recording `oauthAccount` counts.
|
|
62
|
+
* CLAUDE_CONFIG_DIR (which the SDK subprocess inherits) is checked before the defaults.
|
|
63
|
+
*/
|
|
64
|
+
export function hasClaudeLogin(env = process.env, home = homedir()) {
|
|
65
|
+
if (env.CLAUDE_CODE_OAUTH_TOKEN?.trim())
|
|
66
|
+
return true;
|
|
67
|
+
const cfg = env.CLAUDE_CONFIG_DIR?.trim();
|
|
68
|
+
const credentialFiles = [
|
|
69
|
+
...(cfg ? [join(cfg, '.credentials.json')] : []),
|
|
70
|
+
join(home, '.claude', '.credentials.json'),
|
|
71
|
+
join(home, '.config', 'claude', '.credentials.json'),
|
|
72
|
+
];
|
|
73
|
+
if (credentialFiles.some((path) => existsSync(path)))
|
|
74
|
+
return true;
|
|
75
|
+
const configFiles = [...(cfg ? [join(cfg, '.claude.json')] : []), join(home, '.claude.json')];
|
|
76
|
+
return configFiles.some(configRecordsLogin);
|
|
77
|
+
}
|
|
78
|
+
/** Which credential the next model call uses. Read at call time, so an env change takes effect. */
|
|
79
|
+
export function resolveAiCredential(env = process.env, loginAvailable = hasClaudeLogin) {
|
|
80
|
+
const apiKey = envApiKey(env);
|
|
81
|
+
if (apiKey && prefersApiKey(env))
|
|
82
|
+
return { route: 'api_key', method: 'api_key', apiKey };
|
|
83
|
+
if (env.CLAUDE_CODE_OAUTH_TOKEN)
|
|
84
|
+
return { route: 'login', method: 'oauth_token' };
|
|
85
|
+
if (loginAvailable(env))
|
|
86
|
+
return { route: 'login', method: 'ambient' };
|
|
87
|
+
if (apiKey)
|
|
88
|
+
return { route: 'api_key', method: 'api_key', apiKey };
|
|
89
|
+
return { route: 'none' };
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The environment an Agent SDK subprocess runs with, per the ladder. Passed as the query's `env`
|
|
93
|
+
* option, so it never touches process.env and two concurrent runs cannot race.
|
|
94
|
+
*
|
|
95
|
+
* • login → the inherited environment WITHOUT ANTHROPIC_API_KEY (the login pays, not a meter).
|
|
96
|
+
* • API key → the inherited environment WITHOUT CLAUDE_CODE_OAUTH_TOKEN, so the key is used.
|
|
97
|
+
* • none → the inherited environment unchanged; the SDK reports the authoritative auth error.
|
|
98
|
+
*/
|
|
99
|
+
export function agentSdkEnv(env = process.env, credential = resolveAiCredential(env)) {
|
|
100
|
+
const out = { ...env };
|
|
101
|
+
if (credential.route === 'login')
|
|
102
|
+
delete out.ANTHROPIC_API_KEY;
|
|
103
|
+
else if (credential.route === 'api_key') {
|
|
104
|
+
delete out.CLAUDE_CODE_OAUTH_TOKEN;
|
|
105
|
+
out.ANTHROPIC_API_KEY = credential.apiKey;
|
|
106
|
+
}
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
/** Spread into every Agent SDK `query({ options })`, beside `claudeExecutableOptions()`. */
|
|
110
|
+
export function agentAuthOptions() {
|
|
111
|
+
return { env: agentSdkEnv() };
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=credentials.js.map
|
package/dist/api/plugins/auth.js
CHANGED
|
@@ -1,169 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
//
|
|
5
|
-
// (so it covers all routes, including static/health which simply ignore it).
|
|
6
|
-
//
|
|
7
|
-
// Local mode: always the synthesized local account (id 1).
|
|
8
|
-
// Cloud mode: resolved from the sealed session cookie (set up in registerCloudAuth,
|
|
9
|
-
// Phase 1). Unauthenticated requests get `null`; the requireAuth preHandler
|
|
10
|
-
// then 401s the data routes.
|
|
1
|
+
import { getLocalAccountCached, LOCAL_ACCOUNT_ID } from '../../auth/account.js';
|
|
2
|
+
// Attaches `request.account` to every request. Registered once on the root app (so it covers all
|
|
3
|
+
// routes, including static/health which simply ignore it). Limn runs on the reader's own machine
|
|
4
|
+
// with their `gh` login, so every request is the synthesized local account (id 1).
|
|
11
5
|
export function registerAccountContext(app) {
|
|
12
6
|
app.decorateRequest('account', null);
|
|
13
7
|
app.addHook('onRequest', async (req) => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
req.account =
|
|
26
|
-
getLocalAccountCached() ?? {
|
|
27
|
-
id: LOCAL_ACCOUNT_ID,
|
|
28
|
-
githubUserId: '',
|
|
29
|
-
githubLogin: '',
|
|
30
|
-
displayName: null,
|
|
31
|
-
avatarUrl: null,
|
|
32
|
-
isLocal: true,
|
|
33
|
-
plan: 'free',
|
|
34
|
-
stripeCustomerId: null,
|
|
35
|
-
aiCreditAllowance: null,
|
|
36
|
-
benchmarkOptIn: false,
|
|
37
|
-
largePrCodeLocThreshold: null,
|
|
38
|
-
blastRadiusConfig: null,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
8
|
+
req.account =
|
|
9
|
+
getLocalAccountCached() ?? {
|
|
10
|
+
id: LOCAL_ACCOUNT_ID,
|
|
11
|
+
githubUserId: '',
|
|
12
|
+
githubLogin: '',
|
|
13
|
+
displayName: null,
|
|
14
|
+
avatarUrl: null,
|
|
15
|
+
isLocal: true,
|
|
16
|
+
largePrCodeLocThreshold: null,
|
|
17
|
+
blastRadiusConfig: null,
|
|
18
|
+
};
|
|
41
19
|
});
|
|
42
20
|
}
|
|
43
|
-
//
|
|
44
|
-
// only registered in cloud mode (Phase 1); guarded so this is safe pre-registration.
|
|
45
|
-
function readSessionAccountId(req) {
|
|
46
|
-
const session = req
|
|
47
|
-
.session;
|
|
48
|
-
if (!session)
|
|
49
|
-
return null;
|
|
50
|
-
const raw = session.get('accountId');
|
|
51
|
-
return typeof raw === 'number' ? raw : null;
|
|
52
|
-
}
|
|
53
|
-
// Cloud only: register the cookie + sealed-session plugins. MUST run before
|
|
54
|
-
// registerAccountContext so the session cookie is parsed by the time the
|
|
55
|
-
// account-context onRequest hook reads it. The session key is derived from
|
|
56
|
-
// SESSION_SECRET (sha256 → 32 bytes, the size secure-session needs).
|
|
57
|
-
export async function registerSession(app) {
|
|
58
|
-
const cookie = await import('@fastify/cookie');
|
|
59
|
-
const secureSession = await import('@fastify/secure-session');
|
|
60
|
-
await app.register(cookie.default, { secret: config.sessionSecret });
|
|
61
|
-
const key = createHash('sha256').update(config.sessionSecret).digest();
|
|
62
|
-
await app.register(secureSession.default, {
|
|
63
|
-
key,
|
|
64
|
-
cookieName: 'pierre_session',
|
|
65
|
-
cookie: {
|
|
66
|
-
path: '/',
|
|
67
|
-
httpOnly: true,
|
|
68
|
-
sameSite: 'lax',
|
|
69
|
-
secure: config.appBaseUrl.startsWith('https://'),
|
|
70
|
-
maxAge: 30 * 24 * 60 * 60, // 30 days
|
|
71
|
-
},
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
// Cloud only: 401 any unauthenticated /api data route. Skips /api/health,
|
|
75
|
-
// /api/auth/* (sign-in itself), /api/billing/webhook (Stripe posts
|
|
76
|
-
// unauthenticated — verified by signature instead), /api/contact* (the public
|
|
77
|
-
// contact form, whose visitors have no account by definition) and all non-/api requests
|
|
78
|
-
// (the SPA + landing are served openly; the frontend gate handles the signed-out
|
|
79
|
-
// UI). MUST be registered AFTER registerAccountContext so req.account is already
|
|
80
|
-
// resolved. Also the cloud-only ENTITLEMENT gate: an authenticated free-plan
|
|
81
|
-
// account gets 402 on the Pro plugin's /api/pro/* routes (local accounts are
|
|
82
|
-
// always entitled — isLocal never reaches the cloud gate anyway).
|
|
83
|
-
export function registerAuthGate(app) {
|
|
84
|
-
app.addHook('onRequest', async (req, reply) => {
|
|
85
|
-
const path = req.url.split('?')[0] ?? req.url;
|
|
86
|
-
if (!path.startsWith('/api/'))
|
|
87
|
-
return;
|
|
88
|
-
if (path === '/api/health')
|
|
89
|
-
return;
|
|
90
|
-
if (path.startsWith('/api/auth/'))
|
|
91
|
-
return;
|
|
92
|
-
if (path === '/api/billing/webhook')
|
|
93
|
-
return;
|
|
94
|
-
// GitHub App webhook: GitHub posts unauthenticated — authenticity is the
|
|
95
|
-
// X-Hub-Signature-256 HMAC, verified in the route (see api/routes/webhooks.ts).
|
|
96
|
-
if (path === '/api/webhooks/github')
|
|
97
|
-
return;
|
|
98
|
-
// The pricing page's "Get Pro" is a plain browser navigation from the public
|
|
99
|
-
// landing; the route itself bounces anonymous visitors to sign-in instead of
|
|
100
|
-
// dead-ending them on a JSON 401.
|
|
101
|
-
if (path === '/api/billing/checkout')
|
|
102
|
-
return;
|
|
103
|
-
// The public contact form. It exists FOR people who are not signed in — someone
|
|
104
|
-
// asking for a Pro trial does not have an account yet, and someone reporting that
|
|
105
|
-
// sign-in is broken cannot sign in to say so. Spam control is the honeypot, the
|
|
106
|
-
// signed fill-time ticket and the IP-keyed `contact` rate-limit tier, all in
|
|
107
|
-
// api/routes/contact.ts; authentication was never the control here.
|
|
108
|
-
if (path === '/api/contact' || path === '/api/contact/ticket')
|
|
109
|
-
return;
|
|
110
|
-
if (!req.account) {
|
|
111
|
-
await reply.code(401).send({
|
|
112
|
-
error: 'Unauthorized',
|
|
113
|
-
message: 'Sign in with GitHub to continue.',
|
|
114
|
-
});
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
if (isProPath(path) && !req.account.isLocal && req.account.plan === 'free') {
|
|
118
|
-
await reply.code(402).send({ error: 'pro required' });
|
|
119
|
-
}
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
// Which paths the free-plan 402 gate covers.
|
|
123
|
-
//
|
|
124
|
-
// `/api/pro/*` is the convention, but it is NOT the whole surface: Claude Review has always kept
|
|
125
|
-
// its pre-plugin URLs — `/api/prs/:id/claude-review*`, `/api/claude-reviews/*`,
|
|
126
|
-
// `/api/claude-findings/*`, `/api/claude-review/*` — and AI Fix's fixer kept its
|
|
127
|
-
// `/api/pro/prs/:id/ai-fix*` / `/api/pro/ai-fixes/*` paths when both moved to core.
|
|
128
|
-
//
|
|
129
|
-
// ⚠ THIS IS NOW THE SECOND GUARD, NOT THE FIRST. Claude Review, review memory and AI Fix are core,
|
|
130
|
-
// free and LOCAL ONLY: `registerAgenticRoutes` (review/agentic.ts) registers none of them in cloud
|
|
131
|
-
// — an explicit `isCloud` check — so in cloud they 404 before this matters. The entries stay so a
|
|
132
|
-
// future change that registers one in cloud does not hand it to every free account by default.
|
|
133
|
-
// Enumerated explicitly so adding a route outside /api/pro/ is a visible decision.
|
|
134
|
-
function isProPath(path) {
|
|
135
|
-
if (path.startsWith('/api/pro/'))
|
|
136
|
-
return true;
|
|
137
|
-
if (path.startsWith('/api/claude-reviews'))
|
|
138
|
-
return true;
|
|
139
|
-
if (path.startsWith('/api/claude-findings/'))
|
|
140
|
-
return true;
|
|
141
|
-
if (path.startsWith('/api/claude-review/'))
|
|
142
|
-
return true;
|
|
143
|
-
// /api/prs/<id>/claude-review, …/status, …/stream, …/cancel
|
|
144
|
-
if (/^\/api\/prs\/\d+\/claude-review/.test(path))
|
|
145
|
-
return true;
|
|
146
|
-
return false;
|
|
147
|
-
}
|
|
148
|
-
// preHandler that rejects unauthenticated requests in cloud mode. A no-op in
|
|
149
|
-
// local mode (the account is always present). Kept for any route that wants an
|
|
150
|
-
// explicit per-route guard in addition to the global gate above.
|
|
151
|
-
export async function requireAuth(req, reply) {
|
|
152
|
-
if (!config.isCloud)
|
|
153
|
-
return;
|
|
154
|
-
if (!req.account) {
|
|
155
|
-
await reply
|
|
156
|
-
.code(401)
|
|
157
|
-
.send({ error: 'Unauthorized', message: 'Sign in with GitHub to continue.' });
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
// The request's account id, for scoping queries. Always present in local mode;
|
|
161
|
-
// in cloud mode requireAuth has already guaranteed it on data routes.
|
|
21
|
+
// The request's account id, for scoping queries.
|
|
162
22
|
export function accountIdOf(req) {
|
|
163
|
-
|
|
164
|
-
return req.account.id;
|
|
165
|
-
if (!config.isCloud)
|
|
166
|
-
return LOCAL_ACCOUNT_ID;
|
|
167
|
-
throw new Error('no account on request (requireAuth missing?)');
|
|
23
|
+
return req.account?.id ?? LOCAL_ACCOUNT_ID;
|
|
168
24
|
}
|
|
169
25
|
//# sourceMappingURL=auth.js.map
|