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.
- package/dist/index.mjs +149 -0
- package/package.json +26 -65
- package/README.md +0 -15
- package/dist/assets/ChatWidget-BD4etTSI.css +0 -1
- package/dist/assets/ChatWidget-BXmVT9ns.js +0 -2
- package/dist/assets/_number_-ByKh-CJ7.js +0 -1
- package/dist/assets/agent-SYDXCLiI.js +0 -90
- package/dist/assets/andromeeda-vGVdxbeo.js +0 -1
- package/dist/assets/anthropic-messages-XptRMkpJ.js +0 -41
- package/dist/assets/aurora-x-CDeNXAV0.js +0 -1
- package/dist/assets/ayu-dark-DluEY0Gj.js +0 -1
- package/dist/assets/ayu-light-C3h-C4tm.js +0 -1
- package/dist/assets/ayu-mirage-Bqwy1Gya.js +0 -1
- package/dist/assets/c-BWgYNV7i.js +0 -1
- package/dist/assets/catppuccin-frappe-C9Q5zVZY.js +0 -1
- package/dist/assets/catppuccin-latte-CtsyrtPq.js +0 -1
- package/dist/assets/catppuccin-macchiato-R8nAf1vR.js +0 -1
- package/dist/assets/catppuccin-mocha-DjuaAJKi.js +0 -1
- package/dist/assets/chat-CP0CZKJo.js +0 -1
- package/dist/assets/clojure-DqKBuwfJ.js +0 -1
- package/dist/assets/cpp-BBcYm61y.js +0 -1
- package/dist/assets/csharp-oqKa8noW.js +0 -1
- package/dist/assets/css-dNRduEa-.js +0 -1
- package/dist/assets/dark-plus-Cs2F2srj.js +0 -1
- package/dist/assets/diff-woXpYk--.js +0 -1
- package/dist/assets/diffs-store-B1RXognA.js +0 -1696
- package/dist/assets/dist-hXdF5ZNr.js +0 -1
- package/dist/assets/docker-IyjqRm3v.js +0 -1
- package/dist/assets/dracula-BHWKrbxM.js +0 -1
- package/dist/assets/dracula-soft-5eyTD99u.js +0 -1
- package/dist/assets/elixir-BMAS0SZ2.js +0 -1
- package/dist/assets/error-CJ3RHG07.js +0 -1
- package/dist/assets/everforest-dark-sB-x3p7T.js +0 -1
- package/dist/assets/everforest-light-Df2xbC6M.js +0 -1
- package/dist/assets/fonts/dmmono-53a90e28.woff2 +0 -0
- package/dist/assets/fonts/dmmono-cd6ed524.woff2 +0 -0
- package/dist/assets/fonts/dmsans-56778fc7.woff2 +0 -0
- package/dist/assets/fonts/dmsans-7c37c8a6.woff2 +0 -0
- package/dist/assets/fonts/dmserifdisplay-1f997542.woff2 +0 -0
- package/dist/assets/fonts/dmserifdisplay-b6206db2.woff2 +0 -0
- package/dist/assets/github-dark-C-LZuMrd.js +0 -1
- package/dist/assets/github-dark-default-DXG-b-1a.js +0 -1
- package/dist/assets/github-dark-dimmed-Bx1FflLF.js +0 -1
- package/dist/assets/github-dark-high-contrast-B_tTalzw.js +0 -1
- package/dist/assets/github-light-EUqPIrTm.js +0 -1
- package/dist/assets/github-light-default-BXViO-2h.js +0 -1
- package/dist/assets/github-light-high-contrast-B68TUdTA.js +0 -1
- package/dist/assets/go-rLFTqkRN.js +0 -1
- package/dist/assets/graphql-DC6gMr7C.js +0 -1
- package/dist/assets/groovy-CacY0gHj.js +0 -1
- package/dist/assets/gruvbox-dark-hard-C820rvS2.js +0 -1
- package/dist/assets/gruvbox-dark-medium-BPjhmG05.js +0 -1
- package/dist/assets/gruvbox-dark-soft-MrdJrrXF.js +0 -1
- package/dist/assets/gruvbox-light-hard-BC_s9l72.js +0 -1
- package/dist/assets/gruvbox-light-medium-BAWPOn9u.js +0 -1
- package/dist/assets/gruvbox-light-soft-BSMLrYjP.js +0 -1
- package/dist/assets/haskell-D8IpX4py.js +0 -1
- package/dist/assets/horizon-CE9ld1lL.js +0 -1
- package/dist/assets/horizon-bright-DSNQnXHK.js +0 -1
- package/dist/assets/houston-CsvMBhTu.js +0 -1
- package/dist/assets/html-9bR0RcZU.js +0 -1
- package/dist/assets/index-BD_DzwAn.js +0 -3
- package/dist/assets/index-Yd4-oLpR.css +0 -1
- package/dist/assets/indexedb-Cu6ZJjpB.js +0 -1
- package/dist/assets/ini-B5eOa1yu.js +0 -1
- package/dist/assets/java-C0DRq53f.js +0 -1
- package/dist/assets/javascript-UWfzLVwt.js +0 -1
- package/dist/assets/json-qhed-kSA.js +0 -1
- package/dist/assets/jsonc-CYpm1nAK.js +0 -1
- package/dist/assets/jsx-B85L4NBR.js +0 -1
- package/dist/assets/kanagawa-dragon-Bozd7klA.js +0 -1
- package/dist/assets/kanagawa-lotus-BmuOG9ZW.js +0 -1
- package/dist/assets/kanagawa-wave-BML5mF2J.js +0 -1
- package/dist/assets/kotlin-DhhofPvG.js +0 -1
- package/dist/assets/laserwave-C_8bwKvT.js +0 -1
- package/dist/assets/less-DVTAwKKz.js +0 -1
- package/dist/assets/light-plus-DVQuIRkW.js +0 -1
- package/dist/assets/lua-ByOrBoZ-.js +0 -1
- package/dist/assets/make-Dixweg8N.js +0 -1
- package/dist/assets/markdown-BYOwaDjH.js +0 -1
- package/dist/assets/material-theme-Bm3Qr25_.js +0 -1
- package/dist/assets/material-theme-darker-2IIEA8gg.js +0 -1
- package/dist/assets/material-theme-lighter-uhdI0v04.js +0 -1
- package/dist/assets/material-theme-ocean-CHQ94UKr.js +0 -1
- package/dist/assets/material-theme-palenight-B5W6OYN7.js +0 -1
- package/dist/assets/mdx-DQZ5AkYe.js +0 -1
- package/dist/assets/min-dark-BSWPekZh.js +0 -1
- package/dist/assets/min-light-DDpmG2fV.js +0 -1
- package/dist/assets/monokai-B_bV9PQ9.js +0 -1
- package/dist/assets/nginx-DBTb8aIg.js +0 -1
- package/dist/assets/night-owl-DhmEMT88.js +0 -1
- package/dist/assets/night-owl-light-eJ-hLW7d.js +0 -1
- package/dist/assets/node.browser-C40HpO0s.js +0 -1
- package/dist/assets/node.browser-DFtqp6Hr.js +0 -1
- package/dist/assets/nord-Cb4Vim4T.js +0 -1
- package/dist/assets/objective-c-D1A_Heim.js +0 -1
- package/dist/assets/objective-cpp-BsSzOQcm.js +0 -1
- package/dist/assets/one-dark-pro-CLwyXe_n.js +0 -1
- package/dist/assets/one-light-D7Lr4KcI.js +0 -1
- package/dist/assets/openai-completions-Cb_BwZvN.js +0 -21
- package/dist/assets/pages-KWcQcyk5.js +0 -1
- package/dist/assets/perl-Bk6ijEF5.js +0 -1
- package/dist/assets/php-CwqKKdmW.js +0 -1
- package/dist/assets/pierre-dark-CpLgRqie.js +0 -1
- package/dist/assets/pierre-dark-protanopia-deuteranopia-B35FxJx-.js +0 -1
- package/dist/assets/pierre-dark-soft-kZQmAZld.js +0 -1
- package/dist/assets/pierre-dark-tritanopia-CpjhbsIL.js +0 -1
- package/dist/assets/pierre-dark-vibrant-CpQYzh95.js +0 -1
- package/dist/assets/pierre-light-CoaEpmwp.js +0 -1
- package/dist/assets/pierre-light-protanopia-deuteranopia-0fSaH845.js +0 -1
- package/dist/assets/pierre-light-soft-lWLdNTOI.js +0 -1
- package/dist/assets/pierre-light-tritanopia-CEbqgOJL.js +0 -1
- package/dist/assets/pierre-light-vibrant-D80Fkn33.js +0 -1
- package/dist/assets/plastic-DQwYfKfQ.js +0 -1
- package/dist/assets/poimandres-DRFjx7u4.js +0 -1
- package/dist/assets/pr-cache-DNR7E646.js +0 -94
- package/dist/assets/proto-DB4EqR-F.js +0 -1
- package/dist/assets/python-gzcpVVnB.js +0 -1
- package/dist/assets/r-C5FwQflr.js +0 -1
- package/dist/assets/red-DX1BQOs8.js +0 -1
- package/dist/assets/rose-pine-aMsaMD1D.js +0 -1
- package/dist/assets/rose-pine-dawn-8PwUyIlP.js +0 -1
- package/dist/assets/rose-pine-moon-DO-qXg-I.js +0 -1
- package/dist/assets/ruby-Cf2R6w0b.js +0 -1
- package/dist/assets/runtime-core.esm-bundler-B8D2lM98.js +0 -3
- package/dist/assets/rust-Cfkwpbl8.js +0 -1
- package/dist/assets/scala-BiFt_7mu.js +0 -1
- package/dist/assets/scss-Dl-NjxyA.js +0 -1
- package/dist/assets/shellscript-CLZ0U2zV.js +0 -1
- package/dist/assets/shiki-wasm-noop-Gxv9UHE7.js +0 -1
- package/dist/assets/slack-dark-DnToyrRv.js +0 -1
- package/dist/assets/slack-ochin-B2OO5cIa.js +0 -1
- package/dist/assets/snazzy-light-4G7pJPwS.js +0 -1
- package/dist/assets/solarized-dark-UdsmMDCL.js +0 -1
- package/dist/assets/solarized-light-C1IUL_tW.js +0 -1
- package/dist/assets/sql-BsFa4tDR.js +0 -1
- package/dist/assets/swift-CyEgAFGc.js +0 -1
- package/dist/assets/synthwave-84-nFMaYfgc.js +0 -1
- package/dist/assets/terraform-DswuEJGm.js +0 -1
- package/dist/assets/tokyo-night-oM2G3aXe.js +0 -1
- package/dist/assets/toml-CcmNWLt0.js +0 -1
- package/dist/assets/transform-messages-DOewMBlN.js +0 -3
- package/dist/assets/tsx-CssvfOw5.js +0 -1
- package/dist/assets/typescript-CttGnwgr.js +0 -1
- package/dist/assets/upload-D7N53Rri.js +0 -1
- package/dist/assets/uploadSession-BUj4FNau.js +0 -1
- package/dist/assets/vesper-DdrHHSXu.js +0 -1
- package/dist/assets/vitesse-black-fwtXNY1n.js +0 -1
- package/dist/assets/vitesse-dark-BZCL-v6S.js +0 -1
- package/dist/assets/vitesse-light-VbXTXTou.js +0 -1
- package/dist/assets/vue-BeqRp0z0.js +0 -1
- package/dist/assets/vue-html-E9GYf_6s.js +0 -1
- package/dist/assets/xml-Dz7PSrBs.js +0 -1
- package/dist/assets/yaml-rwi0_p6S.js +0 -1
- package/dist/diffs-github.user.js +0 -23
- package/dist/embed/diffs-embed.js +0 -1948
- package/dist/index.html +0 -24
- package/dist/pulls-review-github.user.js +0 -23
- 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.
|
|
5
|
-
"description": "
|
|
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
|
-
"
|
|
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
|
-
"@
|
|
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
|
-
"
|
|
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": "
|
|
73
|
-
"
|
|
74
|
-
"
|
|
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};
|