prreviewbuddy 0.79.0 → 0.80.3
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 +79 -0
- package/dist/{delete_review-DwF1NMJ4.js → delete_review-CYiIfV5A.js} +327 -35
- package/dist/main.js +17 -12
- package/dist/server.js +917 -133
- package/package.json +1 -1
- package/static/chunk-C3E91izb.js +1 -0
- package/static/chunk-C8d9FvLk.js +1 -0
- package/static/chunk-DnOyRP8m.js +1 -0
- package/static/chunk-Dv0Wowan.js +1 -0
- package/static/chunk-h55PfL_M.js +1 -0
- package/static/help.js +1 -1
- package/static/notifications.js +1 -1
- package/static/reviews.js +1 -1
- package/static/runs.js +1 -0
- package/static/settings.js +1 -1
- package/static/shell.css +77 -6
- package/static/workspace.js +80 -80
- package/static/chunk-B6LyLjZ7.js +0 -1
- package/static/chunk-DYrelqtW.js +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { basename, delimiter, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
2
2
|
import { execFile, execFileSync, spawn } from "node:child_process";
|
|
3
|
-
import { accessSync, appendFileSync, closeSync, constants, existsSync, linkSync, mkdirSync, mkdtempSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
|
|
3
|
+
import { accessSync, appendFileSync, closeSync, constants, existsSync, linkSync, lstatSync, mkdirSync, mkdtempSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
|
|
4
4
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
5
5
|
import { homedir, hostname, tmpdir } from "node:os";
|
|
6
6
|
import { promisify } from "node:util";
|
|
@@ -3910,7 +3910,7 @@ function* jsonCandidates(text) {
|
|
|
3910
3910
|
for (const match of text.matchAll(/```(?:json)?\s*([\s\S]*?)```/gi)) {
|
|
3911
3911
|
const inner = match[1].trim();
|
|
3912
3912
|
if (!inner.startsWith("{") && !inner.startsWith("[")) continue;
|
|
3913
|
-
const value = parsed(inner);
|
|
3913
|
+
const value = parsed$1(inner);
|
|
3914
3914
|
if (value.ok) yield {
|
|
3915
3915
|
text: inner,
|
|
3916
3916
|
value: value.value
|
|
@@ -3922,7 +3922,7 @@ function* jsonCandidates(text) {
|
|
|
3922
3922
|
const end = closingIndex(text, start, opener);
|
|
3923
3923
|
if (end === -1) continue;
|
|
3924
3924
|
const candidate = text.slice(start, end + 1);
|
|
3925
|
-
const value = parsed(candidate);
|
|
3925
|
+
const value = parsed$1(candidate);
|
|
3926
3926
|
if (!value.ok) continue;
|
|
3927
3927
|
yield {
|
|
3928
3928
|
text: candidate,
|
|
@@ -3931,7 +3931,7 @@ function* jsonCandidates(text) {
|
|
|
3931
3931
|
start = end;
|
|
3932
3932
|
}
|
|
3933
3933
|
}
|
|
3934
|
-
function parsed(candidate) {
|
|
3934
|
+
function parsed$1(candidate) {
|
|
3935
3935
|
try {
|
|
3936
3936
|
return {
|
|
3937
3937
|
ok: true,
|
|
@@ -6217,6 +6217,11 @@ function summarise(workspace) {
|
|
|
6217
6217
|
questions: questions.length,
|
|
6218
6218
|
unansweredQuestions: questionsOutstanding(questions, answered).open,
|
|
6219
6219
|
messages: workspace.transcript.length,
|
|
6220
|
+
...workspace.jobId && result ? { analysisJobId: workspace.jobId } : {},
|
|
6221
|
+
...(() => {
|
|
6222
|
+
const kiss = presentedKissRunOf(workspace);
|
|
6223
|
+
return kiss ? { presentedKissJobId: kiss.jobId } : {};
|
|
6224
|
+
})(),
|
|
6220
6225
|
lastViewedAt: workspace.lastViewedAt,
|
|
6221
6226
|
completedAt: workspace.completedAt,
|
|
6222
6227
|
pinned: workspace.pinned === true,
|
|
@@ -6477,6 +6482,17 @@ function workspaceIdFrom(entry) {
|
|
|
6477
6482
|
* the other's file by accident.
|
|
6478
6483
|
*/
|
|
6479
6484
|
var CLAIMS_DIR = join(STORE_ROOT, "claims");
|
|
6485
|
+
/**
|
|
6486
|
+
* How long a claim stands without being renewed.
|
|
6487
|
+
*
|
|
6488
|
+
* Deliberately short, and it can be short because renewal is on a timer rather than tied to the
|
|
6489
|
+
* work. The job record's own `updatedAt` moves only when a phase changes or the agent streams a
|
|
6490
|
+
* line, which is why the sweep has to allow it thirty minutes of silence; a heartbeat keeps ticking
|
|
6491
|
+
* through a twenty minute analysis that says nothing at all. Three minutes leaves room for several
|
|
6492
|
+
* missed renewals on an event loop busy parsing a large diff, and still frees a crashed holder long
|
|
6493
|
+
* before anyone would think to ask why Retry does nothing.
|
|
6494
|
+
*/
|
|
6495
|
+
var CLAIM_LEASE_MS = 18e4;
|
|
6480
6496
|
/** Comfortably inside the lease, so one slow tick is never enough to lose a claim that is held. */
|
|
6481
6497
|
var CLAIM_RENEW_MS = 3e4;
|
|
6482
6498
|
function claimPath(key) {
|
|
@@ -6882,6 +6898,128 @@ var JOBS_DIR = join(STORE_ROOT, "jobs");
|
|
|
6882
6898
|
function reusesImportedConversation(job) {
|
|
6883
6899
|
return job.reviewType === "kiss";
|
|
6884
6900
|
}
|
|
6901
|
+
/**
|
|
6902
|
+
* What survives of a finished run when the reviewer deletes its review.
|
|
6903
|
+
*
|
|
6904
|
+
* Runs is a history of executions, not of reviews, so "the review you deleted was analysed twice
|
|
6905
|
+
* yesterday and the first attempt failed" stays true after the deletion. What the reviewer deleted
|
|
6906
|
+
* must not: everything a run produced or was given goes, and so does every sentence that might
|
|
6907
|
+
* quote it. Kept are identity and times, the outcome as a kind rather than a message, which client
|
|
6908
|
+
* asked and which agent ran, and the change's own name (repository, branch, pull request), which
|
|
6909
|
+
* is what makes the entry recognisable at all.
|
|
6910
|
+
*
|
|
6911
|
+
* An allow-list, built field by field, so a field added to the job later is dropped here until
|
|
6912
|
+
* somebody decides it should not be.
|
|
6913
|
+
*/
|
|
6914
|
+
function strippedForDeletedReview(job) {
|
|
6915
|
+
const request = job.target.pullRequest;
|
|
6916
|
+
const attemptFailure = (failure) => failure ? { failure: {
|
|
6917
|
+
message: "",
|
|
6918
|
+
...failure.kind ? { kind: failure.kind } : {},
|
|
6919
|
+
...failure.stopped ? { stopped: true } : {}
|
|
6920
|
+
} } : {};
|
|
6921
|
+
return {
|
|
6922
|
+
id: job.id,
|
|
6923
|
+
workspaceId: job.workspaceId,
|
|
6924
|
+
target: {
|
|
6925
|
+
originRepoPath: job.target.originRepoPath,
|
|
6926
|
+
branch: job.target.branch,
|
|
6927
|
+
sha: job.target.sha,
|
|
6928
|
+
...request ? { pullRequest: {
|
|
6929
|
+
reference: request.url ?? "",
|
|
6930
|
+
headRef: request.headRef,
|
|
6931
|
+
headSha: request.headSha,
|
|
6932
|
+
...request.number !== void 0 ? { number: request.number } : {},
|
|
6933
|
+
...request.url ? { url: request.url } : {},
|
|
6934
|
+
...request.source ? { source: request.source } : {}
|
|
6935
|
+
} } : {}
|
|
6936
|
+
},
|
|
6937
|
+
...job.purpose ? { purpose: job.purpose } : {},
|
|
6938
|
+
...job.reanalysis ? { reanalysis: true } : {},
|
|
6939
|
+
...job.reviewType ? { reviewType: job.reviewType } : {},
|
|
6940
|
+
phase: job.phase,
|
|
6941
|
+
startedAt: job.startedAt,
|
|
6942
|
+
updatedAt: job.updatedAt,
|
|
6943
|
+
...job.finishedAt !== void 0 ? { finishedAt: job.finishedAt } : {},
|
|
6944
|
+
completed: [],
|
|
6945
|
+
...job.failure ? { failure: {
|
|
6946
|
+
phase: job.failure.phase,
|
|
6947
|
+
message: "",
|
|
6948
|
+
...job.failure.kind ? { kind: job.failure.kind } : {},
|
|
6949
|
+
...job.failure.stopped ? { stopped: true } : {}
|
|
6950
|
+
} } : {},
|
|
6951
|
+
env: job.env.agentId ? { agentId: job.env.agentId } : {},
|
|
6952
|
+
attemptId: attemptIdOf(job),
|
|
6953
|
+
...job.source ? { source: job.source } : {},
|
|
6954
|
+
...job.previousAttempts ? { previousAttempts: job.previousAttempts.map((attempt) => ({
|
|
6955
|
+
attemptId: attempt.attemptId,
|
|
6956
|
+
startedAt: attempt.startedAt,
|
|
6957
|
+
finishedAt: attempt.finishedAt,
|
|
6958
|
+
phase: attempt.phase,
|
|
6959
|
+
...attemptFailure(attempt.failure),
|
|
6960
|
+
...attempt.source ? { source: attempt.source } : {},
|
|
6961
|
+
...attempt.agentId ? { agentId: attempt.agentId } : {}
|
|
6962
|
+
})) } : {},
|
|
6963
|
+
...job.removedFromRuns ? { removedFromRuns: job.removedFromRuns } : {},
|
|
6964
|
+
reviewDeleted: true
|
|
6965
|
+
};
|
|
6966
|
+
}
|
|
6967
|
+
/**
|
|
6968
|
+
* How long a finished run is listed, and kept: measured from when it ended, per attempt.
|
|
6969
|
+
*
|
|
6970
|
+
* A strict limit on what the page shows, not only on what the sweep deletes. The sweep runs inside
|
|
6971
|
+
* the workspace server, so while the server is stopped nothing is deleted, and a record can outlive
|
|
6972
|
+
* its week on disk until the next start; the page never shows it past the week regardless.
|
|
6973
|
+
*/
|
|
6974
|
+
var RUN_RECORD_RETENTION_MS = 6048e5;
|
|
6975
|
+
/** The current attempt's id. See `ReviewJob.attemptId`. */
|
|
6976
|
+
function attemptIdOf(job) {
|
|
6977
|
+
return job.attemptId ?? job.id;
|
|
6978
|
+
}
|
|
6979
|
+
/**
|
|
6980
|
+
* The record a driver should save as it picks this job up, before it does any work.
|
|
6981
|
+
*
|
|
6982
|
+
* A job that had ended is starting a new attempt: the ended one is archived, a new attempt id is
|
|
6983
|
+
* minted and the record leaves its terminal phase, all in the one value returned, so the caller
|
|
6984
|
+
* makes a single write. That is what makes the archive happen exactly once. A crash after the write
|
|
6985
|
+
* leaves a working job nobody drives, which the sweep in time records as stopped, and never a
|
|
6986
|
+
* terminal one that the next pickup would archive a second time; the id check covers a record that
|
|
6987
|
+
* was archived and then, somehow, written back terminal.
|
|
6988
|
+
*
|
|
6989
|
+
* A job that had not ended is the same attempt resuming (a restarted daemon, a driver whose claim
|
|
6990
|
+
* lapsed): only `startedAt` moves, because the page times "Running for" from it.
|
|
6991
|
+
*/
|
|
6992
|
+
function beginAttempt(job, next) {
|
|
6993
|
+
if (!isTerminal(job)) return {
|
|
6994
|
+
...job,
|
|
6995
|
+
startedAt: next.startedAt
|
|
6996
|
+
};
|
|
6997
|
+
const ended = attemptIdOf(job);
|
|
6998
|
+
const earlier = job.previousAttempts ?? [];
|
|
6999
|
+
const current = earlier.filter((attempt) => next.startedAt - attempt.finishedAt < RUN_RECORD_RETENTION_MS);
|
|
7000
|
+
const archived = earlier.some((attempt) => attempt.attemptId === ended) ? current : [...current, {
|
|
7001
|
+
attemptId: ended,
|
|
7002
|
+
startedAt: job.startedAt,
|
|
7003
|
+
finishedAt: endedAt(job),
|
|
7004
|
+
phase: job.phase,
|
|
7005
|
+
...job.failure ? { failure: {
|
|
7006
|
+
message: job.failure.message,
|
|
7007
|
+
...job.failure.kind ? { kind: job.failure.kind } : {},
|
|
7008
|
+
...job.failure.stopped ? { stopped: true } : {}
|
|
7009
|
+
} } : {},
|
|
7010
|
+
...job.source ? { source: job.source } : {},
|
|
7011
|
+
...job.env.agentId ? { agentId: job.env.agentId } : {}
|
|
7012
|
+
}];
|
|
7013
|
+
const { failure: _failure, finishedAt: _finishedAt, progress: _progress, ...rest } = job;
|
|
7014
|
+
return {
|
|
7015
|
+
...rest,
|
|
7016
|
+
phase: next.phase,
|
|
7017
|
+
startedAt: next.startedAt,
|
|
7018
|
+
attemptId: randomUUID(),
|
|
7019
|
+
previousAttempts: archived,
|
|
7020
|
+
...next.source ? { source: next.source } : {}
|
|
7021
|
+
};
|
|
7022
|
+
}
|
|
6885
7023
|
function jobPath(id) {
|
|
6886
7024
|
return join(JOBS_DIR, `${id}.json`);
|
|
6887
7025
|
}
|
|
@@ -6889,6 +7027,7 @@ function createJob(input) {
|
|
|
6889
7027
|
const now = Date.now();
|
|
6890
7028
|
return {
|
|
6891
7029
|
id: randomUUID(),
|
|
7030
|
+
attemptId: randomUUID(),
|
|
6892
7031
|
phase: "preparing",
|
|
6893
7032
|
startedAt: now,
|
|
6894
7033
|
updatedAt: now,
|
|
@@ -6896,9 +7035,30 @@ function createJob(input) {
|
|
|
6896
7035
|
...input
|
|
6897
7036
|
};
|
|
6898
7037
|
}
|
|
7038
|
+
/**
|
|
7039
|
+
* Replace the record whole, so a reader sees the old one or the new one and never a prefix.
|
|
7040
|
+
*
|
|
7041
|
+
* `writeFileSync` truncates on open, and a crash between that and the end of the write left a record
|
|
7042
|
+
* that does not parse, which `loadJob` reads as no job at all: the review's analysis, its attempts
|
|
7043
|
+
* and its checkout's only pointer gone at once. Renamed into place instead, from a name unique to
|
|
7044
|
+
* this write, because more than one process writes job records. Serialised first, so a throw in
|
|
7045
|
+
* `JSON.stringify` cannot leave anything behind. Unlike `writeJsonAtomically`, a failure throws:
|
|
7046
|
+
* every caller of this already handles a write that fails.
|
|
7047
|
+
*/
|
|
6899
7048
|
function saveJob(job) {
|
|
7049
|
+
const document = JSON.stringify(job);
|
|
6900
7050
|
mkdirSync(JOBS_DIR, { recursive: true });
|
|
6901
|
-
|
|
7051
|
+
const path = jobPath(job.id);
|
|
7052
|
+
const temp = `${path}.${process.pid}.${randomUUID()}.tmp`;
|
|
7053
|
+
try {
|
|
7054
|
+
writeFileSync(temp, document, { mode: 384 });
|
|
7055
|
+
renameSync(temp, path);
|
|
7056
|
+
} catch (error) {
|
|
7057
|
+
try {
|
|
7058
|
+
unlinkSync(temp);
|
|
7059
|
+
} catch {}
|
|
7060
|
+
throw error;
|
|
7061
|
+
}
|
|
6902
7062
|
}
|
|
6903
7063
|
function loadJob(id) {
|
|
6904
7064
|
try {
|
|
@@ -6925,21 +7085,81 @@ function migrate(job) {
|
|
|
6925
7085
|
}
|
|
6926
7086
|
};
|
|
6927
7087
|
}
|
|
7088
|
+
/**
|
|
7089
|
+
* Every record parsed so far, by file, with the identity of the file it was parsed from.
|
|
7090
|
+
*
|
|
7091
|
+
* Since the Runs page, the directory holds a week of records rather than six hours of them, and the
|
|
7092
|
+
* Reviews and Runs pages each read all of it on every poll. Read and parsed whole, 500 records cost
|
|
7093
|
+
* about 100 ms a time, synchronously, inside the server; asking the filesystem whether each file is
|
|
7094
|
+
* still the one already parsed costs about 1 ms. `saveJob` renames a fresh file into place, so a
|
|
7095
|
+
* record that was written in any way has a new inode, and inode, mtime and size together are a
|
|
7096
|
+
* change no write can slip past.
|
|
7097
|
+
*
|
|
7098
|
+
* Frozen, because every caller now shares one copy: a caller that edited a record in place would
|
|
7099
|
+
* be editing it for everyone, and strict mode turns that into an error where it happens.
|
|
7100
|
+
*/
|
|
7101
|
+
var parsed = /* @__PURE__ */ new Map();
|
|
6928
7102
|
function allJobs() {
|
|
6929
7103
|
let names;
|
|
6930
7104
|
try {
|
|
6931
7105
|
names = readdirSync(JOBS_DIR);
|
|
6932
7106
|
} catch {
|
|
7107
|
+
parsed.clear();
|
|
6933
7108
|
return [];
|
|
6934
7109
|
}
|
|
6935
7110
|
const jobs = [];
|
|
7111
|
+
const present = /* @__PURE__ */ new Set();
|
|
6936
7112
|
for (const name of names) {
|
|
6937
7113
|
if (!name.endsWith(".json")) continue;
|
|
7114
|
+
present.add(name);
|
|
7115
|
+
let identity;
|
|
7116
|
+
try {
|
|
7117
|
+
const stat = statSync(join(JOBS_DIR, name));
|
|
7118
|
+
identity = `${stat.ino}:${stat.mtimeMs}:${stat.size}`;
|
|
7119
|
+
} catch {
|
|
7120
|
+
continue;
|
|
7121
|
+
}
|
|
7122
|
+
const cached = parsed.get(name);
|
|
7123
|
+
if (cached?.identity === identity) {
|
|
7124
|
+
jobs.push(cached.job);
|
|
7125
|
+
continue;
|
|
7126
|
+
}
|
|
6938
7127
|
const job = loadJob(name.slice(0, -5));
|
|
6939
|
-
if (job)
|
|
7128
|
+
if (!job) {
|
|
7129
|
+
parsed.delete(name);
|
|
7130
|
+
continue;
|
|
7131
|
+
}
|
|
7132
|
+
Object.freeze(job);
|
|
7133
|
+
parsed.set(name, {
|
|
7134
|
+
identity,
|
|
7135
|
+
job
|
|
7136
|
+
});
|
|
7137
|
+
jobs.push(job);
|
|
6940
7138
|
}
|
|
7139
|
+
for (const name of parsed.keys()) if (!present.has(name)) parsed.delete(name);
|
|
6941
7140
|
return jobs;
|
|
6942
7141
|
}
|
|
7142
|
+
/**
|
|
7143
|
+
* Temporary files a `saveJob` left behind when its process died between the write and the rename.
|
|
7144
|
+
*
|
|
7145
|
+
* Invisible to every reader, which lists `.json` only, so they cost nothing but disk. A write lasts
|
|
7146
|
+
* milliseconds, so one older than `olderThanMs` is residue rather than a write in flight.
|
|
7147
|
+
*/
|
|
7148
|
+
function pruneJobResidue(now, olderThanMs) {
|
|
7149
|
+
let names;
|
|
7150
|
+
try {
|
|
7151
|
+
names = readdirSync(JOBS_DIR);
|
|
7152
|
+
} catch {
|
|
7153
|
+
return;
|
|
7154
|
+
}
|
|
7155
|
+
for (const name of names) {
|
|
7156
|
+
if (!name.endsWith(".tmp")) continue;
|
|
7157
|
+
const path = join(JOBS_DIR, name);
|
|
7158
|
+
try {
|
|
7159
|
+
if (now - statSync(path).mtimeMs >= olderThanMs) unlinkSync(path);
|
|
7160
|
+
} catch {}
|
|
7161
|
+
}
|
|
7162
|
+
}
|
|
6943
7163
|
function deleteJob(id) {
|
|
6944
7164
|
try {
|
|
6945
7165
|
unlinkSync(jobPath(id));
|
|
@@ -15315,7 +15535,17 @@ function aboutMinutes(ms) {
|
|
|
15315
15535
|
}
|
|
15316
15536
|
//#endregion
|
|
15317
15537
|
//#region ../../packages/review-harness/src/runtime/store.ts
|
|
15318
|
-
var VERSION =
|
|
15538
|
+
var VERSION = 2;
|
|
15539
|
+
/**
|
|
15540
|
+
* Version 1 is the same shape with one field that cannot be trusted. Every update row it holds
|
|
15541
|
+
* names the default agent, Claude, whichever agent ran it: the update's job was stamped with the
|
|
15542
|
+
* daemon's default rather than the review's own, and the row was copied from the job. So that
|
|
15543
|
+
* field is a constant on every such row, and reading it as a fact would credit Codex's updates to
|
|
15544
|
+
* Claude for as long as the rows are kept, which is indefinitely. It is dropped rather than
|
|
15545
|
+
* rewritten, because which agent did run is not recorded anywhere this file can see. The duration
|
|
15546
|
+
* was always right and stays, and so does every other operation's agent.
|
|
15547
|
+
*/
|
|
15548
|
+
var VERSION_WITH_UNKNOWN_UPDATE_AGENTS = 1;
|
|
15319
15549
|
/** Kept in all, so a machine with years of reviews holds a bounded file. */
|
|
15320
15550
|
var ROWS_KEPT = 1e3;
|
|
15321
15551
|
var LOCK = "runtimes";
|
|
@@ -15367,12 +15597,19 @@ function keyOf$1(row) {
|
|
|
15367
15597
|
function readRows() {
|
|
15368
15598
|
try {
|
|
15369
15599
|
const parsed = JSON.parse(readFileSync(runtimesPath(), "utf8"));
|
|
15370
|
-
if (
|
|
15371
|
-
return parsed.runs.filter(isRow);
|
|
15600
|
+
if (!Array.isArray(parsed?.runs)) return [];
|
|
15601
|
+
if (parsed.version === VERSION) return parsed.runs.filter(isRow);
|
|
15602
|
+
if (parsed.version === VERSION_WITH_UNKNOWN_UPDATE_AGENTS) return parsed.runs.filter(isRow).map(withoutUpdateAgent);
|
|
15603
|
+
return [];
|
|
15372
15604
|
} catch {
|
|
15373
15605
|
return [];
|
|
15374
15606
|
}
|
|
15375
15607
|
}
|
|
15608
|
+
function withoutUpdateAgent(row) {
|
|
15609
|
+
if (row.operation !== "update") return row;
|
|
15610
|
+
const { agent: _unknown, ...rest } = row;
|
|
15611
|
+
return rest;
|
|
15612
|
+
}
|
|
15376
15613
|
function isRow(value) {
|
|
15377
15614
|
const row = value;
|
|
15378
15615
|
return typeof row?.operation === "string" && typeof row.repository === "string" && typeof row.subject === "string" && typeof row.durationMs === "number" && Number.isFinite(row.durationMs) && row.durationMs >= 0 && typeof row.completedAt === "number";
|
|
@@ -15938,6 +16175,7 @@ async function startJob(input) {
|
|
|
15938
16175
|
target,
|
|
15939
16176
|
env: agent.captureEnv(),
|
|
15940
16177
|
purpose: "review",
|
|
16178
|
+
...input.source ? { source: input.source } : {},
|
|
15941
16179
|
...input.requestedModel ? { requestedModel: input.requestedModel } : {},
|
|
15942
16180
|
...review.type === "kiss" ? {
|
|
15943
16181
|
reviewType: "kiss",
|
|
@@ -15971,7 +16209,7 @@ async function startJob(input) {
|
|
|
15971
16209
|
* The previous result is snapshotted before the session is replaced, so the review keeps saying who
|
|
15972
16210
|
* made the analysis it is retiring as well as who made the one it now shows.
|
|
15973
16211
|
*/
|
|
15974
|
-
async function reanalyseReview(workspaceId, agentId, onStarted, requestedModel) {
|
|
16212
|
+
async function reanalyseReview(workspaceId, agentId, onStarted, requestedModel, source) {
|
|
15975
16213
|
const workspace = loadWorkspace(workspaceId);
|
|
15976
16214
|
if (!workspace) throw new Error("No such review.");
|
|
15977
16215
|
const sha = workspace.session.metadata?.commitSha;
|
|
@@ -16003,6 +16241,7 @@ async function reanalyseReview(workspaceId, agentId, onStarted, requestedModel)
|
|
|
16003
16241
|
env: agent.captureEnv(),
|
|
16004
16242
|
purpose: "review",
|
|
16005
16243
|
reanalysis: true,
|
|
16244
|
+
...source ? { source } : {},
|
|
16006
16245
|
...model ? { requestedModel: model } : {}
|
|
16007
16246
|
});
|
|
16008
16247
|
saveJob(job);
|
|
@@ -16062,7 +16301,7 @@ async function runJob(workspaceId, runners = {}, reviewType = "standard", option
|
|
|
16062
16301
|
outer?.addEventListener("abort", () => controller.abort(), { once: true });
|
|
16063
16302
|
const unwatch = watchForStop(started.jobId, controller);
|
|
16064
16303
|
try {
|
|
16065
|
-
return await drive(started.jobId, workspaceId, runners, started.claim.claim.holder, controller.signal);
|
|
16304
|
+
return await drive(started.jobId, workspaceId, runners, started.claim.claim.holder, controller.signal, options.source);
|
|
16066
16305
|
} finally {
|
|
16067
16306
|
unwatch();
|
|
16068
16307
|
clearJobEnding(started.jobId);
|
|
@@ -16117,16 +16356,18 @@ function runOfJob(workspace, jobId) {
|
|
|
16117
16356
|
if (!run) throw new Error("This KISS job has no run to write its answer to.");
|
|
16118
16357
|
return run;
|
|
16119
16358
|
}
|
|
16120
|
-
async function drive(jobId, workspaceId, runners, driver, signal) {
|
|
16359
|
+
async function drive(jobId, workspaceId, runners, driver, signal, source) {
|
|
16121
16360
|
let job = loadJob(jobId);
|
|
16122
16361
|
if (!job) throw new Error("No such job.");
|
|
16123
16362
|
const now = runners.now ?? Date.now;
|
|
16124
16363
|
const startedAt = now();
|
|
16125
|
-
const from = resumeFrom(job);
|
|
16126
|
-
job = {
|
|
16127
|
-
|
|
16128
|
-
|
|
16129
|
-
|
|
16364
|
+
const from = checkoutGone$1(job) ? "preparing" : resumeFrom(job);
|
|
16365
|
+
job = beginAttempt(job, {
|
|
16366
|
+
startedAt,
|
|
16367
|
+
phase: from,
|
|
16368
|
+
...source ? { source } : {}
|
|
16369
|
+
});
|
|
16370
|
+
saveJob(job);
|
|
16130
16371
|
try {
|
|
16131
16372
|
signal?.throwIfAborted();
|
|
16132
16373
|
if (needs(from, "preparing")) {
|
|
@@ -16356,6 +16597,18 @@ function explain(job, detail) {
|
|
|
16356
16597
|
}
|
|
16357
16598
|
}
|
|
16358
16599
|
/** True when this phase is at or after the point the job resumes from. */
|
|
16600
|
+
/**
|
|
16601
|
+
* The record says work was done in a checkout that is no longer there.
|
|
16602
|
+
*
|
|
16603
|
+
* The sweep removes a finished job's checkout after six hours and keeps its record for seven days,
|
|
16604
|
+
* so a Retry of an older failure finds `preparing` complete and nothing on disk. Starting from
|
|
16605
|
+
* `preparing` makes the checkout again at the job's commit, and everything after it with it, because
|
|
16606
|
+
* every later phase reads files from it.
|
|
16607
|
+
*/
|
|
16608
|
+
function checkoutGone$1(job) {
|
|
16609
|
+
if (!job.completed.includes("preparing")) return false;
|
|
16610
|
+
return !job.worktreePath || !existsSync(join(job.worktreePath, ".prreviewbuddy-worktree.json"));
|
|
16611
|
+
}
|
|
16359
16612
|
function needs(from, phase) {
|
|
16360
16613
|
return WORK_PHASES.indexOf(phase) >= WORK_PHASES.indexOf(from);
|
|
16361
16614
|
}
|
|
@@ -16642,7 +16895,7 @@ function failureOf(workspaceId) {
|
|
|
16642
16895
|
* "whatever the default is", so a configured default of Codex announced Codex and then analysed
|
|
16643
16896
|
* with Claude, and nothing said so until the failure named the wrong tool.
|
|
16644
16897
|
*/
|
|
16645
|
-
async function prepareReview(target, agentId, fresh, requestedModel) {
|
|
16898
|
+
async function prepareReview(target, agentId, fresh, requestedModel, source) {
|
|
16646
16899
|
if (!fresh) {
|
|
16647
16900
|
const existing = await findExistingReview(target);
|
|
16648
16901
|
if (existing) {
|
|
@@ -16662,7 +16915,8 @@ async function prepareReview(target, agentId, fresh, requestedModel) {
|
|
|
16662
16915
|
workspaceId: await startJob({
|
|
16663
16916
|
target,
|
|
16664
16917
|
agentId,
|
|
16665
|
-
...requestedModel ? { requestedModel } : {}
|
|
16918
|
+
...requestedModel ? { requestedModel } : {},
|
|
16919
|
+
...source ? { source } : {}
|
|
16666
16920
|
})
|
|
16667
16921
|
};
|
|
16668
16922
|
}
|
|
@@ -16679,10 +16933,13 @@ async function prepareReview(target, agentId, fresh, requestedModel) {
|
|
|
16679
16933
|
* that reads as a clean bill of health, which is the opposite of what happened. A KISS run's
|
|
16680
16934
|
* answer is checked by `drive`, which knows which run it is.
|
|
16681
16935
|
*/
|
|
16682
|
-
async function settleReview(workspaceId, reviewType = "standard", signal) {
|
|
16936
|
+
async function settleReview(workspaceId, reviewType = "standard", signal, source) {
|
|
16683
16937
|
let job;
|
|
16684
16938
|
try {
|
|
16685
|
-
job = await runJob(workspaceId, {}, reviewType,
|
|
16939
|
+
job = await runJob(workspaceId, {}, reviewType, {
|
|
16940
|
+
...signal ? { signal } : {},
|
|
16941
|
+
...source ? { source } : {}
|
|
16942
|
+
});
|
|
16686
16943
|
} catch (error) {
|
|
16687
16944
|
return {
|
|
16688
16945
|
ok: false,
|
|
@@ -17645,6 +17902,7 @@ async function recordKissRun(input) {
|
|
|
17645
17902
|
purpose: "review",
|
|
17646
17903
|
reviewType: "kiss",
|
|
17647
17904
|
audience: input.audience,
|
|
17905
|
+
...input.source ? { source: input.source } : {},
|
|
17648
17906
|
...requestedModel ? { requestedModel } : {}
|
|
17649
17907
|
});
|
|
17650
17908
|
saveJob(job);
|
|
@@ -18440,7 +18698,7 @@ async function claimCheckoutJob(workspace, sha, fields) {
|
|
|
18440
18698
|
const job = createJob({
|
|
18441
18699
|
workspaceId: workspace.id,
|
|
18442
18700
|
target,
|
|
18443
|
-
env:
|
|
18701
|
+
env: agentEnvOf(workspace),
|
|
18444
18702
|
...fields
|
|
18445
18703
|
});
|
|
18446
18704
|
saveJob(job);
|
|
@@ -18608,6 +18866,7 @@ async function updateReview(workspace, runners = {}) {
|
|
|
18608
18866
|
if (workspace.changeSet.targetType === "commit") return refuse(reviewedSha, false, COMMIT_REVIEW_CANNOT_UPDATE);
|
|
18609
18867
|
const held = await claimCheckoutJob(workspace, reviewedSha ?? "", {
|
|
18610
18868
|
purpose: "update",
|
|
18869
|
+
...runners.source ? { source: runners.source } : {},
|
|
18611
18870
|
...workspace.prContext ? { conversation: {
|
|
18612
18871
|
kind: "attached",
|
|
18613
18872
|
context: workspace.prContext
|
|
@@ -18673,7 +18932,7 @@ function cancelled(held, reviewedSha) {
|
|
|
18673
18932
|
};
|
|
18674
18933
|
}
|
|
18675
18934
|
async function bringForward(workspace, runners, reviewedSha, held, step, signal, clock) {
|
|
18676
|
-
const remote = await remoteHead(workspace, signal, runners);
|
|
18935
|
+
const remote = await remoteHead(workspace, held.job.env, signal, runners);
|
|
18677
18936
|
signal.throwIfAborted();
|
|
18678
18937
|
if (!remote.sha) return refuse(reviewedSha, remote.fetchFailed, remote.refusal ?? noRemoteHeadMessage(workspace));
|
|
18679
18938
|
adoptLegacyBaseline(workspace);
|
|
@@ -18696,9 +18955,10 @@ async function bringForward(workspace, runners, reviewedSha, held, step, signal,
|
|
|
18696
18955
|
return settled(reviewedSha, remote.sha, remote.fetchFailed, conversationOk, "analysis-failed", "A checkout of the latest commit could not be prepared, so nothing was reassessed.");
|
|
18697
18956
|
}
|
|
18698
18957
|
signal.throwIfAborted();
|
|
18699
|
-
return reconcile(workspace, runners, reviewedSha, remote, conversationOk, worktreePath, step, held.job
|
|
18958
|
+
return reconcile(workspace, runners, reviewedSha, remote, conversationOk, worktreePath, step, held.job, signal, clock, prepared, discussionMoved);
|
|
18700
18959
|
}
|
|
18701
|
-
async function reconcile(workspace, runners, reviewedSha, remote, conversationOk, worktreePath, step,
|
|
18960
|
+
async function reconcile(workspace, runners, reviewedSha, remote, conversationOk, worktreePath, step, job, signal, clock, prepared, discussionMoved) {
|
|
18961
|
+
const { id: jobId, env } = job;
|
|
18702
18962
|
const newHead = remote.sha;
|
|
18703
18963
|
let delta = null;
|
|
18704
18964
|
if (reviewedSha !== newHead) try {
|
|
@@ -18733,9 +18993,9 @@ async function reconcile(workspace, runners, reviewedSha, remote, conversationOk
|
|
|
18733
18993
|
let raw;
|
|
18734
18994
|
try {
|
|
18735
18995
|
const prompt = buildUpdatePrompt(workspace, delta, prepared, reviewedSha, newHead, worktreePath);
|
|
18736
|
-
raw = runners.run ? await runners.run(prompt, worktreePath,
|
|
18996
|
+
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);
|
|
18737
18997
|
} catch (error) {
|
|
18738
|
-
return settled(reviewedSha, newHead, remote.fetchFailed, conversationOk, "analysis-failed", explainUpdateFailure(error,
|
|
18998
|
+
return settled(reviewedSha, newHead, remote.fetchFailed, conversationOk, "analysis-failed", explainUpdateFailure(error, env, requestedModel));
|
|
18739
18999
|
}
|
|
18740
19000
|
const parsed = parseReconciliationResult(raw, previous.issues.length, { priorQuestionCount: previous.questions.length });
|
|
18741
19001
|
if (!parsed) return settled(reviewedSha, newHead, remote.fetchFailed, conversationOk, "analysis-failed", "The reassessment came back in a form this could not read, so nothing was changed.");
|
|
@@ -18753,7 +19013,7 @@ async function reconcile(workspace, runners, reviewedSha, remote, conversationOk
|
|
|
18753
19013
|
const gradeChanges = await applyUpdate(workspace, result, previous, newHead, worktreePath, {
|
|
18754
19014
|
...requestedModel ? { requestedModel } : {},
|
|
18755
19015
|
...observedModel ? { observedModel } : {},
|
|
18756
|
-
...await (runners.agentVersion ?? installedAgentVersion)(
|
|
19016
|
+
...await (runners.agentVersion ?? installedAgentVersion)(env)
|
|
18757
19017
|
}, clock, remote.base, suggestions, conversationTakenIntoAccount(prepared, analysedBaselineOf(workspace)));
|
|
18758
19018
|
const counts = {
|
|
18759
19019
|
...countUpdateChanges(previous, result),
|
|
@@ -18787,9 +19047,9 @@ var BASELINE_GONE_MESSAGE = "The commit this review was made from is no longer i
|
|
|
18787
19047
|
* is allowed to reach the network and that panel is not, so it looks at a newer copy of the same
|
|
18788
19048
|
* refs.
|
|
18789
19049
|
*/
|
|
18790
|
-
async function remoteHead(workspace, signal, runners) {
|
|
19050
|
+
async function remoteHead(workspace, env, signal, runners) {
|
|
18791
19051
|
const source = await storedRequestSource(workspace);
|
|
18792
|
-
if (source) return requestHead(workspace, source, signal, runners);
|
|
19052
|
+
if (source) return requestHead(workspace, env, source, signal, runners);
|
|
18793
19053
|
const fetchFailed = !await fetchOrigin(workspace.repoPath, signal);
|
|
18794
19054
|
return {
|
|
18795
19055
|
sha: (await followedBranch(workspace))?.sha ?? null,
|
|
@@ -18814,8 +19074,8 @@ async function remoteHead(workspace, signal, runners) {
|
|
|
18814
19074
|
* rather than a guess. If even that fetch fails, the last head this repository saw is used and
|
|
18815
19075
|
* the update says the fetch failed, as it always has.
|
|
18816
19076
|
*/
|
|
18817
|
-
async function requestHead(workspace, source, signal, runners) {
|
|
18818
|
-
const outcome = await (runners.headOf ?? ((cwd, asked) => fetchHeadFor(cwd, asked,
|
|
19077
|
+
async function requestHead(workspace, env, source, signal, runners) {
|
|
19078
|
+
const outcome = await (runners.headOf ?? ((cwd, asked) => fetchHeadFor(cwd, asked, env)))(workspace.repoPath, source);
|
|
18819
19079
|
signal.throwIfAborted();
|
|
18820
19080
|
const baseBranch = workspace.changeSet.baseRef || void 0;
|
|
18821
19081
|
if (outcome.kind === "head") {
|
|
@@ -19298,7 +19558,7 @@ async function runUpdate(workspaceId, prompt, cwd, originRepoPath, env, onProgre
|
|
|
19298
19558
|
* nothing is running has answered the same question better, and passes 0.
|
|
19299
19559
|
*/
|
|
19300
19560
|
async function discardJob(job, options = {}) {
|
|
19301
|
-
if (job.worktreePath) {
|
|
19561
|
+
if (job.worktreePath && !checkoutGone(job.worktreePath)) {
|
|
19302
19562
|
const outcome = await removeWorktree({
|
|
19303
19563
|
originRepoPath: job.target.originRepoPath,
|
|
19304
19564
|
worktreePath: job.worktreePath,
|
|
@@ -19313,6 +19573,18 @@ async function discardJob(job, options = {}) {
|
|
|
19313
19573
|
clearClaim(job.id);
|
|
19314
19574
|
return { removed: true };
|
|
19315
19575
|
}
|
|
19576
|
+
/**
|
|
19577
|
+
* Only when the filesystem says there is nothing there. Any other failure to look, a permission
|
|
19578
|
+
* error say, is not proof of absence, and the record is the only thing that names the directory.
|
|
19579
|
+
*/
|
|
19580
|
+
function checkoutGone(path) {
|
|
19581
|
+
try {
|
|
19582
|
+
lstatSync(path);
|
|
19583
|
+
return false;
|
|
19584
|
+
} catch (error) {
|
|
19585
|
+
return error.code === "ENOENT";
|
|
19586
|
+
}
|
|
19587
|
+
}
|
|
19316
19588
|
//#endregion
|
|
19317
19589
|
//#region ../../packages/review-harness/src/workspace/delete_review.ts
|
|
19318
19590
|
/**
|
|
@@ -19396,13 +19668,33 @@ async function deleteReview(id) {
|
|
|
19396
19668
|
*
|
|
19397
19669
|
* The record is unlinked **whether or not** a checkout was refused, and that is deliberate. The
|
|
19398
19670
|
* review is what was asked for; a directory the guard declined keeps its job record, so the sweep
|
|
19399
|
-
* comes back to it
|
|
19671
|
+
* comes back to it once the checkout is past retention, with the origin repository still recorded, and the refusal is
|
|
19400
19672
|
* reported so nobody has to discover it later.
|
|
19401
19673
|
*/
|
|
19402
19674
|
async function deleteLocked(id) {
|
|
19403
19675
|
const report = emptyReport();
|
|
19404
19676
|
if (!loadWorkspace(id)) return report;
|
|
19405
19677
|
for (const job of allJobs().filter((job) => job.workspaceId === id)) {
|
|
19678
|
+
if (isTerminal(job) && purposeOf(job) !== "ask") {
|
|
19679
|
+
if (job.worktreePath && existsSync(job.worktreePath)) {
|
|
19680
|
+
const outcome = await removeWorktree({
|
|
19681
|
+
originRepoPath: job.target.originRepoPath,
|
|
19682
|
+
worktreePath: job.worktreePath,
|
|
19683
|
+
minAgeMs: 0
|
|
19684
|
+
});
|
|
19685
|
+
if (!outcome.removed) {
|
|
19686
|
+
report.refusals.push(outcome.message);
|
|
19687
|
+
saveJob({
|
|
19688
|
+
...strippedForDeletedReview(job),
|
|
19689
|
+
worktreePath: job.worktreePath
|
|
19690
|
+
});
|
|
19691
|
+
continue;
|
|
19692
|
+
}
|
|
19693
|
+
report.worktreesRemoved += 1;
|
|
19694
|
+
}
|
|
19695
|
+
saveJob(strippedForDeletedReview(job));
|
|
19696
|
+
continue;
|
|
19697
|
+
}
|
|
19406
19698
|
const outcome = await discardJob(job, { minAgeMs: 0 });
|
|
19407
19699
|
if (outcome.refusal) {
|
|
19408
19700
|
report.refusals.push(outcome.refusal);
|
|
@@ -19461,4 +19753,4 @@ function lineageIds(id) {
|
|
|
19461
19753
|
return [.../* @__PURE__ */ new Set([id, ...lineage.map((review) => review.id)])];
|
|
19462
19754
|
}
|
|
19463
19755
|
//#endregion
|
|
19464
|
-
export { resolveWorkspacePort as $,
|
|
19756
|
+
export { resolveWorkspacePort as $, AgentUnavailableError as $i, attemptIdOf as $n, isIssueOutstanding as $r, moveIds as $t, parsePullRequestLink as A, resolveTarget as Ai, modelHelpLines as An, recentWorkspaces as Ar, readArchitecture as At, ensureServer as B, resolveAgent as Bi, requestJobStop as Bn, isLifecycle as Br, writeJsonAtomically as Bt, completeRun as C, followUpFindingId as Ci, hasAuthorContent as Cn, lineagePosition as Cr, RUNTIME_WORDS as Ct, relativeTime as D, describeAuthorship as Di, CODE_COPY_CLASS as Dn, positionInLineage as Dr, checkArchitecture as Dt, stopRun as E, objectWithAnyOf as Ei, CODE_BLOCK_CLASS as En, mutateWorkspace as Er, ARCHITECTURE_DIR as Et, queueForReview as F, AmbiguousRefError as Fi, createWorktree as Fn, workspaceRevision as Fr, ownersOf as Ft, stopChild as G, CONFIG_PATH as Gi, checkReview as Gn, parseLifecycle as Gr, createArchitectureNotification as Gt, reviewsUrl as H, clearAgentPreference as Hi, describeSubject as Hn, lifecycleItemLabel as Hr, branchOf as Ht, settleQueue as I, shortNameOf as Ii, holdWorktree as In, workspaceStamps as Ir, QUOTE_LIMITS as It, writeServerRecord as J, agentById as Ji, fetchHead as Jn, queueAddMany as Jr, eventName as Jt, stopServer as K, STORE_ROOT as Ki, followedBranch as Kn, sectionOf as Kr, createPrState as Kt, readIndexToken as L, shorthandOf as Li, isWorktreeHeld as Ln, LIFECYCLES as Lr, REPOSITORY_SCOPE as Lt, runBatch as M, DetachedHeadError as Mi, isBusy as Mn, reviewedRepositories as Mr, storeArchitecture as Mt, activateQueued as N, isCommitReview as Ni, withReviewLock as Nn, summarise as Nr, storedScopes as Nt, batchIdentity as O, WITHHELD_REASON as Oi, escapeHtml as On, presentedKissRunOf as Or, loadArchitecture as Ot, compactQueue as P, resolveBase as Pi, MANAGED_ROOT as Pn, touchWorkspace as Pr, trackedFiles as Pt, parseWorkspacePort as Q, AgentCancelledError as Qi, allJobs as Qn, doneVerb as Qr, markReadForReview as Qt, bootstrapUrl as R, git as Ri, readMarker as Rn, activityAttributes as Rr, ancestorsOf as Rt, beginRun as S, wasReassessed as Si, authorPreview as Sn, latestKissRun as Sr, recordRuntimeBestEffort as St, reportRun as T, extractJsonText as Ti, renderMarkdown as Tn, matchingWorkspaceIds as Tr, formatDuration as Tt, serverEntryExists as U, readAgentPreference as Ui, findExistingReview as Un, lifecyclePill as Ur, subjectOf as Ut, readServerRecord as V, resolveModel as Vi, describeMovement as Vn, lifecycleChip as Vr, announceJob as Vt, spawnServer as W, writeAgentPreference as Wi, checkCodeFreshness as Wn, offersLifecycle as Wr, categoryOf as Wt, MAX_WORKSPACE_PORT as X, detectAgents as Xi, fillFileUrlTemplate as Xn, queueStamp as Xr, markAllRead as Xt, DEFAULT_WORKSPACE_PORT as Y, agentFor as Yi, forgeResolver as Yn, queueRemove as Yr, listNotifications as Yt, MIN_WORKSPACE_PORT as Z, isAgentId as Zi, RUN_RECORD_RETENTION_MS as Zn, readQueue as Zr, markRead as Zt, recordKissRun as _, gradeScale as _i, isUnchanged as _n, groupByLineage as _r, BUILD_VERSION as _t, wasBlocked as a, processDiscussion as ai, toneOf as an, saveJob as ar, settleReview as at, track as b, reassessIn as bi, chatConversationSection as bn, kissDecisionRefusal as br, waitingHistory as bt, RefreshUnavailableError as c, explanationOf as ci, withUsageRecorded as cn, isTerminalJobPhase as cr, startJob as ct, mergeUpdateInto as d, ANALYSIS_ONLY as di, adoptLegacyBaseline as dn, purposeOf as dr, record as dt, isQuestionOutstanding as ei, pruneNotifications as en, endedAt as er, statedWorkspacePort as et, updateReview as f, analysisRefOf as fi, prepareConversationWithin as fn, clearClaim as fr, stamp as ft, runningJobs as g, findingIn as gi, refreshPrContext as gn, followedRefName as gr, telemetryUploadEnabled as gt, liveUpdateFor as h, findingAssessment as hi, unforeseenFailure as hn, decideKissRecommendation as hr, telemetryUploadConsent as ht, liveJobsFor as i, reviewerDispositions as ii, retireNotification as in, pruneJobResidue as ir, prepareReview as it, unsupportedReason as j, originRemote as ji, ReviewBeingDeletedError as jn, reviewedCommit as jr, repositoryKey as jt, extractPullRequestLinks as k, kissOutcome as ki, renderInlineText as kn, previousKissResult as kr, partFiles as kt, cancelUpdate as l, isExplanationAction as li, existingPaths as ln, phasesFor as lr, append as lt, UpdateAlreadyRunningError as m, currentGradeIn as mi, storedConversation as mn, CLAIM_LEASE_MS as mr, recordTelemetryUploadConsent as mt, deleteReview as n, questionsOutstanding as ni, readStateOf as nn, isTerminal as nr, failureOf as nt, discardJob as o, recommendationsOf as oi, unreadAround as on, PHASES as or, reanalyseReview as ot, askCheckout as p, assessmentLookup as pi, saveRefresh as pn, isClaimed as pr, deliver as pt, workspaceUrl as q, AGENT_IDS as qi, reviewedShaOf as qn, queueAdd as qr, createPrUpdate as qt, lineageIds as r, resolvedByConversation as ri, removeNotification as rn, loadJob as rr, observeReview as rt, FETCH_TIMEOUT_MS as s, explanationActionOf as si, unreadCount as sn, isLiveJob as sr, runJob as st, deleteLineage as t, issuesOutstanding as ti, readNotification as tn, fail as tr, writePortPreference as tt, cancellableHere as u, withExplanation as ui, ASK_REREAD_CEILING_MS as un, progressSteps as ur, readEvents as ut, startKissJob as v, isGradeFor as vi, agentEnvOf as vn, indexKeptIds as vr, PACKAGE_NAME as vt, endRun as w, asString$1 as wi, GITHUB_MARKDOWN as wn, loadWorkspace as wr, describeRuntimes as wt, RUN_KINDS as x, sourcePhrase as xi, UNESTABLISHED_MOTIVATION as xn, kissDecisionsOf as xr, mapRuntimes as xt, isDriving as y, promptGrade as yi, EXPLAIN_SIMPLY_PROMPT as yn, indexReviewGroups as yr, feedbackUrl as yt, clearServerRecordOwnedBy as z, refExists as zi, removeWorktree as zn, activityLabel as zr, isArchitectureId as zt };
|