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

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 (120) hide show
  1. package/dist/{account-alias-Bw3PT3Qo.js → account-alias-DXpd0Px8.js} +5 -5
  2. package/dist/{agent-cli-kHRrwO4n.js → agent-cli-COrZtFks.js} +9 -9
  3. package/dist/agent-cli-x6-Eh1S-.js +2 -0
  4. package/dist/{agent-client-CMacGbMp.js → agent-client-BFtYm3Ng.js} +4 -4
  5. package/dist/{authoring-tools-CiLy46kh.js → authoring-tools-D1avYp8-.js} +12 -8
  6. package/dist/{background-server-eZWXoVcI.js → background-server-BiRSqjxG.js} +4 -4
  7. package/dist/{background-server-BLNHbksB.js → background-server-HOJozY99.js} +1 -1
  8. package/dist/build-info.json +1 -1
  9. package/dist/{cli-Bxmiqutp.js → cli-CSlwGRvH.js} +1 -1
  10. package/dist/{cli-runner-DQPuu7kJ.js → cli-runner-CuffXA0Q.js} +22 -22
  11. package/dist/cli.js +2 -2
  12. package/dist/{fuzzy-match-DZjeOaPY.js → fuzzy-match-DEo941za.js} +3 -3
  13. package/dist/{headless-host-B4r0s1ks.js → headless-host-BCkXVVpU.js} +1 -1
  14. package/dist/{headless-host-Dl2KZ9IT.js → headless-host-CIuJJjmM.js} +561 -415
  15. package/dist/{import-YAIU6rB0.js → import-CjcW7EIQ.js} +235 -63
  16. package/dist/{local-data-C58vzLZR.js → local-data-B5PBZ0Ge.js} +101 -17
  17. package/dist/{mcp-COYWiGVn.js → mcp-Ba3WvhUh.js} +9 -6
  18. package/dist/{package-paths-Cg6fnaGp.js → package-paths-Dk7MOXxN.js} +1 -1
  19. package/dist/profile-BstQkIY0.js +2 -0
  20. package/dist/{profile--BYIjPkc.js → profile-CNMhLUhf.js} +2 -2
  21. package/dist/{remote-attach-C1prLjmj.js → remote-attach-DkZoYBHV.js} +4 -4
  22. package/dist/{remote-extensions-Bw029iIS.js → remote-extensions-BvV29_gk.js} +1 -1
  23. package/dist/{remote-extensions-MUUgbLJn.js → remote-extensions-L95HNwIH.js} +2 -2
  24. package/dist/{remote-language-server-z3rdHcLL.js → remote-language-server-l4ConTfj.js} +4 -4
  25. package/dist/{remote-uninstall-B3Slwor1.js → remote-uninstall-BAQM7cU8.js} +5 -5
  26. package/dist/{request-origin-B3_XI2VA.js → request-origin-DZexKlc4.js} +28 -5
  27. package/dist/{review-app-launcher-BZEbDKuK.js → review-app-launcher-B5F10y_4.js} +2 -2
  28. package/dist/{review-home-paths-LdGS4SpR.js → review-home-paths-BmZX2qiz.js} +1 -1
  29. package/dist/{review-telemetry-x8u-9EZb.js → review-telemetry-kQ7esDRE.js} +4 -4
  30. package/dist/server/desktop-host.js +26 -38
  31. package/dist/{server-discovery-WmuFl2S3.js → server-discovery-DYY_xeG9.js} +2 -2
  32. package/dist/sharing/index.d.ts +137 -14
  33. package/dist/sharing/index.js +1 -1
  34. package/dist/{src-DLWol7GZ.js → src-B-91Rd2d.js} +17 -1
  35. package/dist/{src-B2b8cCoI.js → src-DirPN_Qh.js} +82 -6
  36. package/dist/{stored-document-migration-iwIQ4l5G.js → stored-document-migration-vg0NAzXG.js} +4 -89
  37. package/dist/{thread-state-B7L1mpN_.js → thread-state-Jxoh1hde.js} +1 -1
  38. package/dist/{tool-failure-RLR8m9hq.js → tool-failure-BLBwcl3H.js} +319 -55
  39. package/instructions/animation.md +69 -5
  40. package/instructions/animations/before-after-structure/README.md +27 -0
  41. package/instructions/animations/before-after-structure/animation.html +89 -0
  42. package/instructions/animations/before-after-structure/block.json +10 -0
  43. package/instructions/animations/before-after-structure/frames.json +313 -0
  44. package/instructions/animations/cache-fill-evict/README.md +24 -0
  45. package/instructions/animations/cache-fill-evict/animation.html +81 -0
  46. package/instructions/animations/cache-fill-evict/block.json +13 -0
  47. package/instructions/animations/cache-fill-evict/frames.json +79 -0
  48. package/instructions/animations/cache-fill-evict/scenarios.json +17 -0
  49. package/instructions/animations/log-replay/README.md +25 -0
  50. package/instructions/animations/log-replay/animation.html +86 -0
  51. package/instructions/animations/log-replay/block.json +10 -0
  52. package/instructions/animations/log-replay/frames.json +143 -0
  53. package/instructions/animations/log-replay/scenarios.json +18 -0
  54. package/instructions/animations/queue-workers/README.md +23 -0
  55. package/instructions/animations/queue-workers/animation.html +107 -0
  56. package/instructions/animations/queue-workers/block.json +13 -0
  57. package/instructions/animations/queue-workers/frames.json +119 -0
  58. package/instructions/animations/queue-workers/scenarios.json +18 -0
  59. package/instructions/animations/race-two-lanes/README.md +22 -0
  60. package/instructions/animations/race-two-lanes/animation.html +97 -0
  61. package/instructions/animations/race-two-lanes/block.json +1 -0
  62. package/instructions/animations/race-two-lanes/frames.json +234 -0
  63. package/instructions/animations/race-two-lanes/scenarios.json +19 -0
  64. package/instructions/animations/request-across-layers/README.md +24 -0
  65. package/instructions/animations/request-across-layers/animation.html +85 -0
  66. package/instructions/animations/request-across-layers/block.json +17 -0
  67. package/instructions/animations/request-across-layers/frames.json +58 -0
  68. package/instructions/animations/request-across-layers/scenarios.json +12 -0
  69. package/instructions/animations/request-timing/README.md +22 -0
  70. package/instructions/animations/request-timing/animation.html +120 -0
  71. package/instructions/animations/request-timing/block.json +21 -0
  72. package/instructions/animations/request-timing/markers.json +32 -0
  73. package/instructions/animations/request-timing/scenarios.json +4 -0
  74. package/instructions/animations/retry-backoff/README.md +22 -0
  75. package/instructions/animations/retry-backoff/animation.html +122 -0
  76. package/instructions/animations/retry-backoff/block.json +10 -0
  77. package/instructions/animations/retry-backoff/frames.json +65 -0
  78. package/instructions/animations/retry-backoff/scenarios.json +12 -0
  79. package/instructions/animations/state-machine/README.md +24 -0
  80. package/instructions/animations/state-machine/animation.html +95 -0
  81. package/instructions/animations/state-machine/block.json +9 -0
  82. package/instructions/animations/state-machine/frames.json +79 -0
  83. package/instructions/animations/state-machine/scenarios.json +12 -0
  84. package/instructions/animations/video-platform-architecture/README.md +24 -0
  85. package/instructions/animations/video-platform-architecture/animation.html +76 -0
  86. package/instructions/animations/video-platform-architecture/block.json +17 -0
  87. package/instructions/animations/video-platform-architecture/frames.json +97 -0
  88. package/instructions/animations/video-platform-architecture/scenarios.json +28 -0
  89. package/instructions/whiteboard.d.ts +168 -14
  90. package/package.json +5 -5
  91. package/src/animation-stage-kit.ts +150 -10
  92. package/src/cli-runner.ts +4 -1
  93. package/src/fixtures/blocks/clip.json +19 -0
  94. package/src/review-api/README.md +1 -0
  95. package/src/review-api/agent-cli.ts +3 -2
  96. package/src/review-api/animation-drafts.ts +151 -47
  97. package/src/review-api/animation-references.ts +92 -0
  98. package/src/review-api/animation-render.ts +106 -0
  99. package/src/review-api/authoring-tools.ts +10 -3
  100. package/src/review-api/comparison-coverage.ts +6 -7
  101. package/src/review-api/document-text.ts +27 -12
  102. package/src/review-api/http.ts +52 -6
  103. package/src/review-api/instructions.ts +1 -1
  104. package/src/review-api/mcp.ts +10 -5
  105. package/src/review-api/public-tools.ts +71 -2
  106. package/src/review-api/review-progress.ts +2 -3
  107. package/src/review-api/store.ts +89 -12
  108. package/src/server/desktop-server.ts +17 -5
  109. package/src/server/headless-host.ts +4 -0
  110. package/src/server/review-gateway.ts +1 -0
  111. package/src/server/review-server-core.ts +71 -12
  112. package/src/sharing/client.ts +129 -32
  113. package/src/sharing/export.ts +42 -5
  114. package/src/sharing/file.ts +8 -0
  115. package/src/sharing/host.ts +202 -73
  116. package/src/sharing/import.ts +125 -33
  117. package/src/ui-telemetry-events.ts +26 -1
  118. package/dist/agent-cli-B8KBHuh_.js +0 -2
  119. package/dist/profile-BjcXi-oH.js +0 -2
  120. package/src/review-api/lens-alignment.ts +0 -52
@@ -21,7 +21,10 @@ import {
21
21
  import { textIncludesQuote } from "@review/evidence.js";
22
22
  import type { LocalReviewData } from "@review/review-api/local-data.js";
23
23
  import { pullRequestUrl } from "@review/review-api/origin.js";
24
- import type { ReviewStore } from "@review/review-api/store.js";
24
+ import type {
25
+ ReviewStore,
26
+ SharedProvenance,
27
+ } from "@review/review-api/store.js";
25
28
  import { traceSchema } from "@review/review-api/trace-schema.js";
26
29
  import {
27
30
  devReviewHome,
@@ -45,7 +48,7 @@ import {
45
48
  sharedGit,
46
49
  } from "./repository.js";
47
50
 
48
- export const sharedSnapshotSchema = z.strictObject({
51
+ export const sharedSnapshotSchema = z.object({
49
52
  reviewId: z.string().min(1),
50
53
  version: z.number().int().nonnegative(),
51
54
  /** Empty for a board never named; it reads "Untitled". */
@@ -60,7 +63,7 @@ export const sharedSnapshotSchema = z.strictObject({
60
63
  lenses: z.array(lensSchema).optional(),
61
64
  createdAt: z.string(),
62
65
  origin: z
63
- .strictObject({
66
+ .object({
64
67
  branch: z.string().optional(),
65
68
  baseRef: z.string().optional(),
66
69
  baseBranch: z.string().optional(),
@@ -75,7 +78,7 @@ export const sharedSnapshotSchema = z.strictObject({
75
78
 
76
79
  const count = z.number().int().nonnegative();
77
80
 
78
- const counts = z.strictObject({ additions: count, deletions: count });
81
+ const counts = z.object({ additions: count, deletions: count });
79
82
 
80
83
  const mapSchema = softwareModelDataSchema.extend({
81
84
  commit: z.string().regex(COMMIT_ID),
@@ -88,10 +91,10 @@ const mapSchema = softwareModelDataSchema.extend({
88
91
  counts.extend({
89
92
  file: z.string(),
90
93
  hunks: z.array(
91
- z.strictObject({
94
+ z.object({
92
95
  startLine: count,
93
96
  lines: z.array(
94
- z.strictObject({
97
+ z.object({
95
98
  kind: z.enum(["add", "remove"]),
96
99
  oldLine: count.nullable(),
97
100
  newLine: count.nullable(),
@@ -106,7 +109,7 @@ const mapSchema = softwareModelDataSchema.extend({
106
109
  ),
107
110
  });
108
111
 
109
- export const sharePresentationSchema = z.strictObject({
112
+ export const sharePresentationSchema = z.object({
110
113
  maps: z.record(z.string(), mapSchema),
111
114
  });
112
115
 
@@ -129,6 +132,12 @@ export function needsRepository(
129
132
 
130
133
  export function validateShareBundle(input: ShareBundle) {
131
134
  const bundle = shareBundleSchema.parse(input);
135
+
136
+ if (bundle.frozen)
137
+ throw new ReviewInputError(
138
+ "This whiteboard is a read-only snapshot of uncommitted changes. View it in the browser.",
139
+ 409,
140
+ );
132
141
  // SAFETY: a bundle is parsed from JSON, so its snapshot is a JSON object.
133
142
  const stored = bundle.snapshot as JsonObject;
134
143
 
@@ -235,18 +244,99 @@ export interface ShareImport {
235
244
  onStage?: (stage: "fetching" | "validating") => void;
236
245
  }
237
246
 
238
- /** Imports a share as an ordinary board, once per link: the link's copy
239
- * comes back while it exists, even from Trash. */
247
+ export const FRESH_IMPORT_VERSION = 0;
248
+
249
+ /** The revision a link serves and its share's latest. */
250
+ export interface ServedRevision {
251
+ revision: { id: string; version: number; createdAt: number };
252
+ latest: string;
253
+ }
254
+
255
+ export type ShareCopyPlan =
256
+ | { kind: "open"; reviewId: string }
257
+ | { kind: "refresh"; reviewId: string; version: number }
258
+ | { kind: "import" };
259
+
260
+ /** Which copy a served revision opens or refreshes in place; otherwise a new copy. */
261
+ export function planShareCopy(
262
+ copies: ReturnType<ReviewStore["copiesOf"]>,
263
+ served: ServedRevision,
264
+ pinned = false,
265
+ ): ShareCopyPlan {
266
+ const same = copies.find(({ shared }) =>
267
+ shared.revisionId === undefined
268
+ ? shared.sharedAt === served.revision.createdAt
269
+ : shared.revisionId === served.revision.id,
270
+ );
271
+
272
+ if (same) return { kind: "open", reviewId: same.reviewId };
273
+
274
+ const unedited =
275
+ !pinned &&
276
+ served.revision.id === served.latest &&
277
+ copies.find(
278
+ (copy) =>
279
+ !copy.shared.pinned &&
280
+ copy.version === (copy.shared.importedVersion ?? FRESH_IMPORT_VERSION),
281
+ );
282
+
283
+ return unedited
284
+ ? {
285
+ kind: "refresh",
286
+ reviewId: unedited.reviewId,
287
+ version: unedited.version,
288
+ }
289
+ : { kind: "import" };
290
+ }
291
+
292
+ /** Opens, refreshes or copies a link's board by the revision it serves. */
293
+ export async function receiveShare(
294
+ input: ShareImport,
295
+ key: string,
296
+ served: ServedRevision,
297
+ download: () => Promise<{
298
+ bundle: ShareBundle;
299
+ attribution: ShareAttribution;
300
+ }>,
301
+ pinned = false,
302
+ ): Promise<string> {
303
+ const plan = planShareCopy(input.store.copiesOf(key), served, pinned);
304
+
305
+ if (plan.kind === "open") return plan.reviewId;
306
+ const { bundle, attribution } = await download();
307
+
308
+ const provenance = {
309
+ ...attribution,
310
+ revisionId: served.revision.id,
311
+ ...(pinned && { pinned }),
312
+ };
313
+
314
+ if (plan.kind === "import")
315
+ return importShare(input, key, bundle, provenance);
316
+
317
+ try {
318
+ return await importShare(input, key, bundle, provenance, plan);
319
+ } catch (error) {
320
+ // The board was edited or deleted since the plan read it.
321
+ if (
322
+ error instanceof ReviewInputError &&
323
+ (error.status === 409 || error.status === 404)
324
+ )
325
+ return importShare(input, key, bundle, provenance);
326
+ throw error;
327
+ }
328
+ }
329
+
330
+ /** Imports a share as an ordinary board, or into a copy of its link. */
240
331
  export async function importShare(
241
332
  input: ShareImport,
242
333
  key: string,
243
334
  received: ShareBundle,
244
- attribution?: ShareAttribution,
335
+ provenance?: ShareAttribution &
336
+ Pick<SharedProvenance, "revisionId" | "pinned">,
337
+ into?: { reviewId: string; version: number },
245
338
  ): Promise<string> {
246
339
  const { store, data } = input;
247
- const existing = store.copyOf(key);
248
-
249
- if (existing) return existing;
250
340
  const { bundle, snapshot, maps } = validateShareBundle(received);
251
341
  const cloneUrl = bundle.repository?.cloneUrl;
252
342
  let repositoryId: string | undefined;
@@ -319,27 +409,29 @@ export async function importShare(
319
409
 
320
410
  for (const [id, copy] of ids) document = document.replaceAll(id, copy);
321
411
 
322
- const { reviewId } = await store.execute(
323
- {
324
- operation: {
325
- type: "create",
326
- ...(snapshot.title && { title: snapshot.title }),
327
- ...(pins
328
- ? { target: { kind: "commits", ...pins } }
329
- : repositoryId && {
330
- target: { kind: "project", repositoryId },
331
- }),
332
- },
412
+ const create = {
413
+ operation: {
414
+ type: "create",
415
+ ...(snapshot.title && { title: snapshot.title }),
416
+ ...(pins
417
+ ? { target: { kind: "commits", ...pins } }
418
+ : repositoryId && {
419
+ target: { kind: "project", repositoryId },
420
+ }),
333
421
  },
334
- {
335
- document: JSON.parse(document),
336
- lenses: snapshot.lenses,
337
- origin: snapshot.origin,
338
- shared: { ...attribution, cloneUrl, key },
339
- copiedFrom: snapshot.reviewId,
340
- },
341
- { kind: "person" },
342
- );
422
+ };
423
+
424
+ const seed = {
425
+ document: JSON.parse(document),
426
+ lenses: snapshot.lenses,
427
+ origin: snapshot.origin,
428
+ shared: { ...provenance, cloneUrl, key },
429
+ copiedFrom: snapshot.reviewId,
430
+ };
431
+
432
+ const { reviewId } = into
433
+ ? await store.refreshCopy(into.reviewId, into.version, create, seed)
434
+ : await store.execute(create, seed, { kind: "person" });
343
435
 
344
436
  return reviewId;
345
437
  }
@@ -21,6 +21,7 @@ import {
21
21
  REVIEW_COLOR_THEME_KINDS,
22
22
  REVIEW_DIFF_LAYOUTS,
23
23
  REVIEW_DIFF_LAYOUT_SCOPES,
24
+ REVIEW_OPEN_FILES_IN_CHOICES,
24
25
  isJsonObject,
25
26
  jsonBoolean,
26
27
  jsonNumber,
@@ -93,7 +94,12 @@ export const LSP_FEATURE = [
93
94
 
94
95
  export const LSP_VIA = ["command", "mouse"] as const;
95
96
 
96
- export const LSP_EDITOR_KIND = ["files_tab", "inline_peek", "diff"] as const;
97
+ export const LSP_EDITOR_KIND = [
98
+ "files_tab",
99
+ "inline_peek",
100
+ "diff",
101
+ "definition_peek",
102
+ ] as const;
97
103
 
98
104
  export const LSP_LANGUAGE = [
99
105
  "typescript",
@@ -212,6 +218,17 @@ const MAP_LEVEL = ["system", "container", "component", "code"] as const;
212
218
 
213
219
  const SOURCE_TREE_OPENED_VIA = ["topbar", "home"] as const;
214
220
 
221
+ const SOURCE_OPENED_DESTINATION = [
222
+ "source_window",
223
+ "vscode",
224
+ "cursor",
225
+ "zed",
226
+ "intellij",
227
+ "application",
228
+ ] as const;
229
+
230
+ const SOURCE_OPENED_KIND = ["file", "diff", "references", "tree"] as const;
231
+
215
232
  /** Tab names the dwell beacon reports. Shared with its request parser. */
216
233
  export const REVIEW_TELEMETRY_TABS = [
217
234
  "review",
@@ -431,6 +448,13 @@ export const UI_TELEMETRY_EVENTS = {
431
448
  event: "review_source_tree_opened",
432
449
  properties: { via: SOURCE_TREE_OPENED_VIA },
433
450
  },
451
+ source_opened: {
452
+ event: "review_source_opened",
453
+ properties: {
454
+ destination: SOURCE_OPENED_DESTINATION,
455
+ kind: SOURCE_OPENED_KIND,
456
+ },
457
+ },
434
458
  whiteboard_file_exported: {
435
459
  event: "review_whiteboard_file_exported",
436
460
  properties: {},
@@ -571,6 +595,7 @@ export const UI_TELEMETRY_EVENTS = {
571
595
  setting: SETTING_NAME,
572
596
  enabled: "boolean",
573
597
  value: REVIEW_COLOR_THEME_KINDS,
598
+ choice: REVIEW_OPEN_FILES_IN_CHOICES,
574
599
  },
575
600
  },
576
601
  review_opened: {
@@ -1,2 +0,0 @@
1
- import { n as runReviewAgentCli } from "./agent-cli-kHRrwO4n.js";
2
- export { runReviewAgentCli };
@@ -1,2 +0,0 @@
1
- import { t as openReviewProfile } from "./profile--BYIjPkc.js";
2
- export { openReviewProfile };
@@ -1,52 +0,0 @@
1
- import type { AlignmentRow } from "@dev.fast/whiteboard-document";
2
- import { parseUnifiedPatch } from "@review/unified-diff.js";
3
-
4
- /** Project the already-computed patch's runs, including unchanged gaps. */
5
- export function textualRows(
6
- path: string,
7
- patch: string,
8
- baseCount: number,
9
- headCount: number,
10
- ): AlignmentRow[] {
11
- const rows: AlignmentRow[] = [];
12
-
13
- let base = 0,
14
- head = 0;
15
-
16
- const append = (baseEnd: number, headEnd: number) => {
17
- while (base < baseEnd || head < headEnd)
18
- rows.push([
19
- base < baseEnd ? base++ : null,
20
- head < headEnd ? head++ : null,
21
- ]);
22
- };
23
-
24
- for (const hunk of parseUnifiedPatch(path, patch)) {
25
- append(
26
- hunk.oldLines ? hunk.oldStart - 1 : hunk.oldStart,
27
- hunk.newLines ? hunk.newStart - 1 : hunk.newStart,
28
- );
29
-
30
- let removed = 0,
31
- added = 0;
32
-
33
- const flush = () => {
34
- append(base + removed, head + added);
35
- removed = added = 0;
36
- };
37
-
38
- for (const line of hunk.lines) {
39
- if (line.kind === "context") {
40
- flush();
41
- append(base + 1, head + 1);
42
- } else if (line.kind === "add") added++;
43
- else removed++;
44
- }
45
-
46
- flush();
47
- }
48
-
49
- append(baseCount, headCount);
50
-
51
- return rows;
52
- }