prreviewbuddy 0.92.0 → 0.93.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 +21 -0
- package/dist/main.js +2 -2
- package/dist/{mcp_tools-BKPpd9dN.js → mcp_tools-DbFR9Z90.js} +163 -19
- package/dist/server.js +171 -43
- package/package.json +1 -1
- package/static/{chunk-DMxtqzNj.js → chunk-Cg4cN8Vk.js} +1 -1
- package/static/reviews.js +1 -1
- package/static/runs.js +1 -1
- package/static/workspace.js +64 -64
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.93.0
|
|
4
|
+
|
|
5
|
+
**Re-check reconciles your findings with the PR discussion.** **Re-check in PR context** used to
|
|
6
|
+
fetch the latest comments and correct who raised what, and leave every issue and question as it
|
|
7
|
+
was until Update or a card's own Reassess ran. It now runs the same discussion pass as Update,
|
|
8
|
+
against the commit the review read: a comment that answers a question answers it, a comment that
|
|
9
|
+
settles an issue resolves it, and a concern a comment raises becomes a new issue once it is
|
|
10
|
+
confirmed in the reviewed code. A claim that something was fixed is never taken on trust, and a
|
|
11
|
+
thread resolved on the forge is not, by itself, a fix: either stays open for Update to check against
|
|
12
|
+
newer commits, which remain Update's job. Reassess on a single card is unchanged.
|
|
13
|
+
|
|
14
|
+
The steps show while it runs (fetching the discussion, preparing the reviewed code, reassessing
|
|
15
|
+
issues and questions), and Cancel stops it. The result says what happened: the findings that
|
|
16
|
+
changed, that no findings changed, or, when the comments were fetched but the reassessment failed,
|
|
17
|
+
that the discussion was refreshed and the findings were not, with **Try again**. When nothing in
|
|
18
|
+
the discussion is new since the findings were last assessed, no model is asked.
|
|
19
|
+
|
|
20
|
+
The discussion counts as analysed only once a Re-check or an Update has finished reassessing it,
|
|
21
|
+
and only as far as it read, so a comment that arrives during a Re-check is still new to the next
|
|
22
|
+
one. A Re-check never stands in for an Update, and the last update's outcome is left as it was.
|
|
23
|
+
|
|
3
24
|
## 0.92.0
|
|
4
25
|
|
|
5
26
|
**Older issues catch up on Update.** An issue from an earlier review that is still outstanding now
|
package/dist/main.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as readAskRequest,
|
|
2
|
+
import { $ as readAskRequest, Br as progressSteps, Dt as parkedUpdateRefusal, E as relativeTime, Ea as resolveTarget, F as spawnRunner, Fa as git, Ft as failureOf, G as reviewTag, Ga as AGENT_IDS, Gt as stamp, H as findingRef, Ha as writeAgentPreference, Hi as isIssueOutstanding, Hr as clearClaim, Ht as append, I as applyUpdate, Ir as PHASES, J as forgetAskRequest, Ja as agentIdentityOf, Ji as verdictClosure, Jt as telemetryUploadConsent, Ka as agentById, Kt as deliver, L as modelProvenanceOf, La as resolveAgent, Lt as prepareReview, Ma as AmbiguousRefError, Mr as isTerminal$1, Mt as UpdateAlreadyRunningError, Nr as loadJob, Nt as liveUpdateFor, Or as allJobs, P as runDetached, Pt as runningJobs, Qa as runnableAgents, Qi as explanationOf, Ra as resolveModel, Rt as settleReview, T as runBatch, Ta as kissOutcome, Tr as forgeResolver, Ua as CONFIG_PATH, Ui as isQuestionOutstanding, Ur as driverGone, Va as readAgentPreference, Vr as purposeOf, Vt as startJob, Wa as STORE_ROOT, Wr as isClaimed, Xa as isAgentId, Xt as BUILD_VERSION, Y as interruption, Ya as detectAgents, Yt as telemetryUploadEnabled, Z as isTerminalAsk, Za as parkedReason, Zt as PACKAGE_NAME, _r as describeMovement, _t as parseWorkspacePort, ai as positionInLineage, at as healthyPort, bt as writePortPreference, ci as recentWorkspaces, di as summarise, dt as stopServer, et as recordAskAccepted, ft as workspaceUrl, gt as MIN_WORKSPACE_PORT, hr as removeWorktree, ht as MAX_WORKSPACE_PORT, i as deleteReview$1, it as ensureServer, j as RUNNER_KINDS, k as queueForReview, ka as TargetError, kr as attemptIdOf, la as findingStatus, li as reviewedCommit, mr as readMarker, mt as DEFAULT_WORKSPACE_PORT, ni as loadWorkspace, nt as bootstrapUrl, o as liveJobsFor, or as modelHelpLines, ot as readServerRecord, pi as workspaceRevision, q as endAskRequest, qi as reviewerDispositions, qr as followedRefName, qt as recordTelemetryUploadConsent, ri as matchingWorkspaceIds, s as wasBlocked, sa as findingAssessment, st as reviewsUrl, t as MCP_SERVER_INFO_NAME, ti as lineagePosition, tt as readIndexToken, u as recordKissRun, ui as reviewedRepositories, ur as MANAGED_ROOT, vr as describeSubject, wa as WITHHELD_REASON, x as batchIdentity, xt as COMMIT_REVIEW_CANNOT_UPDATE, yr as findExistingReview, yt as statedWorkspacePort, za as agentIdOf, zt as reanalyseReview } from "./mcp_tools-DbFR9Z90.js";
|
|
3
3
|
import { basename, dirname, isAbsolute, 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";
|
|
@@ -1526,7 +1526,7 @@ async function requestUpdate(id, source, deps = defaultDeps) {
|
|
|
1526
1526
|
};
|
|
1527
1527
|
const latest = loadWorkspace(workspace.id)?.lastUpdate;
|
|
1528
1528
|
if (latest && latest.at !== before) {
|
|
1529
|
-
const finished = jobsOf(workspace.id).find((candidate) => purposeOf(candidate) === "update" && candidate.startedAt >= (before ?? 0));
|
|
1529
|
+
const finished = jobsOf(workspace.id).find((candidate) => purposeOf(candidate) === "update" && !candidate.scope && candidate.startedAt >= (before ?? 0));
|
|
1530
1530
|
return {
|
|
1531
1531
|
review: await getReview(workspace.id, deps),
|
|
1532
1532
|
job: finished ? toJobRecord(finished, false) : null,
|
|
@@ -7741,9 +7741,34 @@ var UPDATE_ORDER = [
|
|
|
7741
7741
|
"context",
|
|
7742
7742
|
"analysing"
|
|
7743
7743
|
];
|
|
7744
|
+
/**
|
|
7745
|
+
* The same phases, as a Re-check of the pull request discussion runs them. Nothing is fetched, so
|
|
7746
|
+
* there is no `preparing` step to show, and the checkout is of the commit the review read.
|
|
7747
|
+
*/
|
|
7748
|
+
var RECHECK_PHASES = {
|
|
7749
|
+
...UPDATE_PHASES,
|
|
7750
|
+
conversation: {
|
|
7751
|
+
doing: "Fetching the PR discussion",
|
|
7752
|
+
done: "Fetched the PR discussion"
|
|
7753
|
+
},
|
|
7754
|
+
context: {
|
|
7755
|
+
doing: "Preparing the reviewed code",
|
|
7756
|
+
done: "Prepared the reviewed code"
|
|
7757
|
+
},
|
|
7758
|
+
analysing: {
|
|
7759
|
+
doing: "Reassessing issues and questions",
|
|
7760
|
+
done: "Reassessed issues and questions"
|
|
7761
|
+
}
|
|
7762
|
+
};
|
|
7763
|
+
var RECHECK_ORDER = [
|
|
7764
|
+
"conversation",
|
|
7765
|
+
"context",
|
|
7766
|
+
"analysing"
|
|
7767
|
+
];
|
|
7744
7768
|
/** The names this job's phases go by. */
|
|
7745
7769
|
function phasesFor(job) {
|
|
7746
|
-
|
|
7770
|
+
if (purposeOf(job) !== "update") return PHASES;
|
|
7771
|
+
return job.scope === "conversation" ? RECHECK_PHASES : UPDATE_PHASES;
|
|
7747
7772
|
}
|
|
7748
7773
|
/**
|
|
7749
7774
|
* Whether a phase is part of *this* review, rather than part of the pipeline in general.
|
|
@@ -7783,7 +7808,7 @@ function progressSteps(job) {
|
|
|
7783
7808
|
const failedAt = job.phase === "failed" ? job.failure?.phase : void 0;
|
|
7784
7809
|
const update = purposeOf(job) === "update";
|
|
7785
7810
|
const names = phasesFor(job);
|
|
7786
|
-
const order = (update ? UPDATE_ORDER : WORK_PHASES).filter((phase) => appliesTo(job, phase));
|
|
7811
|
+
const order = (update ? job.scope === "conversation" ? RECHECK_ORDER : UPDATE_ORDER : WORK_PHASES).filter((phase) => appliesTo(job, phase));
|
|
7787
7812
|
return (update && job.phase === "done" ? order.filter((phase) => job.completed.includes(phase)) : order).map((phase) => {
|
|
7788
7813
|
const complete = job.completed.includes(phase) || !update && job.phase === "done";
|
|
7789
7814
|
const failed = failedAt === phase;
|
|
@@ -7876,6 +7901,7 @@ function strippedForDeletedReview(job) {
|
|
|
7876
7901
|
},
|
|
7877
7902
|
...job.purpose ? { purpose: job.purpose } : {},
|
|
7878
7903
|
...job.reanalysis ? { reanalysis: true } : {},
|
|
7904
|
+
...job.scope ? { scope: job.scope } : {},
|
|
7879
7905
|
...job.reviewType ? { reviewType: job.reviewType } : {},
|
|
7880
7906
|
phase: job.phase,
|
|
7881
7907
|
startedAt: job.startedAt,
|
|
@@ -18774,6 +18800,13 @@ function countUpdateChanges(previous, result) {
|
|
|
18774
18800
|
...reopened ? { reopened } : {}
|
|
18775
18801
|
};
|
|
18776
18802
|
}
|
|
18803
|
+
/**
|
|
18804
|
+
* Whether a reconciliation moved any finding or put anything to the reviewer. Still-open findings
|
|
18805
|
+
* are the ones it left alone, so they are the one count that is not a change.
|
|
18806
|
+
*/
|
|
18807
|
+
function findingsChanged(counts) {
|
|
18808
|
+
return counts.resolved + counts.affected + counts.newIssues + counts.questionsAnswered + (counts.reopened ?? 0) + (counts.gradeChanges ?? 0) + (counts.decisionsChallenged ?? 0) > 0;
|
|
18809
|
+
}
|
|
18777
18810
|
//#endregion
|
|
18778
18811
|
//#region ../../packages/review-harness/src/domain/ai_review/update_reconciliation.ts
|
|
18779
18812
|
function reconciledAgainstOf(basis) {
|
|
@@ -19099,8 +19132,93 @@ async function updateReview(workspace, runners = {}) {
|
|
|
19099
19132
|
if (workspace.changeSet.targetType === "commit") return refuse(reviewedSha, false, COMMIT_REVIEW_CANNOT_UPDATE);
|
|
19100
19133
|
const parked = parkedUpdateRefusal(workspace);
|
|
19101
19134
|
if (parked) return refuse(reviewedSha, false, parked);
|
|
19135
|
+
let fetchStartedAt = 0;
|
|
19136
|
+
return driveUpdateJob(workspace, runners, reviewedSha, {
|
|
19137
|
+
startedAt,
|
|
19138
|
+
now
|
|
19139
|
+
}, void 0, async (held, step, signal, clock) => {
|
|
19140
|
+
fetchStartedAt = Date.now();
|
|
19141
|
+
const outcome = await bringForward(workspace, runners, reviewedSha, held, step, signal, clock);
|
|
19142
|
+
if (!signal.aborted && outcome.ok && !outcome.fetchFailed && outcome.toSha) workspace.headSeenAt = fetchStartedAt;
|
|
19143
|
+
return outcome;
|
|
19144
|
+
});
|
|
19145
|
+
}
|
|
19146
|
+
/**
|
|
19147
|
+
* Reconcile the review's findings with its pull request discussion as it is now, at the commit the
|
|
19148
|
+
* review read: the Re-check button.
|
|
19149
|
+
*
|
|
19150
|
+
* The discussion half of an update and nothing else. The conversation is re-read exactly as an
|
|
19151
|
+
* update re-reads it, so every "already raised" line is corrected first; then, when something in it
|
|
19152
|
+
* is new to the analysis, the same reconciliation an update runs is asked of the same agent with no
|
|
19153
|
+
* code delta. It may answer a question, resolve or reopen an issue on the evidence the discussion
|
|
19154
|
+
* rules allow, suggest a grade, or raise a concern as a new issue once it has confirmed it in the
|
|
19155
|
+
* reviewed code. It never fetches and never moves the review to a newer commit: that is an update's,
|
|
19156
|
+
* and the review's commit stays where it was so the next update still sees those commits as new.
|
|
19157
|
+
*
|
|
19158
|
+
* Computes and mutates in memory, like `updateReview`; the route saves.
|
|
19159
|
+
*/
|
|
19160
|
+
async function recheckConversation(workspace, runners = {}) {
|
|
19161
|
+
const now = runners.now ?? Date.now;
|
|
19162
|
+
const startedAt = now();
|
|
19163
|
+
const reviewedSha = workspace.session.metadata?.commitSha || null;
|
|
19164
|
+
const recheck = (outcome) => ({
|
|
19165
|
+
...outcome,
|
|
19166
|
+
scope: "conversation"
|
|
19167
|
+
});
|
|
19168
|
+
if (!workspace.prContext) return recheck(refuse(reviewedSha, false, "This review has no pull request conversation attached, so there is nothing to re-read."));
|
|
19169
|
+
const cannotReassess = parkedUpdateRefusal(workspace) ?? (!workspace.session.result || !reviewedSha ? "This review has no analysis to reassess." : null);
|
|
19170
|
+
if (cannotReassess) {
|
|
19171
|
+
adoptLegacyBaseline(workspace);
|
|
19172
|
+
const conversationOk = await reReadConversation(workspace, runners.runRefresh);
|
|
19173
|
+
return recheck(settled(reviewedSha, reviewedSha, false, conversationOk, "refused", conversationOk ? cannotReassess : rereadFailureOf(workspace)));
|
|
19174
|
+
}
|
|
19175
|
+
return driveUpdateJob(workspace, runners, reviewedSha, {
|
|
19176
|
+
startedAt,
|
|
19177
|
+
now
|
|
19178
|
+
}, "conversation", async (held, step, signal, clock) => recheck(await reconcileConversation(workspace, runners, reviewedSha, held, step, signal, clock)));
|
|
19179
|
+
}
|
|
19180
|
+
/** What a failed re-read said, for an outcome that reports it. */
|
|
19181
|
+
function rereadFailureOf(workspace) {
|
|
19182
|
+
return workspace.lastPrRefresh && !workspace.lastPrRefresh.ok ? workspace.lastPrRefresh.message : "The pull request conversation could not be re-read. Nothing here has changed.";
|
|
19183
|
+
}
|
|
19184
|
+
/** Said when the conversation holds nothing the findings have not already been weighed against. */
|
|
19185
|
+
var NOTHING_NEW_IN_DISCUSSION = "Nothing in the PR discussion is new since the findings were last assessed, so no findings changed.";
|
|
19186
|
+
async function reconcileConversation(workspace, runners, reviewedSha, held, step, signal, clock) {
|
|
19187
|
+
adoptLegacyBaseline(workspace);
|
|
19188
|
+
step("conversation");
|
|
19189
|
+
const conversationOk = await reReadConversation(workspace, runners.runRefresh);
|
|
19190
|
+
signal.throwIfAborted();
|
|
19191
|
+
if (!conversationOk) return settled(reviewedSha, reviewedSha, false, false, "refused", rereadFailureOf(workspace));
|
|
19192
|
+
const { prepared } = await prepareConversation(workspace, {
|
|
19193
|
+
reread: false,
|
|
19194
|
+
...workspace.lastPrRefresh ? { rereadOutcome: workspace.lastPrRefresh } : {}
|
|
19195
|
+
});
|
|
19196
|
+
if (!conversationMoved(prepared)) return settled(reviewedSha, reviewedSha, false, true, "already-current", NOTHING_NEW_IN_DISCUSSION);
|
|
19197
|
+
if (!await commitPresent(workspace.repoPath, reviewedSha)) return settled(reviewedSha, reviewedSha, false, true, "baseline-gone", BASELINE_GONE_MESSAGE);
|
|
19198
|
+
step("context");
|
|
19199
|
+
let worktreePath;
|
|
19200
|
+
try {
|
|
19201
|
+
({path: worktreePath} = await pinCheckout(workspace, reviewedSha, held));
|
|
19202
|
+
} catch (error) {
|
|
19203
|
+
if (error instanceof ReviewBeingDeletedError) throw error;
|
|
19204
|
+
return settled(reviewedSha, reviewedSha, false, true, "analysis-failed", "A checkout of the reviewed commit could not be prepared, so the findings were not reassessed.");
|
|
19205
|
+
}
|
|
19206
|
+
signal.throwIfAborted();
|
|
19207
|
+
return reconcile(workspace, runners, reviewedSha, {
|
|
19208
|
+
sha: reviewedSha,
|
|
19209
|
+
fetchFailed: false
|
|
19210
|
+
}, true, worktreePath, step, held.job, signal, clock, prepared, true, "conversation");
|
|
19211
|
+
}
|
|
19212
|
+
/**
|
|
19213
|
+
* The life of an update's job, whatever the update does inside it: the claim, the cancel, the steps,
|
|
19214
|
+
* how it ends and what it announces. Shared by Update and Re-check so the two cannot disagree about
|
|
19215
|
+
* how a run is watched, cancelled or reported.
|
|
19216
|
+
*/
|
|
19217
|
+
async function driveUpdateJob(workspace, runners, reviewedSha, clock, scope, work) {
|
|
19218
|
+
const { startedAt, now } = clock;
|
|
19102
19219
|
const held = await claimCheckoutJob(workspace, reviewedSha ?? "", {
|
|
19103
19220
|
purpose: "update",
|
|
19221
|
+
...scope ? { scope } : {},
|
|
19104
19222
|
...runners.source ? { source: runners.source } : {},
|
|
19105
19223
|
...workspace.prContext ? { conversation: {
|
|
19106
19224
|
kind: "attached",
|
|
@@ -19114,16 +19232,11 @@ async function updateReview(workspace, runners = {}) {
|
|
|
19114
19232
|
const current = () => loadJob(held.job.id) ?? held.job;
|
|
19115
19233
|
const step = (phase) => saveJob(advance(current(), phase));
|
|
19116
19234
|
try {
|
|
19117
|
-
const
|
|
19118
|
-
|
|
19119
|
-
|
|
19120
|
-
now
|
|
19121
|
-
});
|
|
19122
|
-
if (signal.aborted) return cancelled(held, reviewedSha);
|
|
19123
|
-
if (outcome.ok && !outcome.fetchFailed && outcome.toSha) workspace.headSeenAt = fetchStartedAt;
|
|
19124
|
-
const ended = outcome.stop === "analysis-failed" ? fail(current(), outcome.message) : advance(current(), "done", outcome.message);
|
|
19235
|
+
const outcome = await work(held, step, signal, clock);
|
|
19236
|
+
if (signal.aborted) return scoped(cancelled(held, reviewedSha), scope);
|
|
19237
|
+
const ended = outcome.stop === "analysis-failed" || scope && outcome.conversationOk === false ? fail(current(), outcome.message) : advance(current(), "done", outcome.message);
|
|
19125
19238
|
saveJob(ended);
|
|
19126
|
-
if (outcome.ok && outcome.stop === null) {
|
|
19239
|
+
if (!scope && outcome.ok && outcome.stop === null) {
|
|
19127
19240
|
const completedAt = now();
|
|
19128
19241
|
recordRuntimeBestEffort({
|
|
19129
19242
|
operation: "update",
|
|
@@ -19139,7 +19252,7 @@ async function updateReview(workspace, runners = {}) {
|
|
|
19139
19252
|
announceJob(ended, updateFacts(outcome, workspace));
|
|
19140
19253
|
return outcome;
|
|
19141
19254
|
} catch (error) {
|
|
19142
|
-
if (signal.aborted) return cancelled(held, reviewedSha);
|
|
19255
|
+
if (signal.aborted) return scoped(cancelled(held, reviewedSha), scope);
|
|
19143
19256
|
const failed = fail(current(), error instanceof Error ? error.message : String(error));
|
|
19144
19257
|
saveJob(failed);
|
|
19145
19258
|
announceJob(failed);
|
|
@@ -19149,6 +19262,12 @@ async function updateReview(workspace, runners = {}) {
|
|
|
19149
19262
|
held.claim.release();
|
|
19150
19263
|
}
|
|
19151
19264
|
}
|
|
19265
|
+
function scoped(outcome, scope) {
|
|
19266
|
+
return scope ? {
|
|
19267
|
+
...outcome,
|
|
19268
|
+
scope
|
|
19269
|
+
} : outcome;
|
|
19270
|
+
}
|
|
19152
19271
|
/**
|
|
19153
19272
|
* The reviewer cancelled. Recorded as a stop, not a failure, so nothing announces it or offers a
|
|
19154
19273
|
* retry, and answered as an outcome the page reports on the review it left untouched.
|
|
@@ -19192,7 +19311,7 @@ async function bringForward(workspace, runners, reviewedSha, held, step, signal,
|
|
|
19192
19311
|
signal.throwIfAborted();
|
|
19193
19312
|
return reconcile(workspace, runners, reviewedSha, remote, conversationOk, worktreePath, step, held.job, signal, clock, prepared, discussionMoved);
|
|
19194
19313
|
}
|
|
19195
|
-
async function reconcile(workspace, runners, reviewedSha, remote, conversationOk, worktreePath, step, job, signal, clock, prepared, discussionMoved) {
|
|
19314
|
+
async function reconcile(workspace, runners, reviewedSha, remote, conversationOk, worktreePath, step, job, signal, clock, prepared, discussionMoved, scope) {
|
|
19196
19315
|
const { id: jobId, env } = job;
|
|
19197
19316
|
const newHead = remote.sha;
|
|
19198
19317
|
let delta = null;
|
|
@@ -19227,7 +19346,7 @@ async function reconcile(workspace, runners, reviewedSha, remote, conversationOk
|
|
|
19227
19346
|
const requestedModel = resolveModel({ review: { session: workspace.session } }) ?? void 0;
|
|
19228
19347
|
let raw;
|
|
19229
19348
|
try {
|
|
19230
|
-
const prompt = buildUpdatePrompt(workspace, delta, prepared, reviewedSha, newHead, worktreePath);
|
|
19349
|
+
const prompt = buildUpdatePrompt(workspace, delta, prepared, reviewedSha, newHead, worktreePath, scope);
|
|
19231
19350
|
raw = runners.run ? await runners.run(prompt, worktreePath, env, onProgress, onObservedModel, signal) : await runUpdate(workspace.id, prompt, worktreePath, workspace.repoPath, env, onProgress, requestedModel, onObservedModel, signal);
|
|
19232
19351
|
} catch (error) {
|
|
19233
19352
|
return settled(reviewedSha, newHead, remote.fetchFailed, conversationOk, "analysis-failed", explainUpdateFailure(error, env, requestedModel));
|
|
@@ -19444,11 +19563,36 @@ function mergeUpdateInto(fresh, updated) {
|
|
|
19444
19563
|
for (const field of UPDATE_OWNED_FIELDS) if (field in updated) target[field] = source[field];
|
|
19445
19564
|
else delete target[field];
|
|
19446
19565
|
merged.session = keepReviewerFields(fresh, updated.session);
|
|
19566
|
+
keepNewerConversation(merged, fresh, updated);
|
|
19447
19567
|
carryUpdateSuggestions(merged, updated);
|
|
19448
19568
|
dropStaleChangeMap(merged);
|
|
19449
19569
|
return merged;
|
|
19450
19570
|
}
|
|
19451
19571
|
/**
|
|
19572
|
+
* A conversation re-read that landed on disk while this ran, kept rather than put back.
|
|
19573
|
+
*
|
|
19574
|
+
* An Ask turn re-reads the conversation and saves it, and an update holds its copy for minutes. Laid
|
|
19575
|
+
* over whole, the update's older copy replaced the newer one and the "already raised" lines went
|
|
19576
|
+
* back with it. The newer copy stays, and the attributions are derived again from it: arithmetic,
|
|
19577
|
+
* the same pass the re-read itself runs. `analysedConversation` is untouched either way: it is the
|
|
19578
|
+
* snapshot this run actually reconciled against, so whatever arrived since is still new to the next.
|
|
19579
|
+
*/
|
|
19580
|
+
function keepNewerConversation(merged, fresh, updated) {
|
|
19581
|
+
const theirs = fresh.prContext ? orderOf(fresh.prContext.discussion) : void 0;
|
|
19582
|
+
const ours = updated.prContext ? orderOf(updated.prContext.discussion) : void 0;
|
|
19583
|
+
if (theirs === void 0 || ours === void 0 || theirs <= ours || !fresh.prContext) return;
|
|
19584
|
+
merged.prContext = fresh.prContext;
|
|
19585
|
+
if (fresh.lastPrRefresh) merged.lastPrRefresh = fresh.lastPrRefresh;
|
|
19586
|
+
const result = merged.session.result;
|
|
19587
|
+
if (result) {
|
|
19588
|
+
const { result: attributed } = attributeIssuesToDiscussion(result, processDiscussion(fresh.prContext.discussion));
|
|
19589
|
+
merged.session = {
|
|
19590
|
+
...merged.session,
|
|
19591
|
+
result: attributed
|
|
19592
|
+
};
|
|
19593
|
+
}
|
|
19594
|
+
}
|
|
19595
|
+
/**
|
|
19452
19596
|
* The grade changes this update suggested, onto the review as it is on disk.
|
|
19453
19597
|
*
|
|
19454
19598
|
* The ledger is the reviewer's and comes from the fresh read, so the update's proposals, written on
|
|
@@ -19725,20 +19869,20 @@ function stillPresent(counts) {
|
|
|
19725
19869
|
* Everything after it is the shared builder, so the two clients cannot drift into asking for
|
|
19726
19870
|
* different shapes.
|
|
19727
19871
|
*/
|
|
19728
|
-
function buildUpdatePrompt(workspace, delta, conversation, reviewedSha, newHead, worktreePath) {
|
|
19872
|
+
function buildUpdatePrompt(workspace, delta, conversation, reviewedSha, newHead, worktreePath, scope) {
|
|
19729
19873
|
const previous = workspace.session.result;
|
|
19730
19874
|
const discussionChanged = conversationMoved(conversation);
|
|
19731
19875
|
const conversationBlock = updateConversationBlock(conversation);
|
|
19732
|
-
const opening = delta ? `An earlier review of this branch is being brought up to date with the commits pushed since it was written${discussionChanged ? ", and with what has changed in its pull request conversation since" : ""}.` : "An earlier review of this branch is being brought up to date with what has changed in its pull request conversation since it was written. No commits have been pushed since.";
|
|
19876
|
+
const opening = delta ? `An earlier review of this branch is being brought up to date with the commits pushed since it was written${discussionChanged ? ", and with what has changed in its pull request conversation since" : ""}.` : scope === "conversation" ? "An earlier review of this branch is being reconciled with what has changed in its pull request conversation since it was written. Only the conversation is reassessed in this pass, against the commit the review read. Newer commits on the branch, if any, are not part of it: a comment saying a fix landed in one cannot be confirmed from this checkout, so that finding stays open for a later update to check against the code." : "An earlier review of this branch is being brought up to date with what has changed in its pull request conversation since it was written. No commits have been pushed since.";
|
|
19733
19877
|
const code = delta ? `The change below is what happened between ${reviewedSha} and ${newHead}. It is not the whole branch: the earlier review already covered everything up to ${reviewedSha}.
|
|
19734
19878
|
|
|
19735
19879
|
${renderChangeInventory(delta.changeSet.data.files, inlinePathsOf(delta))}
|
|
19736
19880
|
|
|
19737
|
-
${delta.diff}` : `The code is unchanged since the earlier review: ${newHead} is the commit it read.`;
|
|
19881
|
+
${delta.diff}` : scope === "conversation" ? `There is no code delta in this pass: ${newHead} is the commit the earlier review read.` : `The code is unchanged since the earlier review: ${newHead} is the commit it read.`;
|
|
19738
19882
|
const commits = delta ? (delta.changeSet.authors ?? []).reduce((total, author) => total + author.commits, 0) : 0;
|
|
19739
19883
|
return `${opening}
|
|
19740
19884
|
|
|
19741
|
-
The working tree at ${worktreePath} is checked out at ${newHead}, which is the code as it now stands. You may read any file in it, and you should: the point of doing this here rather than from a diff alone is that you can open the code and see whether a fix actually holds. Read only. Change nothing, commit nothing, and run no command that writes.
|
|
19885
|
+
The working tree at ${worktreePath} is checked out at ${newHead}, which is ${scope === "conversation" ? "the code the review read" : "the code as it now stands"}. You may read any file in it, and you should: the point of doing this here rather than from a diff alone is that you can open the code and see whether a fix actually holds. Read only. Change nothing, commit nothing, and run no command that writes.
|
|
19742
19886
|
|
|
19743
19887
|
${code}
|
|
19744
19888
|
|
|
@@ -21472,4 +21616,4 @@ var MCP_TOOL_NAMES = [
|
|
|
21472
21616
|
"ask_buddy"
|
|
21473
21617
|
];
|
|
21474
21618
|
//#endregion
|
|
21475
|
-
export { readAskRequest as $,
|
|
21619
|
+
export { readAskRequest as $, versionFrom as $a, isExplanationAction as $i, hasAuthorContent as $n, latestKissRun as $r, waitingHistory as $t, settleQueue as A, isCommitReview as Aa, deleteCollection as Ai, markRead as An, endedAt as Ar, askCheckout as At, humanizeModelId as B, clearAgentPreference as Ba, readQueue as Bi, unreadCount as Bn, progressSteps as Br, runJob as Bt, parsePullRequestLink as C, describeAuthorship as Ca, lifecyclePillLabel as Ci, categoryOf as Cn, reviewedShaOf as Cr, RefreshUnavailableError as Ct, activateQueued as D, originRemote as Da, collectionsStamp as Di, eventName as Dn, RUN_RECORD_RETENTION_MS as Dr, parkedUpdateRefusal as Dt, relativeTime as E, resolveTarget as Ea, sectionOf as Ei, createPrUpdate as En, fillFileUrlTemplate as Er, mergeUpdateInto as Et, spawnRunner as F, git as Fa, updateCollections as Fi, readStateOf as Fn, saveJob as Fr, failureOf as Ft, reviewTag as G, AGENT_IDS as Ga, questionsOutstanding as Gi, saveRefresh as Gn, CLAIM_LEASE_MS as Gr, stamp as Gt, findingRef as H, writeAgentPreference as Ha, isIssueOutstanding as Hi, existingPaths as Hn, clearClaim as Hr, append as Ht, applyUpdate as I, refExists as Ia, queueAdd as Ii, removeNotification as In, PHASES as Ir, observeReview as It, forgetAskRequest as J, agentIdentityOf as Ja, verdictClosure as Ji, agentEnvOf as Jn, groupByLineage as Jr, telemetryUploadConsent as Jt, reviewTagsIn as K, agentById as Ka, resolvedByConversation as Ki, storedConversation as Kn, decideKissRecommendation as Kr, deliver as Kt, modelProvenanceOf as L, resolveAgent as La, queueAddMany as Li, retireNotification as Ln, isLiveJob as Lr, prepareReview as Lt, RUNNER_MARKER as M, AmbiguousRefError as Ma, readCollections as Mi, moveIds as Mn, isTerminal as Mr, UpdateAlreadyRunningError as Mt, cliEntry as N, shortNameOf as Na, renameCollection as Ni, pruneNotifications as Nn, loadJob as Nr, liveUpdateFor as Nt, compactQueue as O, DetachedHeadError as Oa, createCollection as Oi, listNotifications as On, allJobs as Or, recheckConversation as Ot, runDetached as P, shorthandOf as Pa, setMembership as Pi, readNotification as Pn, pruneJobResidue as Pr, runningJobs as Pt, markAskRunning as Q, runnableAgents as Qa, explanationOf as Qi, authorPreview as Qn, kissDecisionsOf as Qr, feedbackUrl as Qt, provenanceDetailLines as R, resolveModel as Ra, queueRemove as Ri, toneOf as Rn, isTerminalJobPhase as Rr, settleReview as Rt, extractPullRequestLinks as S, objectWithAnyOf as Sa, lifecyclePillAction as Si, subjectOf as Sn, followedBranch as Sr, FETCH_TIMEOUT_MS as St, runBatch as T, kissOutcome as Ta, parseLifecycle as Ti, createPrState as Tn, forgeResolver as Tr, cancellableHere as Tt, findingRefs as U, CONFIG_PATH as Ua, isQuestionOutstanding as Ui, ASK_REREAD_CEILING_MS as Un, driverGone as Ur, readEvents as Ut, findingAtRef as V, readAgentPreference as Va, doneVerb as Vi, withUsageRecorded as Vn, purposeOf as Vr, startJob as Vt, refOf as W, STORE_ROOT as Wa, issuesOutstanding as Wi, prepareConversationWithin as Wn, isClaimed as Wr, record as Wt, isRequestId as X, isAgentId as Xa, recommendationsOf as Xi, chatConversationSection as Xn, indexReviewGroups as Xr, BUILD_VERSION as Xt, interruption as Y, detectAgents as Ya, processDiscussion as Yi, EXPLAIN_SIMPLY_PROMPT as Yn, indexKeptIds as Yr, telemetryUploadEnabled as Yt, isTerminalAsk as Z, parkedReason as Za, explanationActionOf as Zi, UNESTABLISHED_MOTIVATION as Zn, kissDecisionRefusal as Zr, PACKAGE_NAME as Zt, endRun as _, wasReassessed as _a, activityLabel as _i, ancestorsOf as _n, describeMovement as _r, parseWorkspacePort as _t, lineageIds as a, closesFinding as aa, positionInLineage as ai, ARCHITECTURE_DIR as an, renderInlineText as ar, healthyPort as at, stopRun as b, asString$1 as ba, lifecycleItemLabel as bi, announceJob as bn, checkCodeFreshness as br, writePortPreference as bt, discardJob as c, findingIn as ca, recentWorkspaces as ci, partFiles as cn, isBusy as cr, serverEntryExists as ct, startKissJob as d, isGradeFor as da, summarise as di, storeArchitecture as dn, createWorktree as dr, stopServer as dt, withExplanation as ea, lineageKey as ei, mapRuntimes as en, AGENT_RUN_MARKER as eo, GITHUB_MARKDOWN as er, recordAskAccepted as et, isDriving as f, isOffered as fa, touchWorkspace as fi, storedScopes as fn, holdWorktree as fr, workspaceUrl as ft, completeRun as g, statusLookup as ga, activityAttributes as gi, REPOSITORY_SCOPE as gn, requestJobStop as gr, MIN_WORKSPACE_PORT as gt, beginRun as h, sourcePhrase as ha, LIFECYCLES as hi, QUOTE_LIMITS as hn, removeWorktree as hr, MAX_WORKSPACE_PORT as ht, deleteReview as i, assessmentLookup as ia, mutateWorkspace as ii, formatDuration as in, escapeHtml as ir, ensureServer as it, RUNNER_KINDS as j, resolveBase as ja, nameProblemText as ji, markReadForReview as jn, fail as jr, findingsChanged as jt, queueForReview as k, TargetError as ka, createWithMembers as ki, markAllRead as kn, attemptIdOf as kr, updateReview as kt, kissAgentId as l, findingStatus as la, reviewedCommit as li, readArchitecture as ln, withReviewLock as lr, spawnServer as lt, RUN_KINDS as m, reassessIn as ma, workspaceStamps as mi, ownersOf as mn, readMarker as mr, DEFAULT_WORKSPACE_PORT as mt, MCP_TOOL_NAMES as n, NO_STATUS as na, loadWorkspace as ni, RUNTIME_WORDS as nn, AgentUnavailableError as no, CODE_BLOCK_CLASS as nr, bootstrapUrl as nt, liveJobsFor as o, currentGradeIn as oa, presentedKissRunOf as oi, checkArchitecture as on, modelHelpLines as or, readServerRecord as ot, track as p, promptGrade as pa, workspaceRevision as pi, trackedFiles as pn, isWorktreeHeld as pr, writeServerRecord as pt, endAskRequest as q, agentFor as qa, reviewerDispositions as qi, isUnchanged as qn, followedRefName as qr, recordTelemetryUploadConsent as qt, deleteLineage as r, analysisRefOf as ra, matchingWorkspaceIds as ri, describeRuntimes as rn, CODE_COPY_CLASS as rr, clearServerRecordOwnedBy as rt, wasBlocked as s, findingAssessment as sa, previousKissResult as si, loadArchitecture as sn, ReviewBeingDeletedError as sr, reviewsUrl as st, MCP_SERVER_INFO_NAME as t, ANALYSIS_ONLY as ta, lineagePosition as ti, recordRuntimeBestEffort as tn, AgentCancelledError as to, renderMarkdown as tr, readIndexToken as tt, recordKissRun as u, gradeScale as ua, reviewedRepositories as ui, repositoryKey as un, MANAGED_ROOT as ur, stopChild as ut, heldRuns as v, followUpFindingId as va, isLifecycle as vi, isArchitectureId as vn, describeSubject as vr, resolveWorkspacePort as vt, unsupportedReason as w, WITHHELD_REASON as wa, offersLifecycle as wi, createArchitectureNotification as wn, fetchHead as wr, cancelUpdate as wt, batchIdentity as x, extractJsonText as xa, lifecycleName as xi, branchOf as xn, checkReview as xr, COMMIT_REVIEW_CANNOT_UPDATE as xt, reportRun as y, SEVERITIES as ya, lifecycleChip as yi, writeJsonAtomically as yn, findExistingReview as yr, statedWorkspacePort as yt, agentDisplayName as z, agentIdOf as za, queueStamp as zi, unreadAround as zn, phasesFor as zr, reanalyseReview as zt };
|