prreviewbuddy 0.12.0 → 0.12.1
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/dist/{log-DdPaO6Wo.js → log-PmeEgome.js} +39 -12
- package/dist/main.js +24 -2
- package/dist/server.js +1 -1
- package/package.json +2 -2
|
@@ -404,11 +404,7 @@ var GitError = class extends Error {
|
|
|
404
404
|
};
|
|
405
405
|
async function git(cwd, args, options = {}) {
|
|
406
406
|
try {
|
|
407
|
-
const { stdout } = await execFileAsync$1("git", [
|
|
408
|
-
"-c",
|
|
409
|
-
"core.quotePath=false",
|
|
410
|
-
...args
|
|
411
|
-
], {
|
|
407
|
+
const { stdout } = await execFileAsync$1("git", [...["core.quotePath=false", ...options.config ?? []].flatMap((one) => ["-c", one]), ...args], {
|
|
412
408
|
cwd,
|
|
413
409
|
encoding: "utf8",
|
|
414
410
|
maxBuffer: MAX_BUFFER$1,
|
|
@@ -2092,6 +2088,25 @@ function relativeTime(ms) {
|
|
|
2092
2088
|
*/
|
|
2093
2089
|
var MANAGED_ROOT = join(STORE_ROOT, "worktrees");
|
|
2094
2090
|
/**
|
|
2091
|
+
* An empty directory, pointed at so that the repository's own hooks do not run in our checkout.
|
|
2092
|
+
*
|
|
2093
|
+
* `git worktree add` checks the tree out, which fires `post-checkout` in the reviewer's repository.
|
|
2094
|
+
* Found on a 31,644 file monorepo with husky: its hook asks for `HEAD@{1}`, a brand new worktree's
|
|
2095
|
+
* HEAD reflog has exactly one entry, git answers `fatal: log for 'HEAD' only has 1 entries`, and the
|
|
2096
|
+
* add exits 128 *after* writing the whole tree. Every review of that repository failed, in the first
|
|
2097
|
+
* phase, for a reason that was nothing to do with the review.
|
|
2098
|
+
*
|
|
2099
|
+
* Turning them off is the right answer rather than a workaround. These hooks were written for a
|
|
2100
|
+
* person checking out a branch to work on: install dependencies, warn about a stale lockfile, prompt
|
|
2101
|
+
* something. Nobody works in this directory. It is read once by an agent and deleted. It is also
|
|
2102
|
+
* arbitrary code from the repository being reviewed, and a review that runs it has quietly made
|
|
2103
|
+
* "point PR Review Buddy at this repository" mean "execute this repository".
|
|
2104
|
+
*
|
|
2105
|
+
* A directory rather than `/dev/null` because git is being told where hooks live, and a real empty
|
|
2106
|
+
* one is true on every platform.
|
|
2107
|
+
*/
|
|
2108
|
+
var NO_HOOKS = join(STORE_ROOT, "no-hooks");
|
|
2109
|
+
/**
|
|
2095
2110
|
* The proof that we made a directory, kept inside the directory itself.
|
|
2096
2111
|
*
|
|
2097
2112
|
* It exists for the removal guard. Git normally answers "is this yours", and when git has
|
|
@@ -2101,14 +2116,26 @@ var MANAGED_ROOT = join(STORE_ROOT, "worktrees");
|
|
|
2101
2116
|
var MARKER_FILE = ".prreviewbuddy-worktree.json";
|
|
2102
2117
|
async function createWorktree(input) {
|
|
2103
2118
|
mkdirSync(MANAGED_ROOT, { recursive: true });
|
|
2119
|
+
mkdirSync(NO_HOOKS, { recursive: true });
|
|
2104
2120
|
const path = join(MANAGED_ROOT, input.jobId);
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2121
|
+
try {
|
|
2122
|
+
await git(input.originRepoPath, [
|
|
2123
|
+
"worktree",
|
|
2124
|
+
"add",
|
|
2125
|
+
"--detach",
|
|
2126
|
+
path,
|
|
2127
|
+
input.sha
|
|
2128
|
+
], {
|
|
2129
|
+
config: [`core.hooksPath=${NO_HOOKS}`],
|
|
2130
|
+
timeoutMs: WORKTREE_TIMEOUT_MS
|
|
2131
|
+
});
|
|
2132
|
+
} catch (error) {
|
|
2133
|
+
await removeWorktree({
|
|
2134
|
+
originRepoPath: input.originRepoPath,
|
|
2135
|
+
worktreePath: path
|
|
2136
|
+
}).catch(() => {});
|
|
2137
|
+
throw error;
|
|
2138
|
+
}
|
|
2112
2139
|
const marker = {
|
|
2113
2140
|
jobId: input.jobId,
|
|
2114
2141
|
originRepoPath: input.originRepoPath,
|
package/dist/main.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as agentById, A as WORK_PHASES, F as loadJob, G as saveWorkspace, H as positionInLineage, K as summarise, L as displayRef, O as relativeTime, P as isTerminal, Q as AGENT_IDS, V as loadWorkspace, W as recentWorkspaces, X as resolveTarget, Z as withBase, d as ensureServer, f as readServerRecord, g as BUILD_VERSION, i as updateReview, k as checkFreshness, l as LANDING_PAGE, m as workspaceUrl, n as record, nt as AgentUnavailableError, p as reviewsUrl, tt as defaultAgent, v as runJob, w as isClaimed, x as forgeResolver, y as startJob, z as groupByLineage } from "./log-
|
|
2
|
+
import { $ as agentById, A as WORK_PHASES, F as loadJob, G as saveWorkspace, H as positionInLineage, K as summarise, L as displayRef, O as relativeTime, P as isTerminal, Q as AGENT_IDS, V as loadWorkspace, W as recentWorkspaces, X as resolveTarget, Z as withBase, d as ensureServer, f as readServerRecord, g as BUILD_VERSION, i as updateReview, k as checkFreshness, l as LANDING_PAGE, m as workspaceUrl, n as record, nt as AgentUnavailableError, p as reviewsUrl, tt as defaultAgent, v as runJob, w as isClaimed, x as forgeResolver, y as startJob, z as groupByLineage } from "./log-PmeEgome.js";
|
|
3
3
|
import { basename } from "node:path";
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
5
|
import { platform } from "node:process";
|
|
@@ -318,6 +318,23 @@ function restates(note, label) {
|
|
|
318
318
|
return bare(note) === bare(label);
|
|
319
319
|
}
|
|
320
320
|
/**
|
|
321
|
+
* How many rows this block will actually occupy, which is not how many strings it is.
|
|
322
|
+
*
|
|
323
|
+
* The redraw moves the cursor up by a count and clears from there, so that count has to be in the
|
|
324
|
+
* unit the terminal moves in: rows on screen, after wrapping. Counting strings instead lands the
|
|
325
|
+
* cursor short and clears output the block never drew. The header's second line carries a full
|
|
326
|
+
* repository path and wraps in any normal window, so this was not a corner case.
|
|
327
|
+
*
|
|
328
|
+
* Escape sequences are removed first because they occupy no columns. A resize between drawing and
|
|
329
|
+
* redrawing still misplaces the cursor; nothing short of tracking the resize can fix that, and the
|
|
330
|
+
* next repaint corrects itself.
|
|
331
|
+
*/
|
|
332
|
+
function rowsOccupied(lines, columns) {
|
|
333
|
+
if (!columns) return lines.length;
|
|
334
|
+
const visible = (line) => line.replace(/\u001b\[[0-9;]*m/g, "").length;
|
|
335
|
+
return lines.reduce((rows, line) => rows + Math.max(1, Math.ceil(visible(line) / columns)), 0);
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
321
338
|
* Watch a job and keep one block on the screen describing it.
|
|
322
339
|
*
|
|
323
340
|
* Returns the stop function the caller must call: nothing here may outlive the command, and a
|
|
@@ -339,12 +356,15 @@ function followJob(jobId, target, options = {}) {
|
|
|
339
356
|
if (inPlace && drawn > 0) stream.write(`\u001b[${drawn}A\u001b[0J`);
|
|
340
357
|
stream.write(`${block}\n`);
|
|
341
358
|
last = block;
|
|
342
|
-
drawn = lines.
|
|
359
|
+
drawn = rowsOccupied(lines, stream.columns ?? 0);
|
|
343
360
|
};
|
|
344
361
|
const timer = setInterval(paint, POLL_INTERVAL_MS);
|
|
345
362
|
timer.unref();
|
|
346
363
|
paint();
|
|
364
|
+
let stopped = false;
|
|
347
365
|
return () => {
|
|
366
|
+
if (stopped) return;
|
|
367
|
+
stopped = true;
|
|
348
368
|
clearInterval(timer);
|
|
349
369
|
paint();
|
|
350
370
|
};
|
|
@@ -675,10 +695,12 @@ async function drive(workspaceId, url) {
|
|
|
675
695
|
try {
|
|
676
696
|
finished = await runJob(workspaceId);
|
|
677
697
|
if (finished.phase === "failed") {
|
|
698
|
+
stop();
|
|
678
699
|
err(reviewFailed(finished.failure?.message ?? "The reason was not recorded.", await linkNow(workspace, url)));
|
|
679
700
|
return 1;
|
|
680
701
|
}
|
|
681
702
|
} catch (error) {
|
|
703
|
+
stop();
|
|
682
704
|
err(reviewFailed(error instanceof Error ? error.message : String(error), await linkNow(workspace, url)));
|
|
683
705
|
return 1;
|
|
684
706
|
} finally {
|
package/dist/server.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as lineagePosition, C as clearClaim, D as removeWorktree, E as readMarker, F as loadJob, G as saveWorkspace, I as saveJob, J as processDiscussion, M as deleteJob, N as fail, O as relativeTime$1, P as isTerminal, R as STORE_ROOT, S as fillFileUrlTemplate, T as MANAGED_ROOT, U as recentReviewGroups, V as loadWorkspace, Y as describeAuthorship, _ as feedbackUrl, a as refreshPrContext, b as EXPLAIN_SIMPLY_PROMPT, c as agentEnvOf, et as agentFor, g as BUILD_VERSION, h as writeServerRecord, i as updateReview, j as allJobs, k as checkFreshness, n as record, nt as AgentUnavailableError, o as isUnchanged, q as touchWorkspace, r as RefreshUnavailableError, s as askCheckout, t as readEvents, u as clearServerRecord, v as runJob, w as isClaimed } from "./log-
|
|
1
|
+
import { B as lineagePosition, C as clearClaim, D as removeWorktree, E as readMarker, F as loadJob, G as saveWorkspace, I as saveJob, J as processDiscussion, M as deleteJob, N as fail, O as relativeTime$1, P as isTerminal, R as STORE_ROOT, S as fillFileUrlTemplate, T as MANAGED_ROOT, U as recentReviewGroups, V as loadWorkspace, Y as describeAuthorship, _ as feedbackUrl, a as refreshPrContext, b as EXPLAIN_SIMPLY_PROMPT, c as agentEnvOf, et as agentFor, g as BUILD_VERSION, h as writeServerRecord, i as updateReview, j as allJobs, k as checkFreshness, n as record, nt as AgentUnavailableError, o as isUnchanged, q as touchWorkspace, r as RefreshUnavailableError, s as askCheckout, t as readEvents, u as clearServerRecord, v as runJob, w as isClaimed } from "./log-PmeEgome.js";
|
|
2
2
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
3
3
|
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
4
4
|
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prreviewbuddy",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"description": "PR Review Buddy at the command line: review a branch in an isolated checkout and open the workspace.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"homepage": "https://prreviewbuddy.com",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"bin": {
|
|
9
|
-
"prreviewbuddy": "
|
|
9
|
+
"prreviewbuddy": "dist/main.js"
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"dist",
|