@dev.fast/whiteboard 0.2.1-preview.20261007.102 → 0.2.1-preview.20261007.104
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/{agent-cli-d0YJQNrR.js → agent-cli-DTY727wD.js} +3 -3
- package/dist/agent-cli-Q_EpjIbV.js +2 -0
- package/dist/{authoring-tools-Bvre8hN2.js → authoring-tools-ml8wRIRj.js} +1 -1
- package/dist/build-info.json +1 -1
- package/dist/{cli-runner-CSEH_mQN.js → cli-runner-BApCwwRD.js} +5 -5
- package/dist/cli.js +1 -1
- package/dist/{headless-host-YxYKMcI5.js → headless-host-CUyloTAd.js} +2 -2
- package/dist/{local-data-Dy8AngNb.js → local-data-B_Kfm3Id.js} +58 -8
- package/dist/{mcp-DGKhDPMs.js → mcp-BF2_RoAR.js} +1 -1
- package/dist/{process-error-telemetry-DN5BpZnc.js → process-error-telemetry-Gp3cCIu4.js} +3 -3
- package/dist/profile-BKncMvSE.js +2 -0
- package/dist/{profile-B6jrb2QN.js → profile-CeT6-ZWV.js} +1 -1
- package/dist/{request-origin-BB2TENZ5.js → request-origin-DlHTFCrQ.js} +2 -1
- package/dist/{review-telemetry-2UlsdE4D.js → review-telemetry-Pp4ZsVrh.js} +1 -1
- package/dist/server/desktop-host.js +5 -5
- package/package.json +9 -9
- package/src/review-api/local-data.ts +39 -7
- package/src/review-api/store.ts +4 -0
- package/src/review-api/worktree-events.ts +76 -0
- package/src/review-api/worktree-source.ts +3 -2
- package/src/ui-telemetry-events.ts +1 -0
- package/dist/agent-cli-DdfuiyOF.js +0 -2
- package/dist/profile-D8XSrJYI.js +0 -2
|
@@ -3,8 +3,8 @@ import { a as toolResultText, i as connectReviewInstance, s as ReviewApiError }
|
|
|
3
3
|
import { A as devReviewHome } from "./s3-config-CAxhO9u_.js";
|
|
4
4
|
import { T as traceMachineEnabled } from "./review-home-paths-6zZH-1c9.js";
|
|
5
5
|
import { d as selectReviewInstance, t as REVIEW_INSTANCE_ENV } from "./desktop-discovery-DK2HoBy5.js";
|
|
6
|
-
import { n as reviewSessionAgent } from "./review-telemetry-
|
|
7
|
-
import { n as REVIEW_VIA_HEADER, t as REVIEW_AGENT_HEADER } from "./request-origin-
|
|
6
|
+
import { n as reviewSessionAgent } from "./review-telemetry-Pp4ZsVrh.js";
|
|
7
|
+
import { n as REVIEW_VIA_HEADER, t as REVIEW_AGENT_HEADER } from "./request-origin-DlHTFCrQ.js";
|
|
8
8
|
import { i as publicTool, n as RECOVERY, r as callPublicTool, t as toolFailure } from "./tool-failure-Djeeax6q.js";
|
|
9
9
|
//#region src/review-api/agent-cli.ts
|
|
10
10
|
const reviewAgentCliHelp = "whiteboard api tools (one line per tool)\nwhiteboard api tools <tool-name> (its description and input schema)\nwhiteboard api <tool-name> '<json>'\nwhiteboard api <tool-name> - (read JSON from stdin)\nwhiteboard mcp (stdio MCP adapter; Whiteboard Desktop or whiteboard server start must be running)\nSelect headless state with DEV_REVIEW_SERVER_DIR or whiteboard --state-dir <path> api/mcp.\n";
|
|
@@ -23,7 +23,7 @@ async function runReviewAgentCli(input) {
|
|
|
23
23
|
[REVIEW_AGENT_HEADER]: reviewSessionAgent(env)
|
|
24
24
|
};
|
|
25
25
|
if (mode === "mcp") {
|
|
26
|
-
const { serveReviewMcp } = await import("./mcp-
|
|
26
|
+
const { serveReviewMcp } = await import("./mcp-BF2_RoAR.js");
|
|
27
27
|
await serveReviewMcp(async (key, agentKind) => {
|
|
28
28
|
const connected = await connectReviewInstance(key ? {
|
|
29
29
|
...env,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { g as activityUpdateSchema, h as activityEndSchema, i as commandSchema, m as activityBeginSchema, n as uploadSchema } from "./local-data-
|
|
1
|
+
import { g as activityUpdateSchema, h as activityEndSchema, i as commandSchema, m as activityBeginSchema, n as uploadSchema } from "./local-data-B_Kfm3Id.js";
|
|
2
2
|
import { x as publishedEditSchema, y as pathTargetSchema } from "./stored-document-migration-T9Uj5MkN.js";
|
|
3
3
|
import { t as ReviewInputError } from "./input-error-OLgB_h31.js";
|
|
4
4
|
import { t as findReviewPackageRoot } from "./package-paths-B6-zxvIO.js";
|
package/dist/build-info.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"0.2.1-preview.20261007.
|
|
1
|
+
{"version":"0.2.1-preview.20261007.104","commit":"41906b158c7a3e7cbf8a4bcd4e66a3441006b53b","dirty":true,"builtAt":"2026-10-07T17:19:07.988Z"}
|
|
@@ -9,11 +9,11 @@ import { t as errorMessage } from "./error-message-OtiDonty.js";
|
|
|
9
9
|
import { A as runTraceSessions, D as runTraceAllow, E as traceMachineStatus, G as traceScope, H as resolveTraceCommand, I as traceRepositoryStatus, L as HOSTED_CAPTURE_SCOPE_DESCRIPTION, M as runTraceStoreInfo, O as runTraceDeny, T as traceMachineEnabled, W as traceHomeDir, _ as runTraceRepair, b as runTraceGitHook, c as registerTraceCommands, d as runTraceList$1, f as runTracePull$1, g as runTraceInstallMachine, h as runTraceEnable, j as runTraceStoreDelete, k as runTraceOnboard, l as resolveTraceReadStorage, m as runTraceDisable, p as runTraceShow, u as runTraceBlame, v as runTraceStatus, w as readLegacyCaptureSettings, x as runTraceHook, y as runTraceSync } from "./review-home-paths-6zZH-1c9.js";
|
|
10
10
|
import { i as readReviewPackageVersion, r as readBuildInfo, t as findReviewPackageRoot } from "./package-paths-B6-zxvIO.js";
|
|
11
11
|
import { a as readDefaultReviewInstance, d as selectReviewInstance, f as writeDefaultReviewInstance, i as healthyReviewInstance, l as reviewInstanceStartHint, n as ReviewInstanceUnavailableError, o as readReviewInstances, r as clearDefaultReviewInstance, s as requireHealthyReviewDesktop, t as REVIEW_INSTANCE_ENV, u as reviewInstanceUnavailable } from "./desktop-discovery-DK2HoBy5.js";
|
|
12
|
-
import { t as ReviewTelemetry } from "./review-telemetry-
|
|
12
|
+
import { t as ReviewTelemetry } from "./review-telemetry-Pp4ZsVrh.js";
|
|
13
13
|
import { a as isOwnedShim, f as windowsInstallerCommand, m as connectPrompts, o as pathShimPath, p as scanLegacySkills, t as aliasInstallationToAccount } from "./account-alias-DLE9XZhi.js";
|
|
14
14
|
import { t as fuzzyRank } from "./fuzzy-match-BoAmcyak.js";
|
|
15
15
|
import { n as readReviewServerDiscovery, o as reviewServerStateDir, r as readReviewServerHealth, s as serverNotReady } from "./server-discovery-Dbzn3w6Z.js";
|
|
16
|
-
import { t as reviewAgentCliHelp } from "./agent-cli-
|
|
16
|
+
import { t as reviewAgentCliHelp } from "./agent-cli-DTY727wD.js";
|
|
17
17
|
import { closeSync, existsSync, fstatSync, mkdirSync, mkdtempSync, openSync, readSync, renameSync, writeFileSync } from "node:fs";
|
|
18
18
|
import { realpath } from "node:fs/promises";
|
|
19
19
|
import path from "node:path";
|
|
@@ -4495,7 +4495,7 @@ async function runReviewCli(input) {
|
|
|
4495
4495
|
process.once("SIGINT", stop);
|
|
4496
4496
|
process.once("SIGTERM", stop);
|
|
4497
4497
|
try {
|
|
4498
|
-
const { runHeadlessServer } = await import("./headless-host-
|
|
4498
|
+
const { runHeadlessServer } = await import("./headless-host-CUyloTAd.js");
|
|
4499
4499
|
await runHeadlessServer({
|
|
4500
4500
|
stateDir,
|
|
4501
4501
|
port,
|
|
@@ -4546,7 +4546,7 @@ async function runReviewCli(input) {
|
|
|
4546
4546
|
if (problem) throw new Error(`Cannot tell whether a Whiteboard Desktop is using ${stateDir}: ${problem.message}`);
|
|
4547
4547
|
const inUse = () => /* @__PURE__ */ new Error(`A Whiteboard server is using ${stateDir}. Stop it first, then run whiteboard server reset-id again.`);
|
|
4548
4548
|
if (desktops.instances.some(({ discovery }) => [discovery.appPid, discovery.serverPid].some((pid) => processIsAlive(pid)))) throw inUse();
|
|
4549
|
-
const [{ openReviewProfile }, { withHeadlessServerLock }] = await Promise.all([import("./profile-
|
|
4549
|
+
const [{ openReviewProfile }, { withHeadlessServerLock }] = await Promise.all([import("./profile-BKncMvSE.js"), import("./headless-host-CUyloTAd.js")]);
|
|
4550
4550
|
const reset = await withHeadlessServerLock(await realpath(stateDir), async () => {
|
|
4551
4551
|
const local = await openReviewProfile(stateDir, { manageWorkspaces: false });
|
|
4552
4552
|
try {
|
|
@@ -4774,7 +4774,7 @@ async function runReviewCli(input) {
|
|
|
4774
4774
|
return commands;
|
|
4775
4775
|
} });
|
|
4776
4776
|
for (const [name, description] of [["api", "Call a JSON review authoring tool on the running server"], ["mcp", "Serve the JSON review authoring tools over stdio MCP"]]) configureOutput(program.command(name).description(description).argument("[args...]", "tool name and JSON input").allowUnknownOption().allowExcessArguments().helpOption(false).passThroughOptions().addHelpText("after", `\n${reviewAgentCliHelp}`), "plain").action(async (args) => {
|
|
4777
|
-
const { runReviewAgentCli } = await import("./agent-cli-
|
|
4777
|
+
const { runReviewAgentCli } = await import("./agent-cli-Q_EpjIbV.js");
|
|
4778
4778
|
state.exitCode = await runReviewAgentCli({
|
|
4779
4779
|
...input,
|
|
4780
4780
|
env: authoringEnv(),
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { p as isObjectValue } from "./src-X9phtB2j.js";
|
|
2
2
|
import { O as withFileLock, P as writePrivateJsonAtomic } from "./s3-config-CAxhO9u_.js";
|
|
3
3
|
import "./review-home-paths-6zZH-1c9.js";
|
|
4
|
-
import { t as openReviewProfile } from "./profile-
|
|
5
|
-
import { i as createWhiteboardCore, l as createNodeRequestListener, m as migrateDiffrConfig, n as installProcessErrorTelemetry, p as GlobalReviewDesktopVerbRelay, t as drainServerCrashReport } from "./process-error-telemetry-
|
|
4
|
+
import { t as openReviewProfile } from "./profile-CeT6-ZWV.js";
|
|
5
|
+
import { i as createWhiteboardCore, l as createNodeRequestListener, m as migrateDiffrConfig, n as installProcessErrorTelemetry, p as GlobalReviewDesktopVerbRelay, t as drainServerCrashReport } from "./process-error-telemetry-Gp3cCIu4.js";
|
|
6
6
|
import { i as reviewServerDiscoveryPath, t as headlessServerLockPath } from "./server-discovery-Dbzn3w6Z.js";
|
|
7
7
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
8
8
|
import { mkdir, realpath, rm } from "node:fs/promises";
|
|
@@ -2409,6 +2409,7 @@ var ReviewStore = class {
|
|
|
2409
2409
|
repositoryGroups = /* @__PURE__ */ new Map();
|
|
2410
2410
|
repositoryGroup(root) {
|
|
2411
2411
|
if (this.repositoryGroups.has(root)) return this.repositoryGroups.get(root);
|
|
2412
|
+
if (!existsSync(root)) return void 0;
|
|
2412
2413
|
const context = resolveRepoContextSync(root);
|
|
2413
2414
|
if (!context) return void 0;
|
|
2414
2415
|
const group = context.githubSlug ? {
|
|
@@ -3332,6 +3333,47 @@ var ReviewWorkspaces = class {
|
|
|
3332
3333
|
}
|
|
3333
3334
|
};
|
|
3334
3335
|
//#endregion
|
|
3336
|
+
//#region src/review-api/worktree-events.ts
|
|
3337
|
+
const exec$1 = promisify(execFile);
|
|
3338
|
+
const normalize = (name) => name.replaceAll("\\", "/").normalize("NFC");
|
|
3339
|
+
const parent = (file) => file.slice(0, Math.max(0, file.lastIndexOf("/")));
|
|
3340
|
+
/** Directories that hold tracked files, the root as "". */
|
|
3341
|
+
function trackedDirectories(files) {
|
|
3342
|
+
const directories = /* @__PURE__ */ new Set([""]);
|
|
3343
|
+
for (const file of files) for (let dir = parent(normalize(file)); !directories.has(dir); dir = parent(dir)) directories.add(dir);
|
|
3344
|
+
return directories;
|
|
3345
|
+
}
|
|
3346
|
+
/** Only a tracked directory's entries can change an inspection. */
|
|
3347
|
+
function rootEventMatters(name, tracked) {
|
|
3348
|
+
const file = normalize(name);
|
|
3349
|
+
if (file === ".git" || file.startsWith(".git/")) return false;
|
|
3350
|
+
return !tracked || tracked.has(parent(file));
|
|
3351
|
+
}
|
|
3352
|
+
const CHECKOUT_STATE = /^(?:index|[A-Z_]+|(?:rebase-merge|rebase-apply|sequencer|refs\/(?:bisect|worktree|rewritten))(?:\/.*)?)$/;
|
|
3353
|
+
/** Objects, reflogs, locks and other checkouts' state cannot change this one. */
|
|
3354
|
+
function gitEventMatters(name, prefix) {
|
|
3355
|
+
const file = normalize(name);
|
|
3356
|
+
if (file.endsWith(".lock") || /^(?:objects|logs)\//.test(file)) return false;
|
|
3357
|
+
if (file.startsWith("worktrees/")) return file.startsWith(`${prefix}/`) && !file.startsWith(`${prefix}/logs/`);
|
|
3358
|
+
return !prefix || !CHECKOUT_STATE.test(file);
|
|
3359
|
+
}
|
|
3360
|
+
/** Where this checkout's git directory sits in the common one: "" for the main checkout. */
|
|
3361
|
+
async function gitDirectoryPrefix(rootPath, common) {
|
|
3362
|
+
try {
|
|
3363
|
+
const { stdout } = await exec$1("git", [
|
|
3364
|
+
"-C",
|
|
3365
|
+
rootPath,
|
|
3366
|
+
"rev-parse",
|
|
3367
|
+
"--path-format=absolute",
|
|
3368
|
+
"--git-dir"
|
|
3369
|
+
]);
|
|
3370
|
+
const prefix = normalize(relative(common, stdout.trim()));
|
|
3371
|
+
return isAbsolute(prefix) || prefix.startsWith("..") ? null : prefix;
|
|
3372
|
+
} catch {
|
|
3373
|
+
return null;
|
|
3374
|
+
}
|
|
3375
|
+
}
|
|
3376
|
+
//#endregion
|
|
3335
3377
|
//#region src/review-api/worktree-source.ts
|
|
3336
3378
|
const { lstat: lstat$1, readFile: readFile$1, readlink, realpath: realpath$1 } = checkoutFs;
|
|
3337
3379
|
const exec = promisify(execFile);
|
|
@@ -3403,7 +3445,8 @@ async function untrackedFileCount(vcs) {
|
|
|
3403
3445
|
async function inspectWorktree(repositoryId, vcs) {
|
|
3404
3446
|
const commit = (await vcs.resolveRevision(vcs.kind === "jj" ? "@" : "HEAD"))?.commit ?? "empty-worktree-baseline";
|
|
3405
3447
|
const hash = createHash("sha256").update(`${repositoryId}\0${commit}`);
|
|
3406
|
-
|
|
3448
|
+
const files = await workingFiles(vcs);
|
|
3449
|
+
for (const file of files) try {
|
|
3407
3450
|
const info = await lstat$1(resolve(vcs.rootPath, file), { bigint: true });
|
|
3408
3451
|
hash.update(`\0${file}\0${info.ino}:${info.size}:${info.mode}:${info.mtimeNs}:${info.ctimeNs}`);
|
|
3409
3452
|
} catch (error) {
|
|
@@ -3411,7 +3454,8 @@ async function inspectWorktree(repositoryId, vcs) {
|
|
|
3411
3454
|
}
|
|
3412
3455
|
return {
|
|
3413
3456
|
revision: hash.digest("hex"),
|
|
3414
|
-
commit
|
|
3457
|
+
commit,
|
|
3458
|
+
files
|
|
3415
3459
|
};
|
|
3416
3460
|
}
|
|
3417
3461
|
async function readWorkingFile(root, file) {
|
|
@@ -3732,12 +3776,13 @@ var LocalReviewData = class {
|
|
|
3732
3776
|
};
|
|
3733
3777
|
this.worktrees.set(repositoryId, entry);
|
|
3734
3778
|
const state = entry;
|
|
3735
|
-
const roots = /* @__PURE__ */ new Set([vcs.rootPath]);
|
|
3736
3779
|
const common = await gitCommonDir(vcs.rootPath);
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3780
|
+
const prefix = vcs.kind === "git" && common ? await gitDirectoryPrefix(vcs.rootPath, common) : null;
|
|
3781
|
+
const roots = /* @__PURE__ */ new Map([[vcs.rootPath, (name) => prefix === null || rootEventMatters(name, state.tracked)]]);
|
|
3782
|
+
if (common) roots.set(common, (name) => prefix === null || gitEventMatters(name, prefix));
|
|
3783
|
+
for (const [root, matters] of roots) try {
|
|
3784
|
+
const watcher = (this.options.watch ?? watch)(root, { recursive: true }, (_event, name) => {
|
|
3785
|
+
if (name === null || matters(String(name))) state.epoch++;
|
|
3741
3786
|
});
|
|
3742
3787
|
watcher.on("error", () => {
|
|
3743
3788
|
state.epoch++;
|
|
@@ -3756,8 +3801,9 @@ var LocalReviewData = class {
|
|
|
3756
3801
|
forks: entry.forks
|
|
3757
3802
|
};
|
|
3758
3803
|
const epoch = entry.epoch;
|
|
3759
|
-
const inspected = await inspectWorktree(repositoryId, vcs);
|
|
3804
|
+
const { files, ...inspected } = await inspectWorktree(repositoryId, vcs);
|
|
3760
3805
|
entry.inspection = inspected;
|
|
3806
|
+
entry.tracked = trackedDirectories(files);
|
|
3761
3807
|
entry.inspectedEpoch = epoch;
|
|
3762
3808
|
entry.forks = /* @__PURE__ */ new Map();
|
|
3763
3809
|
return {
|
|
@@ -3786,6 +3832,10 @@ var LocalReviewData = class {
|
|
|
3786
3832
|
this.closeReader(repositoryId);
|
|
3787
3833
|
this.forgetWorktree(repositoryId);
|
|
3788
3834
|
const rootPath = this.store.repositoryPath(repositoryId);
|
|
3835
|
+
if (!existsSync(rootPath)) {
|
|
3836
|
+
this.repositories.delete(repositoryId);
|
|
3837
|
+
return Promise.resolve(null);
|
|
3838
|
+
}
|
|
3789
3839
|
const forget = () => {
|
|
3790
3840
|
this.repositories.delete(repositoryId);
|
|
3791
3841
|
this.closeReader(repositoryId);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as toolResultText, s as ReviewApiError } from "./agent-client-DoaODH6I.js";
|
|
2
2
|
import { t as ReviewInputError } from "./input-error-OLgB_h31.js";
|
|
3
|
-
import { n as REVIEW_STATUS_TOOL, t as authoringTools } from "./authoring-tools-
|
|
3
|
+
import { n as REVIEW_STATUS_TOOL, t as authoringTools } from "./authoring-tools-ml8wRIRj.js";
|
|
4
4
|
import { i as publicTool, n as RECOVERY, r as callPublicTool, t as toolFailure } from "./tool-failure-Djeeax6q.js";
|
|
5
5
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
6
6
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { c as jsonString, m as isStringValue, n as isJsonObject, u as parseJsonText } from "./src-X9phtB2j.js";
|
|
2
2
|
import { a as sharedReviewId, c as verifyShareRepository, d as StreamLimitError, f as readBoundedStream, l as exportShare, m as shareIdSchema, n as ShareClient, p as parseShareLink, r as SharePreflightError, s as readShareRepository, t as ShareAuthError, u as validateShareSources } from "./client-D01H2KOV.js";
|
|
3
|
-
import { _ as invalidateStructuralComparisons, a as inspectSnapshot, c as askAgentIds, d as askQuestionSchema, f as AgentSelectionSchema, i as commandSchema, l as askChoiceKinds, p as selectionMarkdown, r as SCRATCHPAD_ID, s as applyAskChange, u as askPicksSchema, v as diffrExecutable, y as diffrMissingError } from "./local-data-
|
|
3
|
+
import { _ as invalidateStructuralComparisons, a as inspectSnapshot, c as askAgentIds, d as askQuestionSchema, f as AgentSelectionSchema, i as commandSchema, l as askChoiceKinds, p as selectionMarkdown, r as SCRATCHPAD_ID, s as applyAskChange, u as askPicksSchema, v as diffrExecutable, y as diffrMissingError } from "./local-data-B_Kfm3Id.js";
|
|
4
4
|
import { d as REVIEW_CLIENT_REMOTE, i as parseReviewVerbRequest, r as parseReviewDesktopVerbResult, u as REVIEW_CLIENT_HEADER, v as reviewDiffrSummarizerInputSchema, y as decodeStructuralDiffEvent } from "./src-DHiDJQDy.js";
|
|
5
5
|
import { C as TraceStorageDeniedError, G as readStoreAuth, H as DEFAULT_STORE_ORIGIN, U as clearStoreAuth, W as openUrlInBrowser, _ as isTraceStorageConfigured, b as selectTraceStorage, o as listReviewTraceSessions, q as runStoreLogin, s as loadReviewAgentTrace, y as resolveTraceStorage } from "./review-agent-traces-DNJFYzc8.js";
|
|
6
6
|
import { $ as unionIntervals, G as selectionKey, H as comparisonKey, I as fileLineRangeSchema, J as coverageSources, N as lensSelections, Q as subtractIntervals, T as selectionReferences, U as formatAnchor, V as anchorSelection, W as resolveDiffSelection, Y as emptyCoverage, Z as scopedCoverage, h as elements, k as UNCATEGORIZED_LENS_ID, u as anchorPins } from "./stored-document-migration-T9Uj5MkN.js";
|
|
@@ -9,8 +9,8 @@ import { A as devReviewHome, h as TraceConfigurationError, i as isS3MockMode } f
|
|
|
9
9
|
import { t as errorMessage } from "./error-message-OtiDonty.js";
|
|
10
10
|
import { T as traceMachineEnabled } from "./review-home-paths-6zZH-1c9.js";
|
|
11
11
|
import { i as readReviewPackageVersion, n as readBuildCommit } from "./package-paths-B6-zxvIO.js";
|
|
12
|
-
import { a as REVIEW_APP_SESSION_ID_HEADER, c as sanitizeUiTelemetryEvent, i as BUNDLE_FRAME_PATTERN, l as cleanTelemetryText, r as reviewRequestOrigin, s as isReportableCleanedMessage } from "./request-origin-
|
|
13
|
-
import { a as scratchpadAvailable, c as readQuerySchemas, i as renderInstructions, o as inspectQuerySchema, r as instructionsQuerySchema, s as queryAnchor, t as authoringTools } from "./authoring-tools-
|
|
12
|
+
import { a as REVIEW_APP_SESSION_ID_HEADER, c as sanitizeUiTelemetryEvent, i as BUNDLE_FRAME_PATTERN, l as cleanTelemetryText, r as reviewRequestOrigin, s as isReportableCleanedMessage } from "./request-origin-DlHTFCrQ.js";
|
|
13
|
+
import { a as scratchpadAvailable, c as readQuerySchemas, i as renderInstructions, o as inspectQuerySchema, r as instructionsQuerySchema, s as queryAnchor, t as authoringTools } from "./authoring-tools-ml8wRIRj.js";
|
|
14
14
|
import { t as fuzzyRank } from "./fuzzy-match-BoAmcyak.js";
|
|
15
15
|
import { createRequire } from "node:module";
|
|
16
16
|
import crypto$1, { createHash, randomUUID } from "node:crypto";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { o as initializeReviewStoreSchema, t as openLocalReviewStore } from "./local-data-
|
|
1
|
+
import { o as initializeReviewStoreSchema, t as openLocalReviewStore } from "./local-data-B_Kfm3Id.js";
|
|
2
2
|
import { O as withFileLock } from "./s3-config-CAxhO9u_.js";
|
|
3
3
|
import "./review-home-paths-6zZH-1c9.js";
|
|
4
4
|
import { access, mkdir } from "node:fs/promises";
|
|
@@ -3,7 +3,7 @@ import "./src-DHiDJQDy.js";
|
|
|
3
3
|
import { A as devReviewHome, D as processIsAlive, M as writeFileAtomic, O as withFileLock } from "./s3-config-CAxhO9u_.js";
|
|
4
4
|
import "./review-home-paths-6zZH-1c9.js";
|
|
5
5
|
import { i as readReviewPackageVersion, t as findReviewPackageRoot } from "./package-paths-B6-zxvIO.js";
|
|
6
|
-
import "./request-origin-
|
|
6
|
+
import "./request-origin-DlHTFCrQ.js";
|
|
7
7
|
import { createHmac, randomUUID } from "node:crypto";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
import { existsSync, readFileSync, rmSync } from "node:fs";
|
|
@@ -9,12 +9,12 @@ import { A as devReviewHome, P as writePrivateJsonAtomic } from "../s3-config-CA
|
|
|
9
9
|
import { U as shellQuote, i as reviewInstanceDiscoveryPath, o as reviewLegacyDiscoveryPath } from "../review-home-paths-6zZH-1c9.js";
|
|
10
10
|
import { i as readReviewPackageVersion, t as findReviewPackageRoot } from "../package-paths-B6-zxvIO.js";
|
|
11
11
|
import { c as reviewInstanceIdentity, t as REVIEW_INSTANCE_ENV } from "../desktop-discovery-DK2HoBy5.js";
|
|
12
|
-
import { t as openReviewProfile } from "../profile-
|
|
13
|
-
import { r as reviewTelemetryChannel, t as ReviewTelemetry } from "../review-telemetry-
|
|
14
|
-
import { o as REVIEW_TELEMETRY_TABS } from "../request-origin-
|
|
12
|
+
import { t as openReviewProfile } from "../profile-CeT6-ZWV.js";
|
|
13
|
+
import { r as reviewTelemetryChannel, t as ReviewTelemetry } from "../review-telemetry-Pp4ZsVrh.js";
|
|
14
|
+
import { o as REVIEW_TELEMETRY_TABS } from "../request-origin-DlHTFCrQ.js";
|
|
15
15
|
import { c as removeLegacyReviewSkills, d as skipCliInstall, i as finishCliInstallUpdate, l as resetCliInstall, n as applyCliInstall, r as declineCliInstall, s as removeCliInstall, t as aliasInstallationToAccount, u as resolveCliInstallStatus } from "../account-alias-DLE9XZhi.js";
|
|
16
|
-
import { _ as setDiffrConfigValue, a as serverJson, c as recordClientError, d as HttpJsonError, f as ReviewServerError, g as saveDiffrSummarizer, h as readDiffrConfig, i as createWhiteboardCore, l as createNodeRequestListener, m as migrateDiffrConfig, n as installProcessErrorTelemetry, o as captureSanitizedUiTelemetry, p as GlobalReviewDesktopVerbRelay, r as serverCrashReportPath, s as clientErrorsForSession, t as drainServerCrashReport, u as readBoundedRequestJson, v as testDiffrSummarizer } from "../process-error-telemetry-
|
|
17
|
-
import { c as readQuerySchemas } from "../authoring-tools-
|
|
16
|
+
import { _ as setDiffrConfigValue, a as serverJson, c as recordClientError, d as HttpJsonError, f as ReviewServerError, g as saveDiffrSummarizer, h as readDiffrConfig, i as createWhiteboardCore, l as createNodeRequestListener, m as migrateDiffrConfig, n as installProcessErrorTelemetry, o as captureSanitizedUiTelemetry, p as GlobalReviewDesktopVerbRelay, r as serverCrashReportPath, s as clientErrorsForSession, t as drainServerCrashReport, u as readBoundedRequestJson, v as testDiffrSummarizer } from "../process-error-telemetry-Gp3cCIu4.js";
|
|
17
|
+
import { c as readQuerySchemas } from "../authoring-tools-ml8wRIRj.js";
|
|
18
18
|
import crypto, { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
19
19
|
import { z } from "zod";
|
|
20
20
|
import fs, { existsSync } from "node:fs";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dev.fast/whiteboard",
|
|
3
|
-
"version": "0.2.1-preview.20261007.
|
|
3
|
+
"version": "0.2.1-preview.20261007.104",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"@agentclientprotocol/sdk": "1.5.1",
|
|
46
46
|
"@dev.fast/diffr": "0.1.14",
|
|
47
47
|
"@hono/node-server": "2.0.12",
|
|
48
|
-
"@img/sharp-wasm32": "0.35.
|
|
49
|
-
"@modelcontextprotocol/sdk": "1.
|
|
48
|
+
"@img/sharp-wasm32": "0.35.5",
|
|
49
|
+
"@modelcontextprotocol/sdk": "1.31.0",
|
|
50
50
|
"commander": "14.0.3",
|
|
51
51
|
"fuzzysort": "4.0.2",
|
|
52
52
|
"hono": "4.13.7",
|
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
"pi-acp": "0.0.34",
|
|
58
58
|
"pino": "10.3.1",
|
|
59
59
|
"semver": "7.8.5",
|
|
60
|
-
"sharp": "0.35.
|
|
61
|
-
"smol-toml": "1.
|
|
60
|
+
"sharp": "0.35.5",
|
|
61
|
+
"smol-toml": "1.9.0",
|
|
62
62
|
"zod": "4.6.5"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
@@ -72,10 +72,10 @@
|
|
|
72
72
|
"typescript": "6.0.3",
|
|
73
73
|
"vitest": "4.1.11",
|
|
74
74
|
"@dev.fast/json": "0.0.0",
|
|
75
|
-
"@dev.fast/
|
|
76
|
-
"@dev.fast/trace-protocol": "0.5.0",
|
|
75
|
+
"@dev.fast/review-protocol": "0.0.0",
|
|
77
76
|
"@dev.fast/review-share-protocol": "0.1.2",
|
|
78
|
-
"@dev.fast/
|
|
77
|
+
"@dev.fast/trace-core": "0.0.0",
|
|
78
|
+
"@dev.fast/trace-protocol": "0.5.0"
|
|
79
79
|
},
|
|
80
80
|
"engines": {
|
|
81
81
|
"node": ">=24 <25"
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"repo": "devdotfast/review",
|
|
86
86
|
"docs": "packages/review/instructions/authoring.md"
|
|
87
87
|
},
|
|
88
|
-
"gitHead": "
|
|
88
|
+
"gitHead": "41906b158c7a3e7cbf8a4bcd4e66a3441006b53b",
|
|
89
89
|
"scripts": {
|
|
90
90
|
"prebuild": "pnpm run build:workspace-deps",
|
|
91
91
|
"build": "node --max-old-space-size=8192 node_modules/tsdown/dist/run.mjs",
|
|
@@ -87,6 +87,12 @@ import {
|
|
|
87
87
|
} from "./store.js";
|
|
88
88
|
import { traceSchema } from "./trace-schema.js";
|
|
89
89
|
import { ReviewWorkspaces } from "./workspaces.js";
|
|
90
|
+
import {
|
|
91
|
+
gitDirectoryPrefix,
|
|
92
|
+
gitEventMatters,
|
|
93
|
+
rootEventMatters,
|
|
94
|
+
trackedDirectories,
|
|
95
|
+
} from "./worktree-events.js";
|
|
90
96
|
import {
|
|
91
97
|
EMPTY_SOURCE,
|
|
92
98
|
inspectWorktree,
|
|
@@ -636,7 +642,8 @@ export class LocalReviewData {
|
|
|
636
642
|
inspectedEpoch: number;
|
|
637
643
|
watchers: FSWatcher[];
|
|
638
644
|
healthy: boolean;
|
|
639
|
-
inspection?: Awaited<ReturnType<typeof inspectWorktree
|
|
645
|
+
inspection?: Omit<Awaited<ReturnType<typeof inspectWorktree>>, "files">;
|
|
646
|
+
tracked?: Set<string>;
|
|
640
647
|
/** Fork points by base ref, valid for the inspected epoch. */
|
|
641
648
|
forks: Map<string, Promise<{ ref: string; commit: string }>>;
|
|
642
649
|
}
|
|
@@ -662,18 +669,35 @@ export class LocalReviewData {
|
|
|
662
669
|
};
|
|
663
670
|
this.worktrees.set(repositoryId, entry);
|
|
664
671
|
const state = entry;
|
|
665
|
-
const roots = new Set([vcs.rootPath]);
|
|
666
672
|
const common = await gitCommonDir(vcs.rootPath);
|
|
667
673
|
|
|
668
|
-
|
|
674
|
+
// jj snapshots untracked files, so every event can matter there.
|
|
675
|
+
const prefix =
|
|
676
|
+
vcs.kind === "git" && common
|
|
677
|
+
? await gitDirectoryPrefix(vcs.rootPath, common)
|
|
678
|
+
: null;
|
|
679
|
+
|
|
680
|
+
const roots = new Map([
|
|
681
|
+
[
|
|
682
|
+
vcs.rootPath,
|
|
683
|
+
(name: string) =>
|
|
684
|
+
prefix === null || rootEventMatters(name, state.tracked),
|
|
685
|
+
],
|
|
686
|
+
]);
|
|
687
|
+
|
|
688
|
+
if (common)
|
|
689
|
+
roots.set(
|
|
690
|
+
common,
|
|
691
|
+
(name) => prefix === null || gitEventMatters(name, prefix),
|
|
692
|
+
);
|
|
669
693
|
|
|
670
|
-
for (const root of roots) {
|
|
694
|
+
for (const [root, matters] of roots) {
|
|
671
695
|
try {
|
|
672
696
|
const watcher = (this.options.watch ?? watch)(
|
|
673
697
|
root,
|
|
674
698
|
{ recursive: true },
|
|
675
|
-
() => {
|
|
676
|
-
state.epoch++;
|
|
699
|
+
(_event, name) => {
|
|
700
|
+
if (name === null || matters(String(name))) state.epoch++;
|
|
677
701
|
},
|
|
678
702
|
);
|
|
679
703
|
|
|
@@ -700,8 +724,9 @@ export class LocalReviewData {
|
|
|
700
724
|
return { ...entry.inspection, forks: entry.forks };
|
|
701
725
|
|
|
702
726
|
const epoch = entry.epoch;
|
|
703
|
-
const inspected = await inspectWorktree(repositoryId, vcs);
|
|
727
|
+
const { files, ...inspected } = await inspectWorktree(repositoryId, vcs);
|
|
704
728
|
entry.inspection = inspected;
|
|
729
|
+
entry.tracked = trackedDirectories(files);
|
|
705
730
|
entry.inspectedEpoch = epoch;
|
|
706
731
|
entry.forks = new Map();
|
|
707
732
|
|
|
@@ -738,6 +763,13 @@ export class LocalReviewData {
|
|
|
738
763
|
this.forgetWorktree(repositoryId);
|
|
739
764
|
const rootPath = this.store.repositoryPath(repositoryId);
|
|
740
765
|
|
|
766
|
+
// Detection in a missing directory spawns and fails as "tools missing".
|
|
767
|
+
if (!existsSync(rootPath)) {
|
|
768
|
+
this.repositories.delete(repositoryId);
|
|
769
|
+
|
|
770
|
+
return Promise.resolve(null);
|
|
771
|
+
}
|
|
772
|
+
|
|
741
773
|
const forget = () => {
|
|
742
774
|
this.repositories.delete(repositoryId);
|
|
743
775
|
this.closeReader(repositoryId);
|
package/src/review-api/store.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { DatabaseSync } from "node:sqlite";
|
|
4
5
|
|
|
@@ -527,6 +528,9 @@ export class ReviewStore {
|
|
|
527
528
|
private repositoryGroup(root: string): ReviewApiSummary["repositoryGroup"] {
|
|
528
529
|
if (this.repositoryGroups.has(root)) return this.repositoryGroups.get(root);
|
|
529
530
|
|
|
531
|
+
// Resolving a missing checkout would spawn on every listing.
|
|
532
|
+
if (!existsSync(root)) return undefined;
|
|
533
|
+
|
|
530
534
|
const context = resolveRepoContextSync(root);
|
|
531
535
|
|
|
532
536
|
if (!context) return undefined;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { isAbsolute, relative } from "node:path";
|
|
3
|
+
import { promisify } from "node:util";
|
|
4
|
+
|
|
5
|
+
const exec = promisify(execFile);
|
|
6
|
+
|
|
7
|
+
const normalize = (name: string) => name.replaceAll("\\", "/").normalize("NFC");
|
|
8
|
+
|
|
9
|
+
const parent = (file: string) =>
|
|
10
|
+
file.slice(0, Math.max(0, file.lastIndexOf("/")));
|
|
11
|
+
|
|
12
|
+
/** Directories that hold tracked files, the root as "". */
|
|
13
|
+
export function trackedDirectories(files: readonly string[]): Set<string> {
|
|
14
|
+
const directories = new Set([""]);
|
|
15
|
+
|
|
16
|
+
for (const file of files)
|
|
17
|
+
for (
|
|
18
|
+
let dir = parent(normalize(file));
|
|
19
|
+
!directories.has(dir);
|
|
20
|
+
dir = parent(dir)
|
|
21
|
+
)
|
|
22
|
+
directories.add(dir);
|
|
23
|
+
|
|
24
|
+
return directories;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Only a tracked directory's entries can change an inspection. */
|
|
28
|
+
export function rootEventMatters(
|
|
29
|
+
name: string,
|
|
30
|
+
tracked: Set<string> | undefined,
|
|
31
|
+
): boolean {
|
|
32
|
+
const file = normalize(name);
|
|
33
|
+
|
|
34
|
+
// The git directory has its own watcher.
|
|
35
|
+
if (file === ".git" || file.startsWith(".git/")) return false;
|
|
36
|
+
|
|
37
|
+
return !tracked || tracked.has(parent(file));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// A checkout's own state, per gitrepository-layout(5).
|
|
41
|
+
const CHECKOUT_STATE =
|
|
42
|
+
/^(?:index|[A-Z_]+|(?:rebase-merge|rebase-apply|sequencer|refs\/(?:bisect|worktree|rewritten))(?:\/.*)?)$/;
|
|
43
|
+
|
|
44
|
+
/** Objects, reflogs, locks and other checkouts' state cannot change this one. */
|
|
45
|
+
export function gitEventMatters(name: string, prefix: string): boolean {
|
|
46
|
+
const file = normalize(name);
|
|
47
|
+
|
|
48
|
+
if (file.endsWith(".lock") || /^(?:objects|logs)\//.test(file)) return false;
|
|
49
|
+
|
|
50
|
+
if (file.startsWith("worktrees/"))
|
|
51
|
+
return file.startsWith(`${prefix}/`) && !file.startsWith(`${prefix}/logs/`);
|
|
52
|
+
|
|
53
|
+
return !prefix || !CHECKOUT_STATE.test(file);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Where this checkout's git directory sits in the common one: "" for the main checkout. */
|
|
57
|
+
export async function gitDirectoryPrefix(
|
|
58
|
+
rootPath: string,
|
|
59
|
+
common: string,
|
|
60
|
+
): Promise<string | null> {
|
|
61
|
+
try {
|
|
62
|
+
const { stdout } = await exec("git", [
|
|
63
|
+
"-C",
|
|
64
|
+
rootPath,
|
|
65
|
+
"rev-parse",
|
|
66
|
+
"--path-format=absolute",
|
|
67
|
+
"--git-dir",
|
|
68
|
+
]);
|
|
69
|
+
|
|
70
|
+
const prefix = normalize(relative(common, stdout.trim()));
|
|
71
|
+
|
|
72
|
+
return isAbsolute(prefix) || prefix.startsWith("..") ? null : prefix;
|
|
73
|
+
} catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -127,8 +127,9 @@ export async function inspectWorktree(repositoryId: string, vcs: LocalVcs) {
|
|
|
127
127
|
EMPTY_SOURCE;
|
|
128
128
|
|
|
129
129
|
const hash = createHash("sha256").update(`${repositoryId}\0${commit}`);
|
|
130
|
+
const files = await workingFiles(vcs);
|
|
130
131
|
|
|
131
|
-
for (const file of
|
|
132
|
+
for (const file of files) {
|
|
132
133
|
try {
|
|
133
134
|
const info = await lstat(resolve(vcs.rootPath, file), { bigint: true });
|
|
134
135
|
hash.update(
|
|
@@ -139,7 +140,7 @@ export async function inspectWorktree(repositoryId: string, vcs: LocalVcs) {
|
|
|
139
140
|
}
|
|
140
141
|
}
|
|
141
142
|
|
|
142
|
-
return { revision: hash.digest("hex"), commit };
|
|
143
|
+
return { revision: hash.digest("hex"), commit, files };
|
|
143
144
|
}
|
|
144
145
|
|
|
145
146
|
export async function readWorkingFile(
|
package/dist/profile-D8XSrJYI.js
DELETED