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.
Files changed (463) hide show
  1. package/LICENSE +91 -74
  2. package/README.md +19 -7
  3. package/dist/ai/credentials.js +113 -0
  4. package/dist/api/plugins/auth.js +17 -161
  5. package/dist/api/plugins/error-handler.js +12 -74
  6. package/dist/api/plugins/rate-limit.js +21 -88
  7. package/dist/api/plugins/security.js +19 -99
  8. package/dist/api/routes/ai-runtime.js +3 -3
  9. package/dist/api/routes/bot-triage.js +16 -272
  10. package/dist/api/routes/flow.js +5 -43
  11. package/dist/api/routes/insights.js +7 -32
  12. package/dist/api/routes/me.js +12 -136
  13. package/dist/api/routes/ml-labels.js +2 -3
  14. package/dist/api/routes/ml-runtime.js +3 -3
  15. package/dist/api/routes/prs.js +3 -26
  16. package/dist/app.js +44 -124
  17. package/dist/auth/account.js +13 -143
  18. package/dist/auth/crypto.js +8 -9
  19. package/dist/cli.js +21 -68
  20. package/dist/coding/agent.js +4 -2
  21. package/dist/coding/ai-fix/manager.js +0 -6
  22. package/dist/coding/ai-fix/routes.js +1 -12
  23. package/dist/coding/ai-resolve/routes.js +0 -2
  24. package/dist/coding/ai-resolve/run.js +0 -2
  25. package/dist/config.js +49 -288
  26. package/dist/conflict/git.js +1 -1
  27. package/dist/conflict/suggestion.js +1 -1
  28. package/dist/db/blast-radius.js +1 -1
  29. package/dist/db/bot-window.js +1 -1
  30. package/dist/db/client.js +39 -79
  31. package/dist/db/flow-detail.js +1 -1
  32. package/dist/db/flow-pointers.js +1 -1
  33. package/dist/db/migrate.js +0 -2
  34. package/dist/db/period-metrics.js +1 -2
  35. package/dist/db/pr-intervals.js +1 -1
  36. package/dist/db/queries.js +7 -334
  37. package/dist/db/repo-activity.js +1 -1
  38. package/dist/db/run-migrations.js +5 -20
  39. package/dist/db/schema.sqlite.js +8 -16
  40. package/dist/db/synthesis-input.js +0 -230
  41. package/dist/github/client.js +2 -2
  42. package/dist/index.js +13 -19
  43. package/dist/merge/arm-intent.js +2 -3
  44. package/dist/merge/auto-merge-runner.js +3 -3
  45. package/dist/platform/activity-digest/schema.sqlite.js +33 -0
  46. package/dist/platform/advisor/discovery/tier2.js +88 -0
  47. package/dist/platform/advisor/discovery/tier3.js +57 -0
  48. package/dist/platform/advisor/emitters/adapter.js +5 -0
  49. package/dist/platform/advisor/emitters/coderabbit.js +175 -0
  50. package/dist/platform/advisor/emitters/copilot-prose.js +118 -0
  51. package/dist/platform/advisor/emitters/greptile.js +176 -0
  52. package/dist/platform/advisor/emitters/lint.js +37 -0
  53. package/dist/platform/advisor/emitters/manifest.js +239 -0
  54. package/dist/platform/advisor/emitters/prose.js +183 -0
  55. package/dist/platform/advisor/emitters/registry.js +20 -0
  56. package/dist/platform/advisor/emitters/yaml-doc.js +95 -0
  57. package/dist/platform/advisor/evidence.js +79 -0
  58. package/dist/platform/advisor/findings.js +15 -0
  59. package/dist/platform/advisor/intents.js +269 -0
  60. package/dist/platform/advisor/measure/effect.js +18 -0
  61. package/dist/platform/advisor/outputs/brief.js +68 -0
  62. package/dist/platform/advisor/outputs/config-pr.js +156 -0
  63. package/dist/platform/advisor/refine/diff-guard.js +38 -0
  64. package/dist/platform/advisor/refine/refine.js +35 -0
  65. package/dist/platform/advisor/retro-check.js +98 -0
  66. package/dist/platform/advisor/routes.js +648 -0
  67. package/dist/platform/advisor/schema.sqlite.js +107 -0
  68. package/dist/platform/advisor/store.js +321 -0
  69. package/dist/platform/advisor/taxonomy.js +67 -0
  70. package/dist/platform/ai-fix/schema.sqlite.js +32 -0
  71. package/dist/platform/annotations/prompts.js +84 -0
  72. package/dist/platform/annotations/routes.js +86 -0
  73. package/dist/platform/annotations/runner.js +234 -0
  74. package/dist/platform/annotations/schema.sqlite.js +57 -0
  75. package/dist/platform/annotations/targets.js +203 -0
  76. package/dist/platform/bot-themes/build.js +222 -0
  77. package/dist/platform/bot-themes/prompt.js +218 -0
  78. package/dist/platform/bot-themes/routes.js +307 -0
  79. package/dist/platform/bot-themes/schema.sqlite.js +36 -0
  80. package/dist/platform/bots/behaviour-routes.js +65 -0
  81. package/dist/platform/bots/benchmark/anomalies.js +140 -0
  82. package/dist/platform/bots/benchmark/artifact.js +214 -0
  83. package/dist/platform/bots/benchmark/collect.js +571 -0
  84. package/dist/platform/bots/benchmark/cost.js +658 -0
  85. package/dist/platform/bots/benchmark/fold.js +513 -0
  86. package/dist/platform/bots/benchmark/map.js +374 -0
  87. package/dist/platform/bots/benchmark/percentile.js +101 -0
  88. package/dist/platform/bots/benchmark/place.js +184 -0
  89. package/dist/platform/bots/benchmark/placement-routes.js +742 -0
  90. package/dist/platform/bots/benchmark/rollup.js +670 -0
  91. package/dist/platform/bots/benchmark-routes.js +153 -0
  92. package/dist/{pro/bind.js → platform/context.js} +22 -111
  93. package/dist/platform/contract.js +2 -0
  94. package/dist/platform/data/benchmark/benchmark-fit.json +1 -0
  95. package/dist/platform/db.js +51 -0
  96. package/dist/{pro → platform}/event-hooks.js +2 -3
  97. package/dist/platform/flow-pointers/hash.js +84 -0
  98. package/dist/platform/flow-pointers/prompt.js +244 -0
  99. package/dist/platform/flow-pointers/routes.js +277 -0
  100. package/dist/platform/flow-pointers/schema.sqlite.js +41 -0
  101. package/dist/platform/human-themes/schema.sqlite.js +32 -0
  102. package/dist/platform/index.js +84 -0
  103. package/dist/platform/insights/grounded-figures.js +162 -0
  104. package/dist/platform/insights/period-questions.js +235 -0
  105. package/dist/platform/insights/period-report.js +1871 -0
  106. package/dist/platform/insights/period-routes.js +237 -0
  107. package/dist/platform/insights/period-schema.sqlite.js +112 -0
  108. package/dist/platform/insights/pr-refs.js +107 -0
  109. package/dist/platform/insights/pr-token.js +22 -0
  110. package/dist/platform/insights/routes.js +71 -0
  111. package/dist/platform/insights/schema.sqlite.js +122 -0
  112. package/dist/platform/insights/sprint-report.js +605 -0
  113. package/dist/platform/insights/workspace-request.js +64 -0
  114. package/dist/platform/insights/workspace-scope.js +77 -0
  115. package/dist/platform/llm/gate.js +22 -0
  116. package/dist/platform/llm/seam.js +156 -0
  117. package/dist/platform/migrate.js +15 -0
  118. package/dist/platform/migration-files.js +36 -0
  119. package/dist/platform/migrations/0001_init.sql +23 -0
  120. package/dist/platform/migrations/0002_ai_fix.sql +25 -0
  121. package/dist/platform/migrations/0003_ai_fix_resolve.sql +19 -0
  122. package/dist/platform/migrations/0004_sprint_report.sql +19 -0
  123. package/dist/platform/migrations/0005_pro_settings.sql +26 -0
  124. package/dist/platform/migrations/0006_issue_project_keys.sql +7 -0
  125. package/dist/platform/migrations/0007_comparison_mode.sql +8 -0
  126. package/dist/platform/migrations/0008_retro_report.sql +19 -0
  127. package/dist/platform/migrations/0009_bot_settings.sql +17 -0
  128. package/dist/platform/migrations/0010_team_scope.sql +33 -0
  129. package/dist/platform/migrations/0011_comment_assess.sql +22 -0
  130. package/dist/platform/migrations/0012_resolution_check.sql +23 -0
  131. package/dist/platform/migrations/0013_pinned_prompts.sql +19 -0
  132. package/dist/platform/migrations/0014_bot_themes.sql +24 -0
  133. package/dist/platform/migrations/0015_human_themes.sql +23 -0
  134. package/dist/platform/migrations/0016_sprint_chat_history.sql +24 -0
  135. package/dist/platform/migrations/0017_pr_comment_annotations.sql +63 -0
  136. package/dist/platform/migrations/0018_drop_retro_reports.sql +19 -0
  137. package/dist/platform/migrations/0019_bot_cost_to_account_reviewers.sql +258 -0
  138. package/dist/platform/migrations/0020_workspace_scope_keys.sql +235 -0
  139. package/dist/platform/migrations/0021_bot_advisor.sql +82 -0
  140. package/dist/platform/migrations/0022_annotation_evidence.sql +32 -0
  141. package/dist/platform/migrations/0023_chat_answer_window.sql +30 -0
  142. package/dist/platform/migrations/0024_ai_fix_comment_seed.sql +44 -0
  143. package/dist/platform/migrations/0025_period_reports.sql +100 -0
  144. package/dist/platform/migrations/0026_period_lanes.sql +19 -0
  145. package/dist/platform/migrations/0027_synthesis.sql +57 -0
  146. package/dist/platform/migrations/0028_work_plan.sql +66 -0
  147. package/dist/platform/migrations/0029_workspace_sprint_cadence.sql +73 -0
  148. package/dist/platform/migrations/0030_workspace_slack_targets.sql +127 -0
  149. package/dist/platform/migrations/0031_workspace_issue_tracker.sql +116 -0
  150. package/dist/platform/migrations/0032_workspace_comparison_mode.sql +77 -0
  151. package/dist/platform/migrations/0033_slack_target_bot_digest.sql +47 -0
  152. package/dist/platform/migrations/0034_flow_pointers.sql +32 -0
  153. package/dist/platform/migrations/0035_workspace_jira_api.sql +28 -0
  154. package/dist/platform/migrations/0036_workspace_auto_review.sql +19 -0
  155. package/dist/platform/migrations/0037_auto_review_to_core.sql +31 -0
  156. package/dist/platform/migrations/0038_pr_jira_tickets.sql +13 -0
  157. package/dist/platform/migrations/0039_jira_ticket_peers.sql +8 -0
  158. package/dist/platform/migrations/0040_slack_event_signals.sql +24 -0
  159. package/dist/platform/resolution-check/schema.sqlite.js +35 -0
  160. package/dist/platform/retention.js +157 -0
  161. package/dist/platform/review-assess/schema.sqlite.js +32 -0
  162. package/dist/platform/settings/routes.js +172 -0
  163. package/dist/platform/settings/schema.sqlite.js +259 -0
  164. package/dist/platform/settings/store.js +505 -0
  165. package/dist/platform/slack/cron.js +190 -0
  166. package/dist/platform/slack/format.js +335 -0
  167. package/dist/platform/slack/links.js +124 -0
  168. package/dist/platform/slack/pending-blocks.js +212 -0
  169. package/dist/platform/slack/report.js +224 -0
  170. package/dist/platform/slack/routes.js +127 -0
  171. package/dist/platform/slack/schema.sqlite.js +24 -0
  172. package/dist/platform/slack/send.js +32 -0
  173. package/dist/platform/slack/signals.js +195 -0
  174. package/dist/platform/slack/targets.js +237 -0
  175. package/dist/platform/synthesis/hash.js +44 -0
  176. package/dist/platform/synthesis/prompt.js +110 -0
  177. package/dist/platform/synthesis/routes.js +299 -0
  178. package/dist/platform/synthesis/schema.sqlite.js +47 -0
  179. package/dist/platform/synthesis/scope.js +159 -0
  180. package/dist/platform/themes/resolve.js +90 -0
  181. package/dist/platform/work-plan/hash.js +99 -0
  182. package/dist/platform/work-plan/prompt.js +209 -0
  183. package/dist/platform/work-plan/routes.js +344 -0
  184. package/dist/platform/work-plan/schema.sqlite.js +74 -0
  185. package/dist/reference-docs/agent.js +3 -0
  186. package/dist/reference-docs/chat-quotes.js +229 -0
  187. package/dist/reference-docs/chat.js +6 -39
  188. package/dist/reference-docs/context.js +1 -1
  189. package/dist/reference-docs/prompts.js +1 -0
  190. package/dist/reference-docs/render.js +5 -1
  191. package/dist/reference-docs/review-refs.js +3 -35
  192. package/dist/reference-docs/routes.js +0 -3
  193. package/dist/reference-docs/store.js +2 -1
  194. package/dist/reference-docs/url-fetch.js +1 -1
  195. package/dist/review/agent-context.js +2 -26
  196. package/dist/review/agent.js +2 -0
  197. package/dist/review/agentic.js +3 -10
  198. package/dist/review/auth.js +27 -59
  199. package/dist/review/chat-agent.js +2 -0
  200. package/dist/review/ci-review/agent.js +2 -0
  201. package/dist/review/ci-review/routes.js +0 -4
  202. package/dist/review/ci-review/sweep.js +0 -2
  203. package/dist/review/claude-review/auto-post.js +312 -89
  204. package/dist/review/claude-review/auto.js +1 -9
  205. package/dist/review/claude-review/chat.js +1 -9
  206. package/dist/review/claude-review/manager.js +3 -9
  207. package/dist/review/claude-review/persist.js +3 -2
  208. package/dist/review/claude-review/routes.js +1 -9
  209. package/dist/review/claude-review/thread-check-agent.js +2 -0
  210. package/dist/review/claude-review/thread-check-routes.js +0 -4
  211. package/dist/review/diagrams/agent.js +2 -0
  212. package/dist/review/diagrams/routes.js +0 -4
  213. package/dist/review/diagrams/trigger.js +1 -1
  214. package/dist/review/llm.js +35 -48
  215. package/dist/review/post-seam.js +3 -2
  216. package/dist/review/sprint-paths/agent.js +2 -0
  217. package/dist/review/story-docs/agent.js +2 -0
  218. package/dist/review/story-docs/routes.js +0 -3
  219. package/dist/review/story-labels/routes.js +4 -19
  220. package/dist/review/ticket-review/agent.js +2 -0
  221. package/dist/review/ticket-review/auto-post.js +31 -38
  222. package/dist/review/ticket-review/post-item.js +187 -104
  223. package/dist/review/ticket-review/prepass.js +2 -0
  224. package/dist/review/ticket-review/routes.js +20 -19
  225. package/dist/review/ticket-review/sprint-checks.js +1 -4
  226. package/dist/review/ticket-review/sweep.js +0 -2
  227. package/dist/shared/index.js +1 -0
  228. package/dist/shared/reference-docs-quote.js +144 -0
  229. package/dist/shared/reference-docs.js +20 -0
  230. package/dist/shared/types.js +4 -27
  231. package/dist/sonar/comment.js +85 -7
  232. package/dist/sonar/index.js +0 -1
  233. package/dist/sonar/post.js +104 -10
  234. package/dist/sonar/routes.js +34 -36
  235. package/dist/sync/auth-notices.js +3 -5
  236. package/dist/sync/hydrate-detail.js +2 -2
  237. package/dist/sync/mention-scan.js +2 -9
  238. package/dist/sync/ml-enrichment.js +2 -8
  239. package/dist/sync/reviewer-classify.js +1 -1
  240. package/dist/sync/scheduler.js +0 -14
  241. package/dist/sync/sync-manager.js +3 -17
  242. package/dist/sync/upsert.js +1 -1
  243. package/dist/tracker/calls.js +3 -1
  244. package/dist/tracker/legacy-import.js +1 -25
  245. package/dist/tracker/manual-links.js +0 -1
  246. package/dist/tracker/routes.js +2 -3
  247. package/dist/tracker/runtime.js +4 -6
  248. package/dist/tracker/sprint/read.js +1 -2
  249. package/dist/tracker/stories.js +0 -1
  250. package/dist/tracker/worker.js +1 -1
  251. package/package.json +3 -6
  252. package/public/assets/AiFixTab-BRFh4rBA.js +3 -0
  253. package/public/assets/ClaudeReviewTab-D2GE3Lpe.js +20 -0
  254. package/public/assets/{PrBotBehaviourTab-BJelm30R.js → PrBotBehaviourTab-CEBLkCG5.js} +1 -1
  255. package/public/assets/{highlight-CIIZLa6Z.js → highlight-DIEV0qGG.js} +1 -1
  256. package/public/assets/index-hgG9aujx.css +1 -0
  257. package/public/assets/index-jmnLc1R-.js +79 -0
  258. package/public/assets/{markdown-I_JLLVAZ.js → markdown-CcoLFczy.js} +1 -1
  259. package/public/assets/tanstack-BnbsafB1.js +17 -0
  260. package/public/index.html +5 -5
  261. package/dist/api/routes/auth.js +0 -194
  262. package/dist/api/routes/billing.js +0 -209
  263. package/dist/api/routes/contact.js +0 -318
  264. package/dist/api/routes/mentions.js +0 -22
  265. package/dist/api/routes/webhooks.js +0 -181
  266. package/dist/db/automation-output.js +0 -349
  267. package/dist/db/credits.js +0 -79
  268. package/dist/db/migrations-pg/0000_tired_alex_power.sql +0 -268
  269. package/dist/db/migrations-pg/0001_dizzy_mockingbird.sql +0 -3
  270. package/dist/db/migrations-pg/0002_glorious_ikaris.sql +0 -4
  271. package/dist/db/migrations-pg/0003_melted_secret_warriors.sql +0 -2
  272. package/dist/db/migrations-pg/0004_numerous_triton.sql +0 -1
  273. package/dist/db/migrations-pg/0005_thick_blockbuster.sql +0 -2
  274. package/dist/db/migrations-pg/0006_majestic_dracula.sql +0 -1
  275. package/dist/db/migrations-pg/0007_same_human_torch.sql +0 -2
  276. package/dist/db/migrations-pg/0008_slimy_toxin.sql +0 -1
  277. package/dist/db/migrations-pg/0009_fuzzy_jubilee.sql +0 -4
  278. package/dist/db/migrations-pg/0010_late_hammerhead.sql +0 -1
  279. package/dist/db/migrations-pg/0011_happy_leech.sql +0 -16
  280. package/dist/db/migrations-pg/0012_woozy_captain_midlands.sql +0 -16
  281. package/dist/db/migrations-pg/0013_yielding_nicolaos.sql +0 -1
  282. package/dist/db/migrations-pg/0014_wakeful_bill_hollister.sql +0 -2
  283. package/dist/db/migrations-pg/0015_aspiring_black_tom.sql +0 -1
  284. package/dist/db/migrations-pg/0016_cute_ghost_rider.sql +0 -30
  285. package/dist/db/migrations-pg/0017_far_changeling.sql +0 -24
  286. package/dist/db/migrations-pg/0018_fancy_miss_america.sql +0 -1
  287. package/dist/db/migrations-pg/0019_benchmark_contributions.sql +0 -22
  288. package/dist/db/migrations-pg/0020_majestic_edwin_jarvis.sql +0 -3
  289. package/dist/db/migrations-pg/0021_green_salo.sql +0 -1
  290. package/dist/db/migrations-pg/0022_wise_baron_strucker.sql +0 -1
  291. package/dist/db/migrations-pg/0023_search_index.sql +0 -19
  292. package/dist/db/migrations-pg/0024_author_indexes.sql +0 -9
  293. package/dist/db/migrations-pg/0025_auto_merge_requests.sql +0 -26
  294. package/dist/db/migrations-pg/0026_branch_status.sql +0 -32
  295. package/dist/db/migrations-pg/0027_pr_review_decision.sql +0 -5
  296. package/dist/db/migrations-pg/0028_branch_commit_detail.sql +0 -9
  297. package/dist/db/migrations-pg/0029_repo_reviewers.sql +0 -127
  298. package/dist/db/migrations-pg/0030_account_reviewers.sql +0 -77
  299. package/dist/db/migrations-pg/0031_workspaces.sql +0 -131
  300. package/dist/db/migrations-pg/0032_workspace_reviewers.sql +0 -165
  301. package/dist/db/migrations-pg/0033_drop_inbox_watch.sql +0 -14
  302. package/dist/db/migrations-pg/0034_ml_comment_labels.sql +0 -33
  303. package/dist/db/migrations-pg/0035_ml_vendor_severity.sql +0 -16
  304. package/dist/db/migrations-pg/0036_seat_pricing_repo_description.sql +0 -12
  305. package/dist/db/migrations-pg/0037_users_app_slug.sql +0 -9
  306. package/dist/db/migrations-pg/0038_auto_merge_queue.sql +0 -10
  307. package/dist/db/migrations-pg/0039_trunk_ci_status_events.sql +0 -27
  308. package/dist/db/migrations-pg/0040_automation_roles.sql +0 -63
  309. package/dist/db/migrations-pg/0041_automation_vendor_kinds.sql +0 -488
  310. package/dist/db/migrations-pg/0042_auto_merge_phase.sql +0 -8
  311. package/dist/db/migrations-pg/0043_pr_mentions.sql +0 -19
  312. package/dist/db/migrations-pg/0044_large_pr_threshold.sql +0 -6
  313. package/dist/db/migrations-pg/0045_pending_mute.sql +0 -26
  314. package/dist/db/migrations-pg/0046_merge_queue_state.sql +0 -18
  315. package/dist/db/migrations-pg/0047_drop_my_turn_dismissals.sql +0 -21
  316. package/dist/db/migrations-pg/0048_auto_merge_durable_anchors.sql +0 -27
  317. package/dist/db/migrations-pg/0049_blast_radius_config.sql +0 -8
  318. package/dist/db/migrations-pg/0050_repo_file_coupling.sql +0 -13
  319. package/dist/db/migrations-pg/0051_pr_content_kind.sql +0 -6
  320. package/dist/db/migrations-pg/0052_workspace_flow_settings.sql +0 -4
  321. package/dist/db/migrations-pg/0053_review_request_events.sql +0 -18
  322. package/dist/db/migrations-pg/0054_pr_security_signals.sql +0 -59
  323. package/dist/db/migrations-pg/0055_my_turn_settings.sql +0 -6
  324. package/dist/db/migrations-pg/0056_my_turn_dismissals.sql +0 -21
  325. package/dist/db/migrations-pg/0057_claude_review_follow_up_ticket.sql +0 -8
  326. package/dist/db/migrations-pg/0058_claude_review_trigger.sql +0 -4
  327. package/dist/db/migrations-pg/0059_commit_message_headline.sql +0 -3
  328. package/dist/db/migrations-pg/0060_claude_review_chat.sql +0 -24
  329. package/dist/db/migrations-pg/0061_adopt_agentic_tables.sql +0 -79
  330. package/dist/db/migrations-pg/0062_review_lens_drop_learnings.sql +0 -5
  331. package/dist/db/migrations-pg/0063_claude_review_threads.sql +0 -7
  332. package/dist/db/migrations-pg/0064_claude_review_ci_failures.sql +0 -4
  333. package/dist/db/migrations-pg/0065_ai_fix_change_report.sql +0 -9
  334. package/dist/db/migrations-pg/0066_claude_finding_story.sql +0 -7
  335. package/dist/db/migrations-pg/0067_ticket_reviews.sql +0 -79
  336. package/dist/db/migrations-pg/0068_review_request_requester.sql +0 -14
  337. package/dist/db/migrations-pg/0069_ci_reviews.sql +0 -65
  338. package/dist/db/migrations-pg/0070_workspace_auto_fix.sql +0 -3
  339. package/dist/db/migrations-pg/0071_auto_fix_off_by_default.sql +0 -5
  340. package/dist/db/migrations-pg/0072_auto_review_daily_cap.sql +0 -3
  341. package/dist/db/migrations-pg/0073_ticket_review_pr_cards.sql +0 -17
  342. package/dist/db/migrations-pg/0074_auto_post.sql +0 -14
  343. package/dist/db/migrations-pg/0075_issue_tracker.sql +0 -77
  344. package/dist/db/migrations-pg/0076_github_issue_links.sql +0 -6
  345. package/dist/db/migrations-pg/0077_linear_links.sql +0 -8
  346. package/dist/db/migrations-pg/0078_auto_post_verdict_resolve_fix.sql +0 -11
  347. package/dist/db/migrations-pg/0079_finding_pushback.sql +0 -3
  348. package/dist/db/migrations-pg/0080_dependency_auto_merge.sql +0 -16
  349. package/dist/db/migrations-pg/0081_repo_uses_github_issues.sql +0 -7
  350. package/dist/db/migrations-pg/0082_review_chat_explain.sql +0 -5
  351. package/dist/db/migrations-pg/0083_workspace_setting_events.sql +0 -13
  352. package/dist/db/migrations-pg/0084_story_reports.sql +0 -28
  353. package/dist/db/migrations-pg/0085_tracker_ticket_dates.sql +0 -5
  354. package/dist/db/migrations-pg/0086_story_labels.sql +0 -19
  355. package/dist/db/migrations-pg/0087_sprint_stories.sql +0 -121
  356. package/dist/db/migrations-pg/0088_sprint_reads_api_root.sql +0 -3
  357. package/dist/db/migrations-pg/0089_workspace_sprint_checks.sql +0 -3
  358. package/dist/db/migrations-pg/0090_sprint_statuses_and_blockers.sql +0 -14
  359. package/dist/db/migrations-pg/0091_sprint_ticket_repos_saved.sql +0 -4
  360. package/dist/db/migrations-pg/0092_sprint_assessment_mode.sql +0 -4
  361. package/dist/db/migrations-pg/0093_sprint_ref_tickets.sql +0 -21
  362. package/dist/db/migrations-pg/0094_sprint_graph.sql +0 -38
  363. package/dist/db/migrations-pg/0095_sprint_themes.sql +0 -19
  364. package/dist/db/migrations-pg/0096_sprint_story.sql +0 -18
  365. package/dist/db/migrations-pg/0097_finding_reminder.sql +0 -3
  366. package/dist/db/migrations-pg/0098_sprint_dates_story_attempt.sql +0 -12
  367. package/dist/db/migrations-pg/0099_sprint_view_snapshots.sql +0 -15
  368. package/dist/db/migrations-pg/0100_ai_fix_plan.sql +0 -13
  369. package/dist/db/migrations-pg/0101_sonarcloud.sql +0 -31
  370. package/dist/db/migrations-pg/0102_sequence_diagrams.sql +0 -32
  371. package/dist/db/migrations-pg/0103_reference_docs.sql +0 -51
  372. package/dist/db/migrations-pg/0104_review_doc_references.sql +0 -5
  373. package/dist/db/migrations-pg/0105_sequence_diagram_runs.sql +0 -5
  374. package/dist/db/migrations-pg/0106_design_diagrams.sql +0 -3
  375. package/dist/db/migrations-pg/0107_sprint_paths.sql +0 -26
  376. package/dist/db/migrations-pg/0108_story_docs_alignments.sql +0 -34
  377. package/dist/db/migrations-pg/0109_claude_thread_checks.sql +0 -31
  378. package/dist/db/migrations-pg/0110_sprint_brief_one_liner.sql +0 -3
  379. package/dist/db/migrations-pg/0111_reference_doc_crawl.sql +0 -3
  380. package/dist/db/migrations-pg/meta/0000_snapshot.json +0 -2137
  381. package/dist/db/migrations-pg/meta/0001_snapshot.json +0 -2143
  382. package/dist/db/migrations-pg/meta/0002_snapshot.json +0 -2170
  383. package/dist/db/migrations-pg/meta/0003_snapshot.json +0 -2182
  384. package/dist/db/migrations-pg/meta/0004_snapshot.json +0 -2188
  385. package/dist/db/migrations-pg/meta/0005_snapshot.json +0 -2201
  386. package/dist/db/migrations-pg/meta/0006_snapshot.json +0 -2207
  387. package/dist/db/migrations-pg/meta/0007_snapshot.json +0 -2219
  388. package/dist/db/migrations-pg/meta/0008_snapshot.json +0 -2226
  389. package/dist/db/migrations-pg/meta/0009_snapshot.json +0 -2250
  390. package/dist/db/migrations-pg/meta/0010_snapshot.json +0 -2256
  391. package/dist/db/migrations-pg/meta/0011_snapshot.json +0 -2412
  392. package/dist/db/migrations-pg/meta/0012_snapshot.json +0 -2528
  393. package/dist/db/migrations-pg/meta/0013_snapshot.json +0 -2534
  394. package/dist/db/migrations-pg/meta/0014_snapshot.json +0 -2547
  395. package/dist/db/migrations-pg/meta/0015_snapshot.json +0 -2553
  396. package/dist/db/migrations-pg/meta/0016_snapshot.json +0 -2774
  397. package/dist/db/migrations-pg/meta/0017_snapshot.json +0 -2999
  398. package/dist/db/migrations-pg/meta/0018_snapshot.json +0 -3020
  399. package/dist/db/migrations-pg/meta/0020_snapshot.json +0 -3228
  400. package/dist/db/migrations-pg/meta/0021_snapshot.json +0 -3234
  401. package/dist/db/migrations-pg/meta/0022_snapshot.json +0 -3240
  402. package/dist/db/migrations-pg/meta/_journal.json +0 -790
  403. package/dist/db/schema.pg.js +0 -2197
  404. package/dist/pro/contract.js +0 -36
  405. package/dist/pro/migrate.js +0 -64
  406. package/dist/sync/benchmark-rollup.js +0 -50
  407. package/public/assets/AiFixTab-IKfiwwnd.js +0 -3
  408. package/public/assets/ClaudeReviewTab-DlefFnYI.js +0 -20
  409. package/public/assets/index-CB4YyNHK.css +0 -1
  410. package/public/assets/index-Cm0XoYfd.js +0 -79
  411. package/public/assets/tanstack-5qsxxaLe.js +0 -17
  412. package/public-landing/apple-touch-icon.png +0 -0
  413. package/public-landing/assets/archivo-latin-500-BWmvx2Mg.woff2 +0 -0
  414. package/public-landing/assets/archivo-latin-600-BN-JkNrl.woff2 +0 -0
  415. package/public-landing/assets/index-D3DGTvPS.js +0 -40
  416. package/public-landing/assets/index-naQrQ6Fe.css +0 -1
  417. package/public-landing/assets/jetbrains-mono-latin-400-RruCX7RW.woff2 +0 -0
  418. package/public-landing/assets/newsreader-latin-400-DExrRRrN.woff2 +0 -0
  419. package/public-landing/assets/newsreader-latin-400-italic-b0I-AwbV.woff2 +0 -0
  420. package/public-landing/bots/index.html +0 -156
  421. package/public-landing/contact/index.html +0 -156
  422. package/public-landing/cookies/index.html +0 -156
  423. package/public-landing/demo/limn-walkthrough-poster.jpg +0 -0
  424. package/public-landing/demo/limn-walkthrough.cues.json +0 -44
  425. package/public-landing/demo/limn-walkthrough.mp4 +0 -0
  426. package/public-landing/favicon-16.png +0 -0
  427. package/public-landing/favicon-32.png +0 -0
  428. package/public-landing/favicon-48.png +0 -0
  429. package/public-landing/favicon.svg +0 -5
  430. package/public-landing/features/index.html +0 -156
  431. package/public-landing/for-developers/index.html +0 -156
  432. package/public-landing/for-managers/index.html +0 -156
  433. package/public-landing/how-it-works/index.html +0 -156
  434. package/public-landing/how-we-measure/index.html +0 -156
  435. package/public-landing/icon-192.png +0 -0
  436. package/public-landing/icon-512.png +0 -0
  437. package/public-landing/index.html +0 -156
  438. package/public-landing/insights/index.html +0 -156
  439. package/public-landing/og-image.png +0 -0
  440. package/public-landing/pricing/index.html +0 -156
  441. package/public-landing/privacy/index.html +0 -156
  442. package/public-landing/pro/index.html +0 -156
  443. package/public-landing/reviews/index.html +0 -156
  444. package/public-landing/robots.txt +0 -8
  445. package/public-landing/shots/benchmark.png +0 -0
  446. package/public-landing/shots/bot-roi.png +0 -0
  447. package/public-landing/shots/bot-settings.png +0 -0
  448. package/public-landing/shots/chronology.png +0 -0
  449. package/public-landing/shots/feed.png +0 -0
  450. package/public-landing/shots/flow-metrics.png +0 -0
  451. package/public-landing/shots/free-reports.png +0 -0
  452. package/public-landing/shots/pending-board.png +0 -0
  453. package/public-landing/shots/pending-card.png +0 -0
  454. package/public-landing/shots/period-report.png +0 -0
  455. package/public-landing/shots/pr-detail.png +0 -0
  456. package/public-landing/shots/pr-threads.png +0 -0
  457. package/public-landing/shots/reach.png +0 -0
  458. package/public-landing/shots/repo-rows.png +0 -0
  459. package/public-landing/shots/severity-findings.png +0 -0
  460. package/public-landing/shots/severity-strip.png +0 -0
  461. package/public-landing/site.webmanifest +0 -14
  462. package/public-landing/sitemap.xml +0 -51
  463. package/public-landing/terms/index.html +0 -156
package/LICENSE CHANGED
@@ -1,110 +1,127 @@
1
- # Functional Source License, Version 1.1, MIT Future License
1
+ # Limn License 1.0
2
2
 
3
- ## Abbreviation
3
+ Copyright 2026 Alex Wakeman
4
4
 
5
- FSL-1.1-MIT
5
+ ## 1. Acceptance
6
6
 
7
- ## Notice
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
- Copyright 2026 Alex Wakeman
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
- ## Terms and Conditions
21
+ Any purpose is a permitted purpose for:
12
22
 
13
- ### Licensor ("We")
23
+ (a) an individual using the software for themselves; and
14
24
 
15
- The party offering the Software under these Terms and Conditions.
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
- ### The Software
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
- The "Software" is each version of the software that we make available under
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
- ### License Grant
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
- Subject to your compliance with this License Grant and the Patents,
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
- ### Permitted Purpose
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
- A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
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
- 1. substitutes for the Software;
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
- 2. substitutes for any other product or service we offer using the Software
39
- that exists as of the date we make the Software available; or
51
+ ## 7. Notices
40
52
 
41
- 3. offers the same or substantially similar functionality as the Software.
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
- Permitted Purposes specifically include using the Software:
59
+ ## 8. Patent License
44
60
 
45
- 1. for your internal use and access;
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
- 2. for non-commercial education;
65
+ ## 9. Fair Use
48
66
 
49
- 3. for non-commercial research; and
67
+ You may have "fair use" rights for the software under the law. These terms do
68
+ not limit them.
50
69
 
51
- 4. in connection with professional services that you provide to a licensee
52
- using the Software in accordance with these Terms and Conditions.
70
+ ## 10. No Other Rights
53
71
 
54
- ### Patents
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
- To the extent your use for a Permitted Purpose would necessarily infringe our
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
- ### Redistribution
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
- The Terms and Conditions apply to all copies, modifications and derivatives of
65
- the Software.
85
+ ## 12. Violations
66
86
 
67
- If you redistribute any copies, modifications or derivatives of the Software,
68
- you must include a copy of or a link to these Terms and Conditions and not
69
- remove any copyright notices provided in or with the Software.
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
- ### Disclaimer
93
+ ## 13. No Liability
72
94
 
73
- THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
74
- IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
75
- PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
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
- IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
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
- ### Trademarks
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
- Except for displaying the License Details and identifying us as the origin of
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
- ## Grant of Future License
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
- We hereby irrevocably grant you an additional license to use the Software under
90
- the MIT license that is effective on the second anniversary of the date we make
91
- the Software available. On or after that date, you may use the Software under
92
- the MIT license, in which case the following will apply:
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
- Permission is hereby granted, free of charge, to any person obtaining a copy of
95
- this software and associated documentation files (the "Software"), to deal in
96
- the Software without restriction, including without limitation the rights to
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
- The above copyright notice and this permission notice shall be included in all
102
- copies or substantial portions of the Software.
124
+ **Your licenses** are all the licenses granted to you for the software under
125
+ these terms.
103
126
 
104
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
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. They run on
36
- your own Claude Code or Anthropic API key: sign in to Claude Code, or set
37
- `ANTHROPIC_API_KEY`. Limn stores no key and charges nothing for it.
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 **Functional Source License (FSL-1.1-MIT)** — see
129
- [LICENSE](./LICENSE). You may use, self-host, and modify Limn freely; you may
130
- **not** offer it as a competing commercial or hosted product. Each release
131
- automatically converts to the **MIT License** two years after its publication.
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
@@ -1,169 +1,25 @@
1
- import { createHash } from 'node:crypto';
2
- import { config } from '../../config.js';
3
- import { getAccountById, getLocalAccountCached, stampAccountActive, LOCAL_ACCOUNT_ID, } from '../../auth/account.js';
4
- // Attaches `request.account` to every request. Registered once on the root app
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
- if (config.isCloud) {
15
- const accountId = readSessionAccountId(req);
16
- req.account = accountId != null ? await getAccountById(accountId) : null;
17
- // A request from a signed-in account on a real data route means that tenant
18
- // has a loaded frontend — stamp activity (throttled) so the scheduler keeps
19
- // syncing their repos. Skips static/landing assets and the health/auth probes.
20
- if (req.account && req.url.startsWith('/api/')) {
21
- stampAccountActive(req.account.id);
22
- }
23
- }
24
- else {
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
- // Reads {accountId} from the sealed session cookie. @fastify/secure-session is
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
- if (req.account)
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