@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.
Files changed (115) hide show
  1. package/dist/{account-alias-B5-HYi1D.js → account-alias-CprZojXd.js} +8 -13
  2. package/dist/agent-cli-C6SPSII0.js +2 -0
  3. package/dist/{agent-cli-CohHf6Ua.js → agent-cli-CThN7Q59.js} +10 -15
  4. package/dist/{agent-client-Dtc-Kn_w.js → agent-client-BOOi7EUR.js} +3 -13
  5. package/dist/{authoring-tools-B7KU04f7.js → authoring-tools-BNwuMnz6.js} +27 -34
  6. package/dist/{background-server-C03RKxKS.js → background-server-CkvxA-6O.js} +5 -5
  7. package/dist/{background-server-CB9C4uoc.js → background-server-DLSDogkI.js} +1 -1
  8. package/dist/build-info.json +1 -1
  9. package/dist/{cli-CJaEb7zC.js → cli-R4yfa5DT.js} +1 -1
  10. package/dist/{cli-runner-DGDIqh3V.js → cli-runner-Cuc9FSzu.js} +26 -26
  11. package/dist/cli.js +3 -4
  12. package/dist/{client-lKVF_Elo.js → client-BN_FDxFr.js} +47 -253
  13. package/dist/{fuzzy-match-BmVJJm9I.js → fuzzy-match-BO9bK37N.js} +4 -6
  14. package/dist/{headless-host-DRtjf9WA.js → headless-host-CVBOQyRS.js} +1 -1
  15. package/dist/{headless-host-XhL1X4vX.js → headless-host-Cog6SpS9.js} +140 -513
  16. package/dist/{local-data-Cpl4ENbJ.js → local-data-D_9tvdsp.js} +323 -2419
  17. package/dist/{mcp-ovmiUE_x.js → mcp-D1hziANa.js} +9 -5
  18. package/dist/{package-paths-BWxO-UEL.js → package-paths-C--__jEv.js} +1 -1
  19. package/dist/profile-CYPmvBoA.js +2 -0
  20. package/dist/{profile-BadSkCkI.js → profile-DokFw782.js} +8 -20
  21. package/dist/{remote-attach-Dd-YobM6.js → remote-attach-CEJ-kvDY.js} +4 -4
  22. package/dist/{remote-extensions-CNXwqK0D.js → remote-extensions-Blcjr9Ze.js} +3 -3
  23. package/dist/{remote-extensions-VP-kfq0C.js → remote-extensions-GN8Gf_qG.js} +1 -1
  24. package/dist/{remote-language-server-BXk87KCr.js → remote-language-server-BTKBQ7x4.js} +5 -5
  25. package/dist/{remote-uninstall-DuOzsvaD.js → remote-uninstall-DW7Gdryh.js} +6 -6
  26. package/dist/{request-origin-B9qCPiVB.js → request-origin-Zcn_CjX4.js} +12 -45
  27. package/dist/{review-app-launcher-C7el2Uoy.js → review-app-launcher-CkwLclzR.js} +2 -2
  28. package/dist/{review-home-paths-D8AoCdd2.js → review-home-paths-j2BRAaNv.js} +17 -19
  29. package/dist/{review-telemetry-BsoRMC2w.js → review-telemetry-BLNwYnLV.js} +5 -5
  30. package/dist/runtime-CKiWhGrf.js +52 -0
  31. package/dist/runtime.d.ts +1 -1
  32. package/dist/runtime.js +1 -1
  33. package/dist/{s3-CsG2EWED.js → s3-DtJFWC0G.js} +1 -1
  34. package/dist/{s3-config-CjcLyFV5.js → s3-config-BTO12tCC.js} +2 -4
  35. package/dist/{s3-config-zz4GWh2T.js → s3-config-CSy3fx8H.js} +1 -1
  36. package/dist/server/desktop-host.js +76 -29
  37. package/dist/{server-discovery-CKjw3-6h.js → server-discovery-Bey8IqXH.js} +3 -3
  38. package/dist/sharing/index.d.ts +70 -484
  39. package/dist/sharing/index.js +1 -1
  40. package/dist/{src-WPaQn75m.js → src-BMPuxWv4.js} +73 -208
  41. package/dist/{src-BiWNbcF_.js → src-DsM3jO8G.js} +12 -89
  42. package/dist/{stored-document-migration-dFbewRTG.js → stored-document-migration-CChxtFAy.js} +269 -270
  43. package/dist/{thread-state-Do5LX10I.js → thread-state-5pYr6_zM.js} +2 -7
  44. package/dist/{tool-failure-DvI-gys2.js → tool-failure-C9MpbXJJ.js} +3 -10
  45. package/instructions/authoring.md +2 -3
  46. package/instructions/scratchpad.md +23 -0
  47. package/package.json +4 -4
  48. package/src/ask/agents.ts +1 -13
  49. package/src/ask/checkout-files.ts +5 -2
  50. package/src/ask/thread-state.ts +0 -4
  51. package/src/ask/thread.ts +0 -16
  52. package/src/ask/threads.ts +3 -24
  53. package/src/cli-install.ts +2 -13
  54. package/src/cli-runner.ts +1 -4
  55. package/src/cli.ts +1 -4
  56. package/src/diff-selection-migration.ts +34 -48
  57. package/src/lens-selection.ts +2 -38
  58. package/src/review-api/README.md +13 -52
  59. package/src/review-api/activity.ts +4 -1
  60. package/src/review-api/agent-cli.ts +1 -9
  61. package/src/review-api/anchor-quotes.ts +7 -14
  62. package/src/review-api/ask-history.ts +51 -137
  63. package/src/review-api/authoring-tools.ts +30 -45
  64. package/src/review-api/blocks/definition.ts +1 -1
  65. package/src/review-api/blocks/markdown.ts +2 -2
  66. package/src/review-api/document-headings.ts +27 -58
  67. package/src/review-api/document-text.ts +2 -31
  68. package/src/review-api/document.ts +34 -281
  69. package/src/review-api/github-provider.ts +13 -51
  70. package/src/review-api/http.ts +123 -702
  71. package/src/review-api/instructions.ts +19 -0
  72. package/src/review-api/local-data.ts +46 -310
  73. package/src/review-api/mcp.ts +11 -3
  74. package/src/review-api/onboarding.ts +1 -1
  75. package/src/review-api/profile.ts +6 -37
  76. package/src/review-api/public-tools.ts +2 -24
  77. package/src/review-api/pull-request.ts +49 -82
  78. package/src/review-api/request-origin.ts +0 -10
  79. package/src/review-api/review-progress.ts +27 -61
  80. package/src/review-api/store-schema.ts +29 -38
  81. package/src/review-api/store.ts +478 -2142
  82. package/src/review-api/worktree-events.ts +5 -3
  83. package/src/review-api/worktree-source.ts +7 -3
  84. package/src/review-api/worktree-structural.integration.ts +0 -72
  85. package/src/review-preferences.ts +88 -0
  86. package/src/review-stack.ts +23 -15
  87. package/src/runtime.ts +30 -4
  88. package/src/server/desktop-host.ts +1 -6
  89. package/src/server/desktop-server.ts +31 -1
  90. package/src/server/headless-host.ts +2 -0
  91. package/src/server/hono-http.ts +1 -2
  92. package/src/server/legacy-tutorial-cleanup.ts +3 -2
  93. package/src/server/review-gateway-list.ts +5 -3
  94. package/src/server/review-gateway-memory.ts +1 -1
  95. package/src/server/review-lifecycle-telemetry.ts +2 -2
  96. package/src/server/review-server-core.ts +5 -1
  97. package/src/server/structural-comparisons.ts +0 -47
  98. package/src/sharing/export.ts +7 -36
  99. package/src/sharing/host.ts +14 -34
  100. package/src/sharing/import.ts +24 -156
  101. package/src/sharing/repository.ts +20 -128
  102. package/src/startup-trace.ts +3 -3
  103. package/src/stored-document-migration.ts +19 -110
  104. package/src/ui-telemetry-events.ts +11 -33
  105. package/dist/agent-cli-_YyMIMRY.js +0 -2
  106. package/dist/lens-selection-CyJapcsl.js +0 -214
  107. package/dist/profile-DJvkBJNQ.js +0 -2
  108. package/dist/runtime-Bj2tD33R.js +0 -27
  109. package/src/heading-anchors.ts +0 -42
  110. package/src/review-api/board-order.ts +0 -144
  111. package/src/review-api/checkout-groups.ts +0 -560
  112. package/src/review-api/foreign-references.ts +0 -328
  113. package/src/review-api/link-preview.ts +0 -113
  114. package/src/review-api/scratchpad-plan-upgrade.ts +0 -250
  115. package/src/review-api/store-migrations.ts +0 -357
@@ -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
- readsAtBoardPins,
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 && readsAtBoardPins(snapshot))
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
- const stored = structuredClone(
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
- } = stored;
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, { repositoryId }),
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 || referenceCommits(stored).length) && !input.repository)
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)) {
@@ -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
- type openUrlInBrowser,
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: options.openUrl,
100
- onDeviceCode: (device) => {
101
- Object.assign(login, device);
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 repositoryId =
231
- snapshot.pins?.repositoryId ?? snapshot.target?.repositoryId;
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 readRepository = options.readRepository ?? readShareRepository;
236
-
237
- // Unpinned boards name their repository when they can, so receivers can
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 && (snapshot.pins || commits.length) && repository
264
- ? verifyRepository(root, snapshot.pins, repository, commits).then(
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
  )
@@ -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
- /** Empty for a board never named; it reads "Untitled". */
76
- title: z.string(),
66
+ title: z.string().min(1),
77
67
  pins: pinsSchema
78
68
  .extend({
79
- base: z.string().regex(COMMIT_ID),
80
- head: z.string().regex(COMMIT_ID),
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().regex(COMMIT_ID),
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 && !manifest.repository)
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
- await this.prepareUnpinned(id, saved.manifest.repository?.cloneUrl);
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, commits))) {
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
- { commit: saved.snapshot.pins.head },
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
- await this.validateReferences(saved, repository.id, pins);
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
- path.join(await realpath(this.root), ".repositories", id) ||
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
- if (this.repositories.has(id) || !validated.manifest.repository)
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
- : repositoryId
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
- await this.local?.store.unregisterRepository(repositoryId);
704
+ this.local?.store.unregisterRepository(repositoryId);
837
705
  }
838
706
 
839
707
  await rm(this.repositoryRoot(id), { recursive: true, force: true });