prreviewbuddy 0.95.2 → 0.96.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/CHANGELOG.md +30 -0
- package/dist/main.js +1 -1
- package/dist/{mcp_tools-DDbcXys2.js → mcp_tools-DEx9NxAc.js} +278 -4
- package/dist/server.js +10614 -8591
- package/package.json +1 -1
- package/static/chunk-C0JUspm9.js +1 -0
- package/static/{chunk-Cum6sHaC.js → chunk-CZ1YsjDz.js} +1 -1
- package/static/{chunk-D1LBeOJc.js → chunk-DLCpB0qV.js} +1 -1
- package/static/chunk-SPHga_7I.js +5 -0
- package/static/help.js +1 -1
- package/static/notifications.js +1 -1
- package/static/reviews.js +1 -1
- package/static/runs.js +1 -1
- package/static/settings.js +1 -1
- package/static/shell.css +231 -0
- package/static/workspace.js +85 -89
- package/static/chunk-CQIPqX7U.js +0 -1
- package/static/chunk-Cs33-tV3.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.96.0
|
|
4
|
+
|
|
5
|
+
**Quick Review.** Press Space on a review in the Reviews list, or choose Quick Review from its menu
|
|
6
|
+
or above the list, to read its brief in a window over the list: why the change exists, how things
|
|
7
|
+
work today and what changes, what it depends on and what depends on it, its issues and questions by
|
|
8
|
+
impact, what needs your decision, and the commit it describes with whether newer commits have
|
|
9
|
+
arrived. J and K scroll, H and L (or the arrow keys) go to the previous and next review in the list
|
|
10
|
+
as filtered and sorted, M opens the review's menu, and Escape returns to the list where you left it.
|
|
11
|
+
Opening a brief calls no model and marks nothing as read or reviewed. The review menu on the list
|
|
12
|
+
moves from Space to M, which the first Quick Review says once, and each control shows its key. Deleting a
|
|
13
|
+
review from its menu in Quick Review keeps Quick Review open on the next review.
|
|
14
|
+
|
|
15
|
+
**Your outcome.** Record Reviewed: no concerns, Needs changes, Needs a decision / answer, Needs
|
|
16
|
+
deeper review or Later, kept in this workspace only and never sent to the forge. The first three
|
|
17
|
+
also mark the review Reviewed and set the point that "Since your last review" is measured from:
|
|
18
|
+
the new commits, which findings were addressed in code or marked resolved through discussion, what
|
|
19
|
+
is new and what is still open. Needs deeper review and Later are shown beside your verdict and never
|
|
20
|
+
replace it. An outcome recorded on an earlier commit or an earlier analysis of
|
|
21
|
+
the same commit is shown as such, and one recorded against a brief that has since changed is
|
|
22
|
+
refused and the brief refreshed.
|
|
23
|
+
|
|
24
|
+
**Dependencies.** Stacked pull requests are detected from the base and head repository and branch,
|
|
25
|
+
with unclear cases offered as "Possibly stacked". You can link one review to another, and a
|
|
26
|
+
description that says it depends on a reviewed pull request is offered as a suggestion to confirm
|
|
27
|
+
or dismiss. A stacked branch can be marked Not a dependency, kept on view with what was detected
|
|
28
|
+
and undone, and detected afresh if either branch changes.
|
|
29
|
+
|
|
30
|
+
**Before and after.** New analyses and updates describe how the code behaves at the base and how
|
|
31
|
+
it behaves after the change. Earlier reviews say this isn't available rather than guessing.
|
|
32
|
+
|
|
3
33
|
## 0.95.2
|
|
4
34
|
|
|
5
35
|
`review --no-wait` without `--json` no longer prints advice meant for MCP clients, such as tool
|
package/dist/main.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $
|
|
2
|
+
import { $r as describeSubject, An as telemetryUploadEnabled, Ao as readAgentPreference, At as interruption, Bi as matchingWorkspaceIds, Bo as runnableAgents, Bt as healthyPort, Ci as clearClaim, Cn as append, Ct as findingRef, Dn as deliver$1, Do as resolveModel, E as relativeTime, En as stamp, Eo as resolveAgent, Et as reviewTag, Ft as recordAskAccepted, Go as cleanName, Gr as MANAGED_ROOT, Ht as reviewsUrl, Ia as reviewerDispositions, Io as agentIdentityOf, It as readIndexToken, Ji as reviewedRepositories, Ki as recentWorkspaces, Kt as stopServer, L as collectionHash, La as verdictClosure, Lo as detectAgents, Lt as bootstrapUrl, Ma as isQuestionOutstanding, Mn as PACKAGE_NAME, Mo as CONFIG_PATH, Mt as isTerminalAsk, No as AGENT_IDS, Oi as followedRefName, On as recordTelemetryUploadConsent, Oo as agentIdOf, Ot as endAskRequest, Po as agentById, Pt as readAskRequest, Qa as findingStatus, Qr as describeMovement, Qt as parseWorkspacePort, Ri as lineagePosition, Ro as isAgentId, Si as purposeOf, Sn as startJob, T as runBatch, Ti as isClaimed, Ui as positionInLineage, Va as explanationOf, Vr as modelHelpLines, Vt as readServerRecord, Xa as findingAssessment, Xr as removeWorktree, Xt as MAX_WORKSPACE_PORT, Yi as summarise, Yr as readMarker, Yt as DEFAULT_WORKSPACE_PORT, Zi as workspaceRevision, Zt as MIN_WORKSPACE_PORT, _i as PHASES, _t as applyUpdate, bn as reanalyseReview, cn as parkedUpdateRefusal, ei as findExistingReview, en as statedWorkspacePort, ft as RUNNER_KINDS, gn as failureOf, gt as spawnRunner, hn as runningJobs, ho as resolveTarget, ht as runDetached, i as deleteReview$1, it as openDestination, ja as isIssueOutstanding, jn as BUILD_VERSION, jo as writeAgentPreference, kn as telemetryUploadConsent, kt as forgetAskRequest, li as allJobs, mi as loadJob, mn as liveUpdateFor, mo as kissOutcome, nn as COMMIT_REVIEW_CANNOT_UPDATE, nt as isDelivered, o as liveJobsFor, oi as forgeResolver, pi as isTerminal$1, pn as UpdateAlreadyRunningError, po as WITHHELD_REASON, qi as reviewedCommit, qt as workspaceUrl, rt as missedDelivery, s as wasBlocked, t as MCP_SERVER_INFO_NAME, tn as writePortPreference, ts as STORE_ROOT, tt as deliver, u as recordKissRun, ui as attemptIdOf, ut as queueForReview, vn as prepareReview, vo as TargetError, vt as modelProvenanceOf, wi as driverGone, wo as git, x as batchIdentity, xi as progressSteps, xo as AmbiguousRefError, yn as settleReview, zi as loadWorkspace, zo as parkedReason, zt as ensureServer } from "./mcp_tools-DEx9NxAc.js";
|
|
3
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
4
4
|
import { existsSync, mkdirSync, readdirSync, realpathSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { basename, dirname, isAbsolute, join, resolve } from "node:path";
|
|
@@ -6556,6 +6556,159 @@ function lifecycleItemLabel(target, lifecycle, activity) {
|
|
|
6556
6556
|
return lifecycleAction(target);
|
|
6557
6557
|
}
|
|
6558
6558
|
//#endregion
|
|
6559
|
+
//#region ../../packages/review-harness/src/workspace/reviewer_outcome.ts
|
|
6560
|
+
var REVIEWER_OUTCOMES = [
|
|
6561
|
+
{
|
|
6562
|
+
id: "no-concerns",
|
|
6563
|
+
name: "Reviewed: no concerns",
|
|
6564
|
+
baseline: true
|
|
6565
|
+
},
|
|
6566
|
+
{
|
|
6567
|
+
id: "needs-changes",
|
|
6568
|
+
name: "Needs changes",
|
|
6569
|
+
baseline: true
|
|
6570
|
+
},
|
|
6571
|
+
{
|
|
6572
|
+
id: "needs-decision",
|
|
6573
|
+
name: "Needs a decision / answer",
|
|
6574
|
+
baseline: true
|
|
6575
|
+
},
|
|
6576
|
+
{
|
|
6577
|
+
id: "deeper-review",
|
|
6578
|
+
name: "Needs deeper review",
|
|
6579
|
+
baseline: false
|
|
6580
|
+
},
|
|
6581
|
+
{
|
|
6582
|
+
id: "later",
|
|
6583
|
+
name: "Later",
|
|
6584
|
+
baseline: false
|
|
6585
|
+
}
|
|
6586
|
+
];
|
|
6587
|
+
function parseOutcomeSnapshot(value) {
|
|
6588
|
+
if (typeof value !== "object" || value === null) return null;
|
|
6589
|
+
const raw = value;
|
|
6590
|
+
if (typeof raw.sessionId !== "string" || typeof raw.commitSha !== "string" || typeof raw.analysisRevision !== "string") return null;
|
|
6591
|
+
return {
|
|
6592
|
+
sessionId: raw.sessionId,
|
|
6593
|
+
commitSha: raw.commitSha,
|
|
6594
|
+
analysisRevision: raw.analysisRevision
|
|
6595
|
+
};
|
|
6596
|
+
}
|
|
6597
|
+
function outcomeDefinition(kind) {
|
|
6598
|
+
return REVIEWER_OUTCOMES.find((outcome) => outcome.id === kind);
|
|
6599
|
+
}
|
|
6600
|
+
function isBaselineKind(kind) {
|
|
6601
|
+
return outcomeDefinition(kind)?.baseline === true;
|
|
6602
|
+
}
|
|
6603
|
+
function parseStoredOutcome(value) {
|
|
6604
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
6605
|
+
const raw = value;
|
|
6606
|
+
if (typeof raw.kind !== "string" || !outcomeDefinition(raw.kind)) return void 0;
|
|
6607
|
+
if (typeof raw.at !== "number" || !Number.isFinite(raw.at)) return void 0;
|
|
6608
|
+
if (typeof raw.commitSha !== "string" || typeof raw.sessionId !== "string") return void 0;
|
|
6609
|
+
return {
|
|
6610
|
+
kind: raw.kind,
|
|
6611
|
+
at: raw.at,
|
|
6612
|
+
commitSha: raw.commitSha,
|
|
6613
|
+
sessionId: raw.sessionId,
|
|
6614
|
+
analysisRevision: typeof raw.analysisRevision === "string" ? raw.analysisRevision : "",
|
|
6615
|
+
...typeof raw.recordId === "string" ? { recordId: raw.recordId } : {},
|
|
6616
|
+
...typeof raw.analysisJobId === "string" ? { analysisJobId: raw.analysisJobId } : {},
|
|
6617
|
+
...Array.isArray(raw.answeredQuestions) ? { answeredQuestions: raw.answeredQuestions.filter((q) => typeof q === "string") } : {}
|
|
6618
|
+
};
|
|
6619
|
+
}
|
|
6620
|
+
function parseOutcomes(value) {
|
|
6621
|
+
if (!Array.isArray(value)) return [];
|
|
6622
|
+
return value.map(parseStoredOutcome).filter((outcome) => outcome !== void 0);
|
|
6623
|
+
}
|
|
6624
|
+
/** Newest last, capped. The baseline lives in its own field, so nothing here has to survive pruning. */
|
|
6625
|
+
function appendOutcome(history, outcome) {
|
|
6626
|
+
return [...history, outcome].slice(-20);
|
|
6627
|
+
}
|
|
6628
|
+
/** The newer of two baselines; a non-baseline outcome never replaces one. */
|
|
6629
|
+
function nextBaseline(current, outcome) {
|
|
6630
|
+
if (!isBaselineKind(outcome.kind)) return current;
|
|
6631
|
+
return !current || outcome.at >= current.at ? outcome : current;
|
|
6632
|
+
}
|
|
6633
|
+
/** The newest baseline across a lineage's records, so a re-analysis that made a new record keeps it. */
|
|
6634
|
+
function lastBaseline(baselines) {
|
|
6635
|
+
let newest;
|
|
6636
|
+
for (const baseline of baselines) if (baseline && (!newest || baseline.at > newest.at)) newest = baseline;
|
|
6637
|
+
return newest;
|
|
6638
|
+
}
|
|
6639
|
+
function sameSha(a, b) {
|
|
6640
|
+
if (!a || !b) return false;
|
|
6641
|
+
const length = Math.min(a.length, b.length);
|
|
6642
|
+
return length >= 7 && a.slice(0, length) === b.slice(0, length);
|
|
6643
|
+
}
|
|
6644
|
+
/** How an outcome relates to the analysis on screen. */
|
|
6645
|
+
function outcomeStanding(outcome, snapshot) {
|
|
6646
|
+
if (!sameSha(outcome.commitSha, snapshot.commitSha)) return "earlier-snapshot";
|
|
6647
|
+
if (outcome.sessionId !== snapshot.sessionId || outcome.analysisRevision !== snapshot.analysisRevision) return "earlier-analysis";
|
|
6648
|
+
return "current";
|
|
6649
|
+
}
|
|
6650
|
+
/**
|
|
6651
|
+
* Verdicts come from the history and from the stored baseline, which is never pruned: twenty
|
|
6652
|
+
* deferrals after a verdict push it out of the history, but not out of the reading.
|
|
6653
|
+
*/
|
|
6654
|
+
function readOutcomes(history, snapshot, baseline) {
|
|
6655
|
+
const verdicts = history.filter((outcome) => isBaselineKind(outcome.kind));
|
|
6656
|
+
if (baseline && isBaselineKind(baseline.kind) && !verdicts.some((outcome) => outcome.at === baseline.at && outcome.kind === baseline.kind)) verdicts.push(baseline);
|
|
6657
|
+
verdicts.sort((a, b) => a.at - b.at);
|
|
6658
|
+
const newestVerdict = verdicts.at(-1);
|
|
6659
|
+
if (!snapshot) return newestVerdict ? { previous: {
|
|
6660
|
+
outcome: newestVerdict,
|
|
6661
|
+
standing: "earlier-snapshot"
|
|
6662
|
+
} } : {};
|
|
6663
|
+
const verdict = verdicts.filter((outcome) => outcomeStanding(outcome, snapshot) === "current").at(-1);
|
|
6664
|
+
const deferral = history.filter((outcome) => !isBaselineKind(outcome.kind) && outcomeStanding(outcome, snapshot) === "current" && (!verdict || outcome.at > verdict.at)).at(-1);
|
|
6665
|
+
const reading = {};
|
|
6666
|
+
if (verdict) reading.verdict = verdict;
|
|
6667
|
+
else if (newestVerdict) reading.previous = {
|
|
6668
|
+
outcome: newestVerdict,
|
|
6669
|
+
standing: outcomeStanding(newestVerdict, snapshot)
|
|
6670
|
+
};
|
|
6671
|
+
if (deferral) reading.deferral = deferral;
|
|
6672
|
+
return reading;
|
|
6673
|
+
}
|
|
6674
|
+
/** "Needs changes", or how an older one reads beside a newer analysis. */
|
|
6675
|
+
function outcomeLabel(outcome, standing) {
|
|
6676
|
+
const name = outcomeDefinition(outcome.kind)?.name ?? outcome.kind;
|
|
6677
|
+
if (standing === "current") return name;
|
|
6678
|
+
if (standing === "earlier-analysis") return `Outcome on an earlier analysis: ${name}`;
|
|
6679
|
+
return `${name} on ${outcome.commitSha.slice(0, 7)} (earlier snapshot)`;
|
|
6680
|
+
}
|
|
6681
|
+
//#endregion
|
|
6682
|
+
//#region ../../packages/review-harness/src/workspace/analysis_revision.ts
|
|
6683
|
+
/**
|
|
6684
|
+
* A short fingerprint of the analysis a reviewer is reading: its findings, statuses, notes and text.
|
|
6685
|
+
*
|
|
6686
|
+
* The session id and the commit do not move when a Re-check reconciles findings at the same commit,
|
|
6687
|
+
* so a verdict checked against those two alone would be accepted for findings the reviewer never saw.
|
|
6688
|
+
* The reviewer's own ticks are not part of it: those are the reviewer's acts, not the analysis.
|
|
6689
|
+
*/
|
|
6690
|
+
function analysisRevision(workspace) {
|
|
6691
|
+
const result = workspace.session.result;
|
|
6692
|
+
if (!result) return "";
|
|
6693
|
+
return createHash("sha256").update(JSON.stringify(result)).digest("hex").slice(0, 16);
|
|
6694
|
+
}
|
|
6695
|
+
/** The analysed commit, falling back the way `reviewedCommit` does. */
|
|
6696
|
+
function analysedCommit(workspace) {
|
|
6697
|
+
return workspace.session.metadata?.commitSha || workspace.changeSet.data.pullRequest.head.sha || "";
|
|
6698
|
+
}
|
|
6699
|
+
function analysisSnapshot(workspace) {
|
|
6700
|
+
if (!workspace.session.result) return null;
|
|
6701
|
+
return {
|
|
6702
|
+
sessionId: workspace.session.id,
|
|
6703
|
+
commitSha: analysedCommit(workspace),
|
|
6704
|
+
analysisRevision: analysisRevision(workspace)
|
|
6705
|
+
};
|
|
6706
|
+
}
|
|
6707
|
+
/** When the analysis on screen was last produced or reconciled: the upper time bound for its history. */
|
|
6708
|
+
function analysedAt(workspace) {
|
|
6709
|
+
return Math.max(workspace.session.metadata?.generatedAt ?? 0, workspace.lastUpdate?.at ?? 0, workspace.lastRecheck?.at ?? 0, workspace.createdAt);
|
|
6710
|
+
}
|
|
6711
|
+
//#endregion
|
|
6559
6712
|
//#region ../../packages/review-harness/src/workspace/store.ts
|
|
6560
6713
|
var WORKSPACES_DIR = join(STORE_ROOT, "workspaces");
|
|
6561
6714
|
/**
|
|
@@ -6750,6 +6903,18 @@ function workspaceRevision(workspace) {
|
|
|
6750
6903
|
}
|
|
6751
6904
|
}
|
|
6752
6905
|
/**
|
|
6906
|
+
* Moves whenever any review is written or deleted, by this process or another: every write stages a
|
|
6907
|
+
* file in the directory and renames it into place, and a delete unlinks one. One stat, where
|
|
6908
|
+
* `workspaceStamps` is one per review, for a cache to ask whether anything changed at all.
|
|
6909
|
+
*/
|
|
6910
|
+
function workspacesRevision() {
|
|
6911
|
+
try {
|
|
6912
|
+
return statSync(WORKSPACES_DIR).mtimeMs;
|
|
6913
|
+
} catch {
|
|
6914
|
+
return 0;
|
|
6915
|
+
}
|
|
6916
|
+
}
|
|
6917
|
+
/**
|
|
6753
6918
|
* Every stored review as an id and a revision token, without reading one of them.
|
|
6754
6919
|
*
|
|
6755
6920
|
* Here rather than in `reviews_revision.ts` because this module owns the layout of `workspaces/`,
|
|
@@ -7031,6 +7196,14 @@ function groupByLineage(reviews) {
|
|
|
7031
7196
|
}
|
|
7032
7197
|
return [...groups].map(([key, members]) => {
|
|
7033
7198
|
const history = [...members].sort((a, b) => b.createdAt - a.createdAt);
|
|
7199
|
+
const [newest] = history;
|
|
7200
|
+
if (newest.outcomeInputs && history.length > 1) {
|
|
7201
|
+
const { outcome: _outcome, deferral: _deferral, ...rest } = newest;
|
|
7202
|
+
history[0] = {
|
|
7203
|
+
...rest,
|
|
7204
|
+
...lineageOutcome(newest.outcomeInputs, history.map((review) => review.outcomeInputs))
|
|
7205
|
+
};
|
|
7206
|
+
}
|
|
7034
7207
|
return {
|
|
7035
7208
|
key,
|
|
7036
7209
|
latest: history[0],
|
|
@@ -7161,6 +7334,8 @@ function summarise(workspace) {
|
|
|
7161
7334
|
})(),
|
|
7162
7335
|
lastViewedAt: workspace.lastViewedAt,
|
|
7163
7336
|
completedAt: workspace.completedAt,
|
|
7337
|
+
outcomeInputs: outcomeInputsOf(workspace),
|
|
7338
|
+
...outcomeSummary(outcomeInputsOf(workspace)),
|
|
7164
7339
|
pinned: workspace.pinned === true,
|
|
7165
7340
|
lifecycle: parseLifecycle(workspace.lifecycle),
|
|
7166
7341
|
paths: files.slice(0, MAX_INDEXED_PATHS).map((file) => file.name),
|
|
@@ -7171,6 +7346,42 @@ function summarise(workspace) {
|
|
|
7171
7346
|
authorName: workspace.prContext?.pullRequest.author?.name || void 0
|
|
7172
7347
|
};
|
|
7173
7348
|
}
|
|
7349
|
+
function outcomeInputsOf(workspace) {
|
|
7350
|
+
const baseline = parseStoredOutcome(workspace.reviewedBaseline);
|
|
7351
|
+
return {
|
|
7352
|
+
history: parseOutcomes(workspace.reviewerOutcomes),
|
|
7353
|
+
snapshot: analysisSnapshot(workspace),
|
|
7354
|
+
...baseline ? { baseline } : {}
|
|
7355
|
+
};
|
|
7356
|
+
}
|
|
7357
|
+
/**
|
|
7358
|
+
* The newest record's outcomes read with the newest baseline of its whole lineage, as Quick Review
|
|
7359
|
+
* reads them. A fresh analysis makes a record with no baseline of its own, and the verdict on the
|
|
7360
|
+
* one before must still show on the card, as an earlier one, instead of vanishing from it.
|
|
7361
|
+
*/
|
|
7362
|
+
function lineageOutcome(newest, lineage) {
|
|
7363
|
+
return outcomeSummary(newest, lastBaseline([newest.baseline, ...lineage.map((inputs) => inputs?.baseline)]));
|
|
7364
|
+
}
|
|
7365
|
+
function outcomeSummary(inputs, baseline = inputs.baseline) {
|
|
7366
|
+
const reading = readOutcomes(inputs.history, inputs.snapshot, baseline);
|
|
7367
|
+
const verdict = reading.verdict ? {
|
|
7368
|
+
outcome: reading.verdict,
|
|
7369
|
+
standing: "current"
|
|
7370
|
+
} : reading.previous;
|
|
7371
|
+
return {
|
|
7372
|
+
...verdict ? { outcome: {
|
|
7373
|
+
kind: verdict.outcome.kind,
|
|
7374
|
+
standing: verdict.standing,
|
|
7375
|
+
label: outcomeLabel(verdict.outcome, verdict.standing),
|
|
7376
|
+
at: verdict.outcome.at
|
|
7377
|
+
} } : {},
|
|
7378
|
+
...reading.deferral ? { deferral: {
|
|
7379
|
+
kind: reading.deferral.kind,
|
|
7380
|
+
label: outcomeLabel(reading.deferral, "current"),
|
|
7381
|
+
at: reading.deferral.at
|
|
7382
|
+
} } : {}
|
|
7383
|
+
};
|
|
7384
|
+
}
|
|
7174
7385
|
/**
|
|
7175
7386
|
* The commit a review was made from, however the record spells it. Null when it recorded none.
|
|
7176
7387
|
*
|
|
@@ -8386,6 +8597,14 @@ function sanitisePullRequest(value) {
|
|
|
8386
8597
|
if (template) pr.fileUrlTemplate = template;
|
|
8387
8598
|
const author = pullRequestAuthor(value.author);
|
|
8388
8599
|
if (author) pr.author = author;
|
|
8600
|
+
if (isRecord$1(value.headRepository)) {
|
|
8601
|
+
const owner = label(value.headRepository.owner);
|
|
8602
|
+
const repo = label(value.headRepository.repo);
|
|
8603
|
+
if (owner && repo) pr.headRepository = {
|
|
8604
|
+
owner,
|
|
8605
|
+
repo
|
|
8606
|
+
};
|
|
8607
|
+
}
|
|
8389
8608
|
return pr;
|
|
8390
8609
|
}
|
|
8391
8610
|
/**
|
|
@@ -9093,7 +9312,7 @@ function slug(repo) {
|
|
|
9093
9312
|
* `baseRefOid` is a diff taken against the wrong *commit*, which is worse because the branch name
|
|
9094
9313
|
* is right and everything reads as normal. A list nobody asserts is a list somebody tidies.
|
|
9095
9314
|
*/
|
|
9096
|
-
var PR_FIELDS = "number,url,title,body,headRefName,headRefOid,baseRefName,baseRefOid,changedFiles,author";
|
|
9315
|
+
var PR_FIELDS = "number,url,title,body,headRefName,headRefOid,baseRefName,baseRefOid,changedFiles,author,headRepository,headRepositoryOwner";
|
|
9097
9316
|
async function viewRequest(repo, reference, cwd, env) {
|
|
9098
9317
|
return await ghJson([
|
|
9099
9318
|
"pr",
|
|
@@ -9142,7 +9361,11 @@ function identity(raw) {
|
|
|
9142
9361
|
author: author ? {
|
|
9143
9362
|
name: text$2(author.name),
|
|
9144
9363
|
handle: text$2(author.login)
|
|
9145
|
-
} : null
|
|
9364
|
+
} : null,
|
|
9365
|
+
...text$2(raw.headRepositoryOwner?.login) && text$2(raw.headRepository?.name) ? { headRepository: {
|
|
9366
|
+
owner: text$2(raw.headRepositoryOwner?.login),
|
|
9367
|
+
repo: text$2(raw.headRepository?.name)
|
|
9368
|
+
} } : {}
|
|
9146
9369
|
};
|
|
9147
9370
|
}
|
|
9148
9371
|
/**
|
|
@@ -11337,6 +11560,32 @@ ${diff}`;
|
|
|
11337
11560
|
};
|
|
11338
11561
|
}
|
|
11339
11562
|
//#endregion
|
|
11563
|
+
//#region ../../packages/review-harness/src/domain/ai_review/behaviour_change.ts
|
|
11564
|
+
/** Both sides present and non-empty, or nothing: half an explanation is not one. */
|
|
11565
|
+
function parseBehaviourChange(value) {
|
|
11566
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
|
|
11567
|
+
const raw = value;
|
|
11568
|
+
const before = typeof raw.before === "string" ? raw.before.trim() : "";
|
|
11569
|
+
const after = typeof raw.after === "string" ? raw.after.trim() : "";
|
|
11570
|
+
return before && after ? {
|
|
11571
|
+
before,
|
|
11572
|
+
after
|
|
11573
|
+
} : void 0;
|
|
11574
|
+
}
|
|
11575
|
+
function withBehaviourChange(change) {
|
|
11576
|
+
return change ? { behaviourChange: change } : {};
|
|
11577
|
+
}
|
|
11578
|
+
/**
|
|
11579
|
+
* The behaviourChange an update keeps.
|
|
11580
|
+
*
|
|
11581
|
+
* Restated: the new one. New code and none restated: dropped, because the old one describes a head
|
|
11582
|
+
* that no longer exists. A conversation-only pass read no new code, so the previous one still holds.
|
|
11583
|
+
*/
|
|
11584
|
+
function mergeBehaviourChange(previous, restated, codeChanged) {
|
|
11585
|
+
if (restated) return restated;
|
|
11586
|
+
return codeChanged ? void 0 : previous;
|
|
11587
|
+
}
|
|
11588
|
+
//#endregion
|
|
11340
11589
|
//#region ../../packages/review-harness/src/domain/utils/html.ts
|
|
11341
11590
|
function escapeHtml(value) {
|
|
11342
11591
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
@@ -12652,6 +12901,10 @@ var CONSEQUENCE_GUIDANCE = `"consequence" on an issue: the same issue told as wh
|
|
|
12652
12901
|
- An issue names a concrete consequence. A request for missing requirements with no concrete consequence is a question for the author, not an issue, and is never raised as both.`;
|
|
12653
12902
|
/** What "orientation" is for, as the first analysis and an update ask for it. */
|
|
12654
12903
|
var ORIENTATION_GUIDANCE = `"orientation": one sentence, at most about 25 words, naming the behaviour or product area this change touches, for a reviewer about to decide on its issues (e.g. "This change affects receipt extraction and how duplicate receipt details are combined."). Say what it touches, not whether it is safe, and do not summarise the issues.`;
|
|
12904
|
+
/** The behaviourChange shape, written out whole for every prompt that asks for it. */
|
|
12905
|
+
var BEHAVIOUR_CHANGE_FIELD = "\"behaviourChange\"?: { \"before\": string, \"after\": string }";
|
|
12906
|
+
/** What "behaviourChange" is for, as the first analysis and an update ask for it. */
|
|
12907
|
+
var BEHAVIOUR_CHANGE_GUIDANCE = `"behaviourChange": how the behaviour this pull request touches works today and how it works with the whole pull request applied, for a reviewer who knows the product. "before" is the behaviour at the base the pull request targets; "after" is the behaviour at the head you analysed. One to three plain sentences each, leading with what a user or the system experiences, not with the implementation (e.g. before: "A failed payment is shown as an error and the order is cancelled.", after: "A failed payment is retried twice before the order is cancelled, and the customer is emailed after the last attempt."). Describe the whole pull request, not one commit. Omit the field entirely when the code you read does not establish how it works today: never guess "before".`;
|
|
12655
12908
|
/**
|
|
12656
12909
|
* How an update keeps a prior finding's consequence and resolution true, beside its status.
|
|
12657
12910
|
*
|
|
@@ -13458,6 +13711,7 @@ var STRUCTURED_OUTPUT_INSTRUCTIONS = `In addition to the review principles above
|
|
|
13458
13711
|
},
|
|
13459
13712
|
"overallRisk": "low" | "medium" | "high",
|
|
13460
13713
|
"orientation": string,
|
|
13714
|
+
${BEHAVIOUR_CHANGE_FIELD},
|
|
13461
13715
|
"sections": [{
|
|
13462
13716
|
"id": string,
|
|
13463
13717
|
"order": number,
|
|
@@ -13495,6 +13749,7 @@ Field guidance:
|
|
|
13495
13749
|
- ${CONSEQUENCE_GUIDANCE}
|
|
13496
13750
|
- ${QUESTION_FRAMING_GUIDANCE}
|
|
13497
13751
|
- ${ORIENTATION_GUIDANCE}
|
|
13752
|
+
- ${BEHAVIOUR_CHANGE_GUIDANCE}
|
|
13498
13753
|
- "existingDiscussion" on an issue: set this only when a thread in the PR DISCUSSION CONTEXT block already raises this same concern, and you have independently confirmed from the diff that it still applies. "threadId" must be copied verbatim from that thread's [T_...] marker — never invent an id, never guess, and omit the field entirely if no thread matches. Set "relation" to "same" when the thread already makes this exact point, or "related" when it discusses this area without covering the finding — a reviewer acts differently on "someone said this already" than on "someone was looking near here". Still write the issue normally; this field only records that the point was raised before, so the reviewer is not shown it as a fresh discovery. Do not use it to pad the review with issues you would otherwise have left out.
|
|
13499
13754
|
- "confidence" on an issue: how sure you are the issue is real, on the same high/medium/low scale as a question's "importance". This is a separate axis from "severity", which is how much it would matter if real — a critical issue you are unsure about and a nit you are certain of are different things to act on, so do not let one field stand in for the other. Use LOW when you are reasoning from a diff excerpt without the surrounding code, and say what would confirm it in the description. Omit the field rather than guessing a middle value.
|
|
13500
13755
|
- "questions": each one is a genuine open item the reviewer needs answered before they can sign off, not a rhetorical prompt. "importance" is how much attention it deserves, on the same high/medium/low scale as a section's "reviewAttention" (e.g. a question about a possibly-exposed secret is "high"; a naming preference is "low"). "whyThisMatters" is 1-2 sentences explaining the concrete consequence of the question going unanswered — not a restatement of the question itself.
|
|
@@ -13553,6 +13808,7 @@ function parseUnchecked(raw) {
|
|
|
13553
13808
|
summary,
|
|
13554
13809
|
overallRisk: RISKS.includes(obj.overallRisk) ? obj.overallRisk : "medium",
|
|
13555
13810
|
...asString$1(obj.orientation).trim() ? { orientation: asString$1(obj.orientation).trim() } : {},
|
|
13811
|
+
...withBehaviourChange(parseBehaviourChange(obj.behaviourChange)),
|
|
13556
13812
|
sections: normalizeSections(obj.sections),
|
|
13557
13813
|
issues: normalizeIssues(obj.issues),
|
|
13558
13814
|
questions: normalizeQuestions(obj.questions),
|
|
@@ -18226,6 +18482,7 @@ var RECONCILIATION_SHAPE = `{
|
|
|
18226
18482
|
}],
|
|
18227
18483
|
"summary": string,
|
|
18228
18484
|
"orientation": string,
|
|
18485
|
+
${BEHAVIOUR_CHANGE_FIELD},
|
|
18229
18486
|
"overallRisk": "low" | "medium" | "high",
|
|
18230
18487
|
"recommendation": string,
|
|
18231
18488
|
"nextSteps": string[]
|
|
@@ -18333,6 +18590,12 @@ var GRADE_TASK = {
|
|
|
18333
18590
|
* written to fix a finding is precisely where a regression gets introduced. A run that only
|
|
18334
18591
|
* reassessed the list has done half the work, and it is the half that looks complete.
|
|
18335
18592
|
*/
|
|
18593
|
+
/** The earlier before-and-after, quoted so the model can restate it rather than start over. */
|
|
18594
|
+
function previousBehaviourChange(previous) {
|
|
18595
|
+
const change = previous.behaviourChange;
|
|
18596
|
+
if (!change) return "";
|
|
18597
|
+
return ` (the earlier analysis said: before: ${JSON.stringify(change.before)}; after: ${JSON.stringify(change.after)}. Keep what still holds, correct what the new changes alter)`;
|
|
18598
|
+
}
|
|
18336
18599
|
function buildReconciliationInstructions(input, options = {}) {
|
|
18337
18600
|
const { previous, totalCommits, changedFiles, possiblyTruncated } = input;
|
|
18338
18601
|
const reassess = input.reassess ?? /* @__PURE__ */ new Map();
|
|
@@ -18366,7 +18629,7 @@ ${REASSESS_TASK}` : ""}
|
|
|
18366
18629
|
${GRADE_TASK.question}`] : [],
|
|
18367
18630
|
conversationOnly ? `No commits were pushed, so there is no new code to review. Report a problem in "newIssues" only where the conversation points at something in the code the earlier analysis missed and you have confirmed it by reading the code. Do NOT repeat a previous finding here: if it still stands, that is what "still-open" is for.` : `Read the changed code above as a reviewer, not only as an auditor of the numbered list. These commits have not been reviewed by anyone. Report every genuinely NEW problem you find in them in "newIssues", whether or not it relates to anything on the list — code written to fix a finding is exactly where a regression gets introduced, and reassessing the list and stopping there is half the job. Do NOT repeat a previous finding here: if it still stands, that is what "still-open" is for.`,
|
|
18368
18631
|
`If the new changes introduce an area the earlier analysis had no section for, add it to "newSections". Otherwise return an empty array. Do not restate or restructure the earlier analysis's existing sections.`,
|
|
18369
|
-
`Give a fresh "summary", "overallRisk", "recommendation" and "nextSteps" for the pull request AS IT NOW STANDS, taking both the earlier findings that survive and the new changes into account. Unlike a partial review, you have been shown the earlier analysis in full and are expected to revise its verdict where the new changes justify it. ${SUMMARY_GUIDANCE} ${ORIENTATION_GUIDANCE}
|
|
18632
|
+
`Give a fresh "summary", "overallRisk", "recommendation" and "nextSteps" for the pull request AS IT NOW STANDS, taking both the earlier findings that survive and the new changes into account. Unlike a partial review, you have been shown the earlier analysis in full and are expected to revise its verdict where the new changes justify it. ${SUMMARY_GUIDANCE} ${ORIENTATION_GUIDANCE} ${BEHAVIOUR_CHANGE_GUIDANCE} Restate "behaviourChange" for the whole pull request as it now stands${previousBehaviourChange(previous)}, or omit it when the evidence does not establish it.`
|
|
18370
18633
|
].map((task, index) => `${index + 1}. ${task}`).join("\n");
|
|
18371
18634
|
return `${conversationOnly ? `You are RECONCILING an earlier analysis of this pull request against what has changed in its conversation since that analysis was made.
|
|
18372
18635
|
|
|
@@ -18540,6 +18803,7 @@ function parseReconciliationResult(raw, priorCount, options = {}) {
|
|
|
18540
18803
|
})),
|
|
18541
18804
|
summary: asString$1(obj.summary).trim(),
|
|
18542
18805
|
orientation: asString$1(obj.orientation).trim(),
|
|
18806
|
+
...withBehaviourChange(parseBehaviourChange(obj.behaviourChange)),
|
|
18543
18807
|
overallRisk: RISKS.includes(obj.overallRisk) ? obj.overallRisk : null,
|
|
18544
18808
|
recommendation: asString$1(obj.recommendation).trim(),
|
|
18545
18809
|
nextSteps: asStringArray(obj.nextSteps)
|
|
@@ -18817,6 +19081,15 @@ function findingsChanged(counts) {
|
|
|
18817
19081
|
}
|
|
18818
19082
|
//#endregion
|
|
18819
19083
|
//#region ../../packages/review-harness/src/domain/ai_review/update_reconciliation.ts
|
|
19084
|
+
/**
|
|
19085
|
+
* Folding an update's answer onto the analysis it brings up to date.
|
|
19086
|
+
*
|
|
19087
|
+
* One function for every client that updates a review, so the workspace and the extension cannot
|
|
19088
|
+
* come to read the same evidence differently: what a cited comment may settle, when a resolution is
|
|
19089
|
+
* marked for reassessment instead, which findings a changed comment reopens, what each status is
|
|
19090
|
+
* recorded against, and which threads a new finding may claim. A client differs only in how it
|
|
19091
|
+
* fetched the changes and ran the model.
|
|
19092
|
+
*/
|
|
18820
19093
|
function reconciledAgainstOf(basis) {
|
|
18821
19094
|
return basis.code ? basis.discussion ? "commits-and-conversation" : "commits" : "conversation";
|
|
18822
19095
|
}
|
|
@@ -18849,6 +19122,7 @@ function applyReconciliation(previous, parsed, context) {
|
|
|
18849
19122
|
schemaVersion: 1,
|
|
18850
19123
|
summary: parsed.summary || previous.summary,
|
|
18851
19124
|
...parsed.orientation || previous.orientation ? { orientation: parsed.orientation || previous.orientation } : {},
|
|
19125
|
+
...withBehaviourChange(mergeBehaviourChange(previous.behaviourChange, parsed.behaviourChange, context.codeChanged)),
|
|
18852
19126
|
...motivation ? { motivation } : {},
|
|
18853
19127
|
overallRisk: parsed.overallRisk ?? previous.overallRisk,
|
|
18854
19128
|
recommendation: parsed.recommendation || previous.recommendation,
|
|
@@ -22175,4 +22449,4 @@ var MCP_TOOL_NAMES = [
|
|
|
22175
22449
|
"ask_buddy"
|
|
22176
22450
|
];
|
|
22177
22451
|
//#endregion
|
|
22178
|
-
export {
|
|
22452
|
+
export { statusLabel as $, gradeScale as $a, workspacesRevision as $i, isArchitectureId as $n, setMembership as $o, describeSubject as $r, resolveWorkspacePort as $t, PR_FILTER_OPTIONS as A, doneVerb as Aa, indexKeptIds as Ai, telemetryUploadEnabled as An, readAgentPreference as Ao, EXPLAIN_SIMPLY_PROMPT as Ar, interruption as At, completedFold as B, explanationActionOf as Ba, matchingWorkspaceIds as Bi, ARCHITECTURE_DIR as Bn, runnableAgents as Bo, renderInlineText as Br, healthyPort as Bt, parsePullRequestLink as C, parseLifecycle as Ca, clearClaim as Ci, append as Cn, shorthandOf as Co, existingPaths as Cr, findingRef as Ct, INDEX_SECTIONS as D, queueRemove as Da, decideKissRecommendation as Di, deliver$1 as Dn, resolveModel as Do, storedConversation as Dr, reviewTagsIn as Dt, relativeTime as E, queueAddMany as Ea, CLAIM_LEASE_MS as Ei, stamp as En, resolveAgent as Eo, saveRefresh as Er, reviewTag as Et, collectionEmptyText as F, resolvedByConversation as Fa, lineageKey as Fi, mapRuntimes as Fn, agentFor as Fo, GITHUB_MARKDOWN as Fr, recordAskAccepted as Ft, isFoldKey as G, NO_STATUS as Ga, previousKissResult as Gi, repositoryKey as Gn, cleanName as Go, MANAGED_ROOT as Gr, stopChild as Gt, countLabel as H, isExplanationAction as Ha, outcomeInputsOf as Hi, loadArchitecture as Hn, AGENT_RUN_MARKER as Ho, ReviewBeingDeletedError as Hr, reviewsUrl as Ht, collectionFold as I, reviewerDispositions as Ia, lineageKeyFor as Ii, recordRuntimeBestEffort as In, agentIdentityOf as Io, renderMarkdown as Ir, readIndexToken as It, pinItemLabel as J, closesFinding as Ja, reviewedRepositories as Ji, trackedFiles as Jn, createWithMembers as Jo, isWorktreeHeld as Jr, writeServerRecord as Jt, markItemLabel as K, analysisRefOf as Ka, recentWorkspaces as Ki, storeArchitecture as Kn, collectionsStamp as Ko, createWorktree as Kr, stopServer as Kt, collectionHash as L, verdictClosure as La, lineageOutcome as Li, RUNTIME_WORDS as Ln, detectAgents as Lo, CODE_BLOCK_CLASS as Lr, bootstrapUrl as Lt, authorOptionLabel as M, isQuestionOutstanding as Ma, kissDecisionRefusal as Mi, PACKAGE_NAME as Mn, CONFIG_PATH as Mo, UNESTABLISHED_MOTIVATION as Mr, isTerminalAsk as Mt, authorOptions as N, issuesOutstanding as Na, kissDecisionsOf as Ni, feedbackUrl as Nn, AGENT_IDS as No, authorPreview as Nr, markAskRunning as Nt, INDEX_SECTION_NAMES as O, queueStamp as Oa, followedRefName as Oi, recordTelemetryUploadConsent as On, agentIdOf as Oo, isUnchanged as Or, endAskRequest as Ot, collectionCountLabel as P, questionsOutstanding as Pa, latestKissRun as Pi, waitingHistory as Pn, agentById as Po, hasAuthorContent as Pr, readAskRequest as Pt, selectAllLabel as Q, findingStatus as Qa, workspaceStamps as Qi, ancestorsOf as Qn, renameCollection as Qo, describeMovement as Qr, parseWorkspacePort as Qt, collectionPlacement as R, processDiscussion as Ra, lineagePosition as Ri, describeRuntimes as Rn, isAgentId as Ro, CODE_COPY_CLASS as Rr, clearServerRecordOwnedBy as Rt, extractPullRequestLinks as S, offersLifecycle as Sa, purposeOf as Si, startJob as Sn, shortNameOf as So, withUsageRecorded as Sr, findingAtRef as St, runBatch as T, queueAdd as Ta, isClaimed as Ti, record as Tn, refExists as To, prepareConversationWithin as Tr, refOf as Tt, homeSection as U, withExplanation as Ua, positionInLineage as Ui, partFiles as Un, AgentCancelledError as Uo, isBusy as Ur, serverEntryExists as Ut, completedLabel as V, explanationOf as Va, mutateWorkspace as Vi, checkArchitecture as Vn, versionFrom as Vo, modelHelpLines as Vr, readServerRecord as Vt, isCollectionId as W, ANALYSIS_ONLY as Wa, presentedKissRunOf as Wi, readArchitecture as Wn, AgentUnavailableError as Wo, withReviewLock as Wr, spawnServer as Wt, queueOptionLabel as X, findingAssessment as Xa, touchWorkspace as Xi, QUOTE_LIMITS as Xn, nameProblemText as Xo, removeWorktree as Xr, MAX_WORKSPACE_PORT as Xt, queueItemLabel as Y, currentGradeIn as Ya, summarise as Yi, ownersOf as Yn, deleteCollection as Yo, readMarker as Yr, DEFAULT_WORKSPACE_PORT as Yt, sectionOpen as Z, findingIn as Za, workspaceRevision as Zi, REPOSITORY_SCOPE as Zn, readCollections as Zo, requestJobStop as Zr, MIN_WORKSPACE_PORT as Zt, endRun as _, lifecycleChip as _a, PHASES as _i, observeReview as _n, DetachedHeadError as _o, removeNotification as _r, applyUpdate as _t, lineageIds as a, nextBaseline as aa, fetchHead as ai, cancelUpdate as an, statusLookup as ao, createArchitectureNotification as ar, retryableMiss as at, stopRun as b, lifecyclePillAction as ba, phasesFor as bi, reanalyseReview as bn, resolveBase as bo, unreadAround as br, agentDisplayName as bt, discardJob as c, outcomeStanding as ca, RUN_RECORD_RETENTION_MS as ci, parkedUpdateRefusal as cn, SEVERITIES as co, eventName as cr, activateQueued as ct, startKissJob as d, readOutcomes as da, endedAt as di, askCheckout as dn, objectWithAnyOf as do, markRead as dr, settleQueue as dt, analysedAt as ea, findExistingReview as ei, statedWorkspacePort as en, isGradeFor as eo, writeJsonAtomically as er, withWriteLock as es, statusPillLabel as et, isDriving as f, sameSha as fa, fail as fi, findingsChanged as fn, describeAuthorship as fo, markReadForReview as fr, RUNNER_KINDS as ft, completeRun as g, isLifecycle as ga, saveJob as gi, failureOf as gn, originRemote as go, readStateOf as gr, spawnRunner as gt, beginRun as h, activityLabel as ha, pruneJobResidue as hi, runningJobs as hn, resolveTarget as ho, readNotification as hr, runDetached as ht, deleteReview as i, lastBaseline as ia, reviewedShaOf as ii, RefreshUnavailableError as in, sourcePhrase as io, categoryOf as ir, openDestination as it, anythingRunning as j, isIssueOutstanding as ja, indexReviewGroups as ji, BUILD_VERSION as jn, writeAgentPreference as jo, chatConversationSection as jr, isRequestId as jt, LIST_SECTIONS as k, readQueue as ka, groupByLineage as ki, telemetryUploadConsent as kn, clearAgentPreference as ko, agentEnvOf as kr, forgetAskRequest as kt, kissAgentId as l, parseOutcomeSnapshot as la, allJobs as li, recheckConversation as ln, asString$1 as lo, listNotifications as lr, compactQueue as lt, RUN_KINDS as m, activityAttributes as ma, loadJob as mi, liveUpdateFor as mn, kissOutcome as mo, pruneNotifications as mr, cliEntry as mt, MCP_TOOL_NAMES as n, REVIEWER_OUTCOMES as na, checkReview as ni, COMMIT_REVIEW_CANNOT_UPDATE as nn, promptGrade as no, branchOf as nr, isDelivered as nt, liveJobsFor as o, outcomeDefinition as oa, forgeResolver as oi, cancellableHere as on, wasReassessed as oo, createPrState as or, lineageKeysFor as ot, track as p, LIFECYCLES as pa, isTerminal as pi, UpdateAlreadyRunningError as pn, WITHHELD_REASON as po, moveIds as pr, RUNNER_MARKER as pt, omittedText as q, assessmentLookup as qa, reviewedCommit as qi, storedScopes as qn, createCollection as qo, holdWorktree as qr, workspaceUrl as qt, deleteLineage as r, appendOutcome as ra, followedBranch as ri, FETCH_TIMEOUT_MS as rn, reassessIn as ro, subjectOf as rr, missedDelivery as rt, wasBlocked as s, outcomeLabel as sa, fillFileUrlTemplate as si, mergeUpdateInto as sn, followUpFindingId as so, createPrUpdate as sr, settleCollections as st, MCP_SERVER_INFO_NAME as t, analysisSnapshot as ta, checkCodeFreshness as ti, writePortPreference as tn, isOffered as to, announceJob as tr, STORE_ROOT as ts, deliver as tt, recordKissRun as u, parseOutcomes as ua, attemptIdOf as ui, updateReview as un, extractJsonText as uo, markAllRead as ur, queueForReview as ut, heldRuns as v, lifecycleItemLabel as va, isLiveJob as vi, prepareReview as vn, TargetError as vo, retireNotification as vr, modelProvenanceOf as vt, unsupportedReason as w, sectionOf as wa, driverGone as wi, readEvents as wn, git as wo, ASK_REREAD_CEILING_MS as wr, findingRefs as wt, batchIdentity as x, lifecyclePillLabel as xa, progressSteps as xi, runJob as xn, AmbiguousRefError as xo, unreadCount as xr, humanizeModelId as xt, reportRun as y, lifecycleName$1 as ya, isTerminalJobPhase as yi, settleReview as yn, isCommitReview as yo, toneOf as yr, provenanceDetailLines as yt, collectionsLine as z, recommendationsOf as za, loadWorkspace as zi, formatDuration as zn, parkedReason as zo, escapeHtml as zr, ensureServer as zt };
|