pulls.review 0.0.0 → 0.1.0

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 (159) hide show
  1. package/dist/index.mjs +149 -0
  2. package/package.json +26 -65
  3. package/README.md +0 -15
  4. package/dist/assets/ChatWidget-BD4etTSI.css +0 -1
  5. package/dist/assets/ChatWidget-BXmVT9ns.js +0 -2
  6. package/dist/assets/_number_-ByKh-CJ7.js +0 -1
  7. package/dist/assets/agent-SYDXCLiI.js +0 -90
  8. package/dist/assets/andromeeda-vGVdxbeo.js +0 -1
  9. package/dist/assets/anthropic-messages-XptRMkpJ.js +0 -41
  10. package/dist/assets/aurora-x-CDeNXAV0.js +0 -1
  11. package/dist/assets/ayu-dark-DluEY0Gj.js +0 -1
  12. package/dist/assets/ayu-light-C3h-C4tm.js +0 -1
  13. package/dist/assets/ayu-mirage-Bqwy1Gya.js +0 -1
  14. package/dist/assets/c-BWgYNV7i.js +0 -1
  15. package/dist/assets/catppuccin-frappe-C9Q5zVZY.js +0 -1
  16. package/dist/assets/catppuccin-latte-CtsyrtPq.js +0 -1
  17. package/dist/assets/catppuccin-macchiato-R8nAf1vR.js +0 -1
  18. package/dist/assets/catppuccin-mocha-DjuaAJKi.js +0 -1
  19. package/dist/assets/chat-CP0CZKJo.js +0 -1
  20. package/dist/assets/clojure-DqKBuwfJ.js +0 -1
  21. package/dist/assets/cpp-BBcYm61y.js +0 -1
  22. package/dist/assets/csharp-oqKa8noW.js +0 -1
  23. package/dist/assets/css-dNRduEa-.js +0 -1
  24. package/dist/assets/dark-plus-Cs2F2srj.js +0 -1
  25. package/dist/assets/diff-woXpYk--.js +0 -1
  26. package/dist/assets/diffs-store-B1RXognA.js +0 -1696
  27. package/dist/assets/dist-hXdF5ZNr.js +0 -1
  28. package/dist/assets/docker-IyjqRm3v.js +0 -1
  29. package/dist/assets/dracula-BHWKrbxM.js +0 -1
  30. package/dist/assets/dracula-soft-5eyTD99u.js +0 -1
  31. package/dist/assets/elixir-BMAS0SZ2.js +0 -1
  32. package/dist/assets/error-CJ3RHG07.js +0 -1
  33. package/dist/assets/everforest-dark-sB-x3p7T.js +0 -1
  34. package/dist/assets/everforest-light-Df2xbC6M.js +0 -1
  35. package/dist/assets/fonts/dmmono-53a90e28.woff2 +0 -0
  36. package/dist/assets/fonts/dmmono-cd6ed524.woff2 +0 -0
  37. package/dist/assets/fonts/dmsans-56778fc7.woff2 +0 -0
  38. package/dist/assets/fonts/dmsans-7c37c8a6.woff2 +0 -0
  39. package/dist/assets/fonts/dmserifdisplay-1f997542.woff2 +0 -0
  40. package/dist/assets/fonts/dmserifdisplay-b6206db2.woff2 +0 -0
  41. package/dist/assets/github-dark-C-LZuMrd.js +0 -1
  42. package/dist/assets/github-dark-default-DXG-b-1a.js +0 -1
  43. package/dist/assets/github-dark-dimmed-Bx1FflLF.js +0 -1
  44. package/dist/assets/github-dark-high-contrast-B_tTalzw.js +0 -1
  45. package/dist/assets/github-light-EUqPIrTm.js +0 -1
  46. package/dist/assets/github-light-default-BXViO-2h.js +0 -1
  47. package/dist/assets/github-light-high-contrast-B68TUdTA.js +0 -1
  48. package/dist/assets/go-rLFTqkRN.js +0 -1
  49. package/dist/assets/graphql-DC6gMr7C.js +0 -1
  50. package/dist/assets/groovy-CacY0gHj.js +0 -1
  51. package/dist/assets/gruvbox-dark-hard-C820rvS2.js +0 -1
  52. package/dist/assets/gruvbox-dark-medium-BPjhmG05.js +0 -1
  53. package/dist/assets/gruvbox-dark-soft-MrdJrrXF.js +0 -1
  54. package/dist/assets/gruvbox-light-hard-BC_s9l72.js +0 -1
  55. package/dist/assets/gruvbox-light-medium-BAWPOn9u.js +0 -1
  56. package/dist/assets/gruvbox-light-soft-BSMLrYjP.js +0 -1
  57. package/dist/assets/haskell-D8IpX4py.js +0 -1
  58. package/dist/assets/horizon-CE9ld1lL.js +0 -1
  59. package/dist/assets/horizon-bright-DSNQnXHK.js +0 -1
  60. package/dist/assets/houston-CsvMBhTu.js +0 -1
  61. package/dist/assets/html-9bR0RcZU.js +0 -1
  62. package/dist/assets/index-BD_DzwAn.js +0 -3
  63. package/dist/assets/index-Yd4-oLpR.css +0 -1
  64. package/dist/assets/indexedb-Cu6ZJjpB.js +0 -1
  65. package/dist/assets/ini-B5eOa1yu.js +0 -1
  66. package/dist/assets/java-C0DRq53f.js +0 -1
  67. package/dist/assets/javascript-UWfzLVwt.js +0 -1
  68. package/dist/assets/json-qhed-kSA.js +0 -1
  69. package/dist/assets/jsonc-CYpm1nAK.js +0 -1
  70. package/dist/assets/jsx-B85L4NBR.js +0 -1
  71. package/dist/assets/kanagawa-dragon-Bozd7klA.js +0 -1
  72. package/dist/assets/kanagawa-lotus-BmuOG9ZW.js +0 -1
  73. package/dist/assets/kanagawa-wave-BML5mF2J.js +0 -1
  74. package/dist/assets/kotlin-DhhofPvG.js +0 -1
  75. package/dist/assets/laserwave-C_8bwKvT.js +0 -1
  76. package/dist/assets/less-DVTAwKKz.js +0 -1
  77. package/dist/assets/light-plus-DVQuIRkW.js +0 -1
  78. package/dist/assets/lua-ByOrBoZ-.js +0 -1
  79. package/dist/assets/make-Dixweg8N.js +0 -1
  80. package/dist/assets/markdown-BYOwaDjH.js +0 -1
  81. package/dist/assets/material-theme-Bm3Qr25_.js +0 -1
  82. package/dist/assets/material-theme-darker-2IIEA8gg.js +0 -1
  83. package/dist/assets/material-theme-lighter-uhdI0v04.js +0 -1
  84. package/dist/assets/material-theme-ocean-CHQ94UKr.js +0 -1
  85. package/dist/assets/material-theme-palenight-B5W6OYN7.js +0 -1
  86. package/dist/assets/mdx-DQZ5AkYe.js +0 -1
  87. package/dist/assets/min-dark-BSWPekZh.js +0 -1
  88. package/dist/assets/min-light-DDpmG2fV.js +0 -1
  89. package/dist/assets/monokai-B_bV9PQ9.js +0 -1
  90. package/dist/assets/nginx-DBTb8aIg.js +0 -1
  91. package/dist/assets/night-owl-DhmEMT88.js +0 -1
  92. package/dist/assets/night-owl-light-eJ-hLW7d.js +0 -1
  93. package/dist/assets/node.browser-C40HpO0s.js +0 -1
  94. package/dist/assets/node.browser-DFtqp6Hr.js +0 -1
  95. package/dist/assets/nord-Cb4Vim4T.js +0 -1
  96. package/dist/assets/objective-c-D1A_Heim.js +0 -1
  97. package/dist/assets/objective-cpp-BsSzOQcm.js +0 -1
  98. package/dist/assets/one-dark-pro-CLwyXe_n.js +0 -1
  99. package/dist/assets/one-light-D7Lr4KcI.js +0 -1
  100. package/dist/assets/openai-completions-Cb_BwZvN.js +0 -21
  101. package/dist/assets/pages-KWcQcyk5.js +0 -1
  102. package/dist/assets/perl-Bk6ijEF5.js +0 -1
  103. package/dist/assets/php-CwqKKdmW.js +0 -1
  104. package/dist/assets/pierre-dark-CpLgRqie.js +0 -1
  105. package/dist/assets/pierre-dark-protanopia-deuteranopia-B35FxJx-.js +0 -1
  106. package/dist/assets/pierre-dark-soft-kZQmAZld.js +0 -1
  107. package/dist/assets/pierre-dark-tritanopia-CpjhbsIL.js +0 -1
  108. package/dist/assets/pierre-dark-vibrant-CpQYzh95.js +0 -1
  109. package/dist/assets/pierre-light-CoaEpmwp.js +0 -1
  110. package/dist/assets/pierre-light-protanopia-deuteranopia-0fSaH845.js +0 -1
  111. package/dist/assets/pierre-light-soft-lWLdNTOI.js +0 -1
  112. package/dist/assets/pierre-light-tritanopia-CEbqgOJL.js +0 -1
  113. package/dist/assets/pierre-light-vibrant-D80Fkn33.js +0 -1
  114. package/dist/assets/plastic-DQwYfKfQ.js +0 -1
  115. package/dist/assets/poimandres-DRFjx7u4.js +0 -1
  116. package/dist/assets/pr-cache-DNR7E646.js +0 -94
  117. package/dist/assets/proto-DB4EqR-F.js +0 -1
  118. package/dist/assets/python-gzcpVVnB.js +0 -1
  119. package/dist/assets/r-C5FwQflr.js +0 -1
  120. package/dist/assets/red-DX1BQOs8.js +0 -1
  121. package/dist/assets/rose-pine-aMsaMD1D.js +0 -1
  122. package/dist/assets/rose-pine-dawn-8PwUyIlP.js +0 -1
  123. package/dist/assets/rose-pine-moon-DO-qXg-I.js +0 -1
  124. package/dist/assets/ruby-Cf2R6w0b.js +0 -1
  125. package/dist/assets/runtime-core.esm-bundler-B8D2lM98.js +0 -3
  126. package/dist/assets/rust-Cfkwpbl8.js +0 -1
  127. package/dist/assets/scala-BiFt_7mu.js +0 -1
  128. package/dist/assets/scss-Dl-NjxyA.js +0 -1
  129. package/dist/assets/shellscript-CLZ0U2zV.js +0 -1
  130. package/dist/assets/shiki-wasm-noop-Gxv9UHE7.js +0 -1
  131. package/dist/assets/slack-dark-DnToyrRv.js +0 -1
  132. package/dist/assets/slack-ochin-B2OO5cIa.js +0 -1
  133. package/dist/assets/snazzy-light-4G7pJPwS.js +0 -1
  134. package/dist/assets/solarized-dark-UdsmMDCL.js +0 -1
  135. package/dist/assets/solarized-light-C1IUL_tW.js +0 -1
  136. package/dist/assets/sql-BsFa4tDR.js +0 -1
  137. package/dist/assets/swift-CyEgAFGc.js +0 -1
  138. package/dist/assets/synthwave-84-nFMaYfgc.js +0 -1
  139. package/dist/assets/terraform-DswuEJGm.js +0 -1
  140. package/dist/assets/tokyo-night-oM2G3aXe.js +0 -1
  141. package/dist/assets/toml-CcmNWLt0.js +0 -1
  142. package/dist/assets/transform-messages-DOewMBlN.js +0 -3
  143. package/dist/assets/tsx-CssvfOw5.js +0 -1
  144. package/dist/assets/typescript-CttGnwgr.js +0 -1
  145. package/dist/assets/upload-D7N53Rri.js +0 -1
  146. package/dist/assets/uploadSession-BUj4FNau.js +0 -1
  147. package/dist/assets/vesper-DdrHHSXu.js +0 -1
  148. package/dist/assets/vitesse-black-fwtXNY1n.js +0 -1
  149. package/dist/assets/vitesse-dark-BZCL-v6S.js +0 -1
  150. package/dist/assets/vitesse-light-VbXTXTou.js +0 -1
  151. package/dist/assets/vue-BeqRp0z0.js +0 -1
  152. package/dist/assets/vue-html-E9GYf_6s.js +0 -1
  153. package/dist/assets/xml-Dz7PSrBs.js +0 -1
  154. package/dist/assets/yaml-rwi0_p6S.js +0 -1
  155. package/dist/diffs-github.user.js +0 -23
  156. package/dist/embed/diffs-embed.js +0 -1948
  157. package/dist/index.html +0 -24
  158. package/dist/pulls-review-github.user.js +0 -23
  159. package/dist/robots.txt +0 -2
package/dist/index.mjs ADDED
@@ -0,0 +1,149 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
3
+ import process from "node:process";
4
+ import { parseArgs } from "node:util";
5
+ import { githubTokenFromEnv, llmSettingsFromEnv } from "@pulls.review/core/env";
6
+ import { runLlmAnalysis } from "@pulls.review/core/llm";
7
+ import { Diagnostic, formatDiagnostic } from "nostics";
8
+ import { DEFAULT_LOCALE, isLocale } from "@pulls.review/core/locales";
9
+ import { resolveModel } from "@pulls.review/core/analyze";
10
+ import { diagnostics } from "@pulls.review/core/diagnostics";
11
+ import { createGithubPullRequestSource } from "@pulls.review/core/github";
12
+ import { staticCredentials } from "@pulls.review/core/types";
13
+ //#region src/config.ts
14
+ /** The first value that is set and not blank: an Action passes unset inputs as `''`. */
15
+ function first(...values) {
16
+ return values.find((value) => value);
17
+ }
18
+ function resolveGithubToken(env) {
19
+ const token = githubTokenFromEnv(env);
20
+ if (!token) throw new Error("A GitHub token is required: set GITHUB_TOKEN (or PULLS_REVIEW_GITHUB_TOKEN).");
21
+ return token;
22
+ }
23
+ function resolveLocale(env, flags = {}) {
24
+ const requested = first(flags.locale, env.PULLS_REVIEW_LOCALE);
25
+ if (requested === void 0) return DEFAULT_LOCALE;
26
+ if (!isLocale(requested)) throw new Error(`Unsupported locale "${requested}".`);
27
+ return requested;
28
+ }
29
+ /**
30
+ * `owner/repo#123` or a github.com PR URL; in a workflow run, the PR the event is about.
31
+ */
32
+ function resolveTarget(arg, env, event) {
33
+ if (arg) {
34
+ const match = arg.match(/^(?:https:\/\/github\.com\/)?([^/\s]+)\/([^/#\s]+)(?:#|\/pull\/)(\d+)\/?$/);
35
+ if (!match) throw new Error(`Cannot read a pull request from "${arg}": expected owner/repo#123 or a github.com pull request URL.`);
36
+ return {
37
+ owner: match[1],
38
+ repo: match[2],
39
+ number: match[3]
40
+ };
41
+ }
42
+ const [owner, repo] = env.GITHUB_REPOSITORY?.split("/") ?? [];
43
+ const number = event?.pull_request?.number;
44
+ if (!owner || !repo || number === void 0) throw new Error("No pull request given. Pass owner/repo#123, or run on a pull_request event in GitHub Actions.");
45
+ return {
46
+ owner,
47
+ repo,
48
+ number: String(number)
49
+ };
50
+ }
51
+ //#endregion
52
+ //#region src/run.ts
53
+ /** The author GitHub shows for a workflow's `GITHUB_TOKEN`, which cannot look itself up at `/user`. */
54
+ const ACTIONS_BOT_LOGIN = "github-actions[bot]";
55
+ function describeProgress(progress) {
56
+ switch (progress.kind) {
57
+ case "thinking": return `[${progress.step}] thinking`;
58
+ case "reading": return `[${progress.step}] reading ${progress.paths.length} file${progress.paths.length === 1 ? "" : "s"}`;
59
+ case "organizing": return `[${progress.step}] organizing groups`;
60
+ }
61
+ }
62
+ /**
63
+ * Fetches the PR, analyzes it and upserts the shared-analysis comment, exactly like the
64
+ * site's "share as comment" - one comment per author, found by its marker. A comment
65
+ * already carrying the PR's current head sha is left alone, so re-runs on an unchanged
66
+ * PR cost no model call.
67
+ */
68
+ async function run({ pr, githubToken, llm, locale, log }, analyze) {
69
+ const resolved = resolveModel(llm);
70
+ if (!resolved) throw diagnostics.llmNotConfigured();
71
+ const source = createGithubPullRequestSource(pr, staticCredentials(githubToken));
72
+ const [diff, login, comments] = await Promise.all([
73
+ source.fetch(),
74
+ source.viewer().then((viewer) => viewer?.login ?? ACTIONS_BOT_LOGIN, () => ACTIONS_BOT_LOGIN),
75
+ source.sharing.list()
76
+ ]);
77
+ const headSha = diff.head?.sha ?? "";
78
+ const existing = comments.find((comment) => comment.login === login);
79
+ if (existing && existing.analysis.headSha === headSha) return {
80
+ status: "up-to-date",
81
+ url: existing.url
82
+ };
83
+ log(`Analyzing ${pr.owner}/${pr.repo}#${pr.number} (${diff.files.length} files) with ${resolved.model.provider}/${resolved.model.id}`);
84
+ const { result } = await analyze(diff, resolved, locale, { onProgress: (progress) => log(describeProgress(progress)) });
85
+ return {
86
+ status: "posted",
87
+ url: (await source.sharing.upsert(login, {
88
+ headSha,
89
+ result
90
+ }, existing)).url
91
+ };
92
+ }
93
+ //#endregion
94
+ //#region src/index.ts
95
+ const HELP = `Usage: pulls.review [owner/repo#123 | https://github.com/owner/repo/pull/123] [options]
96
+
97
+ Analyzes the pull request with an LLM and posts (or updates) the grouped summary as
98
+ a PR comment that pulls.review picks up. Without a target, reads the pull_request
99
+ event of the running GitHub Actions job.
100
+
101
+ Options:
102
+ --provider <name> gateway | anthropic | openai-compatible (PULLS_REVIEW_PROVIDER)
103
+ --model <id> model id for the provider (PULLS_REVIEW_MODEL)
104
+ --locale <tag> language of the summaries, default en (PULLS_REVIEW_LOCALE)
105
+ -h, --help
106
+
107
+ Environment:
108
+ GITHUB_TOKEN token with pull-requests: write (PULLS_REVIEW_GITHUB_TOKEN)
109
+ AI_GATEWAY_API_KEY Vercel AI Gateway key (PULLS_REVIEW_API_KEY)
110
+ ANTHROPIC_API_KEY Anthropic key (PULLS_REVIEW_API_KEY)
111
+ OPENAI_API_KEY OpenAI-compatible key (PULLS_REVIEW_API_KEY)
112
+ OPENAI_BASE_URL OpenAI-compatible endpoint (PULLS_REVIEW_BASE_URL)
113
+ `;
114
+ function readEvent(path) {
115
+ return path ? JSON.parse(readFileSync(path, "utf-8")) : void 0;
116
+ }
117
+ async function main() {
118
+ const { values: flags, positionals } = parseArgs({
119
+ options: {
120
+ provider: { type: "string" },
121
+ model: { type: "string" },
122
+ locale: { type: "string" },
123
+ help: {
124
+ type: "boolean",
125
+ short: "h"
126
+ }
127
+ },
128
+ allowPositionals: true
129
+ });
130
+ if (flags.help) {
131
+ console.log(HELP);
132
+ return;
133
+ }
134
+ const env = process.env;
135
+ const outcome = await run({
136
+ pr: resolveTarget(positionals[0], env, readEvent(env.GITHUB_EVENT_PATH)),
137
+ githubToken: resolveGithubToken(env),
138
+ llm: llmSettingsFromEnv(env, flags),
139
+ locale: resolveLocale(env, flags),
140
+ log: (line) => console.log(line)
141
+ }, runLlmAnalysis);
142
+ console.log(outcome.status === "up-to-date" ? `Comment already covers the current head: ${outcome.url}` : `Posted ${outcome.url}`);
143
+ }
144
+ main().catch((error) => {
145
+ console.error(error instanceof Diagnostic ? formatDiagnostic(error) : error instanceof Error ? error.message : String(error));
146
+ process.exitCode = 1;
147
+ });
148
+ //#endregion
149
+ export {};
package/package.json CHANGED
@@ -1,85 +1,46 @@
1
1
  {
2
2
  "name": "pulls.review",
3
3
  "type": "module",
4
- "version": "0.0.0",
5
- "description": "Review pull requests with grouped, summarized, and beautiful diffs.",
4
+ "version": "0.1.0",
5
+ "description": "Analyze a GitHub pull request with pulls.review and post the grouped summary as a PR comment.",
6
6
  "author": "Anthony Fu <hi@antfu.me>",
7
7
  "license": "MIT",
8
8
  "funding": "https://github.com/sponsors/antfu",
9
9
  "homepage": "https://pulls.review",
10
10
  "repository": {
11
11
  "type": "git",
12
- "url": "git+https://github.com/antfu/pulls.review.git"
12
+ "url": "git+https://github.com/antfu/pulls.review.git",
13
+ "directory": "packages/cli"
13
14
  },
14
15
  "bugs": "https://github.com/antfu/pulls.review/issues",
16
+ "keywords": [
17
+ "pull-request",
18
+ "code-review",
19
+ "github-actions",
20
+ "llm"
21
+ ],
22
+ "bin": {
23
+ "pulls.review": "./dist/index.mjs",
24
+ "pulls-review": "./dist/index.mjs"
25
+ },
15
26
  "files": [
16
27
  "dist"
17
28
  ],
18
- "dependencies": {},
29
+ "engines": {
30
+ "node": ">=20"
31
+ },
32
+ "dependencies": {
33
+ "@pulls.review/core": "^0.1.0",
34
+ "nostics": "^1.3.0"
35
+ },
19
36
  "devDependencies": {
20
- "@ai-sdk/anthropic": "^4.0.65",
21
- "@ai-sdk/gateway": "^4.0.96",
22
- "@ai-sdk/openai-compatible": "^3.0.57",
23
- "@antfu/design": "^0.5.3",
24
- "@antfu/eslint-config": "^9.5.1",
25
- "@antfu/utils": "^9.3.0",
26
- "@comark/vue": "^0.7.0",
27
- "@earendil-works/pi-agent-core": "^0.87.1",
28
- "@earendil-works/pi-ai": "^0.87.1",
29
- "@iconify-json/carbon": "^1.2.28",
30
- "@iconify-json/catppuccin": "^1.2.17",
31
- "@iconify-json/ph": "^1.2.2",
32
- "@iconify-json/twemoji": "^1.2.5",
33
- "@pierre/diffs": "^1.5.1",
34
- "@shikijs/engine-javascript": "^4.4.3",
35
- "@storybook/vue3-vite": "^10.6.0",
36
- "@tanstack/vue-virtual": "^3.13.39",
37
- "@types/node": "^26.6.3",
38
- "@types/picomatch": "^4.0.3",
39
- "@unocss/eslint-config": "^66.10.5",
40
- "@unocss/reset": "^66.10.5",
41
- "@valibot/to-json-schema": "^1.8.0",
42
- "@vitejs/plugin-vue": "^6.0.9",
43
- "@vue/test-utils": "^2.5.1",
44
- "@vueuse/core": "^14.4.0",
45
- "ai": "^7.0.118",
46
- "colorjs.io": "^0.7.1",
47
- "eslint": "^10.11.0",
48
- "eslint-plugin-format": "^2.0.1",
49
- "eslint-plugin-slop": "^0.1.3",
50
- "eslint-plugin-sonarjs": "^4.2.1",
51
- "fake-indexeddb": "^6.2.5",
52
- "happy-dom": "^20.14.5",
53
- "idb-keyval": "^6.3.0",
54
- "jiti": "^2.7.0",
55
- "lightningcss": "^1.33.0",
56
- "picomatch": "^4.0.7",
57
- "reka-ui": "^2.10.5",
58
- "storybook": "^10.6.0",
59
- "tinyglobby": "^0.2.17",
37
+ "@types/node": "^26.6.4",
60
38
  "typescript": "^6.0.3",
61
- "unocss": "^66.10.5",
62
- "unstorage": "^1.17.5",
63
- "valibot": "^1.5.0",
64
- "vite": "^8.3.1",
65
- "vitest": "^5.0.2",
66
- "vue": "^3.5.43",
67
- "vue-afloat": "^0.1.1",
68
- "vue-router": "^4.6.4",
69
- "vue-tsc": "^3.3.11"
39
+ "vitest": "^5.0.3"
70
40
  },
71
41
  "scripts": {
72
- "build": "pnpm run build:embed && vite build",
73
- "build:embed": "vite build --config vite.config.embed.ts",
74
- "dev": "vite",
75
- "play:embed": "pnpm run build:embed && vite --open /playgrounds/embed/",
76
- "preview": "vite preview",
77
- "start:generate": "npx serve dist",
78
- "lint": "eslint .",
79
- "typecheck": "vue-tsc --noEmit",
80
- "test": "vitest run",
81
- "test:watch": "vitest",
82
- "storybook": "storybook dev -p 6006",
83
- "storybook:build": "storybook build"
42
+ "build": "tsdown",
43
+ "typecheck": "tsc --noEmit",
44
+ "test": "vitest run"
84
45
  }
85
46
  }
package/README.md DELETED
@@ -1,15 +0,0 @@
1
- # pulls.review
2
-
3
- [pulls.review](https://pulls.review)
4
-
5
- > [!WARNING]
6
- > Heavily work in progress. Expect breaking changes, missing polish, and things that don't work yet.
7
-
8
- Review pull request with grouped, summarized, and beautiful diffs to be more focused and efficient.
9
-
10
- ## Userscript
11
-
12
- 1. Install [Tampermonkey](https://www.tampermonkey.net/) or [Violentmonkey](https://violentmonkey.github.io/).
13
- 2. Open [`pulls-review-github.user.js`](https://pulls.review/pulls-review-github.user.js) and let your extension pick it up (or create a new script and paste its contents in).
14
- 3. Visit any `github.com/{owner}/{repo}/pull/{number}` page - a "pulls.review" tab appears on the right edge; click it to open the drawer.
15
- 4. Drag the drawer's left edge to resize it - the width is remembered (`localStorage`, per-browser) for next time.
@@ -1 +0,0 @@
1
- @property --un-leading{syntax:"*";inherits:false}@property --un-bg-opacity{syntax:"<percentage>";inherits:false;initial-value:100%}@property --un-border-opacity{syntax:"<percentage>";inherits:false;initial-value:100%}.chat-md[data-v-b78b767b]{font-size:var(--text-sm-fontSize);line-height:var(--un-leading,var(--text-sm-lineHeight));--un-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);overflow-wrap:break-word}.chat-md[data-v-b78b767b] :is(p,ul,ol,pre,blockquote,table,hr,h1,h2,h3,h4)+:is(p,ul,ol,pre,blockquote,table,hr,h1,h2,h3,h4){margin-top:calc(var(--spacing) * 2.5)}.chat-md[data-v-b78b767b] :is(h1,h2,h3,h4){--un-leading:var(--leading-snug);line-height:var(--leading-snug);--un-font-weight:var(--fontWeight-semibold);font-weight:var(--fontWeight-semibold)}.chat-md[data-v-b78b767b] :is(h1,h2){font-size:var(--text-base-fontSize);line-height:var(--un-leading,var(--text-base-lineHeight))}.chat-md[data-v-b78b767b] :is(h3,h4){font-size:var(--text-sm-fontSize);line-height:var(--un-leading,var(--text-sm-lineHeight))}.chat-md[data-v-b78b767b] *+:is(h1,h2,h3,h4){margin-top:calc(var(--spacing) * 4)}.chat-md[data-v-b78b767b] :is(ul,ol){padding-left:calc(var(--spacing) * 5)}.chat-md[data-v-b78b767b] ul{list-style-type:disc}.chat-md[data-v-b78b767b] ol{list-style-type:decimal}.chat-md[data-v-b78b767b] li+li{margin-top:calc(var(--spacing) * 1)}.chat-md[data-v-b78b767b] :not(pre)>code{padding-inline:calc(var(--spacing) * 1);padding-block:calc(var(--spacing) * .5);border-radius:var(--radius-DEFAULT);background-color:color-mix(in srgb, var(--colors-gray-500) 5%, transparent);font-size:.85em}@supports (color:color-mix(in lab, red, red)){.chat-md[data-v-b78b767b] :not(pre)>code{background-color:color-mix(in oklab, var(--colors-gray-500) 5%, transparent)}}.chat-md[data-v-b78b767b] pre{font-size:var(--text-xs-fontSize);line-height:var(--un-leading,var(--text-xs-lineHeight));--un-leading:var(--leading-relaxed);line-height:var(--leading-relaxed);padding:calc(var(--spacing) * 3);border-width:1px;border-color:color-mix(in oklab, #9992 var(--un-border-opacity), transparent);border-radius:var(--radius-md);background-color:color-mix(in srgb, var(--colors-gray-500) 5%, transparent);max-width:100%;overflow-x:auto}@supports (color:color-mix(in lab, red, red)){.chat-md[data-v-b78b767b] pre{background-color:color-mix(in oklab, var(--colors-gray-500) 5%, transparent)}}.chat-md[data-v-b78b767b] pre code{white-space:pre}.chat-md[data-v-b78b767b] blockquote{padding-left:calc(var(--spacing) * 3);border-color:color-mix(in oklab, #9992 var(--un-border-opacity), transparent);opacity:.65;border-left-width:2px}.dark .chat-md[data-v-b78b767b] blockquote{opacity:.55}.chat-md[data-v-b78b767b] table{font-size:var(--text-xs-fontSize);line-height:var(--un-leading,var(--text-xs-lineHeight));border-collapse:collapse;max-width:100%;display:block;overflow-x:auto}.chat-md[data-v-b78b767b] :is(th,td){padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 1);text-align:left;border-width:1px;border-color:color-mix(in oklab, #9992 var(--un-border-opacity), transparent)}.chat-md[data-v-b78b767b] a{text-underline-offset:2px;text-decoration-line:underline}.chat-md[data-v-b78b767b] a:hover{opacity:.8}.chat-md[data-v-b78b767b] hr{border-color:color-mix(in oklab, #9992 var(--un-border-opacity), transparent)}
@@ -1,2 +0,0 @@
1
- import{U as e,V as t}from"./pr-cache-DNR7E646.js";import{$ as n,D as r,E as i,Ft as a,On as o,Rt as s,Yt as c,_ as l,b as u,bt as d,g as f,k as p,l as m,mt as h,o as g,qt as _,tr as v,v as y,vn as b,y as x}from"./runtime-core.esm-bundler-B8D2lM98.js";import{T as S,i as C}from"./index-BD_DzwAn.js";import{a as w}from"./diffs-store-B1RXognA.js";import{c as T}from"./dist-hXdF5ZNr.js";var E={key:0,class:`flex justify-end`},D={class:`text-sm px-3 py-2 rounded-lg bg-active max-w-[85%] whitespace-pre-wrap break-words`},O={key:1,class:`flex flex-col gap-1.5 max-w-full items-start`},k={key:1,class:`text-xs op-mute flex gap-1.5 items-center`},A={key:0,class:`text-sm text-red-500 flex flex-wrap gap-2 items-center`},j={class:`break-words`},M={key:1,class:`text-xs px-1.5 border border-base rounded op-mute`},N={key:2,class:`text-xs op-mute flex gap-1.5 items-center`},P=C(p({__name:`ChatMessage`,props:{message:{},retryable:{type:Boolean}},emits:[`retry`],setup(t){let n=t;function a(e){return typeof e==`string`?e:e.map(e=>e.text??``).join(`
2
- `)}let s=f(()=>n.message.role===`user`?a(n.message.content):``),c=f(()=>{let e=n.message;if(e.role!==`toolResult`||e.toolName!==`update_grouping`||e.isError)return;let t=a(e.content).match(/(\d+) groups?/)?.[1];return t?`Updated grouping: ${t} groups`:void 0});function p(e){if(e.name===`read_diffs`){let t=e.arguments.paths;return`Read ${Array.isArray(t)?t.length:0} file(s)`}return e.name===`update_grouping`?`Updating grouping…`:e.name}return(n,a)=>t.message.role===`user`?(h(),u(`div`,E,[l(`div`,D,v(s.value),1)])):t.message.role===`assistant`?(h(),u(`div`,O,[(h(!0),u(g,null,d(t.message.content,(e,n)=>(h(),u(g,{key:n},[e.type===`text`&&e.text.trim()?(h(),y(m,{key:0},{default:_(()=>[r(o(w),{value:e.text,streaming:t.message.stopReason===`pending`,class:`chat-md min-w-0 self-stretch`},null,8,[`value`,`streaming`])]),_:2},1024)):e.type===`toolCall`?(h(),u(`div`,k,[a[1]||=l(`span`,{class:`i-ph:wrench-duotone`,"aria-hidden":`true`},null,-1),i(` `+v(p(e)),1)])):x(``,!0)],64))),128)),t.message.stopReason===`error`?(h(),u(`div`,A,[l(`span`,j,v(t.message.errorMessage??`Request failed`),1),t.retryable?(h(),y(e,{key:0,size:`sm`,icon:`i-ph:arrow-clockwise-duotone`,onClick:a[0]||=e=>n.$emit(`retry`)},{default:_(()=>[...a[2]||=[i(` Retry `,-1)]]),_:1})):x(``,!0)])):t.message.stopReason===`aborted`?(h(),u(`span`,M,`stopped`)):x(``,!0)])):c.value?(h(),u(`div`,N,[a[3]||=l(`span`,{class:`i-ph:tree-structure-duotone`,"aria-hidden":`true`},null,-1),i(` `+v(c.value),1)])):x(``,!0)}}),[[`__scopeId`,`data-v-b78b767b`]]),F={class:`bottom-4 right-4 fixed z-dropdown`},I={key:1,class:`border border-base rounded-lg bg-base flex flex-col h-140 max-h-[calc(100vh-2rem)] max-w-[calc(100vw-2rem)] w-100 shadow-xl overflow-hidden`},L={class:`px-3 py-2 border-b border-base flex gap-2 items-center`},R={key:0,class:`text-sm p-6 text-center op-mute flex flex-auto items-center justify-center`},z={key:0,class:`text-xs op-mute flex gap-1.5 items-center`,role:`status`},B={key:0,class:`text-xs text-red-500 px-3 pb-2 break-words`},V={class:`p-2 border-t border-base flex gap-2 items-end`},H=[`disabled`],U=p({__name:`ChatWidget`,props:n({store:{}},{open:{type:Boolean,default:!1},openModifiers:{}}),emits:[`update:open`],setup(n){let o=n,p=f(()=>o.store.llm.chat),m=a(n,`open`),C=b(``),w=f(()=>p.value.isStreaming||o.store.llm.isAnalyzing),E=f(()=>p.value.messages.length-1),D=f(()=>{let e=p.value.messages.at(-1);return e?.role===`assistant`&&e.stopReason===`error`}),O=f(()=>{if(!p.value.isStreaming)return!1;let e=p.value.messages.at(-1),t=e?.role===`assistant`?e.content.at(-1):void 0;return!(t?.type===`text`&&t.text.trim())}),k=s(`listEl`),A=s(`contentEl`),j=b(!0);function M(){let e=k.value;e&&(j.value=e.scrollHeight-e.scrollTop-e.clientHeight<40)}T(A,()=>{j.value&&k.value&&(k.value.scrollTop=k.value.scrollHeight)});async function N(){let e=C.value;e.trim()&&!w.value&&(C.value=``,j.value=!0,await p.value.send(e))}function U(e){e.key!==`Enter`||e.shiftKey||e.isComposing||(e.preventDefault(),N())}return(n,a)=>(h(),u(`div`,F,[m.value?(h(),u(`div`,I,[l(`div`,L,[a[8]||=l(`span`,{class:`i-ph:chat-circle-dots-duotone op-mute`,"aria-hidden":`true`},null,-1),a[9]||=l(`span`,{class:`text-sm font-semibold flex-auto`},`Ask about this PR`,-1),p.value.available?(h(),y(e,{key:0,size:`sm`,variant:`text`,onClick:a[1]||=e=>p.value.clear()},{default:_(()=>[...a[7]||=[i(` Clear `,-1)]]),_:1})):x(``,!0),r(t,{compact:``,icon:`i-ph:caret-down`,tooltip:`Collapse`,onClick:a[2]||=e=>m.value=!1})]),p.value.available?(h(),u(g,{key:1},[l(`div`,{ref_key:`listEl`,ref:k,class:`p-3 overscroll-contain flex-auto min-w-0 overflow-y-auto`,onScroll:M},[l(`div`,{ref_key:`contentEl`,ref:A,class:`flex flex-col gap-3`},[(h(!0),u(g,null,d(p.value.messages,(e,t)=>(h(),y(P,{key:t,message:e,retryable:t===E.value&&!p.value.isStreaming,onRetry:a[3]||=e=>p.value.retry()},null,8,[`message`,`retryable`]))),128)),O.value?(h(),u(`div`,z,[...a[10]||=[l(`span`,{class:`i-ph:spinner-duotone animate-spin`,"aria-hidden":`true`},null,-1),i(` Thinking… `,-1)]])):x(``,!0)],512)],544),p.value.error&&!D.value?(h(),u(`p`,B,v(p.value.error.message),1)):x(``,!0),l(`div`,V,[c(l(`textarea`,{"onUpdate:modelValue":a[4]||=e=>C.value=e,rows:`2`,placeholder:`Ask about this PR…`,"aria-label":`Ask about this PR`,disabled:w.value,class:`text-sm p-2 outline-none border border-base rounded bg-raised flex-auto resize-none disabled:op-mute focus-visible:ring-2 focus-visible:ring-primary-500/40`,onKeydown:U},null,40,H),[[S,C.value]]),p.value.isStreaming?(h(),y(e,{key:0,size:`sm`,icon:`i-ph:stop-duotone`,onClick:a[5]||=e=>p.value.stop()},{default:_(()=>[...a[11]||=[i(` Stop `,-1)]]),_:1})):(h(),y(e,{key:1,size:`sm`,variant:`primary`,icon:`i-ph:paper-plane-right-duotone`,disabled:w.value||!C.value.trim(),onClick:a[6]||=e=>N()},{default:_(()=>[...a[12]||=[i(` Send `,-1)]]),_:1},8,[`disabled`]))])],64)):(h(),u(`div`,R,` Re-analyze to enable chat `))])):(h(),y(t,{key:0,icon:`i-ph:chat-circle-dots-duotone`,title:`Ask about this PR`,label:`Ask about this PR`,class:`text-xl border border-base bg-base shadow-lg`,onClick:a[0]||=e=>m.value=!0}))]))}});export{U as default};
@@ -1 +0,0 @@
1
- import{G as e,U as t}from"./pr-cache-DNR7E646.js";import{D as n,E as r,On as i,b as a,ct as o,g as s,k as c,mt as l,qt as u,tr as d}from"./runtime-core.esm-bundler-B8D2lM98.js";import{n as f}from"./index-BD_DzwAn.js";import{i as p,n as m,r as h,t as g}from"./diffs-store-B1RXognA.js";var _=c({__name:`[number]`,setup(c){let _=f(),v=s(()=>({kind:`github-pr`,owner:_.params.owner,repo:_.params.repo,number:_.params.number})),y=g(v.value,{token:e.value.githubToken});return o(()=>y.load()),(e,o)=>(l(),a(`main`,null,[n(m,{store:i(y)},{loading:u(()=>[n(h,{text:`Loading pull request…`})]),error:u(({error:e,retry:i})=>[n(p,{icon:`i-ph:warning-duotone`,title:`Couldn't load this pull request`},{hint:u(()=>[r(d(e.message),1)]),actions:u(()=>[n(t,{variant:`primary`,onClick:i},{default:u(()=>[...o[0]||=[r(` Retry `,-1)]]),_:1},8,[`onClick`])]),_:2},1024)]),_:1},8,[`store`])]))}});export{_ as default};