@dev.fast/whiteboard 0.4.0 → 0.4.1-preview.20261026.138

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 (78) hide show
  1. package/dist/{account-alias-2yTAxoBx.js → account-alias-BPlPnzQM.js} +7 -7
  2. package/dist/{agent-cli-CHNDd4Ga.js → agent-cli-BbCf9uid.js} +11 -11
  3. package/dist/agent-cli-ipN_JmzG.js +2 -0
  4. package/dist/{agent-client-Dc0vHFJt.js → agent-client-DfpM8F5N.js} +3 -3
  5. package/dist/{authoring-tools-D8EkIDjm.js → authoring-tools-bm39DRoV.js} +23 -10
  6. package/dist/{background-server-DyWnPJyZ.js → background-server--0EeCCeV.js} +1 -1
  7. package/dist/{background-server-DHWHzpo5.js → background-server-B--5p72o.js} +6 -6
  8. package/dist/build-info.json +1 -1
  9. package/dist/{cli-qZomwJmK.js → cli-DBTQIroM.js} +2 -2
  10. package/dist/{cli-runner-DFBaVGij.js → cli-runner-CRFCdb7G.js} +25 -25
  11. package/dist/cli.js +3 -3
  12. package/dist/{fuzzy-match-CfSxqzBF.js → fuzzy-match-l3mJZ1Ge.js} +5 -5
  13. package/dist/{headless-host-dwlqhqMY.js → headless-host-5ei3nHS8.js} +1 -1
  14. package/dist/{headless-host-DJhcab6r.js → headless-host-BkJ9OUQY.js} +131 -299
  15. package/dist/{client-p9WB8Sj0.js → import-Bwvf9Wos.js} +505 -390
  16. package/dist/{lens-selection-9byzEgvU.js → lens-selection-EuZdag4Q.js} +1 -1
  17. package/dist/{local-data-DHedfhxw.js → local-data-BCSeTyic.js} +98 -154
  18. package/dist/{mcp-Br-r_wwR.js → mcp-_Xg1gQuA.js} +17 -8
  19. package/dist/{package-paths-BeYHYjeR.js → package-paths-Bg731FHS.js} +2 -2
  20. package/dist/profile-C8zL4u3L.js +2 -0
  21. package/dist/{profile-D9wdlPgw.js → profile-xzrUFgbT.js} +4 -4
  22. package/dist/{remote-attach-DSGpTOJ4.js → remote-attach-DF25Epoa.js} +4 -4
  23. package/dist/{remote-extensions-WtJO7pkb.js → remote-extensions-BJamgsCe.js} +1 -1
  24. package/dist/{remote-extensions-CsI_BJ_f.js → remote-extensions-CeywZL-Z.js} +4 -4
  25. package/dist/{remote-language-server-Dx13Mg2m.js → remote-language-server-CH8sG_CU.js} +6 -6
  26. package/dist/{remote-uninstall-Dp2o3qz0.js → remote-uninstall-Cq-lkBY7.js} +7 -7
  27. package/dist/{request-origin-CNSLVn7x.js → request-origin-CargJFvH.js} +14 -3
  28. package/dist/{review-app-launcher-BZAnR8Vp.js → review-app-launcher-D8ApNDUV.js} +3 -3
  29. package/dist/{review-home-paths-CG-sb9Cw.js → review-home-paths-DcB4xLD-.js} +2 -2
  30. package/dist/{review-telemetry-BM-_KdLi.js → review-telemetry-BW7gJrSo.js} +7 -7
  31. package/dist/{runtime-C6_1K-3Z.js → runtime-DY6Ctyog.js} +1 -1
  32. package/dist/runtime.js +1 -1
  33. package/dist/{s3-CsG2EWED.js → s3-BIWv4h1J.js} +2 -2
  34. package/dist/{s3-config-zz4GWh2T.js → s3-config-Du3RBIvv.js} +1 -1
  35. package/dist/server/desktop-host.js +51 -17
  36. package/dist/{server-discovery-DKLIOgg3.js → server-discovery-aHK_1r3U.js} +5 -5
  37. package/dist/sharing/index.d.ts +209 -98
  38. package/dist/sharing/index.js +1 -1
  39. package/dist/{src-DYHVzX3b.js → src-DEOc8bvC.js} +63 -2
  40. package/dist/{src-Z1x4-Qmb.js → src-DjRaCctk.js} +6 -6
  41. package/dist/{stored-document-migration-DEt8iwem.js → stored-document-migration-CwmTwTb8.js} +139 -13
  42. package/dist/{thread-state-CO97FUqK.js → thread-state-CbLB0jUA.js} +1 -1
  43. package/dist/{tool-failure-C1L1vJyz.js → tool-failure-DZaQzi4f.js} +2 -2
  44. package/instructions/animation.md +345 -0
  45. package/instructions/authoring.md +2 -2
  46. package/package.json +6 -6
  47. package/src/fixtures/blocks/animation.json +19 -0
  48. package/src/review-api/authoring-tools.ts +17 -6
  49. package/src/review-api/blocks/animation.ts +98 -0
  50. package/src/review-api/blocks/index.ts +3 -0
  51. package/src/review-api/blocks/sequence.ts +3 -1
  52. package/src/review-api/comparison-coverage.ts +120 -89
  53. package/src/review-api/component-reference.ts +16 -0
  54. package/src/review-api/document-text.ts +11 -0
  55. package/src/review-api/document.ts +26 -5
  56. package/src/review-api/http.ts +31 -2
  57. package/src/review-api/instructions.ts +11 -2
  58. package/src/review-api/local-data.ts +21 -4
  59. package/src/review-api/mcp.ts +22 -14
  60. package/src/review-api/onboarding.ts +100 -26
  61. package/src/review-preferences.ts +43 -0
  62. package/src/server/desktop-server.ts +24 -0
  63. package/src/server/json-review-reporting.ts +1 -1
  64. package/src/server/review-server-core.ts +2 -0
  65. package/src/server/structural-comparisons.ts +5 -11
  66. package/src/server/structural-diff.ts +8 -2
  67. package/src/sharing/cli.ts +1 -1
  68. package/src/sharing/client.ts +54 -222
  69. package/src/sharing/export.ts +172 -114
  70. package/src/sharing/host.ts +32 -36
  71. package/src/sharing/import.ts +93 -147
  72. package/src/sharing/index.ts +1 -6
  73. package/src/sharing/routes.ts +18 -17
  74. package/src/ui-telemetry-events.ts +11 -0
  75. package/dist/agent-cli-Cn4-16XA.js +0 -2
  76. package/dist/profile-BopGMZUh.js +0 -2
  77. package/dist/{s3-config-CjcLyFV5.js → s3-config-D7Yt0VhS.js} +1 -1
  78. package/dist/{src-X9ZebeOD.js → src-DXnn7RrI.js} +1 -1
@@ -37,6 +37,10 @@ const StructuralDiffEventSchema = z.lazy(() => z.union([
37
37
  type: z.literal("file"),
38
38
  file: structuralPairingSchema(StructuralFileRefSchema)
39
39
  }).and(StructuralOutcomeSchema),
40
+ z.object({
41
+ type: z.literal("update"),
42
+ file: structuralPairingSchema(StructuralFileRefSchema)
43
+ }).and(StructuralUpdateSchema),
40
44
  z.object({
41
45
  type: z.literal("complete"),
42
46
  succeeded: structuralU32,
@@ -51,6 +55,20 @@ const StructuralOutcomeSchema = z.lazy(() => z.union([z.object({
51
55
  error: StructuralProblemSchema,
52
56
  diff: z.never().optional()
53
57
  })]));
58
+ const StructuralUpdateSchema = z.lazy(() => z.union([z.object({
59
+ regions: z.array(StructuralRegionVisibilitySchema),
60
+ visible: StructuralLineCountsSchema,
61
+ error: z.never().optional()
62
+ }), z.object({
63
+ error: StructuralProblemSchema,
64
+ regions: z.never().optional(),
65
+ visible: z.never().optional()
66
+ })]));
67
+ const StructuralRegionVisibilitySchema = z.lazy(() => z.object({
68
+ id: structuralU32,
69
+ collapsed: z.boolean().optional(),
70
+ label: z.string().optional()
71
+ }));
54
72
  const StructuralSnapshotSchema = z.lazy(() => z.union([
55
73
  z.object({
56
74
  type: z.literal("revision"),
@@ -174,6 +192,45 @@ const ReviewStructuralDiffErrorSchema = z.object({
174
192
  message: z.string()
175
193
  });
176
194
  z.union([StructuralDiffEventSchema, ReviewStructuralDiffErrorSchema]);
195
+ /**
196
+ * A copy of `diff` with an update's region visibility and visible counts.
197
+ * `accept` may change what a region takes from its entry.
198
+ */
199
+ function applyStructuralUpdate(diff, update, accept = (_, next) => next) {
200
+ const entries = new Map(update.regions.map(({ id, ...visibility }) => [id, visibility]));
201
+ const visit = (region) => {
202
+ const entry = entries.get(region.id);
203
+ let next = region;
204
+ if (entry) {
205
+ const { collapsed, label } = accept(region, entry);
206
+ const { visibility: _, ...rest } = region;
207
+ next = collapsed || label ? {
208
+ ...rest,
209
+ visibility: {
210
+ ...collapsed && { collapsed },
211
+ ...label && { label }
212
+ }
213
+ } : rest;
214
+ }
215
+ return next.kind === "fold" ? {
216
+ ...next,
217
+ children: next.children.map(visit)
218
+ } : next;
219
+ };
220
+ const side = (source) => ({
221
+ ...source,
222
+ root: visit(source.root)
223
+ });
224
+ return {
225
+ ...diff,
226
+ ...diff.lhs && { lhs: side(diff.lhs) },
227
+ ...diff.rhs && { rhs: side(diff.rhs) },
228
+ stats: {
229
+ ...diff.stats,
230
+ visible: update.visible
231
+ }
232
+ };
233
+ }
177
234
  const REVIEW_CLIENT_HEADER = "x-review-client";
178
235
  const REVIEW_CLIENT_REMOTE = "remote";
179
236
  const REVIEW_HOST_HEADER = "x-review-host";
@@ -194,7 +251,11 @@ const reviewViewSchema = z.enum([
194
251
  "map",
195
252
  "trace"
196
253
  ]);
197
- const reviewThemeSchema = z.enum(["light", "dark"], { error: "must be light or dark" });
254
+ const reviewThemeSchema = z.enum([
255
+ "light",
256
+ "dark",
257
+ "system"
258
+ ], { error: "must be light, dark or system" });
198
259
  function urlSchema(output, constraint) {
199
260
  return requiredString$1.transform((value, context) => {
200
261
  let url;
@@ -1108,4 +1169,4 @@ function formatIssuePath(path) {
1108
1169
  return output;
1109
1170
  }
1110
1171
  //#endregion
1111
- export { ReviewGatewayHostSchema as A, REVIEW_REMOTE_INSTALL_LOCK as C, ReviewConnectRequestSchema as D, ReviewCliInstallStampSchema as E, structuralChangeCounts as F, ReviewSelectedDiffSchema as M, reviewDiffrSummarizerInputSchema as N, ReviewFeedbackContactSchema as O, decodeStructuralDiffEvent as P, REVIEW_REMOTE_ATTACH_END as S, ReviewApiSelectionSourceSchema as T, REVIEW_DIFF_LAYOUTS as _, parseReviewVerbRequest as a, REVIEW_REMOTE_AGENT_IDS as b, boardIconKind as c, ReviewBugReportRequestSchema as d, parseReviewBugReportResponse as f, REVIEW_COLOR_THEME_KINDS as g, REVIEW_CLI_INSTALL_TARGET_LABELS as h, parseReviewDesktopVerbResult as i, ReviewOnboardingRunRequestSchema as j, ReviewFeedbackSchema as k, boardTitle as l, REVIEW_CLIENT_REMOTE as m, parseReviewDesktopDiscovery as n, parseReviewVerbResponse as o, REVIEW_CLIENT_HEADER as p, parseReviewDesktopVerbFrame as r, parseZod as s, parseReviewCliInstallApplyRequest as t, ReviewBugReportMetaV2Schema as u, REVIEW_DIFF_LAYOUT_SCOPES as v, REVIEW_REMOTE_WRAPPER_MARK as w, REVIEW_REMOTE_ATTACH_BEGIN as x, REVIEW_HOST_HEADER as y };
1172
+ export { ReviewGatewayHostSchema as A, REVIEW_REMOTE_INSTALL_LOCK as C, ReviewConnectRequestSchema as D, ReviewCliInstallStampSchema as E, decodeStructuralDiffEvent as F, structuralChangeCounts as I, ReviewSelectedDiffSchema as M, reviewDiffrSummarizerInputSchema as N, ReviewFeedbackContactSchema as O, applyStructuralUpdate as P, REVIEW_REMOTE_ATTACH_END as S, ReviewApiSelectionSourceSchema as T, REVIEW_DIFF_LAYOUTS as _, parseReviewVerbRequest as a, REVIEW_REMOTE_AGENT_IDS as b, boardIconKind as c, ReviewBugReportRequestSchema as d, parseReviewBugReportResponse as f, REVIEW_COLOR_THEME_KINDS as g, REVIEW_CLI_INSTALL_TARGET_LABELS as h, parseReviewDesktopVerbResult as i, ReviewOnboardingRunRequestSchema as j, ReviewFeedbackSchema as k, boardTitle as l, REVIEW_CLIENT_REMOTE as m, parseReviewDesktopDiscovery as n, parseReviewVerbResponse as o, REVIEW_CLIENT_HEADER as p, parseReviewDesktopVerbFrame as r, parseZod as s, parseReviewCliInstallApplyRequest as t, ReviewBugReportMetaV2Schema as u, REVIEW_DIFF_LAYOUT_SCOPES as v, REVIEW_REMOTE_WRAPPER_MARK as w, REVIEW_REMOTE_ATTACH_BEGIN as x, REVIEW_HOST_HEADER as y };
@@ -1,13 +1,13 @@
1
- import { b as resolveRepoContext, d as git, f as gitAt, w as runVcs } from "./src-X9ZebeOD.js";
1
+ import { b as resolveRepoContext, d as git, f as gitAt, w as runVcs } from "./src-DXnn7RrI.js";
2
2
  import { a as jsonNumber, c as jsonString, i as jsonBoolean, m as isStringValue, n as isJsonObject, o as jsonObject, r as jsonArray, t as isJsonArray, u as parseJsonText } from "./src-X9phtB2j.js";
3
3
  import { a as TRACE_STORE_CLIENT_ID, b as commitShaSchema, c as deleteStoreResponseSchema, d as listUploadsResponseSchema, f as storeErrorCodeSchema, g as uploadManifestMismatch, h as traceObjectNameSchema, i as storeRoutes, l as listSessionsResponseSchema, m as storeResponseSchema, n as DEVICE_TOKEN_PATH, o as beginUploadResponseSchema, p as storeErrorEnvelopeSchema, r as SESSION_PATH, s as completeUploadResponseSchema, t as DEVICE_CODE_PATH, u as listUploadsQuerySchema, x as sessionIdSchema } from "./src-CGP5ytbV.js";
4
- import { E as writeTraceConfigFile, F as writeFileAtomic, I as writeFileAtomicAsync, L as writePrivateJsonAtomic, N as devReviewHome, P as normalizeStoreOrigin, S as readTraceConfigFile, _ as emptyTraceConfig, b as hostedCaptureEnabled, c as resolveS3Setup, d as traceEnvPath, f as traceEnvValue$1, g as currentStore, h as TraceConfigurationError, i as isS3MockMode, l as s3CacheIdentity, m as DEFAULT_HOSTED_ORIGIN, n as clearTraceEnvCache$1, p as traceSettingsPath, u as s3MockRoot, v as enabledOriginsOf, w as s3Store, x as hostedOrigin, y as hasHostedStore } from "./s3-config-CjcLyFV5.js";
4
+ import { E as writeTraceConfigFile, F as writeFileAtomic, I as writeFileAtomicAsync, L as writePrivateJsonAtomic, N as devReviewHome, P as normalizeStoreOrigin, S as readTraceConfigFile, _ as emptyTraceConfig, b as hostedCaptureEnabled, c as resolveS3Setup, d as traceEnvPath, f as traceEnvValue$1, g as currentStore, h as TraceConfigurationError, i as isS3MockMode, l as s3CacheIdentity, m as DEFAULT_HOSTED_ORIGIN, n as clearTraceEnvCache$1, p as traceSettingsPath, u as s3MockRoot, v as enabledOriginsOf, w as s3Store, x as hostedOrigin, y as hasHostedStore } from "./s3-config-D7Yt0VhS.js";
5
5
  import { t as errorMessage } from "./error-message-OtiDonty.js";
6
6
  import { createHash, randomBytes } from "node:crypto";
7
7
  import { z } from "zod";
8
+ import path from "node:path";
8
9
  import { accessSync, closeSync, constants, createReadStream, createWriteStream, existsSync, mkdirSync, openSync, readFileSync, readdirSync, rmSync, statSync } from "node:fs";
9
10
  import { chmod, mkdir, mkdtemp, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
10
- import path from "node:path";
11
11
  import { Readable, Transform } from "node:stream";
12
12
  import { AsyncLocalStorage } from "node:async_hooks";
13
13
  import os, { homedir, tmpdir } from "node:os";
@@ -2540,7 +2540,7 @@ function isTraceStorageConfigured(scope = {}) {
2540
2540
  }
2541
2541
  /** Loads the direct-store implementation on demand, without opening a store. */
2542
2542
  async function loadS3TraceStorage() {
2543
- return (await import("./s3-CsG2EWED.js")).S3TraceStorage;
2543
+ return (await import("./s3-BIWv4h1J.js")).S3TraceStorage;
2544
2544
  }
2545
2545
  //#endregion
2546
2546
  //#region ../trace-core/src/trace-upload-status.ts
@@ -5266,7 +5266,7 @@ async function configureTraceMachine(input) {
5266
5266
  if (input.verify !== false) {
5267
5267
  if (env.TRACE_R2_MODE === "mock") verifiedAt = (/* @__PURE__ */ new Date()).toISOString();
5268
5268
  else {
5269
- const { S3TraceStorage } = await import("./s3-CsG2EWED.js");
5269
+ const { S3TraceStorage } = await import("./s3-BIWv4h1J.js");
5270
5270
  const readiness = await S3TraceStorage.fromCredentials({
5271
5271
  endpoint: credentials.endpoint,
5272
5272
  bucket: credentials.bucket,
@@ -5736,7 +5736,7 @@ async function runTraceStatus(input) {
5736
5736
  input.stderr.write("Upload status filters require hosted storage.\n");
5737
5737
  return 1;
5738
5738
  }
5739
- const [{ S3TraceStorage }, { describeS3Setup, noTraceConfigurationMessage }] = await Promise.all([import("./s3-CsG2EWED.js"), import("./s3-config-zz4GWh2T.js")]);
5739
+ const [{ S3TraceStorage }, { describeS3Setup, noTraceConfigurationMessage }] = await Promise.all([import("./s3-BIWv4h1J.js"), import("./s3-config-Du3RBIvv.js")]);
5740
5740
  const setup = describeS3Setup(input.scope.env);
5741
5741
  input.stdout.write(`Checking trace configuration (${setup.envPath})…\n`);
5742
5742
  for (const failure of await listTraceSyncFailures(input.scope.devHome)) input.stdout.write(describeTraceSyncFailure(failure));
@@ -1,8 +1,8 @@
1
- import { C as renderVcsArgs, v as parseGitRemote, w as runVcs } from "./src-X9ZebeOD.js";
1
+ import { C as renderVcsArgs, v as parseGitRemote, w as runVcs } from "./src-DXnn7RrI.js";
2
2
  import { d as isBooleanValue, f as isNumberValue, l as jsonValueSchema, m as isStringValue, n as isJsonObject, t as isJsonArray } from "./src-X9phtB2j.js";
3
- import "./src-DYHVzX3b.js";
4
- import "./src-Z1x4-Qmb.js";
5
- import { a as commitLinkTarget, c as parseAnchor, d as selectionProblem, f as sourceAnchors, i as anchorSelection, r as anchorSchema, s as formatAnchor } from "./lens-selection-9byzEgvU.js";
3
+ import "./src-DEOc8bvC.js";
4
+ import "./src-DjRaCctk.js";
5
+ import { a as commitLinkTarget, c as parseAnchor, d as selectionProblem, f as sourceAnchors, i as anchorSelection, r as anchorSchema, s as formatAnchor } from "./lens-selection-EuZdag4Q.js";
6
6
  import { t as ReviewInputError } from "./input-error-OLgB_h31.js";
7
7
  import { t as errorMessage } from "./error-message-OtiDonty.js";
8
8
  import { randomUUID } from "node:crypto";
@@ -1041,6 +1041,33 @@ const flow_diagram = {
1041
1041
  }
1042
1042
  };
1043
1043
  //#endregion
1044
+ //#region src/review-api/blocks/animation.ts
1045
+ /** A name the stage's script passes to the `whiteboard` shim. */
1046
+ const handle = z.string().regex(/^[A-Za-z][\w-]{0,63}$/, "Use a short name: a letter, then letters, digits, _ or -.");
1047
+ const animationFrameSchema = z.strictObject({
1048
+ key: handle.describe("Names the frame for the stage: data-frame on <html>, data-enter/data-exit, and whiteboard.on(key, ...)."),
1049
+ title: label$1,
1050
+ label: z.string().min(1).max(24).optional().describe("A short name for the step strip under the stage, e.g. PUSH. Give every frame one, or none."),
1051
+ caption: text$1.optional().describe("One or two short sentences shown under the stage."),
1052
+ duration: z.number().int().min(300).max(3e4).optional().describe("Milliseconds this frame stays up while playing. Default 3000.")
1053
+ });
1054
+ const animation = {
1055
+ type: "animation",
1056
+ schema: defineBlock("animation", {
1057
+ title: label$1,
1058
+ html: text$1.min(1).max(2e5).describe("The stage's body markup: elements, <style> and <script>. It runs in a sandboxed frame with a global `whiteboard` shim; see session_get_instructions({topic:\"animation\"})."),
1059
+ frames: z.array(animationFrameSchema).min(1).max(60).describe("Every possible frame. Stage scripts may select an ordered branch with whiteboard.setSequence(keys); keys stay unique and stable."),
1060
+ code: z.record(handle, anchorSchema).default({}).describe("Source ranges the stage shows as code peeks, by name: whiteboard.code(name)."),
1061
+ height: z.union([z.literal("auto"), z.number().int().min(120).max(1200)]).default("auto").describe("Fit the stage to its content by default, or set a fixed height in CSS pixels."),
1062
+ pins: elementPins
1063
+ }),
1064
+ check(block) {
1065
+ if (new Set(block.frames.map((frame) => frame.key)).size !== block.frames.length) throw new ReviewInputError("Animation frame keys must be unique within the animation.");
1066
+ const labelled = block.frames.filter((frame) => frame.label).length;
1067
+ if (labelled && labelled !== block.frames.length) throw new ReviewInputError("Give every animation frame a label, or none: the step strip needs one per frame.");
1068
+ }
1069
+ };
1070
+ //#endregion
1044
1071
  //#region src/review-api/blocks/call_stack_diff.ts
1045
1072
  const frameSchema = z.strictObject({
1046
1073
  ...identity,
@@ -1253,7 +1280,7 @@ const stepSchema = z.strictObject({
1253
1280
  ]).default("call"),
1254
1281
  /** The call site this arrow stands for, then any ranges directly about
1255
1282
  * that call, each shown as its own card. */
1256
- source: z.union([anchorSchema, z.array(anchorSchema).min(1).max(4)]).optional(),
1283
+ source: z.union([anchorSchema, z.array(anchorSchema).min(1).max(4)], { error: "source must be one range or a list of 1 to 4 ranges" }).optional(),
1257
1284
  pins: elementPins,
1258
1285
  explanation: label$1.optional(),
1259
1286
  code: z.strictObject(codeFields).optional()
@@ -1338,7 +1365,8 @@ const leafSchema = z.discriminatedUnion("type", [
1338
1365
  image.schema,
1339
1366
  trace_quote.schema,
1340
1367
  software_map.schema,
1341
- flow_diagram.schema
1368
+ flow_diagram.schema,
1369
+ animation.schema
1342
1370
  ]);
1343
1371
  /** Every block kind, keyed by type. A kind without a definition is a compile error. */
1344
1372
  const blocks = {
@@ -1353,6 +1381,7 @@ const blocks = {
1353
1381
  trace_quote,
1354
1382
  software_map,
1355
1383
  flow_diagram,
1384
+ animation,
1356
1385
  section,
1357
1386
  callout
1358
1387
  };
@@ -1457,6 +1486,9 @@ const unitTypes = /* @__PURE__ */ new Set([
1457
1486
  "flow_edge"
1458
1487
  ]);
1459
1488
  const isUnit = (element) => unitTypes.has(element.type);
1489
+ /** The reference id of a code peek an animation names: the canvas finds the
1490
+ * peek's resolved anchor by it. */
1491
+ const animationCodeId = (blockId, name) => `${blockId}:code:${name}`;
1460
1492
  /** Rewrites old review-source: and review-trace: links to their whiteboard: form. */
1461
1493
  function canonicalLink(href) {
1462
1494
  return href.replace(/^review-(source|trace):/i, (_, kind) => `whiteboard:${kind.toLowerCase()}/`);
@@ -1639,6 +1671,12 @@ function documentReferences(document, { tolerant = false, markdown = true, repos
1639
1671
  label: attachment.label,
1640
1672
  peek: true
1641
1673
  })))));
1674
+ if (element.type === "animation") return Object.entries(element.code).flatMap(([name, anchor]) => select(anchor, element.pins).map((source) => ({
1675
+ id: animationCodeId(element.id, name),
1676
+ source,
1677
+ label: name,
1678
+ peek: true
1679
+ })));
1642
1680
  if (element.type === "call_stack_diff") return [...element.base, ...element.head].flatMap((frame) => {
1643
1681
  const pins = frame.pins ?? element.pins;
1644
1682
  return [
@@ -1789,12 +1827,15 @@ const writableBlockTypes = Object.keys(blocks);
1789
1827
  const namedByType = (types) => z.looseObject({ type: z.enum(types) }).describe("Fields depend on type; see the tool description.");
1790
1828
  /** What agents are shown: content names only its type. The host parses
1791
1829
  * editSchema, reporting the named kind's issues. */
1792
- const publishedEditSchema = edits(namedByType([
1793
- ...writableBlockTypes,
1794
- "step",
1795
- "flow_node",
1796
- "flow_edge"
1797
- ]), namedByType(writableBlockTypes), z.unknown());
1830
+ function publishedEdits(animationsEnabled = true) {
1831
+ const types = writableBlockTypes.filter((type) => animationsEnabled || type !== "animation");
1832
+ return edits(namedByType([
1833
+ ...types,
1834
+ "step",
1835
+ "flow_node",
1836
+ "flow_edge"
1837
+ ]), namedByType(types), z.unknown());
1838
+ }
1798
1839
  /** The block an element belongs to: itself, or the diagram around a unit. */
1799
1840
  function enclosingBlock(document, id) {
1800
1841
  for (const block of elements(document)) {
@@ -2036,6 +2077,91 @@ function written(element) {
2036
2077
  return applied;
2037
2078
  }
2038
2079
  //#endregion
2080
+ //#region src/unified-diff.ts
2081
+ const HUNK_HEADER = /^@@ -(?<oldStart>\d+)(?:,(?<oldLines>\d+))? \+(?<newStart>\d+)(?:,(?<newLines>\d+))? @@/;
2082
+ function parseUnifiedPatch(file, patch) {
2083
+ if (!patch) return [];
2084
+ const hunks = [];
2085
+ let current = null;
2086
+ let oldLine = 0;
2087
+ let newLine = 0;
2088
+ for (const row of patch.split(/\r?\n/)) {
2089
+ const header = HUNK_HEADER.exec(row);
2090
+ if (header?.groups) {
2091
+ current = {
2092
+ file,
2093
+ oldStart: Number(header.groups.oldStart),
2094
+ oldLines: Number(header.groups.oldLines ?? "1"),
2095
+ newStart: Number(header.groups.newStart),
2096
+ newLines: Number(header.groups.newLines ?? "1"),
2097
+ lines: []
2098
+ };
2099
+ oldLine = current.oldStart;
2100
+ newLine = current.newStart;
2101
+ hunks.push(current);
2102
+ continue;
2103
+ }
2104
+ if (!current || row.startsWith("\")) continue;
2105
+ const marker = row[0];
2106
+ const text = row.slice(1);
2107
+ let line = null;
2108
+ if (marker === " ") {
2109
+ line = {
2110
+ kind: "context",
2111
+ oldLine,
2112
+ newLine,
2113
+ text
2114
+ };
2115
+ oldLine += 1;
2116
+ newLine += 1;
2117
+ } else if (marker === "+") {
2118
+ line = {
2119
+ kind: "add",
2120
+ oldLine: null,
2121
+ newLine,
2122
+ text
2123
+ };
2124
+ newLine += 1;
2125
+ } else if (marker === "-") {
2126
+ line = {
2127
+ kind: "remove",
2128
+ oldLine,
2129
+ newLine: null,
2130
+ text
2131
+ };
2132
+ oldLine += 1;
2133
+ }
2134
+ if (line) current.lines.push(line);
2135
+ }
2136
+ return hunks;
2137
+ }
2138
+ //#endregion
2139
+ //#region src/review-api/lens-alignment.ts
2140
+ /** Project the already-computed patch's runs, including unchanged gaps. */
2141
+ function textualRows(path, patch, baseCount, headCount) {
2142
+ const rows = [];
2143
+ let base = 0, head = 0;
2144
+ const append = (baseEnd, headEnd) => {
2145
+ while (base < baseEnd || head < headEnd) rows.push([base < baseEnd ? base++ : null, head < headEnd ? head++ : null]);
2146
+ };
2147
+ for (const hunk of parseUnifiedPatch(path, patch)) {
2148
+ append(hunk.oldLines ? hunk.oldStart - 1 : hunk.oldStart, hunk.newLines ? hunk.newStart - 1 : hunk.newStart);
2149
+ let removed = 0, added = 0;
2150
+ const flush = () => {
2151
+ append(base + removed, head + added);
2152
+ removed = added = 0;
2153
+ };
2154
+ for (const line of hunk.lines) if (line.kind === "context") {
2155
+ flush();
2156
+ append(base + 1, head + 1);
2157
+ } else if (line.kind === "add") added++;
2158
+ else removed++;
2159
+ flush();
2160
+ }
2161
+ append(baseCount, headCount);
2162
+ return rows;
2163
+ }
2164
+ //#endregion
2039
2165
  //#region src/evidence.ts
2040
2166
  /** Quote matching shared by legacy publish and JSON accept: authors paste
2041
2167
  * transcript text with arbitrary line wrapping, so both sides compare on
@@ -3213,4 +3339,4 @@ function liftFileLenses(document) {
3213
3339
  };
3214
3340
  }
3215
3341
  //#endregion
3216
- export { lensEditSchema as $, editSchema as A, resourceReferences as B, applyEdit as C, boardRepositoryId as D, boardLinks as E, pinnedRepositoryIds as F, selectionReferences as G, respellDocumentLinks as H, pinsSchema as I, checkReferences as J, sourceReferences as K, publishedEditSchema as L, explicitPins as M, pathTargetSchema as N, commitLinkCommits as O, pinDocumentReferences as P, applyLensEdit as Q, readsAtBoardPins as R, anchorPins as S, assignMissingIds as T, respellEditLinks as U, respellCommitLinks as V, reviewTargetSchema as W, stepSources as X, documentAdvice as Y, UNCATEGORIZED_LENS_ID as Z, fetchPullRequest as _, SoftwareModelValidationError as a, requireVisibleSource as at, textIncludesQuote as b, traceSchema as c, markdownText as ct, setPullRequest as d, lensSchema as et, sourceBranchName as f, defaultPullRequestDeps as g, GitHubRefusedRead as h, readStoredDocument as i, fileLineRangeSchema as it, elements as j, documentSchema as k, pullRequestKey as l, parseMarkdown as lt, resolvePullRequest as m, migrateStoredDocument as n, SourceRangeError as nt, defineSoftwareMap as o, sliceSourceRange as ot, pullRequestProvider as p, summarizeEdit as q, migrateStoredLenses as r, checkSourcePath as rt, softwareModelDataSchema as s, markdownNodes as st, liftFileLenses as t, lensSelections as tt, pullRequestUrl as u, remoteUrls as v, assignFreshIds as w, adoptFlowUnits as x, azureRepositoryOf as y, resourceReference as z };
3342
+ export { UNCATEGORIZED_LENS_ID as $, commitLinkCommits as A, readsAtBoardPins as B, adoptFlowUnits as C, assignMissingIds as D, assignFreshIds as E, pathTargetSchema as F, respellEditLinks as G, resourceReferences as H, pinDocumentReferences as I, sourceReferences as J, reviewTargetSchema as K, pinnedRepositoryIds as L, editSchema as M, elements as N, boardLinks as O, explicitPins as P, stepSources as Q, pinsSchema as R, parseUnifiedPatch as S, applyEdit as T, respellCommitLinks as U, resourceReference as V, respellDocumentLinks as W, checkReferences as X, summarizeEdit as Y, documentAdvice as Z, fetchPullRequest as _, SoftwareModelValidationError as a, checkSourcePath as at, textIncludesQuote as b, traceSchema as c, sliceSourceRange as ct, setPullRequest as d, parseMarkdown as dt, applyLensEdit as et, sourceBranchName as f, defaultPullRequestDeps as g, GitHubRefusedRead as h, readStoredDocument as i, SourceRangeError as it, documentSchema as j, boardRepositoryId as k, pullRequestKey as l, markdownNodes as lt, resolvePullRequest as m, migrateStoredDocument as n, lensSchema as nt, defineSoftwareMap as o, fileLineRangeSchema as ot, pullRequestProvider as p, selectionReferences as q, migrateStoredLenses as r, lensSelections as rt, softwareModelDataSchema as s, requireVisibleSource as st, liftFileLenses as t, lensEditSchema as tt, pullRequestUrl as u, markdownText as ut, remoteUrls as v, anchorPins as w, textualRows as x, azureRepositoryOf as y, publishedEdits as z };
@@ -1,4 +1,4 @@
1
- import { M as ReviewSelectedDiffSchema, T as ReviewApiSelectionSourceSchema } from "./src-DYHVzX3b.js";
1
+ import { M as ReviewSelectedDiffSchema, T as ReviewApiSelectionSourceSchema } from "./src-DEOc8bvC.js";
2
2
  import { z } from "zod";
3
3
  /** A semantic selection, independent of comment/thread creation. */
4
4
  const AgentSelectionSchema = z.strictObject({
@@ -1,6 +1,6 @@
1
1
  import { m as isStringValue, n as isJsonObject } from "./src-X9phtB2j.js";
2
- import { l as boardTitle } from "./src-DYHVzX3b.js";
3
- import { n as callAuthoringTool, s as ReviewApiError, t as ToolText } from "./agent-client-Dc0vHFJt.js";
2
+ import { l as boardTitle } from "./src-DEOc8bvC.js";
3
+ import { n as callAuthoringTool, s as ReviewApiError, t as ToolText } from "./agent-client-DfpM8F5N.js";
4
4
  import { t as ReviewInputError } from "./input-error-OLgB_h31.js";
5
5
  //#region src/review-api/public-tools.ts
6
6
  function publicDescription(text) {