@dev.fast/whiteboard 0.5.2-preview.20261104.146 → 0.5.2-preview.20261109.148
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/{account-alias-BlYamXAG.js → account-alias-Cs5YqXRj.js} +5 -5
- package/dist/agent-cli-DdUAmdca.js +2 -0
- package/dist/{agent-cli-D7fF5xmm.js → agent-cli-a5J-juuu.js} +8 -8
- package/dist/{agent-client-BCEbSPWU.js → agent-client-CgnEo6lf.js} +4 -4
- package/dist/{authoring-tools-CkfxTVJm.js → authoring-tools-BgZvnbjN.js} +3 -3
- package/dist/{background-server-CwToVN1g.js → background-server-D8SaPvuC.js} +1 -1
- package/dist/{background-server-BraP8pJ9.js → background-server-DHEcsFwH.js} +4 -4
- package/dist/build-info.json +1 -1
- package/dist/{cli-BpadBaGU.js → cli-Bq5zVqlc.js} +1 -1
- package/dist/{cli-runner-BebYF50a.js → cli-runner-hL2efcxb.js} +21 -21
- package/dist/cli.js +2 -2
- package/dist/{fuzzy-match-CxcsLQGx.js → fuzzy-match-DNyQDN3P.js} +3 -3
- package/dist/{headless-host-cLipIufH.js → headless-host-CGyfb5mS.js} +1 -1
- package/dist/{headless-host-FAlbekFD.js → headless-host-bb09yVkX.js} +18 -16
- package/dist/{import-CZ1958L4.js → import-_XAsWqen.js} +25 -140
- package/dist/{local-data-DdFkxFK_.js → local-data-ZQIkF5k1.js} +83 -13
- package/dist/{mcp-Claiy9xE.js → mcp-B-J8P5xm.js} +4 -4
- package/dist/{package-paths-Dk7MOXxN.js → package-paths-wobHueCx.js} +1 -1
- package/dist/profile-Bi2SbpSI.js +2 -0
- package/dist/{profile-Bsgzi9PA.js → profile-D-SbO3p9.js} +2 -2
- package/dist/{remote-attach-LGTpwpUv.js → remote-attach-DyIESbbf.js} +4 -4
- package/dist/{remote-extensions-BvV29_gk.js → remote-extensions-BHHFPyYW.js} +1 -1
- package/dist/{remote-extensions-L95HNwIH.js → remote-extensions-gTMcRBg-.js} +2 -2
- package/dist/{remote-language-server-BAznkpeu.js → remote-language-server-Pp261dqJ.js} +4 -4
- package/dist/{remote-uninstall-CLP79Cuk.js → remote-uninstall-D_hSuBik.js} +5 -5
- package/dist/{request-origin-D6B-zrL8.js → request-origin-ENYd0Ymr.js} +4 -3
- package/dist/{review-app-launcher-tTe8bTwg.js → review-app-launcher-DR5vYGEl.js} +2 -2
- package/dist/{review-home-paths-BmZX2qiz.js → review-home-paths-B8909D07.js} +19 -19
- package/dist/{review-telemetry-DACDMfqq.js → review-telemetry-CxNvwdDS.js} +4 -4
- package/dist/server/desktop-host.js +13 -13
- package/dist/{server-discovery-CV5qf1J8.js → server-discovery-Fme7f3fb.js} +2 -2
- package/dist/sharing/index.d.ts +21 -21
- package/dist/sharing/index.js +1 -1
- package/dist/{src-CrrW7lcY.js → src-B-91Rd2d.js} +1 -0
- package/dist/{src-BQDlJXkG.js → src-BPrngiWX.js} +1806 -1
- package/dist/{stored-document-migration-D1wK4yID.js → stored-document-migration-BQcUyXO8.js} +4 -158
- package/dist/{thread-state-WTqSborE.js → thread-state-Jxoh1hde.js} +1 -1
- package/dist/{tool-failure-YOFGHJCZ.js → tool-failure-Cgjidoud.js} +6 -6
- package/package.json +5 -6
- package/src/review-api/comparison-coverage.ts +8 -23
- package/src/review-api/http.ts +20 -16
- package/src/review-api/review-progress.ts +40 -126
- package/src/review-api/store.ts +4 -6
- package/src/software-map-diff-counts.ts +4 -2
- package/src/ui-telemetry-events.ts +1 -0
- package/src/viewed-coverage.ts +9 -252
- package/dist/agent-cli-DLibAL4u.js +0 -2
- package/dist/profile-BxdzBxHW.js +0 -2
- package/src/review-api/file-lenses.ts +0 -125
- package/src/review-api/lens-alignment.ts +0 -52
- package/src/unified-diff.ts +0 -71
- package/dist/{s3-CsG2EWED.js → s3-d8RGPKwt.js} +1 -1
package/dist/{stored-document-migration-D1wK4yID.js → stored-document-migration-BQcUyXO8.js}
RENAMED
|
@@ -1,167 +1,13 @@
|
|
|
1
1
|
import { C as renderVcsArgs, v as parseGitRemote, w as runVcs } from "./src-Y30gweiK.js";
|
|
2
2
|
import { d as isBooleanValue, f as isNumberValue, l as jsonValueSchema, m as isStringValue, n as isJsonObject } from "./src-X9phtB2j.js";
|
|
3
|
-
import {
|
|
4
|
-
import "./
|
|
5
|
-
import "./review-home-paths-BmZX2qiz.js";
|
|
3
|
+
import { E as respellLinks, G as lensTargetsSchema, X as label, at as formatAnchor, mt as ReviewInputError } from "./src-BPrngiWX.js";
|
|
4
|
+
import "./review-home-paths-B8909D07.js";
|
|
6
5
|
import { t as errorMessage } from "./error-message-OtiDonty.js";
|
|
6
|
+
import "./src-B-91Rd2d.js";
|
|
7
7
|
import { randomUUID } from "node:crypto";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
import { execFile } from "node:child_process";
|
|
10
10
|
import { promisify } from "node:util";
|
|
11
|
-
//#region src/viewed-coverage.ts
|
|
12
|
-
const coverageSchema = z.object({
|
|
13
|
-
base: z.array(z.tuple([z.number().int().nonnegative(), z.number().int().nonnegative()])),
|
|
14
|
-
head: z.array(z.tuple([z.number().int().nonnegative(), z.number().int().nonnegative()]))
|
|
15
|
-
});
|
|
16
|
-
const emptyCoverage = () => ({
|
|
17
|
-
base: [],
|
|
18
|
-
head: []
|
|
19
|
-
});
|
|
20
|
-
function intersectIntervals(left, right) {
|
|
21
|
-
const result = [];
|
|
22
|
-
const a = unionIntervals(left), b = unionIntervals(right);
|
|
23
|
-
let i = 0, j = 0;
|
|
24
|
-
while (i < a.length && j < b.length) {
|
|
25
|
-
const start = Math.max(a[i][0], b[j][0]), end = Math.min(a[i][1], b[j][1]);
|
|
26
|
-
if (start < end) result.push([start, end]);
|
|
27
|
-
if (a[i][1] < b[j][1]) i++;
|
|
28
|
-
else j++;
|
|
29
|
-
}
|
|
30
|
-
return result;
|
|
31
|
-
}
|
|
32
|
-
function subtractIntervals(left, right) {
|
|
33
|
-
const result = [];
|
|
34
|
-
const removed = unionIntervals(right);
|
|
35
|
-
for (const [start, end] of unionIntervals(left)) {
|
|
36
|
-
let cursor = start;
|
|
37
|
-
for (const [from, to] of removed) {
|
|
38
|
-
if (to <= cursor) continue;
|
|
39
|
-
if (from >= end) break;
|
|
40
|
-
if (from > cursor) result.push([cursor, from]);
|
|
41
|
-
cursor = Math.min(end, Math.max(cursor, to));
|
|
42
|
-
}
|
|
43
|
-
if (cursor < end) result.push([cursor, end]);
|
|
44
|
-
}
|
|
45
|
-
return result;
|
|
46
|
-
}
|
|
47
|
-
function updateCoverage(current, scope, viewed) {
|
|
48
|
-
const apply = (side) => viewed ? unionIntervals([...current[side], ...scope[side]]) : subtractIntervals(current[side], scope[side]);
|
|
49
|
-
return {
|
|
50
|
-
base: apply("base"),
|
|
51
|
-
head: apply("head")
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
function scopedCoverage(file, sources) {
|
|
55
|
-
if (!sources) return file.changed;
|
|
56
|
-
const side = (side) => intersectIntervals(file.changed[side], sources.flatMap((source) => source.side === side && source.file === (side === "base" ? file.previousPath ?? file.path : file.path) ? [[source.fromLine - 1, source.toLine]] : []));
|
|
57
|
-
return {
|
|
58
|
-
base: side("base"),
|
|
59
|
-
head: side("head")
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
/** Each file's own sources, grouped once. */
|
|
63
|
-
function sourcesForFile(sources) {
|
|
64
|
-
if (!sources) return () => void 0;
|
|
65
|
-
const byFile = Map.groupBy(sources, (source) => source.file);
|
|
66
|
-
return (file) => {
|
|
67
|
-
const base = byFile.get(file.previousPath ?? file.path) ?? [];
|
|
68
|
-
return file.previousPath && file.previousPath !== file.path ? [...base, ...byFile.get(file.path) ?? []] : base;
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
function coverageSources(file, coverage = file.viewed) {
|
|
72
|
-
return ["base", "head"].flatMap((side) => coverage[side].map(([start, end]) => ({
|
|
73
|
-
side,
|
|
74
|
-
file: side === "base" ? file.previousPath ?? file.path : file.path,
|
|
75
|
-
fromLine: start + 1,
|
|
76
|
-
toLine: end
|
|
77
|
-
})));
|
|
78
|
-
}
|
|
79
|
-
//#endregion
|
|
80
|
-
//#region src/unified-diff.ts
|
|
81
|
-
const HUNK_HEADER = /^@@ -(?<oldStart>\d+)(?:,(?<oldLines>\d+))? \+(?<newStart>\d+)(?:,(?<newLines>\d+))? @@/;
|
|
82
|
-
function parseUnifiedPatch(file, patch) {
|
|
83
|
-
if (!patch) return [];
|
|
84
|
-
const hunks = [];
|
|
85
|
-
let current = null;
|
|
86
|
-
let oldLine = 0;
|
|
87
|
-
let newLine = 0;
|
|
88
|
-
for (const row of patch.split(/\r?\n/)) {
|
|
89
|
-
const header = HUNK_HEADER.exec(row);
|
|
90
|
-
if (header?.groups) {
|
|
91
|
-
current = {
|
|
92
|
-
file,
|
|
93
|
-
oldStart: Number(header.groups.oldStart),
|
|
94
|
-
oldLines: Number(header.groups.oldLines ?? "1"),
|
|
95
|
-
newStart: Number(header.groups.newStart),
|
|
96
|
-
newLines: Number(header.groups.newLines ?? "1"),
|
|
97
|
-
lines: []
|
|
98
|
-
};
|
|
99
|
-
oldLine = current.oldStart;
|
|
100
|
-
newLine = current.newStart;
|
|
101
|
-
hunks.push(current);
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
if (!current || row.startsWith("\")) continue;
|
|
105
|
-
const marker = row[0];
|
|
106
|
-
const text = row.slice(1);
|
|
107
|
-
let line = null;
|
|
108
|
-
if (marker === " ") {
|
|
109
|
-
line = {
|
|
110
|
-
kind: "context",
|
|
111
|
-
oldLine,
|
|
112
|
-
newLine,
|
|
113
|
-
text
|
|
114
|
-
};
|
|
115
|
-
oldLine += 1;
|
|
116
|
-
newLine += 1;
|
|
117
|
-
} else if (marker === "+") {
|
|
118
|
-
line = {
|
|
119
|
-
kind: "add",
|
|
120
|
-
oldLine: null,
|
|
121
|
-
newLine,
|
|
122
|
-
text
|
|
123
|
-
};
|
|
124
|
-
newLine += 1;
|
|
125
|
-
} else if (marker === "-") {
|
|
126
|
-
line = {
|
|
127
|
-
kind: "remove",
|
|
128
|
-
oldLine,
|
|
129
|
-
newLine: null,
|
|
130
|
-
text
|
|
131
|
-
};
|
|
132
|
-
oldLine += 1;
|
|
133
|
-
}
|
|
134
|
-
if (line) current.lines.push(line);
|
|
135
|
-
}
|
|
136
|
-
return hunks;
|
|
137
|
-
}
|
|
138
|
-
//#endregion
|
|
139
|
-
//#region src/review-api/lens-alignment.ts
|
|
140
|
-
/** Project the already-computed patch's runs, including unchanged gaps. */
|
|
141
|
-
function textualRows(path, patch, baseCount, headCount) {
|
|
142
|
-
const rows = [];
|
|
143
|
-
let base = 0, head = 0;
|
|
144
|
-
const append = (baseEnd, headEnd) => {
|
|
145
|
-
while (base < baseEnd || head < headEnd) rows.push([base < baseEnd ? base++ : null, head < headEnd ? head++ : null]);
|
|
146
|
-
};
|
|
147
|
-
for (const hunk of parseUnifiedPatch(path, patch)) {
|
|
148
|
-
append(hunk.oldLines ? hunk.oldStart - 1 : hunk.oldStart, hunk.newLines ? hunk.newStart - 1 : hunk.newStart);
|
|
149
|
-
let removed = 0, added = 0;
|
|
150
|
-
const flush = () => {
|
|
151
|
-
append(base + removed, head + added);
|
|
152
|
-
removed = added = 0;
|
|
153
|
-
};
|
|
154
|
-
for (const line of hunk.lines) if (line.kind === "context") {
|
|
155
|
-
flush();
|
|
156
|
-
append(base + 1, head + 1);
|
|
157
|
-
} else if (line.kind === "add") added++;
|
|
158
|
-
else removed++;
|
|
159
|
-
flush();
|
|
160
|
-
}
|
|
161
|
-
append(baseCount, headCount);
|
|
162
|
-
return rows;
|
|
163
|
-
}
|
|
164
|
-
//#endregion
|
|
165
11
|
//#region src/evidence.ts
|
|
166
12
|
/** Quote matching shared by legacy publish and JSON accept: authors paste
|
|
167
13
|
* transcript text with arbitrary line wrapping, so both sides compare on
|
|
@@ -1339,4 +1185,4 @@ function liftFileLenses(document) {
|
|
|
1339
1185
|
};
|
|
1340
1186
|
}
|
|
1341
1187
|
//#endregion
|
|
1342
|
-
export {
|
|
1188
|
+
export { fetchPullRequest as _, SoftwareModelValidationError as a, textIncludesQuote as b, traceSchema as c, setPullRequest as d, sourceBranchName as f, defaultPullRequestDeps as g, GitHubRefusedRead as h, readStoredDocument as i, pullRequestKey as l, resolvePullRequest as m, migrateStoredDocument as n, defineSoftwareMap as o, pullRequestProvider as p, migrateStoredLenses as r, softwareModelDataSchema as s, liftFileLenses as t, pullRequestUrl as u, remoteUrls as v, azureRepositoryOf as y };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { E as ReviewApiSelectionSourceSchema, N as ReviewSelectedDiffSchema } from "./src-
|
|
1
|
+
import { E as ReviewApiSelectionSourceSchema, N as ReviewSelectedDiffSchema } from "./src-B-91Rd2d.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { stat } from "node:fs/promises";
|
|
4
4
|
//#region src/fs-utils.ts
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { m as isStringValue, n as isJsonObject, u as parseJsonText } from "./src-X9phtB2j.js";
|
|
2
|
-
import {
|
|
3
|
-
import { l as boardTitle } from "./src-CrrW7lcY.js";
|
|
4
|
-
import "./review-home-paths-BmZX2qiz.js";
|
|
5
|
-
import { n as callAuthoringTool, s as ReviewApiError, t as ToolText } from "./agent-client-BCEbSPWU.js";
|
|
2
|
+
import { F as checkReferences, P as blocks, mt as ReviewInputError } from "./src-BPrngiWX.js";
|
|
6
3
|
import { N as devReviewHome } from "./s3-config-CjcLyFV5.js";
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
4
|
+
import "./review-home-paths-B8909D07.js";
|
|
5
|
+
import { t as findReviewPackageRoot } from "./package-paths-wobHueCx.js";
|
|
6
|
+
import { l as boardTitle } from "./src-B-91Rd2d.js";
|
|
7
|
+
import { n as callAuthoringTool, s as ReviewApiError, t as ToolText } from "./agent-client-CgnEo6lf.js";
|
|
8
|
+
import { m as isMissingFileError } from "./thread-state-Jxoh1hde.js";
|
|
9
9
|
import { createHash } from "node:crypto";
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
import { chmod, cp, mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dev.fast/whiteboard",
|
|
3
|
-
"version": "0.5.2-preview.
|
|
3
|
+
"version": "0.5.2-preview.20261109.148",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -53,7 +53,6 @@
|
|
|
53
53
|
"mdast-util-gfm": "3.1.0",
|
|
54
54
|
"mdast-util-math": "3.0.0",
|
|
55
55
|
"micromark-extension-gfm": "3.0.0",
|
|
56
|
-
"minimatch": "10.2.6",
|
|
57
56
|
"pi-acp": "0.0.34",
|
|
58
57
|
"pino": "10.3.1",
|
|
59
58
|
"semver": "7.8.5",
|
|
@@ -78,10 +77,10 @@
|
|
|
78
77
|
"vitest": "4.1.12",
|
|
79
78
|
"@dev.fast/json": "0.0.0",
|
|
80
79
|
"@dev.fast/review-share-protocol": "0.6.0",
|
|
81
|
-
"@dev.fast/review-protocol": "0.0.0",
|
|
82
|
-
"@dev.fast/trace-protocol": "0.5.0",
|
|
83
80
|
"@dev.fast/trace-core": "0.0.0",
|
|
84
|
-
"@dev.fast/
|
|
81
|
+
"@dev.fast/trace-protocol": "0.5.0",
|
|
82
|
+
"@dev.fast/review-protocol": "0.0.0",
|
|
83
|
+
"@dev.fast/whiteboard-document": "0.3.0"
|
|
85
84
|
},
|
|
86
85
|
"engines": {
|
|
87
86
|
"node": ">=24 <25"
|
|
@@ -91,7 +90,7 @@
|
|
|
91
90
|
"repo": "devdotfast/review",
|
|
92
91
|
"docs": "packages/review/instructions/authoring.md"
|
|
93
92
|
},
|
|
94
|
-
"gitHead": "
|
|
93
|
+
"gitHead": "b2e15bbe59af85f4e1a721e310526de6c60a4f3b",
|
|
95
94
|
"scripts": {
|
|
96
95
|
"prebuild": "pnpm run build:workspace-deps",
|
|
97
96
|
"build": "node --max-old-space-size=8192 node_modules/tsdown/dist/run.mjs",
|
|
@@ -7,23 +7,21 @@ import {
|
|
|
7
7
|
applyStructuralUpdate,
|
|
8
8
|
structuralRows,
|
|
9
9
|
} from "@dev.fast/review-protocol";
|
|
10
|
-
import type {
|
|
11
|
-
AlignmentRow,
|
|
12
|
-
FileLineRange,
|
|
13
|
-
Pins,
|
|
14
|
-
} from "@dev.fast/whiteboard-document";
|
|
15
|
-
import { parseUnifiedPatch } from "@review/unified-diff.js";
|
|
16
10
|
import {
|
|
11
|
+
type AlignmentRow,
|
|
17
12
|
type Coverage,
|
|
18
13
|
type CoverageFile,
|
|
14
|
+
type FileLineRange,
|
|
19
15
|
type LineInterval,
|
|
16
|
+
type Pins,
|
|
20
17
|
emptyCoverage,
|
|
21
18
|
intersectIntervals,
|
|
19
|
+
patchChanges,
|
|
20
|
+
patchRows,
|
|
22
21
|
subtractIntervals,
|
|
23
22
|
unionIntervals,
|
|
24
|
-
} from "@
|
|
23
|
+
} from "@dev.fast/whiteboard-document";
|
|
25
24
|
|
|
26
|
-
import { textualRows } from "./lens-alignment.js";
|
|
27
25
|
import type { LocalReviewData } from "./local-data.js";
|
|
28
26
|
|
|
29
27
|
const hash = (parts: (string | null)[]) =>
|
|
@@ -60,19 +58,7 @@ export async function comparisonCoverage(
|
|
|
60
58
|
patches?.get(file.path) ??
|
|
61
59
|
(await data.changes(pins, file.path, file.previousPath));
|
|
62
60
|
|
|
63
|
-
const changed =
|
|
64
|
-
|
|
65
|
-
for (const hunk of parseUnifiedPatch(file.path, patch))
|
|
66
|
-
for (const line of hunk.lines) {
|
|
67
|
-
if (line.kind === "add")
|
|
68
|
-
changed.head.push([line.newLine! - 1, line.newLine!]);
|
|
69
|
-
|
|
70
|
-
if (line.kind === "remove")
|
|
71
|
-
changed.base.push([line.oldLine! - 1, line.oldLine!]);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
changed.base = unionIntervals(changed.base);
|
|
75
|
-
changed.head = unionIntervals(changed.head);
|
|
61
|
+
const changed = patchChanges(file.path, patch);
|
|
76
62
|
|
|
77
63
|
const [base, head] = await Promise.all([
|
|
78
64
|
file.status === "added"
|
|
@@ -91,8 +77,7 @@ export async function comparisonCoverage(
|
|
|
91
77
|
|
|
92
78
|
alignments.set(
|
|
93
79
|
file.path,
|
|
94
|
-
|
|
95
|
-
file.path,
|
|
80
|
+
patchRows(
|
|
96
81
|
patch,
|
|
97
82
|
base === null ? 0 : base.split("\n").length,
|
|
98
83
|
head === null ? 0 : head.split("\n").length,
|
package/src/review-api/http.ts
CHANGED
|
@@ -25,8 +25,12 @@ import { errorMessage } from "@dev.fast/trace-core";
|
|
|
25
25
|
import {
|
|
26
26
|
ReviewInputError,
|
|
27
27
|
type ReviewTarget,
|
|
28
|
+
type UncategorizedReport,
|
|
28
29
|
boardRepositoryId,
|
|
29
30
|
elements,
|
|
31
|
+
lensReport,
|
|
32
|
+
scopedCoverage,
|
|
33
|
+
uncategorizedReport,
|
|
30
34
|
} from "@dev.fast/whiteboard-document";
|
|
31
35
|
import {
|
|
32
36
|
type AgentSelection,
|
|
@@ -63,7 +67,6 @@ import {
|
|
|
63
67
|
} from "@review/sharing/host.js";
|
|
64
68
|
import { forgetSharedCommits } from "@review/sharing/repository.js";
|
|
65
69
|
import type { ReviewSessionAgent } from "@review/ui-telemetry-events.js";
|
|
66
|
-
import { scopedCoverage } from "@review/viewed-coverage.js";
|
|
67
70
|
import { type Context, Hono, type MiddlewareHandler } from "hono";
|
|
68
71
|
import { z } from "zod";
|
|
69
72
|
|
|
@@ -91,12 +94,9 @@ import {
|
|
|
91
94
|
reviewRequestOrigin,
|
|
92
95
|
} from "./request-origin.js";
|
|
93
96
|
import {
|
|
94
|
-
type UncategorizedReport,
|
|
95
97
|
legacyModeSchema,
|
|
96
|
-
lensReport,
|
|
97
98
|
progressUpdateSchema,
|
|
98
99
|
reviewProgress,
|
|
99
|
-
uncategorizedReport,
|
|
100
100
|
} from "./review-progress.js";
|
|
101
101
|
import {
|
|
102
102
|
type Author,
|
|
@@ -456,12 +456,16 @@ export function createReviewApi(
|
|
|
456
456
|
|
|
457
457
|
const snapshot = readReview(context.req.param("id"));
|
|
458
458
|
|
|
459
|
+
const progress = await reviewProgress(
|
|
460
|
+
store,
|
|
461
|
+
data,
|
|
462
|
+
snapshot,
|
|
463
|
+
context.req.raw.signal,
|
|
464
|
+
);
|
|
465
|
+
|
|
459
466
|
return context.json({
|
|
460
467
|
version: snapshot.version,
|
|
461
|
-
...lensReport(
|
|
462
|
-
snapshot.lenses ?? [],
|
|
463
|
-
await reviewProgress(store, data, snapshot, context.req.raw.signal),
|
|
464
|
-
),
|
|
468
|
+
...lensReport(snapshot.lenses ?? [], progress.lenses, progress.files),
|
|
465
469
|
});
|
|
466
470
|
});
|
|
467
471
|
app.get("/status", async (context) =>
|
|
@@ -2155,15 +2159,15 @@ export function createReviewApi(
|
|
|
2155
2159
|
if (!data) return {};
|
|
2156
2160
|
|
|
2157
2161
|
try {
|
|
2162
|
+
const progress = await reviewProgress(
|
|
2163
|
+
store,
|
|
2164
|
+
data,
|
|
2165
|
+
store.read(reviewId, version),
|
|
2166
|
+
request.signal,
|
|
2167
|
+
);
|
|
2168
|
+
|
|
2158
2169
|
return {
|
|
2159
|
-
uncategorized: uncategorizedReport(
|
|
2160
|
-
await reviewProgress(
|
|
2161
|
-
store,
|
|
2162
|
-
data,
|
|
2163
|
-
store.read(reviewId, version),
|
|
2164
|
-
request.signal,
|
|
2165
|
-
),
|
|
2166
|
-
),
|
|
2170
|
+
uncategorized: uncategorizedReport(progress.lenses, progress.files),
|
|
2167
2171
|
};
|
|
2168
2172
|
} catch (error) {
|
|
2169
2173
|
return {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
-
type
|
|
2
|
+
type CoverageFile,
|
|
3
3
|
type FileLineRange,
|
|
4
|
-
type Lens,
|
|
5
4
|
type LensSource,
|
|
6
5
|
type Pins,
|
|
6
|
+
type ResolvedLens,
|
|
7
7
|
ReviewInputError,
|
|
8
8
|
SelectionUnavailableError,
|
|
9
9
|
type SelectionUnavailableReason,
|
|
@@ -11,22 +11,18 @@ import {
|
|
|
11
11
|
anchorPins,
|
|
12
12
|
boardRepositoryId,
|
|
13
13
|
comparisonKey,
|
|
14
|
+
emptyCoverage,
|
|
14
15
|
fileLineRangeSchema,
|
|
15
16
|
lensSelections,
|
|
17
|
+
patchRows,
|
|
16
18
|
resolveDiffSelection,
|
|
19
|
+
resolveLenses,
|
|
17
20
|
selectionKey,
|
|
18
21
|
selectionReferences,
|
|
19
22
|
} from "@dev.fast/whiteboard-document";
|
|
20
|
-
import { type CoverageFile, emptyCoverage } from "@review/viewed-coverage.js";
|
|
21
23
|
import { z } from "zod";
|
|
22
24
|
|
|
23
25
|
import type { ComparisonCoverage } from "./comparison-coverage.js";
|
|
24
|
-
import {
|
|
25
|
-
changedPath,
|
|
26
|
-
resolveFileLens,
|
|
27
|
-
uncategorizedSources,
|
|
28
|
-
} from "./file-lenses.js";
|
|
29
|
-
import { textualRows } from "./lens-alignment.js";
|
|
30
26
|
import type { LocalReviewData } from "./local-data.js";
|
|
31
27
|
import type { ReviewStore, Snapshot } from "./store.js";
|
|
32
28
|
|
|
@@ -60,7 +56,7 @@ export interface ReviewProgress {
|
|
|
60
56
|
referenceFiles?: Record<string, Record<string, CoverageFile>>;
|
|
61
57
|
resolvedSelections: Record<string, FileLineRange[]>;
|
|
62
58
|
/** The review's file lenses, then the automatic "Uncategorized changes". */
|
|
63
|
-
lenses: (
|
|
59
|
+
lenses: (ResolvedLens & { pending?: boolean })[];
|
|
64
60
|
/** Untracked files a live worktree review leaves out of its comparison. */
|
|
65
61
|
untrackedFiles?: number;
|
|
66
62
|
}
|
|
@@ -208,8 +204,7 @@ export async function reviewProgress(
|
|
|
208
204
|
"no_alignment",
|
|
209
205
|
"Changed context file has no alignment.",
|
|
210
206
|
);
|
|
211
|
-
rows =
|
|
212
|
-
source.file,
|
|
207
|
+
rows = patchRows(
|
|
213
208
|
"",
|
|
214
209
|
base?.split("\n").length ?? 0,
|
|
215
210
|
head?.split("\n").length ?? 0,
|
|
@@ -244,40 +239,17 @@ export async function reviewProgress(
|
|
|
244
239
|
}
|
|
245
240
|
};
|
|
246
241
|
|
|
247
|
-
|
|
242
|
+
// Explicit ranges use the same pin validation as diagram evidence.
|
|
243
|
+
await Promise.all(
|
|
248
244
|
(snapshot.lenses ?? []).map(async (authored) => {
|
|
249
|
-
const lens = { id: authored.id, title: authored.title };
|
|
250
|
-
|
|
251
245
|
try {
|
|
252
|
-
// Explicit ranges use the same pin validation as diagram evidence.
|
|
253
246
|
await Promise.all(
|
|
254
247
|
lensSelections([authored]).map(({ source }) =>
|
|
255
248
|
resolveAvailable(source),
|
|
256
249
|
),
|
|
257
250
|
);
|
|
258
|
-
|
|
259
|
-
const resolved = resolveFileLens(
|
|
260
|
-
authored,
|
|
261
|
-
files,
|
|
262
|
-
fileSources,
|
|
263
|
-
(source) => resolvedSelections[selectionKey(source)] ?? [],
|
|
264
|
-
);
|
|
265
|
-
|
|
266
|
-
return {
|
|
267
|
-
...lens,
|
|
268
|
-
...resolved,
|
|
269
|
-
pending: counting,
|
|
270
|
-
unavailable:
|
|
271
|
-
counting || resolved.fileCount
|
|
272
|
-
? undefined
|
|
273
|
-
: "No files match these targets",
|
|
274
|
-
};
|
|
275
251
|
} catch {
|
|
276
|
-
|
|
277
|
-
...lens,
|
|
278
|
-
sources: [],
|
|
279
|
-
unavailable: "Source links need updating at these pins",
|
|
280
|
-
};
|
|
252
|
+
/* resolveLenses reports a lens whose anchors don't parse. */
|
|
281
253
|
}
|
|
282
254
|
}),
|
|
283
255
|
);
|
|
@@ -296,27 +268,19 @@ export async function reviewProgress(
|
|
|
296
268
|
}),
|
|
297
269
|
);
|
|
298
270
|
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
wholeFiles: false,
|
|
313
|
-
fileCount: new Set(uncategorized.map(changedPath(files))).size,
|
|
314
|
-
pending: counting,
|
|
315
|
-
unavailable:
|
|
316
|
-
counting || uncategorized.length
|
|
317
|
-
? undefined
|
|
318
|
-
: "All changed lines are covered by lenses",
|
|
319
|
-
});
|
|
271
|
+
const lenses = pendingLenses(
|
|
272
|
+
resolveLenses(
|
|
273
|
+
snapshot.lenses ?? [],
|
|
274
|
+
files,
|
|
275
|
+
fileSources,
|
|
276
|
+
(source) =>
|
|
277
|
+
unavailableSelections[selectionKey(source)]
|
|
278
|
+
? undefined
|
|
279
|
+
: (resolvedSelections[selectionKey(source)] ?? []),
|
|
280
|
+
{ nocase: process.platform === "darwin" || process.platform === "win32" },
|
|
281
|
+
),
|
|
282
|
+
counting,
|
|
283
|
+
);
|
|
320
284
|
|
|
321
285
|
const progress: ReviewProgress = {
|
|
322
286
|
complete: !counting && !pendingSources.size,
|
|
@@ -334,71 +298,21 @@ export async function reviewProgress(
|
|
|
334
298
|
return progress;
|
|
335
299
|
}
|
|
336
300
|
|
|
337
|
-
/**
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
export function uncategorizedReport(
|
|
355
|
-
progress: ReviewProgress,
|
|
356
|
-
): UncategorizedReport {
|
|
357
|
-
const sources =
|
|
358
|
-
progress.lenses.find((lens) => lens.id === UNCATEGORIZED_LENS_ID)
|
|
359
|
-
?.sources ?? [];
|
|
360
|
-
|
|
361
|
-
const byPath = new Map<string, UncategorizedReport["files"][number]>();
|
|
362
|
-
const pathOf = changedPath(progress.files);
|
|
363
|
-
|
|
364
|
-
for (const source of sources) {
|
|
365
|
-
const path = pathOf(source);
|
|
366
|
-
|
|
367
|
-
const entry = byPath.get(path) ?? { path, lines: 0, ranges: [] };
|
|
368
|
-
entry.lines += source.toLine - source.fromLine + 1;
|
|
369
|
-
entry.ranges.push({
|
|
370
|
-
side: source.side,
|
|
371
|
-
fromLine: source.fromLine,
|
|
372
|
-
toLine: source.toLine,
|
|
373
|
-
});
|
|
374
|
-
byPath.set(path, entry);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
const files = [...byPath.values()];
|
|
378
|
-
|
|
379
|
-
const report: UncategorizedReport = {
|
|
380
|
-
lines: files.reduce((total, file) => total + file.lines, 0),
|
|
381
|
-
files: files.slice(0, REPORT_FILES),
|
|
382
|
-
};
|
|
383
|
-
|
|
384
|
-
if (files.length > REPORT_FILES)
|
|
385
|
-
report.moreFiles = files.length - REPORT_FILES;
|
|
386
|
-
|
|
387
|
-
return report;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/** Each lens as authored, with what it resolves to, for a lens author. */
|
|
391
|
-
export function lensReport(lenses: readonly Lens[], progress: ReviewProgress) {
|
|
392
|
-
return {
|
|
393
|
-
lenses: lenses.map((lens) => {
|
|
394
|
-
const resolved = progress.lenses.find((item) => item.id === lens.id);
|
|
395
|
-
|
|
396
|
-
return {
|
|
397
|
-
...lens,
|
|
398
|
-
fileCount: resolved?.fileCount ?? 0,
|
|
399
|
-
...(resolved?.unavailable && { unavailable: resolved.unavailable }),
|
|
400
|
-
};
|
|
401
|
-
}),
|
|
402
|
-
uncategorized: uncategorizedReport(progress),
|
|
403
|
-
};
|
|
301
|
+
/** A lens with no fileCount failed to resolve, so it is never pending. */
|
|
302
|
+
export function pendingLenses(
|
|
303
|
+
lenses: readonly ResolvedLens[],
|
|
304
|
+
counting: boolean,
|
|
305
|
+
): ReviewProgress["lenses"] {
|
|
306
|
+
return lenses.map((lens) => {
|
|
307
|
+
if (lens.fileCount === undefined) return lens;
|
|
308
|
+
|
|
309
|
+
if (!counting) return { ...lens, pending: false };
|
|
310
|
+
|
|
311
|
+
return {
|
|
312
|
+
...lens,
|
|
313
|
+
...(lens.id === UNCATEGORIZED_LENS_ID && { sources: [], fileCount: 0 }),
|
|
314
|
+
unavailable: undefined,
|
|
315
|
+
pending: true,
|
|
316
|
+
};
|
|
317
|
+
});
|
|
404
318
|
}
|
package/src/review-api/store.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
type Applied,
|
|
18
18
|
type Block,
|
|
19
19
|
type BoardLinkRef,
|
|
20
|
+
type Coverage,
|
|
20
21
|
type EditSummary,
|
|
21
22
|
type Element,
|
|
22
23
|
type FileLineRange,
|
|
@@ -39,6 +40,7 @@ import {
|
|
|
39
40
|
documentSchema,
|
|
40
41
|
editSchema,
|
|
41
42
|
elements,
|
|
43
|
+
emptyCoverage,
|
|
42
44
|
explicitPins,
|
|
43
45
|
lensEditSchema,
|
|
44
46
|
lensSchema,
|
|
@@ -53,18 +55,14 @@ import {
|
|
|
53
55
|
sourceAnchors,
|
|
54
56
|
sourceReferences,
|
|
55
57
|
summarizeEdit,
|
|
58
|
+
updateCoverage,
|
|
56
59
|
} from "@dev.fast/whiteboard-document";
|
|
57
60
|
import type { GitHubPullRequest } from "@review/github-pr-graph.js";
|
|
58
61
|
import {
|
|
59
62
|
migrateStoredLenses,
|
|
60
63
|
readStoredDocument,
|
|
61
64
|
} from "@review/stored-document-migration.js";
|
|
62
|
-
import {
|
|
63
|
-
type Coverage,
|
|
64
|
-
coverageSchema,
|
|
65
|
-
emptyCoverage,
|
|
66
|
-
updateCoverage,
|
|
67
|
-
} from "@review/viewed-coverage.js";
|
|
65
|
+
import { coverageSchema } from "@review/viewed-coverage.js";
|
|
68
66
|
import { z } from "zod";
|
|
69
67
|
|
|
70
68
|
import { ReviewActivity } from "./activity.js";
|
|
@@ -3,8 +3,10 @@ import {
|
|
|
3
3
|
diff as readLocalVcsDiff,
|
|
4
4
|
} from "@dev.fast/local-vcs";
|
|
5
5
|
import { jsonString, parseJsonText } from "@dev.fast/review-protocol";
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
import {
|
|
7
|
+
type DiffHunkLine,
|
|
8
|
+
parseUnifiedPatch,
|
|
9
|
+
} from "@dev.fast/whiteboard-document";
|
|
8
10
|
|
|
9
11
|
export interface SoftwareMapDiffLineCount {
|
|
10
12
|
additions: number;
|