@dev.fast/whiteboard 0.5.2-preview.20261104.147 → 0.5.2-preview.20261109.149

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.
Files changed (50) hide show
  1. package/dist/{account-alias-DXpd0Px8.js → account-alias-Cs5YqXRj.js} +4 -4
  2. package/dist/agent-cli-DdUAmdca.js +2 -0
  3. package/dist/{agent-cli-COrZtFks.js → agent-cli-a5J-juuu.js} +8 -8
  4. package/dist/{agent-client-BFtYm3Ng.js → agent-client-CgnEo6lf.js} +3 -3
  5. package/dist/{authoring-tools-D1avYp8-.js → authoring-tools-BgZvnbjN.js} +3 -3
  6. package/dist/{background-server-HOJozY99.js → background-server-D8SaPvuC.js} +1 -1
  7. package/dist/{background-server-BiRSqjxG.js → background-server-DHEcsFwH.js} +4 -4
  8. package/dist/build-info.json +1 -1
  9. package/dist/{cli-CSlwGRvH.js → cli-Bq5zVqlc.js} +1 -1
  10. package/dist/{cli-runner-CuffXA0Q.js → cli-runner-hL2efcxb.js} +21 -21
  11. package/dist/cli.js +1 -1
  12. package/dist/{fuzzy-match-DEo941za.js → fuzzy-match-DNyQDN3P.js} +2 -2
  13. package/dist/{headless-host-BCkXVVpU.js → headless-host-CGyfb5mS.js} +1 -1
  14. package/dist/{headless-host-CIuJJjmM.js → headless-host-bb09yVkX.js} +17 -15
  15. package/dist/{import-CjcW7EIQ.js → import-_XAsWqen.js} +24 -139
  16. package/dist/{local-data-B5PBZ0Ge.js → local-data-ZQIkF5k1.js} +81 -70
  17. package/dist/{mcp-Ba3WvhUh.js → mcp-B-J8P5xm.js} +4 -4
  18. package/dist/{package-paths-Dk7MOXxN.js → package-paths-wobHueCx.js} +1 -1
  19. package/dist/profile-Bi2SbpSI.js +2 -0
  20. package/dist/{profile-CNMhLUhf.js → profile-D-SbO3p9.js} +2 -2
  21. package/dist/{remote-attach-DkZoYBHV.js → remote-attach-DyIESbbf.js} +4 -4
  22. package/dist/{remote-extensions-BvV29_gk.js → remote-extensions-BHHFPyYW.js} +1 -1
  23. package/dist/{remote-extensions-L95HNwIH.js → remote-extensions-gTMcRBg-.js} +2 -2
  24. package/dist/{remote-language-server-l4ConTfj.js → remote-language-server-Pp261dqJ.js} +4 -4
  25. package/dist/{remote-uninstall-BAQM7cU8.js → remote-uninstall-D_hSuBik.js} +5 -5
  26. package/dist/{request-origin-DZexKlc4.js → request-origin-ENYd0Ymr.js} +1 -1
  27. package/dist/{review-app-launcher-B5F10y_4.js → review-app-launcher-DR5vYGEl.js} +1 -1
  28. package/dist/{review-home-paths-BmZX2qiz.js → review-home-paths-B8909D07.js} +19 -19
  29. package/dist/{review-telemetry-kQ7esDRE.js → review-telemetry-CxNvwdDS.js} +4 -4
  30. package/dist/server/desktop-host.js +74 -16
  31. package/dist/{server-discovery-DYY_xeG9.js → server-discovery-Fme7f3fb.js} +2 -2
  32. package/dist/sharing/index.d.ts +21 -21
  33. package/dist/sharing/index.js +1 -1
  34. package/dist/{src-DirPN_Qh.js → src-BPrngiWX.js} +1769 -1
  35. package/dist/{stored-document-migration-vg0NAzXG.js → stored-document-migration-BQcUyXO8.js} +4 -73
  36. package/dist/{tool-failure-BLBwcl3H.js → tool-failure-Cgjidoud.js} +5 -5
  37. package/package.json +5 -6
  38. package/src/review-api/comparison-coverage.ts +6 -20
  39. package/src/review-api/http.ts +20 -16
  40. package/src/review-api/review-progress.ts +38 -123
  41. package/src/review-api/store.ts +4 -6
  42. package/src/server/review-gateway-pushes.ts +5 -1
  43. package/src/server/review-gateway.ts +15 -1
  44. package/src/software-map-diff-counts.ts +4 -2
  45. package/src/viewed-coverage.ts +9 -252
  46. package/dist/agent-cli-x6-Eh1S-.js +0 -2
  47. package/dist/profile-BstQkIY0.js +0 -2
  48. package/src/review-api/file-lenses.ts +0 -125
  49. package/src/unified-diff.ts +0 -71
  50. package/dist/{s3-CsG2EWED.js → s3-d8RGPKwt.js} +1 -1
@@ -1,17 +1,14 @@
1
- import { structuralChangeCounts } from "@dev.fast/review-protocol";
2
- import {
3
- type FileLineRange,
4
- type LineInterval,
5
- unionIntervals,
6
- } from "@dev.fast/whiteboard-document";
7
1
  import { z } from "zod";
8
2
 
9
- export { type LineInterval, unionIntervals };
10
-
11
- export interface Coverage {
12
- base: LineInterval[];
13
- head: LineInterval[];
14
- }
3
+ export {
4
+ type CoverageFile,
5
+ type CoverageProgress,
6
+ coverageProgress,
7
+ coverageSources,
8
+ emptyCoverage,
9
+ mergeCoverageProgress,
10
+ scopedCoverage,
11
+ } from "@dev.fast/whiteboard-document";
15
12
 
16
13
  export const coverageSchema = z.object({
17
14
  base: z.array(
@@ -21,243 +18,3 @@ export const coverageSchema = z.object({
21
18
  z.tuple([z.number().int().nonnegative(), z.number().int().nonnegative()]),
22
19
  ),
23
20
  });
24
-
25
- export interface ChangeCounts {
26
- additions: number;
27
- deletions: number;
28
- }
29
-
30
- /**
31
- * Changed lines that diffr folds by default count as done, the way the
32
- * reader's viewed marks do. `folded` is how many of the scope's lines are
33
- * done only because they are folded; `remaining` excludes them.
34
- * "folded" is the state of a scope with nothing left to read and nothing the
35
- * reader marked: all of it starts folded.
36
- */
37
- export interface CoverageProgress {
38
- state: "unread" | "partial" | "viewed" | "folded";
39
- total: ChangeCounts;
40
- remaining: ChangeCounts;
41
- folded: ChangeCounts;
42
- }
43
-
44
- export interface CoverageFile {
45
- path: string;
46
- previousPath?: string;
47
- fingerprint: string;
48
- changed: Coverage;
49
- /** The changed lines diffr folds by default: every changed line of a file
50
- * it hides, or those under a region that starts collapsed. Absent without
51
- * structural data, where every changed line is left to read. */
52
- folded?: Coverage;
53
- viewed: Coverage;
54
- }
55
-
56
- export const emptyCoverage = (): Coverage => ({ base: [], head: [] });
57
-
58
- export function intersectIntervals(
59
- left: readonly LineInterval[],
60
- right: readonly LineInterval[],
61
- ): LineInterval[] {
62
- const result: LineInterval[] = [];
63
-
64
- const a = unionIntervals(left),
65
- b = unionIntervals(right);
66
-
67
- let i = 0,
68
- j = 0;
69
-
70
- while (i < a.length && j < b.length) {
71
- const start = Math.max(a[i][0], b[j][0]),
72
- end = Math.min(a[i][1], b[j][1]);
73
-
74
- if (start < end) result.push([start, end]);
75
-
76
- if (a[i][1] < b[j][1]) i++;
77
- else j++;
78
- }
79
-
80
- return result;
81
- }
82
-
83
- export function subtractIntervals(
84
- left: readonly LineInterval[],
85
- right: readonly LineInterval[],
86
- ): LineInterval[] {
87
- const result: LineInterval[] = [];
88
- const removed = unionIntervals(right);
89
-
90
- for (const [start, end] of unionIntervals(left)) {
91
- let cursor = start;
92
-
93
- for (const [from, to] of removed) {
94
- if (to <= cursor) continue;
95
-
96
- if (from >= end) break;
97
-
98
- if (from > cursor) result.push([cursor, from]);
99
- cursor = Math.min(end, Math.max(cursor, to));
100
- }
101
-
102
- if (cursor < end) result.push([cursor, end]);
103
- }
104
-
105
- return result;
106
- }
107
-
108
- export function updateCoverage(
109
- current: Coverage,
110
- scope: Coverage,
111
- viewed: boolean,
112
- ): Coverage {
113
- const apply = (side: "base" | "head") =>
114
- viewed
115
- ? unionIntervals([...current[side], ...scope[side]])
116
- : subtractIntervals(current[side], scope[side]);
117
-
118
- return { base: apply("base"), head: apply("head") };
119
- }
120
-
121
- export function scopedCoverage(
122
- file: CoverageFile,
123
- sources?: readonly FileLineRange[],
124
- ): Coverage {
125
- if (!sources) return file.changed;
126
-
127
- const side = (side: "base" | "head") =>
128
- intersectIntervals(
129
- file.changed[side],
130
- sources.flatMap((source): LineInterval[] =>
131
- source.side === side &&
132
- source.file ===
133
- (side === "base" ? (file.previousPath ?? file.path) : file.path)
134
- ? [[source.fromLine - 1, source.toLine]]
135
- : [],
136
- ),
137
- );
138
-
139
- return { base: side("base"), head: side("head") };
140
- }
141
-
142
- /** Each file's own sources, grouped once. */
143
- export function sourcesForFile(
144
- sources?: readonly FileLineRange[],
145
- ): (file: CoverageFile) => FileLineRange[] | undefined {
146
- if (!sources) return () => undefined;
147
- const byFile = Map.groupBy(sources, (source) => source.file);
148
-
149
- return (file) => {
150
- const base = byFile.get(file.previousPath ?? file.path) ?? [];
151
-
152
- return file.previousPath && file.previousPath !== file.path
153
- ? [...base, ...(byFile.get(file.path) ?? [])]
154
- : base;
155
- };
156
- }
157
-
158
- export function coverageProgress(
159
- files: readonly CoverageFile[],
160
- sources?: readonly FileLineRange[],
161
- ): CoverageProgress {
162
- const total = { additions: 0, deletions: 0 },
163
- remaining = { additions: 0, deletions: 0 },
164
- folded = { additions: 0, deletions: 0 };
165
-
166
- const own = sourcesForFile(sources);
167
-
168
- for (const file of files) {
169
- const scope = scopedCoverage(file, own(file));
170
- const counts = structuralChangeCounts(scope);
171
-
172
- const side = (side: "base" | "head") => {
173
- const unviewed = subtractIntervals(scope[side], file.viewed[side]);
174
-
175
- return {
176
- unread: subtractIntervals(unviewed, file.folded?.[side] ?? []),
177
- folded: intersectIntervals(unviewed, file.folded?.[side] ?? []),
178
- };
179
- };
180
-
181
- const base = side("base"),
182
- head = side("head");
183
-
184
- const unread = structuralChangeCounts({
185
- base: base.unread,
186
- head: head.unread,
187
- });
188
-
189
- const foldedCounts = structuralChangeCounts({
190
- base: base.folded,
191
- head: head.folded,
192
- });
193
-
194
- total.additions += counts.added;
195
- total.deletions += counts.removed;
196
- remaining.additions += unread.added;
197
- remaining.deletions += unread.removed;
198
- folded.additions += foldedCounts.added;
199
- folded.deletions += foldedCounts.removed;
200
- }
201
-
202
- return {
203
- total,
204
- remaining,
205
- folded,
206
- state: progressState(total, remaining, folded),
207
- };
208
- }
209
-
210
- /** Progress over several comparisons at once: the sums, and the same state
211
- * rule as one. */
212
- export function mergeCoverageProgress(
213
- parts: readonly CoverageProgress[],
214
- ): CoverageProgress {
215
- const total = { additions: 0, deletions: 0 },
216
- remaining = { additions: 0, deletions: 0 },
217
- folded = { additions: 0, deletions: 0 };
218
-
219
- for (const part of parts) {
220
- total.additions += part.total.additions;
221
- total.deletions += part.total.deletions;
222
- remaining.additions += part.remaining.additions;
223
- remaining.deletions += part.remaining.deletions;
224
- folded.additions += part.folded.additions;
225
- folded.deletions += part.folded.deletions;
226
- }
227
-
228
- return {
229
- total,
230
- remaining,
231
- folded,
232
- state: progressState(total, remaining, folded),
233
- };
234
- }
235
-
236
- /** Done lines are the viewed and the folded ones; the state names which. */
237
- function progressState(
238
- total: ChangeCounts,
239
- remaining: ChangeCounts,
240
- folded: ChangeCounts,
241
- ): CoverageProgress["state"] {
242
- const size = total.additions + total.deletions,
243
- unread = remaining.additions + remaining.deletions,
244
- viewed = size - unread - folded.additions - folded.deletions;
245
-
246
- if (size > 0 && unread === 0) return viewed > 0 ? "viewed" : "folded";
247
-
248
- return viewed > 0 ? "partial" : "unread";
249
- }
250
-
251
- export function coverageSources(
252
- file: CoverageFile,
253
- coverage = file.viewed,
254
- ): FileLineRange[] {
255
- return (["base", "head"] as const).flatMap((side) =>
256
- coverage[side].map(([start, end]) => ({
257
- side,
258
- file: side === "base" ? (file.previousPath ?? file.path) : file.path,
259
- fromLine: start + 1,
260
- toLine: end,
261
- })),
262
- );
263
- }
@@ -1,2 +0,0 @@
1
- import { n as runReviewAgentCli } from "./agent-cli-COrZtFks.js";
2
- export { runReviewAgentCli };
@@ -1,2 +0,0 @@
1
- import { t as openReviewProfile } from "./profile-CNMhLUhf.js";
2
- export { openReviewProfile };
@@ -1,125 +0,0 @@
1
- import {
2
- type FileLineRange,
3
- type Lens,
4
- type LensSource,
5
- anchorSelection,
6
- } from "@dev.fast/whiteboard-document";
7
- import {
8
- type CoverageFile,
9
- coverageSources,
10
- scopedCoverage,
11
- sourcesForFile,
12
- subtractIntervals,
13
- unionIntervals,
14
- } from "@review/viewed-coverage.js";
15
- import { Minimatch } from "minimatch";
16
-
17
- /** Subtract authored coverage, independently of viewed state. */
18
- export function uncategorizedSources(
19
- files: readonly CoverageFile[],
20
- sources: readonly FileLineRange[],
21
- ): FileLineRange[] {
22
- const own = sourcesForFile(sources);
23
-
24
- return files.flatMap((file) => {
25
- const covered = scopedCoverage(file, own(file));
26
-
27
- return coverageSources(file, {
28
- base: subtractIntervals(file.changed.base, covered.base),
29
- head: subtractIntervals(file.changed.head, covered.head),
30
- });
31
- });
32
- }
33
-
34
- /** Resolve all targets into one union; a whole-file range subsumes narrower ranges. */
35
- export function resolveFileLens(
36
- lens: Lens,
37
- files: readonly CoverageFile[],
38
- fileSources: ReadonlyMap<string, FileLineRange[]>,
39
- resolve: (source: LensSource) => FileLineRange[],
40
- ) {
41
- const targets = lens.targets;
42
-
43
- const selected = targets.flatMap((target) => {
44
- if (target.kind === "ranges")
45
- return target.sources.flatMap((source) =>
46
- resolve(anchorSelection(source)),
47
- );
48
- const matches = fileLensMatcher(target.patterns);
49
-
50
- return files
51
- .filter(matches)
52
- .flatMap((file) => fileSources.get(file.path) ?? []);
53
- });
54
-
55
- const groups = new Map<string, FileLineRange[]>();
56
-
57
- for (const source of selected) {
58
- const key = JSON.stringify([source.side, source.file]);
59
- const group = groups.get(key) ?? [];
60
- group.push(source);
61
- groups.set(key, group);
62
- }
63
-
64
- const sources = [...groups.values()].flatMap((group) =>
65
- unionIntervals(
66
- group.map((source) => [source.fromLine - 1, source.toLine]),
67
- ).map(([start, end]) => ({
68
- ...group[0],
69
- fromLine: start + 1,
70
- toLine: end,
71
- })),
72
- );
73
-
74
- const fileCount = new Set(sources.map(changedPath(files))).size;
75
-
76
- return {
77
- sources,
78
- fileCount,
79
- wholeFiles: targets.every((target) => target.kind === "files"),
80
- };
81
- }
82
-
83
- /** The changed file a source names on its side, or the source's own file. */
84
- export function changedPath(
85
- files: readonly CoverageFile[],
86
- ): (source: FileLineRange) => string {
87
- const paths = new Map<string, string>();
88
-
89
- for (const file of files)
90
- for (const key of [
91
- `base:${file.previousPath ?? file.path}`,
92
- `head:${file.path}`,
93
- ])
94
- if (!paths.has(key)) paths.set(key, file.path);
95
-
96
- return (source) => paths.get(`${source.side}:${source.file}`) ?? source.file;
97
- }
98
-
99
- /** Evaluate authored patterns against the changed-file list, never the filesystem. */
100
- export function fileLensMatcher(
101
- patterns: readonly string[],
102
- ): (file: { path: string; previousPath?: string }) => boolean {
103
- const matchers = patterns.map((pattern) => {
104
- const normalized = pattern.startsWith("./") ? pattern.slice(2) : pattern;
105
-
106
- const glob = new Minimatch(normalized, {
107
- nocase: process.platform === "darwin" || process.platform === "win32",
108
- windowsPathsNoEscape: true,
109
- nonegate: true,
110
- nocomment: true,
111
- optimizationLevel: 2,
112
- platform: "linux",
113
- nocaseMagicOnly: true,
114
- });
115
-
116
- return (path: string) => path === normalized || glob.match(path);
117
- });
118
-
119
- return (file) =>
120
- matchers.some(
121
- (matches) =>
122
- matches(file.path) ||
123
- (file.previousPath !== undefined && matches(file.previousPath)),
124
- );
125
- }
@@ -1,71 +0,0 @@
1
- export interface DiffHunk {
2
- file: string;
3
- oldStart: number;
4
- oldLines: number;
5
- newStart: number;
6
- newLines: number;
7
- lines: DiffHunkLine[];
8
- }
9
-
10
- export interface DiffHunkLine {
11
- kind: "context" | "add" | "remove";
12
- oldLine: number | null;
13
- newLine: number | null;
14
- text: string;
15
- }
16
-
17
- const HUNK_HEADER =
18
- /^@@ -(?<oldStart>\d+)(?:,(?<oldLines>\d+))? \+(?<newStart>\d+)(?:,(?<newLines>\d+))? @@/;
19
-
20
- export function parseUnifiedPatch(
21
- file: string,
22
- patch: string | null | undefined,
23
- ): DiffHunk[] {
24
- if (!patch) return [];
25
-
26
- const hunks: DiffHunk[] = [];
27
- let current: DiffHunk | null = null;
28
- let oldLine = 0;
29
- let newLine = 0;
30
-
31
- for (const row of patch.split(/\r?\n/)) {
32
- const header = HUNK_HEADER.exec(row);
33
-
34
- if (header?.groups) {
35
- current = {
36
- file,
37
- oldStart: Number(header.groups.oldStart),
38
- oldLines: Number(header.groups.oldLines ?? "1"),
39
- newStart: Number(header.groups.newStart),
40
- newLines: Number(header.groups.newLines ?? "1"),
41
- lines: [],
42
- };
43
- oldLine = current.oldStart;
44
- newLine = current.newStart;
45
- hunks.push(current);
46
- continue;
47
- }
48
-
49
- if (!current || row.startsWith("\")) continue;
50
-
51
- const marker = row[0];
52
- const text = row.slice(1);
53
- let line: DiffHunkLine | null = null;
54
-
55
- if (marker === " ") {
56
- line = { kind: "context", oldLine, newLine, text };
57
- oldLine += 1;
58
- newLine += 1;
59
- } else if (marker === "+") {
60
- line = { kind: "add", oldLine: null, newLine, text };
61
- newLine += 1;
62
- } else if (marker === "-") {
63
- line = { kind: "remove", oldLine, newLine: null, text };
64
- oldLine += 1;
65
- }
66
-
67
- if (line) current.lines.push(line);
68
- }
69
-
70
- return hunks;
71
- }
@@ -1,7 +1,7 @@
1
1
  import { a as jsonNumber, c as jsonString, o as jsonObject, r as jsonArray, u as parseJsonText } from "./src-X9phtB2j.js";
2
- import { S as sessionMetaSchema, b as commitShaSchema, y as byCommitSchema } from "./src-CGP5ytbV.js";
3
2
  import { i as isS3MockMode, l as s3CacheIdentity, s as resolveS3Credentials, u as s3MockRoot } from "./s3-config-CjcLyFV5.js";
4
3
  import { t as errorMessage } from "./error-message-OtiDonty.js";
4
+ import { S as sessionMetaSchema, b as commitShaSchema, y as byCommitSchema } from "./src-CGP5ytbV.js";
5
5
  import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
6
6
  import path from "node:path";
7
7
  import { tmpdir } from "node:os";