@dev.fast/whiteboard 0.5.0 → 0.5.2-preview.20261104.146

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 (117) hide show
  1. package/dist/{account-alias-Bw3PT3Qo.js → account-alias-BlYamXAG.js} +5 -5
  2. package/dist/{agent-cli-kHRrwO4n.js → agent-cli-D7fF5xmm.js} +9 -9
  3. package/dist/agent-cli-DLibAL4u.js +2 -0
  4. package/dist/{agent-client-CMacGbMp.js → agent-client-BCEbSPWU.js} +4 -4
  5. package/dist/{authoring-tools-CiLy46kh.js → authoring-tools-CkfxTVJm.js} +12 -8
  6. package/dist/{background-server-eZWXoVcI.js → background-server-BraP8pJ9.js} +4 -4
  7. package/dist/{background-server-BLNHbksB.js → background-server-CwToVN1g.js} +1 -1
  8. package/dist/build-info.json +1 -1
  9. package/dist/{cli-Bxmiqutp.js → cli-BpadBaGU.js} +1 -1
  10. package/dist/{cli-runner-DQPuu7kJ.js → cli-runner-BebYF50a.js} +22 -22
  11. package/dist/cli.js +2 -2
  12. package/dist/{fuzzy-match-DZjeOaPY.js → fuzzy-match-CxcsLQGx.js} +3 -3
  13. package/dist/{headless-host-Dl2KZ9IT.js → headless-host-FAlbekFD.js} +561 -415
  14. package/dist/{headless-host-B4r0s1ks.js → headless-host-cLipIufH.js} +1 -1
  15. package/dist/{import-YAIU6rB0.js → import-CZ1958L4.js} +234 -62
  16. package/dist/{local-data-C58vzLZR.js → local-data-DdFkxFK_.js} +41 -16
  17. package/dist/{mcp-COYWiGVn.js → mcp-Claiy9xE.js} +9 -6
  18. package/dist/{package-paths-Cg6fnaGp.js → package-paths-Dk7MOXxN.js} +1 -1
  19. package/dist/{profile--BYIjPkc.js → profile-Bsgzi9PA.js} +2 -2
  20. package/dist/profile-BxdzBxHW.js +2 -0
  21. package/dist/{remote-attach-C1prLjmj.js → remote-attach-LGTpwpUv.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-BAznkpeu.js} +4 -4
  25. package/dist/{remote-uninstall-B3Slwor1.js → remote-uninstall-CLP79Cuk.js} +5 -5
  26. package/dist/{request-origin-B3_XI2VA.js → request-origin-D6B-zrL8.js} +27 -5
  27. package/dist/{review-app-launcher-BZEbDKuK.js → review-app-launcher-tTe8bTwg.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-DACDMfqq.js} +4 -4
  30. package/dist/server/desktop-host.js +26 -38
  31. package/dist/{server-discovery-WmuFl2S3.js → server-discovery-CV5qf1J8.js} +2 -2
  32. package/dist/sharing/index.d.ts +137 -14
  33. package/dist/sharing/index.js +1 -1
  34. package/dist/{src-B2b8cCoI.js → src-BQDlJXkG.js} +44 -5
  35. package/dist/{src-DLWol7GZ.js → src-CrrW7lcY.js} +16 -1
  36. package/dist/{stored-document-migration-iwIQ4l5G.js → stored-document-migration-D1wK4yID.js} +3 -3
  37. package/dist/{thread-state-B7L1mpN_.js → thread-state-WTqSborE.js} +1 -1
  38. package/dist/{tool-failure-RLR8m9hq.js → tool-failure-YOFGHJCZ.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 +6 -6
  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/document-text.ts +27 -12
  101. package/src/review-api/http.ts +52 -6
  102. package/src/review-api/instructions.ts +1 -1
  103. package/src/review-api/mcp.ts +10 -5
  104. package/src/review-api/public-tools.ts +71 -2
  105. package/src/review-api/store.ts +89 -12
  106. package/src/server/desktop-server.ts +17 -5
  107. package/src/server/headless-host.ts +4 -0
  108. package/src/server/review-gateway.ts +1 -0
  109. package/src/server/review-server-core.ts +71 -12
  110. package/src/sharing/client.ts +129 -32
  111. package/src/sharing/export.ts +42 -5
  112. package/src/sharing/file.ts +8 -0
  113. package/src/sharing/host.ts +202 -73
  114. package/src/sharing/import.ts +125 -33
  115. package/src/ui-telemetry-events.ts +25 -1
  116. package/dist/agent-cli-B8KBHuh_.js +0 -2
  117. package/dist/profile-BjcXi-oH.js +0 -2
@@ -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,16 @@ 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
+ "application",
227
+ ] as const;
228
+
229
+ const SOURCE_OPENED_KIND = ["file", "diff", "references", "tree"] as const;
230
+
215
231
  /** Tab names the dwell beacon reports. Shared with its request parser. */
216
232
  export const REVIEW_TELEMETRY_TABS = [
217
233
  "review",
@@ -431,6 +447,13 @@ export const UI_TELEMETRY_EVENTS = {
431
447
  event: "review_source_tree_opened",
432
448
  properties: { via: SOURCE_TREE_OPENED_VIA },
433
449
  },
450
+ source_opened: {
451
+ event: "review_source_opened",
452
+ properties: {
453
+ destination: SOURCE_OPENED_DESTINATION,
454
+ kind: SOURCE_OPENED_KIND,
455
+ },
456
+ },
434
457
  whiteboard_file_exported: {
435
458
  event: "review_whiteboard_file_exported",
436
459
  properties: {},
@@ -571,6 +594,7 @@ export const UI_TELEMETRY_EVENTS = {
571
594
  setting: SETTING_NAME,
572
595
  enabled: "boolean",
573
596
  value: REVIEW_COLOR_THEME_KINDS,
597
+ choice: REVIEW_OPEN_FILES_IN_CHOICES,
574
598
  },
575
599
  },
576
600
  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 };