@dev.fast/whiteboard 0.2.3 → 0.2.4
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-DLE9XZhi.js → account-alias-_1_7vROx.js} +1 -1
- package/dist/agent-cli-BR2j-2n5.js +2 -0
- package/dist/{agent-cli-DRRQfHQ-.js → agent-cli-BrFqhnzM.js} +6 -6
- package/dist/{agent-client-DoaODH6I.js → agent-client-B_b1GtUc.js} +2 -2
- package/dist/{authoring-tools-F_q8cC7J.js → authoring-tools-DvIO906l.js} +2 -2
- package/dist/build-info.json +1 -1
- package/dist/{cli-DtolttUF.js → cli-gRGxkwc0.js} +1 -1
- package/dist/{cli-runner-Cwg5PeH2.js → cli-runner-Cjl8h376.js} +11 -11
- package/dist/cli.js +2 -2
- package/dist/{client-D01H2KOV.js → client-BFClfQLO.js} +2 -2
- package/dist/{desktop-discovery-DK2HoBy5.js → desktop-discovery-C-Qz54wO.js} +1 -1
- package/dist/{headless-host-Dd_-zkC4.js → headless-host-DcWaxx9P.js} +2 -2
- package/dist/{local-data-D-EoJfPx.js → local-data-Bm84Xdck.js} +72 -78
- package/dist/{mcp-BAE5rMgB.js → mcp-BDy9Aybd.js} +3 -3
- package/dist/{process-error-telemetry-mzRG988B.js → process-error-telemetry-Dzh5a3s_.js} +23 -17
- package/dist/profile-BQGaX8aX.js +2 -0
- package/dist/{profile-WzZu7Spt.js → profile-RDEioF8b.js} +1 -1
- package/dist/{request-origin-DlHTFCrQ.js → request-origin-DA4K1qWY.js} +1 -1
- package/dist/{review-telemetry-Pp4ZsVrh.js → review-telemetry-DBy3eVCo.js} +2 -2
- package/dist/server/desktop-host.js +10 -10
- package/dist/sharing/index.d.ts +13 -12
- package/dist/sharing/index.js +1 -1
- package/dist/{src-DHiDJQDy.js → src-WCbabvdS.js} +3 -2
- package/dist/{stored-document-migration-T9Uj5MkN.js → stored-document-migration-BxZWQQjv.js} +1 -1
- package/dist/{tool-failure-Djeeax6q.js → tool-failure-DJmTieh5.js} +1 -1
- package/package.json +5 -5
- package/src/review-api/comparison-coverage.ts +192 -165
- package/src/review-api/http.ts +11 -0
- package/src/review-api/local-data.ts +9 -3
- package/src/review-api/review-progress.ts +19 -9
- package/src/server/diffr-config.ts +1 -1
- package/src/server/structural-diff.ts +10 -9
- package/dist/agent-cli-50KJgMKi.js +0 -2
- package/dist/profile-Cqztt-9-.js +0 -2
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { a as diffFileSummaries, b as resolveRevision, i as diff, x as splitGitPatchFiles } from "../src-CmdiBL20.js";
|
|
3
3
|
import { c as jsonString, i as jsonBoolean, n as isJsonObject, p as isObjectValue, s as jsonProperty, u as parseJsonText } from "../src-X9phtB2j.js";
|
|
4
|
-
import { i as SharedReviewStore } from "../client-
|
|
5
|
-
import { c as ReviewBugReportRequestSchema, l as parseReviewBugReportResponse, o as parseZod, s as ReviewBugReportMetaV2Schema, t as parseReviewCliInstallApplyRequest, v as reviewDiffrSummarizerInputSchema } from "../src-
|
|
6
|
-
import { C as resourceReferences, p as documentSchema } from "../stored-document-migration-
|
|
4
|
+
import { i as SharedReviewStore } from "../client-BFClfQLO.js";
|
|
5
|
+
import { c as ReviewBugReportRequestSchema, l as parseReviewBugReportResponse, o as parseZod, s as ReviewBugReportMetaV2Schema, t as parseReviewCliInstallApplyRequest, v as reviewDiffrSummarizerInputSchema } from "../src-WCbabvdS.js";
|
|
6
|
+
import { C as resourceReferences, p as documentSchema } from "../stored-document-migration-BxZWQQjv.js";
|
|
7
7
|
import { t as ReviewInputError } from "../input-error-OLgB_h31.js";
|
|
8
8
|
import { A as devReviewHome, P as writePrivateJsonAtomic } from "../s3-config-CAxhO9u_.js";
|
|
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
|
-
import { c as reviewInstanceIdentity, t as REVIEW_INSTANCE_ENV } from "../desktop-discovery-
|
|
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-
|
|
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-
|
|
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-
|
|
11
|
+
import { c as reviewInstanceIdentity, t as REVIEW_INSTANCE_ENV } from "../desktop-discovery-C-Qz54wO.js";
|
|
12
|
+
import { t as openReviewProfile } from "../profile-RDEioF8b.js";
|
|
13
|
+
import { r as reviewTelemetryChannel, t as ReviewTelemetry } from "../review-telemetry-DBy3eVCo.js";
|
|
14
|
+
import { o as REVIEW_TELEMETRY_TABS } from "../request-origin-DA4K1qWY.js";
|
|
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-_1_7vROx.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-Dzh5a3s_.js";
|
|
17
|
+
import { c as readQuerySchemas } from "../authoring-tools-DvIO906l.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/dist/sharing/index.d.ts
CHANGED
|
@@ -67,7 +67,7 @@ interface LocalVcsCommitSummary {
|
|
|
67
67
|
deletions: number;
|
|
68
68
|
}
|
|
69
69
|
//#endregion
|
|
70
|
-
//#region ../../
|
|
70
|
+
//#region ../../diffr/diffr-ts/dist/contract.d.ts
|
|
71
71
|
/** A pairing always has at least one side; additions/deletions omit the other. */
|
|
72
72
|
type StructuralPairing<T> = {
|
|
73
73
|
lhs: T;
|
|
@@ -171,6 +171,8 @@ type StructuralRegion = {
|
|
|
171
171
|
type StructuralNode = {
|
|
172
172
|
kind: "leaf";
|
|
173
173
|
alignment_id: number;
|
|
174
|
+
/** The partner leaf's `id` on the other side; absent when added or deleted. */
|
|
175
|
+
pair?: number;
|
|
174
176
|
changed?: StructuralSpan[];
|
|
175
177
|
} | {
|
|
176
178
|
kind: "fold";
|
|
@@ -310,7 +312,7 @@ declare const fileLineRangeSchema: z.ZodObject<{
|
|
|
310
312
|
type FileLineRange = z.infer<typeof fileLineRangeSchema>;
|
|
311
313
|
//#endregion
|
|
312
314
|
//#region src/lens-selection.d.ts
|
|
313
|
-
type AlignmentRow
|
|
315
|
+
type AlignmentRow = readonly [number | null, number | null];
|
|
314
316
|
//#endregion
|
|
315
317
|
//#region src/viewed-coverage.d.ts
|
|
316
318
|
/** Zero-based, half-open intervals; always normalized at the storage boundary. */
|
|
@@ -319,7 +321,7 @@ interface Coverage {
|
|
|
319
321
|
base: LineInterval[];
|
|
320
322
|
head: LineInterval[];
|
|
321
323
|
}
|
|
322
|
-
interface CoverageFile
|
|
324
|
+
interface CoverageFile {
|
|
323
325
|
path: string;
|
|
324
326
|
previousPath?: string;
|
|
325
327
|
fingerprint: string;
|
|
@@ -1038,9 +1040,11 @@ interface WrittenComponent {
|
|
|
1038
1040
|
//#region src/review-api/comparison-coverage.d.ts
|
|
1039
1041
|
type CoverageMode = "structural" | "textual";
|
|
1040
1042
|
interface ComparisonCoverage {
|
|
1041
|
-
|
|
1043
|
+
/** All Git changes are counted, even if folding is still loading. */
|
|
1044
|
+
counted: boolean;
|
|
1045
|
+
files: CoverageFile[];
|
|
1042
1046
|
fileSources: Map<string, FileLineRange[]>;
|
|
1043
|
-
alignments: Map<string, readonly AlignmentRow
|
|
1047
|
+
alignments: Map<string, readonly AlignmentRow[]>;
|
|
1044
1048
|
}
|
|
1045
1049
|
//#endregion
|
|
1046
1050
|
//#region src/review-api/pull-request.d.ts
|
|
@@ -1694,6 +1698,7 @@ declare class LocalReviewData {
|
|
|
1694
1698
|
coverageSnapshot(reviewId: string, pins: Pins, mode: CoverageMode): {
|
|
1695
1699
|
pending: boolean;
|
|
1696
1700
|
comparison: ComparisonCoverage | {
|
|
1701
|
+
counted: false;
|
|
1697
1702
|
files: never[];
|
|
1698
1703
|
fileSources: Map<any, any>;
|
|
1699
1704
|
alignments: Map<any, any>;
|
|
@@ -1701,14 +1706,10 @@ declare class LocalReviewData {
|
|
|
1701
1706
|
};
|
|
1702
1707
|
private coverageNotification;
|
|
1703
1708
|
private notifyCoverage;
|
|
1704
|
-
coverage(reviewId: string, pins: Pins, mode: CoverageMode): Promise<
|
|
1705
|
-
files: CoverageFile[];
|
|
1706
|
-
fileSources: Map<string, FileLineRange[]>;
|
|
1707
|
-
alignments: Map<string, readonly AlignmentRow[]>;
|
|
1708
|
-
}>;
|
|
1709
|
+
coverage(reviewId: string, pins: Pins, mode: CoverageMode): Promise<ComparisonCoverage>;
|
|
1709
1710
|
changes(pins: Pins): Promise<LocalVcsDiffFileSummary[]>;
|
|
1710
|
-
changes(pins: Pins, file: string): Promise<string>;
|
|
1711
|
-
changes(pins: Pins, file?: string): Promise<LocalVcsDiffFileSummary[] | string>;
|
|
1711
|
+
changes(pins: Pins, file: string, previousPath?: string): Promise<string>;
|
|
1712
|
+
changes(pins: Pins, file?: string, previousPath?: string): Promise<LocalVcsDiffFileSummary[] | string>;
|
|
1712
1713
|
private summaries;
|
|
1713
1714
|
/** Raw Git patch text for exact filenames, or every change. */
|
|
1714
1715
|
private rawPatch;
|
package/dist/sharing/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as sharedReviewId, c as verifyShareRepository, i as SharedReviewStore, l as exportShare, n as ShareClient, o as validateShareBundle } from "../client-
|
|
1
|
+
import { a as sharedReviewId, c as verifyShareRepository, i as SharedReviewStore, l as exportShare, n as ShareClient, o as validateShareBundle } from "../client-BFClfQLO.js";
|
|
2
2
|
export { ShareClient, SharedReviewStore, exportShare, sharedReviewId, validateShareBundle, verifyShareRepository };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as isJsonObject } from "./src-X9phtB2j.js";
|
|
2
2
|
import { _ as ReviewAgentTraceEventSchema, v as ReviewAgentTraceSessionSchema } from "./src-CGP5ytbV.js";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
-
//#region ../../
|
|
4
|
+
//#region ../../diffr/diffr-ts/dist/contract.js
|
|
5
5
|
/**
|
|
6
6
|
* Mirrors crates/diffr-core/src/protocol/mod.rs and crates/diffr-core/src/pairing.rs. See ../README.md for sync checks.
|
|
7
7
|
* Import only zod: Review embeds this file in generated source.
|
|
@@ -128,6 +128,7 @@ const StructuralRegionSchema = z.lazy(() => z.object({
|
|
|
128
128
|
const StructuralNodeSchema = z.lazy(() => z.union([z.object({
|
|
129
129
|
kind: z.literal("leaf"),
|
|
130
130
|
alignment_id: structuralU32,
|
|
131
|
+
pair: structuralU32.optional(),
|
|
131
132
|
changed: z.array(StructuralSpanSchema).optional()
|
|
132
133
|
}), z.object({
|
|
133
134
|
kind: z.literal("fold"),
|
|
@@ -158,7 +159,7 @@ const StructuralLineCountsSchema = z.lazy(() => z.object({
|
|
|
158
159
|
removed: structuralU32
|
|
159
160
|
}));
|
|
160
161
|
//#endregion
|
|
161
|
-
//#region ../../
|
|
162
|
+
//#region ../../diffr/diffr-ts/dist/stream.js
|
|
162
163
|
function decodeStructuralDiffEvent(line) {
|
|
163
164
|
try {
|
|
164
165
|
return StructuralDiffEventSchema.parse(JSON.parse(line));
|
package/dist/{stored-document-migration-T9Uj5MkN.js → stored-document-migration-BxZWQQjv.js}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { f as isNumberValue, l as jsonValueSchema, m as isStringValue, n as isJsonObject } from "./src-X9phtB2j.js";
|
|
2
|
-
import "./src-
|
|
2
|
+
import "./src-WCbabvdS.js";
|
|
3
3
|
import { t as ReviewInputError } from "./input-error-OLgB_h31.js";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { fromMarkdown } from "mdast-util-from-markdown";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { m as isStringValue, n as isJsonObject } from "./src-X9phtB2j.js";
|
|
2
|
-
import { n as callAuthoringTool, s as ReviewApiError, t as ToolText } from "./agent-client-
|
|
2
|
+
import { n as callAuthoringTool, s as ReviewApiError, t as ToolText } from "./agent-client-B_b1GtUc.js";
|
|
3
3
|
import { t as ReviewInputError } from "./input-error-OLgB_h31.js";
|
|
4
4
|
//#region src/review-api/public-tools.ts
|
|
5
5
|
function publicDescription(text) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dev.fast/whiteboard",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -43,7 +43,6 @@
|
|
|
43
43
|
"@agentclientprotocol/claude-agent-acp": "0.84.0",
|
|
44
44
|
"@agentclientprotocol/codex-acp": "2.0.0",
|
|
45
45
|
"@agentclientprotocol/sdk": "1.5.1",
|
|
46
|
-
"@dev.fast/diffr": "0.1.15",
|
|
47
46
|
"@hono/node-server": "2.0.12",
|
|
48
47
|
"@img/sharp-wasm32": "0.35.5",
|
|
49
48
|
"@modelcontextprotocol/sdk": "1.31.0",
|
|
@@ -59,7 +58,8 @@
|
|
|
59
58
|
"semver": "7.8.5",
|
|
60
59
|
"sharp": "0.35.5",
|
|
61
60
|
"smol-toml": "1.9.0",
|
|
62
|
-
"zod": "4.6.5"
|
|
61
|
+
"zod": "4.6.5",
|
|
62
|
+
"@dev.fast/diffr": "0.1.17"
|
|
63
63
|
},
|
|
64
64
|
"devDependencies": {
|
|
65
65
|
"@dev.fast/local-vcs": "^0.1.0",
|
|
@@ -85,14 +85,14 @@
|
|
|
85
85
|
"repo": "devdotfast/review",
|
|
86
86
|
"docs": "packages/review/instructions/authoring.md"
|
|
87
87
|
},
|
|
88
|
-
"gitHead": "
|
|
88
|
+
"gitHead": "5b00f0e66d034e187a29d270b3690a37b57ccf7b",
|
|
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",
|
|
92
92
|
"build:tutorial-assets": "tsx scripts/build-tutorial-assets.ts",
|
|
93
93
|
"ensure:tutorial-assets": "tsx scripts/ensure-tutorial-assets.ts",
|
|
94
94
|
"check:tutorial": "tsx scripts/check-tutorial.ts",
|
|
95
|
-
"build:workspace-deps": "pnpm --filter @dev.fast/json --filter @dev.fast/local-vcs --filter @dev.fast/review-protocol --filter @dev.fast/review-share-protocol --filter @dev.fast/trace-protocol --filter @dev.fast/trace-core build",
|
|
95
|
+
"build:workspace-deps": "pnpm --filter @dev.fast/diffr --filter @dev.fast/json --filter @dev.fast/local-vcs --filter @dev.fast/review-protocol --filter @dev.fast/review-share-protocol --filter @dev.fast/trace-protocol --filter @dev.fast/trace-core build",
|
|
96
96
|
"pretypecheck": "pnpm run ensure:tutorial-assets",
|
|
97
97
|
"pretest": "pnpm run ensure:tutorial-assets",
|
|
98
98
|
"pretest:node": "pnpm run ensure:tutorial-assets",
|
|
@@ -29,6 +29,8 @@ const hash = (parts: (string | null)[]) =>
|
|
|
29
29
|
createHash("sha256").update(JSON.stringify(parts)).digest("hex");
|
|
30
30
|
|
|
31
31
|
export interface ComparisonCoverage {
|
|
32
|
+
/** All Git changes are counted, even if folding is still loading. */
|
|
33
|
+
counted: boolean;
|
|
32
34
|
files: CoverageFile[];
|
|
33
35
|
fileSources: Map<string, FileLineRange[]>;
|
|
34
36
|
alignments: Map<string, readonly AlignmentRow[]>;
|
|
@@ -42,196 +44,221 @@ export async function comparisonCoverage(
|
|
|
42
44
|
mode: CoverageMode,
|
|
43
45
|
signal: AbortSignal,
|
|
44
46
|
publish?: (coverage: ComparisonCoverage) => void,
|
|
45
|
-
) {
|
|
47
|
+
): Promise<ComparisonCoverage> {
|
|
46
48
|
const fileSources = new Map<string, FileLineRange[]>();
|
|
47
49
|
const alignments = new Map<string, readonly AlignmentRow[]>();
|
|
48
50
|
|
|
49
51
|
const files: CoverageFile[] = [];
|
|
50
52
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const changed = emptyCoverage();
|
|
56
|
-
|
|
57
|
-
for (const hunk of parseUnifiedPatch(file.path, patch))
|
|
58
|
-
for (const line of hunk.lines) {
|
|
59
|
-
if (line.kind === "add")
|
|
60
|
-
changed.head.push([line.newLine! - 1, line.newLine!]);
|
|
61
|
-
|
|
62
|
-
if (line.kind === "remove")
|
|
63
|
-
changed.base.push([line.oldLine! - 1, line.oldLine!]);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
changed.base = unionIntervals(changed.base);
|
|
67
|
-
changed.head = unionIntervals(changed.head);
|
|
68
|
-
|
|
69
|
-
const [base, head] = await Promise.all([
|
|
70
|
-
file.status === "added"
|
|
71
|
-
? null
|
|
72
|
-
: data
|
|
73
|
-
.file(pins, "base", file.previousPath ?? file.path)
|
|
74
|
-
.then((value) => value.text)
|
|
75
|
-
.catch(() => null),
|
|
76
|
-
file.status === "deleted"
|
|
77
|
-
? null
|
|
78
|
-
: data
|
|
79
|
-
.file(pins, "head", file.path)
|
|
80
|
-
.then((value) => value.text)
|
|
81
|
-
.catch(() => null),
|
|
82
|
-
]);
|
|
83
|
-
|
|
84
|
-
alignments.set(
|
|
85
|
-
file.path,
|
|
86
|
-
textualRows(
|
|
87
|
-
file.path,
|
|
88
|
-
patch,
|
|
89
|
-
base === null ? 0 : base.split("\n").length,
|
|
90
|
-
head === null ? 0 : head.split("\n").length,
|
|
91
|
-
),
|
|
92
|
-
);
|
|
53
|
+
for (const file of await data.changes(pins)) {
|
|
54
|
+
signal.throwIfAborted();
|
|
55
|
+
const patch = await data.changes(pins, file.path, file.previousPath);
|
|
56
|
+
const changed = emptyCoverage();
|
|
93
57
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
(
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
58
|
+
for (const hunk of parseUnifiedPatch(file.path, patch))
|
|
59
|
+
for (const line of hunk.lines) {
|
|
60
|
+
if (line.kind === "add")
|
|
61
|
+
changed.head.push([line.newLine! - 1, line.newLine!]);
|
|
62
|
+
|
|
63
|
+
if (line.kind === "remove")
|
|
64
|
+
changed.base.push([line.oldLine! - 1, line.oldLine!]);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
changed.base = unionIntervals(changed.base);
|
|
68
|
+
changed.head = unionIntervals(changed.head);
|
|
69
|
+
|
|
70
|
+
const [base, head] = await Promise.all([
|
|
71
|
+
file.status === "added"
|
|
72
|
+
? null
|
|
73
|
+
: data
|
|
74
|
+
.file(pins, "base", file.previousPath ?? file.path)
|
|
75
|
+
.then((value) => value.text)
|
|
76
|
+
.catch(() => null),
|
|
77
|
+
file.status === "deleted"
|
|
78
|
+
? null
|
|
79
|
+
: data
|
|
80
|
+
.file(pins, "head", file.path)
|
|
81
|
+
.then((value) => value.text)
|
|
82
|
+
.catch(() => null),
|
|
83
|
+
]);
|
|
84
|
+
|
|
85
|
+
alignments.set(
|
|
86
|
+
file.path,
|
|
87
|
+
textualRows(
|
|
88
|
+
file.path,
|
|
89
|
+
patch,
|
|
90
|
+
base === null ? 0 : base.split("\n").length,
|
|
91
|
+
head === null ? 0 : head.split("\n").length,
|
|
92
|
+
),
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
const readable =
|
|
96
|
+
(file.status === "added" || base !== null) &&
|
|
97
|
+
(file.status === "deleted" || head !== null);
|
|
98
|
+
|
|
99
|
+
const fingerprint = hash([
|
|
100
|
+
pins.repositoryId,
|
|
101
|
+
base,
|
|
102
|
+
head,
|
|
103
|
+
...(readable ? [] : [pins.base, pins.head, patch]),
|
|
104
|
+
]);
|
|
105
|
+
|
|
106
|
+
fileSources.set(file.path, [
|
|
107
|
+
...(base !== null
|
|
108
|
+
? [
|
|
109
|
+
{
|
|
110
|
+
side: "base" as const,
|
|
111
|
+
file: file.previousPath ?? file.path,
|
|
112
|
+
fromLine: 1,
|
|
113
|
+
toLine: base.split("\n").length,
|
|
114
|
+
},
|
|
115
|
+
]
|
|
116
|
+
: []),
|
|
117
|
+
...(head !== null
|
|
118
|
+
? [
|
|
119
|
+
{
|
|
120
|
+
side: "head" as const,
|
|
121
|
+
file: file.path,
|
|
122
|
+
fromLine: 1,
|
|
123
|
+
toLine: head.split("\n").length,
|
|
124
|
+
},
|
|
125
|
+
]
|
|
126
|
+
: []),
|
|
127
|
+
]);
|
|
128
|
+
files.push({
|
|
129
|
+
path: file.path,
|
|
130
|
+
previousPath: file.previousPath,
|
|
131
|
+
fingerprint,
|
|
132
|
+
changed,
|
|
133
|
+
viewed: emptyCoverage(),
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
if (mode === "textual")
|
|
134
137
|
publish?.({
|
|
138
|
+
counted: false,
|
|
135
139
|
files: [...files],
|
|
136
140
|
fileSources: new Map(fileSources),
|
|
137
141
|
alignments: new Map(alignments),
|
|
138
142
|
});
|
|
139
|
-
|
|
140
|
-
} else {
|
|
141
|
-
const remaining = new Set<string>();
|
|
142
|
-
|
|
143
|
-
for await (const event of data.structuralChanges({
|
|
144
|
-
reviewId,
|
|
145
|
-
pins,
|
|
146
|
-
signal,
|
|
147
|
-
})) {
|
|
148
|
-
if (event.type === "start") {
|
|
149
|
-
for (const entry of event.files)
|
|
150
|
-
remaining.add((entry.file.rhs ?? entry.file.lhs)!.path);
|
|
151
|
-
|
|
152
|
-
if (!remaining.size) break;
|
|
153
|
-
continue;
|
|
154
|
-
}
|
|
143
|
+
}
|
|
155
144
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
145
|
+
const coverage: ComparisonCoverage = {
|
|
146
|
+
files,
|
|
147
|
+
fileSources,
|
|
148
|
+
alignments,
|
|
149
|
+
counted: true,
|
|
150
|
+
};
|
|
160
151
|
|
|
161
|
-
|
|
152
|
+
if (mode === "textual") return coverage;
|
|
162
153
|
|
|
163
|
-
|
|
154
|
+
// Keep Git's totals and file identities while structural results add folding.
|
|
155
|
+
const publishCurrent = () =>
|
|
156
|
+
publish?.({ ...coverage, files: [...coverage.files] });
|
|
164
157
|
|
|
165
|
-
|
|
166
|
-
throw new Error(`Unexpected structural result: ${path}`);
|
|
158
|
+
publishCurrent();
|
|
167
159
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
160
|
+
const baseFiles = new Map(
|
|
161
|
+
coverage.files.map((file, index) => [
|
|
162
|
+
file.previousPath ?? file.path,
|
|
163
|
+
index,
|
|
164
|
+
]),
|
|
165
|
+
);
|
|
171
166
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
167
|
+
const headFiles = new Map(
|
|
168
|
+
coverage.files.map((file, index) => [file.path, index]),
|
|
169
|
+
);
|
|
175
170
|
|
|
176
|
-
|
|
171
|
+
const remaining = new Set<string>();
|
|
177
172
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
base,
|
|
187
|
-
head,
|
|
188
|
-
...(diff.type === "binary"
|
|
189
|
-
? [event.file.lhs?.oid ?? null, event.file.rhs?.oid ?? null]
|
|
190
|
-
: []),
|
|
191
|
-
]);
|
|
192
|
-
|
|
193
|
-
const sources: FileLineRange[] = [];
|
|
194
|
-
|
|
195
|
-
if (base !== null)
|
|
196
|
-
sources.push({
|
|
197
|
-
side: "base",
|
|
198
|
-
file: event.file.lhs!.path,
|
|
199
|
-
fromLine: 1,
|
|
200
|
-
toLine: base.split("\n").length,
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
if (head !== null)
|
|
204
|
-
sources.push({
|
|
205
|
-
side: "head",
|
|
206
|
-
file: path,
|
|
207
|
-
fromLine: 1,
|
|
208
|
-
toLine: head.split("\n").length,
|
|
209
|
-
});
|
|
210
|
-
fileSources.set(path, sources);
|
|
211
|
-
|
|
212
|
-
if (diff.type === "text") alignments.set(path, structuralRows(diff));
|
|
213
|
-
files.push({
|
|
214
|
-
path,
|
|
215
|
-
previousPath,
|
|
216
|
-
fingerprint,
|
|
217
|
-
changed:
|
|
218
|
-
diff.type === "text" ? diff.structural_changes : emptyCoverage(),
|
|
219
|
-
folded: foldedChanges(diff),
|
|
220
|
-
viewed: emptyCoverage(),
|
|
221
|
-
});
|
|
222
|
-
publish?.({
|
|
223
|
-
files: [...files],
|
|
224
|
-
fileSources: new Map(fileSources),
|
|
225
|
-
alignments: new Map(alignments),
|
|
226
|
-
});
|
|
173
|
+
for await (const event of data.structuralChanges({
|
|
174
|
+
reviewId,
|
|
175
|
+
pins,
|
|
176
|
+
signal,
|
|
177
|
+
})) {
|
|
178
|
+
if (event.type === "start") {
|
|
179
|
+
for (const entry of event.files)
|
|
180
|
+
remaining.add((entry.file.rhs ?? entry.file.lhs)!.path);
|
|
227
181
|
|
|
228
182
|
if (!remaining.size) break;
|
|
183
|
+
continue;
|
|
229
184
|
}
|
|
230
185
|
|
|
231
|
-
if (
|
|
186
|
+
if (event.type === "complete" && (event.failed || event.aborted))
|
|
187
|
+
throw new Error(
|
|
188
|
+
event.aborted?.message ?? "Structural coverage is incomplete.",
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
if (event.type !== "file") continue;
|
|
192
|
+
|
|
193
|
+
const path = (event.file.rhs ?? event.file.lhs)!.path;
|
|
194
|
+
|
|
195
|
+
if (!remaining.delete(path))
|
|
196
|
+
throw new Error(`Unexpected structural result: ${path}`);
|
|
197
|
+
|
|
198
|
+
if (event.error) {
|
|
199
|
+
if (
|
|
200
|
+
event.error.code !== "unsupported_file_type" &&
|
|
201
|
+
event.error.code !== "not_utf8"
|
|
202
|
+
)
|
|
203
|
+
throw new Error(`Cannot count ${path}: ${event.error.message}`);
|
|
204
|
+
} else if (event.diff.type === "text") {
|
|
205
|
+
const diff = event.diff;
|
|
206
|
+
const folded = foldedChanges(diff);
|
|
207
|
+
|
|
208
|
+
// Match each side separately: diffr can split a Git rename into two files.
|
|
209
|
+
for (const side of ["base", "head"] as const) {
|
|
210
|
+
const source = side === "base" ? event.file.lhs : event.file.rhs;
|
|
211
|
+
|
|
212
|
+
const index =
|
|
213
|
+
source && (side === "base" ? baseFiles : headFiles).get(source.path);
|
|
214
|
+
|
|
215
|
+
if (index === undefined) continue;
|
|
216
|
+
const file = coverage.files[index];
|
|
217
|
+
|
|
218
|
+
const visible = subtractIntervals(
|
|
219
|
+
diff.structural_changes[side],
|
|
220
|
+
folded[side],
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
coverage.files[index] = {
|
|
224
|
+
...file,
|
|
225
|
+
folded: {
|
|
226
|
+
...(file.folded ?? emptyCoverage()),
|
|
227
|
+
[side]: subtractIntervals(file.changed[side], visible),
|
|
228
|
+
},
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const baseIndex = event.file.lhs && baseFiles.get(event.file.lhs.path);
|
|
233
|
+
const headIndex = event.file.rhs && headFiles.get(event.file.rhs.path);
|
|
234
|
+
const index = headIndex ?? baseIndex;
|
|
235
|
+
|
|
236
|
+
if (index !== undefined) {
|
|
237
|
+
const sources =
|
|
238
|
+
coverage.fileSources.get(coverage.files[index].path) ?? [];
|
|
239
|
+
|
|
240
|
+
if (
|
|
241
|
+
sources.every(
|
|
242
|
+
(source) =>
|
|
243
|
+
source.file ===
|
|
244
|
+
(source.side === "base" ? event.file.lhs : event.file.rhs)?.path,
|
|
245
|
+
)
|
|
246
|
+
)
|
|
247
|
+
coverage.alignments = new Map(coverage.alignments).set(
|
|
248
|
+
coverage.files[index].path,
|
|
249
|
+
structuralRows(diff),
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
publishCurrent();
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (!remaining.size) break;
|
|
232
257
|
}
|
|
233
258
|
|
|
234
|
-
|
|
259
|
+
if (remaining.size) throw new Error("Structural coverage is incomplete.");
|
|
260
|
+
|
|
261
|
+
return coverage;
|
|
235
262
|
}
|
|
236
263
|
|
|
237
264
|
/**
|
package/src/review-api/http.ts
CHANGED
|
@@ -389,12 +389,22 @@ export function createReviewApi(
|
|
|
389
389
|
|
|
390
390
|
const snapshot = store.read(id);
|
|
391
391
|
|
|
392
|
+
const pins = snapshot.pins
|
|
393
|
+
? (await data.resolveSource(snapshot)).pins
|
|
394
|
+
: undefined;
|
|
395
|
+
|
|
396
|
+
const coverage = pins && data.coverageSnapshot(id, pins, input.mode);
|
|
397
|
+
|
|
398
|
+
const partial =
|
|
399
|
+
coverage && coverage.pending ? coverage.comparison : undefined;
|
|
400
|
+
|
|
392
401
|
const progress = await reviewProgress(
|
|
393
402
|
store,
|
|
394
403
|
data,
|
|
395
404
|
snapshot,
|
|
396
405
|
context.req.raw.signal,
|
|
397
406
|
input.mode,
|
|
407
|
+
partial,
|
|
398
408
|
);
|
|
399
409
|
|
|
400
410
|
const files = input.files.map((update) => {
|
|
@@ -427,6 +437,7 @@ export function createReviewApi(
|
|
|
427
437
|
store.read(id, input.version),
|
|
428
438
|
context.req.raw.signal,
|
|
429
439
|
input.mode,
|
|
440
|
+
partial,
|
|
430
441
|
),
|
|
431
442
|
);
|
|
432
443
|
});
|
|
@@ -1409,6 +1409,7 @@ export class LocalReviewData {
|
|
|
1409
1409
|
return {
|
|
1410
1410
|
pending,
|
|
1411
1411
|
comparison: entry.partial ?? {
|
|
1412
|
+
counted: false,
|
|
1412
1413
|
files: [],
|
|
1413
1414
|
fileSources: new Map(),
|
|
1414
1415
|
alignments: new Map(),
|
|
@@ -1496,16 +1497,21 @@ export class LocalReviewData {
|
|
|
1496
1497
|
}
|
|
1497
1498
|
|
|
1498
1499
|
changes(pins: Pins): Promise<LocalVcsDiffFileSummary[]>;
|
|
1499
|
-
changes(pins: Pins, file: string): Promise<string>;
|
|
1500
|
+
changes(pins: Pins, file: string, previousPath?: string): Promise<string>;
|
|
1500
1501
|
changes(
|
|
1501
1502
|
pins: Pins,
|
|
1502
1503
|
file?: string,
|
|
1504
|
+
previousPath?: string,
|
|
1503
1505
|
): Promise<LocalVcsDiffFileSummary[] | string>;
|
|
1504
|
-
async changes(pins: Pins, file?: string) {
|
|
1506
|
+
async changes(pins: Pins, file?: string, previousPath?: string) {
|
|
1505
1507
|
if (file === undefined) return this.summaries(pins);
|
|
1506
1508
|
checkRelativePath(file);
|
|
1507
1509
|
|
|
1508
|
-
|
|
1510
|
+
if (previousPath) checkRelativePath(previousPath);
|
|
1511
|
+
|
|
1512
|
+
return this.rawPatch(pins, {
|
|
1513
|
+
paths: previousPath ? [previousPath, file] : [file],
|
|
1514
|
+
});
|
|
1509
1515
|
}
|
|
1510
1516
|
private async summaries(pins: Pins) {
|
|
1511
1517
|
if (pins.worktreeRevision) {
|