@dev.fast/whiteboard 0.3.4-preview.20261019.127 → 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
@@ -1,8 +1,7 @@
1
- import { f as gitAt } from "./src-WPaQn75m.js";
1
+ import { f as gitAt } from "./src-BMPuxWv4.js";
2
2
  import { n as isJsonObject, u as parseJsonText } from "./src-X9phtB2j.js";
3
- import "./src-BiWNbcF_.js";
4
- import { f as sourceAnchors } from "./lens-selection-CyJapcsl.js";
5
- import { $ as parseMarkdown, A as resourceReferences, E as pinsSchema, G as lensSelections, I as sourceReferences, O as readsAtBoardPins, R as checkReferences, W as lensSchema, Z as markdownNodes, _ as boardRepositoryId, c as normalizedSoftwareRelationshipSchema, f as anchorPins, k as resourceReference, l as traceSchema, n as migrateStoredDocument, r as migrateStoredLenses, s as normalizedSoftwareElementSchema, t as liftFileLenses, u as textIncludesQuote, x as elements, y as documentSchema } from "./stored-document-migration-dFbewRTG.js";
3
+ import "./src-DsM3jO8G.js";
4
+ import { C as resourceReference, D as sourceReferences, F as lensSchema, H as markdownNodes, I as lensSelections, U as parseMarkdown, Y as sourceAnchors, _ as hasCodeReferences, c as traceSchema, h as elements, k as checkReferences, l as textIncludesQuote, n as migrateStoredDocument, o as normalizedSoftwareElementSchema, p as documentSchema, r as migrateStoredLenses, s as normalizedSoftwareRelationshipSchema, t as liftFileLenses, u as anchorPins, w as resourceReferences, x as pinsSchema } from "./stored-document-migration-CChxtFAy.js";
6
5
  import { t as ReviewInputError } from "./input-error-OLgB_h31.js";
7
6
  import { createHash, randomUUID } from "node:crypto";
8
7
  import { z } from "zod";
@@ -124,25 +123,11 @@ function digestBytes(bytes) {
124
123
  return createHash("sha256").update(bytes).digest("hex");
125
124
  }
126
125
  function validateShareSources(snapshot) {
127
- if (!snapshot.pins && readsAtBoardPins(snapshot)) throw new ReviewInputError("Reviews with code references need source pins before sharing.", 409);
128
- }
129
- /** The commits a board's references read at besides its base and head. A
130
- * recipient fetches them too. A shared board names no repository of its
131
- * own, so one stands in for its commit links. */
132
- function referenceCommits(snapshot, repositoryId = boardRepositoryId(snapshot) ?? "shared") {
133
- const own = /* @__PURE__ */ new Set([snapshot.pins?.base, snapshot.pins?.head]);
134
- const commits = /* @__PURE__ */ new Set();
135
- for (const { source } of sourceReferences(snapshot.document, {
136
- tolerant: true,
137
- repositoryId
138
- })) for (const commit of [source.pins?.base, source.pins?.head]) if (commit && !own.has(commit)) commits.add(commit);
139
- return [...commits].sort();
126
+ if (!snapshot.pins && hasCodeReferences(snapshot)) throw new ReviewInputError("Reviews with code references need source pins before sharing.", 409);
140
127
  }
141
128
  /** Freeze one stored version before any asynchronous source reads. */
142
129
  async function exportShare(input) {
143
- const stored = structuredClone(input.store.read(input.reviewId, input.version));
144
- const repositoryId = boardRepositoryId(stored);
145
- const { target, staleSources: _staleSources, sourceUnavailable: _sourceUnavailable, lastEdit: _lastEdit, trashedAt: _trashedAt, personEdit: _personEdit, ...snapshot } = stored;
130
+ const { target, kind: _kind, staleSources: _staleSources, sourceUnavailable: _sourceUnavailable, lastEdit: _lastEdit, trashedAt: _trashedAt, ...snapshot } = structuredClone(input.store.read(input.reviewId, input.version));
146
131
  if (target?.kind === "worktree") throw new ReviewInputError("Pin this review to commits before sharing it.");
147
132
  documentSchema.parse(snapshot.document);
148
133
  checkReferences(snapshot.document);
@@ -161,14 +146,14 @@ async function exportShare(input) {
161
146
  const json = (value) => add(Buffer.from(JSON.stringify(value)));
162
147
  const resources = [];
163
148
  const maps = {};
164
- const sources = [...sourceReferences(snapshot.document, { repositoryId }), ...lensSelections(snapshot.lenses ?? []).flatMap((selection) => sourceAnchors(selection.source).map((source) => ({
149
+ const sources = [...sourceReferences(snapshot.document), ...lensSelections(snapshot.lenses ?? []).flatMap((selection) => sourceAnchors(selection.source).map((source) => ({
165
150
  ...selection,
166
151
  source,
167
152
  peek: false
168
153
  })))];
169
154
  const pins = snapshot.pins;
170
155
  validateShareSources(snapshot);
171
- if ((pins || referenceCommits(stored).length) && !input.repository) throw new ReviewInputError("Shared source pins require a repository.", 409);
156
+ if (Boolean(pins) !== Boolean(input.repository)) throw new ReviewInputError("Shared source pins require a repository.", 409);
172
157
  for (const block of elements(snapshot.document)) {
173
158
  if (block.type !== "markdown") continue;
174
159
  for (const node of markdownNodes(parseMarkdown(block.markdown))) if (node.type === "image") throw new ReviewInputError("Convert Markdown images to managed image blocks before sharing.");
@@ -230,14 +215,6 @@ async function exportShare(input) {
230
215
  }
231
216
  //#endregion
232
217
  //#region src/sharing/repository.ts
233
- /** A full commit id, SHA-1 or SHA-256. */
234
- const COMMIT_ID = /^(?:[a-f0-9]{40}|[a-f0-9]{64})$/;
235
- /** Refuses anything but full commit ids, before any of them reaches git:
236
- * a shared board's commits come from someone else, and one spelled as an
237
- * option or a refspec would make git do something else. */
238
- function assertCommitIds(commits) {
239
- if (!commits.every((commit) => COMMIT_ID.test(commit))) throw new ReviewInputError("The shared whiteboard names a commit that isn't a full commit id.");
240
- }
241
218
  /** Keep credential helpers but prevent the calling shell from redirecting Git's object store. */
242
219
  function sharedGit(cwd, args) {
243
220
  const env = Object.fromEntries(Object.entries(process.env).filter(([key]) => !key.startsWith("GIT_") || [
@@ -253,7 +230,10 @@ function sharedGit(cwd, args) {
253
230
  "core.fsmonitor=false",
254
231
  ...args
255
232
  ], {
256
- env,
233
+ env: {
234
+ ...env,
235
+ GIT_TERMINAL_PROMPT: "0"
236
+ },
257
237
  timeout: 3e5
258
238
  });
259
239
  }
@@ -261,21 +241,9 @@ function fetchError(stderr, publishing) {
261
241
  if (/not our ref|couldn't find remote ref|unadvertised object/i.test(stderr)) return new ReviewInputError(publishing ? "Push the reviewed commits to GitHub before sharing." : "The shared commits are no longer available on GitHub. Ask the sender to restore them, then retry.", 409);
262
242
  return new ReviewInputError("Could not fetch the GitHub repository. Check your connection and Git credentials for this repository, then retry.", 409);
263
243
  }
264
- /** Recipients need complete history; publication only checks that the commits exist.
265
- * `commits` are other commits the board's references read at; a plan has
266
- * only those. */
267
- async function fetchPinnedRepository(root, url, pins, publishing = false, commits = []) {
268
- const named = [...pins ? [{
269
- commit: pins.base,
270
- ref: "base"
271
- }, {
272
- commit: pins.head,
273
- ref: "head"
274
- }] : [], ...commits.map((commit) => ({
275
- commit,
276
- ref: `commits/${commit}`
277
- }))];
278
- if (!named.every(({ commit }) => COMMIT_ID.test(commit))) throw new ReviewInputError("Sharing requires immutable base and head commits.");
244
+ /** Recipients need complete history; publication only checks that the commits exist. */
245
+ async function fetchPinnedRepository(root, url, pins, publishing = false) {
246
+ if (![pins.base, pins.head].every((commit) => /^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(commit))) throw new ReviewInputError("Sharing requires immutable base and head commits.");
279
247
  await mkdir(root, {
280
248
  recursive: true,
281
249
  mode: 448
@@ -296,7 +264,7 @@ async function fetchPinnedRepository(root, url, pins, publishing = false, commit
296
264
  "remote",
297
265
  "add",
298
266
  "origin",
299
- { remote: url }
267
+ url
300
268
  ]);
301
269
  }
302
270
  const refs = publishing ? "refs/heads/review" : "refs/review";
@@ -306,129 +274,26 @@ async function fetchPinnedRepository(root, url, pins, publishing = false, commit
306
274
  "--no-tags",
307
275
  "--force",
308
276
  ...publishing ? ["--depth=1", "--filter=tree:0"] : [],
309
- { remote: publishing ? url : "origin" },
310
- ...named.map(({ commit, ref }) => ({ refspec: {
311
- from: commit,
312
- to: `${refs}/${ref}`
313
- } }))
277
+ publishing ? url : "origin",
278
+ `${pins.base}:${refs}/base`,
279
+ `${pins.head}:${refs}/head`
314
280
  ]);
315
281
  } catch (error) {
316
282
  throw fetchError(error instanceof Error && "stderr" in error ? String(error.stderr) : "", publishing);
317
283
  }
318
- if (!publishing) for (const { commit } of named) await sharedGit(root, [
284
+ if (!publishing) for (const commit of [pins.base, pins.head]) await sharedGit(root, [
319
285
  "cat-file",
320
286
  "-e",
321
- { rev: `${commit}^{commit}` }
287
+ `${commit}^{commit}`
322
288
  ]);
323
289
  }
324
- /** Fetches the commits a shared board's links read at into a checkout of
325
- * its repository, from its origin unless it has them, and keeps each under
326
- * `refs/review/shared/<share>/<commit>`, so `git gc` can't prune one the
327
- * board still quotes. */
328
- async function fetchSharedCommits(root, commits, share) {
329
- assertCommitIds(commits);
330
- const ref = (commit) => `refs/review/shared/${share}/${commit}`;
331
- const missing = [];
332
- for (const commit of commits) try {
333
- await sharedGit(root, [
334
- "cat-file",
335
- "-e",
336
- { rev: `${commit}^{commit}` }
337
- ]);
338
- await sharedGit(root, [
339
- "update-ref",
340
- { ref: ref(commit) },
341
- { commit }
342
- ]);
343
- } catch {
344
- missing.push(commit);
345
- }
346
- if (!missing.length) return;
347
- try {
348
- await sharedGit(root, [
349
- "fetch",
350
- "--no-tags",
351
- "origin",
352
- ...missing.map((commit) => ({ refspec: {
353
- from: commit,
354
- to: ref(commit),
355
- force: true
356
- } }))
357
- ]);
358
- } catch (error) {
359
- throw fetchError(error instanceof Error && "stderr" in error ? String(error.stderr) : "", false);
360
- }
361
- }
362
- /** Drops the refs `fetchSharedCommits` kept for a share, once the share is
363
- * gone, so `git gc` can prune what only it quoted. */
364
- async function forgetSharedCommits(root, share) {
365
- const { stdout } = await sharedGit(root, [
366
- "for-each-ref",
367
- "--format=%(refname)",
368
- { ref: `refs/review/shared/${share}/` }
369
- ]);
370
- for (const ref of stdout.split("\n").filter(Boolean)) await sharedGit(root, [
371
- "update-ref",
372
- "-d",
373
- { ref }
374
- ]);
375
- }
376
- /** A managed clone of a repository's default branch, for a shared board
377
- * with no pins whose repository the receiver has no checkout of. */
378
- async function cloneSharedRepository(root, url) {
379
- await mkdir(root, {
380
- recursive: true,
381
- mode: 448
382
- });
383
- await sharedGit(root, ["init", "--quiet"]);
384
- await sharedGit(root, [
385
- "config",
386
- "core.hooksPath",
387
- "/dev/null"
388
- ]);
389
- await sharedGit(root, [
390
- "config",
391
- "core.fsmonitor",
392
- "false"
393
- ]);
394
- await sharedGit(root, [
395
- "remote",
396
- "add",
397
- "origin",
398
- { remote: url }
399
- ]);
400
- try {
401
- await sharedGit(root, [
402
- "fetch",
403
- "--no-tags",
404
- "origin",
405
- "HEAD"
406
- ]);
407
- } catch (error) {
408
- throw fetchError(error instanceof Error && "stderr" in error ? String(error.stderr) : "", false);
409
- }
410
- await sharedGit(root, [
411
- "checkout",
412
- "--detach",
413
- "FETCH_HEAD"
414
- ]);
415
- }
416
- async function repositoryReady(root, pins, commits = []) {
417
- if (![
418
- pins.base,
419
- pins.head,
420
- ...commits
421
- ].every((commit) => COMMIT_ID.test(commit))) return false;
290
+ async function repositoryReady(root, pins) {
422
291
  try {
423
292
  if ((await sharedGit(root, ["rev-parse", "HEAD"])).stdout.trim() !== pins.head) return false;
424
- for (const commit of [
425
- pins.base,
426
- pins.head,
427
- ...commits
428
- ]) await sharedGit(root, [
293
+ for (const commit of [pins.base, pins.head]) await sharedGit(root, [
429
294
  "cat-file",
430
295
  "-e",
431
- { rev: `${commit}^{commit}` }
296
+ `${commit}^{commit}`
432
297
  ]);
433
298
  return true;
434
299
  } catch {
@@ -448,11 +313,11 @@ async function readShareRepository(root) {
448
313
  }
449
314
  return { cloneUrl };
450
315
  }
451
- async function verifyShareRepository(root, pins, repository, commits = []) {
316
+ async function verifyShareRepository(root, pins, repository) {
452
317
  const { cloneUrl } = repository ?? await readShareRepository(root);
453
318
  const temporary = await mkdtemp(path.join(tmpdir(), "review-share-check-"));
454
319
  try {
455
- await fetchPinnedRepository(temporary, cloneUrl, pins, true, commits);
320
+ await fetchPinnedRepository(temporary, cloneUrl, pins, true);
456
321
  } finally {
457
322
  await rm(temporary, {
458
323
  recursive: true,
@@ -466,11 +331,10 @@ async function verifyShareRepository(root, pins, repository, commits = []) {
466
331
  const sharedSnapshotSchema = z.strictObject({
467
332
  reviewId: z.string().min(1),
468
333
  version: z.number().int().nonnegative(),
469
- /** Empty for a board never named; it reads "Untitled". */
470
- title: z.string(),
334
+ title: z.string().min(1),
471
335
  pins: pinsSchema.extend({
472
- base: z.string().regex(COMMIT_ID),
473
- head: z.string().regex(COMMIT_ID)
336
+ base: z.string().regex(/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/),
337
+ head: z.string().regex(/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/)
474
338
  }).optional(),
475
339
  document: documentSchema,
476
340
  lenses: z.array(lensSchema).optional(),
@@ -490,7 +354,7 @@ const counts = z.strictObject({
490
354
  deletions: count
491
355
  });
492
356
  const mapSchema = z.strictObject({
493
- commit: z.string().regex(COMMIT_ID),
357
+ commit: z.string(),
494
358
  side: z.enum(["base", "head"]),
495
359
  elements: z.array(normalizedSoftwareElementSchema),
496
360
  relationships: z.array(normalizedSoftwareRelationshipSchema),
@@ -523,8 +387,7 @@ function validateShareBundle(bundle) {
523
387
  if (snapshot.reviewId !== manifest.reviewId || snapshot.version !== manifest.version || snapshot.title !== manifest.title) throw new Error("Shared snapshot does not match its manifest.");
524
388
  checkReferences(snapshot.document);
525
389
  validateShareSources(snapshot);
526
- assertCommitIds(referenceCommits(snapshot));
527
- if (snapshot.pins && !manifest.repository) throw new Error("Shared source pins require a repository.");
390
+ if (Boolean(snapshot.pins) !== Boolean(manifest.repository)) throw new Error("Shared source pins require a repository.");
528
391
  const presentation = sharePresentationSchema.parse(json(manifest.presentation));
529
392
  if (!snapshot.pins && Object.keys(presentation.maps).length) throw new Error("Shared maps require source pins.");
530
393
  const traces = /* @__PURE__ */ new Map();
@@ -572,7 +435,6 @@ function sharedReviewId(origin, shareId) {
572
435
  var SharedReviewStore = class {
573
436
  root;
574
437
  fetchRepository;
575
- cloneRepository;
576
438
  loaded = /* @__PURE__ */ new Map();
577
439
  validated = /* @__PURE__ */ new Map();
578
440
  attention = /* @__PURE__ */ new Map();
@@ -594,10 +456,9 @@ var SharedReviewStore = class {
594
456
  repositories = /* @__PURE__ */ new Map();
595
457
  jobs = /* @__PURE__ */ new Map();
596
458
  states = /* @__PURE__ */ new Map();
597
- constructor(root, fetchRepository = fetchPinnedRepository, cloneRepository = cloneSharedRepository) {
459
+ constructor(root, fetchRepository = fetchPinnedRepository) {
598
460
  this.root = root;
599
461
  this.fetchRepository = fetchRepository;
600
- this.cloneRepository = cloneRepository;
601
462
  this.purgeTimer = setInterval(() => {
602
463
  this.purgeExpired().catch((error) => console.error("Could not purge expired shared whiteboards:", error));
603
464
  }, 6e4);
@@ -657,15 +518,14 @@ var SharedReviewStore = class {
657
518
  const saved = this.validated.get(id);
658
519
  if (!saved) throw new ReviewInputError("Shared review is not available.", 404);
659
520
  if (!saved.snapshot.pins) {
660
- await this.prepareUnpinned(id, saved.manifest.repository?.cloneUrl);
521
+ this.setStatus(id, "ready");
661
522
  return;
662
523
  }
663
524
  if (!local) throw new ReviewInputError("Repository service is unavailable.", 409);
664
525
  const root = this.repositoryRoot(id);
665
- const commits = referenceCommits(saved.snapshot);
666
526
  try {
667
527
  this.setStatus(id, "fetching");
668
- if (!await repositoryReady(root, saved.snapshot.pins, commits)) {
528
+ if (!await repositoryReady(root, saved.snapshot.pins)) {
669
529
  const prior = this.repositories.get(id);
670
530
  await local.data.workspaces.remove(id);
671
531
  if (prior) await local.data.forgetRepository(prior);
@@ -673,11 +533,11 @@ var SharedReviewStore = class {
673
533
  recursive: true,
674
534
  force: true
675
535
  });
676
- await this.fetchRepository(root, saved.manifest.repository.cloneUrl, saved.snapshot.pins, false, commits);
536
+ await this.fetchRepository(root, saved.manifest.repository.cloneUrl, saved.snapshot.pins);
677
537
  await sharedGit(root, [
678
538
  "checkout",
679
539
  "--detach",
680
- { commit: saved.snapshot.pins.head }
540
+ saved.snapshot.pins.head
681
541
  ]);
682
542
  }
683
543
  const repository = await local.data.register(root);
@@ -692,7 +552,12 @@ var SharedReviewStore = class {
692
552
  };
693
553
  this.setStatus(id, "validating");
694
554
  await local.data.validatePins(pins);
695
- await this.validateReferences(saved, repository.id, pins);
555
+ const references = sourceReferences(saved.snapshot.document).map((item) => item.source);
556
+ for (const map of Object.values(saved.presentation.maps)) for (const element of map.elements) for (const range of element.sourceRanges ?? []) references.push({
557
+ ...range,
558
+ side: map.side
559
+ });
560
+ await local.data.validateSources(pins, references);
696
561
  await local.data.workspaces.open(id, pins);
697
562
  if (local.data.workspaces.list(id).some((workspace) => !workspace.rootPath)) throw new ReviewInputError("Could not prepare the pinned checkout. Retry opening the share.", 409);
698
563
  await writeFile(path.join(this.root, id, "repository.json"), JSON.stringify({
@@ -706,71 +571,9 @@ var SharedReviewStore = class {
706
571
  throw new ReviewInputError(message, 409);
707
572
  }
708
573
  }
709
- /** Reads each of a shared board's references at its own commits, in the
710
- * checkout of its repository. */
711
- async validateReferences(saved, repositoryId, pins) {
712
- const references = /* @__PURE__ */ new Map();
713
- const add = (at, range) => {
714
- const key = JSON.stringify([at.base, at.head]);
715
- const group = references.get(key) ?? {
716
- pins: at,
717
- ranges: []
718
- };
719
- group.ranges.push(range);
720
- references.set(key, group);
721
- };
722
- for (const { source } of sourceReferences(saved.snapshot.document, { repositoryId })) add({
723
- ...anchorPins(source, pins),
724
- repositoryId
725
- }, source);
726
- if (pins) for (const map of Object.values(saved.presentation.maps)) for (const element of map.elements) for (const range of element.sourceRanges ?? []) add(pins, {
727
- ...range,
728
- side: map.side
729
- });
730
- for (const group of references.values()) await this.local.data.validateSources(group.pins, group.ranges);
731
- }
732
- /** Files an unpinned board under a local checkout of its repository,
733
- * else a managed clone. */
734
- async prepareUnpinned(id, cloneUrl) {
735
- const local = this.local;
736
- const saved = this.validated.get(id);
737
- if (!cloneUrl || !local) {
738
- this.setStatus(id, "ready");
739
- return;
740
- }
741
- const root = this.repositoryRoot(id);
742
- try {
743
- this.setStatus(id, "fetching");
744
- const managed = path.join(await realpath(this.root), ".repositories");
745
- let repositoryId = local.store.checkoutsOf(cloneUrl).find((checkout) => !local.store.repositoryPath(checkout).startsWith(managed));
746
- if (!repositoryId) {
747
- if (!existsSync(path.join(root, ".git"))) {
748
- await rm(root, {
749
- recursive: true,
750
- force: true
751
- });
752
- await this.cloneRepository(root, cloneUrl);
753
- }
754
- repositoryId = (await local.data.register(root)).id;
755
- }
756
- await fetchSharedCommits(local.store.repositoryPath(repositoryId), referenceCommits(saved.snapshot, repositoryId), id);
757
- this.setStatus(id, "validating");
758
- await this.validateReferences(saved, repositoryId);
759
- this.repositories.set(id, repositoryId);
760
- await writeFile(path.join(this.root, id, "repository.json"), JSON.stringify({
761
- repositoryId,
762
- ready: true
763
- }), { mode: 384 });
764
- this.setStatus(id, "ready");
765
- } catch (error) {
766
- const message = error instanceof ReviewInputError ? error.message : "Could not prepare the shared repository. Check Git credentials and retry.";
767
- this.setStatus(id, "error", message);
768
- throw new ReviewInputError(message, 409);
769
- }
770
- }
771
574
  async assertReady(id) {
772
575
  const saved = this.validated.get(id);
773
- if (!saved || saved.snapshot.pins && !await repositoryReady(this.repositoryRoot(id), saved.snapshot.pins, referenceCommits(saved.snapshot))) {
576
+ if (!saved || saved.snapshot.pins && !await repositoryReady(this.repositoryRoot(id), saved.snapshot.pins)) {
774
577
  this.setStatus(id, "error", "The managed checkout is missing. Reopen the share link to fetch it again.");
775
578
  throw new ReviewInputError(this.status(id).error, 409);
776
579
  }
@@ -809,15 +612,13 @@ var SharedReviewStore = class {
809
612
  repositoryId: z.string(),
810
613
  ready: z.boolean()
811
614
  }).parse(JSON.parse(await readFile(path.join(this.root, id, "repository.json"), "utf8")));
812
- if (this.local?.store.repositoryPath(metadata.repositoryId) === path.join(await realpath(this.root), ".repositories", id) || !validated.snapshot.pins && this.local?.store.repositories().some((repository) => repository.id === metadata.repositoryId)) {
615
+ if (this.local?.store.repositoryPath(metadata.repositoryId) === path.join(await realpath(this.root), ".repositories", id)) {
813
616
  this.repositories.set(id, metadata.repositoryId);
814
617
  prepared = metadata.ready;
815
618
  }
816
619
  } catch {}
817
- if (!validated.snapshot.pins) {
818
- if (this.repositories.has(id) || !validated.manifest.repository) this.setStatus(id, "ready");
819
- else this.prepare(id).catch(() => {});
820
- } else if (prepared && this.local && await repositoryReady(this.repositoryRoot(id), validated.snapshot.pins, referenceCommits(validated.snapshot))) {
620
+ if (!validated.snapshot.pins) this.setStatus(id, "ready");
621
+ else if (prepared && this.local && await repositoryReady(this.repositoryRoot(id), validated.snapshot.pins)) {
821
622
  const repository = await this.local.data.register(this.repositoryRoot(id));
822
623
  this.repositories.set(id, repository.id);
823
624
  this.setStatus(id, "ready");
@@ -868,9 +669,6 @@ var SharedReviewStore = class {
868
669
  kind: "commits",
869
670
  ...validated.snapshot.pins,
870
671
  repositoryId
871
- } : repositoryId ? {
872
- kind: "project",
873
- repositoryId
874
672
  } : void 0,
875
673
  shared: {
876
674
  ...bundle.attribution,
@@ -882,12 +680,10 @@ var SharedReviewStore = class {
882
680
  list() {
883
681
  const reviews = this.loaded.keys().filter((id) => this.status(id).stage === "ready" && (!this.validated.get(id)?.snapshot.pins || existsSync(path.join(this.repositoryRoot(id), ".git")))).map((id) => {
884
682
  const { document: _document, ...snapshot } = this.get(id).snapshot;
885
- const project = snapshot.target ? this.local?.store.checkoutProject(snapshot.target.repositoryId) : void 0;
886
683
  return {
887
684
  ...snapshot,
888
685
  firstCreatedAt: snapshot.version === 0 ? snapshot.createdAt : void 0,
889
686
  repositoryName: "Shared review",
890
- ...project && { project },
891
687
  viewedAt: this.attention.get(id)?.viewedAt ?? null,
892
688
  trashedAt: this.attention.get(id)?.trashedAt ?? null
893
689
  };
@@ -909,10 +705,8 @@ var SharedReviewStore = class {
909
705
  await this.local?.data.workspaces.remove(id);
910
706
  const repositoryId = this.repositories.get(id);
911
707
  if (repositoryId) {
912
- const checkout = this.local?.store.repositoryPath(repositoryId);
913
- if (checkout) await forgetSharedCommits(checkout, id).catch((error) => console.error(`Could not drop the refs kept for share ${id}:`, error));
914
708
  await this.local?.data.forgetRepository(repositoryId);
915
- await this.local?.store.unregisterRepository(repositoryId);
709
+ this.local?.store.unregisterRepository(repositoryId);
916
710
  }
917
711
  await rm(this.repositoryRoot(id), {
918
712
  recursive: true,
@@ -1205,4 +999,4 @@ var ShareClient = class {
1205
999
  }
1206
1000
  };
1207
1001
  //#endregion
1208
- export { sharedReviewId as a, verifyShareRepository as c, validateShareSources as d, StreamLimitError as f, shareIdSchema as h, SharedReviewStore as i, exportShare as l, parseShareLink as m, ShareClient as n, validateShareBundle as o, readBoundedStream as p, SharePreflightError as r, readShareRepository as s, ShareAuthError as t, referenceCommits as u };
1002
+ export { sharedReviewId as a, verifyShareRepository as c, StreamLimitError as d, readBoundedStream as f, SharedReviewStore as i, exportShare as l, shareIdSchema as m, ShareClient as n, validateShareBundle as o, parseShareLink as p, SharePreflightError as r, readShareRepository as s, ShareAuthError as t, validateShareSources as u };
@@ -1,7 +1,6 @@
1
- import "./review-home-paths-D8AoCdd2.js";
2
- import { N as devReviewHome } from "./s3-config-CjcLyFV5.js";
3
- import { n as askAgentIds } from "./thread-state-Do5LX10I.js";
4
- import { t as ASK_THREAD_ENV } from "./request-origin-B9qCPiVB.js";
1
+ import "./review-home-paths-j2BRAaNv.js";
2
+ import { N as devReviewHome } from "./s3-config-BTO12tCC.js";
3
+ import { n as askAgentIds } from "./thread-state-5pYr6_zM.js";
5
4
  import { createRequire } from "node:module";
6
5
  import { constants } from "node:fs";
7
6
  import { access, chmod, mkdir, readFile, rename, stat, writeFile } from "node:fs/promises";
@@ -278,7 +277,7 @@ async function detectAskAgents(env = process.env) {
278
277
  }
279
278
  /** Runs an adapter with this server's runtime, Desktop's being Electron, or
280
279
  * the user's CLI itself. */
281
- const launchAskAgent = async (agent, cwd, { permissions = "read-only", mcpServers = [], env: base = process.env, threadId } = {}) => {
280
+ const launchAskAgent = async (agent, cwd, { permissions = "read-only", mcpServers = [], env: base = process.env } = {}) => {
282
281
  const spec = askAgents[agent];
283
282
  const executable = await findAgent(spec, base);
284
283
  if (!executable) throw new Error(`${spec.name} is not installed.`);
@@ -286,7 +285,6 @@ const launchAskAgent = async (agent, cwd, { permissions = "read-only", mcpServer
286
285
  ...base,
287
286
  ...askAgentSettings(agent, permissions).env
288
287
  };
289
- if (threadId) env[ASK_THREAD_ENV] = threadId;
290
288
  delete env.CLAUDECODE;
291
289
  delete env.CLAUDE_CODE_ENTRYPOINT;
292
290
  const { launch } = spec;
@@ -1,2 +1,2 @@
1
- import { i as withHeadlessServerLock, n as runHeadlessServer, r as takeOverServerHome, t as HeadlessServerBusyError } from "./headless-host-XhL1X4vX.js";
1
+ import { i as withHeadlessServerLock, n as runHeadlessServer, r as takeOverServerHome, t as HeadlessServerBusyError } from "./headless-host-Cog6SpS9.js";
2
2
  export { HeadlessServerBusyError, runHeadlessServer, takeOverServerHome, withHeadlessServerLock };