prreviewbuddy 0.25.7 → 0.25.13
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/CHANGELOG.md +115 -0
- package/dist/main.js +76 -9
- package/dist/{relative_time-CDvK_Zaj.js → relative_time-vn8Ex9E8.js} +847 -505
- package/dist/server.js +312 -42
- package/package.json +1 -1
- package/static/chunk-B80S6zbH.js +4 -4
- package/static/chunk-CIsM3PMS.js +1 -0
- package/static/{chunk-B9H2wUlQ.js → chunk-gBDI1-Cy.js} +1 -1
- package/static/reviews.js +1 -1
- package/static/settings.js +1 -1
- package/static/shell.css +48 -0
- package/static/workspace.js +44 -44
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,120 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.25.13
|
|
4
|
+
|
|
5
|
+
**Two updates of the same review no longer run over each other.** Pressing **Update review** on the
|
|
6
|
+
page while `prreviewbuddy review --update` was working on the same review started a second update
|
|
7
|
+
alongside the first. Whichever finished last replaced the other's result without a word, after
|
|
8
|
+
both had spent minutes of agent time.
|
|
9
|
+
|
|
10
|
+
A second update is now refused while one is running, from wherever it was asked for. On the page,
|
|
11
|
+
the review reloads onto the running update's steps. In the terminal, the command says the review
|
|
12
|
+
is already being updated, gives the link where you can follow it, and exits without changing
|
|
13
|
+
anything. An analysis, a KISS review or a question to the assistant does not block an update.
|
|
14
|
+
|
|
15
|
+
## 0.25.12
|
|
16
|
+
|
|
17
|
+
**An update shows what it is doing, in the terminal and on the review.** `prreviewbuddy review
|
|
18
|
+
--update` printed nothing until the reassessment was over, usually minutes after you typed it, and
|
|
19
|
+
the review page showed nothing either. Only the reviews list noticed, and it called the whole update
|
|
20
|
+
"Preparing isolated checkout".
|
|
21
|
+
|
|
22
|
+
The command now prints the link straight away and then draws the same step list a new review does:
|
|
23
|
+
fetching the latest commits, re-reading the pull request conversation, preparing a checkout of the
|
|
24
|
+
new commits, and reassessing the review, with the agent's own notes under the step that is running.
|
|
25
|
+
Open the link while it works and those steps tick over above the review, which stays readable
|
|
26
|
+
underneath until the update lands. The page refreshes onto the result when it finishes, and the
|
|
27
|
+
reviews list names each step in the same words.
|
|
28
|
+
|
|
29
|
+
An update that finds no new commits stops after the fetch and says so, without ticking steps it
|
|
30
|
+
never ran. **Update review** on the page now shows the same live steps, where it used to show
|
|
31
|
+
captions guessed from a timer.
|
|
32
|
+
|
|
33
|
+
`--reanalyse` kept the terminal silent in the same way, for a whole analysis, and now draws its
|
|
34
|
+
progress too.
|
|
35
|
+
|
|
36
|
+
## 0.25.11
|
|
37
|
+
|
|
38
|
+
**A review with nothing committed to read now says why, straight away.** Running
|
|
39
|
+
`prreviewbuddy review` on `main` with a dozen edited files said "No changes found to review",
|
|
40
|
+
which looked like a bug to anyone who could see the edits. It now says there are no *committed*
|
|
41
|
+
changes, counts the uncommitted ones (new files included), and explains that PR Review Buddy
|
|
42
|
+
reviews a fixed snapshot of your code, so work that is not committed yet is not included. Then
|
|
43
|
+
it tells you what to do: commit on a branch, or just commit if you are already on one.
|
|
44
|
+
|
|
45
|
+
The refusal also comes at once. It used to arrive after an isolated checkout had been prepared,
|
|
46
|
+
reported as a paused review that would refuse again every time you tried to carry it on. Nothing
|
|
47
|
+
is created now. A branch that has since been merged still opens the review it already has.
|
|
48
|
+
|
|
49
|
+
## 0.25.10
|
|
50
|
+
|
|
51
|
+
**The reviews list now shows what is happening, and keeps showing it.** A review being analysed
|
|
52
|
+
right now, one whose analysis failed, and one that was never analysed all looked the same on the
|
|
53
|
+
list: every card said "No standard review yet". Start a review, go back to the list, and you
|
|
54
|
+
watched nothing happen for three minutes.
|
|
55
|
+
|
|
56
|
+
A card now says which step an analysis has reached, in the same words the terminal prints, and says
|
|
57
|
+
when one has stopped. It updates on its own, so a review that finishes while you are looking at the
|
|
58
|
+
list fills in its summary, risk and counts without you touching anything. A review started in
|
|
59
|
+
another terminal appears by itself too.
|
|
60
|
+
|
|
61
|
+
Where a review already has results, they stay put while a new analysis runs over them: a KISS run
|
|
62
|
+
no longer hides the issues you were reading.
|
|
63
|
+
|
|
64
|
+
The list checks in about once a second while something is being made and once every fifteen when
|
|
65
|
+
nothing is, and it waits rather than refreshing under you if you have rows ticked or are partway
|
|
66
|
+
through typing a search.
|
|
67
|
+
|
|
68
|
+
## 0.25.9
|
|
69
|
+
|
|
70
|
+
**Marking a review reviewed shows up straight away on the reviews list.** It used to keep saying
|
|
71
|
+
what it had said before, and catch up some minutes later on its own. Nothing was actually stale:
|
|
72
|
+
the mark is written to disk before the button finishes repainting, and the list is rebuilt from
|
|
73
|
+
those files on every request. The browser simply stopped asking. No page this server sends had
|
|
74
|
+
ever carried a caching rule, so a browser was free to reuse the copy it already had, and pressing
|
|
75
|
+
Back does not reload a page at all: it restores a frozen one from memory, JavaScript variables and
|
|
76
|
+
all, without a single request.
|
|
77
|
+
|
|
78
|
+
Both doors are shut now, and shut in one place rather than per page. Every response describing a
|
|
79
|
+
review, HTML and JSON alike, says it must not be stored, and that is a property of the two helpers
|
|
80
|
+
that write responses rather than something each route remembers. Every page now reloads itself
|
|
81
|
+
when the browser restores it from history, because a restored page may be stale in any of its
|
|
82
|
+
parts and not only the one that prompted this.
|
|
83
|
+
|
|
84
|
+
Assets went the other way, which is the arrangement they should always have had. The bundles whose
|
|
85
|
+
filenames carry a content hash, which are most of what a page downloads, may now be kept
|
|
86
|
+
indefinitely: a new build asks for different names. The handful named plainly still check in every
|
|
87
|
+
time, because those names survive an upgrade.
|
|
88
|
+
|
|
89
|
+
## 0.25.8
|
|
90
|
+
|
|
91
|
+
**A review that fails says so, instead of reporting itself as ready.** An analysis that failed
|
|
92
|
+
after the agent had started work left no trace of the failure: the job stayed at `Analysing the
|
|
93
|
+
change`, the workspace page kept the running rail over it, and the terminal printed
|
|
94
|
+
`Review ready . Risk not rated . 0 findings`, which reads as a change with nothing wrong with it.
|
|
95
|
+
The review it was reporting did not exist.
|
|
96
|
+
|
|
97
|
+
The record refuses to be failed by anyone but the run that owns it, so that a driver whose job has
|
|
98
|
+
been taken over cannot mark a healthy review as broken. It asked that question of the record's
|
|
99
|
+
timestamp, and the timestamp moves every time the agent reports what it is doing. So a run that
|
|
100
|
+
streamed a single line and then failed looked, to itself, like a run that had been taken over, and
|
|
101
|
+
declined to record its own failure. It asks the claim now, which is who is actually driving.
|
|
102
|
+
|
|
103
|
+
**The terminal reports what happened, and refuses to invent the rest.** `prreviewbuddy review` read
|
|
104
|
+
"the job did not fail" as "the review is ready". A run can also stop without recording why, and now
|
|
105
|
+
says so, naming the phase it stopped in, which is the phase running the command again picks up
|
|
106
|
+
from. A finished job holding no review is reported as a review that stopped rather than as a clean
|
|
107
|
+
one: the standard review is held to the rule the KISS lens has always been held to.
|
|
108
|
+
|
|
109
|
+
**A fenced answer is read to its end, not to the first ``` inside it.** The model is asked for
|
|
110
|
+
JSON and often wraps it in a code fence, and the summary and next steps of a review about code
|
|
111
|
+
frequently hold a fenced snippet of their own. The unwrapping stopped at the first closing marker
|
|
112
|
+
it found, which in that case is the one *opening* a snippet inside one of the answer's own
|
|
113
|
+
strings. A real review of a ten-file pull request was cut in half 24KB in, mid-string, and thrown
|
|
114
|
+
away whole: four themes, six findings, six questions and six next steps, none of which anything
|
|
115
|
+
ever showed. A fence says where an answer starts, not where it ends, so one that does not parse is
|
|
116
|
+
now passed over for the scanner that reads such an object correctly.
|
|
117
|
+
|
|
3
118
|
## 0.25.7
|
|
4
119
|
|
|
5
120
|
**The agent you chose is the agent that runs.** Setting a default agent, with
|
package/dist/main.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { B as
|
|
2
|
+
import { A as liveUpdateFor, B as recordTelemetryUploadConsent, Bt as displayRef, C as writePortPreference, Ct as recentWorkspaces, Dt as summarise, Et as saveWorkspace, F as reanalyseReview, Gt as writeAgentPreference, H as BUILD_VERSION, Ht as agentIdOf, I as runJob, Jt as AGENT_IDS, Kt as CONFIG_PATH, L as startJob, N as recordKissRun, Q as removeWorktree, Qt as detectAgents, S as statedWorkspacePort, T as updateReview, Tt as reviewedRepositories, U as PACKAGE_NAME, V as telemetryUploadConsent, Vt as git, Wt as readAgentPreference, X as MANAGED_ROOT, Xt as agentById, Yt as DEFAULT_AGENT_ID, Z as readMarker, _ as DEFAULT_WORKSPACE_PORT, a as liveJobsFor, at as loadJob, b as parseWorkspacePort, bt as positionInLineage, c as readIndexToken, d as ensureServer, dt as clearClaim, et as checkFreshness, ft as isClaimed, gt as lineageKeyFor, h as workspaceUrl, it as isTerminal, j as runningJobs, k as UpdateAlreadyRunningError, l as bootstrapUrl, lt as progressSteps, m as stopServer, mt as groupByLineage, o as wasBlocked, p as reviewsUrl, pt as followedRefName, q as forgeResolver, qt as STORE_ROOT, r as deleteReview$1, st as PHASES, t as relativeTime, tt as allJobs, ut as purposeOf, v as MAX_WORKSPACE_PORT, vt as loadWorkspace, y as MIN_WORKSPACE_PORT, yt as matchingWorkspaceIds, z as record, zt as resolveTarget } from "./relative_time-vn8Ex9E8.js";
|
|
3
3
|
import { basename, dirname, join, resolve } from "node:path";
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
5
|
import { existsSync, mkdirSync, readdirSync, realpathSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
@@ -1267,6 +1267,19 @@ function agentUnusedByResume(agentId) {
|
|
|
1267
1267
|
* link. Not rephrased here: an update that stopped early has a specific reason and the reviewer
|
|
1268
1268
|
* gets the same reason whichever surface asked for it.
|
|
1269
1269
|
*/
|
|
1270
|
+
/**
|
|
1271
|
+
* Said before the update starts, so the command answers at once and the link is there to open while
|
|
1272
|
+
* it works. The same label the creation path uses, because it is the same offer.
|
|
1273
|
+
*
|
|
1274
|
+
* Not "continues if this terminal closes", which the creation path can say and this cannot: the
|
|
1275
|
+
* update runs in this process, so closing the terminal stops it.
|
|
1276
|
+
*/
|
|
1277
|
+
function startedUpdate(url, acted) {
|
|
1278
|
+
return `${subjectLine(acted)}\nOpen workspace now ${url}`;
|
|
1279
|
+
}
|
|
1280
|
+
function updateAlreadyRunning(url, acted) {
|
|
1281
|
+
return `${subjectLine(acted)}\nThis review is already being updated. Follow it here ${url}`;
|
|
1282
|
+
}
|
|
1270
1283
|
function updateFinished(outcome, url, acted) {
|
|
1271
1284
|
return `${subjectLine(acted)}\n${outcome.message}\n${url}`;
|
|
1272
1285
|
}
|
|
@@ -1572,10 +1585,10 @@ var GREEN = "\x1B[32m";
|
|
|
1572
1585
|
var RED = "\x1B[31m";
|
|
1573
1586
|
var RESET = "\x1B[0m";
|
|
1574
1587
|
/** The header above the phases: what is being reviewed, and the facts about how. */
|
|
1575
|
-
function header(target, colour) {
|
|
1588
|
+
function header(target, colour, purpose = "review") {
|
|
1576
1589
|
const meta = `${target.sha.slice(0, 7)} · isolated checkout · ${target.originRepoPath}`;
|
|
1577
1590
|
return [
|
|
1578
|
-
|
|
1591
|
+
`${purpose === "update" ? "Updating" : "Reviewing"} ${target.branch}`,
|
|
1579
1592
|
colour ? `${DIM}${meta}${RESET}` : meta,
|
|
1580
1593
|
""
|
|
1581
1594
|
];
|
|
@@ -1638,7 +1651,7 @@ function followJob(jobId, target, options = {}) {
|
|
|
1638
1651
|
const paint = () => {
|
|
1639
1652
|
const job = read(jobId);
|
|
1640
1653
|
if (!job) return;
|
|
1641
|
-
const lines = [...header(target, colour), ...phaseLines(job, colour)];
|
|
1654
|
+
const lines = [...header(job.target ?? target, colour, purposeOf(job)), ...phaseLines(job, colour)];
|
|
1642
1655
|
const block = lines.join("\n");
|
|
1643
1656
|
if (block === last) return;
|
|
1644
1657
|
if (inPlace && drawn > 0) stream.write(`\u001b[${drawn}A\u001b[0J`);
|
|
@@ -1851,13 +1864,38 @@ async function operate(command, workspace) {
|
|
|
1851
1864
|
if (command.operation === "reanalyse") {
|
|
1852
1865
|
const agent = await chooseFor(command, workspace);
|
|
1853
1866
|
if (!agent) return 1;
|
|
1854
|
-
|
|
1867
|
+
let stopReanalysis;
|
|
1868
|
+
try {
|
|
1869
|
+
await reanalyseReview(workspace.id, agent.id, (jobId) => {
|
|
1870
|
+
stopReanalysis = follow(jobId);
|
|
1871
|
+
});
|
|
1872
|
+
} finally {
|
|
1873
|
+
stopReanalysis?.();
|
|
1874
|
+
}
|
|
1855
1875
|
const port = await ensureServer();
|
|
1856
1876
|
out(reanalysed(agent.displayName, linkTo(port, workspace.id, workspace.token), actedOn(workspace)));
|
|
1857
1877
|
return 0;
|
|
1858
1878
|
}
|
|
1859
1879
|
if (command.agentId) err(agentUnusedByUpdate(command.agentId));
|
|
1860
|
-
const
|
|
1880
|
+
const url = linkTo(await ensureServer(), workspace.id, workspace.token);
|
|
1881
|
+
if (liveUpdateFor(workspace.id)) {
|
|
1882
|
+
out(updateAlreadyRunning(url, actedOn(workspace)));
|
|
1883
|
+
return 1;
|
|
1884
|
+
}
|
|
1885
|
+
out(startedUpdate(url, actedOn(workspace)));
|
|
1886
|
+
let stopUpdate;
|
|
1887
|
+
let outcome;
|
|
1888
|
+
try {
|
|
1889
|
+
outcome = await updateReview(workspace, { onStarted: (jobId) => {
|
|
1890
|
+
stopUpdate = follow(jobId);
|
|
1891
|
+
} });
|
|
1892
|
+
} catch (error) {
|
|
1893
|
+
if (!(error instanceof UpdateAlreadyRunningError)) throw error;
|
|
1894
|
+
out(updateAlreadyRunning(url, actedOn(workspace)));
|
|
1895
|
+
return 1;
|
|
1896
|
+
} finally {
|
|
1897
|
+
stopUpdate?.();
|
|
1898
|
+
}
|
|
1861
1899
|
workspace.lastUpdate = outcome;
|
|
1862
1900
|
saveWorkspace(workspace);
|
|
1863
1901
|
record({
|
|
@@ -1872,10 +1910,23 @@ async function operate(command, workspace) {
|
|
|
1872
1910
|
newIssues: outcome.counts?.newIssues ?? 0,
|
|
1873
1911
|
questionsAnswered: outcome.counts?.questionsAnswered ?? 0
|
|
1874
1912
|
});
|
|
1875
|
-
out(updateFinished(outcome,
|
|
1913
|
+
out(updateFinished(outcome, url, actedOn(workspace)));
|
|
1876
1914
|
return 0;
|
|
1877
1915
|
}
|
|
1878
1916
|
/**
|
|
1917
|
+
* Draw a job's progress block, from what the job itself records about its target.
|
|
1918
|
+
*
|
|
1919
|
+
* From the record rather than the caller, for the reason `drive` gives: the job knows what it is
|
|
1920
|
+
* working on, and a second copy assembled here could disagree with it.
|
|
1921
|
+
*/
|
|
1922
|
+
function follow(jobId) {
|
|
1923
|
+
return followJob(jobId, loadJob(jobId)?.target ?? {
|
|
1924
|
+
branch: "",
|
|
1925
|
+
sha: "",
|
|
1926
|
+
originRepoPath: ""
|
|
1927
|
+
});
|
|
1928
|
+
}
|
|
1929
|
+
/**
|
|
1879
1930
|
* What to call the review an operation acted on.
|
|
1880
1931
|
*
|
|
1881
1932
|
* Read off the record rather than off the command, because the two are not the same question. The
|
|
@@ -1950,9 +2001,9 @@ async function drive(workspaceId, url, kissRun) {
|
|
|
1950
2001
|
let finished;
|
|
1951
2002
|
try {
|
|
1952
2003
|
finished = await runJob(workspaceId, {}, kissRun ? "kiss" : "standard");
|
|
1953
|
-
if (finished.phase
|
|
2004
|
+
if (finished.phase !== "done") {
|
|
1954
2005
|
stop();
|
|
1955
|
-
err(reviewFailed(finished
|
|
2006
|
+
err(reviewFailed(failureMessage(finished), await linkNow(workspace, url)));
|
|
1956
2007
|
return 1;
|
|
1957
2008
|
}
|
|
1958
2009
|
} catch (error) {
|
|
@@ -1973,10 +2024,26 @@ async function drive(workspaceId, url, kissRun) {
|
|
|
1973
2024
|
out(kissFinished(link, answer.recommendations.length));
|
|
1974
2025
|
return 0;
|
|
1975
2026
|
}
|
|
2027
|
+
if (!done.session.result) {
|
|
2028
|
+
err(reviewFailed("The analysis finished without recording a review.", link));
|
|
2029
|
+
return 1;
|
|
2030
|
+
}
|
|
1976
2031
|
out(reviewFinished(link, summarise(done), finished.conversation));
|
|
1977
2032
|
return 0;
|
|
1978
2033
|
}
|
|
1979
2034
|
/**
|
|
2035
|
+
* Why a run ended, when it did not end by finishing.
|
|
2036
|
+
*
|
|
2037
|
+
* A job that recorded a failure says so in its own words. One that did not is a driver that went
|
|
2038
|
+
* away mid-phase -- killed, or crashed past the point where it could write -- and the honest thing
|
|
2039
|
+
* to say is which phase it was in, because that is the phase the next run picks up from.
|
|
2040
|
+
*/
|
|
2041
|
+
function failureMessage(job) {
|
|
2042
|
+
if (job.failure?.message) return job.failure.message;
|
|
2043
|
+
const doing = PHASES[job.phase].doing;
|
|
2044
|
+
return `The reason was not recorded. It was ${doing.charAt(0).toLowerCase()}${doing.slice(1)} when it stopped.`;
|
|
2045
|
+
}
|
|
2046
|
+
/**
|
|
1980
2047
|
* Every link this command prints, and the reason they are not plain workspace URLs.
|
|
1981
2048
|
*
|
|
1982
2049
|
* A reviewer who only ever runs this command was never sent to the reviews index, so their browser
|