@dev.fast/whiteboard 0.3.4-preview.20261019.126 → 0.3.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-B5-HYi1D.js → account-alias-CprZojXd.js} +8 -13
- package/dist/agent-cli-C6SPSII0.js +2 -0
- package/dist/{agent-cli-CohHf6Ua.js → agent-cli-CThN7Q59.js} +10 -15
- package/dist/{agent-client-Dtc-Kn_w.js → agent-client-BOOi7EUR.js} +3 -13
- package/dist/{authoring-tools-B7KU04f7.js → authoring-tools-BNwuMnz6.js} +27 -34
- package/dist/{background-server-C03RKxKS.js → background-server-CkvxA-6O.js} +5 -5
- package/dist/{background-server-CB9C4uoc.js → background-server-DLSDogkI.js} +1 -1
- package/dist/build-info.json +1 -1
- package/dist/{cli-CJaEb7zC.js → cli-R4yfa5DT.js} +1 -1
- package/dist/{cli-runner-DGDIqh3V.js → cli-runner-Cuc9FSzu.js} +26 -26
- package/dist/cli.js +3 -4
- package/dist/{client-lKVF_Elo.js → client-BN_FDxFr.js} +47 -253
- package/dist/{fuzzy-match-BmVJJm9I.js → fuzzy-match-BO9bK37N.js} +4 -6
- package/dist/{headless-host-DRtjf9WA.js → headless-host-CVBOQyRS.js} +1 -1
- package/dist/{headless-host-XhL1X4vX.js → headless-host-Cog6SpS9.js} +140 -513
- package/dist/{local-data-Cpl4ENbJ.js → local-data-D_9tvdsp.js} +323 -2419
- package/dist/{mcp-ovmiUE_x.js → mcp-D1hziANa.js} +9 -5
- package/dist/{package-paths-BWxO-UEL.js → package-paths-C--__jEv.js} +1 -1
- package/dist/profile-CYPmvBoA.js +2 -0
- package/dist/{profile-BadSkCkI.js → profile-DokFw782.js} +8 -20
- package/dist/{remote-attach-Dd-YobM6.js → remote-attach-CEJ-kvDY.js} +4 -4
- package/dist/{remote-extensions-CNXwqK0D.js → remote-extensions-Blcjr9Ze.js} +3 -3
- package/dist/{remote-extensions-VP-kfq0C.js → remote-extensions-GN8Gf_qG.js} +1 -1
- package/dist/{remote-language-server-BXk87KCr.js → remote-language-server-BTKBQ7x4.js} +5 -5
- package/dist/{remote-uninstall-DuOzsvaD.js → remote-uninstall-DW7Gdryh.js} +6 -6
- package/dist/{request-origin-B9qCPiVB.js → request-origin-Zcn_CjX4.js} +12 -45
- package/dist/{review-app-launcher-C7el2Uoy.js → review-app-launcher-CkwLclzR.js} +2 -2
- package/dist/{review-home-paths-D8AoCdd2.js → review-home-paths-j2BRAaNv.js} +17 -19
- package/dist/{review-telemetry-BsoRMC2w.js → review-telemetry-BLNwYnLV.js} +5 -5
- package/dist/runtime-CKiWhGrf.js +52 -0
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.js +1 -1
- package/dist/{s3-CsG2EWED.js → s3-DtJFWC0G.js} +1 -1
- package/dist/{s3-config-CjcLyFV5.js → s3-config-BTO12tCC.js} +2 -4
- package/dist/{s3-config-zz4GWh2T.js → s3-config-CSy3fx8H.js} +1 -1
- package/dist/server/desktop-host.js +76 -29
- package/dist/{server-discovery-CKjw3-6h.js → server-discovery-Bey8IqXH.js} +3 -3
- package/dist/sharing/index.d.ts +70 -484
- package/dist/sharing/index.js +1 -1
- package/dist/{src-WPaQn75m.js → src-BMPuxWv4.js} +73 -208
- package/dist/{src-BiWNbcF_.js → src-DsM3jO8G.js} +12 -89
- package/dist/{stored-document-migration-dFbewRTG.js → stored-document-migration-CChxtFAy.js} +269 -270
- package/dist/{thread-state-Do5LX10I.js → thread-state-5pYr6_zM.js} +2 -7
- package/dist/{tool-failure-DvI-gys2.js → tool-failure-C9MpbXJJ.js} +3 -10
- package/instructions/authoring.md +2 -3
- package/instructions/scratchpad.md +23 -0
- package/package.json +4 -4
- package/src/ask/agents.ts +1 -13
- package/src/ask/checkout-files.ts +5 -2
- package/src/ask/thread-state.ts +0 -4
- package/src/ask/thread.ts +0 -16
- package/src/ask/threads.ts +3 -24
- package/src/cli-install.ts +2 -13
- package/src/cli-runner.ts +1 -4
- package/src/cli.ts +1 -4
- package/src/diff-selection-migration.ts +34 -48
- package/src/lens-selection.ts +2 -38
- package/src/review-api/README.md +13 -52
- package/src/review-api/activity.ts +4 -1
- package/src/review-api/agent-cli.ts +1 -9
- package/src/review-api/anchor-quotes.ts +7 -14
- package/src/review-api/ask-history.ts +51 -137
- package/src/review-api/authoring-tools.ts +30 -45
- package/src/review-api/blocks/definition.ts +1 -1
- package/src/review-api/blocks/markdown.ts +2 -2
- package/src/review-api/document-headings.ts +27 -58
- package/src/review-api/document-text.ts +2 -31
- package/src/review-api/document.ts +34 -281
- package/src/review-api/github-provider.ts +13 -51
- package/src/review-api/http.ts +123 -702
- package/src/review-api/instructions.ts +19 -0
- package/src/review-api/local-data.ts +46 -310
- package/src/review-api/mcp.ts +11 -3
- package/src/review-api/onboarding.ts +1 -1
- package/src/review-api/profile.ts +6 -37
- package/src/review-api/public-tools.ts +2 -24
- package/src/review-api/pull-request.ts +49 -82
- package/src/review-api/request-origin.ts +0 -10
- package/src/review-api/review-progress.ts +27 -61
- package/src/review-api/store-schema.ts +29 -38
- package/src/review-api/store.ts +478 -2142
- package/src/review-api/worktree-events.ts +5 -3
- package/src/review-api/worktree-source.ts +7 -3
- package/src/review-api/worktree-structural.integration.ts +0 -72
- package/src/review-preferences.ts +88 -0
- package/src/review-stack.ts +23 -15
- package/src/runtime.ts +30 -4
- package/src/server/desktop-host.ts +1 -6
- package/src/server/desktop-server.ts +31 -1
- package/src/server/headless-host.ts +2 -0
- package/src/server/hono-http.ts +1 -2
- package/src/server/legacy-tutorial-cleanup.ts +3 -2
- package/src/server/review-gateway-list.ts +5 -3
- package/src/server/review-gateway-memory.ts +1 -1
- package/src/server/review-lifecycle-telemetry.ts +2 -2
- package/src/server/review-server-core.ts +5 -1
- package/src/server/structural-comparisons.ts +0 -47
- package/src/sharing/export.ts +7 -36
- package/src/sharing/host.ts +14 -34
- package/src/sharing/import.ts +24 -156
- package/src/sharing/repository.ts +20 -128
- package/src/startup-trace.ts +3 -3
- package/src/stored-document-migration.ts +19 -110
- package/src/ui-telemetry-events.ts +11 -33
- package/dist/agent-cli-_YyMIMRY.js +0 -2
- package/dist/lens-selection-CyJapcsl.js +0 -214
- package/dist/profile-DJvkBJNQ.js +0 -2
- package/dist/runtime-Bj2tD33R.js +0 -27
- package/src/heading-anchors.ts +0 -42
- package/src/review-api/board-order.ts +0 -144
- package/src/review-api/checkout-groups.ts +0 -560
- package/src/review-api/foreign-references.ts +0 -328
- package/src/review-api/link-preview.ts +0 -113
- package/src/review-api/scratchpad-plan-upgrade.ts +0 -250
- package/src/review-api/store-migrations.ts +0 -357
package/src/sharing/export.ts
CHANGED
|
@@ -14,11 +14,10 @@ import { lensSelections } from "@review/review-api/diff-lenses.js";
|
|
|
14
14
|
import { ReviewInputError } from "@review/review-api/document.js";
|
|
15
15
|
import {
|
|
16
16
|
anchorPins,
|
|
17
|
-
boardRepositoryId,
|
|
18
17
|
checkReferences,
|
|
19
18
|
documentSchema,
|
|
20
19
|
elements,
|
|
21
|
-
|
|
20
|
+
hasCodeReferences,
|
|
22
21
|
resourceReference,
|
|
23
22
|
resourceReferences,
|
|
24
23
|
sourceReferences,
|
|
@@ -47,33 +46,13 @@ export function digestBytes(bytes: Uint8Array): string {
|
|
|
47
46
|
export function validateShareSources(
|
|
48
47
|
snapshot: Pick<Snapshot, "pins" | "document" | "lenses">,
|
|
49
48
|
) {
|
|
50
|
-
if (!snapshot.pins &&
|
|
49
|
+
if (!snapshot.pins && hasCodeReferences(snapshot))
|
|
51
50
|
throw new ReviewInputError(
|
|
52
51
|
"Reviews with code references need source pins before sharing.",
|
|
53
52
|
409,
|
|
54
53
|
);
|
|
55
54
|
}
|
|
56
55
|
|
|
57
|
-
/** The commits a board's references read at besides its base and head. A
|
|
58
|
-
* recipient fetches them too. A shared board names no repository of its
|
|
59
|
-
* own, so one stands in for its commit links. */
|
|
60
|
-
export function referenceCommits(
|
|
61
|
-
snapshot: Pick<Snapshot, "pins" | "document" | "target">,
|
|
62
|
-
repositoryId = boardRepositoryId(snapshot) ?? "shared",
|
|
63
|
-
): string[] {
|
|
64
|
-
const own = new Set([snapshot.pins?.base, snapshot.pins?.head]);
|
|
65
|
-
const commits = new Set<string>();
|
|
66
|
-
|
|
67
|
-
for (const { source } of sourceReferences(snapshot.document, {
|
|
68
|
-
tolerant: true,
|
|
69
|
-
repositoryId,
|
|
70
|
-
}))
|
|
71
|
-
for (const commit of [source.pins?.base, source.pins?.head])
|
|
72
|
-
if (commit && !own.has(commit)) commits.add(commit);
|
|
73
|
-
|
|
74
|
-
return [...commits].sort();
|
|
75
|
-
}
|
|
76
|
-
|
|
77
56
|
/** Freeze one stored version before any asynchronous source reads. */
|
|
78
57
|
export async function exportShare(input: {
|
|
79
58
|
store: ShareExportStore;
|
|
@@ -82,24 +61,16 @@ export async function exportShare(input: {
|
|
|
82
61
|
version?: number;
|
|
83
62
|
repository?: ShareManifest["repository"];
|
|
84
63
|
}): Promise<ShareBundle> {
|
|
85
|
-
|
|
86
|
-
input.store.read(input.reviewId, input.version),
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
// Commit links read from the board's repository, which a plan names only
|
|
90
|
-
// in its target.
|
|
91
|
-
const repositoryId = boardRepositoryId(stored);
|
|
92
|
-
|
|
93
|
-
// Local-only fields stay home; the target names a local checkout.
|
|
64
|
+
// A share is the finished document: what edit last touched it stays home.
|
|
94
65
|
const {
|
|
95
66
|
target,
|
|
67
|
+
kind: _kind,
|
|
96
68
|
staleSources: _staleSources,
|
|
97
69
|
sourceUnavailable: _sourceUnavailable,
|
|
98
70
|
lastEdit: _lastEdit,
|
|
99
71
|
trashedAt: _trashedAt,
|
|
100
|
-
personEdit: _personEdit,
|
|
101
72
|
...snapshot
|
|
102
|
-
} =
|
|
73
|
+
} = structuredClone(input.store.read(input.reviewId, input.version));
|
|
103
74
|
|
|
104
75
|
if (target?.kind === "worktree")
|
|
105
76
|
throw new ReviewInputError("Pin this review to commits before sharing it.");
|
|
@@ -131,7 +102,7 @@ export async function exportShare(input: {
|
|
|
131
102
|
|
|
132
103
|
// Lens ranges travel with the snapshot and must resolve at its pins too.
|
|
133
104
|
const sources = [
|
|
134
|
-
...sourceReferences(snapshot.document
|
|
105
|
+
...sourceReferences(snapshot.document),
|
|
135
106
|
...lensSelections(snapshot.lenses ?? []).flatMap((selection) =>
|
|
136
107
|
sourceAnchors(selection.source).map((source) => ({
|
|
137
108
|
...selection,
|
|
@@ -145,7 +116,7 @@ export async function exportShare(input: {
|
|
|
145
116
|
|
|
146
117
|
validateShareSources(snapshot);
|
|
147
118
|
|
|
148
|
-
if ((pins
|
|
119
|
+
if (Boolean(pins) !== Boolean(input.repository))
|
|
149
120
|
throw new ReviewInputError("Shared source pins require a repository.", 409);
|
|
150
121
|
|
|
151
122
|
for (const block of elements(snapshot.document)) {
|
package/src/sharing/host.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { parseShareLink, shareIdSchema } from "@dev.fast/review-share-protocol";
|
|
|
5
5
|
import {
|
|
6
6
|
DEFAULT_STORE_ORIGIN,
|
|
7
7
|
clearStoreAuth,
|
|
8
|
-
|
|
8
|
+
openUrlInBrowser,
|
|
9
9
|
readStoreAuth,
|
|
10
10
|
runStoreLogin,
|
|
11
11
|
} from "@dev.fast/trace-core";
|
|
@@ -18,18 +18,13 @@ import { z } from "zod";
|
|
|
18
18
|
|
|
19
19
|
import { readSharingAuth } from "./auth.js";
|
|
20
20
|
import { ShareAuthError, ShareClient, SharePreflightError } from "./client.js";
|
|
21
|
-
import {
|
|
22
|
-
exportShare,
|
|
23
|
-
referenceCommits,
|
|
24
|
-
validateShareSources,
|
|
25
|
-
} from "./export.js";
|
|
21
|
+
import { exportShare, validateShareSources } from "./export.js";
|
|
26
22
|
import { SharedReviewStore, sharedReviewId } from "./import.js";
|
|
27
23
|
import { readShareRepository, verifyShareRepository } from "./repository.js";
|
|
28
24
|
|
|
29
25
|
interface LoginState {
|
|
30
26
|
pending: boolean;
|
|
31
27
|
url?: string;
|
|
32
|
-
userCode?: string;
|
|
33
28
|
error?: string;
|
|
34
29
|
}
|
|
35
30
|
|
|
@@ -66,6 +61,7 @@ export function mountSharingHost(
|
|
|
66
61
|
options: SharingHostOptions = {},
|
|
67
62
|
) {
|
|
68
63
|
const startLogin = options.login ?? runStoreLogin;
|
|
64
|
+
const openUrl = options.openUrl ?? openUrlInBrowser;
|
|
69
65
|
|
|
70
66
|
let login: LoginState = {
|
|
71
67
|
pending: false,
|
|
@@ -96,9 +92,9 @@ export function mountSharingHost(
|
|
|
96
92
|
traces: false,
|
|
97
93
|
stdout: discard,
|
|
98
94
|
stderr: discard,
|
|
99
|
-
openUrl:
|
|
100
|
-
|
|
101
|
-
|
|
95
|
+
openUrl: async (url) => {
|
|
96
|
+
login.url = url;
|
|
97
|
+
await openUrl(url);
|
|
102
98
|
},
|
|
103
99
|
})
|
|
104
100
|
.then((code) => {
|
|
@@ -227,26 +223,13 @@ export function mountSharingPublisher(
|
|
|
227
223
|
409,
|
|
228
224
|
);
|
|
229
225
|
|
|
230
|
-
const
|
|
231
|
-
snapshot.pins
|
|
232
|
-
|
|
233
|
-
const root = repositoryId ? store.repositoryPath(repositoryId) : undefined;
|
|
226
|
+
const root = snapshot.pins
|
|
227
|
+
? store.repositoryPath(snapshot.pins.repositoryId)
|
|
228
|
+
: undefined;
|
|
234
229
|
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
// group them.
|
|
239
|
-
const repository = !root
|
|
240
|
-
? undefined
|
|
241
|
-
: snapshot.pins
|
|
242
|
-
? await readRepository(root)
|
|
243
|
-
: await (async () => {
|
|
244
|
-
try {
|
|
245
|
-
return await readRepository(root);
|
|
246
|
-
} catch {
|
|
247
|
-
return undefined;
|
|
248
|
-
}
|
|
249
|
-
})();
|
|
230
|
+
const repository = root
|
|
231
|
+
? await (options.readRepository ?? readShareRepository)(root)
|
|
232
|
+
: undefined;
|
|
250
233
|
|
|
251
234
|
const bundle = await exportShare({
|
|
252
235
|
store,
|
|
@@ -256,12 +239,9 @@ export function mountSharingPublisher(
|
|
|
256
239
|
repository,
|
|
257
240
|
});
|
|
258
241
|
|
|
259
|
-
const commits = referenceCommits(snapshot);
|
|
260
|
-
|
|
261
|
-
// The commits must be on GitHub for a recipient to fetch them.
|
|
262
242
|
const verification =
|
|
263
|
-
root &&
|
|
264
|
-
? verifyRepository(root, snapshot.pins, repository
|
|
243
|
+
root && snapshot.pins && repository
|
|
244
|
+
? verifyRepository(root, snapshot.pins, repository).then(
|
|
265
245
|
() => ({ ok: true as const }),
|
|
266
246
|
(error: Error) => ({ ok: false as const, error }),
|
|
267
247
|
)
|
package/src/sharing/import.ts
CHANGED
|
@@ -28,9 +28,6 @@ import { textIncludesQuote } from "@review/evidence.js";
|
|
|
28
28
|
import { lensSchema } from "@review/review-api/diff-lenses.js";
|
|
29
29
|
import { ReviewInputError } from "@review/review-api/document.js";
|
|
30
30
|
import {
|
|
31
|
-
type FileLineRange,
|
|
32
|
-
type Pins,
|
|
33
|
-
anchorPins,
|
|
34
31
|
checkReferences,
|
|
35
32
|
documentSchema,
|
|
36
33
|
pinsSchema,
|
|
@@ -55,16 +52,10 @@ import { z } from "zod";
|
|
|
55
52
|
import {
|
|
56
53
|
type ShareBundle,
|
|
57
54
|
digestBytes,
|
|
58
|
-
referenceCommits,
|
|
59
55
|
validateShareSources,
|
|
60
56
|
} from "./export.js";
|
|
61
57
|
import {
|
|
62
|
-
COMMIT_ID,
|
|
63
|
-
assertCommitIds,
|
|
64
|
-
cloneSharedRepository,
|
|
65
58
|
fetchPinnedRepository,
|
|
66
|
-
fetchSharedCommits,
|
|
67
|
-
forgetSharedCommits,
|
|
68
59
|
repositoryReady,
|
|
69
60
|
sharedGit,
|
|
70
61
|
} from "./repository.js";
|
|
@@ -72,12 +63,11 @@ import {
|
|
|
72
63
|
export const sharedSnapshotSchema = z.strictObject({
|
|
73
64
|
reviewId: z.string().min(1),
|
|
74
65
|
version: z.number().int().nonnegative(),
|
|
75
|
-
|
|
76
|
-
title: z.string(),
|
|
66
|
+
title: z.string().min(1),
|
|
77
67
|
pins: pinsSchema
|
|
78
68
|
.extend({
|
|
79
|
-
base: z.string().regex(
|
|
80
|
-
head: z.string().regex(
|
|
69
|
+
base: z.string().regex(/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/),
|
|
70
|
+
head: z.string().regex(/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/),
|
|
81
71
|
})
|
|
82
72
|
.optional(),
|
|
83
73
|
document: documentSchema,
|
|
@@ -100,7 +90,7 @@ const count = z.number().int().nonnegative();
|
|
|
100
90
|
const counts = z.strictObject({ additions: count, deletions: count });
|
|
101
91
|
|
|
102
92
|
const mapSchema = z.strictObject({
|
|
103
|
-
commit: z.string()
|
|
93
|
+
commit: z.string(),
|
|
104
94
|
side: z.enum(["base", "head"]),
|
|
105
95
|
elements: z.array(normalizedSoftwareElementSchema),
|
|
106
96
|
relationships: z.array(normalizedSoftwareRelationshipSchema),
|
|
@@ -176,10 +166,8 @@ export function validateShareBundle(bundle: ShareBundle) {
|
|
|
176
166
|
throw new Error("Shared snapshot does not match its manifest.");
|
|
177
167
|
checkReferences(snapshot.document);
|
|
178
168
|
validateShareSources(snapshot);
|
|
179
|
-
// Every commit it quotes reaches git as an argument.
|
|
180
|
-
assertCommitIds(referenceCommits(snapshot));
|
|
181
169
|
|
|
182
|
-
if (snapshot.pins
|
|
170
|
+
if (Boolean(snapshot.pins) !== Boolean(manifest.repository))
|
|
183
171
|
throw new Error("Shared source pins require a repository.");
|
|
184
172
|
|
|
185
173
|
const presentation = sharePresentationSchema.parse(
|
|
@@ -297,7 +285,6 @@ export class SharedReviewStore {
|
|
|
297
285
|
constructor(
|
|
298
286
|
readonly root: string,
|
|
299
287
|
private readonly fetchRepository = fetchPinnedRepository,
|
|
300
|
-
private readonly cloneRepository = cloneSharedRepository,
|
|
301
288
|
) {
|
|
302
289
|
this.purgeTimer = setInterval(() => {
|
|
303
290
|
void this.purgeExpired().catch((error) =>
|
|
@@ -385,7 +372,7 @@ export class SharedReviewStore {
|
|
|
385
372
|
throw new ReviewInputError("Shared review is not available.", 404);
|
|
386
373
|
|
|
387
374
|
if (!saved.snapshot.pins) {
|
|
388
|
-
|
|
375
|
+
this.setStatus(id, "ready");
|
|
389
376
|
|
|
390
377
|
return;
|
|
391
378
|
}
|
|
@@ -394,12 +381,10 @@ export class SharedReviewStore {
|
|
|
394
381
|
throw new ReviewInputError("Repository service is unavailable.", 409);
|
|
395
382
|
const root = this.repositoryRoot(id);
|
|
396
383
|
|
|
397
|
-
const commits = referenceCommits(saved.snapshot);
|
|
398
|
-
|
|
399
384
|
try {
|
|
400
385
|
this.setStatus(id, "fetching");
|
|
401
386
|
|
|
402
|
-
if (!(await repositoryReady(root, saved.snapshot.pins
|
|
387
|
+
if (!(await repositoryReady(root, saved.snapshot.pins))) {
|
|
403
388
|
const prior = this.repositories.get(id);
|
|
404
389
|
await local.data.workspaces.remove(id);
|
|
405
390
|
|
|
@@ -409,13 +394,11 @@ export class SharedReviewStore {
|
|
|
409
394
|
root,
|
|
410
395
|
saved.manifest.repository!.cloneUrl,
|
|
411
396
|
saved.snapshot.pins,
|
|
412
|
-
false,
|
|
413
|
-
commits,
|
|
414
397
|
);
|
|
415
398
|
await sharedGit(root, [
|
|
416
399
|
"checkout",
|
|
417
400
|
"--detach",
|
|
418
|
-
|
|
401
|
+
saved.snapshot.pins.head,
|
|
419
402
|
]);
|
|
420
403
|
}
|
|
421
404
|
|
|
@@ -430,7 +413,16 @@ export class SharedReviewStore {
|
|
|
430
413
|
this.setStatus(id, "validating");
|
|
431
414
|
await local.data.validatePins(pins);
|
|
432
415
|
|
|
433
|
-
|
|
416
|
+
const references = sourceReferences(saved.snapshot.document).map(
|
|
417
|
+
(item) => item.source,
|
|
418
|
+
);
|
|
419
|
+
|
|
420
|
+
for (const map of Object.values(saved.presentation.maps))
|
|
421
|
+
for (const element of map.elements)
|
|
422
|
+
for (const range of element.sourceRanges ?? [])
|
|
423
|
+
references.push({ ...range, side: map.side });
|
|
424
|
+
|
|
425
|
+
await local.data.validateSources(pins, references);
|
|
434
426
|
await local.data.workspaces.open(id, pins);
|
|
435
427
|
|
|
436
428
|
if (
|
|
@@ -457,114 +449,13 @@ export class SharedReviewStore {
|
|
|
457
449
|
}
|
|
458
450
|
}
|
|
459
451
|
|
|
460
|
-
/** Reads each of a shared board's references at its own commits, in the
|
|
461
|
-
* checkout of its repository. */
|
|
462
|
-
private async validateReferences(
|
|
463
|
-
saved: ReturnType<typeof validateShareBundle>,
|
|
464
|
-
repositoryId: string,
|
|
465
|
-
pins?: Pins,
|
|
466
|
-
) {
|
|
467
|
-
const references = new Map<
|
|
468
|
-
string,
|
|
469
|
-
{ pins: Pins; ranges: FileLineRange[] }
|
|
470
|
-
>();
|
|
471
|
-
|
|
472
|
-
const add = (at: Pins, range: FileLineRange) => {
|
|
473
|
-
const key = JSON.stringify([at.base, at.head]);
|
|
474
|
-
const group = references.get(key) ?? { pins: at, ranges: [] };
|
|
475
|
-
|
|
476
|
-
group.ranges.push(range);
|
|
477
|
-
references.set(key, group);
|
|
478
|
-
};
|
|
479
|
-
|
|
480
|
-
for (const { source } of sourceReferences(saved.snapshot.document, {
|
|
481
|
-
repositoryId,
|
|
482
|
-
}))
|
|
483
|
-
add({ ...anchorPins(source, pins), repositoryId }, source);
|
|
484
|
-
|
|
485
|
-
if (pins)
|
|
486
|
-
for (const map of Object.values(saved.presentation.maps))
|
|
487
|
-
for (const element of map.elements)
|
|
488
|
-
for (const range of element.sourceRanges ?? [])
|
|
489
|
-
add(pins, { ...range, side: map.side });
|
|
490
|
-
|
|
491
|
-
for (const group of references.values())
|
|
492
|
-
await this.local!.data.validateSources(group.pins, group.ranges);
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
/** Files an unpinned board under a local checkout of its repository,
|
|
496
|
-
* else a managed clone. */
|
|
497
|
-
private async prepareUnpinned(id: string, cloneUrl: string | undefined) {
|
|
498
|
-
const local = this.local;
|
|
499
|
-
const saved = this.validated.get(id)!;
|
|
500
|
-
|
|
501
|
-
if (!cloneUrl || !local) {
|
|
502
|
-
this.setStatus(id, "ready");
|
|
503
|
-
|
|
504
|
-
return;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
const root = this.repositoryRoot(id);
|
|
508
|
-
|
|
509
|
-
try {
|
|
510
|
-
this.setStatus(id, "fetching");
|
|
511
|
-
const managed = path.join(await realpath(this.root), ".repositories");
|
|
512
|
-
|
|
513
|
-
let repositoryId = local.store
|
|
514
|
-
.checkoutsOf(cloneUrl)
|
|
515
|
-
.find(
|
|
516
|
-
(checkout) =>
|
|
517
|
-
!local.store.repositoryPath(checkout).startsWith(managed),
|
|
518
|
-
);
|
|
519
|
-
|
|
520
|
-
if (!repositoryId) {
|
|
521
|
-
if (!existsSync(path.join(root, ".git"))) {
|
|
522
|
-
await rm(root, { recursive: true, force: true });
|
|
523
|
-
await this.cloneRepository(root, cloneUrl);
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
repositoryId = (await local.data.register(root)).id;
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
// A plan's commit links read at commits the checkout may not have.
|
|
530
|
-
const checkout = local.store.repositoryPath(repositoryId);
|
|
531
|
-
|
|
532
|
-
await fetchSharedCommits(
|
|
533
|
-
checkout,
|
|
534
|
-
referenceCommits(saved.snapshot, repositoryId),
|
|
535
|
-
id,
|
|
536
|
-
);
|
|
537
|
-
this.setStatus(id, "validating");
|
|
538
|
-
await this.validateReferences(saved, repositoryId);
|
|
539
|
-
this.repositories.set(id, repositoryId);
|
|
540
|
-
await writeFile(
|
|
541
|
-
path.join(this.root, id, "repository.json"),
|
|
542
|
-
JSON.stringify({ repositoryId, ready: true }),
|
|
543
|
-
{ mode: 0o600 },
|
|
544
|
-
);
|
|
545
|
-
this.setStatus(id, "ready");
|
|
546
|
-
} catch (error) {
|
|
547
|
-
const message =
|
|
548
|
-
error instanceof ReviewInputError
|
|
549
|
-
? error.message
|
|
550
|
-
: "Could not prepare the shared repository. Check Git credentials and retry.";
|
|
551
|
-
|
|
552
|
-
this.setStatus(id, "error", message);
|
|
553
|
-
throw new ReviewInputError(message, 409);
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
|
|
557
452
|
async assertReady(id: string) {
|
|
558
453
|
const saved = this.validated.get(id);
|
|
559
454
|
|
|
560
455
|
if (
|
|
561
456
|
!saved ||
|
|
562
457
|
(saved.snapshot.pins &&
|
|
563
|
-
!(await repositoryReady(
|
|
564
|
-
this.repositoryRoot(id),
|
|
565
|
-
saved.snapshot.pins,
|
|
566
|
-
referenceCommits(saved.snapshot),
|
|
567
|
-
)))
|
|
458
|
+
!(await repositoryReady(this.repositoryRoot(id), saved.snapshot.pins)))
|
|
568
459
|
) {
|
|
569
460
|
this.setStatus(
|
|
570
461
|
id,
|
|
@@ -626,14 +517,9 @@ export class SharedReviewStore {
|
|
|
626
517
|
),
|
|
627
518
|
);
|
|
628
519
|
|
|
629
|
-
// A board with no pins may use the receiver's own checkout.
|
|
630
520
|
if (
|
|
631
521
|
this.local?.store.repositoryPath(metadata.repositoryId) ===
|
|
632
|
-
|
|
633
|
-
(!validated.snapshot.pins &&
|
|
634
|
-
this.local?.store
|
|
635
|
-
.repositories()
|
|
636
|
-
.some((repository) => repository.id === metadata.repositoryId))
|
|
522
|
+
path.join(await realpath(this.root), ".repositories", id)
|
|
637
523
|
) {
|
|
638
524
|
this.repositories.set(id, metadata.repositoryId);
|
|
639
525
|
prepared = metadata.ready;
|
|
@@ -642,17 +528,13 @@ export class SharedReviewStore {
|
|
|
642
528
|
/* A first or interrupted import has no local registration yet. */
|
|
643
529
|
}
|
|
644
530
|
|
|
645
|
-
if (!validated.snapshot.pins)
|
|
646
|
-
|
|
647
|
-
this.setStatus(id, "ready");
|
|
648
|
-
else void this.prepare(id).catch(() => {});
|
|
649
|
-
} else if (
|
|
531
|
+
if (!validated.snapshot.pins) this.setStatus(id, "ready");
|
|
532
|
+
else if (
|
|
650
533
|
prepared &&
|
|
651
534
|
this.local &&
|
|
652
535
|
(await repositoryReady(
|
|
653
536
|
this.repositoryRoot(id),
|
|
654
537
|
validated.snapshot.pins,
|
|
655
|
-
referenceCommits(validated.snapshot),
|
|
656
538
|
))
|
|
657
539
|
) {
|
|
658
540
|
const repository = await this.local.data.register(
|
|
@@ -755,9 +637,7 @@ export class SharedReviewStore {
|
|
|
755
637
|
...validated.snapshot.pins,
|
|
756
638
|
repositoryId: repositoryId!,
|
|
757
639
|
}
|
|
758
|
-
:
|
|
759
|
-
? { kind: "project" as const, repositoryId }
|
|
760
|
-
: undefined,
|
|
640
|
+
: undefined,
|
|
761
641
|
shared: {
|
|
762
642
|
...bundle.attribution,
|
|
763
643
|
cloneUrl: bundle.manifest.repository?.cloneUrl,
|
|
@@ -778,16 +658,11 @@ export class SharedReviewStore {
|
|
|
778
658
|
.map((id) => {
|
|
779
659
|
const { document: _document, ...snapshot } = this.get(id).snapshot;
|
|
780
660
|
|
|
781
|
-
const project = snapshot.target
|
|
782
|
-
? this.local?.store.checkoutProject(snapshot.target.repositoryId)
|
|
783
|
-
: undefined;
|
|
784
|
-
|
|
785
661
|
return {
|
|
786
662
|
...snapshot,
|
|
787
663
|
firstCreatedAt:
|
|
788
664
|
snapshot.version === 0 ? snapshot.createdAt : undefined,
|
|
789
665
|
repositoryName: "Shared review",
|
|
790
|
-
...(project && { project }),
|
|
791
666
|
viewedAt: this.attention.get(id)?.viewedAt ?? null,
|
|
792
667
|
trashedAt: this.attention.get(id)?.trashedAt ?? null,
|
|
793
668
|
};
|
|
@@ -825,15 +700,8 @@ export class SharedReviewStore {
|
|
|
825
700
|
const repositoryId = this.repositories.get(id);
|
|
826
701
|
|
|
827
702
|
if (repositoryId) {
|
|
828
|
-
const checkout = this.local?.store.repositoryPath(repositoryId);
|
|
829
|
-
|
|
830
|
-
// The commits kept for its links go with it.
|
|
831
|
-
if (checkout)
|
|
832
|
-
await forgetSharedCommits(checkout, id).catch((error) =>
|
|
833
|
-
console.error(`Could not drop the refs kept for share ${id}:`, error),
|
|
834
|
-
);
|
|
835
703
|
await this.local?.data.forgetRepository(repositoryId);
|
|
836
|
-
|
|
704
|
+
this.local?.store.unregisterRepository(repositoryId);
|
|
837
705
|
}
|
|
838
706
|
|
|
839
707
|
await rm(this.repositoryRoot(id), { recursive: true, force: true });
|