@dev.fast/whiteboard 0.4.1-preview.20261031.144 → 0.5.0
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-DbtsNr_c.js → account-alias-Bw3PT3Qo.js} +3 -3
- package/dist/agent-cli-B8KBHuh_.js +2 -0
- package/dist/{agent-cli-DPt9w5-8.js → agent-cli-kHRrwO4n.js} +6 -6
- package/dist/{agent-client-CXXjD60Q.js → agent-client-CMacGbMp.js} +3 -3
- package/dist/{authoring-tools-BEGW2s0A.js → authoring-tools-CiLy46kh.js} +1 -1
- package/dist/{background-server-Cw7lddwb.js → background-server-BLNHbksB.js} +1 -1
- package/dist/{background-server-D_4Xt3fF.js → background-server-eZWXoVcI.js} +2 -2
- package/dist/build-info.json +1 -1
- package/dist/{cli-SDWXOZPY.js → cli-Bxmiqutp.js} +35 -2
- package/dist/{cli-runner-aO7Bw1Bn.js → cli-runner-DQPuu7kJ.js} +26 -17
- package/dist/cli.js +2 -2
- package/dist/{fuzzy-match-DRhI0DDn.js → fuzzy-match-DZjeOaPY.js} +2 -2
- package/dist/{headless-host-CgxnmRir.js → headless-host-B4r0s1ks.js} +1 -1
- package/dist/{headless-host-s4A3qcsl.js → headless-host-Dl2KZ9IT.js} +88 -26
- package/dist/{import-Dnbujw7d.js → import-YAIU6rB0.js} +3 -3
- package/dist/{local-data-G2I-77FX.js → local-data-C58vzLZR.js} +3 -3
- package/dist/{mcp-tqD6Fwvy.js → mcp-COYWiGVn.js} +3 -3
- package/dist/{profile-i2n1HdIg.js → profile--BYIjPkc.js} +1 -1
- package/dist/profile-BjcXi-oH.js +2 -0
- package/dist/{remote-attach-BsOO_ER4.js → remote-attach-C1prLjmj.js} +3 -3
- package/dist/{remote-language-server-AamAHhw_.js → remote-language-server-z3rdHcLL.js} +1 -1
- package/dist/{remote-uninstall-BH2ovwP1.js → remote-uninstall-B3Slwor1.js} +3 -3
- package/dist/{request-origin-Cr1tW4Vl.js → request-origin-B3_XI2VA.js} +7 -2
- package/dist/{review-app-launcher-1tcH84u6.js → review-app-launcher-BZEbDKuK.js} +2 -2
- package/dist/{review-telemetry-CzYSJMMy.js → review-telemetry-x8u-9EZb.js} +2 -2
- package/dist/server/desktop-host.js +10 -10
- package/dist/{server-discovery-nLX2SH_v.js → server-discovery-WmuFl2S3.js} +1 -1
- package/dist/sharing/index.d.ts +2 -0
- package/dist/sharing/index.js +1 -1
- package/dist/{src-Coec7jLU.js → src-DLWol7GZ.js} +7 -0
- package/dist/{stored-document-migration-Ca9BWqEF.js → stored-document-migration-iwIQ4l5G.js} +1 -1
- package/dist/{thread-state-DosGpp3S.js → thread-state-B7L1mpN_.js} +1 -1
- package/dist/{tool-failure-CwTgI76j.js → tool-failure-RLR8m9hq.js} +3 -3
- package/package.json +9 -9
- package/src/cli-runner.ts +29 -0
- package/src/sharing/cli.ts +59 -0
- package/src/sharing/file.ts +52 -0
- package/src/sharing/host.ts +131 -37
- package/src/sharing/import.ts +1 -1
- package/src/ui-telemetry-events.ts +5 -0
- package/dist/agent-cli-BL1HiH5g.js +0 -2
- package/dist/profile-Bw0hDDNd.js +0 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as jsonNumber, c as jsonString, i as jsonBoolean, n as isJsonObject } from "./src-X9phtB2j.js";
|
|
2
2
|
import { X as SELECTION_UNAVAILABLE_REASONS } from "./src-B2b8cCoI.js";
|
|
3
|
-
import { _ as REVIEW_DIFF_LAYOUTS, g as REVIEW_COLOR_THEME_KINDS, v as REVIEW_DIFF_LAYOUT_SCOPES } from "./src-
|
|
4
|
-
import { n as askAgentIds } from "./thread-state-
|
|
3
|
+
import { _ as REVIEW_DIFF_LAYOUTS, g as REVIEW_COLOR_THEME_KINDS, v as REVIEW_DIFF_LAYOUT_SCOPES } from "./src-DLWol7GZ.js";
|
|
4
|
+
import { n as askAgentIds } from "./thread-state-B7L1mpN_.js";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
//#region src/telemetry-clean-text.ts
|
|
7
7
|
const USER_DATA_REGEXES = [
|
|
@@ -232,6 +232,7 @@ const SETTING_NAME = [
|
|
|
232
232
|
"keymap",
|
|
233
233
|
"software_map_enabled",
|
|
234
234
|
"show_release_notes",
|
|
235
|
+
"update_pill",
|
|
235
236
|
"diffr_config",
|
|
236
237
|
"theme",
|
|
237
238
|
"diff_theme",
|
|
@@ -499,6 +500,10 @@ const UI_TELEMETRY_EVENTS = {
|
|
|
499
500
|
event: "review_source_tree_opened",
|
|
500
501
|
properties: { via: SOURCE_TREE_OPENED_VIA }
|
|
501
502
|
},
|
|
503
|
+
whiteboard_file_exported: {
|
|
504
|
+
event: "review_whiteboard_file_exported",
|
|
505
|
+
properties: {}
|
|
506
|
+
},
|
|
502
507
|
diff_layout_changed: {
|
|
503
508
|
event: "review_diff_layout_changed",
|
|
504
509
|
properties: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { o as parseReviewVerbResponse } from "./src-
|
|
2
|
-
import { b as selectReviewInstance, m as healthyReviewInstance, v as reviewInstanceStartHint, y as reviewInstanceUnavailable } from "./server-discovery-
|
|
1
|
+
import { o as parseReviewVerbResponse } from "./src-DLWol7GZ.js";
|
|
2
|
+
import { b as selectReviewInstance, m as healthyReviewInstance, v as reviewInstanceStartHint, y as reviewInstanceUnavailable } from "./server-discovery-WmuFl2S3.js";
|
|
3
3
|
import { closeSync, existsSync, fstatSync, mkdtempSync, openSync, readSync } from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { homedir, tmpdir } from "node:os";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { c as jsonString, l as jsonValueSchema, o as jsonObject, u as parseJsonText } from "./src-X9phtB2j.js";
|
|
2
|
-
import "./src-
|
|
2
|
+
import "./src-DLWol7GZ.js";
|
|
3
3
|
import "./review-home-paths-LdGS4SpR.js";
|
|
4
4
|
import { F as writeFileAtomic, N as devReviewHome, j as withFileLock, k as processIsAlive } from "./s3-config-CjcLyFV5.js";
|
|
5
5
|
import { i as readReviewPackageVersion, t as findReviewPackageRoot } from "./package-paths-Cg6fnaGp.js";
|
|
6
|
-
import "./request-origin-
|
|
6
|
+
import "./request-origin-B3_XI2VA.js";
|
|
7
7
|
import { createHmac, randomUUID } from "node:crypto";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
import { existsSync, readFileSync, rmSync } from "node:fs";
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { S as splitGitPatchFiles, a as diff, o as diffFileSummaries } from "../src-Y30gweiK.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 {
|
|
4
|
+
import { _ as readBoundedStream, d as legacyModeSchema, g as StreamLimitError } from "../import-YAIU6rB0.js";
|
|
5
5
|
import { ot as ReviewInputError, y as resourceReferences } from "../src-B2b8cCoI.js";
|
|
6
|
-
import { A as ReviewGatewayHostSchema, D as ReviewConnectRequestSchema, P as reviewDiffrSummarizerInputSchema, d as ReviewBugReportRequestSchema, f as parseReviewBugReportResponse, m as REVIEW_CLIENT_REMOTE, p as REVIEW_CLIENT_HEADER, r as parseReviewDesktopVerbFrame, s as parseZod, t as parseReviewCliInstallApplyRequest, u as ReviewBugReportMetaV2Schema, y as REVIEW_HOST_HEADER } from "../src-
|
|
6
|
+
import { A as ReviewGatewayHostSchema, D as ReviewConnectRequestSchema, P as reviewDiffrSummarizerInputSchema, d as ReviewBugReportRequestSchema, f as parseReviewBugReportResponse, m as REVIEW_CLIENT_REMOTE, p as REVIEW_CLIENT_HEADER, r as parseReviewDesktopVerbFrame, s as parseZod, t as parseReviewCliInstallApplyRequest, u as ReviewBugReportMetaV2Schema, y as REVIEW_HOST_HEADER } from "../src-DLWol7GZ.js";
|
|
7
7
|
import { i as reviewInstanceDiscoveryPath, o as reviewLegacyDiscoveryPath } from "../review-home-paths-LdGS4SpR.js";
|
|
8
|
-
import { p as pullRequestProvider } from "../stored-document-migration-
|
|
8
|
+
import { p as pullRequestProvider } from "../stored-document-migration-iwIQ4l5G.js";
|
|
9
9
|
import { L as writePrivateJsonAtomic, N as devReviewHome } from "../s3-config-CjcLyFV5.js";
|
|
10
10
|
import { t as errorMessage } from "../error-message-OtiDonty.js";
|
|
11
11
|
import { i as readReviewPackageVersion, t as findReviewPackageRoot } from "../package-paths-Cg6fnaGp.js";
|
|
12
|
-
import { _ as reviewInstanceIdentity, u as REVIEW_INSTANCE_ENV } from "../server-discovery-
|
|
13
|
-
import { t as openReviewProfile } from "../profile
|
|
14
|
-
import { r as reviewTelemetryChannel, t as ReviewTelemetry } from "../review-telemetry-
|
|
15
|
-
import { l as REVIEW_TELEMETRY_TABS } from "../request-origin-
|
|
16
|
-
import { c as removeLegacyReviewSkills, d as skipCliInstall, h as detectConnectAgents, i as finishCliInstallUpdate, l as resetCliInstall, m as connectAgent, n as applyCliInstall, o as pathShimPath, r as declineCliInstall, s as removeCliInstall, t as aliasInstallationToAccount, u as resolveCliInstallStatus } from "../account-alias-
|
|
17
|
-
import { C as setDiffrConfigValue, S as saveDiffrSummarizer, T as cliAskTools, _ as HttpJsonError, a as drainServerCrashReport, b as migrateDiffrConfig, c as answerErrorsAsJson, d as captureSanitizedUiTelemetry, f as clientErrorsForSession, g as DEFAULT_MAX_REQUEST_BYTES, h as readBoundedRequestJson, l as createWhiteboardCore, m as createNodeRequestListener, o as installProcessErrorTelemetry, p as recordClientError, r as takeOverServerHome, s as serverCrashReportPath, u as serverJson, v as ReviewServerError, w as testDiffrSummarizer, x as readDiffrConfig, y as GlobalReviewDesktopVerbRelay } from "../headless-host-
|
|
18
|
-
import { s as readQuerySchemas } from "../authoring-tools-
|
|
12
|
+
import { _ as reviewInstanceIdentity, u as REVIEW_INSTANCE_ENV } from "../server-discovery-WmuFl2S3.js";
|
|
13
|
+
import { t as openReviewProfile } from "../profile--BYIjPkc.js";
|
|
14
|
+
import { r as reviewTelemetryChannel, t as ReviewTelemetry } from "../review-telemetry-x8u-9EZb.js";
|
|
15
|
+
import { l as REVIEW_TELEMETRY_TABS } from "../request-origin-B3_XI2VA.js";
|
|
16
|
+
import { c as removeLegacyReviewSkills, d as skipCliInstall, h as detectConnectAgents, i as finishCliInstallUpdate, l as resetCliInstall, m as connectAgent, n as applyCliInstall, o as pathShimPath, r as declineCliInstall, s as removeCliInstall, t as aliasInstallationToAccount, u as resolveCliInstallStatus } from "../account-alias-Bw3PT3Qo.js";
|
|
17
|
+
import { C as setDiffrConfigValue, S as saveDiffrSummarizer, T as cliAskTools, _ as HttpJsonError, a as drainServerCrashReport, b as migrateDiffrConfig, c as answerErrorsAsJson, d as captureSanitizedUiTelemetry, f as clientErrorsForSession, g as DEFAULT_MAX_REQUEST_BYTES, h as readBoundedRequestJson, l as createWhiteboardCore, m as createNodeRequestListener, o as installProcessErrorTelemetry, p as recordClientError, r as takeOverServerHome, s as serverCrashReportPath, u as serverJson, v as ReviewServerError, w as testDiffrSummarizer, x as readDiffrConfig, y as GlobalReviewDesktopVerbRelay } from "../headless-host-Dl2KZ9IT.js";
|
|
18
|
+
import { s as readQuerySchemas } from "../authoring-tools-CiLy46kh.js";
|
|
19
19
|
import crypto, { createHash, randomBytes } from "node:crypto";
|
|
20
20
|
import { z } from "zod";
|
|
21
21
|
import { Agent, request } from "undici";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as jsonNumber, n as isJsonObject, s as jsonProperty, u as parseJsonText } from "./src-X9phtB2j.js";
|
|
2
|
-
import { n as parseReviewDesktopDiscovery } from "./src-
|
|
2
|
+
import { n as parseReviewDesktopDiscovery } from "./src-DLWol7GZ.js";
|
|
3
3
|
import { a as reviewInstancesDir, o as reviewLegacyDiscoveryPath, r as reviewDevInstanceKey, t as reviewDefaultInstancePath } from "./review-home-paths-LdGS4SpR.js";
|
|
4
4
|
import { M as DEV_REVIEW_HOME_ENV, N as devReviewHome, k as processIsAlive } from "./s3-config-CjcLyFV5.js";
|
|
5
5
|
import { z } from "zod";
|
package/dist/sharing/index.d.ts
CHANGED
|
@@ -635,6 +635,8 @@ interface ActivityPresence {
|
|
|
635
635
|
focus?: ActivityFocus;
|
|
636
636
|
/** Where it last wrote; absent until its first attributed write. */
|
|
637
637
|
surface?: ActivitySurface;
|
|
638
|
+
/** Blocks reserved for it; others' edits on them or inside them are refused. */
|
|
639
|
+
hold?: string[];
|
|
638
640
|
}
|
|
639
641
|
interface ActivitySnapshot {
|
|
640
642
|
/** Live presences. */
|
package/dist/sharing/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { c as
|
|
1
|
+
import { c as ShareClient, i as validateShareBundle, l as exportShare, r as shareKey, t as importShare } from "../import-YAIU6rB0.js";
|
|
2
2
|
export { ShareClient, exportShare, importShare, shareKey, validateShareBundle };
|
|
@@ -827,6 +827,13 @@ const ReviewVerbRequestSchema = z.discriminatedUnion("name", [
|
|
|
827
827
|
reviewId: apiReviewIdSchema,
|
|
828
828
|
title: requiredString$1
|
|
829
829
|
})
|
|
830
|
+
}),
|
|
831
|
+
z.strictObject({
|
|
832
|
+
name: z.literal("exportReviewFile"),
|
|
833
|
+
args: z.strictObject({
|
|
834
|
+
reviewId: apiReviewIdSchema,
|
|
835
|
+
version: z.number().int().nonnegative().optional()
|
|
836
|
+
})
|
|
830
837
|
})
|
|
831
838
|
]);
|
|
832
839
|
const ReviewVerbResponseSchema = z.discriminatedUnion("ok", [z.strictObject({
|
package/dist/{stored-document-migration-Ca9BWqEF.js → stored-document-migration-iwIQ4l5G.js}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { C as renderVcsArgs, v as parseGitRemote, w as runVcs } from "./src-Y30gweiK.js";
|
|
2
2
|
import { d as isBooleanValue, f as isNumberValue, l as jsonValueSchema, m as isStringValue, n as isJsonObject } from "./src-X9phtB2j.js";
|
|
3
3
|
import { C as respellLinks, H as lensTargetsSchema, W as label, at as unionIntervals, et as formatAnchor, ot as ReviewInputError } from "./src-B2b8cCoI.js";
|
|
4
|
-
import "./src-
|
|
4
|
+
import "./src-DLWol7GZ.js";
|
|
5
5
|
import "./review-home-paths-LdGS4SpR.js";
|
|
6
6
|
import { t as errorMessage } from "./error-message-OtiDonty.js";
|
|
7
7
|
import { randomUUID } from "node:crypto";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { M as ReviewSelectedDiffSchema, T as ReviewApiSelectionSourceSchema } from "./src-
|
|
1
|
+
import { M as ReviewSelectedDiffSchema, T as ReviewApiSelectionSourceSchema } from "./src-DLWol7GZ.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { stat } from "node:fs/promises";
|
|
4
4
|
//#region src/fs-utils.ts
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { m as isStringValue, n as isJsonObject, u as parseJsonText } from "./src-X9phtB2j.js";
|
|
2
2
|
import { M as checkReferences, j as blocks, ot as ReviewInputError } from "./src-B2b8cCoI.js";
|
|
3
|
-
import { l as boardTitle } from "./src-
|
|
3
|
+
import { l as boardTitle } from "./src-DLWol7GZ.js";
|
|
4
4
|
import "./review-home-paths-LdGS4SpR.js";
|
|
5
|
-
import { n as callAuthoringTool, s as ReviewApiError, t as ToolText } from "./agent-client-
|
|
5
|
+
import { n as callAuthoringTool, s as ReviewApiError, t as ToolText } from "./agent-client-CMacGbMp.js";
|
|
6
6
|
import { N as devReviewHome } from "./s3-config-CjcLyFV5.js";
|
|
7
7
|
import { t as findReviewPackageRoot } from "./package-paths-Cg6fnaGp.js";
|
|
8
|
-
import { m as isMissingFileError } from "./thread-state-
|
|
8
|
+
import { m as isMissingFileError } from "./thread-state-B7L1mpN_.js";
|
|
9
9
|
import { createHash } from "node:crypto";
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dev.fast/whiteboard",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"@agentclientprotocol/claude-agent-acp": "0.84.0",
|
|
43
43
|
"@agentclientprotocol/codex-acp": "2.0.0",
|
|
44
44
|
"@agentclientprotocol/sdk": "1.5.1",
|
|
45
|
-
"@hono/node-server": "2.
|
|
45
|
+
"@hono/node-server": "2.1.5",
|
|
46
46
|
"@img/sharp-wasm32": "0.35.5",
|
|
47
47
|
"@modelcontextprotocol/server": "2.3.1",
|
|
48
48
|
"@parcel/watcher": "2.6.0",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"semver": "7.8.5",
|
|
60
60
|
"sharp": "0.35.5",
|
|
61
61
|
"smol-toml": "1.9.0",
|
|
62
|
-
"undici": "7.
|
|
62
|
+
"undici": "7.30.1",
|
|
63
63
|
"yauzl": "3.4.0",
|
|
64
64
|
"zod": "4.6.6",
|
|
65
65
|
"@dev.fast/diffr": "0.1.23"
|
|
@@ -75,13 +75,13 @@
|
|
|
75
75
|
"tsdown": "0.22.14",
|
|
76
76
|
"tsx": "4.21.0",
|
|
77
77
|
"typescript": "6.0.3",
|
|
78
|
-
"vitest": "4.1.
|
|
78
|
+
"vitest": "4.1.12",
|
|
79
79
|
"@dev.fast/json": "0.0.0",
|
|
80
|
-
"@dev.fast/review-share-protocol": "0.3.0",
|
|
81
|
-
"@dev.fast/review-protocol": "0.0.0",
|
|
82
80
|
"@dev.fast/trace-core": "0.0.0",
|
|
83
|
-
"@dev.fast/
|
|
84
|
-
"@dev.fast/whiteboard-document": "0.2.
|
|
81
|
+
"@dev.fast/review-share-protocol": "0.3.1",
|
|
82
|
+
"@dev.fast/whiteboard-document": "0.2.1",
|
|
83
|
+
"@dev.fast/review-protocol": "0.0.0",
|
|
84
|
+
"@dev.fast/trace-protocol": "0.5.0"
|
|
85
85
|
},
|
|
86
86
|
"engines": {
|
|
87
87
|
"node": ">=24 <25"
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"repo": "devdotfast/review",
|
|
92
92
|
"docs": "packages/review/instructions/authoring.md"
|
|
93
93
|
},
|
|
94
|
-
"gitHead": "
|
|
94
|
+
"gitHead": "b3f475d81a1ec90ba0b8c597a19b5bf9221c158a",
|
|
95
95
|
"scripts": {
|
|
96
96
|
"prebuild": "pnpm run build:workspace-deps",
|
|
97
97
|
"build": "node --max-old-space-size=8192 node_modules/tsdown/dist/run.mjs",
|
package/src/cli-runner.ts
CHANGED
|
@@ -1191,6 +1191,35 @@ export async function runReviewCli(input: ReviewCliInput): Promise<number> {
|
|
|
1191
1191
|
});
|
|
1192
1192
|
});
|
|
1193
1193
|
|
|
1194
|
+
configureJsonOutput(
|
|
1195
|
+
program
|
|
1196
|
+
.command("export")
|
|
1197
|
+
.description("Write a review snapshot as a .whiteboard file"),
|
|
1198
|
+
"plain",
|
|
1199
|
+
)
|
|
1200
|
+
.option("--review <id>", "review ID")
|
|
1201
|
+
.option("--version <number>", "Saved version to export")
|
|
1202
|
+
.option(
|
|
1203
|
+
"--out <path>",
|
|
1204
|
+
"File to write, or - for stdout; defaults to <title>.whiteboard here",
|
|
1205
|
+
)
|
|
1206
|
+
.action(
|
|
1207
|
+
async (options: {
|
|
1208
|
+
review?: string;
|
|
1209
|
+
version?: string;
|
|
1210
|
+
out?: string;
|
|
1211
|
+
json?: boolean;
|
|
1212
|
+
}) => {
|
|
1213
|
+
const { runExportCli } = await import("./sharing/cli.js");
|
|
1214
|
+
state.exitCode = await runExportCli({
|
|
1215
|
+
...input,
|
|
1216
|
+
...options,
|
|
1217
|
+
cwd,
|
|
1218
|
+
env: authoringEnv(),
|
|
1219
|
+
});
|
|
1220
|
+
},
|
|
1221
|
+
);
|
|
1222
|
+
|
|
1194
1223
|
// Hosted trace store login. Logging in authenticates a user; it selects
|
|
1195
1224
|
// no storage by itself.
|
|
1196
1225
|
configureJsonOutput(
|
package/src/sharing/cli.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
2
4
|
import type { Writable } from "node:stream";
|
|
3
5
|
|
|
4
6
|
import { connectReviewApi } from "@review/review-api/agent-client.js";
|
|
@@ -81,3 +83,60 @@ export async function runShareCli(input: {
|
|
|
81
83
|
return 1;
|
|
82
84
|
}
|
|
83
85
|
}
|
|
86
|
+
|
|
87
|
+
const exportSchema = z.strictObject({
|
|
88
|
+
filename: z.string().min(1),
|
|
89
|
+
text: z.string(),
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
export async function runExportCli(input: {
|
|
93
|
+
review?: string;
|
|
94
|
+
version?: string;
|
|
95
|
+
out?: string;
|
|
96
|
+
json?: boolean;
|
|
97
|
+
cwd: string;
|
|
98
|
+
env?: NodeJS.ProcessEnv;
|
|
99
|
+
stdout: Writable;
|
|
100
|
+
stderr: Writable;
|
|
101
|
+
}) {
|
|
102
|
+
try {
|
|
103
|
+
if (!input.review) throw new Error("Use whiteboard export --review <id>.");
|
|
104
|
+
|
|
105
|
+
const client = await connectReviewApi(input.env);
|
|
106
|
+
|
|
107
|
+
const result = exportSchema.parse(
|
|
108
|
+
await client.post("/sharing/export", {
|
|
109
|
+
reviewId: input.review,
|
|
110
|
+
version:
|
|
111
|
+
input.version === undefined
|
|
112
|
+
? undefined
|
|
113
|
+
: z.number().int().nonnegative().parse(Number(input.version)),
|
|
114
|
+
}),
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
if (input.out === "-") {
|
|
118
|
+
input.stdout.write(result.text);
|
|
119
|
+
|
|
120
|
+
return 0;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const file = path.resolve(input.cwd, input.out ?? result.filename);
|
|
124
|
+
await mkdir(path.dirname(file), { recursive: true });
|
|
125
|
+
await writeFile(file, result.text);
|
|
126
|
+
input.stdout.write(
|
|
127
|
+
input.json ? JSON.stringify({ path: file }) + "\n" : file + "\n",
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
return 0;
|
|
131
|
+
} catch (error) {
|
|
132
|
+
const message = error instanceof Error ? error.message : "Export failed.";
|
|
133
|
+
|
|
134
|
+
if (input.json)
|
|
135
|
+
input.stdout.write(
|
|
136
|
+
JSON.stringify({ error: { code: "export_failed", message } }) + "\n",
|
|
137
|
+
);
|
|
138
|
+
input.stderr.write(message + "\n");
|
|
139
|
+
|
|
140
|
+
return 1;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
SHARE_FORMAT,
|
|
5
|
+
type ShareBundle,
|
|
6
|
+
shareBundleSchema,
|
|
7
|
+
} from "@dev.fast/review-share-protocol";
|
|
8
|
+
import { ReviewInputError } from "@dev.fast/whiteboard-document";
|
|
9
|
+
import { slugify } from "@review/slug.js";
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
|
|
12
|
+
export const WHITEBOARD_FILE_EXTENSION = ".whiteboard";
|
|
13
|
+
|
|
14
|
+
const headerSchema = z.looseObject({ format: z.string() });
|
|
15
|
+
|
|
16
|
+
export function whiteboardFileName(title: string): string {
|
|
17
|
+
return `${slugify(title) || "untitled"}${WHITEBOARD_FILE_EXTENSION}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function whiteboardFileText(bundle: ShareBundle): string {
|
|
21
|
+
return JSON.stringify(bundle, null, 2) + "\n";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function parseWhiteboardFile(text: string): ShareBundle {
|
|
25
|
+
let parsed: unknown;
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
parsed = JSON.parse(text);
|
|
29
|
+
} catch {
|
|
30
|
+
parsed = undefined;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const header = headerSchema.safeParse(parsed);
|
|
34
|
+
|
|
35
|
+
if (!header.success)
|
|
36
|
+
throw new ReviewInputError("This is not a Whiteboard file.", 400);
|
|
37
|
+
|
|
38
|
+
if (header.data.format !== SHARE_FORMAT)
|
|
39
|
+
throw new ReviewInputError(
|
|
40
|
+
"This file needs a different Whiteboard version.",
|
|
41
|
+
400,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
return shareBundleSchema.parse(parsed);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function whiteboardFileKey(text: string): string {
|
|
48
|
+
return createHash("sha256")
|
|
49
|
+
.update("whiteboard-file\0")
|
|
50
|
+
.update(text)
|
|
51
|
+
.digest("hex");
|
|
52
|
+
}
|
package/src/sharing/host.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
2
4
|
import { Writable } from "node:stream";
|
|
3
5
|
|
|
4
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
type ShareBundle,
|
|
8
|
+
parseShareLink,
|
|
9
|
+
shareIdSchema,
|
|
10
|
+
} from "@dev.fast/review-share-protocol";
|
|
5
11
|
import {
|
|
6
12
|
DEFAULT_STORE_ORIGIN,
|
|
7
13
|
clearStoreAuth,
|
|
@@ -11,7 +17,7 @@ import {
|
|
|
11
17
|
} from "@dev.fast/trace-core";
|
|
12
18
|
import { ReviewInputError } from "@dev.fast/whiteboard-document";
|
|
13
19
|
import type { LocalReviewData } from "@review/review-api/local-data.js";
|
|
14
|
-
import type { ReviewStore } from "@review/review-api/store.js";
|
|
20
|
+
import type { ReviewStore, Snapshot } from "@review/review-api/store.js";
|
|
15
21
|
import { readBoundedRequestJson } from "@review/server/hono-http.js";
|
|
16
22
|
import type { Hono } from "hono";
|
|
17
23
|
import { z } from "zod";
|
|
@@ -19,7 +25,18 @@ import { z } from "zod";
|
|
|
19
25
|
import { readSharingAuth } from "./auth.js";
|
|
20
26
|
import { ShareAuthError, ShareClient } from "./client.js";
|
|
21
27
|
import { exportShare, validateShareSources } from "./export.js";
|
|
22
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
parseWhiteboardFile,
|
|
30
|
+
whiteboardFileKey,
|
|
31
|
+
whiteboardFileName,
|
|
32
|
+
whiteboardFileText,
|
|
33
|
+
} from "./file.js";
|
|
34
|
+
import {
|
|
35
|
+
type ShareAttribution,
|
|
36
|
+
importShare,
|
|
37
|
+
needsRepository,
|
|
38
|
+
shareKey,
|
|
39
|
+
} from "./import.js";
|
|
23
40
|
import {
|
|
24
41
|
type cloneSharedRepository,
|
|
25
42
|
type fetchPinnedRepository,
|
|
@@ -58,8 +75,19 @@ interface SharingHostOptions extends SharingHostEvents {
|
|
|
58
75
|
fetch?: typeof fetch;
|
|
59
76
|
}
|
|
60
77
|
|
|
78
|
+
const importSchema = z.union([
|
|
79
|
+
z.strictObject({ url: z.string().max(2048) }),
|
|
80
|
+
z.strictObject({ path: z.string().min(1).max(4096) }),
|
|
81
|
+
]);
|
|
82
|
+
|
|
61
83
|
interface ImportStatus {
|
|
62
|
-
stage:
|
|
84
|
+
stage:
|
|
85
|
+
| "downloading"
|
|
86
|
+
| "reading"
|
|
87
|
+
| "fetching"
|
|
88
|
+
| "validating"
|
|
89
|
+
| "ready"
|
|
90
|
+
| "error";
|
|
63
91
|
/** The copy, once it is made. */
|
|
64
92
|
reviewId?: string;
|
|
65
93
|
error?: string;
|
|
@@ -170,23 +198,15 @@ export function mountSharingHost(
|
|
|
170
198
|
...(status.stage === "ready" && { title: store.read(reviewId).title }),
|
|
171
199
|
});
|
|
172
200
|
});
|
|
173
|
-
app.post("/sharing/import", async (context) => {
|
|
174
|
-
const { url } = z
|
|
175
|
-
.strictObject({ url: z.string().max(2048) })
|
|
176
|
-
.parse(await readBoundedRequestJson(context.req.raw));
|
|
177
|
-
|
|
178
|
-
const parsed = parseShareLink(url);
|
|
179
|
-
const account = await readStoreAuth();
|
|
180
201
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
)
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const id = shareKey(parsed.origin, parsed.capability);
|
|
202
|
+
const startImport = (
|
|
203
|
+
id: string,
|
|
204
|
+
initial: "downloading" | "reading",
|
|
205
|
+
load: () => Promise<{
|
|
206
|
+
bundle: ShareBundle;
|
|
207
|
+
attribution?: ShareAttribution;
|
|
208
|
+
}>,
|
|
209
|
+
) => {
|
|
190
210
|
const known = imports.get(id)?.stage;
|
|
191
211
|
|
|
192
212
|
// A failed import retries, and a deleted copy imports again.
|
|
@@ -195,16 +215,14 @@ export function mountSharingHost(
|
|
|
195
215
|
|
|
196
216
|
const status: ImportStatus = copy
|
|
197
217
|
? { stage: "ready", reviewId: copy }
|
|
198
|
-
: { stage:
|
|
218
|
+
: { stage: initial };
|
|
199
219
|
|
|
200
220
|
imports.set(id, status);
|
|
201
221
|
|
|
202
222
|
if (!copy)
|
|
203
223
|
importing = importing
|
|
204
224
|
.then(async () => {
|
|
205
|
-
const { bundle, attribution } = await
|
|
206
|
-
parsed.origin,
|
|
207
|
-
).download(parsed.capability);
|
|
225
|
+
const { bundle, attribution } = await load();
|
|
208
226
|
|
|
209
227
|
status.reviewId = await importShare(
|
|
210
228
|
{
|
|
@@ -233,7 +251,53 @@ export function mountSharingHost(
|
|
|
233
251
|
|
|
234
252
|
const { reviewId: _reviewId, ...status } = imports.get(id)!;
|
|
235
253
|
|
|
236
|
-
return
|
|
254
|
+
return { reviewId: id, ...status };
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
app.post("/sharing/import", async (context) => {
|
|
258
|
+
const input = importSchema.parse(
|
|
259
|
+
await readBoundedRequestJson(context.req.raw),
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
if ("path" in input) {
|
|
263
|
+
if (!path.isAbsolute(input.path))
|
|
264
|
+
throw new ReviewInputError("Use an absolute file path.", 400);
|
|
265
|
+
|
|
266
|
+
const text = await readFile(input.path, "utf8").catch(() => {
|
|
267
|
+
throw new ReviewInputError(
|
|
268
|
+
`Could not read ${path.basename(input.path)}. Check that the file still exists and Whiteboard can open it.`,
|
|
269
|
+
400,
|
|
270
|
+
);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
return context.json(
|
|
274
|
+
startImport(whiteboardFileKey(text), "reading", async () => ({
|
|
275
|
+
bundle: parseWhiteboardFile(text),
|
|
276
|
+
})),
|
|
277
|
+
202,
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const parsed = parseShareLink(input.url);
|
|
282
|
+
const account = await readStoreAuth();
|
|
283
|
+
|
|
284
|
+
if (
|
|
285
|
+
parsed.origin !== DEFAULT_STORE_ORIGIN &&
|
|
286
|
+
parsed.origin !== account?.origin
|
|
287
|
+
)
|
|
288
|
+
throw new ReviewInputError(
|
|
289
|
+
"This share uses an untrusted service. Sign in to that service before opening its links.",
|
|
290
|
+
400,
|
|
291
|
+
);
|
|
292
|
+
|
|
293
|
+
return context.json(
|
|
294
|
+
startImport(
|
|
295
|
+
shareKey(parsed.origin, parsed.capability),
|
|
296
|
+
"downloading",
|
|
297
|
+
() => new ShareClient(parsed.origin).download(parsed.capability),
|
|
298
|
+
),
|
|
299
|
+
202,
|
|
300
|
+
);
|
|
237
301
|
});
|
|
238
302
|
}
|
|
239
303
|
|
|
@@ -247,11 +311,7 @@ export function mountSharingPublisher(
|
|
|
247
311
|
"readRepository" | "fetch" | "onPublished" | "onRevoked"
|
|
248
312
|
> = {},
|
|
249
313
|
) {
|
|
250
|
-
|
|
251
|
-
const input = publishSchema.parse(
|
|
252
|
-
await readBoundedRequestJson(context.req.raw),
|
|
253
|
-
);
|
|
254
|
-
|
|
314
|
+
const shareable = (input: z.infer<typeof publishSchema>) => {
|
|
255
315
|
const snapshot = store.read(input.reviewId, input.version);
|
|
256
316
|
|
|
257
317
|
if (snapshot.target?.kind === "worktree")
|
|
@@ -260,14 +320,11 @@ export function mountSharingPublisher(
|
|
|
260
320
|
);
|
|
261
321
|
|
|
262
322
|
validateShareSources(snapshot);
|
|
263
|
-
const account = await readSharingAuth();
|
|
264
323
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
"Set DEV_REVIEW_SHARE_TOKEN for CI, or run whiteboard login before sharing.",
|
|
268
|
-
409,
|
|
269
|
-
);
|
|
324
|
+
return snapshot;
|
|
325
|
+
};
|
|
270
326
|
|
|
327
|
+
const shareBundle = async (snapshot: Snapshot) => {
|
|
271
328
|
const repositoryId =
|
|
272
329
|
snapshot.pins?.repositoryId ?? snapshot.target?.repositoryId;
|
|
273
330
|
|
|
@@ -283,7 +340,7 @@ export function mountSharingPublisher(
|
|
|
283
340
|
const bundle = await exportShare({
|
|
284
341
|
store,
|
|
285
342
|
data,
|
|
286
|
-
reviewId:
|
|
343
|
+
reviewId: snapshot.reviewId,
|
|
287
344
|
version: snapshot.version,
|
|
288
345
|
});
|
|
289
346
|
|
|
@@ -291,6 +348,43 @@ export function mountSharingPublisher(
|
|
|
291
348
|
|
|
292
349
|
if (verified) bundle.repository = verified;
|
|
293
350
|
|
|
351
|
+
return bundle;
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
app.post("/sharing/export", async (context) => {
|
|
355
|
+
const snapshot = shareable(
|
|
356
|
+
publishSchema.parse(await readBoundedRequestJson(context.req.raw)),
|
|
357
|
+
);
|
|
358
|
+
|
|
359
|
+
const bundle = await shareBundle(snapshot);
|
|
360
|
+
|
|
361
|
+
// A link falls back to the browser viewer; a file has no such reader.
|
|
362
|
+
if (!bundle.repository && needsRepository(bundle, snapshot))
|
|
363
|
+
throw new ReviewInputError(
|
|
364
|
+
"Exporting pinned code needs a GitHub remote the file's reader can fetch from.",
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
return context.json({
|
|
368
|
+
filename: whiteboardFileName(snapshot.title),
|
|
369
|
+
text: whiteboardFileText(bundle),
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
app.post("/sharing/publish", async (context) => {
|
|
373
|
+
const input = publishSchema.parse(
|
|
374
|
+
await readBoundedRequestJson(context.req.raw),
|
|
375
|
+
);
|
|
376
|
+
|
|
377
|
+
const snapshot = shareable(input);
|
|
378
|
+
const account = await readSharingAuth();
|
|
379
|
+
|
|
380
|
+
if (!account)
|
|
381
|
+
throw new ReviewInputError(
|
|
382
|
+
"Set DEV_REVIEW_SHARE_TOKEN for CI, or run whiteboard login before sharing.",
|
|
383
|
+
409,
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
const bundle = await shareBundle(snapshot);
|
|
387
|
+
|
|
294
388
|
try {
|
|
295
389
|
const result = await new ShareClient(
|
|
296
390
|
account.origin,
|
package/src/sharing/import.ts
CHANGED
|
@@ -116,7 +116,7 @@ export interface ShareAttribution {
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
/** Commits and traces live in a checkout; a document alone needs none. */
|
|
119
|
-
function needsRepository(
|
|
119
|
+
export function needsRepository(
|
|
120
120
|
bundle: ShareBundle,
|
|
121
121
|
snapshot: Parameters<typeof referenceCommits>[0],
|
|
122
122
|
) {
|
|
@@ -146,6 +146,7 @@ export const SETTING_NAME = [
|
|
|
146
146
|
"keymap",
|
|
147
147
|
"software_map_enabled",
|
|
148
148
|
"show_release_notes",
|
|
149
|
+
"update_pill",
|
|
149
150
|
"diffr_config",
|
|
150
151
|
"theme",
|
|
151
152
|
"diff_theme",
|
|
@@ -430,6 +431,10 @@ export const UI_TELEMETRY_EVENTS = {
|
|
|
430
431
|
event: "review_source_tree_opened",
|
|
431
432
|
properties: { via: SOURCE_TREE_OPENED_VIA },
|
|
432
433
|
},
|
|
434
|
+
whiteboard_file_exported: {
|
|
435
|
+
event: "review_whiteboard_file_exported",
|
|
436
|
+
properties: {},
|
|
437
|
+
},
|
|
433
438
|
diff_layout_changed: {
|
|
434
439
|
event: "review_diff_layout_changed",
|
|
435
440
|
properties: {
|
package/dist/profile-Bw0hDDNd.js
DELETED