@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.
- package/dist/{account-alias-2yTAxoBx.js → account-alias-BPlPnzQM.js} +7 -7
- package/dist/{agent-cli-CHNDd4Ga.js → agent-cli-BbCf9uid.js} +11 -11
- package/dist/agent-cli-ipN_JmzG.js +2 -0
- package/dist/{agent-client-Dc0vHFJt.js → agent-client-DfpM8F5N.js} +3 -3
- package/dist/{authoring-tools-D8EkIDjm.js → authoring-tools-bm39DRoV.js} +23 -10
- package/dist/{background-server-DyWnPJyZ.js → background-server--0EeCCeV.js} +1 -1
- package/dist/{background-server-DHWHzpo5.js → background-server-B--5p72o.js} +6 -6
- package/dist/build-info.json +1 -1
- package/dist/{cli-qZomwJmK.js → cli-DBTQIroM.js} +2 -2
- package/dist/{cli-runner-DFBaVGij.js → cli-runner-CRFCdb7G.js} +25 -25
- package/dist/cli.js +3 -3
- package/dist/{fuzzy-match-CfSxqzBF.js → fuzzy-match-l3mJZ1Ge.js} +5 -5
- package/dist/{headless-host-dwlqhqMY.js → headless-host-5ei3nHS8.js} +1 -1
- package/dist/{headless-host-DJhcab6r.js → headless-host-BkJ9OUQY.js} +131 -299
- package/dist/{client-p9WB8Sj0.js → import-Bwvf9Wos.js} +505 -390
- package/dist/{lens-selection-9byzEgvU.js → lens-selection-EuZdag4Q.js} +1 -1
- package/dist/{local-data-DHedfhxw.js → local-data-BCSeTyic.js} +98 -154
- package/dist/{mcp-Br-r_wwR.js → mcp-_Xg1gQuA.js} +17 -8
- package/dist/{package-paths-BeYHYjeR.js → package-paths-Bg731FHS.js} +2 -2
- package/dist/profile-C8zL4u3L.js +2 -0
- package/dist/{profile-D9wdlPgw.js → profile-xzrUFgbT.js} +4 -4
- package/dist/{remote-attach-DSGpTOJ4.js → remote-attach-DF25Epoa.js} +4 -4
- package/dist/{remote-extensions-WtJO7pkb.js → remote-extensions-BJamgsCe.js} +1 -1
- package/dist/{remote-extensions-CsI_BJ_f.js → remote-extensions-CeywZL-Z.js} +4 -4
- package/dist/{remote-language-server-Dx13Mg2m.js → remote-language-server-CH8sG_CU.js} +6 -6
- package/dist/{remote-uninstall-Dp2o3qz0.js → remote-uninstall-Cq-lkBY7.js} +7 -7
- package/dist/{request-origin-CNSLVn7x.js → request-origin-CargJFvH.js} +14 -3
- package/dist/{review-app-launcher-BZAnR8Vp.js → review-app-launcher-D8ApNDUV.js} +3 -3
- package/dist/{review-home-paths-CG-sb9Cw.js → review-home-paths-DcB4xLD-.js} +2 -2
- package/dist/{review-telemetry-BM-_KdLi.js → review-telemetry-BW7gJrSo.js} +7 -7
- package/dist/{runtime-C6_1K-3Z.js → runtime-DY6Ctyog.js} +1 -1
- package/dist/runtime.js +1 -1
- package/dist/{s3-CsG2EWED.js → s3-BIWv4h1J.js} +2 -2
- package/dist/{s3-config-zz4GWh2T.js → s3-config-Du3RBIvv.js} +1 -1
- package/dist/server/desktop-host.js +51 -17
- package/dist/{server-discovery-DKLIOgg3.js → server-discovery-aHK_1r3U.js} +5 -5
- package/dist/sharing/index.d.ts +209 -98
- package/dist/sharing/index.js +1 -1
- package/dist/{src-DYHVzX3b.js → src-DEOc8bvC.js} +63 -2
- package/dist/{src-Z1x4-Qmb.js → src-DjRaCctk.js} +6 -6
- package/dist/{stored-document-migration-DEt8iwem.js → stored-document-migration-CwmTwTb8.js} +139 -13
- package/dist/{thread-state-CO97FUqK.js → thread-state-CbLB0jUA.js} +1 -1
- package/dist/{tool-failure-C1L1vJyz.js → tool-failure-DZaQzi4f.js} +2 -2
- package/instructions/animation.md +345 -0
- package/instructions/authoring.md +2 -2
- package/package.json +6 -6
- package/src/fixtures/blocks/animation.json +19 -0
- package/src/review-api/authoring-tools.ts +17 -6
- package/src/review-api/blocks/animation.ts +98 -0
- package/src/review-api/blocks/index.ts +3 -0
- package/src/review-api/blocks/sequence.ts +3 -1
- package/src/review-api/comparison-coverage.ts +120 -89
- package/src/review-api/component-reference.ts +16 -0
- package/src/review-api/document-text.ts +11 -0
- package/src/review-api/document.ts +26 -5
- package/src/review-api/http.ts +31 -2
- package/src/review-api/instructions.ts +11 -2
- package/src/review-api/local-data.ts +21 -4
- package/src/review-api/mcp.ts +22 -14
- package/src/review-api/onboarding.ts +100 -26
- package/src/review-preferences.ts +43 -0
- package/src/server/desktop-server.ts +24 -0
- package/src/server/json-review-reporting.ts +1 -1
- package/src/server/review-server-core.ts +2 -0
- package/src/server/structural-comparisons.ts +5 -11
- package/src/server/structural-diff.ts +8 -2
- package/src/sharing/cli.ts +1 -1
- package/src/sharing/client.ts +54 -222
- package/src/sharing/export.ts +172 -114
- package/src/sharing/host.ts +32 -36
- package/src/sharing/import.ts +93 -147
- package/src/sharing/index.ts +1 -6
- package/src/sharing/routes.ts +18 -17
- package/src/ui-telemetry-events.ts +11 -0
- package/dist/agent-cli-Cn4-16XA.js +0 -2
- package/dist/profile-BopGMZUh.js +0 -2
- package/dist/{s3-config-CjcLyFV5.js → s3-config-D7Yt0VhS.js} +1 -1
- package/dist/{src-X9ZebeOD.js → src-DXnn7RrI.js} +1 -1
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import { b as resolveRepoContext, d as git, r as defaultBranch, w as runVcs } from "./src-
|
|
1
|
+
import { b as resolveRepoContext, d as git, r as defaultBranch, w as runVcs } from "./src-DXnn7RrI.js";
|
|
2
2
|
import { c as jsonString, m as isStringValue, n as isJsonObject, p as isObjectValue, u as parseJsonText } from "./src-X9phtB2j.js";
|
|
3
|
-
import { a as
|
|
4
|
-
import { d as
|
|
5
|
-
import {
|
|
6
|
-
import { $ as runStoreLogin, M as selectTraceStorage, N as TraceStorageDeniedError, Q as readStoreAuth, X as DEFAULT_STORE_ORIGIN, Z as clearStoreAuth, b as listReviewTraceSessions, j as resolveTraceStorage, k as isTraceStorageConfigured, q as shellQuote, v as traceMachineEnabled, x as loadReviewAgentTrace } from "./src-
|
|
7
|
-
import { _ as scopedCoverage,
|
|
8
|
-
import {
|
|
3
|
+
import { _ as readBoundedStream, a as verifyShareRepository, c as exportShare, d as legacyModeSchema, f as lensReport, g as StreamLimitError, h as uncategorizedReport, i as readShareRepository, l as referenceCommits, m as reviewProgress, n as sharedReviewId, o as ShareAuthError, p as progressUpdateSchema, s as ShareClient, u as validateShareSources, v as parseShareLink, y as shareIdSchema } from "./import-Bwvf9Wos.js";
|
|
4
|
+
import { d as invalidateStructuralComparisons, f as diffrExecutable, i as inspectSnapshot, m as readGitHubPullRequests, p as diffrMissingError, r as commandSchema } from "./local-data-BCSeTyic.js";
|
|
5
|
+
import { F as decodeStructuralDiffEvent, N as reviewDiffrSummarizerInputSchema, O as ReviewFeedbackContactSchema, a as parseReviewVerbRequest, c as boardIconKind, i as parseReviewDesktopVerbResult, j as ReviewOnboardingRunRequestSchema, k as ReviewFeedbackSchema, l as boardTitle, m as REVIEW_CLIENT_REMOTE, p as REVIEW_CLIENT_HEADER, y as REVIEW_HOST_HEADER } from "./src-DEOc8bvC.js";
|
|
6
|
+
import { $ as runStoreLogin, M as selectTraceStorage, N as TraceStorageDeniedError, Q as readStoreAuth, X as DEFAULT_STORE_ORIGIN, Z as clearStoreAuth, b as listReviewTraceSessions, j as resolveTraceStorage, k as isTraceStorageConfigured, q as shellQuote, v as traceMachineEnabled, x as loadReviewAgentTrace } from "./src-DjRaCctk.js";
|
|
7
|
+
import { _ as scopedCoverage, s as formatAnchor, u as selectionKey } from "./lens-selection-EuZdag4Q.js";
|
|
8
|
+
import { N as elements, O as boardLinks, Q as stepSources, f as sourceBranchName, k as boardRepositoryId, l as pullRequestKey, p as pullRequestProvider, q as selectionReferences, w as anchorPins } from "./stored-document-migration-CwmTwTb8.js";
|
|
9
9
|
import { t as ReviewInputError } from "./input-error-OLgB_h31.js";
|
|
10
|
-
import { A as processStartIdentity, L as writePrivateJsonAtomic, N as devReviewHome, h as TraceConfigurationError, i as isS3MockMode, j as withFileLock } from "./s3-config-
|
|
10
|
+
import { A as processStartIdentity, L as writePrivateJsonAtomic, N as devReviewHome, h as TraceConfigurationError, i as isS3MockMode, j as withFileLock } from "./s3-config-D7Yt0VhS.js";
|
|
11
11
|
import { t as errorMessage } from "./error-message-OtiDonty.js";
|
|
12
|
-
import { i as readReviewPackageVersion, n as readBuildCommit, t as findReviewPackageRoot } from "./package-paths-
|
|
13
|
-
import "./review-home-paths-
|
|
14
|
-
import { _ as reviewInstanceIdentity, n as desktopOwnsHome, o as reviewServerDiscoveryPath, p as desktopUsesHome, r as headlessServerLockPath, t as DESKTOP_TAKEOVER_SIGNAL } from "./server-discovery-
|
|
15
|
-
import { c as askPicksSchema, d as selectionMarkdown, l as askQuestionSchema, n as askAgentIds, r as askChoiceKinds, s as askPermissionsSchema, t as applyAskChange, u as AgentSelectionSchema } from "./thread-state-
|
|
16
|
-
import { t as openReviewProfile } from "./profile-
|
|
17
|
-
import { c as REVIEW_APP_SESSION_ID_HEADER, d as sanitizeUiTelemetryEvent, f as cleanTelemetryText, o as reviewRequestOrigin, r as REVIEW_PERSON_HEADER, s as BUNDLE_FRAME_PATTERN, t as ASK_THREAD_ENV, u as isReportableCleanedMessage } from "./request-origin-
|
|
18
|
-
import { a as defaultAskPermissions, i as askAgents, l as launchAskAgent, n as askAgentSettings, o as detectAskAgents, r as askAgentTakesMcp, t as fuzzyRank } from "./fuzzy-match-
|
|
19
|
-
import { a as inspectQuerySchema, i as renderInstructions, o as queryAnchor, r as instructionsQuerySchema, s as readQuerySchemas, t as authoringTools } from "./authoring-tools-
|
|
20
|
-
import { a as headlessServerOwner, c as stopBackgroundServer, o as recordedBackgroundServer } from "./background-server-
|
|
12
|
+
import { i as readReviewPackageVersion, n as readBuildCommit, t as findReviewPackageRoot } from "./package-paths-Bg731FHS.js";
|
|
13
|
+
import "./review-home-paths-DcB4xLD-.js";
|
|
14
|
+
import { _ as reviewInstanceIdentity, n as desktopOwnsHome, o as reviewServerDiscoveryPath, p as desktopUsesHome, r as headlessServerLockPath, t as DESKTOP_TAKEOVER_SIGNAL } from "./server-discovery-aHK_1r3U.js";
|
|
15
|
+
import { c as askPicksSchema, d as selectionMarkdown, l as askQuestionSchema, n as askAgentIds, r as askChoiceKinds, s as askPermissionsSchema, t as applyAskChange, u as AgentSelectionSchema } from "./thread-state-CbLB0jUA.js";
|
|
16
|
+
import { t as openReviewProfile } from "./profile-xzrUFgbT.js";
|
|
17
|
+
import { c as REVIEW_APP_SESSION_ID_HEADER, d as sanitizeUiTelemetryEvent, f as cleanTelemetryText, o as reviewRequestOrigin, r as REVIEW_PERSON_HEADER, s as BUNDLE_FRAME_PATTERN, t as ASK_THREAD_ENV, u as isReportableCleanedMessage } from "./request-origin-CargJFvH.js";
|
|
18
|
+
import { a as defaultAskPermissions, i as askAgents, l as launchAskAgent, n as askAgentSettings, o as detectAskAgents, r as askAgentTakesMcp, t as fuzzyRank } from "./fuzzy-match-l3mJZ1Ge.js";
|
|
19
|
+
import { a as inspectQuerySchema, i as renderInstructions, o as queryAnchor, r as instructionsQuerySchema, s as readQuerySchemas, t as authoringTools } from "./authoring-tools-bm39DRoV.js";
|
|
20
|
+
import { a as headlessServerOwner, c as stopBackgroundServer, o as recordedBackgroundServer } from "./background-server-B--5p72o.js";
|
|
21
21
|
import crypto$1, { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
22
22
|
import { z } from "zod";
|
|
23
|
+
import path, { join } from "node:path";
|
|
23
24
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
24
25
|
import { mkdir, mkdtemp, readFile, realpath, rm, stat, writeFile } from "node:fs/promises";
|
|
25
|
-
import path, { join, posix } from "node:path";
|
|
26
26
|
import { Writable } from "node:stream";
|
|
27
27
|
import os, { tmpdir } from "node:os";
|
|
28
28
|
import { execFile, spawn } from "node:child_process";
|
|
@@ -2200,244 +2200,6 @@ async function captureSanitizedUiTelemetry(telemetry, request, name, properties,
|
|
|
2200
2200
|
}
|
|
2201
2201
|
}
|
|
2202
2202
|
//#endregion
|
|
2203
|
-
//#region src/review-api/file-lenses.ts
|
|
2204
|
-
/** Subtract authored coverage, independently of viewed state. */
|
|
2205
|
-
function uncategorizedSources(files, sources) {
|
|
2206
|
-
return files.flatMap((file) => {
|
|
2207
|
-
const covered = scopedCoverage(file, sources);
|
|
2208
|
-
return coverageSources(file, {
|
|
2209
|
-
base: subtractIntervals(file.changed.base, covered.base),
|
|
2210
|
-
head: subtractIntervals(file.changed.head, covered.head)
|
|
2211
|
-
});
|
|
2212
|
-
});
|
|
2213
|
-
}
|
|
2214
|
-
/** Resolve all targets into one union; a whole-file range subsumes narrower ranges. */
|
|
2215
|
-
function resolveFileLens(lens, files, fileSources, resolve) {
|
|
2216
|
-
const targets = lens.targets;
|
|
2217
|
-
const selected = targets.flatMap((target) => target.kind === "ranges" ? target.sources.flatMap((source) => resolve(anchorSelection(source))) : files.filter((file) => matchesFileLens(target.patterns, file)).flatMap((file) => fileSources.get(file.path) ?? []));
|
|
2218
|
-
const groups = /* @__PURE__ */ new Map();
|
|
2219
|
-
for (const source of selected) {
|
|
2220
|
-
const key = JSON.stringify([source.side, source.file]);
|
|
2221
|
-
const group = groups.get(key) ?? [];
|
|
2222
|
-
group.push(source);
|
|
2223
|
-
groups.set(key, group);
|
|
2224
|
-
}
|
|
2225
|
-
const sources = [...groups.values()].flatMap((group) => unionIntervals(group.map((source) => [source.fromLine - 1, source.toLine])).map(([start, end]) => ({
|
|
2226
|
-
...group[0],
|
|
2227
|
-
fromLine: start + 1,
|
|
2228
|
-
toLine: end
|
|
2229
|
-
})));
|
|
2230
|
-
return {
|
|
2231
|
-
sources,
|
|
2232
|
-
fileCount: new Set(sources.map((source) => files.find((file) => source.file === (source.side === "base" ? file.previousPath ?? file.path : file.path))?.path ?? source.file)).size,
|
|
2233
|
-
wholeFiles: targets.every((target) => target.kind === "files")
|
|
2234
|
-
};
|
|
2235
|
-
}
|
|
2236
|
-
/** Evaluate authored patterns against the changed-file list, never the filesystem. */
|
|
2237
|
-
function matchesFileLens(patterns, file) {
|
|
2238
|
-
return patterns.some((pattern) => {
|
|
2239
|
-
const normalized = pattern.startsWith("./") ? pattern.slice(2) : pattern;
|
|
2240
|
-
return [file.path, file.previousPath].some((path) => path !== void 0 && (path === normalized || posix.matchesGlob(path, normalized)));
|
|
2241
|
-
});
|
|
2242
|
-
}
|
|
2243
|
-
//#endregion
|
|
2244
|
-
//#region src/review-api/review-progress.ts
|
|
2245
|
-
/** Older clients still send `mode`. */
|
|
2246
|
-
const legacyModeSchema = z.unknown().optional();
|
|
2247
|
-
const progressUpdateSchema = z.strictObject({
|
|
2248
|
-
mode: legacyModeSchema,
|
|
2249
|
-
version: z.number().int().nonnegative(),
|
|
2250
|
-
files: z.array(z.strictObject({
|
|
2251
|
-
path: z.string(),
|
|
2252
|
-
fingerprint: z.string().min(1),
|
|
2253
|
-
sources: z.array(fileLineRangeSchema)
|
|
2254
|
-
})).max(1e4),
|
|
2255
|
-
viewed: z.boolean()
|
|
2256
|
-
});
|
|
2257
|
-
/** Coverage survives new pins only when both complete file contents are unchanged. */
|
|
2258
|
-
async function reviewProgress(store, data, snapshot, signal = new AbortController().signal, partial) {
|
|
2259
|
-
const marks = snapshot.shared ? /* @__PURE__ */ new Map() : store.viewedCoverage(snapshot.reviewId);
|
|
2260
|
-
const pins = snapshot.pins ? (await data.resolveSource(snapshot)).pins : void 0;
|
|
2261
|
-
const comparison = pins ? partial ?? await data.coverage(snapshot.reviewId, pins) : {
|
|
2262
|
-
counted: true,
|
|
2263
|
-
files: [],
|
|
2264
|
-
fileSources: /* @__PURE__ */ new Map(),
|
|
2265
|
-
alignments: /* @__PURE__ */ new Map()
|
|
2266
|
-
};
|
|
2267
|
-
const counting = !comparison.counted;
|
|
2268
|
-
signal.throwIfAborted();
|
|
2269
|
-
const documentKey = JSON.stringify(pins);
|
|
2270
|
-
const comparisons = /* @__PURE__ */ new Map();
|
|
2271
|
-
/** The comparison a reference's own pins name, shared across references. */
|
|
2272
|
-
const ownComparison = (own) => {
|
|
2273
|
-
const key = JSON.stringify(own);
|
|
2274
|
-
let loading = comparisons.get(key);
|
|
2275
|
-
if (loading) return loading;
|
|
2276
|
-
if (partial) {
|
|
2277
|
-
const state = data.coverageSnapshot(snapshot.reviewId, own);
|
|
2278
|
-
if (state.pending) return state.comparison.counted ? Promise.resolve(state.comparison) : void 0;
|
|
2279
|
-
}
|
|
2280
|
-
loading = data.coverage(snapshot.reviewId, own);
|
|
2281
|
-
comparisons.set(key, loading);
|
|
2282
|
-
return loading;
|
|
2283
|
-
};
|
|
2284
|
-
const withViewed = (file) => ({
|
|
2285
|
-
...file,
|
|
2286
|
-
viewed: marks.get(file.path)?.fingerprint === file.fingerprint ? marks.get(file.path).coverage : emptyCoverage()
|
|
2287
|
-
});
|
|
2288
|
-
const files = comparison.files.map(withViewed);
|
|
2289
|
-
const referenceFiles = {};
|
|
2290
|
-
const fileSources = new Map(comparison.fileSources);
|
|
2291
|
-
const alignments = new Map(comparison.alignments);
|
|
2292
|
-
const resolvedSelections = {};
|
|
2293
|
-
const unavailableSelections = {};
|
|
2294
|
-
const pendingSources = /* @__PURE__ */ new Set();
|
|
2295
|
-
const resolve = async (source) => {
|
|
2296
|
-
const key = selectionKey(source);
|
|
2297
|
-
if (resolvedSelections[key]) return resolvedSelections[key];
|
|
2298
|
-
const sourcePins = anchorPins(source, pins);
|
|
2299
|
-
const own = JSON.stringify(sourcePins) !== documentKey;
|
|
2300
|
-
let ownFiles = files;
|
|
2301
|
-
let ownAlignments = alignments;
|
|
2302
|
-
if (own) {
|
|
2303
|
-
const loading = ownComparison(sourcePins);
|
|
2304
|
-
if (!loading) {
|
|
2305
|
-
pendingSources.add(key);
|
|
2306
|
-
return [];
|
|
2307
|
-
}
|
|
2308
|
-
const loaded = await loading;
|
|
2309
|
-
ownFiles = loaded.files;
|
|
2310
|
-
ownAlignments = loaded.alignments;
|
|
2311
|
-
}
|
|
2312
|
-
const file = ownFiles.find((file) => source.file === file.path || source.file === file.previousPath);
|
|
2313
|
-
if (own) {
|
|
2314
|
-
const group = referenceFiles[comparisonKey(sourcePins)] ??= {};
|
|
2315
|
-
if (file) group[file.path] ??= withViewed(file);
|
|
2316
|
-
}
|
|
2317
|
-
let rows = file && ownAlignments.get(file.path);
|
|
2318
|
-
if (!file && counting && !own) {
|
|
2319
|
-
pendingSources.add(key);
|
|
2320
|
-
return [];
|
|
2321
|
-
}
|
|
2322
|
-
if (!file) {
|
|
2323
|
-
const [base, head] = await Promise.all(["base", "head"].map((side) => data.file(sourcePins, side, source.file).then((value) => value.text, (error) => {
|
|
2324
|
-
if (error instanceof ReviewInputError && error.status === 404) return null;
|
|
2325
|
-
throw error;
|
|
2326
|
-
})));
|
|
2327
|
-
if (base === null && head === null) throw new SelectionUnavailableError("missing_file", "File is unavailable at these pins.");
|
|
2328
|
-
if (base !== null && head !== null && base !== head) throw new SelectionUnavailableError("no_alignment", "Changed context file has no alignment.");
|
|
2329
|
-
rows = textualRows(source.file, "", base?.split("\n").length ?? 0, head?.split("\n").length ?? 0);
|
|
2330
|
-
}
|
|
2331
|
-
if (!rows) throw new SelectionUnavailableError("no_alignment", "File has no text alignment.");
|
|
2332
|
-
const result = resolveDiffSelection(source, rows, file ?? { path: source.file });
|
|
2333
|
-
resolvedSelections[key] = result;
|
|
2334
|
-
return result;
|
|
2335
|
-
};
|
|
2336
|
-
const resolveAvailable = async (source) => {
|
|
2337
|
-
try {
|
|
2338
|
-
return await resolve(source);
|
|
2339
|
-
} catch (error) {
|
|
2340
|
-
unavailableSelections[selectionKey(source)] = error instanceof SelectionUnavailableError ? error.reason : "other";
|
|
2341
|
-
return [];
|
|
2342
|
-
}
|
|
2343
|
-
};
|
|
2344
|
-
const lenses = await Promise.all((snapshot.lenses ?? []).map(async (authored) => {
|
|
2345
|
-
const lens = {
|
|
2346
|
-
id: authored.id,
|
|
2347
|
-
title: authored.title
|
|
2348
|
-
};
|
|
2349
|
-
try {
|
|
2350
|
-
await Promise.all(lensSelections([authored]).map(({ source }) => resolveAvailable(source)));
|
|
2351
|
-
const resolved = resolveFileLens(authored, files, fileSources, (source) => resolvedSelections[selectionKey(source)] ?? []);
|
|
2352
|
-
return {
|
|
2353
|
-
...lens,
|
|
2354
|
-
...resolved,
|
|
2355
|
-
pending: counting,
|
|
2356
|
-
unavailable: counting || resolved.fileCount ? void 0 : "No files match these targets"
|
|
2357
|
-
};
|
|
2358
|
-
} catch {
|
|
2359
|
-
return {
|
|
2360
|
-
...lens,
|
|
2361
|
-
sources: [],
|
|
2362
|
-
unavailable: "Source links need updating at these pins"
|
|
2363
|
-
};
|
|
2364
|
-
}
|
|
2365
|
-
}));
|
|
2366
|
-
await Promise.all(selectionReferences(snapshot.document, {
|
|
2367
|
-
tolerant: true,
|
|
2368
|
-
repositoryId: boardRepositoryId(snapshot)
|
|
2369
|
-
}).map(async ({ source }) => {
|
|
2370
|
-
try {
|
|
2371
|
-
await resolveAvailable(source);
|
|
2372
|
-
} catch {}
|
|
2373
|
-
}));
|
|
2374
|
-
const uncategorized = counting ? [] : uncategorizedSources(files, lenses.filter((lens) => !lens.unavailable).flatMap((lens) => lens.sources));
|
|
2375
|
-
lenses.push({
|
|
2376
|
-
id: UNCATEGORIZED_LENS_ID,
|
|
2377
|
-
title: "Uncategorized changes",
|
|
2378
|
-
sources: uncategorized,
|
|
2379
|
-
wholeFiles: false,
|
|
2380
|
-
fileCount: new Set(uncategorized.map((source) => files.find((file) => source.file === (source.side === "base" ? file.previousPath ?? file.path : file.path))?.path ?? source.file)).size,
|
|
2381
|
-
pending: counting,
|
|
2382
|
-
unavailable: counting || uncategorized.length ? void 0 : "All changed lines are covered by lenses"
|
|
2383
|
-
});
|
|
2384
|
-
const progress = {
|
|
2385
|
-
complete: !counting && !pendingSources.size,
|
|
2386
|
-
files,
|
|
2387
|
-
referenceFiles,
|
|
2388
|
-
lenses,
|
|
2389
|
-
resolvedSelections,
|
|
2390
|
-
unavailableSelections
|
|
2391
|
-
};
|
|
2392
|
-
const untrackedFiles = pins ? await data.untrackedFiles(pins) : void 0;
|
|
2393
|
-
if (untrackedFiles) progress.untrackedFiles = untrackedFiles;
|
|
2394
|
-
return progress;
|
|
2395
|
-
}
|
|
2396
|
-
/** The most files an uncategorized report names; the rest are counted. */
|
|
2397
|
-
const REPORT_FILES = 50;
|
|
2398
|
-
/** What a lens author still has to place: the changed lines no lens selects,
|
|
2399
|
-
* grouped by file. */
|
|
2400
|
-
function uncategorizedReport(progress) {
|
|
2401
|
-
const sources = progress.lenses.find((lens) => lens.id === "automatic-uncategorized")?.sources ?? [];
|
|
2402
|
-
const byPath = /* @__PURE__ */ new Map();
|
|
2403
|
-
for (const source of sources) {
|
|
2404
|
-
const path = progress.files.find((file) => source.file === (source.side === "base" ? file.previousPath ?? file.path : file.path))?.path ?? source.file;
|
|
2405
|
-
const entry = byPath.get(path) ?? {
|
|
2406
|
-
path,
|
|
2407
|
-
lines: 0,
|
|
2408
|
-
ranges: []
|
|
2409
|
-
};
|
|
2410
|
-
entry.lines += source.toLine - source.fromLine + 1;
|
|
2411
|
-
entry.ranges.push({
|
|
2412
|
-
side: source.side,
|
|
2413
|
-
fromLine: source.fromLine,
|
|
2414
|
-
toLine: source.toLine
|
|
2415
|
-
});
|
|
2416
|
-
byPath.set(path, entry);
|
|
2417
|
-
}
|
|
2418
|
-
const files = [...byPath.values()];
|
|
2419
|
-
const report = {
|
|
2420
|
-
lines: files.reduce((total, file) => total + file.lines, 0),
|
|
2421
|
-
files: files.slice(0, REPORT_FILES)
|
|
2422
|
-
};
|
|
2423
|
-
if (files.length > REPORT_FILES) report.moreFiles = files.length - REPORT_FILES;
|
|
2424
|
-
return report;
|
|
2425
|
-
}
|
|
2426
|
-
/** Each lens as authored, with what it resolves to, for a lens author. */
|
|
2427
|
-
function lensReport(lenses, progress) {
|
|
2428
|
-
return {
|
|
2429
|
-
lenses: lenses.map((lens) => {
|
|
2430
|
-
const resolved = progress.lenses.find((item) => item.id === lens.id);
|
|
2431
|
-
return {
|
|
2432
|
-
...lens,
|
|
2433
|
-
fileCount: resolved?.fileCount ?? 0,
|
|
2434
|
-
...resolved?.unavailable && { unavailable: resolved.unavailable }
|
|
2435
|
-
};
|
|
2436
|
-
}),
|
|
2437
|
-
uncategorized: uncategorizedReport(progress)
|
|
2438
|
-
};
|
|
2439
|
-
}
|
|
2440
|
-
//#endregion
|
|
2441
2203
|
//#region src/ask/checkout-files.ts
|
|
2442
2204
|
/** The checkout's files relative to its root: tracked ones, and new ones git
|
|
2443
2205
|
* does not ignore. None where git cannot list them. */
|
|
@@ -2883,7 +2645,7 @@ function mountSharingHost(app, store, data, shared, options = {}) {
|
|
|
2883
2645
|
const parsed = parseShareLink(url);
|
|
2884
2646
|
const account = await readStoreAuth();
|
|
2885
2647
|
if (parsed.origin !== DEFAULT_STORE_ORIGIN && parsed.origin !== account?.origin) throw new ReviewInputError("This share uses an untrusted service. Sign in to that service before opening its links.", 400);
|
|
2886
|
-
const id = sharedReviewId(parsed.origin, parsed.
|
|
2648
|
+
const id = sharedReviewId(parsed.origin, parsed.capability);
|
|
2887
2649
|
if (!imports.has(id)) {
|
|
2888
2650
|
shared.setStatus(id, "downloading");
|
|
2889
2651
|
const job = (async () => {
|
|
@@ -2891,8 +2653,8 @@ function mountSharingHost(app, store, data, shared, options = {}) {
|
|
|
2891
2653
|
await shared.prepare(id);
|
|
2892
2654
|
return;
|
|
2893
2655
|
}
|
|
2894
|
-
const bundle = await new ShareClient(parsed.origin).download(parsed.
|
|
2895
|
-
await shared.import(parsed.origin, parsed.
|
|
2656
|
+
const { bundle, attribution } = await new ShareClient(parsed.origin).download(parsed.capability);
|
|
2657
|
+
await shared.import(parsed.origin, parsed.capability, bundle, attribution);
|
|
2896
2658
|
})().catch((error) => {
|
|
2897
2659
|
shared.setStatus(id, "error", error instanceof ReviewInputError ? error.message : "This share is unavailable, revoked, or needs a newer Whiteboard version.");
|
|
2898
2660
|
}).finally(() => imports.delete(id));
|
|
@@ -2919,9 +2681,13 @@ function mountSharingPublisher(app, store, data, options = {}) {
|
|
|
2919
2681
|
const repositoryId = snapshot.pins?.repositoryId ?? snapshot.target?.repositoryId;
|
|
2920
2682
|
const root = repositoryId ? store.repositoryPath(repositoryId) : void 0;
|
|
2921
2683
|
const readRepository = options.readRepository ?? readShareRepository;
|
|
2922
|
-
const
|
|
2684
|
+
const commits = referenceCommits(snapshot);
|
|
2685
|
+
const repository = (async () => {
|
|
2686
|
+
if (!root) return void 0;
|
|
2923
2687
|
try {
|
|
2924
|
-
|
|
2688
|
+
const repository = await readRepository(root);
|
|
2689
|
+
if (snapshot.pins || commits.length) await verifyRepository(root, snapshot.pins, commits);
|
|
2690
|
+
return repository;
|
|
2925
2691
|
} catch {
|
|
2926
2692
|
return;
|
|
2927
2693
|
}
|
|
@@ -2930,19 +2696,12 @@ function mountSharingPublisher(app, store, data, options = {}) {
|
|
|
2930
2696
|
store,
|
|
2931
2697
|
data,
|
|
2932
2698
|
reviewId: input.reviewId,
|
|
2933
|
-
version: snapshot.version
|
|
2934
|
-
repository
|
|
2699
|
+
version: snapshot.version
|
|
2935
2700
|
});
|
|
2936
|
-
const
|
|
2937
|
-
|
|
2938
|
-
ok: false,
|
|
2939
|
-
error
|
|
2940
|
-
})) : Promise.resolve({ ok: true });
|
|
2701
|
+
const verified = await repository;
|
|
2702
|
+
if (verified) bundle.repository = verified;
|
|
2941
2703
|
try {
|
|
2942
|
-
const result = await new ShareClient(account.origin, account.token, options.fetch).create(bundle, input.requestId ?? randomUUID()
|
|
2943
|
-
const result = await verification;
|
|
2944
|
-
if (!result.ok) throw result.error;
|
|
2945
|
-
});
|
|
2704
|
+
const result = await new ShareClient(account.origin, account.token, options.fetch).create(bundle, input.requestId ?? randomUUID());
|
|
2946
2705
|
const url = new URL(result.url);
|
|
2947
2706
|
if (process.env.DEV_FAST_REVIEW_APP_URL_PROTOCOL === "dev-fast-review-preview") url.searchParams.set("app", "preview");
|
|
2948
2707
|
options.onPublished?.({
|
|
@@ -2955,7 +2714,7 @@ function mountSharingPublisher(app, store, data, options = {}) {
|
|
|
2955
2714
|
version: snapshot.version
|
|
2956
2715
|
});
|
|
2957
2716
|
} catch (error) {
|
|
2958
|
-
if (error instanceof
|
|
2717
|
+
if (error instanceof ReviewInputError) throw error;
|
|
2959
2718
|
if (error instanceof ShareAuthError) {
|
|
2960
2719
|
if (process.env.DEV_REVIEW_SHARE_TOKEN === void 0) await clearStoreAuth();
|
|
2961
2720
|
throw new ReviewInputError("Your sign-in has expired. Sign in again to share.", 401);
|
|
@@ -2984,17 +2743,21 @@ var SharedReviewData = class {
|
|
|
2984
2743
|
this.store = store;
|
|
2985
2744
|
}
|
|
2986
2745
|
map(id, resourceId) {
|
|
2987
|
-
const
|
|
2988
|
-
if (!
|
|
2989
|
-
return
|
|
2746
|
+
const { maps } = this.store.get(id);
|
|
2747
|
+
if (!Object.hasOwn(maps, resourceId)) throw new ReviewInputError("Map is not included in this share.", 404);
|
|
2748
|
+
return maps[resourceId];
|
|
2990
2749
|
}
|
|
2991
2750
|
async resource(id, resourceId) {
|
|
2992
|
-
const
|
|
2993
|
-
if (
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2751
|
+
const { bundle } = this.store.get(id);
|
|
2752
|
+
if (Object.hasOwn(bundle.images, resourceId)) return {
|
|
2753
|
+
data: Buffer.from(bundle.images[resourceId].png, "base64"),
|
|
2754
|
+
mimeType: "image/png"
|
|
2755
|
+
};
|
|
2756
|
+
if (Object.hasOwn(bundle.traces, resourceId)) return {
|
|
2757
|
+
data: Buffer.from(JSON.stringify(bundle.traces[resourceId])),
|
|
2758
|
+
mimeType: "application/json"
|
|
2997
2759
|
};
|
|
2760
|
+
throw new ReviewInputError("Resource is not included in this share.", 404);
|
|
2998
2761
|
}
|
|
2999
2762
|
};
|
|
3000
2763
|
//#endregion
|
|
@@ -3136,6 +2899,14 @@ function documentText(snapshot, targetId, full = false, relations) {
|
|
|
3136
2899
|
}
|
|
3137
2900
|
for (const edge of element.edges) detail(`[${edge.id}] ${edge.from} → ${edge.to}${edge.label ? `: ${edge.label}` : ""}`);
|
|
3138
2901
|
break;
|
|
2902
|
+
case "animation":
|
|
2903
|
+
for (const [index, frame] of element.frames.entries()) detail(`Frame ${index + 1} [${frame.key}]: ${frame.title}${frame.caption ? ` — ${frame.caption}` : ""}`);
|
|
2904
|
+
for (const [name, anchor] of Object.entries(element.code)) detail(`Code ${name}: ${anchor}`);
|
|
2905
|
+
if (detailed) code(depth + 1, {
|
|
2906
|
+
language: "html",
|
|
2907
|
+
text: element.html
|
|
2908
|
+
});
|
|
2909
|
+
break;
|
|
3139
2910
|
case "software_map": detail(`Map: ${element.mapVersionId}${element.focusElementId ? `, focus: ${element.focusElementId}` : ""}`);
|
|
3140
2911
|
}
|
|
3141
2912
|
};
|
|
@@ -3272,24 +3043,53 @@ async function modified(file) {
|
|
|
3272
3043
|
return 0;
|
|
3273
3044
|
}
|
|
3274
3045
|
}
|
|
3046
|
+
/** The folder holding a bare clone's `.git` file, as in `project/.bare`;
|
|
3047
|
+
* else the clone itself. */
|
|
3048
|
+
async function bareRoot(bare) {
|
|
3049
|
+
const parent = path.dirname(bare);
|
|
3050
|
+
try {
|
|
3051
|
+
const gitdir = /^gitdir:\s*(.+)$/m.exec(await readFile(path.join(parent, ".git"), "utf8"))?.[1];
|
|
3052
|
+
if (gitdir && path.resolve(parent, gitdir.trim()) === bare) return parent;
|
|
3053
|
+
} catch {}
|
|
3054
|
+
return bare;
|
|
3055
|
+
}
|
|
3056
|
+
/** A folder's project: its main checkout, its bare clone, or itself. */
|
|
3057
|
+
async function projectOf(folder, run) {
|
|
3058
|
+
const git = (args, cwd = folder) => run("git", args, cwd).then((output) => output.trim());
|
|
3059
|
+
const common = path.resolve(folder, await git([
|
|
3060
|
+
"rev-parse",
|
|
3061
|
+
"--path-format=absolute",
|
|
3062
|
+
"--git-common-dir"
|
|
3063
|
+
]));
|
|
3064
|
+
if (path.basename(common) === ".git") return {
|
|
3065
|
+
root: path.dirname(common),
|
|
3066
|
+
common,
|
|
3067
|
+
bare: false
|
|
3068
|
+
};
|
|
3069
|
+
if (await git(["rev-parse", "--is-bare-repository"], common) === "true") return {
|
|
3070
|
+
root: await bareRoot(common),
|
|
3071
|
+
common,
|
|
3072
|
+
bare: true
|
|
3073
|
+
};
|
|
3074
|
+
return {
|
|
3075
|
+
root: await git(["rev-parse", "--show-toplevel"]),
|
|
3076
|
+
common,
|
|
3077
|
+
bare: false
|
|
3078
|
+
};
|
|
3079
|
+
}
|
|
3275
3080
|
/** The repository a folder belongs to, and when it last saw Git activity.
|
|
3276
3081
|
* Worktrees resolve to their main checkout, which lists them as targets. */
|
|
3277
3082
|
async function repositoryOf(folder, run) {
|
|
3278
3083
|
try {
|
|
3279
3084
|
if (!(await stat(folder)).isDirectory()) return void 0;
|
|
3280
|
-
const common =
|
|
3281
|
-
"rev-parse",
|
|
3282
|
-
"--path-format=absolute",
|
|
3283
|
-
"--git-common-dir"
|
|
3284
|
-
], folder)).trim());
|
|
3285
|
-
if (path.basename(common) !== ".git") return void 0;
|
|
3085
|
+
const { root, common } = await projectOf(folder, run);
|
|
3286
3086
|
const activity = await Promise.all([
|
|
3287
3087
|
"index",
|
|
3288
3088
|
"FETCH_HEAD",
|
|
3289
3089
|
path.join("logs", "HEAD")
|
|
3290
3090
|
].map((file) => modified(path.join(common, file))));
|
|
3291
3091
|
return {
|
|
3292
|
-
root
|
|
3092
|
+
root,
|
|
3293
3093
|
active: Math.max(...activity)
|
|
3294
3094
|
};
|
|
3295
3095
|
} catch {
|
|
@@ -3322,9 +3122,24 @@ function parseWorktrees(output) {
|
|
|
3322
3122
|
for (const line of output.split("\n")) if (line.startsWith("worktree ")) {
|
|
3323
3123
|
current = { path: line.slice(9) };
|
|
3324
3124
|
worktrees.push(current);
|
|
3325
|
-
} else if (current
|
|
3125
|
+
} else if (!current) continue;
|
|
3126
|
+
else if (line.startsWith("branch ")) current.branch = line.slice(7).replace(/^refs\/heads\//, "");
|
|
3127
|
+
else if (line === "bare") current.bare = true;
|
|
3128
|
+
else if (line.startsWith("prunable")) current.prunable = true;
|
|
3326
3129
|
return worktrees;
|
|
3327
3130
|
}
|
|
3131
|
+
const drawable = (worktree) => !worktree.bare && !worktree.prunable && !worktree.path.split(/[\\/]/).includes("dev-fast") && !isInside(TEMPORARY_ROOTS, worktree.path);
|
|
3132
|
+
/** In a bare clone, a pull request is drawn from the worktree on its branch. */
|
|
3133
|
+
async function checkoutOf(project, branch, run) {
|
|
3134
|
+
const worktrees = parseWorktrees(await run("git", [
|
|
3135
|
+
"worktree",
|
|
3136
|
+
"list",
|
|
3137
|
+
"--porcelain"
|
|
3138
|
+
], project).catch(() => ""));
|
|
3139
|
+
if (!worktrees[0]?.bare) return project;
|
|
3140
|
+
const usable = worktrees.filter(drawable);
|
|
3141
|
+
return (usable.find((tree) => tree.branch === branch) ?? usable[0])?.path;
|
|
3142
|
+
}
|
|
3328
3143
|
const pullRequestsSchema = z.array(z.object({
|
|
3329
3144
|
number: z.number().int().positive(),
|
|
3330
3145
|
title: z.string().min(1),
|
|
@@ -3387,13 +3202,17 @@ async function pullRequests(root, run) {
|
|
|
3387
3202
|
* worktrees, and its open pull requests, most recently touched first. */
|
|
3388
3203
|
async function onboardingTargets(directory, run = runCommand) {
|
|
3389
3204
|
let root;
|
|
3205
|
+
let bare = false;
|
|
3390
3206
|
try {
|
|
3391
3207
|
root = (await run("git", ["rev-parse", "--show-toplevel"], directory)).trim();
|
|
3392
3208
|
} catch {
|
|
3393
|
-
|
|
3209
|
+
const project = await projectOf(directory, run).catch(() => void 0);
|
|
3210
|
+
if (!project?.bare) throw new ReviewInputError("Choose a folder inside a Git repository.", 400);
|
|
3211
|
+
root = project.root;
|
|
3212
|
+
bare = true;
|
|
3394
3213
|
}
|
|
3395
3214
|
const [branch, worktreeList, base, prs, times] = await Promise.all([
|
|
3396
|
-
run("git", ["branch", "--show-current"], root).then((output) => output.trim(), () => ""),
|
|
3215
|
+
bare ? "" : run("git", ["branch", "--show-current"], root).then((output) => output.trim(), () => ""),
|
|
3397
3216
|
run("git", [
|
|
3398
3217
|
"worktree",
|
|
3399
3218
|
"list",
|
|
@@ -3407,7 +3226,7 @@ async function onboardingTargets(directory, run = runCommand) {
|
|
|
3407
3226
|
target,
|
|
3408
3227
|
at: times.get(target.branch) ?? 0
|
|
3409
3228
|
});
|
|
3410
|
-
const worktrees = parseWorktrees(worktreeList).filter((worktree) => worktree.branch && path.resolve(worktree.path) !== path.resolve(root) &&
|
|
3229
|
+
const worktrees = parseWorktrees(worktreeList).filter((worktree) => worktree.branch && path.resolve(worktree.path) !== path.resolve(root) && drawable(worktree)).map((worktree) => local({
|
|
3411
3230
|
kind: "worktree",
|
|
3412
3231
|
path: worktree.path,
|
|
3413
3232
|
branch: worktree.branch ?? ""
|
|
@@ -3450,7 +3269,8 @@ function registerOnboardingRoutes(app, store, ask, host, run = runCommand) {
|
|
|
3450
3269
|
if (!parsed.success) throw new ReviewInputError("Invalid run.", 400);
|
|
3451
3270
|
const input = parsed.data;
|
|
3452
3271
|
const { target } = input;
|
|
3453
|
-
const cwd = target.kind === "pr" ? input.projectPath : target.path;
|
|
3272
|
+
const cwd = target.kind === "pr" ? await checkoutOf(input.projectPath, target.branch, run) : target.path;
|
|
3273
|
+
if (!cwd) throw new ReviewInputError("This bare clone has no worktrees. Add one with git worktree add.", 400);
|
|
3454
3274
|
let head;
|
|
3455
3275
|
try {
|
|
3456
3276
|
head = (await run("git", ["rev-parse", "HEAD"], cwd)).trim();
|
|
@@ -3638,7 +3458,7 @@ const remoteCaller = (context) => context.req.header(REVIEW_CLIENT_HEADER) === R
|
|
|
3638
3458
|
function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
3639
3459
|
desktopAvailable: Boolean(open),
|
|
3640
3460
|
softwareMapEnabled: false
|
|
3641
|
-
}), traceEnabled = async () => false, status = () => ({}), hooks = {}, ask) {
|
|
3461
|
+
}), traceEnabled = async () => false, status = () => ({}), hooks = {}, ask, animationsEnabled = () => false) {
|
|
3642
3462
|
const app = new Hono();
|
|
3643
3463
|
app.onError((error, context) => {
|
|
3644
3464
|
if (error instanceof HttpJsonError) return context.json({ error: error.message }, error.statusCode);
|
|
@@ -3729,10 +3549,13 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
3729
3549
|
};
|
|
3730
3550
|
app.get("/", (context) => context.json(catalog()));
|
|
3731
3551
|
app.get("/feedback-eligibility", (context) => context.json({ eligible: store.feedbackEligible() }));
|
|
3732
|
-
const instructionContext = async () => ({
|
|
3552
|
+
const instructionContext = async () => ({
|
|
3553
|
+
traceEnabled: await traceEnabled(),
|
|
3554
|
+
animationsEnabled: animationsEnabled()
|
|
3555
|
+
});
|
|
3733
3556
|
app.get("/authoring", async (context) => {
|
|
3734
3557
|
const instructions = await instructionContext();
|
|
3735
|
-
return context.json(authoringTools(instructions.traceEnabled));
|
|
3558
|
+
return context.json(authoringTools(instructions.traceEnabled, instructions.animationsEnabled));
|
|
3736
3559
|
});
|
|
3737
3560
|
app.get("/instructions", async (context) => {
|
|
3738
3561
|
const { topic } = instructionsQuerySchema.parse(context.req.query());
|
|
@@ -3786,7 +3609,10 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
3786
3609
|
...status(),
|
|
3787
3610
|
desktopAvailable: (await capabilities()).desktopAvailable
|
|
3788
3611
|
}));
|
|
3789
|
-
app.get("/capabilities", async (context) => context.json(
|
|
3612
|
+
app.get("/capabilities", async (context) => context.json({
|
|
3613
|
+
...await capabilities(),
|
|
3614
|
+
animationsEnabled: animationsEnabled()
|
|
3615
|
+
}));
|
|
3790
3616
|
app.get("/:id/activity", (context) => {
|
|
3791
3617
|
const id = context.req.param("id");
|
|
3792
3618
|
readReview(id);
|
|
@@ -4721,6 +4547,12 @@ function createReviewApi(store, data, open, shared, capabilities = () => ({
|
|
|
4721
4547
|
const register = async (path) => data ? data.register(path) : store.registerRepository(path);
|
|
4722
4548
|
const request = withBoardRepository(await locateRepositories(await pullRequestTargets(body, register, (id) => store.read(id)), register), (id) => store.has(id) ? store.read(id) : void 0);
|
|
4723
4549
|
const input = commandSchema.parse(request);
|
|
4550
|
+
if (!animationsEnabled() && input.operation.type === "edit") {
|
|
4551
|
+
const { edit, reviewId } = input.operation;
|
|
4552
|
+
const incoming = "content" in edit ? elements([edit.content]) : [];
|
|
4553
|
+
const target = "targetId" in edit ? elements(readReview(reviewId).document).find((element) => element.id === edit.targetId) : void 0;
|
|
4554
|
+
if (incoming.some((element) => element.type === "animation") || target?.type === "animation") throw new ReviewInputError("Animation authoring is disabled. Enable Animations in Settings under Experimental Features to edit animations. Existing animations can still be viewed.", 409);
|
|
4555
|
+
}
|
|
4724
4556
|
const command = sharedCommandSchema.safeParse(input);
|
|
4725
4557
|
if (command.success && command.data.operation.reviewId?.startsWith("shared-")) {
|
|
4726
4558
|
const parsed = commandSchema.parse(input);
|
|
@@ -5096,7 +4928,7 @@ function createWhiteboardCore(input) {
|
|
|
5096
4928
|
const api = createReviewApi(store, data, callbacks.open, shared, callbacks.capabilities, () => traceMachineEnabled(), input.status, input.hooks, askThreads && {
|
|
5097
4929
|
threads: askThreads,
|
|
5098
4930
|
agents: async () => detectAskAgents(await ask?.env)
|
|
5099
|
-
});
|
|
4931
|
+
}, input.animations);
|
|
5100
4932
|
if (!shared) mountSharingPublisher(api, store, data);
|
|
5101
4933
|
return {
|
|
5102
4934
|
app,
|
|
@@ -5431,4 +5263,4 @@ async function serve(input) {
|
|
|
5431
5263
|
}
|
|
5432
5264
|
}
|
|
5433
5265
|
//#endregion
|
|
5434
|
-
export {
|
|
5266
|
+
export { setDiffrConfigValue as C, saveDiffrSummarizer as S, cliAskTools as T, HttpJsonError as _, drainServerCrashReport as a, migrateDiffrConfig as b, answerErrorsAsJson as c, captureSanitizedUiTelemetry as d, clientErrorsForSession as f, DEFAULT_MAX_REQUEST_BYTES as g, readBoundedRequestJson as h, withHeadlessServerLock as i, createWhiteboardCore as l, createNodeRequestListener as m, runHeadlessServer as n, installProcessErrorTelemetry as o, recordClientError as p, takeOverServerHome as r, serverCrashReportPath as s, HeadlessServerBusyError as t, serverJson as u, ReviewServerError as v, testDiffrSummarizer as w, readDiffrConfig as x, GlobalReviewDesktopVerbRelay as y };
|