@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.
- package/dist/{account-alias-B5-HYi1D.js → account-alias-CprZojXd.js} +8 -13
- package/dist/agent-cli-C6SPSII0.js +2 -0
- package/dist/{agent-cli-CohHf6Ua.js → agent-cli-CThN7Q59.js} +10 -15
- package/dist/{agent-client-Dtc-Kn_w.js → agent-client-BOOi7EUR.js} +3 -13
- package/dist/{authoring-tools-B7KU04f7.js → authoring-tools-BNwuMnz6.js} +27 -34
- package/dist/{background-server-C03RKxKS.js → background-server-CkvxA-6O.js} +5 -5
- package/dist/{background-server-CB9C4uoc.js → background-server-DLSDogkI.js} +1 -1
- package/dist/build-info.json +1 -1
- package/dist/{cli-CJaEb7zC.js → cli-R4yfa5DT.js} +1 -1
- package/dist/{cli-runner-DGDIqh3V.js → cli-runner-Cuc9FSzu.js} +26 -26
- package/dist/cli.js +3 -4
- package/dist/{client-lKVF_Elo.js → client-BN_FDxFr.js} +47 -253
- package/dist/{fuzzy-match-BmVJJm9I.js → fuzzy-match-BO9bK37N.js} +4 -6
- package/dist/{headless-host-DRtjf9WA.js → headless-host-CVBOQyRS.js} +1 -1
- package/dist/{headless-host-XhL1X4vX.js → headless-host-Cog6SpS9.js} +140 -513
- package/dist/{local-data-Cpl4ENbJ.js → local-data-D_9tvdsp.js} +323 -2419
- package/dist/{mcp-ovmiUE_x.js → mcp-D1hziANa.js} +9 -5
- package/dist/{package-paths-BWxO-UEL.js → package-paths-C--__jEv.js} +1 -1
- package/dist/profile-CYPmvBoA.js +2 -0
- package/dist/{profile-BadSkCkI.js → profile-DokFw782.js} +8 -20
- package/dist/{remote-attach-Dd-YobM6.js → remote-attach-CEJ-kvDY.js} +4 -4
- package/dist/{remote-extensions-CNXwqK0D.js → remote-extensions-Blcjr9Ze.js} +3 -3
- package/dist/{remote-extensions-VP-kfq0C.js → remote-extensions-GN8Gf_qG.js} +1 -1
- package/dist/{remote-language-server-BXk87KCr.js → remote-language-server-BTKBQ7x4.js} +5 -5
- package/dist/{remote-uninstall-DuOzsvaD.js → remote-uninstall-DW7Gdryh.js} +6 -6
- package/dist/{request-origin-B9qCPiVB.js → request-origin-Zcn_CjX4.js} +12 -45
- package/dist/{review-app-launcher-C7el2Uoy.js → review-app-launcher-CkwLclzR.js} +2 -2
- package/dist/{review-home-paths-D8AoCdd2.js → review-home-paths-j2BRAaNv.js} +17 -19
- package/dist/{review-telemetry-BsoRMC2w.js → review-telemetry-BLNwYnLV.js} +5 -5
- package/dist/runtime-CKiWhGrf.js +52 -0
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.js +1 -1
- package/dist/{s3-CsG2EWED.js → s3-DtJFWC0G.js} +1 -1
- package/dist/{s3-config-CjcLyFV5.js → s3-config-BTO12tCC.js} +2 -4
- package/dist/{s3-config-zz4GWh2T.js → s3-config-CSy3fx8H.js} +1 -1
- package/dist/server/desktop-host.js +76 -29
- package/dist/{server-discovery-CKjw3-6h.js → server-discovery-Bey8IqXH.js} +3 -3
- package/dist/sharing/index.d.ts +70 -484
- package/dist/sharing/index.js +1 -1
- package/dist/{src-WPaQn75m.js → src-BMPuxWv4.js} +73 -208
- package/dist/{src-BiWNbcF_.js → src-DsM3jO8G.js} +12 -89
- package/dist/{stored-document-migration-dFbewRTG.js → stored-document-migration-CChxtFAy.js} +269 -270
- package/dist/{thread-state-Do5LX10I.js → thread-state-5pYr6_zM.js} +2 -7
- package/dist/{tool-failure-DvI-gys2.js → tool-failure-C9MpbXJJ.js} +3 -10
- package/instructions/authoring.md +2 -3
- package/instructions/scratchpad.md +23 -0
- package/package.json +4 -4
- package/src/ask/agents.ts +1 -13
- package/src/ask/checkout-files.ts +5 -2
- package/src/ask/thread-state.ts +0 -4
- package/src/ask/thread.ts +0 -16
- package/src/ask/threads.ts +3 -24
- package/src/cli-install.ts +2 -13
- package/src/cli-runner.ts +1 -4
- package/src/cli.ts +1 -4
- package/src/diff-selection-migration.ts +34 -48
- package/src/lens-selection.ts +2 -38
- package/src/review-api/README.md +13 -52
- package/src/review-api/activity.ts +4 -1
- package/src/review-api/agent-cli.ts +1 -9
- package/src/review-api/anchor-quotes.ts +7 -14
- package/src/review-api/ask-history.ts +51 -137
- package/src/review-api/authoring-tools.ts +30 -45
- package/src/review-api/blocks/definition.ts +1 -1
- package/src/review-api/blocks/markdown.ts +2 -2
- package/src/review-api/document-headings.ts +27 -58
- package/src/review-api/document-text.ts +2 -31
- package/src/review-api/document.ts +34 -281
- package/src/review-api/github-provider.ts +13 -51
- package/src/review-api/http.ts +123 -702
- package/src/review-api/instructions.ts +19 -0
- package/src/review-api/local-data.ts +46 -310
- package/src/review-api/mcp.ts +11 -3
- package/src/review-api/onboarding.ts +1 -1
- package/src/review-api/profile.ts +6 -37
- package/src/review-api/public-tools.ts +2 -24
- package/src/review-api/pull-request.ts +49 -82
- package/src/review-api/request-origin.ts +0 -10
- package/src/review-api/review-progress.ts +27 -61
- package/src/review-api/store-schema.ts +29 -38
- package/src/review-api/store.ts +478 -2142
- package/src/review-api/worktree-events.ts +5 -3
- package/src/review-api/worktree-source.ts +7 -3
- package/src/review-api/worktree-structural.integration.ts +0 -72
- package/src/review-preferences.ts +88 -0
- package/src/review-stack.ts +23 -15
- package/src/runtime.ts +30 -4
- package/src/server/desktop-host.ts +1 -6
- package/src/server/desktop-server.ts +31 -1
- package/src/server/headless-host.ts +2 -0
- package/src/server/hono-http.ts +1 -2
- package/src/server/legacy-tutorial-cleanup.ts +3 -2
- package/src/server/review-gateway-list.ts +5 -3
- package/src/server/review-gateway-memory.ts +1 -1
- package/src/server/review-lifecycle-telemetry.ts +2 -2
- package/src/server/review-server-core.ts +5 -1
- package/src/server/structural-comparisons.ts +0 -47
- package/src/sharing/export.ts +7 -36
- package/src/sharing/host.ts +14 -34
- package/src/sharing/import.ts +24 -156
- package/src/sharing/repository.ts +20 -128
- package/src/startup-trace.ts +3 -3
- package/src/stored-document-migration.ts +19 -110
- package/src/ui-telemetry-events.ts +11 -33
- package/dist/agent-cli-_YyMIMRY.js +0 -2
- package/dist/lens-selection-CyJapcsl.js +0 -214
- package/dist/profile-DJvkBJNQ.js +0 -2
- package/dist/runtime-Bj2tD33R.js +0 -27
- package/src/heading-anchors.ts +0 -42
- package/src/review-api/board-order.ts +0 -144
- package/src/review-api/checkout-groups.ts +0 -560
- package/src/review-api/foreign-references.ts +0 -328
- package/src/review-api/link-preview.ts +0 -113
- package/src/review-api/scratchpad-plan-upgrade.ts +0 -250
- package/src/review-api/store-migrations.ts +0 -357
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { f as gitAt } from "./src-
|
|
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-
|
|
4
|
-
import {
|
|
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 &&
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
266
|
-
|
|
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
|
-
|
|
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
|
-
|
|
310
|
-
|
|
311
|
-
|
|
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
|
|
284
|
+
if (!publishing) for (const commit of [pins.base, pins.head]) await sharedGit(root, [
|
|
319
285
|
"cat-file",
|
|
320
286
|
"-e",
|
|
321
|
-
|
|
287
|
+
`${commit}^{commit}`
|
|
322
288
|
]);
|
|
323
289
|
}
|
|
324
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
470
|
-
title: z.string(),
|
|
334
|
+
title: z.string().min(1),
|
|
471
335
|
pins: pinsSchema.extend({
|
|
472
|
-
base: z.string().regex(
|
|
473
|
-
head: z.string().regex(
|
|
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()
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
536
|
+
await this.fetchRepository(root, saved.manifest.repository.cloneUrl, saved.snapshot.pins);
|
|
677
537
|
await sharedGit(root, [
|
|
678
538
|
"checkout",
|
|
679
539
|
"--detach",
|
|
680
|
-
|
|
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
|
-
|
|
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
|
|
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)
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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-
|
|
2
|
-
import { N as devReviewHome } from "./s3-config-
|
|
3
|
-
import { n as askAgentIds } from "./thread-state-
|
|
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
|
|
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-
|
|
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 };
|