@dev.fast/whiteboard 0.2.4 → 0.2.5-preview.20261013.109
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-_1_7vROx.js → account-alias-D0hF0sKk.js} +2 -3
- package/dist/{agent-cli-BrFqhnzM.js → agent-cli-BBPxwUOd.js} +6 -6
- package/dist/agent-cli-YSuhE5X8.js +2 -0
- package/dist/{agent-client-B_b1GtUc.js → agent-client-P3J4y8Zn.js} +3 -3
- package/dist/{authoring-tools-DvIO906l.js → authoring-tools-D8WXsm_g.js} +11 -10
- package/dist/build-info.json +1 -1
- package/dist/{cli-gRGxkwc0.js → cli-C0ziP6hg.js} +1 -1
- package/dist/{cli-runner-Cjl8h376.js → cli-runner-C1gY-HAI.js} +16 -17
- package/dist/cli.js +1 -1
- package/dist/{client-BFClfQLO.js → client-DzcSt6pV.js} +63 -13
- package/dist/{desktop-discovery-C-Qz54wO.js → desktop-discovery-Ba3dD5Cn.js} +1 -1
- package/dist/{headless-host-DcWaxx9P.js → headless-host-BHD_Vg5F.js} +4 -4
- package/dist/{local-data-Bm84Xdck.js → local-data-BlERtVm2.js} +281 -75
- package/dist/{mcp-BDy9Aybd.js → mcp-t7VN9R3k.js} +4 -4
- package/dist/{package-paths-B6-zxvIO.js → package-paths-B9PDoAl6.js} +1 -1
- package/dist/{process-error-telemetry-Dzh5a3s_.js → process-error-telemetry-C0swByfp.js} +158 -57
- package/dist/{profile-RDEioF8b.js → profile-BsYDBr7t.js} +2 -2
- package/dist/profile-j97aRTS7.js +2 -0
- package/dist/{review-agent-traces-DNJFYzc8.js → review-home-paths-Y9mYWkCI.js} +2600 -62
- package/dist/{review-telemetry-DBy3eVCo.js → review-telemetry-CmM6tCbj.js} +2 -2
- package/dist/server/desktop-host.js +35 -46
- package/dist/{server-discovery-Dbzn3w6Z.js → server-discovery-ZVi8Ay8J.js} +1 -1
- package/dist/sharing/index.d.ts +37 -49
- package/dist/sharing/index.js +1 -1
- package/dist/{src-CmdiBL20.js → src-DiHP11l3.js} +11 -1
- package/dist/{stored-document-migration-BxZWQQjv.js → stored-document-migration-u4L_1VZa.js} +15 -36
- package/dist/{tool-failure-DJmTieh5.js → tool-failure-CJHBCHMh.js} +2 -2
- package/instructions/scratchpad.md +1 -1
- package/package.json +5 -4
- package/src/ask/agents.ts +6 -0
- package/src/ask/thread-state.ts +17 -1
- package/src/ask/thread.ts +116 -22
- package/src/ask/threads.ts +8 -2
- package/src/error-telemetry.ts +13 -9
- package/src/fixtures/blocks/tutorial.json +3 -40
- package/src/review-api/README.md +10 -7
- package/src/review-api/ask-history.ts +37 -0
- package/src/review-api/authoring-tools.ts +8 -5
- package/src/review-api/blocks/database_lens.ts +5 -0
- package/src/review-api/blocks/tutorial.ts +2 -18
- package/src/review-api/comparison-coverage.ts +16 -9
- package/src/review-api/component-reference.ts +1 -1
- package/src/review-api/document.ts +24 -10
- package/src/review-api/http.ts +267 -189
- package/src/review-api/local-data.ts +126 -37
- package/src/review-api/store-schema.ts +25 -1
- package/src/review-api/store.ts +165 -33
- package/src/review-api/workspaces.ts +14 -14
- package/src/review-api/worktree-events.ts +46 -0
- package/src/review-app.ts +1 -1
- package/src/review-info.ts +1 -1
- package/src/review-stack.ts +2 -2
- package/src/server/review-server-core.ts +25 -1
- package/src/server/tutorial-service.ts +22 -46
- package/src/sharing/export.ts +1 -0
- package/src/sharing/import.ts +111 -26
- package/tutorial/document.json +27 -86
- package/tutorial/lenses.json +10 -0
- package/tutorial/runtime-manifest.json +2 -3
- package/tutorial/sample-service/src/database/drizzle-orm.d.ts +16 -0
- package/tutorial/sample-service/src/database/schema.ts +9 -10
- package/tutorial/sample-service/src/inventory/forklift-mood.ts +4 -0
- package/tutorial/sample-service/src/inventory/inventory-service.ts +18 -1
- package/tutorial/sample-service/src/inventory/warehouse-lore.ts +11 -0
- package/tutorial/sample-service/src/orders/order-service.ts +3 -2
- package/tutorial/sample-service/src/orders/order.ts +27 -5
- package/tutorial/sample-service/src/payments/fraud-vibes.ts +4 -0
- package/tutorial/sample-service/src/payments/payment-gateway.ts +19 -2
- package/tutorial/sample-service/src/payments/raccoon-ledger.ts +9 -0
- package/dist/agent-cli-BR2j-2n5.js +0 -2
- package/dist/input-error-OLgB_h31.js +0 -11
- package/dist/profile-BQGaX8aX.js +0 -2
- package/dist/review-home-paths-6zZH-1c9.js +0 -2560
- package/dist/tutorial-trace-DrBvkaeL.js +0 -43
- package/src/tutorial-conversation.ts +0 -18
- package/tutorial/software-map.json +0 -139
- package/tutorial/trace.json +0 -20
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { c as jsonString, l as jsonValueSchema, o as jsonObject, u as parseJsonText } from "./src-X9phtB2j.js";
|
|
2
2
|
import "./src-WCbabvdS.js";
|
|
3
|
+
import "./review-home-paths-Y9mYWkCI.js";
|
|
3
4
|
import { A as devReviewHome, D as processIsAlive, M as writeFileAtomic, O as withFileLock } from "./s3-config-CAxhO9u_.js";
|
|
4
|
-
import "./
|
|
5
|
-
import { i as readReviewPackageVersion, t as findReviewPackageRoot } from "./package-paths-B6-zxvIO.js";
|
|
5
|
+
import { i as readReviewPackageVersion, t as findReviewPackageRoot } from "./package-paths-B9PDoAl6.js";
|
|
6
6
|
import "./request-origin-DA4K1qWY.js";
|
|
7
7
|
import { createHmac, randomUUID } from "node:crypto";
|
|
8
8
|
import { z } from "zod";
|
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as diffFileSummaries, b as resolveRevision, i as diff, x as splitGitPatchFiles } from "../src-
|
|
2
|
+
import { C as ReviewInputError, a as diffFileSummaries, b as resolveRevision, i as diff, x as splitGitPatchFiles } from "../src-DiHP11l3.js";
|
|
3
3
|
import { c as jsonString, i as jsonBoolean, n as isJsonObject, p as isObjectValue, s as jsonProperty, u as parseJsonText } from "../src-X9phtB2j.js";
|
|
4
|
-
import { i as SharedReviewStore } from "../client-
|
|
4
|
+
import { i as SharedReviewStore } from "../client-DzcSt6pV.js";
|
|
5
5
|
import { c as ReviewBugReportRequestSchema, l as parseReviewBugReportResponse, o as parseZod, s as ReviewBugReportMetaV2Schema, t as parseReviewCliInstallApplyRequest, v as reviewDiffrSummarizerInputSchema } from "../src-WCbabvdS.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { et as shellQuote, i as reviewInstanceDiscoveryPath, o as reviewLegacyDiscoveryPath } from "../review-home-paths-Y9mYWkCI.js";
|
|
7
|
+
import { C as resourceReferences, M as lensSchema, p as documentSchema } from "../stored-document-migration-u4L_1VZa.js";
|
|
8
8
|
import { A as devReviewHome, P as writePrivateJsonAtomic } from "../s3-config-CAxhO9u_.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { t as
|
|
13
|
-
import { r as reviewTelemetryChannel, t as ReviewTelemetry } from "../review-telemetry-DBy3eVCo.js";
|
|
9
|
+
import { i as readReviewPackageVersion, t as findReviewPackageRoot } from "../package-paths-B9PDoAl6.js";
|
|
10
|
+
import { c as reviewInstanceIdentity, t as REVIEW_INSTANCE_ENV } from "../desktop-discovery-Ba3dD5Cn.js";
|
|
11
|
+
import { t as openReviewProfile } from "../profile-BsYDBr7t.js";
|
|
12
|
+
import { r as reviewTelemetryChannel, t as ReviewTelemetry } from "../review-telemetry-CmM6tCbj.js";
|
|
14
13
|
import { o as REVIEW_TELEMETRY_TABS } from "../request-origin-DA4K1qWY.js";
|
|
15
|
-
import { c as removeLegacyReviewSkills, d as skipCliInstall, i as finishCliInstallUpdate, l as resetCliInstall, n as applyCliInstall, r as declineCliInstall, s as removeCliInstall, t as aliasInstallationToAccount, u as resolveCliInstallStatus } from "../account-alias-
|
|
16
|
-
import { _ as setDiffrConfigValue, a as serverJson, c as recordClientError, d as HttpJsonError, f as ReviewServerError, g as saveDiffrSummarizer, h as readDiffrConfig, i as createWhiteboardCore, l as createNodeRequestListener, m as migrateDiffrConfig, n as installProcessErrorTelemetry, o as captureSanitizedUiTelemetry, p as GlobalReviewDesktopVerbRelay, r as serverCrashReportPath, s as clientErrorsForSession, t as drainServerCrashReport, u as readBoundedRequestJson, v as testDiffrSummarizer } from "../process-error-telemetry-
|
|
17
|
-
import { c as readQuerySchemas } from "../authoring-tools-
|
|
14
|
+
import { c as removeLegacyReviewSkills, d as skipCliInstall, i as finishCliInstallUpdate, l as resetCliInstall, n as applyCliInstall, r as declineCliInstall, s as removeCliInstall, t as aliasInstallationToAccount, u as resolveCliInstallStatus } from "../account-alias-D0hF0sKk.js";
|
|
15
|
+
import { _ as setDiffrConfigValue, a as serverJson, c as recordClientError, d as HttpJsonError, f as ReviewServerError, g as saveDiffrSummarizer, h as readDiffrConfig, i as createWhiteboardCore, l as createNodeRequestListener, m as migrateDiffrConfig, n as installProcessErrorTelemetry, o as captureSanitizedUiTelemetry, p as GlobalReviewDesktopVerbRelay, r as serverCrashReportPath, s as clientErrorsForSession, t as drainServerCrashReport, u as readBoundedRequestJson, v as testDiffrSummarizer } from "../process-error-telemetry-C0swByfp.js";
|
|
16
|
+
import { c as readQuerySchemas } from "../authoring-tools-D8WXsm_g.js";
|
|
18
17
|
import crypto, { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
19
18
|
import { z } from "zod";
|
|
20
19
|
import fs, { existsSync } from "node:fs";
|
|
@@ -814,6 +813,7 @@ const authoredSchema = z.strictObject({
|
|
|
814
813
|
title: z.string().min(1),
|
|
815
814
|
document: documentSchema
|
|
816
815
|
});
|
|
816
|
+
const lensesSchema = z.array(lensSchema.omit({ id: true }));
|
|
817
817
|
const pinsSchema = z.strictObject({
|
|
818
818
|
base: z.string().regex(/^[a-f0-9]{40}$/),
|
|
819
819
|
head: z.string().regex(/^[a-f0-9]{40}$/)
|
|
@@ -826,15 +826,13 @@ const stampSchema = z.object({
|
|
|
826
826
|
async function readTutorialAssets(assetsRoot) {
|
|
827
827
|
const bytes = await Promise.all([
|
|
828
828
|
"document.json",
|
|
829
|
-
"
|
|
830
|
-
"software-map.json",
|
|
829
|
+
"lenses.json",
|
|
831
830
|
"pins.json"
|
|
832
831
|
].map((name) => readFile(path.join(assetsRoot, name), "utf8")));
|
|
833
832
|
return {
|
|
834
833
|
authored: authoredSchema.parse(JSON.parse(bytes[0])),
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
pins: pinsSchema.parse(JSON.parse(bytes[3])),
|
|
834
|
+
lenses: lensesSchema.parse(JSON.parse(bytes[1])),
|
|
835
|
+
pins: pinsSchema.parse(JSON.parse(bytes[2])),
|
|
838
836
|
contentHash: createHash("sha256").update(JSON.stringify(bytes)).digest("hex")
|
|
839
837
|
};
|
|
840
838
|
}
|
|
@@ -843,31 +841,6 @@ async function createNativeTutorial(input) {
|
|
|
843
841
|
const assets = await readTutorialAssets(input.assetsRoot);
|
|
844
842
|
const repository = await input.data.register(input.sampleRoot);
|
|
845
843
|
const pins = await input.data.resolvePins(repository.id, assets.pins.base, assets.pins.head);
|
|
846
|
-
const aliases = /* @__PURE__ */ new Map();
|
|
847
|
-
const traceId = randomUUID();
|
|
848
|
-
await input.data.upload({
|
|
849
|
-
id: traceId,
|
|
850
|
-
repositoryId: repository.id,
|
|
851
|
-
kind: "trace",
|
|
852
|
-
trace: assets.trace
|
|
853
|
-
});
|
|
854
|
-
aliases.set("tutorial-trace", traceId);
|
|
855
|
-
for (const side of ["base", "head"]) {
|
|
856
|
-
const id = randomUUID();
|
|
857
|
-
await input.data.upload({
|
|
858
|
-
id,
|
|
859
|
-
repositoryId: repository.id,
|
|
860
|
-
kind: "map",
|
|
861
|
-
pins,
|
|
862
|
-
side,
|
|
863
|
-
model: assets.model
|
|
864
|
-
});
|
|
865
|
-
aliases.set(`tutorial-map-${side}`, id);
|
|
866
|
-
}
|
|
867
|
-
for (const block of resourceReferences(assets.authored.document)) {
|
|
868
|
-
if (block.type === "trace_quote") block.traceId = aliases.get(block.traceId) ?? block.traceId;
|
|
869
|
-
if (block.type === "software_map") block.mapVersionId = aliases.get(block.mapVersionId) ?? block.mapVersionId;
|
|
870
|
-
}
|
|
871
844
|
const result = await input.store.execute({ operation: {
|
|
872
845
|
type: "create",
|
|
873
846
|
title: assets.authored.title,
|
|
@@ -879,6 +852,15 @@ async function createNativeTutorial(input) {
|
|
|
879
852
|
document: assets.authored.document,
|
|
880
853
|
origin: { tutorial: true }
|
|
881
854
|
});
|
|
855
|
+
for (const { title, targets } of assets.lenses) await input.store.execute({ operation: {
|
|
856
|
+
type: "lens_edit",
|
|
857
|
+
reviewId: result.reviewId,
|
|
858
|
+
edit: {
|
|
859
|
+
type: "insert",
|
|
860
|
+
title,
|
|
861
|
+
targets
|
|
862
|
+
}
|
|
863
|
+
} });
|
|
882
864
|
return {
|
|
883
865
|
snapshot: input.store.read(result.reviewId),
|
|
884
866
|
contentHash: assets.contentHash
|
|
@@ -903,10 +885,17 @@ function createTutorialService(input) {
|
|
|
903
885
|
}
|
|
904
886
|
}
|
|
905
887
|
async function cleanup() {
|
|
906
|
-
for (const reviewId of input.store.tutorialIds())
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
888
|
+
for (const reviewId of input.store.tutorialIds()) {
|
|
889
|
+
if (!input.store.read(reviewId).trashedAt) await input.store.execute({ operation: {
|
|
890
|
+
type: "lifecycle",
|
|
891
|
+
state: "trash",
|
|
892
|
+
reviewId
|
|
893
|
+
} });
|
|
894
|
+
await input.store.execute({ operation: {
|
|
895
|
+
type: "delete",
|
|
896
|
+
reviewId
|
|
897
|
+
} });
|
|
898
|
+
}
|
|
910
899
|
for (const repository of input.store.repositories()) {
|
|
911
900
|
const relative = path.relative(tutorialRoot, repository.path);
|
|
912
901
|
if (relative && !relative.startsWith("..") && !path.isAbsolute(relative)) await input.data.forgetRepository(repository.id);
|
package/dist/sharing/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { watch } from "node:fs";
|
|
3
2
|
import { DatabaseSync } from "node:sqlite";
|
|
3
|
+
import { subscribe } from "@parcel/watcher";
|
|
4
4
|
//#region ../json/src/json.d.ts
|
|
5
5
|
/**
|
|
6
6
|
* JSON values as they come off the wire or out of a file. Parse into one of
|
|
@@ -263,7 +263,7 @@ interface ReviewApiSummary {
|
|
|
263
263
|
deletions: number;
|
|
264
264
|
} | null;
|
|
265
265
|
viewedAt: string | null;
|
|
266
|
-
|
|
266
|
+
trashedAt: string | null;
|
|
267
267
|
/** An agent holds a live lease; absent on shared reviews. */
|
|
268
268
|
working?: boolean;
|
|
269
269
|
}
|
|
@@ -425,34 +425,13 @@ interface SectionBlock {
|
|
|
425
425
|
children: Block[];
|
|
426
426
|
}
|
|
427
427
|
//#endregion
|
|
428
|
-
//#region src/tutorial-conversation.d.ts
|
|
429
|
-
declare const tutorialAuthoringConversationSchema: z.ZodObject<{
|
|
430
|
-
version: z.ZodLiteral<1>;
|
|
431
|
-
title: z.ZodString;
|
|
432
|
-
messages: z.ZodArray<z.ZodObject<{
|
|
433
|
-
role: z.ZodEnum<{
|
|
434
|
-
user: "user";
|
|
435
|
-
assistant: "assistant";
|
|
436
|
-
}>;
|
|
437
|
-
body: z.ZodString;
|
|
438
|
-
}, z.core.$strict>>;
|
|
439
|
-
}, z.core.$strict>;
|
|
440
|
-
type TutorialAuthoringConversation = z.infer<typeof tutorialAuthoringConversationSchema>;
|
|
441
|
-
//#endregion
|
|
442
428
|
//#region src/review-api/blocks/tutorial.d.ts
|
|
443
429
|
type TutorialContent = {
|
|
444
430
|
kind: "keymap";
|
|
445
|
-
} | {
|
|
446
|
-
kind: "conversation";
|
|
447
|
-
conversation: TutorialAuthoringConversation;
|
|
448
431
|
} | {
|
|
449
432
|
kind: "view";
|
|
450
|
-
view: "
|
|
433
|
+
view: "diff";
|
|
451
434
|
label: string;
|
|
452
|
-
} | {
|
|
453
|
-
kind: "feature";
|
|
454
|
-
feature: "softwareMap";
|
|
455
|
-
children: Block[];
|
|
456
435
|
};
|
|
457
436
|
type TutorialBlock = {
|
|
458
437
|
id?: string;
|
|
@@ -575,6 +554,7 @@ declare const leafSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
575
554
|
label: z.ZodString;
|
|
576
555
|
key: z.ZodOptional<z.ZodString>;
|
|
577
556
|
fields: z.ZodRecord<z.ZodString, z.ZodType<DatabaseField, unknown, z.core.$ZodTypeInternals<DatabaseField, unknown>>>;
|
|
557
|
+
source: any;
|
|
578
558
|
}, z.core.$strict>>;
|
|
579
559
|
}, z.core.$strict>>;
|
|
580
560
|
useCases: z.ZodArray<z.ZodObject<{
|
|
@@ -815,6 +795,7 @@ declare const editSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
815
795
|
label: z.ZodString;
|
|
816
796
|
key: z.ZodOptional<z.ZodString>;
|
|
817
797
|
fields: z.ZodRecord<z.ZodString, z.ZodType<DatabaseField, unknown, z.core.$ZodTypeInternals<DatabaseField, unknown>>>;
|
|
798
|
+
source: any;
|
|
818
799
|
}, z.core.$strict>>;
|
|
819
800
|
}, z.core.$strict>>;
|
|
820
801
|
useCases: z.ZodArray<z.ZodObject<{
|
|
@@ -914,28 +895,12 @@ declare const editSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
914
895
|
type: z.ZodLiteral<"tutorial">;
|
|
915
896
|
id: z.ZodOptional<z.ZodString>;
|
|
916
897
|
kind: z.ZodLiteral<"keymap">;
|
|
917
|
-
}, z.core.$strict>, z.ZodObject<{
|
|
918
|
-
type: z.ZodLiteral<"tutorial">;
|
|
919
|
-
id: z.ZodOptional<z.ZodString>;
|
|
920
|
-
kind: z.ZodLiteral<"conversation">;
|
|
921
|
-
conversation: any;
|
|
922
898
|
}, z.core.$strict>, z.ZodObject<{
|
|
923
899
|
type: z.ZodLiteral<"tutorial">;
|
|
924
900
|
id: z.ZodOptional<z.ZodString>;
|
|
925
901
|
kind: z.ZodLiteral<"view">;
|
|
926
|
-
view: z.
|
|
927
|
-
map: "map";
|
|
928
|
-
commits: "commits";
|
|
929
|
-
review: "review";
|
|
930
|
-
diff: "diff";
|
|
931
|
-
}>;
|
|
902
|
+
view: z.ZodLiteral<"diff">;
|
|
932
903
|
label: z.ZodString;
|
|
933
|
-
}, z.core.$strict>, z.ZodObject<{
|
|
934
|
-
type: z.ZodLiteral<"tutorial">;
|
|
935
|
-
id: z.ZodOptional<z.ZodString>;
|
|
936
|
-
kind: z.ZodLiteral<"feature">;
|
|
937
|
-
feature: z.ZodLiteral<"softwareMap">;
|
|
938
|
-
children: z.ZodArray<z.ZodLazy<z.ZodType<Block, unknown, z.core.$ZodTypeInternals<Block, unknown>>>>;
|
|
939
904
|
}, z.core.$strict>], "kind">, z.ZodObject<{
|
|
940
905
|
type: z.ZodDefault<z.ZodLiteral<"step">>;
|
|
941
906
|
from: z.ZodString;
|
|
@@ -1235,7 +1200,11 @@ type AskRecord = z.infer<typeof askRecordSchema>;
|
|
|
1235
1200
|
* `reviews`, so there is no foreign key; deleting a review deletes its rows. */
|
|
1236
1201
|
declare class AskHistory {
|
|
1237
1202
|
private readonly db;
|
|
1203
|
+
private externalWriteGuard?;
|
|
1204
|
+
setExternalWriteGuard(guard: (reviewId: string) => void): void;
|
|
1238
1205
|
constructor(db: DatabaseSync);
|
|
1206
|
+
private assertWritable;
|
|
1207
|
+
private assertThreadWritable;
|
|
1239
1208
|
save(record: AskRecord): void;
|
|
1240
1209
|
/** Whether reopening the conversation bypasses permissions. */
|
|
1241
1210
|
setBypass(id: string, bypass: boolean): void;
|
|
@@ -1256,6 +1225,7 @@ declare class AskHistory {
|
|
|
1256
1225
|
/** Newest first. */
|
|
1257
1226
|
list(reviewId: string): AskHistoryEntry[];
|
|
1258
1227
|
get(id: string): AskRecord | undefined;
|
|
1228
|
+
removeReview(reviewId: string): void;
|
|
1259
1229
|
delete(id: string): void;
|
|
1260
1230
|
}
|
|
1261
1231
|
//#endregion
|
|
@@ -1272,6 +1242,8 @@ interface SnapshotOrigin {
|
|
|
1272
1242
|
revision?: string;
|
|
1273
1243
|
}
|
|
1274
1244
|
interface Snapshot {
|
|
1245
|
+
/** Current lifecycle state, projected onto every version when read. */
|
|
1246
|
+
trashedAt?: string | null;
|
|
1275
1247
|
shared?: {
|
|
1276
1248
|
login?: string;
|
|
1277
1249
|
sharedAt?: number;
|
|
@@ -1319,6 +1291,7 @@ interface Result {
|
|
|
1319
1291
|
type?: Element["type"] | "lens";
|
|
1320
1292
|
children?: WrittenComponent[];
|
|
1321
1293
|
attention?: true;
|
|
1294
|
+
lifecycle?: true;
|
|
1322
1295
|
deleted?: true;
|
|
1323
1296
|
warnings?: string[];
|
|
1324
1297
|
}
|
|
@@ -1372,6 +1345,7 @@ declare class ReviewStore {
|
|
|
1372
1345
|
private readonly liveSources;
|
|
1373
1346
|
private refreshTimer?;
|
|
1374
1347
|
private refreshSubscribers;
|
|
1348
|
+
private readonly purgeTimer;
|
|
1375
1349
|
watchWorktrees(): () => void;
|
|
1376
1350
|
private projectLiveSource;
|
|
1377
1351
|
private refreshPending;
|
|
@@ -1382,6 +1356,7 @@ declare class ReviewStore {
|
|
|
1382
1356
|
private readonly externalChanges;
|
|
1383
1357
|
private observedDataVersion;
|
|
1384
1358
|
private observedVersions;
|
|
1359
|
+
private observedDeletions;
|
|
1385
1360
|
subscribeCatalog(listener: () => void): () => void;
|
|
1386
1361
|
/** For a host whose listing changed without the store: a preference flip. */
|
|
1387
1362
|
invalidateCatalog(): void;
|
|
@@ -1389,6 +1364,7 @@ declare class ReviewStore {
|
|
|
1389
1364
|
constructor(databasePath: string, providers: ReviewProviders);
|
|
1390
1365
|
private dataVersion;
|
|
1391
1366
|
private currentVersions;
|
|
1367
|
+
private currentDeletions;
|
|
1392
1368
|
private refreshExternalChanges;
|
|
1393
1369
|
/** Reader progress never creates a document version or authoring event. */
|
|
1394
1370
|
viewedCoverage(reviewId: string): Map<string, {
|
|
@@ -1431,6 +1407,10 @@ declare class ReviewStore {
|
|
|
1431
1407
|
resetServerId(): string;
|
|
1432
1408
|
/** The 404 check alone, without loading a snapshot. */
|
|
1433
1409
|
assertExists(id: string): void;
|
|
1410
|
+
assertWritable(id: string): void;
|
|
1411
|
+
private trashTime;
|
|
1412
|
+
private removePermanently;
|
|
1413
|
+
private purgeExpired;
|
|
1434
1414
|
read(id: string, version?: number): Snapshot;
|
|
1435
1415
|
setDiffStats(pins: Pins, stats: NonNullable<ReviewApiSummary["diffStats"]>, mode?: "structural" | "textual"): void;
|
|
1436
1416
|
/** Managed records are discoverable even if their preparation stamp was lost. */
|
|
@@ -1465,14 +1445,15 @@ declare class ReviewStore {
|
|
|
1465
1445
|
private startPullRequest;
|
|
1466
1446
|
/** Reviews whose PR is this one, newest version first. Summaries only. */
|
|
1467
1447
|
private reviewsForPullRequest;
|
|
1448
|
+
private assertReusableReview;
|
|
1468
1449
|
/** The answer to a create that found its PR's review. Its target stays:
|
|
1469
1450
|
* moving it would silently point existing links at different code. */
|
|
1470
1451
|
private existingReview;
|
|
1471
1452
|
private commitCommand;
|
|
1472
1453
|
private assertMutation;
|
|
1473
1454
|
private notify;
|
|
1474
|
-
/**
|
|
1475
|
-
|
|
1455
|
+
/** Viewing a review in Trash does not restore it. */
|
|
1456
|
+
trashedIds(): string[];
|
|
1476
1457
|
has(reviewId: string): boolean;
|
|
1477
1458
|
private validateExternal;
|
|
1478
1459
|
}
|
|
@@ -1502,15 +1483,15 @@ declare class ReviewWorkspaces {
|
|
|
1502
1483
|
private closed;
|
|
1503
1484
|
private readonly ownerId;
|
|
1504
1485
|
constructor(databasePath: string, store: ReviewStore);
|
|
1505
|
-
private
|
|
1486
|
+
private trashed?;
|
|
1506
1487
|
private readonly releasing;
|
|
1507
1488
|
/**
|
|
1508
|
-
* Frees a newly
|
|
1489
|
+
* Frees a newly trashed review's checkouts to save disk. The review itself
|
|
1509
1490
|
* stays; reopening it rebuilds them. Checkouts rebuilt by peeking at a
|
|
1510
|
-
*
|
|
1491
|
+
* trashed review are kept until the next startup or move to Trash, since
|
|
1511
1492
|
* the Desktop's canvas tabs and source windows may still show them.
|
|
1512
1493
|
*/
|
|
1513
|
-
private
|
|
1494
|
+
private releaseTrashed;
|
|
1514
1495
|
private repositoryDirs;
|
|
1515
1496
|
/** Resolves once no release of the review is pending, so an ensure cannot race it. */
|
|
1516
1497
|
released(reviewId: string): Promise<void>;
|
|
@@ -1617,7 +1598,7 @@ declare class LocalReviewData {
|
|
|
1617
1598
|
blobReaderIdleTimeoutMs?: number;
|
|
1618
1599
|
workspaceDatabase?: string;
|
|
1619
1600
|
manageWorkspaces?: boolean;
|
|
1620
|
-
|
|
1601
|
+
subscribe?: typeof subscribe;
|
|
1621
1602
|
/** gh, git and GitHub API access for pull request targets. */
|
|
1622
1603
|
pullRequests?: PullRequestDeps;
|
|
1623
1604
|
});
|
|
@@ -1866,6 +1847,8 @@ declare class SharedReviewStore {
|
|
|
1866
1847
|
private readonly attention;
|
|
1867
1848
|
private readonly listeners;
|
|
1868
1849
|
private catalogLoaded;
|
|
1850
|
+
private readonly purgeTimer;
|
|
1851
|
+
private purgePending;
|
|
1869
1852
|
private readonly downloads;
|
|
1870
1853
|
trackImport(job: Promise<void>): void;
|
|
1871
1854
|
close(): Promise<void>;
|
|
@@ -1874,6 +1857,7 @@ declare class SharedReviewStore {
|
|
|
1874
1857
|
private readonly jobs;
|
|
1875
1858
|
private readonly states;
|
|
1876
1859
|
constructor(root: string, fetchRepository?: typeof fetchPinnedRepository);
|
|
1860
|
+
private purgeExpired;
|
|
1877
1861
|
connect(store: ReviewStore, data: LocalReviewData): void;
|
|
1878
1862
|
has(id: string): boolean;
|
|
1879
1863
|
status(id: string): {
|
|
@@ -1887,9 +1871,11 @@ declare class SharedReviewStore {
|
|
|
1887
1871
|
assertReady(id: string): Promise<void>;
|
|
1888
1872
|
subscribe(listener: () => void): () => void;
|
|
1889
1873
|
load(): Promise<void>;
|
|
1874
|
+
assertWritable(id: string): void;
|
|
1890
1875
|
get(id: string): {
|
|
1891
1876
|
snapshot: {
|
|
1892
1877
|
reviewId: string;
|
|
1878
|
+
trashedAt: string | null;
|
|
1893
1879
|
pins: any;
|
|
1894
1880
|
target: any;
|
|
1895
1881
|
shared: {
|
|
@@ -1965,7 +1951,9 @@ declare class SharedReviewStore {
|
|
|
1965
1951
|
list(mode?: "structural" | "textual"): any;
|
|
1966
1952
|
readObject(id: string, objectId: string): Promise<NonSharedBuffer>;
|
|
1967
1953
|
removeLocal(id: string): Promise<void>;
|
|
1968
|
-
setAttention(id: string
|
|
1954
|
+
setAttention(id: string): Promise<void>;
|
|
1955
|
+
setLifecycle(id: string, state: "active" | "trash"): Promise<void>;
|
|
1956
|
+
private updateAttention;
|
|
1969
1957
|
import(origin: string, shareId: string, bundle: ShareBundle): Promise<string>;
|
|
1970
1958
|
read(id: string): Promise<ShareBundle>;
|
|
1971
1959
|
private readValidated;
|
package/dist/sharing/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as sharedReviewId, c as verifyShareRepository, i as SharedReviewStore, l as exportShare, n as ShareClient, o as validateShareBundle } from "../client-
|
|
1
|
+
import { a as sharedReviewId, c as verifyShareRepository, i as SharedReviewStore, l as exportShare, n as ShareClient, o as validateShareBundle } from "../client-DzcSt6pV.js";
|
|
2
2
|
export { ShareClient, SharedReviewStore, exportShare, sharedReviewId, validateShareBundle, verifyShareRepository };
|
|
@@ -29,6 +29,16 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
29
29
|
}) : target, mod));
|
|
30
30
|
var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
|
|
31
31
|
//#endregion
|
|
32
|
+
//#region src/review-api/input-error.ts
|
|
33
|
+
/** Deliberately safe to show to API clients, unlike filesystem/provider errors. */
|
|
34
|
+
var ReviewInputError = class extends Error {
|
|
35
|
+
status;
|
|
36
|
+
constructor(message, status = 400) {
|
|
37
|
+
super(message);
|
|
38
|
+
this.status = status;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
//#endregion
|
|
32
42
|
//#region ../../node_modules/protocols/lib/index.js
|
|
33
43
|
var require_lib$4 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
34
44
|
/**
|
|
@@ -3673,4 +3683,4 @@ var require_adapter = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
3673
3683
|
module.exports.checkSync = checkSync;
|
|
3674
3684
|
})))();
|
|
3675
3685
|
//#endregion
|
|
3676
|
-
export {
|
|
3686
|
+
export { ReviewInputError as C, __toESM as E, setLocalVcsCommandObserver as S, __require as T, readFileAtCommit as _, diffFileSummaries as a, resolveRevision as b, diffTrees as c, gitAt as d, gitCommonDir as f, parseGitRemote as g, listTrackedFilesAtCommit as h, diff as i, diffWorkingTree as l, listCommitRange as m, createBlobBatchReader as n, diffFileSummariesTrees as o, jjRevisionIsConflicted as p, detectLocalVcs as r, diffFileSummariesWorkingTree as s, LocalVcsToolsMissingError as t, git as u, resolveRepoContext as v, __commonJSMin as w, splitGitPatchFiles as x, resolveRepoContextSync as y };
|
package/dist/{stored-document-migration-BxZWQQjv.js → stored-document-migration-u4L_1VZa.js}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { C as ReviewInputError } from "./src-DiHP11l3.js";
|
|
1
2
|
import { f as isNumberValue, l as jsonValueSchema, m as isStringValue, n as isJsonObject } from "./src-X9phtB2j.js";
|
|
2
3
|
import "./src-WCbabvdS.js";
|
|
3
|
-
import { t as ReviewInputError } from "./input-error-OLgB_h31.js";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { fromMarkdown } from "mdast-util-from-markdown";
|
|
6
6
|
import { gfmFromMarkdown } from "mdast-util-gfm";
|
|
@@ -1305,7 +1305,8 @@ const storeSchema = z.strictObject({
|
|
|
1305
1305
|
collections: z.record(text$1, z.strictObject({
|
|
1306
1306
|
label: label$1,
|
|
1307
1307
|
key: label$1.optional(),
|
|
1308
|
-
fields: z.record(text$1, fieldSchema)
|
|
1308
|
+
fields: z.record(text$1, fieldSchema),
|
|
1309
|
+
source: anchorSchema.optional().describe("Where the table or collection is declared, such as its schema definition. Its use cases' tours start here.")
|
|
1309
1310
|
}))
|
|
1310
1311
|
});
|
|
1311
1312
|
const operationSchema = z.strictObject({
|
|
@@ -1447,39 +1448,12 @@ const trace_quote = {
|
|
|
1447
1448
|
})
|
|
1448
1449
|
};
|
|
1449
1450
|
//#endregion
|
|
1450
|
-
//#region src/tutorial-conversation.ts
|
|
1451
|
-
const tutorialAuthoringConversationSchema = z.strictObject({
|
|
1452
|
-
version: z.literal(1),
|
|
1453
|
-
title: z.string().trim().min(1),
|
|
1454
|
-
messages: z.array(z.strictObject({
|
|
1455
|
-
role: z.enum(["user", "assistant"]),
|
|
1456
|
-
body: z.string().trim().min(1)
|
|
1457
|
-
})).min(2)
|
|
1458
|
-
});
|
|
1459
|
-
//#endregion
|
|
1460
1451
|
//#region src/review-api/blocks/tutorial.ts
|
|
1461
|
-
const tutorialSchema = z.discriminatedUnion("kind", [
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
}),
|
|
1467
|
-
defineBlock("tutorial", {
|
|
1468
|
-
kind: z.literal("view"),
|
|
1469
|
-
view: z.enum([
|
|
1470
|
-
"review",
|
|
1471
|
-
"commits",
|
|
1472
|
-
"diff",
|
|
1473
|
-
"map"
|
|
1474
|
-
]),
|
|
1475
|
-
label: z.string()
|
|
1476
|
-
}),
|
|
1477
|
-
defineBlock("tutorial", {
|
|
1478
|
-
kind: z.literal("feature"),
|
|
1479
|
-
feature: z.literal("softwareMap"),
|
|
1480
|
-
children: z.array(z.lazy(() => blockSchema))
|
|
1481
|
-
})
|
|
1482
|
-
]);
|
|
1452
|
+
const tutorialSchema = z.discriminatedUnion("kind", [defineBlock("tutorial", { kind: z.literal("keymap") }), defineBlock("tutorial", {
|
|
1453
|
+
kind: z.literal("view"),
|
|
1454
|
+
view: z.literal("diff"),
|
|
1455
|
+
label: z.string()
|
|
1456
|
+
})]);
|
|
1483
1457
|
const tutorial = {
|
|
1484
1458
|
type: "tutorial",
|
|
1485
1459
|
schema: tutorialSchema
|
|
@@ -1709,12 +1683,17 @@ function documentReferences(document, { tolerant = false } = {}) {
|
|
|
1709
1683
|
})) : []
|
|
1710
1684
|
];
|
|
1711
1685
|
});
|
|
1712
|
-
if (element.type === "database_lens") return element.
|
|
1686
|
+
if (element.type === "database_lens") return [...Object.entries(element.stores).flatMap(([storeKey, store]) => Object.entries(store.collections).flatMap(([key, collection]) => collection.source ? select(collection.source, element.pins).map((source) => ({
|
|
1687
|
+
id: `${element.id}:schema:${storeKey}:${key}`,
|
|
1688
|
+
source,
|
|
1689
|
+
label: collection.label,
|
|
1690
|
+
peek: true
|
|
1691
|
+
})) : [])), ...element.useCases.flatMap((useCase) => useCase.operations.flatMap((operation) => select(operation.source, operation.pins ?? element.pins).map((source) => ({
|
|
1713
1692
|
id: operation.id,
|
|
1714
1693
|
source,
|
|
1715
1694
|
label: operation.label,
|
|
1716
1695
|
peek: true
|
|
1717
|
-
}))));
|
|
1696
|
+
}))))];
|
|
1718
1697
|
return [];
|
|
1719
1698
|
});
|
|
1720
1699
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { C as ReviewInputError } from "./src-DiHP11l3.js";
|
|
1
2
|
import { m as isStringValue, n as isJsonObject } from "./src-X9phtB2j.js";
|
|
2
|
-
import { n as callAuthoringTool, s as ReviewApiError, t as ToolText } from "./agent-client-
|
|
3
|
-
import { t as ReviewInputError } from "./input-error-OLgB_h31.js";
|
|
3
|
+
import { n as callAuthoringTool, s as ReviewApiError, t as ToolText } from "./agent-client-P3J4y8Zn.js";
|
|
4
4
|
//#region src/review-api/public-tools.ts
|
|
5
5
|
function publicDescription(text) {
|
|
6
6
|
return text.replace(/\breview_(\w+)/g, "session_$1").replace(/\breviewId\b/g, "sessionId").replace(/\bReview\b/g, "Whiteboard").replace("The result carries review,", "The result carries session,");
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The scratchpad is one document in Whiteboard that is not a session for any change. It has no target, base, head or lifecycle. You draw on it the way you would sketch an explanation on a whiteboard: a short paragraph, a sequence or flow diagram, a call tree, a code peek, and the smallest view that makes the point. The user reads it in the app and copies blocks back to you.
|
|
4
4
|
|
|
5
|
-
Its id is fixed: `scratchpad`. While it is turned on in Whiteboard Settings it always exists; never create, rename,
|
|
5
|
+
Its id is fixed: `scratchpad`. While it is turned on in Whiteboard Settings it always exists; never create, rename, trash, delete or share it.
|
|
6
6
|
|
|
7
7
|
## When to draw here
|
|
8
8
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dev.fast/whiteboard",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5-preview.20261013.109",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
"@hono/node-server": "2.0.12",
|
|
47
47
|
"@img/sharp-wasm32": "0.35.5",
|
|
48
48
|
"@modelcontextprotocol/sdk": "1.31.0",
|
|
49
|
+
"@parcel/watcher": "2.6.0",
|
|
49
50
|
"commander": "14.0.3",
|
|
50
51
|
"fuzzysort": "4.0.2",
|
|
51
52
|
"hono": "4.13.7",
|
|
@@ -59,7 +60,7 @@
|
|
|
59
60
|
"sharp": "0.35.5",
|
|
60
61
|
"smol-toml": "1.9.0",
|
|
61
62
|
"zod": "4.6.5",
|
|
62
|
-
"@dev.fast/diffr": "0.1.
|
|
63
|
+
"@dev.fast/diffr": "0.1.19"
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
|
65
66
|
"@dev.fast/local-vcs": "^0.1.0",
|
|
@@ -72,9 +73,9 @@
|
|
|
72
73
|
"typescript": "6.0.3",
|
|
73
74
|
"vitest": "4.1.11",
|
|
74
75
|
"@dev.fast/json": "0.0.0",
|
|
75
|
-
"@dev.fast/review-protocol": "0.0.0",
|
|
76
76
|
"@dev.fast/review-share-protocol": "0.1.2",
|
|
77
77
|
"@dev.fast/trace-core": "0.0.0",
|
|
78
|
+
"@dev.fast/review-protocol": "0.0.0",
|
|
78
79
|
"@dev.fast/trace-protocol": "0.5.0"
|
|
79
80
|
},
|
|
80
81
|
"engines": {
|
|
@@ -85,7 +86,7 @@
|
|
|
85
86
|
"repo": "devdotfast/review",
|
|
86
87
|
"docs": "packages/review/instructions/authoring.md"
|
|
87
88
|
},
|
|
88
|
-
"gitHead": "
|
|
89
|
+
"gitHead": "a3d88565d0643e8a8f9e80f24a9b9d29b6a97e3d",
|
|
89
90
|
"scripts": {
|
|
90
91
|
"prebuild": "pnpm run build:workspace-deps",
|
|
91
92
|
"build": "node --max-old-space-size=8192 node_modules/tsdown/dist/run.mjs",
|
package/src/ask/agents.ts
CHANGED
|
@@ -52,6 +52,11 @@ interface AskAgentSpec {
|
|
|
52
52
|
* read-only mode and settings, when the reviewer bypasses permissions.
|
|
53
53
|
* Whiteboard also allows whatever it still asks. */
|
|
54
54
|
bypass?: AskAgentBypass;
|
|
55
|
+
/** A follow-up asked while it answers joins that turn, when it says it
|
|
56
|
+
* takes one. Only for an adapter that leaves a follow-up arriving as the
|
|
57
|
+
* turn ends to Whiteboard: Codex's starts a turn of its own instead,
|
|
58
|
+
* which Whiteboard does not see end, so its follow-ups wait their turn. */
|
|
59
|
+
steers?: boolean;
|
|
55
60
|
}
|
|
56
61
|
|
|
57
62
|
interface AskAgentMcp {
|
|
@@ -81,6 +86,7 @@ export const askAgents: Record<AskAgentId, AskAgentSpec> = {
|
|
|
81
86
|
executableEnv: "CLAUDE_CODE_EXECUTABLE",
|
|
82
87
|
},
|
|
83
88
|
signIn: "claude auth login",
|
|
89
|
+
steers: true,
|
|
84
90
|
// Plan mode would end each answer asking to leave it, and it blocks the
|
|
85
91
|
// Whiteboard tools that edit the review. Claude instead runs in its
|
|
86
92
|
// default mode without its file tools, and without bypass, so commands
|
package/src/ask/thread-state.ts
CHANGED
|
@@ -174,6 +174,9 @@ export const askUsageSchema = z.object({
|
|
|
174
174
|
|
|
175
175
|
export type AskUsage = z.infer<typeof askUsageSchema>;
|
|
176
176
|
|
|
177
|
+
/** A follow-up waiting for the turn under way to end. */
|
|
178
|
+
const askQueuedSchema = z.object({ id: z.string(), text: z.string() });
|
|
179
|
+
|
|
177
180
|
const statusSchema = z.enum([
|
|
178
181
|
"starting",
|
|
179
182
|
"running",
|
|
@@ -209,6 +212,9 @@ export const askThreadStateSchema = z.object({
|
|
|
209
212
|
title: z.string().optional(),
|
|
210
213
|
selection: z.object({ title: z.string(), quote: z.string().optional() }),
|
|
211
214
|
entries: z.array(askEntrySchema),
|
|
215
|
+
/** Follow-ups asked while the agent answered, which it could not take
|
|
216
|
+
* then: each goes as its own question once the turn ends. */
|
|
217
|
+
queued: z.array(askQueuedSchema).optional(),
|
|
212
218
|
});
|
|
213
219
|
|
|
214
220
|
export type AskEntry = z.infer<typeof askEntrySchema>;
|
|
@@ -228,6 +234,8 @@ export const askChangeSchema = z.discriminatedUnion("type", [
|
|
|
228
234
|
accepts: askAcceptsSchema.optional(),
|
|
229
235
|
usage: askUsageSchema.optional(),
|
|
230
236
|
title: z.string().optional(),
|
|
237
|
+
/** Replaces the queue; empty clears it. */
|
|
238
|
+
queued: z.array(askQueuedSchema).optional(),
|
|
231
239
|
/** `null` clears the error; absent leaves it. */
|
|
232
240
|
error: z.string().nullable().optional(),
|
|
233
241
|
/** `null` clears it; absent leaves it. */
|
|
@@ -271,7 +279,12 @@ export function applyAskChange(
|
|
|
271
279
|
): AskThreadState {
|
|
272
280
|
switch (change.type) {
|
|
273
281
|
case "set": {
|
|
274
|
-
const {
|
|
282
|
+
const {
|
|
283
|
+
error: _error,
|
|
284
|
+
signIn: _signIn,
|
|
285
|
+
queued: _queued,
|
|
286
|
+
...rest
|
|
287
|
+
} = state;
|
|
275
288
|
|
|
276
289
|
const next: AskThreadState = {
|
|
277
290
|
...rest,
|
|
@@ -295,6 +308,9 @@ export function applyAskChange(
|
|
|
295
308
|
const title = change.title ?? state.title;
|
|
296
309
|
|
|
297
310
|
if (title) next.title = title;
|
|
311
|
+
const queued = change.queued ?? state.queued;
|
|
312
|
+
|
|
313
|
+
if (queued?.length) next.queued = queued;
|
|
298
314
|
|
|
299
315
|
// Absent keeps the error, null clears it, a message replaces it.
|
|
300
316
|
const error = change.error === undefined ? state.error : change.error;
|