@dev.fast/whiteboard 0.3.0 → 0.3.1
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-CwNaMOwU.js → account-alias-D_mqo_Jk.js} +2 -2
- package/dist/agent-cli-2D4icmBR.js +2 -0
- package/dist/{agent-cli-S0bt9I7V.js → agent-cli-Cp7ufSvb.js} +3 -3
- package/dist/{authoring-tools-CjFAGHBa.js → authoring-tools-ByMdW_S8.js} +1 -1
- package/dist/build-info.json +1 -1
- package/dist/{cli-runner-DeQ4IhcG.js → cli-runner-2sJKjaRX.js} +7 -7
- package/dist/cli.js +1 -1
- package/dist/fs-utils-BMPLt0cr.js +22 -0
- package/dist/{fuzzy-match-DFPKdSLR.js → fuzzy-match-C9olHRCK.js} +1 -1
- package/dist/{headless-host-CoN2f0Sk.js → headless-host-CnCDrHTx.js} +6 -6
- package/dist/{headless-host-DHShakz_.js → headless-host-DRwHcAuF.js} +1 -1
- package/dist/{local-data-DN-A5p0K.js → local-data-DKmj2ygd.js} +5 -3
- package/dist/{mcp-BY4ExeMQ.js → mcp-D-7jkRTU.js} +1 -1
- package/dist/{profile-Dm6irjbg.js → profile-B58hz5n7.js} +1 -1
- package/dist/profile-D1rScZ-E.js +2 -0
- package/dist/{request-origin-D1RNVSeK.js → request-origin-BSwTNS8K.js} +93 -3
- package/dist/{review-telemetry-DnQNwgR1.js → review-telemetry-ClhP_5lW.js} +1 -1
- package/dist/server/desktop-host.js +47 -24
- package/dist/sharing/index.d.ts +1 -0
- package/dist/{thread-state-CaQ2lGdj.js → thread-state-DZihwhfu.js} +1 -21
- package/package.json +5 -5
- package/src/review-api/local-data.ts +3 -2
- package/src/server/desktop-server.ts +43 -16
- package/src/server/json-review-reporting.ts +24 -15
- package/src/server/review-gateway.ts +12 -1
- package/src/ui-telemetry-events.ts +87 -1
- package/dist/agent-cli-NWQPsL0W.js +0 -2
- package/dist/profile-BBw-jMW3.js +0 -2
|
@@ -3,8 +3,8 @@ import { w as ReviewCliInstallStampSchema } from "./src-DZG1xAqW.js";
|
|
|
3
3
|
import { C as disableTraceMachine, E as traceMachineStatus, G as listTraceRepositoryRoots, K as traceRepositoryStatus, Q as removeAgentTraceHook, S as configureTraceMachine, T as traceMachineEnabled, U as disableAllTraceRepositories, W as enableTraceRepository, X as describeTraceHookOwners, Y as AGENT_TRACE_HOOK_AGENTS, Z as installHarnessHooks, dt as StoreClient, n as reviewDesktopStateDir, nt as traceScope, ot as readStoreAuth } from "./review-home-paths-Lc02WFuX.js";
|
|
4
4
|
import { A as withFileLock, F as writeFileAtomicAsync, I as writePrivateJsonAtomic, M as devReviewHome } from "./s3-config-DDWWMh5x.js";
|
|
5
5
|
import { i as readReviewPackageVersion } from "./package-paths-jMg6JxDP.js";
|
|
6
|
-
import {
|
|
7
|
-
import { s as findExecutable } from "./fuzzy-match-
|
|
6
|
+
import { n as isFile, t as isDirectory } from "./fs-utils-BMPLt0cr.js";
|
|
7
|
+
import { s as findExecutable } from "./fuzzy-match-C9olHRCK.js";
|
|
8
8
|
import { createHash } from "node:crypto";
|
|
9
9
|
import { constants } from "node:fs";
|
|
10
10
|
import { access, chmod, lstat, mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
@@ -3,8 +3,8 @@ import { T as traceMachineEnabled } from "./review-home-paths-Lc02WFuX.js";
|
|
|
3
3
|
import { a as toolResultText, i as connectReviewInstance, s as ReviewApiError } from "./agent-client-DjXQy6CL.js";
|
|
4
4
|
import { M as devReviewHome } from "./s3-config-DDWWMh5x.js";
|
|
5
5
|
import { b as selectReviewInstance, u as REVIEW_INSTANCE_ENV } from "./server-discovery-DVqrcIDT.js";
|
|
6
|
-
import { n as reviewSessionAgent } from "./review-telemetry-
|
|
7
|
-
import { n as REVIEW_VIA_HEADER, t as REVIEW_AGENT_HEADER } from "./request-origin-
|
|
6
|
+
import { n as reviewSessionAgent } from "./review-telemetry-ClhP_5lW.js";
|
|
7
|
+
import { n as REVIEW_VIA_HEADER, t as REVIEW_AGENT_HEADER } from "./request-origin-BSwTNS8K.js";
|
|
8
8
|
import { i as publicTool, n as RECOVERY, r as callPublicTool, t as toolFailure } from "./tool-failure-CVJrfi5s.js";
|
|
9
9
|
//#region src/review-api/agent-cli.ts
|
|
10
10
|
const reviewAgentCliHelp = "whiteboard api tools (one line per tool)\nwhiteboard api tools <tool-name> (its description and input schema)\nwhiteboard api <tool-name> '<json>'\nwhiteboard api <tool-name> - (read JSON from stdin)\nwhiteboard mcp (stdio MCP adapter; Whiteboard Desktop or whiteboard server start must be running)\nSelect headless state with DEV_REVIEW_SERVER_DIR or whiteboard --state-dir <path> api/mcp.\n";
|
|
@@ -20,7 +20,7 @@ async function runReviewAgentCli(input) {
|
|
|
20
20
|
if (extra.length || mode === "mcp" && name) throw new Error("Unexpected arguments. Use whiteboard api --help.");
|
|
21
21
|
const headers = Object.fromEntries([[REVIEW_VIA_HEADER, mode === "mcp" ? "mcp" : "api"], [REVIEW_AGENT_HEADER, reviewSessionAgent(env)]]);
|
|
22
22
|
if (mode === "mcp") {
|
|
23
|
-
const { serveReviewMcp } = await import("./mcp-
|
|
23
|
+
const { serveReviewMcp } = await import("./mcp-D-7jkRTU.js");
|
|
24
24
|
await serveReviewMcp(async (key, agentKind) => {
|
|
25
25
|
const connected = await connectReviewInstance(key ? {
|
|
26
26
|
...env,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as activityEndSchema, i as commandSchema, l as activityUpdateSchema, n as uploadSchema, s as activityBeginSchema } from "./local-data-
|
|
1
|
+
import { c as activityEndSchema, i as commandSchema, l as activityUpdateSchema, n as uploadSchema, s as activityBeginSchema } from "./local-data-DKmj2ygd.js";
|
|
2
2
|
import { S as publishedEditSchema, y as pathTargetSchema } from "./stored-document-migration-DLBhkSfp.js";
|
|
3
3
|
import { t as ReviewInputError } from "./input-error-OLgB_h31.js";
|
|
4
4
|
import { t as findReviewPackageRoot } from "./package-paths-jMg6JxDP.js";
|
package/dist/build-info.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"0.3.
|
|
1
|
+
{"version":"0.3.1","commit":"674dfbb9b0de56eb16c9ac015f2f0b2b3fa01980","dirty":true,"builtAt":"2026-10-16T20:29:45.789Z"}
|
|
@@ -8,11 +8,11 @@ import { C as s3ProfileSchema, E as writeTraceConfigFile, M as devReviewHome, N
|
|
|
8
8
|
import { t as errorMessage } from "./error-message-OtiDonty.js";
|
|
9
9
|
import { i as readReviewPackageVersion, r as readBuildInfo, t as findReviewPackageRoot } from "./package-paths-jMg6JxDP.js";
|
|
10
10
|
import { a as readReviewServerHealth, b as selectReviewInstance, c as reviewServerStateDir, d as ReviewInstanceUnavailableError, f as clearDefaultReviewInstance, g as requireHealthyReviewDesktop, h as readDefaultReviewInstance, i as readReviewServerDiscovery, l as serverNotReady, m as healthyReviewInstance, p as desktopUsesHome, t as DESKTOP_TAKEOVER_SIGNAL, u as REVIEW_INSTANCE_ENV, x as writeDefaultReviewInstance, y as reviewInstanceUnavailable } from "./server-discovery-DVqrcIDT.js";
|
|
11
|
-
import { t as ReviewTelemetry } from "./review-telemetry-
|
|
12
|
-
import { t as fuzzyRank } from "./fuzzy-match-
|
|
13
|
-
import { _ as isInstallTarget, a as isOwnedShim, f as windowsInstallerCommand, g as ALL_INSTALL_TARGETS, h as detectConnectAgents, m as connectAgent, o as pathShimPath, p as scanLegacySkills, t as aliasInstallationToAccount, v as connectPrompts } from "./account-alias-
|
|
11
|
+
import { t as ReviewTelemetry } from "./review-telemetry-ClhP_5lW.js";
|
|
12
|
+
import { t as fuzzyRank } from "./fuzzy-match-C9olHRCK.js";
|
|
13
|
+
import { _ as isInstallTarget, a as isOwnedShim, f as windowsInstallerCommand, g as ALL_INSTALL_TARGETS, h as detectConnectAgents, m as connectAgent, o as pathShimPath, p as scanLegacySkills, t as aliasInstallationToAccount, v as connectPrompts } from "./account-alias-D_mqo_Jk.js";
|
|
14
14
|
import { n as focusReviewDesktop, r as runReviewAppLaunch } from "./review-app-launcher-i1hmxOZA.js";
|
|
15
|
-
import { t as reviewAgentCliHelp } from "./agent-cli-
|
|
15
|
+
import { t as reviewAgentCliHelp } from "./agent-cli-Cp7ufSvb.js";
|
|
16
16
|
import { existsSync, mkdirSync, renameSync, writeFileSync } from "node:fs";
|
|
17
17
|
import { realpath } from "node:fs/promises";
|
|
18
18
|
import path from "node:path";
|
|
@@ -4319,7 +4319,7 @@ async function runReviewCli(input) {
|
|
|
4319
4319
|
process.once("SIGINT", stop);
|
|
4320
4320
|
process.once("SIGTERM", stop);
|
|
4321
4321
|
process.once(DESKTOP_TAKEOVER_SIGNAL, takeover);
|
|
4322
|
-
const { HeadlessServerBusyError, runHeadlessServer } = await import("./headless-host-
|
|
4322
|
+
const { HeadlessServerBusyError, runHeadlessServer } = await import("./headless-host-DRwHcAuF.js");
|
|
4323
4323
|
try {
|
|
4324
4324
|
await runHeadlessServer({
|
|
4325
4325
|
stateDir,
|
|
@@ -4384,7 +4384,7 @@ async function runReviewCli(input) {
|
|
|
4384
4384
|
if (!existsSync(path.join(stateDir, "review-api.db"))) throw new Error(`No saved reviews in ${stateDir}, so there is no server id to reset. Check --state-dir.`);
|
|
4385
4385
|
const inUse = `A Whiteboard server is using ${stateDir}. Stop it first, then run whiteboard server reset-id again.`;
|
|
4386
4386
|
if (await desktopUsesHome(stateDir, env)) return refuse(inUse, options.json);
|
|
4387
|
-
const [{ openReviewProfile }, { withHeadlessServerLock }] = await Promise.all([import("./profile-
|
|
4387
|
+
const [{ openReviewProfile }, { withHeadlessServerLock }] = await Promise.all([import("./profile-D1rScZ-E.js"), import("./headless-host-DRwHcAuF.js")]);
|
|
4388
4388
|
const reset = await withHeadlessServerLock(await realpath(stateDir), async () => {
|
|
4389
4389
|
const local = await openReviewProfile(stateDir, { manageWorkspaces: false });
|
|
4390
4390
|
try {
|
|
@@ -4758,7 +4758,7 @@ async function runReviewCli(input) {
|
|
|
4758
4758
|
return commands;
|
|
4759
4759
|
} });
|
|
4760
4760
|
for (const [name, description] of [["api", "Call a JSON review authoring tool on the running server"], ["mcp", "Serve the JSON review authoring tools over stdio MCP"]]) configureOutput(program.command(name).description(description).argument("[args...]", "tool name and JSON input").allowUnknownOption().allowExcessArguments().helpOption(false).passThroughOptions().addHelpText("after", `\n${reviewAgentCliHelp}`), "plain").action(async (args) => {
|
|
4761
|
-
const { runReviewAgentCli } = await import("./agent-cli-
|
|
4761
|
+
const { runReviewAgentCli } = await import("./agent-cli-2D4icmBR.js");
|
|
4762
4762
|
state.exitCode = await runReviewAgentCli({
|
|
4763
4763
|
...input,
|
|
4764
4764
|
env: authoringEnv(),
|
package/dist/cli.js
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { stat } from "node:fs/promises";
|
|
2
|
+
//#region src/fs-utils.ts
|
|
3
|
+
/** Whether a thrown filesystem error reports a missing file (ENOENT). */
|
|
4
|
+
function isMissingFileError(cause) {
|
|
5
|
+
return cause instanceof Error && "code" in cause && cause.code === "ENOENT";
|
|
6
|
+
}
|
|
7
|
+
async function isDirectory(target) {
|
|
8
|
+
try {
|
|
9
|
+
return (await stat(target)).isDirectory();
|
|
10
|
+
} catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
async function isFile(target) {
|
|
15
|
+
try {
|
|
16
|
+
return (await stat(target)).isFile();
|
|
17
|
+
} catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { isFile as n, isMissingFileError as r, isDirectory as t };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./review-home-paths-Lc02WFuX.js";
|
|
2
2
|
import { M as devReviewHome } from "./s3-config-DDWWMh5x.js";
|
|
3
|
-
import { n as askAgentIds } from "./thread-state-
|
|
3
|
+
import { n as askAgentIds } from "./thread-state-DZihwhfu.js";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { constants } from "node:fs";
|
|
6
6
|
import { access, chmod, mkdir, readFile, rename, stat, writeFile } from "node:fs/promises";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { d as git, r as defaultBranch } from "./src-BMPuxWv4.js";
|
|
2
2
|
import { c as jsonString, m as isStringValue, n as isJsonObject, p as isObjectValue, u as parseJsonText } from "./src-X9phtB2j.js";
|
|
3
3
|
import { a as sharedReviewId, c as verifyShareRepository, d as StreamLimitError, f as readBoundedStream, l as exportShare, m as shareIdSchema, n as ShareClient, p as parseShareLink, r as SharePreflightError, s as readShareRepository, t as ShareAuthError, u as validateShareSources } from "./client-CLqKkzOc.js";
|
|
4
|
-
import { a as inspectSnapshot, d as
|
|
4
|
+
import { a as inspectSnapshot, d as invalidateStructuralComparisons, f as diffrExecutable, i as commandSchema, p as diffrMissingError, r as SCRATCHPAD_ID } from "./local-data-DKmj2ygd.js";
|
|
5
5
|
import { A as reviewDiffrSummarizerInputSchema, D as ReviewOnboardingRunRequestSchema, a as parseReviewVerbRequest, g as REVIEW_HOST_HEADER, i as parseReviewDesktopVerbResult, j as decodeStructuralDiffEvent } from "./src-DZG1xAqW.js";
|
|
6
6
|
import { B as TraceStorageDeniedError, D as listReviewTraceSessions, I as isTraceStorageConfigured, O as loadReviewAgentTrace, R as resolveTraceStorage, T as traceMachineEnabled, at as openUrlInBrowser, et as shellQuote, it as clearStoreAuth, ot as readStoreAuth, rt as DEFAULT_STORE_ORIGIN, st as runStoreLogin, z as selectTraceStorage } from "./review-home-paths-Lc02WFuX.js";
|
|
7
7
|
import { E as selectionReferences, G as comparisonKey, I as lensSelections, J as selectionKey, K as formatAnchor, M as UNCATEGORIZED_LENS_ID, Q as emptyCoverage, W as anchorSelection, Z as coverageSources, et as scopedCoverage, h as elements, j as stepSources, nt as unionIntervals, q as resolveDiffSelection, tt as subtractIntervals, u as anchorPins, z as fileLineRangeSchema } from "./stored-document-migration-DLBhkSfp.js";
|
|
@@ -10,11 +10,11 @@ import { A as withFileLock, I as writePrivateJsonAtomic, M as devReviewHome, h a
|
|
|
10
10
|
import { t as errorMessage } from "./error-message-OtiDonty.js";
|
|
11
11
|
import { i as readReviewPackageVersion, n as readBuildCommit, t as findReviewPackageRoot } from "./package-paths-jMg6JxDP.js";
|
|
12
12
|
import { i as readReviewServerDiscovery, n as desktopOwnsHome, o as reviewServerDiscoveryPath, p as desktopUsesHome, r as headlessServerLockPath, t as DESKTOP_TAKEOVER_SIGNAL } from "./server-discovery-DVqrcIDT.js";
|
|
13
|
-
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-
|
|
14
|
-
import { t as openReviewProfile } from "./profile-
|
|
15
|
-
import { a as REVIEW_APP_SESSION_ID_HEADER, c as sanitizeUiTelemetryEvent, i as BUNDLE_FRAME_PATTERN, l as cleanTelemetryText, r as reviewRequestOrigin, s as isReportableCleanedMessage } from "./request-origin-
|
|
16
|
-
import { a as defaultAskPermissions, c as launchAskAgent, i as askAgents, n as askAgentSettings, o as detectAskAgents, r as askAgentTakesMcp, t as fuzzyRank } from "./fuzzy-match-
|
|
17
|
-
import { a as scratchpadAvailable, c as readQuerySchemas, i as renderInstructions, o as inspectQuerySchema, r as instructionsQuerySchema, s as queryAnchor, t as authoringTools } from "./authoring-tools-
|
|
13
|
+
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-DZihwhfu.js";
|
|
14
|
+
import { t as openReviewProfile } from "./profile-B58hz5n7.js";
|
|
15
|
+
import { a as REVIEW_APP_SESSION_ID_HEADER, c as sanitizeUiTelemetryEvent, i as BUNDLE_FRAME_PATTERN, l as cleanTelemetryText, r as reviewRequestOrigin, s as isReportableCleanedMessage } from "./request-origin-BSwTNS8K.js";
|
|
16
|
+
import { a as defaultAskPermissions, c as launchAskAgent, i as askAgents, n as askAgentSettings, o as detectAskAgents, r as askAgentTakesMcp, t as fuzzyRank } from "./fuzzy-match-C9olHRCK.js";
|
|
17
|
+
import { a as scratchpadAvailable, c as readQuerySchemas, i as renderInstructions, o as inspectQuerySchema, r as instructionsQuerySchema, s as queryAnchor, t as authoringTools } from "./authoring-tools-ByMdW_S8.js";
|
|
18
18
|
import { a as headlessServerOwner, c as stopBackgroundServer } from "./background-server-ONy-xKJ1.js";
|
|
19
19
|
import crypto$1, { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
20
20
|
import { z } from "zod";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as withHeadlessServerLock, n as runHeadlessServer, r as takeOverServerHome, t as HeadlessServerBusyError } from "./headless-host-
|
|
1
|
+
import { i as withHeadlessServerLock, n as runHeadlessServer, r as takeOverServerHome, t as HeadlessServerBusyError } from "./headless-host-CnCDrHTx.js";
|
|
2
2
|
export { HeadlessServerBusyError, runHeadlessServer, takeOverServerHome, withHeadlessServerLock };
|
|
@@ -6,7 +6,8 @@ import { $ as intersectIntervals, A as documentAdvice, B as requireVisibleSource
|
|
|
6
6
|
import { t as ReviewInputError } from "./input-error-OLgB_h31.js";
|
|
7
7
|
import { A as withFileLock, I as writePrivateJsonAtomic, O as processIsAlive } from "./s3-config-DDWWMh5x.js";
|
|
8
8
|
import { t as errorMessage } from "./error-message-OtiDonty.js";
|
|
9
|
-
import {
|
|
9
|
+
import { r as isMissingFileError } from "./fs-utils-BMPLt0cr.js";
|
|
10
|
+
import { a as askHistoryEntrySchema, i as askEntrySchema, o as askOfferSchema, s as askPermissionsSchema } from "./thread-state-DZihwhfu.js";
|
|
10
11
|
import { createRequire } from "node:module";
|
|
11
12
|
import crypto, { createHash, randomUUID } from "node:crypto";
|
|
12
13
|
import { z } from "zod";
|
|
@@ -3736,7 +3737,8 @@ var LocalReviewData = class {
|
|
|
3736
3737
|
}
|
|
3737
3738
|
return {
|
|
3738
3739
|
workspacePath,
|
|
3739
|
-
filePath
|
|
3740
|
+
filePath,
|
|
3741
|
+
rootPath
|
|
3740
3742
|
};
|
|
3741
3743
|
}
|
|
3742
3744
|
/** A document read that needs default pins; 409 when the document has none. */
|
|
@@ -4592,4 +4594,4 @@ async function readWorkspace(file) {
|
|
|
4592
4594
|
}
|
|
4593
4595
|
}
|
|
4594
4596
|
//#endregion
|
|
4595
|
-
export { inspectSnapshot as a, activityEndSchema as c,
|
|
4597
|
+
export { inspectSnapshot as a, activityEndSchema as c, invalidateStructuralComparisons as d, diffrExecutable as f, commandSchema as i, activityUpdateSchema as l, uploadSchema as n, initializeReviewStoreSchema as o, diffrMissingError as p, SCRATCHPAD_ID as r, activityBeginSchema as s, openLocalReviewStore as t, pullRequestProvider as u };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as toolResultText, s as ReviewApiError } from "./agent-client-DjXQy6CL.js";
|
|
2
2
|
import { t as ReviewInputError } from "./input-error-OLgB_h31.js";
|
|
3
|
-
import { n as REVIEW_STATUS_TOOL, t as authoringTools } from "./authoring-tools-
|
|
3
|
+
import { n as REVIEW_STATUS_TOOL, t as authoringTools } from "./authoring-tools-ByMdW_S8.js";
|
|
4
4
|
import { i as publicTool, n as RECOVERY, r as callPublicTool, t as toolFailure } from "./tool-failure-CVJrfi5s.js";
|
|
5
5
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
6
6
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { o as initializeReviewStoreSchema, t as openLocalReviewStore } from "./local-data-
|
|
1
|
+
import { o as initializeReviewStoreSchema, t as openLocalReviewStore } from "./local-data-DKmj2ygd.js";
|
|
2
2
|
import "./review-home-paths-Lc02WFuX.js";
|
|
3
3
|
import { A as withFileLock } from "./s3-config-DDWWMh5x.js";
|
|
4
4
|
import { access, mkdir } from "node:fs/promises";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { a as jsonNumber, c as jsonString, i as jsonBoolean, n as isJsonObject } from "./src-X9phtB2j.js";
|
|
2
2
|
import { S as REVIEW_THEME_CHOICES, h as REVIEW_DIFF_LAYOUT_SCOPES, m as REVIEW_DIFF_LAYOUTS } from "./src-DZG1xAqW.js";
|
|
3
|
+
import { n as askAgentIds } from "./thread-state-DZihwhfu.js";
|
|
3
4
|
import { z } from "zod";
|
|
4
5
|
//#region src/telemetry-clean-text.ts
|
|
5
6
|
const USER_DATA_REGEXES = [
|
|
@@ -150,7 +151,8 @@ const PEEK_VIA = [
|
|
|
150
151
|
"diagram",
|
|
151
152
|
"map",
|
|
152
153
|
"db_lens",
|
|
153
|
-
"call_stack_frame"
|
|
154
|
+
"call_stack_frame",
|
|
155
|
+
"diff_definition"
|
|
154
156
|
];
|
|
155
157
|
const PEEK_ROOT_KIND = ["range"];
|
|
156
158
|
const LSP_FEATURE = [
|
|
@@ -226,6 +228,7 @@ const SETTING_NAME = [
|
|
|
226
228
|
"diffr_config",
|
|
227
229
|
"theme",
|
|
228
230
|
"ctrl_tab",
|
|
231
|
+
"open_files_in",
|
|
229
232
|
"ready_notification",
|
|
230
233
|
"document_width",
|
|
231
234
|
"code_font_size"
|
|
@@ -322,10 +325,39 @@ const INSTALL_LOCATION = [
|
|
|
322
325
|
const DIFF_OPENED_VIA = [
|
|
323
326
|
"topbar",
|
|
324
327
|
"lens",
|
|
325
|
-
"locate"
|
|
328
|
+
"locate",
|
|
329
|
+
"file_picker"
|
|
326
330
|
];
|
|
327
331
|
/** Which diff opened: a commit's, or a file diff drawn plain or structural. */
|
|
328
332
|
const DIFF_OPENED_KIND = ["commit", "structural"];
|
|
333
|
+
/** GitHub Enterprise is any GitHub host but github.com. */
|
|
334
|
+
const PR_PROVIDER = [
|
|
335
|
+
"github",
|
|
336
|
+
"github_enterprise",
|
|
337
|
+
"azure_devops"
|
|
338
|
+
];
|
|
339
|
+
const REMOTE_HOST_PROBLEM = [
|
|
340
|
+
"unreachable",
|
|
341
|
+
"not_installed",
|
|
342
|
+
"auth_failed",
|
|
343
|
+
"unsupported",
|
|
344
|
+
"incompatible"
|
|
345
|
+
];
|
|
346
|
+
const REMOTE_HOST_TARGET = ["linux-x64", "linux-arm64"];
|
|
347
|
+
const ASK_SELECTION = [
|
|
348
|
+
"text",
|
|
349
|
+
"code",
|
|
350
|
+
"diff",
|
|
351
|
+
"review"
|
|
352
|
+
];
|
|
353
|
+
const ONBOARDING_STEP = [
|
|
354
|
+
"welcome",
|
|
355
|
+
"install",
|
|
356
|
+
"run"
|
|
357
|
+
];
|
|
358
|
+
const RUN_MODE = ["draw", "copy"];
|
|
359
|
+
const NEW_WHITEBOARD_VIA = ["button", "command"];
|
|
360
|
+
const FIND_SURFACE = ["review", "diff"];
|
|
329
361
|
const DISCORD_VIA = [
|
|
330
362
|
"topbar",
|
|
331
363
|
"dialog",
|
|
@@ -586,7 +618,9 @@ const UI_TELEMETRY_EVENTS = {
|
|
|
586
618
|
event: "review_session_started",
|
|
587
619
|
properties: {
|
|
588
620
|
source_kind: SESSION_SOURCE_KIND,
|
|
589
|
-
agent_kind: SESSION_AGENT_KIND
|
|
621
|
+
agent_kind: SESSION_AGENT_KIND,
|
|
622
|
+
remote: "boolean",
|
|
623
|
+
pr_provider: PR_PROVIDER
|
|
590
624
|
}
|
|
591
625
|
},
|
|
592
626
|
session_ended: {
|
|
@@ -674,6 +708,62 @@ const UI_TELEMETRY_EVENTS = {
|
|
|
674
708
|
review_shared: {
|
|
675
709
|
event: "review_review_shared",
|
|
676
710
|
properties: {}
|
|
711
|
+
},
|
|
712
|
+
find_opened: {
|
|
713
|
+
event: "review_find_opened",
|
|
714
|
+
properties: { surface: FIND_SURFACE }
|
|
715
|
+
},
|
|
716
|
+
ask_sent: {
|
|
717
|
+
event: "review_ask_sent",
|
|
718
|
+
properties: {
|
|
719
|
+
agent: askAgentIds,
|
|
720
|
+
follow_up: "boolean",
|
|
721
|
+
selection: ASK_SELECTION,
|
|
722
|
+
remote: "boolean"
|
|
723
|
+
}
|
|
724
|
+
},
|
|
725
|
+
onboarding_step_viewed: {
|
|
726
|
+
event: "review_onboarding_step_viewed",
|
|
727
|
+
properties: { step: ONBOARDING_STEP }
|
|
728
|
+
},
|
|
729
|
+
onboarding_skipped: {
|
|
730
|
+
event: "review_onboarding_skipped",
|
|
731
|
+
properties: { step: ONBOARDING_STEP }
|
|
732
|
+
},
|
|
733
|
+
onboarding_run_started: {
|
|
734
|
+
event: "review_onboarding_run_started",
|
|
735
|
+
properties: {
|
|
736
|
+
mode: RUN_MODE,
|
|
737
|
+
agent: askAgentIds
|
|
738
|
+
}
|
|
739
|
+
},
|
|
740
|
+
new_whiteboard_opened: {
|
|
741
|
+
event: "review_new_whiteboard_opened",
|
|
742
|
+
properties: { via: NEW_WHITEBOARD_VIA }
|
|
743
|
+
},
|
|
744
|
+
new_whiteboard_started: {
|
|
745
|
+
event: "review_new_whiteboard_started",
|
|
746
|
+
properties: {
|
|
747
|
+
mode: RUN_MODE,
|
|
748
|
+
embedded: "boolean",
|
|
749
|
+
agent: askAgentIds
|
|
750
|
+
}
|
|
751
|
+
},
|
|
752
|
+
remote_host_installed: {
|
|
753
|
+
event: "review_remote_host_installed",
|
|
754
|
+
properties: {
|
|
755
|
+
ok: "boolean",
|
|
756
|
+
target: REMOTE_HOST_TARGET,
|
|
757
|
+
duration_ms: "number"
|
|
758
|
+
}
|
|
759
|
+
},
|
|
760
|
+
remote_host_connected: {
|
|
761
|
+
event: "review_remote_host_connected",
|
|
762
|
+
properties: {
|
|
763
|
+
ok: "boolean",
|
|
764
|
+
problem: REMOTE_HOST_PROBLEM,
|
|
765
|
+
direct: "boolean"
|
|
766
|
+
}
|
|
677
767
|
}
|
|
678
768
|
};
|
|
679
769
|
const MAX_FREE_STRING_LENGTH = 40;
|
|
@@ -3,7 +3,7 @@ import "./src-DZG1xAqW.js";
|
|
|
3
3
|
import "./review-home-paths-Lc02WFuX.js";
|
|
4
4
|
import { A as withFileLock, M as devReviewHome, O as processIsAlive, P as writeFileAtomic } from "./s3-config-DDWWMh5x.js";
|
|
5
5
|
import { i as readReviewPackageVersion, t as findReviewPackageRoot } from "./package-paths-jMg6JxDP.js";
|
|
6
|
-
import "./request-origin-
|
|
6
|
+
import "./request-origin-BSwTNS8K.js";
|
|
7
7
|
import { createHmac, randomUUID } from "node:crypto";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
import { existsSync, readFileSync, rmSync } from "node:fs";
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { S as splitGitPatchFiles, a as diff, o as diffFileSummaries } from "../src-BMPuxWv4.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
4
|
import { d as StreamLimitError, f as readBoundedStream, i as SharedReviewStore } from "../client-CLqKkzOc.js";
|
|
5
|
+
import { u as pullRequestProvider } from "../local-data-DKmj2ygd.js";
|
|
5
6
|
import { A as reviewDiffrSummarizerInputSchema, E as ReviewGatewayHostSchema, T as ReviewConnectRequestSchema, c as ReviewBugReportMetaV2Schema, d as REVIEW_CLIENT_HEADER, f as REVIEW_CLIENT_REMOTE, g as REVIEW_HOST_HEADER, l as ReviewBugReportRequestSchema, r as parseReviewDesktopVerbFrame, s as parseZod, t as parseReviewCliInstallApplyRequest, u as parseReviewBugReportResponse } from "../src-DZG1xAqW.js";
|
|
6
7
|
import { i as reviewInstanceDiscoveryPath, o as reviewLegacyDiscoveryPath } from "../review-home-paths-Lc02WFuX.js";
|
|
7
8
|
import { w as resourceReferences } from "../stored-document-migration-DLBhkSfp.js";
|
|
@@ -10,12 +11,12 @@ import { I as writePrivateJsonAtomic, M as devReviewHome } from "../s3-config-DD
|
|
|
10
11
|
import { t as errorMessage } from "../error-message-OtiDonty.js";
|
|
11
12
|
import { i as readReviewPackageVersion, t as findReviewPackageRoot } from "../package-paths-jMg6JxDP.js";
|
|
12
13
|
import { _ as reviewInstanceIdentity, u as REVIEW_INSTANCE_ENV } from "../server-discovery-DVqrcIDT.js";
|
|
13
|
-
import { t as openReviewProfile } from "../profile-
|
|
14
|
-
import { r as reviewTelemetryChannel, t as ReviewTelemetry } from "../review-telemetry-
|
|
15
|
-
import { o 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 saveDiffrSummarizer, E as cliAskTools, S as readDiffrConfig, T as testDiffrSummarizer, _ as DEFAULT_MAX_REQUEST_BYTES, a as drainServerCrashReport, b as GlobalReviewDesktopVerbRelay, c as answerErrorsAsJson, d as legacyModeSchema, f as captureSanitizedUiTelemetry, g as readBoundedRequestJson, h as createNodeRequestListener, l as createWhiteboardCore, m as recordClientError, o as installProcessErrorTelemetry, p as clientErrorsForSession, r as takeOverServerHome, s as serverCrashReportPath, u as serverJson, v as HttpJsonError, w as setDiffrConfigValue, x as migrateDiffrConfig, y as ReviewServerError } from "../headless-host-
|
|
18
|
-
import { c as readQuerySchemas } from "../authoring-tools-
|
|
14
|
+
import { t as openReviewProfile } from "../profile-B58hz5n7.js";
|
|
15
|
+
import { r as reviewTelemetryChannel, t as ReviewTelemetry } from "../review-telemetry-ClhP_5lW.js";
|
|
16
|
+
import { o as REVIEW_TELEMETRY_TABS } from "../request-origin-BSwTNS8K.js";
|
|
17
|
+
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-D_mqo_Jk.js";
|
|
18
|
+
import { C as saveDiffrSummarizer, E as cliAskTools, S as readDiffrConfig, T as testDiffrSummarizer, _ as DEFAULT_MAX_REQUEST_BYTES, a as drainServerCrashReport, b as GlobalReviewDesktopVerbRelay, c as answerErrorsAsJson, d as legacyModeSchema, f as captureSanitizedUiTelemetry, g as readBoundedRequestJson, h as createNodeRequestListener, l as createWhiteboardCore, m as recordClientError, o as installProcessErrorTelemetry, p as clientErrorsForSession, r as takeOverServerHome, s as serverCrashReportPath, u as serverJson, v as HttpJsonError, w as setDiffrConfigValue, x as migrateDiffrConfig, y as ReviewServerError } from "../headless-host-CnCDrHTx.js";
|
|
19
|
+
import { c as readQuerySchemas } from "../authoring-tools-ByMdW_S8.js";
|
|
19
20
|
import crypto, { createHash, randomBytes } from "node:crypto";
|
|
20
21
|
import { z } from "zod";
|
|
21
22
|
import fs, { existsSync, readFileSync } from "node:fs";
|
|
@@ -741,6 +742,16 @@ function jsonReviewBugReportSource(store, snapshot) {
|
|
|
741
742
|
}
|
|
742
743
|
};
|
|
743
744
|
}
|
|
745
|
+
/** The path id wins over any review id in the payload. */
|
|
746
|
+
async function captureReviewUiEvent(telemetry, request, reviewId) {
|
|
747
|
+
const body = await readBoundedRequestJson(request, void 0, {});
|
|
748
|
+
const payload = isJsonObject(body) ? body : {};
|
|
749
|
+
const rawContext = isJsonObject(payload.context) ? payload.context : {};
|
|
750
|
+
await captureSanitizedUiTelemetry(telemetry, request, payload.name, payload.properties, recordClientError, payload.error, {
|
|
751
|
+
...rawContext,
|
|
752
|
+
reviewUuid: reviewId
|
|
753
|
+
}, payload.occurredAt);
|
|
754
|
+
}
|
|
744
755
|
/** Telemetry and report uploads for a pinned native review. */
|
|
745
756
|
function createJsonReviewReporting(store, telemetry, options = {}) {
|
|
746
757
|
const { submit = submitReviewBugReport, shared } = options;
|
|
@@ -758,13 +769,7 @@ function createJsonReviewReporting(store, telemetry, options = {}) {
|
|
|
758
769
|
await next();
|
|
759
770
|
});
|
|
760
771
|
app.post("/:id/telemetry/event", async (c) => {
|
|
761
|
-
|
|
762
|
-
const payload = isJsonObject(body) ? body : {};
|
|
763
|
-
const rawContext = isJsonObject(payload.context) ? payload.context : {};
|
|
764
|
-
await captureSanitizedUiTelemetry(telemetry, c.req.raw, payload.name, payload.properties, recordClientError, payload.error, {
|
|
765
|
-
...rawContext,
|
|
766
|
-
reviewUuid: c.req.param("id")
|
|
767
|
-
}, payload.occurredAt);
|
|
772
|
+
await captureReviewUiEvent(telemetry, c.req.raw, c.req.param("id"));
|
|
768
773
|
return c.json({ ok: true });
|
|
769
774
|
});
|
|
770
775
|
app.post("/:id/telemetry/tab", async (context) => {
|
|
@@ -1902,7 +1907,8 @@ function createReviewGateway(input) {
|
|
|
1902
1907
|
if (owner === void 0 || owner === "local") return input.local(request);
|
|
1903
1908
|
const alias = "remote" in owner ? owner.remote.alias : owner.down.alias;
|
|
1904
1909
|
if (route === "telemetry") {
|
|
1905
|
-
|
|
1910
|
+
if (input.remoteEvent && new URL(request.url).pathname.endsWith("/telemetry/event")) await input.remoteEvent(request, reviewId);
|
|
1911
|
+
else await request.body?.cancel();
|
|
1906
1912
|
return answer(alias, 200, { ok: true });
|
|
1907
1913
|
}
|
|
1908
1914
|
if (!route) return answer(alias, 404, {
|
|
@@ -1946,6 +1952,10 @@ function createReviewGateway(input) {
|
|
|
1946
1952
|
fetch: (request) => app.fetch(request),
|
|
1947
1953
|
setHosts: (list) => hosts.set(list),
|
|
1948
1954
|
hosts: () => hosts.states(),
|
|
1955
|
+
isRemote(reviewId) {
|
|
1956
|
+
const owner = locate(reviewId);
|
|
1957
|
+
return owner !== void 0 && owner !== "local";
|
|
1958
|
+
},
|
|
1949
1959
|
async close() {
|
|
1950
1960
|
closed = true;
|
|
1951
1961
|
stopWatchingWindows();
|
|
@@ -2115,6 +2125,7 @@ function createGlobalReviewServer(input) {
|
|
|
2115
2125
|
home: devReviewHome(),
|
|
2116
2126
|
relay,
|
|
2117
2127
|
restarted: (alias) => input.onRemoteHostRestarted?.(alias),
|
|
2128
|
+
remoteEvent: (request, reviewId) => captureReviewUiEvent(telemetry, request, reviewId),
|
|
2118
2129
|
log: input.log
|
|
2119
2130
|
});
|
|
2120
2131
|
app.all("/reviews-api", (context) => gateway.fetch(context.req.raw));
|
|
@@ -2150,8 +2161,9 @@ function createGlobalReviewServer(input) {
|
|
|
2150
2161
|
delete eventProperties.source_kind;
|
|
2151
2162
|
delete eventProperties.agent_kind;
|
|
2152
2163
|
const rawContext = isJsonObject(payload.context) ? payload.context : {};
|
|
2153
|
-
const
|
|
2154
|
-
|
|
2164
|
+
const reviewUuid = jsonString(rawContext.reviewUuid);
|
|
2165
|
+
Object.assign(eventProperties, sessionStartedSource(reviewStore, reviewUuid));
|
|
2166
|
+
if (reviewUuid) eventProperties.remote = gateway.isRemote(reviewUuid);
|
|
2155
2167
|
}
|
|
2156
2168
|
await captureSanitizedUiTelemetry(telemetry, context.req.raw, payload.name, eventProperties, (event, eventContext) => {
|
|
2157
2169
|
flushBeforeOptOut = event.event === "review_setting_changed" && event.properties.setting === "telemetry_enabled" && event.properties.enabled === false;
|
|
@@ -2286,20 +2298,31 @@ function watchSessionOpen(watchdog, event, context) {
|
|
|
2286
2298
|
else if (event === "review_review_presented" || event === "review_session_ended") watchdog.presented(presentationSessionId);
|
|
2287
2299
|
}
|
|
2288
2300
|
/**
|
|
2289
|
-
* `session_started`'s `source_kind
|
|
2290
|
-
*
|
|
2291
|
-
*
|
|
2292
|
-
* event arriving) or was left without a target.
|
|
2301
|
+
* `session_started`'s `source_kind` and `pr_provider`. Empty when the review
|
|
2302
|
+
* is not in this store: a shared or remote review, or one deleted between open
|
|
2303
|
+
* and the event arriving.
|
|
2293
2304
|
*/
|
|
2294
|
-
function
|
|
2295
|
-
if (!reviewUuid) return
|
|
2305
|
+
function sessionStartedSource(reviewStore, reviewUuid) {
|
|
2306
|
+
if (!reviewUuid) return {};
|
|
2296
2307
|
try {
|
|
2297
2308
|
const snapshot = reviewStore.read(reviewUuid);
|
|
2298
|
-
|
|
2309
|
+
const sourceKind = snapshot.kind === "scratchpad" ? snapshot.kind : snapshot.target?.kind;
|
|
2310
|
+
const pullRequestUrl = snapshot.origin?.pullRequestUrl;
|
|
2311
|
+
const prProvider = pullRequestUrl && prProviderOf(pullRequestUrl);
|
|
2312
|
+
return {
|
|
2313
|
+
...sourceKind && { source_kind: sourceKind },
|
|
2314
|
+
...prProvider && { pr_provider: prProvider }
|
|
2315
|
+
};
|
|
2299
2316
|
} catch {
|
|
2300
|
-
return;
|
|
2317
|
+
return {};
|
|
2301
2318
|
}
|
|
2302
2319
|
}
|
|
2320
|
+
function prProviderOf(url) {
|
|
2321
|
+
const resolved = pullRequestProvider(url);
|
|
2322
|
+
if (!resolved) return void 0;
|
|
2323
|
+
if (resolved.provider.id === "azure-devops") return "azure_devops";
|
|
2324
|
+
return resolved.address.host === "github.com" ? "github" : "github_enterprise";
|
|
2325
|
+
}
|
|
2303
2326
|
function listen(server, port) {
|
|
2304
2327
|
return new Promise((resolve, reject) => {
|
|
2305
2328
|
server.once("error", reject);
|
package/dist/sharing/index.d.ts
CHANGED
|
@@ -1644,6 +1644,7 @@ declare class LocalReviewData {
|
|
|
1644
1644
|
}): Promise<{
|
|
1645
1645
|
workspacePath: string;
|
|
1646
1646
|
filePath?: string;
|
|
1647
|
+
rootPath: string;
|
|
1647
1648
|
}>;
|
|
1648
1649
|
/** A document read that needs default pins; 409 when the document has none. */
|
|
1649
1650
|
documentPins(snapshot: Snapshot): Promise<Pins>;
|
|
@@ -1,25 +1,5 @@
|
|
|
1
1
|
import { C as ReviewApiSelectionSourceSchema, O as ReviewSelectedDiffSchema } from "./src-DZG1xAqW.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { stat } from "node:fs/promises";
|
|
4
|
-
//#region src/fs-utils.ts
|
|
5
|
-
/** Whether a thrown filesystem error reports a missing file (ENOENT). */
|
|
6
|
-
function isMissingFileError(cause) {
|
|
7
|
-
return cause instanceof Error && "code" in cause && cause.code === "ENOENT";
|
|
8
|
-
}
|
|
9
|
-
async function isDirectory(target) {
|
|
10
|
-
try {
|
|
11
|
-
return (await stat(target)).isDirectory();
|
|
12
|
-
} catch {
|
|
13
|
-
return false;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
async function isFile(target) {
|
|
17
|
-
try {
|
|
18
|
-
return (await stat(target)).isFile();
|
|
19
|
-
} catch {
|
|
20
|
-
return false;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
3
|
/** A semantic selection, independent of comment/thread creation. */
|
|
24
4
|
const AgentSelectionSchema = z.strictObject({
|
|
25
5
|
target: z.discriminatedUnion("kind", [
|
|
@@ -397,4 +377,4 @@ const askHistoryEntrySchema = z.object({
|
|
|
397
377
|
updatedAt: z.string()
|
|
398
378
|
});
|
|
399
379
|
//#endregion
|
|
400
|
-
export { askHistoryEntrySchema as a, askPicksSchema as c, selectionMarkdown as d,
|
|
380
|
+
export { askHistoryEntrySchema as a, askPicksSchema as c, selectionMarkdown as d, askEntrySchema as i, askQuestionSchema as l, askAgentIds as n, askOfferSchema as o, askChoiceKinds as r, askPermissionsSchema as s, applyAskChange as t, AgentSelectionSchema as u };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dev.fast/whiteboard",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -74,11 +74,11 @@
|
|
|
74
74
|
"tsx": "4.21.0",
|
|
75
75
|
"typescript": "6.0.3",
|
|
76
76
|
"vitest": "4.1.11",
|
|
77
|
-
"@dev.fast/json": "0.0.0",
|
|
78
|
-
"@dev.fast/review-share-protocol": "0.1.2",
|
|
79
77
|
"@dev.fast/trace-core": "0.0.0",
|
|
78
|
+
"@dev.fast/review-share-protocol": "0.1.2",
|
|
80
79
|
"@dev.fast/review-protocol": "0.0.0",
|
|
81
|
-
"@dev.fast/trace-protocol": "0.5.0"
|
|
80
|
+
"@dev.fast/trace-protocol": "0.5.0",
|
|
81
|
+
"@dev.fast/json": "0.0.0"
|
|
82
82
|
},
|
|
83
83
|
"engines": {
|
|
84
84
|
"node": ">=24 <25"
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"repo": "devdotfast/review",
|
|
89
89
|
"docs": "packages/review/instructions/authoring.md"
|
|
90
90
|
},
|
|
91
|
-
"gitHead": "
|
|
91
|
+
"gitHead": "674dfbb9b0de56eb16c9ac015f2f0b2b3fa01980",
|
|
92
92
|
"scripts": {
|
|
93
93
|
"prebuild": "pnpm run build:workspace-deps",
|
|
94
94
|
"build": "node --max-old-space-size=8192 node_modules/tsdown/dist/run.mjs",
|
|
@@ -382,7 +382,7 @@ export class LocalReviewData {
|
|
|
382
382
|
commit?: string;
|
|
383
383
|
anchor?: SourcePins;
|
|
384
384
|
} = {},
|
|
385
|
-
): Promise<{ workspacePath: string; filePath?: string }> {
|
|
385
|
+
): Promise<{ workspacePath: string; filePath?: string; rootPath: string }> {
|
|
386
386
|
const { pins } = await this.resolveSource(
|
|
387
387
|
snapshot,
|
|
388
388
|
source.commit,
|
|
@@ -515,7 +515,8 @@ export class LocalReviewData {
|
|
|
515
515
|
}
|
|
516
516
|
}
|
|
517
517
|
|
|
518
|
-
|
|
518
|
+
// External editors open the checkout as their workspace beside the file.
|
|
519
|
+
return { workspacePath, filePath, rootPath };
|
|
519
520
|
}
|
|
520
521
|
|
|
521
522
|
/** A document read that needs default pins; 409 when the document has none. */
|
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
} from "@review/desktop-discovery";
|
|
41
41
|
import { readReviewPackageVersion } from "@review/package-paths";
|
|
42
42
|
import type { LocalReviewData } from "@review/review-api/local-data.js";
|
|
43
|
+
import { pullRequestProvider } from "@review/review-api/provider.js";
|
|
43
44
|
import type { ReviewStore } from "@review/review-api/store.js";
|
|
44
45
|
import {
|
|
45
46
|
devReviewHome,
|
|
@@ -77,7 +78,10 @@ import {
|
|
|
77
78
|
readBoundedRequestJson,
|
|
78
79
|
} from "./hono-http";
|
|
79
80
|
import { ReviewServerError } from "./http-json";
|
|
80
|
-
import {
|
|
81
|
+
import {
|
|
82
|
+
captureReviewUiEvent,
|
|
83
|
+
createJsonReviewReporting,
|
|
84
|
+
} from "./json-review-reporting";
|
|
81
85
|
import { removeLegacyTutorial } from "./legacy-tutorial-cleanup";
|
|
82
86
|
import { createReviewGateway } from "./review-gateway";
|
|
83
87
|
import { reviewLifecycleTelemetry } from "./review-lifecycle-telemetry";
|
|
@@ -253,6 +257,8 @@ export function createGlobalReviewServer(
|
|
|
253
257
|
home: devReviewHome(),
|
|
254
258
|
relay,
|
|
255
259
|
restarted: (alias) => input.onRemoteHostRestarted?.(alias),
|
|
260
|
+
remoteEvent: (request, reviewId) =>
|
|
261
|
+
captureReviewUiEvent(telemetry, request, reviewId),
|
|
256
262
|
log: input.log,
|
|
257
263
|
});
|
|
258
264
|
|
|
@@ -314,12 +320,14 @@ export function createGlobalReviewServer(
|
|
|
314
320
|
|
|
315
321
|
const rawContext = isJsonObject(payload.context) ? payload.context : {};
|
|
316
322
|
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
323
|
+
const reviewUuid = jsonString(rawContext.reviewUuid);
|
|
324
|
+
|
|
325
|
+
Object.assign(
|
|
326
|
+
eventProperties,
|
|
327
|
+
sessionStartedSource(reviewStore, reviewUuid),
|
|
320
328
|
);
|
|
321
329
|
|
|
322
|
-
if (
|
|
330
|
+
if (reviewUuid) eventProperties.remote = gateway.isRemote(reviewUuid);
|
|
323
331
|
}
|
|
324
332
|
|
|
325
333
|
await captureSanitizedUiTelemetry(
|
|
@@ -562,28 +570,47 @@ function watchSessionOpen(
|
|
|
562
570
|
}
|
|
563
571
|
|
|
564
572
|
/**
|
|
565
|
-
* `session_started`'s `source_kind
|
|
566
|
-
*
|
|
567
|
-
*
|
|
568
|
-
* event arriving) or was left without a target.
|
|
573
|
+
* `session_started`'s `source_kind` and `pr_provider`. Empty when the review
|
|
574
|
+
* is not in this store: a shared or remote review, or one deleted between open
|
|
575
|
+
* and the event arriving.
|
|
569
576
|
*/
|
|
570
|
-
export function
|
|
577
|
+
export function sessionStartedSource(
|
|
571
578
|
reviewStore: ReviewStore,
|
|
572
579
|
reviewUuid: string | undefined,
|
|
573
|
-
)
|
|
574
|
-
if (!reviewUuid) return
|
|
580
|
+
) {
|
|
581
|
+
if (!reviewUuid) return {};
|
|
575
582
|
|
|
576
583
|
try {
|
|
577
584
|
const snapshot = reviewStore.read(reviewUuid);
|
|
578
585
|
|
|
579
|
-
|
|
580
|
-
? snapshot.kind
|
|
581
|
-
|
|
586
|
+
const sourceKind =
|
|
587
|
+
snapshot.kind === "scratchpad" ? snapshot.kind : snapshot.target?.kind;
|
|
588
|
+
|
|
589
|
+
const pullRequestUrl = snapshot.origin?.pullRequestUrl;
|
|
590
|
+
|
|
591
|
+
const prProvider = pullRequestUrl && prProviderOf(pullRequestUrl);
|
|
592
|
+
|
|
593
|
+
return {
|
|
594
|
+
...(sourceKind && { source_kind: sourceKind }),
|
|
595
|
+
...(prProvider && { pr_provider: prProvider }),
|
|
596
|
+
};
|
|
582
597
|
} catch {
|
|
583
|
-
return
|
|
598
|
+
return {};
|
|
584
599
|
}
|
|
585
600
|
}
|
|
586
601
|
|
|
602
|
+
function prProviderOf(url: string) {
|
|
603
|
+
const resolved = pullRequestProvider(url);
|
|
604
|
+
|
|
605
|
+
if (!resolved) return undefined;
|
|
606
|
+
|
|
607
|
+
if (resolved.provider.id === "azure-devops") return "azure_devops";
|
|
608
|
+
|
|
609
|
+
return resolved.address.host === "github.com"
|
|
610
|
+
? "github"
|
|
611
|
+
: "github_enterprise";
|
|
612
|
+
}
|
|
613
|
+
|
|
587
614
|
function listen(server: Server, port: number): Promise<number> {
|
|
588
615
|
return new Promise((resolve, reject) => {
|
|
589
616
|
server.once("error", reject);
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
requestJsonErrorStatus,
|
|
24
24
|
} from "./review-api-parsers";
|
|
25
25
|
import {
|
|
26
|
+
type ReviewTelemetryCapture,
|
|
26
27
|
captureSanitizedUiTelemetry,
|
|
27
28
|
clientErrorsForSession,
|
|
28
29
|
recordClientError,
|
|
@@ -69,6 +70,27 @@ export function jsonReviewBugReportSource(
|
|
|
69
70
|
};
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
/** The path id wins over any review id in the payload. */
|
|
74
|
+
export async function captureReviewUiEvent(
|
|
75
|
+
telemetry: ReviewTelemetryCapture,
|
|
76
|
+
request: Request,
|
|
77
|
+
reviewId: string,
|
|
78
|
+
) {
|
|
79
|
+
const body = await readBoundedRequestJson(request, undefined, {});
|
|
80
|
+
const payload = isJsonObject(body) ? body : {};
|
|
81
|
+
const rawContext = isJsonObject(payload.context) ? payload.context : {};
|
|
82
|
+
await captureSanitizedUiTelemetry(
|
|
83
|
+
telemetry,
|
|
84
|
+
request,
|
|
85
|
+
payload.name,
|
|
86
|
+
payload.properties,
|
|
87
|
+
recordClientError,
|
|
88
|
+
payload.error,
|
|
89
|
+
{ ...rawContext, reviewUuid: reviewId },
|
|
90
|
+
payload.occurredAt,
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
72
94
|
/** Telemetry and report uploads for a pinned native review. */
|
|
73
95
|
export function createJsonReviewReporting(
|
|
74
96
|
store: ReviewStore,
|
|
@@ -105,21 +127,8 @@ export function createJsonReviewReporting(
|
|
|
105
127
|
await next();
|
|
106
128
|
});
|
|
107
129
|
app.post("/:id/telemetry/event", async (c) => {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const rawContext = isJsonObject(payload.context) ? payload.context : {};
|
|
111
|
-
await captureSanitizedUiTelemetry(
|
|
112
|
-
telemetry,
|
|
113
|
-
c.req.raw,
|
|
114
|
-
payload.name,
|
|
115
|
-
payload.properties,
|
|
116
|
-
recordClientError,
|
|
117
|
-
payload.error,
|
|
118
|
-
// The path id wins: the middleware above already asserted it exists,
|
|
119
|
-
// so a payload trying to assert a different review id is overridden.
|
|
120
|
-
{ ...rawContext, reviewUuid: c.req.param("id") },
|
|
121
|
-
payload.occurredAt,
|
|
122
|
-
);
|
|
130
|
+
// The middleware above already asserted the review exists.
|
|
131
|
+
await captureReviewUiEvent(telemetry, c.req.raw, c.req.param("id"));
|
|
123
132
|
|
|
124
133
|
return c.json({ ok: true });
|
|
125
134
|
});
|
|
@@ -129,6 +129,7 @@ export function createReviewGateway(input: {
|
|
|
129
129
|
firstByteMs?: number;
|
|
130
130
|
slowRouteMs?: number;
|
|
131
131
|
restarted?(alias: string): void;
|
|
132
|
+
remoteEvent?(request: Request, reviewId: string): Promise<void>;
|
|
132
133
|
log?(message: string): void;
|
|
133
134
|
}) {
|
|
134
135
|
const log = input.log ?? (() => {});
|
|
@@ -352,7 +353,12 @@ export function createReviewGateway(input: {
|
|
|
352
353
|
const alias = "remote" in owner ? owner.remote.alias : owner.down.alias;
|
|
353
354
|
|
|
354
355
|
if (route === "telemetry") {
|
|
355
|
-
|
|
356
|
+
if (
|
|
357
|
+
input.remoteEvent &&
|
|
358
|
+
new URL(request.url).pathname.endsWith("/telemetry/event")
|
|
359
|
+
)
|
|
360
|
+
await input.remoteEvent(request, reviewId);
|
|
361
|
+
else await request.body?.cancel();
|
|
356
362
|
|
|
357
363
|
return answer(alias, 200, { ok: true });
|
|
358
364
|
}
|
|
@@ -420,6 +426,11 @@ export function createReviewGateway(input: {
|
|
|
420
426
|
fetch: (request: Request) => app.fetch(request),
|
|
421
427
|
setHosts: (list: ReviewGatewayHost[]) => hosts.set(list),
|
|
422
428
|
hosts: () => hosts.states(),
|
|
429
|
+
isRemote(reviewId: string) {
|
|
430
|
+
const owner = locate(reviewId);
|
|
431
|
+
|
|
432
|
+
return owner !== undefined && owner !== "local";
|
|
433
|
+
},
|
|
423
434
|
async close() {
|
|
424
435
|
closed = true;
|
|
425
436
|
stopWatchingWindows();
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
} from "@dev.fast/review-protocol";
|
|
29
29
|
import { z } from "zod";
|
|
30
30
|
|
|
31
|
+
import { askAgentIds } from "./ask/thread-state";
|
|
31
32
|
import { containsFilePath, hasPossibleUserInfo } from "./telemetry-clean-text";
|
|
32
33
|
|
|
33
34
|
/** Property value validators: an enum of allowed strings, or a scalar type. */
|
|
@@ -64,6 +65,7 @@ const PEEK_VIA = [
|
|
|
64
65
|
"map",
|
|
65
66
|
"db_lens",
|
|
66
67
|
"call_stack_frame",
|
|
68
|
+
"diff_definition",
|
|
67
69
|
] as const;
|
|
68
70
|
|
|
69
71
|
export const PEEK_ROOT_KIND = ["range"] as const;
|
|
@@ -139,6 +141,7 @@ export const SETTING_NAME = [
|
|
|
139
141
|
"diffr_config",
|
|
140
142
|
"theme",
|
|
141
143
|
"ctrl_tab",
|
|
144
|
+
"open_files_in",
|
|
142
145
|
"ready_notification",
|
|
143
146
|
"document_width",
|
|
144
147
|
"code_font_size",
|
|
@@ -241,11 +244,43 @@ export const INSTALL_LOCATION = [
|
|
|
241
244
|
"other",
|
|
242
245
|
] as const;
|
|
243
246
|
|
|
244
|
-
export const DIFF_OPENED_VIA = [
|
|
247
|
+
export const DIFF_OPENED_VIA = [
|
|
248
|
+
"topbar",
|
|
249
|
+
"lens",
|
|
250
|
+
"locate",
|
|
251
|
+
"file_picker",
|
|
252
|
+
] as const;
|
|
245
253
|
|
|
246
254
|
/** Which diff opened: a commit's, or a file diff drawn plain or structural. */
|
|
247
255
|
export const DIFF_OPENED_KIND = ["commit", "structural"] as const;
|
|
248
256
|
|
|
257
|
+
/** GitHub Enterprise is any GitHub host but github.com. */
|
|
258
|
+
export const PR_PROVIDER = [
|
|
259
|
+
"github",
|
|
260
|
+
"github_enterprise",
|
|
261
|
+
"azure_devops",
|
|
262
|
+
] as const;
|
|
263
|
+
|
|
264
|
+
export const REMOTE_HOST_PROBLEM = [
|
|
265
|
+
"unreachable",
|
|
266
|
+
"not_installed",
|
|
267
|
+
"auth_failed",
|
|
268
|
+
"unsupported",
|
|
269
|
+
"incompatible",
|
|
270
|
+
] as const;
|
|
271
|
+
|
|
272
|
+
export const REMOTE_HOST_TARGET = ["linux-x64", "linux-arm64"] as const;
|
|
273
|
+
|
|
274
|
+
export const ASK_SELECTION = ["text", "code", "diff", "review"] as const;
|
|
275
|
+
|
|
276
|
+
export const ONBOARDING_STEP = ["welcome", "install", "run"] as const;
|
|
277
|
+
|
|
278
|
+
export const RUN_MODE = ["draw", "copy"] as const;
|
|
279
|
+
|
|
280
|
+
export const NEW_WHITEBOARD_VIA = ["button", "command"] as const;
|
|
281
|
+
|
|
282
|
+
export const FIND_SURFACE = ["review", "diff"] as const;
|
|
283
|
+
|
|
249
284
|
export const DISCORD_VIA = ["topbar", "dialog", "docs"] as const;
|
|
250
285
|
|
|
251
286
|
const REVIEW_DELETED_VIA = ["home"] as const;
|
|
@@ -514,6 +549,8 @@ export const UI_TELEMETRY_EVENTS = {
|
|
|
514
549
|
properties: {
|
|
515
550
|
source_kind: SESSION_SOURCE_KIND,
|
|
516
551
|
agent_kind: SESSION_AGENT_KIND,
|
|
552
|
+
remote: "boolean",
|
|
553
|
+
pr_provider: PR_PROVIDER,
|
|
517
554
|
},
|
|
518
555
|
},
|
|
519
556
|
session_ended: {
|
|
@@ -584,6 +621,55 @@ export const UI_TELEMETRY_EVENTS = {
|
|
|
584
621
|
},
|
|
585
622
|
// The reader copied the review's share link.
|
|
586
623
|
review_shared: { event: "review_review_shared", properties: {} },
|
|
624
|
+
find_opened: {
|
|
625
|
+
event: "review_find_opened",
|
|
626
|
+
properties: { surface: FIND_SURFACE },
|
|
627
|
+
},
|
|
628
|
+
ask_sent: {
|
|
629
|
+
event: "review_ask_sent",
|
|
630
|
+
properties: {
|
|
631
|
+
agent: askAgentIds,
|
|
632
|
+
follow_up: "boolean",
|
|
633
|
+
selection: ASK_SELECTION,
|
|
634
|
+
remote: "boolean",
|
|
635
|
+
},
|
|
636
|
+
},
|
|
637
|
+
onboarding_step_viewed: {
|
|
638
|
+
event: "review_onboarding_step_viewed",
|
|
639
|
+
properties: { step: ONBOARDING_STEP },
|
|
640
|
+
},
|
|
641
|
+
onboarding_skipped: {
|
|
642
|
+
event: "review_onboarding_skipped",
|
|
643
|
+
properties: { step: ONBOARDING_STEP },
|
|
644
|
+
},
|
|
645
|
+
onboarding_run_started: {
|
|
646
|
+
event: "review_onboarding_run_started",
|
|
647
|
+
properties: { mode: RUN_MODE, agent: askAgentIds },
|
|
648
|
+
},
|
|
649
|
+
new_whiteboard_opened: {
|
|
650
|
+
event: "review_new_whiteboard_opened",
|
|
651
|
+
properties: { via: NEW_WHITEBOARD_VIA },
|
|
652
|
+
},
|
|
653
|
+
new_whiteboard_started: {
|
|
654
|
+
event: "review_new_whiteboard_started",
|
|
655
|
+
properties: { mode: RUN_MODE, embedded: "boolean", agent: askAgentIds },
|
|
656
|
+
},
|
|
657
|
+
remote_host_installed: {
|
|
658
|
+
event: "review_remote_host_installed",
|
|
659
|
+
properties: {
|
|
660
|
+
ok: "boolean",
|
|
661
|
+
target: REMOTE_HOST_TARGET,
|
|
662
|
+
duration_ms: "number",
|
|
663
|
+
},
|
|
664
|
+
},
|
|
665
|
+
remote_host_connected: {
|
|
666
|
+
event: "review_remote_host_connected",
|
|
667
|
+
properties: {
|
|
668
|
+
ok: "boolean",
|
|
669
|
+
problem: REMOTE_HOST_PROBLEM,
|
|
670
|
+
direct: "boolean",
|
|
671
|
+
},
|
|
672
|
+
},
|
|
587
673
|
} as const satisfies Record<
|
|
588
674
|
string,
|
|
589
675
|
{ event: string; properties: Record<string, UiTelemetryPropertySpec> }
|
package/dist/profile-BBw-jMW3.js
DELETED