prreviewbuddy 0.25.0 → 0.25.7
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 +83 -0
- package/dist/main.js +35 -82
- package/dist/{relative_time-BeAMrdB1.js → relative_time-CDvK_Zaj.js} +114 -8
- package/dist/server.js +263 -51
- package/package.json +1 -1
- package/static/shell.css +144 -16
- package/static/sidebar.css +31 -7
- package/static/workspace.js +28 -24
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,88 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.25.7
|
|
4
|
+
|
|
5
|
+
**The agent you chose is the agent that runs.** Setting a default agent, with
|
|
6
|
+
`prreviewbuddy config set agent codex` or by picking one when asked, made the terminal say
|
|
7
|
+
`Using Codex.` and then start the review under Claude anyway. Only `--agent` typed on the command
|
|
8
|
+
line reached the job; every other way of arriving at an agent, including the configured default and
|
|
9
|
+
the first-run picker, was worked out, announced and then dropped, and the review fell back to
|
|
10
|
+
Claude because that is what a job with no agent recorded means.
|
|
11
|
+
|
|
12
|
+
Nothing about it was visible unless it failed. A signed-in Claude simply reviewed the change, well,
|
|
13
|
+
under a tool nobody had asked for; the way it surfaced was a sign-in message naming Claude on a
|
|
14
|
+
machine where Codex was the default.
|
|
15
|
+
|
|
16
|
+
**Resuming a paused review answers `--agent` instead of ignoring it.** A resume continues under the
|
|
17
|
+
agent the review was started by, because the phases it has already finished were done by that one
|
|
18
|
+
and switching halfway would leave a review whose provenance and whose execution disagree. That is
|
|
19
|
+
unchanged; what is new is that it says so, and names `--reanalyse --agent` as the way to analyse
|
|
20
|
+
the same commit with another agent. It stays quiet when the flag asks for the agent already
|
|
21
|
+
running.
|
|
22
|
+
|
|
23
|
+
## 0.25.6
|
|
24
|
+
|
|
25
|
+
**A review you open while it is still running now looks like one that is running.** Following the
|
|
26
|
+
link the moment it is printed used to show the finished layout with most of it missing: a two line
|
|
27
|
+
status strip, the KISS card, a screen of white below it, and an empty column down the right where
|
|
28
|
+
the assistant would go. It read as a page that had failed to draw rather than as a review being
|
|
29
|
+
made.
|
|
30
|
+
|
|
31
|
+
There is now a **Review in progress** page, and it is what a running review opens on. It lists the
|
|
32
|
+
steps of the run, ticks them off as they finish, and marks the one going with the note the agent is
|
|
33
|
+
writing as it works:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
✓ Prepared isolated checkout
|
|
37
|
+
✓ Read what changed
|
|
38
|
+
✓ Read pull request conversation
|
|
39
|
+
● Analysing the change
|
|
40
|
+
Reading packages/alerts/src/ede/adapter.ts
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Those are the same step names the terminal prints while you wait, so switching between the two
|
|
44
|
+
shows one operation rather than two descriptions of it. The elapsed time counts in seconds while it
|
|
45
|
+
is under a minute, because a number that does not move is no evidence that anything is happening.
|
|
46
|
+
|
|
47
|
+
**The changed files open before the review is finished.** They are known minutes before anything
|
|
48
|
+
has been concluded about them, so once the change has been read the page offers them, and the Files
|
|
49
|
+
tab works exactly as it does on a finished review. You can start reading the code while the model
|
|
50
|
+
is still thinking about it. The findings, questions and assistant stay behind until they exist,
|
|
51
|
+
since an empty Issues tab cannot be told apart from a review that found nothing.
|
|
52
|
+
|
|
53
|
+
Going into Files while it runs keeps you there. The page refreshes itself only when it has
|
|
54
|
+
something new to show you, not on every step.
|
|
55
|
+
|
|
56
|
+
**A run that stopped says which step it stopped on.** The message and **Retry** used to sit in the
|
|
57
|
+
strip, which had room to say a review had paused but not where. The failure now sits under the same
|
|
58
|
+
checklist, with the step that broke marked and the ones after it left unclaimed, so what failed is
|
|
59
|
+
a thing you read rather than a thing you infer.
|
|
60
|
+
|
|
61
|
+
**KISS is no longer where you land by accident.** A change whose standard review had not finished
|
|
62
|
+
opened on the KISS run form, because it was the only page with anything on it. It is a peer review
|
|
63
|
+
type, not the fallback for whichever review is busy, and it is still one click away in the sidebar.
|
|
64
|
+
|
|
65
|
+
**Locations under a KISS recommendation fit the page.** A repository path is one long unbreakable
|
|
66
|
+
word, and the buttons holding them grew wider than the document, cutting off the end of the path,
|
|
67
|
+
which is the half naming the file. They now wrap the way the standard review's file rows always
|
|
68
|
+
have: a quiet directory line above a filename that wraps.
|
|
69
|
+
|
|
70
|
+
The **Main** badge on those rows is gone. It was our word for a flag in the data, worn as a label,
|
|
71
|
+
so it read as a fact about the file and left you to work out what it was for. The rows now sit
|
|
72
|
+
under **Start here** and **Also relevant**, which say what to do instead of what we call it. Both
|
|
73
|
+
headings are dropped where a recommendation cites a single file.
|
|
74
|
+
|
|
75
|
+
**"Show more of this file" shows more of the file.** Under a finding at line 804 it used to jump to
|
|
76
|
+
the top of the file and then do nothing at all when pressed again, because it meant "the first 600
|
|
77
|
+
lines" rather than "more". Each press now widens the window around the line you arrived at, and the
|
|
78
|
+
button is only there while there is more to show.
|
|
79
|
+
|
|
80
|
+
**Your own saved prompts no longer look unavailable.** In the selection menu they appeared greyed
|
|
81
|
+
out, under a dividing rule, from the first one you saved. A rule written when "Ask a question" was
|
|
82
|
+
the last item in the menu was landing on the last saved prompt instead. They now sit under a **Your
|
|
83
|
+
prompts** heading, in the same words the assistant panel uses for the same set, and read as the
|
|
84
|
+
most available thing in the menu rather than the least.
|
|
85
|
+
|
|
3
86
|
## 0.25.0
|
|
4
87
|
|
|
5
88
|
**PR Review Buddy no longer guesses which `main` you meant.** A repository usually holds two
|
package/dist/main.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { B as BUILD_VERSION, Bt as
|
|
2
|
+
import { B as BUILD_VERSION, Bt as STORE_ROOT, C as statedWorkspacePort, E as updateReview, F as startJob, Ft as agentIdOf, G as forgeResolver, Gt as detectAgents, Ht as DEFAULT_AGENT_ID, J as clearClaim, L as record, Lt as readAgentPreference, Mt as resolveTarget, N as reanalyseReview, Nt as displayRef, P as runJob, Pt as git, Q as removeWorktree, R as recordTelemetryUploadConsent, Rt as writeAgentPreference, St as summarise, Ut as agentById, V as PACKAGE_NAME, Vt as AGENT_IDS, X as MANAGED_ROOT, Y as isClaimed, Z as readMarker, a as liveJobsFor, b as MIN_WORKSPACE_PORT, bt as reviewedRepositories, ct as followedRefName, dt as lineageKeyFor, et as checkFreshness, f as ensureServer, g as workspaceUrl, h as stopServer, ht as positionInLineage, it as loadJob, j as recordKissRun, l as readIndexToken, lt as groupByLineage, m as reviewsUrl, mt as matchingWorkspaceIds, o as wasBlocked, pt as loadWorkspace, r as deleteReview$1, rt as isTerminal, s as runningJobs, st as progressSteps, t as relativeTime, tt as allJobs, u as bootstrapUrl, v as DEFAULT_WORKSPACE_PORT, vt as recentWorkspaces, w as writePortPreference, x as parseWorkspacePort, xt as saveWorkspace, y as MAX_WORKSPACE_PORT, z as telemetryUploadConsent, zt as CONFIG_PATH } from "./relative_time-CDvK_Zaj.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";
|
|
@@ -1250,6 +1250,19 @@ function agentUnusedByUpdate(agentId) {
|
|
|
1250
1250
|
return `An update continues the review with the agent it was made by, so \`--agent ${agentId}\` changes nothing here. To analyse the same commit again with another agent, run \`prreviewbuddy review --reanalyse --agent ${agentId}\`.`;
|
|
1251
1251
|
}
|
|
1252
1252
|
/**
|
|
1253
|
+
* `--agent` was named alongside a resume, where it changes nothing either.
|
|
1254
|
+
*
|
|
1255
|
+
* A paused job carries the agent it was started under, and its finished phases were done by that
|
|
1256
|
+
* agent. Switching engines halfway would leave one review whose provenance and whose execution
|
|
1257
|
+
* disagree, so the flag does not mutate the job; it is said instead, for the reason above.
|
|
1258
|
+
*
|
|
1259
|
+
* Only when the two differ. Resuming a Codex job with `--agent codex` is the agent the reviewer
|
|
1260
|
+
* asked for, and telling them it was ignored would be true and useless.
|
|
1261
|
+
*/
|
|
1262
|
+
function agentUnusedByResume(agentId) {
|
|
1263
|
+
return `A resume continues with the agent the review was started by, so \`--agent ${agentId}\` changes nothing here. To analyse the same commit with it instead, run \`prreviewbuddy review --reanalyse --agent ${agentId}\`.`;
|
|
1264
|
+
}
|
|
1265
|
+
/**
|
|
1253
1266
|
* The update's own sentence, which the harness already wrote for the workspace strip, plus the
|
|
1254
1267
|
* link. Not rephrased here: an update that stopped early has a specific reason and the reviewer
|
|
1255
1268
|
* gets the same reason whichever surface asked for it.
|
|
@@ -1546,39 +1559,6 @@ function describe(deps, id) {
|
|
|
1546
1559
|
*/
|
|
1547
1560
|
var POLL_INTERVAL_MS = 500;
|
|
1548
1561
|
/**
|
|
1549
|
-
* Two forms per phase, because a finished step and a running one are different sentences.
|
|
1550
|
-
*
|
|
1551
|
-
* The page says these differently again (`job_view.ts`), and deliberately: it is describing a
|
|
1552
|
-
* review to someone who arrived after the fact, while this is narrating one to someone watching it
|
|
1553
|
-
* happen. Sharing the strings would force one of the two to read wrongly.
|
|
1554
|
-
*/
|
|
1555
|
-
var PHASES = {
|
|
1556
|
-
preparing: {
|
|
1557
|
-
doing: "Preparing isolated checkout",
|
|
1558
|
-
done: "Prepared isolated checkout"
|
|
1559
|
-
},
|
|
1560
|
-
context: {
|
|
1561
|
-
doing: "Reading what changed",
|
|
1562
|
-
done: "Read what changed"
|
|
1563
|
-
},
|
|
1564
|
-
conversation: {
|
|
1565
|
-
doing: "Reading pull request conversation",
|
|
1566
|
-
done: "Read pull request conversation"
|
|
1567
|
-
},
|
|
1568
|
-
analysing: {
|
|
1569
|
-
doing: "Analysing the change",
|
|
1570
|
-
done: "Analysed the change"
|
|
1571
|
-
},
|
|
1572
|
-
done: {
|
|
1573
|
-
doing: "Finishing",
|
|
1574
|
-
done: "Finished"
|
|
1575
|
-
},
|
|
1576
|
-
failed: {
|
|
1577
|
-
doing: "Stopped",
|
|
1578
|
-
done: "Stopped"
|
|
1579
|
-
}
|
|
1580
|
-
};
|
|
1581
|
-
/**
|
|
1582
1562
|
* Colour only where it means something, and never where it cannot be seen.
|
|
1583
1563
|
*
|
|
1584
1564
|
* `NO_COLOR` is honoured because this writes to stderr, which people redirect into files and CI
|
|
@@ -1606,58 +1586,26 @@ function header(target, colour) {
|
|
|
1606
1586
|
* Completed phases stay visible because they are the part that says how far along this is. Their
|
|
1607
1587
|
* detail does not: a note about a file read two phases ago is history, and history is what the
|
|
1608
1588
|
* transcript was made of.
|
|
1589
|
+
*
|
|
1590
|
+
* Which phases there are, what they are called and what has become of each is `progressSteps`,
|
|
1591
|
+
* shared with the workspace page so the browser and this block never name one phase two things.
|
|
1592
|
+
* What is left here is how a terminal draws that: a mark, a colour, and an indent.
|
|
1609
1593
|
*/
|
|
1610
1594
|
function phaseLines(job, colour) {
|
|
1611
1595
|
const lines = [];
|
|
1612
|
-
const
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
const current = !complete && !failed && job.phase === phase;
|
|
1618
|
-
const mark = failed ? "✕" : complete ? "✓" : current ? "⟳" : " ";
|
|
1619
|
-
const label = complete || failed ? PHASES[phase].done : PHASES[phase].doing;
|
|
1620
|
-
const paint = failed ? RED : complete ? GREEN : "";
|
|
1621
|
-
if (!complete && !current && !failed) {
|
|
1622
|
-
lines.push(colour ? `${DIM} ${mark} ${label}${RESET}` : ` ${mark} ${label}`);
|
|
1596
|
+
for (const step of progressSteps(job)) {
|
|
1597
|
+
const mark = step.state === "failed" ? "✕" : step.state === "complete" ? "✓" : step.state === "active" ? "⟳" : " ";
|
|
1598
|
+
const paint = step.state === "failed" ? RED : step.state === "complete" ? GREEN : "";
|
|
1599
|
+
if (step.state === "pending") {
|
|
1600
|
+
lines.push(colour ? `${DIM} ${mark} ${step.label}${RESET}` : ` ${mark} ${step.label}`);
|
|
1623
1601
|
continue;
|
|
1624
1602
|
}
|
|
1625
|
-
lines.push(colour && paint ? `${paint}${mark}${RESET} ${label}` : `${mark} ${label}`);
|
|
1626
|
-
if (
|
|
1603
|
+
lines.push(colour && paint ? `${paint}${mark}${RESET} ${step.label}` : `${mark} ${step.label}`);
|
|
1604
|
+
if (step.note) lines.push(colour ? `${DIM} ${step.note}${RESET}` : ` ${step.note}`);
|
|
1627
1605
|
}
|
|
1628
1606
|
return lines;
|
|
1629
1607
|
}
|
|
1630
1608
|
/**
|
|
1631
|
-
* Whether a phase is part of *this* review, rather than part of the pipeline in general.
|
|
1632
|
-
*
|
|
1633
|
-
* Only `conversation` is ever optional, and reviewing a branch with no pull request is an ordinary
|
|
1634
|
-
* supported thing to do rather than a degraded version of something else. Ticking "Read pull
|
|
1635
|
-
* request conversation" on such a review claims a step that did not happen and makes a complete
|
|
1636
|
-
* review look like an incomplete one; printing "No pull request found" instead is no better,
|
|
1637
|
-
* because a line in a checklist reads as something missing whatever words are in it.
|
|
1638
|
-
*
|
|
1639
|
-
* So the rule is that an optional stage which did not apply is not rendered at all:
|
|
1640
|
-
*
|
|
1641
|
-
* - A pull request review always shows it. It is the point of that review, and it is known before
|
|
1642
|
-
* the phase runs, so the line never appears late.
|
|
1643
|
-
* - A branch review shows it only once a conversation was actually attached, which happens when the
|
|
1644
|
-
* branch turns out to have a request on a forge we read. Real work, worth saying.
|
|
1645
|
-
* - Everything else — no request, an unsupported host, `gh` missing — shows nothing.
|
|
1646
|
-
*
|
|
1647
|
-
* The absent cases are still explained, once, at the end: the closing summary says the review was
|
|
1648
|
-
* made without the conversation and why. That is the right place for it, because by then it is a
|
|
1649
|
-
* fact about the finished review rather than a gap in a list of things still happening.
|
|
1650
|
-
*/
|
|
1651
|
-
function applies(job, phase) {
|
|
1652
|
-
if (phase !== "conversation") return true;
|
|
1653
|
-
return job.target.pullRequest !== void 0 || job.conversation?.kind === "attached";
|
|
1654
|
-
}
|
|
1655
|
-
/** Same words as the phase heading, give or take the articles and the trailing full stop. */
|
|
1656
|
-
function restates(note, label) {
|
|
1657
|
-
const bare = (text) => text.toLowerCase().replace(/\bthe\b/g, "").replace(/[^a-z]/g, "");
|
|
1658
|
-
return bare(note) === bare(label);
|
|
1659
|
-
}
|
|
1660
|
-
/**
|
|
1661
1609
|
* How many rows this block will actually occupy, which is not how many strings it is.
|
|
1662
1610
|
*
|
|
1663
1611
|
* The redraw moves the cursor up by a count and clears from there, so that count has to be in the
|
|
@@ -1787,7 +1735,8 @@ async function review(command, repoPath) {
|
|
|
1787
1735
|
return operate(command, workspace);
|
|
1788
1736
|
}
|
|
1789
1737
|
if (command.lens === "kiss") return kiss(command, target);
|
|
1790
|
-
|
|
1738
|
+
const agent = await chooseFor(command);
|
|
1739
|
+
if (!agent) return 1;
|
|
1791
1740
|
if (command.operation !== "fresh") {
|
|
1792
1741
|
const existing = await findExistingReview(target);
|
|
1793
1742
|
if (existing) {
|
|
@@ -1797,13 +1746,14 @@ async function review(command, repoPath) {
|
|
|
1797
1746
|
out(existingReview(existing, url));
|
|
1798
1747
|
return 0;
|
|
1799
1748
|
}
|
|
1800
|
-
err(resumingReview(failed, existing));
|
|
1749
|
+
err(resumingReview(failed.message, existing));
|
|
1750
|
+
if (command.agentId && command.agentId !== failed.agentId) err(agentUnusedByResume(command.agentId));
|
|
1801
1751
|
return drive(existing.id, url);
|
|
1802
1752
|
}
|
|
1803
1753
|
}
|
|
1804
1754
|
const workspaceId = await startJob({
|
|
1805
1755
|
target,
|
|
1806
|
-
|
|
1756
|
+
agentId: agent.id
|
|
1807
1757
|
});
|
|
1808
1758
|
const url = linkTo(await ensureServer(), workspaceId, loadWorkspace(workspaceId).token);
|
|
1809
1759
|
out(startedReview(url, target));
|
|
@@ -1852,7 +1802,7 @@ async function kiss(command, target) {
|
|
|
1852
1802
|
type: "kiss",
|
|
1853
1803
|
audience
|
|
1854
1804
|
},
|
|
1855
|
-
|
|
1805
|
+
agentId: agent.id
|
|
1856
1806
|
});
|
|
1857
1807
|
const fresh = loadWorkspace(workspaceId);
|
|
1858
1808
|
const run = (fresh.kissRuns ?? [])[0];
|
|
@@ -1970,7 +1920,10 @@ function failureOf(workspaceId) {
|
|
|
1970
1920
|
const job = loadJob(workspace.jobId);
|
|
1971
1921
|
if (!job || !isTerminal(job) || job.phase !== "failed") return null;
|
|
1972
1922
|
if (isClaimed(job.id)) return null;
|
|
1973
|
-
return
|
|
1923
|
+
return {
|
|
1924
|
+
message: job.failure?.message ?? "The reason was not recorded.",
|
|
1925
|
+
agentId: job.env.agentId ?? DEFAULT_AGENT_ID
|
|
1926
|
+
};
|
|
1974
1927
|
}
|
|
1975
1928
|
/**
|
|
1976
1929
|
* Run the job to its end, saying what it is doing while it does it.
|
|
@@ -3869,6 +3869,112 @@ function pruneOldWorkspaces() {
|
|
|
3869
3869
|
} catch {}
|
|
3870
3870
|
}
|
|
3871
3871
|
//#endregion
|
|
3872
|
+
//#region ../../packages/review-harness/src/workspace/job_progress.ts
|
|
3873
|
+
/**
|
|
3874
|
+
* The phases that do work, in the order they run. `done` and `failed` are outcomes, not work.
|
|
3875
|
+
*
|
|
3876
|
+
* Declared here rather than in `job_store.ts`, which is where it used to live, because this module
|
|
3877
|
+
* is imported by the browser bundle and that one opens files. Everything here is a string table
|
|
3878
|
+
* and a fold over a record; the store reads this rather than the other way round, so the client
|
|
3879
|
+
* can share the phase model without dragging `node:fs` in behind it. The type still comes from the
|
|
3880
|
+
* store, which is harmless: types are erased.
|
|
3881
|
+
*/
|
|
3882
|
+
var WORK_PHASES = [
|
|
3883
|
+
"preparing",
|
|
3884
|
+
"context",
|
|
3885
|
+
"conversation",
|
|
3886
|
+
"analysing"
|
|
3887
|
+
];
|
|
3888
|
+
/**
|
|
3889
|
+
* Two forms per phase, because a finished step and a running one are different sentences.
|
|
3890
|
+
*
|
|
3891
|
+
* `done` and `failed` are outcomes rather than work, so they never appear in a checklist; they
|
|
3892
|
+
* are named anyway because `JobPhase` includes them and a partial table would make every lookup
|
|
3893
|
+
* a possible undefined.
|
|
3894
|
+
*/
|
|
3895
|
+
var PHASES = {
|
|
3896
|
+
preparing: {
|
|
3897
|
+
doing: "Preparing isolated checkout",
|
|
3898
|
+
done: "Prepared isolated checkout"
|
|
3899
|
+
},
|
|
3900
|
+
context: {
|
|
3901
|
+
doing: "Reading what changed",
|
|
3902
|
+
done: "Read what changed"
|
|
3903
|
+
},
|
|
3904
|
+
conversation: {
|
|
3905
|
+
doing: "Reading pull request conversation",
|
|
3906
|
+
done: "Read pull request conversation"
|
|
3907
|
+
},
|
|
3908
|
+
analysing: {
|
|
3909
|
+
doing: "Analysing the change",
|
|
3910
|
+
done: "Analysed the change"
|
|
3911
|
+
},
|
|
3912
|
+
done: {
|
|
3913
|
+
doing: "Finishing",
|
|
3914
|
+
done: "Finished"
|
|
3915
|
+
},
|
|
3916
|
+
failed: {
|
|
3917
|
+
doing: "Stopped",
|
|
3918
|
+
done: "Stopped"
|
|
3919
|
+
}
|
|
3920
|
+
};
|
|
3921
|
+
/**
|
|
3922
|
+
* Whether a phase is part of *this* review, rather than part of the pipeline in general.
|
|
3923
|
+
*
|
|
3924
|
+
* Only `conversation` is ever optional, and reviewing a branch with no pull request is an ordinary
|
|
3925
|
+
* supported thing to do rather than a degraded version of something else. Ticking "Read pull
|
|
3926
|
+
* request conversation" on such a review claims a step that did not happen and makes a complete
|
|
3927
|
+
* review look like an incomplete one; printing "No pull request found" instead is no better,
|
|
3928
|
+
* because a line in a checklist reads as something missing whatever words are in it.
|
|
3929
|
+
*
|
|
3930
|
+
* So the rule is that an optional stage which did not apply is not rendered at all:
|
|
3931
|
+
*
|
|
3932
|
+
* - A pull request review always shows it. It is the point of that review, and it is known before
|
|
3933
|
+
* the phase runs, so the line never appears late.
|
|
3934
|
+
* - A branch review shows it only once a conversation was actually attached, which happens when the
|
|
3935
|
+
* branch turns out to have a request on a forge we read. Real work, worth saying.
|
|
3936
|
+
* - Everything else — no request, an unsupported host, `gh` missing — shows nothing.
|
|
3937
|
+
*
|
|
3938
|
+
* The absent cases are still explained, once, at the end: the CLI's closing summary and the page's
|
|
3939
|
+
* `conversationNote` both say the review was made without the conversation and why. That is the
|
|
3940
|
+
* right place for it, because by then it is a fact about the finished review rather than a gap in
|
|
3941
|
+
* a list of things still happening.
|
|
3942
|
+
*/
|
|
3943
|
+
function appliesTo(job, phase) {
|
|
3944
|
+
if (phase !== "conversation") return true;
|
|
3945
|
+
return job.target.pullRequest !== void 0 || job.conversation?.kind === "attached";
|
|
3946
|
+
}
|
|
3947
|
+
/**
|
|
3948
|
+
* Every step this review runs, in order, with what has become of each.
|
|
3949
|
+
*
|
|
3950
|
+
* Read from `job.completed` rather than inferred from the position of `job.phase` in the list.
|
|
3951
|
+
* The job records a phase as complete when it is *left*, so a run that died inside a phase leaves
|
|
3952
|
+
* it uncompleted — which is the honest shape of that, and the thing a retry resumes from. Working
|
|
3953
|
+
* it out from ordering instead would tick a step the job never finished.
|
|
3954
|
+
*/
|
|
3955
|
+
function progressSteps(job) {
|
|
3956
|
+
const failedAt = job.phase === "failed" ? job.failure?.phase : void 0;
|
|
3957
|
+
return WORK_PHASES.filter((phase) => appliesTo(job, phase)).map((phase) => {
|
|
3958
|
+
const complete = job.completed.includes(phase) || job.phase === "done";
|
|
3959
|
+
const failed = failedAt === phase;
|
|
3960
|
+
const active = !complete && !failed && job.phase === phase;
|
|
3961
|
+
const state = failed ? "failed" : complete ? "complete" : active ? "active" : "pending";
|
|
3962
|
+
const label = complete ? PHASES[phase].done : PHASES[phase].doing;
|
|
3963
|
+
const note = active && job.progress && !restates(job.progress, label) ? job.progress : void 0;
|
|
3964
|
+
return {
|
|
3965
|
+
phase,
|
|
3966
|
+
label,
|
|
3967
|
+
state,
|
|
3968
|
+
...note ? { note } : {}
|
|
3969
|
+
};
|
|
3970
|
+
});
|
|
3971
|
+
}
|
|
3972
|
+
/** Same words as the phase heading, give or take the articles and the trailing full stop. */
|
|
3973
|
+
function restates(note, label) {
|
|
3974
|
+
const bare = (text) => text.toLowerCase().replace(/\bthe\b/g, "").replace(/[^a-z]/g, "");
|
|
3975
|
+
return bare(note) === bare(label);
|
|
3976
|
+
}
|
|
3977
|
+
//#endregion
|
|
3872
3978
|
//#region ../../packages/review-harness/src/workspace/job_store.ts
|
|
3873
3979
|
/**
|
|
3874
3980
|
* What a review is doing right now, kept apart from the review itself.
|
|
@@ -3878,14 +3984,14 @@ function pruneOldWorkspaces() {
|
|
|
3878
3984
|
* process that rewrites reviews. And a job is finished business within hours while a review is
|
|
3879
3985
|
* kept for thirty days, so one record with two lifetimes would have to encode both.
|
|
3880
3986
|
*/
|
|
3987
|
+
/**
|
|
3988
|
+
* The phases that do work, in the order they run. `done` and `failed` are outcomes, not work.
|
|
3989
|
+
*
|
|
3990
|
+
* Defined in `job_progress.ts` and re-exported here, where every existing caller already looks for
|
|
3991
|
+
* it. It lives there because the workspace page's client bundle needs the phase model and must not
|
|
3992
|
+
* import this module, which opens files.
|
|
3993
|
+
*/
|
|
3881
3994
|
var JOBS_DIR = join(STORE_ROOT, "jobs");
|
|
3882
|
-
/** The phases that do work, in the order they run. `done` and `failed` are outcomes, not work. */
|
|
3883
|
-
var WORK_PHASES = [
|
|
3884
|
-
"preparing",
|
|
3885
|
-
"context",
|
|
3886
|
-
"conversation",
|
|
3887
|
-
"analysing"
|
|
3888
|
-
];
|
|
3889
3995
|
/**
|
|
3890
3996
|
* Whether this job asks the forge for the conversation, or reads what is already on the workspace.
|
|
3891
3997
|
*
|
|
@@ -10629,4 +10735,4 @@ function relativeTime(ms) {
|
|
|
10629
10735
|
return `${days} day${days === 1 ? "" : "s"} ago`;
|
|
10630
10736
|
}
|
|
10631
10737
|
//#endregion
|
|
10632
|
-
export { checkCodeFreshness as $, agentEnvOf as A,
|
|
10738
|
+
export { checkCodeFreshness as $, agentEnvOf as A, processDiscussion as At, BUILD_VERSION as B, STORE_ROOT as Bt, statedWorkspacePort as C, touchWorkspace as Ct, refreshPrContext as D, issuesOutstanding as Dt, updateReview as E, isQuestionOutstanding as Et, startJob as F, agentIdOf as Ft, forgeResolver as G, detectAgents as Gt, feedbackUrl as H, DEFAULT_AGENT_ID as Ht, readEvents as I, clearAgentPreference as It, clearClaim as J, fillFileUrlTemplate as K, AgentCancelledError as Kt, record as L, readAgentPreference as Lt, startKissJob as M, resolveTarget as Mt, reanalyseReview as N, displayRef as Nt, isUnchanged as O, questionsOutstanding as Ot, runJob as P, git as Pt, removeWorktree as Q, recordTelemetryUploadConsent as R, writeAgentPreference as Rt, resolveWorkspacePort as S, summarise as St, RefreshUnavailableError as T, isIssueOutstanding as Tt, withUsageRecorded as U, agentById as Ut, PACKAGE_NAME as V, AGENT_IDS as Vt, EXPLAIN_SIMPLY_PROMPT as W, agentFor as Wt, MANAGED_ROOT as X, isClaimed as Y, readMarker as Z, writeServerRecord as _, recentReviewGroups as _t, liveJobsFor as a, saveJob as at, MIN_WORKSPACE_PORT as b, reviewedRepositories as bt, discardJob as c, followedRefName as ct, clearServerRecord as d, lineageKeyFor as dt, checkFreshness as et, ensureServer as f, lineagePosition as ft, workspaceUrl as g, previousKissResult as gt, stopServer as h, positionInLineage as ht, lineageIds as i, loadJob as it, recordKissRun as j, describeAuthorship as jt, askCheckout as k, reviewerDispositions as kt, readIndexToken as l, groupByLineage as lt, reviewsUrl as m, matchingWorkspaceIds as mt, deleteLineage as n, fail as nt, wasBlocked as o, PHASES as ot, readServerRecord as p, loadWorkspace as pt, ReviewBeingDeletedError as q, AgentUnavailableError as qt, deleteReview as r, isTerminal as rt, runningJobs as s, progressSteps as st, relativeTime as t, allJobs as tt, bootstrapUrl as u, latestKissRun as ut, DEFAULT_WORKSPACE_PORT as v, recentWorkspaces as vt, writePortPreference as w, doneVerb as wt, parseWorkspacePort as x, saveWorkspace as xt, MAX_WORKSPACE_PORT as y, reviewedCommit as yt, telemetryUploadConsent as z, CONFIG_PATH as zt };
|