@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,7 @@
|
|
|
1
1
|
import { h as ReviewCliInstallStampSchema } from "./src-WCbabvdS.js";
|
|
2
|
-
import { G as
|
|
2
|
+
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-Y9mYWkCI.js";
|
|
3
3
|
import { A as devReviewHome, N as writeFileAtomicAsync, O as withFileLock, P as writePrivateJsonAtomic } from "./s3-config-CAxhO9u_.js";
|
|
4
|
-
import {
|
|
5
|
-
import { i as readReviewPackageVersion } from "./package-paths-B6-zxvIO.js";
|
|
4
|
+
import { i as readReviewPackageVersion } from "./package-paths-B9PDoAl6.js";
|
|
6
5
|
import { n as isFile, t as isDirectory } from "./fs-utils-BMPLt0cr.js";
|
|
7
6
|
import { createHash } from "node:crypto";
|
|
8
7
|
import { constants } from "node:fs";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { n as isJsonObject, u as parseJsonText } from "./src-X9phtB2j.js";
|
|
2
|
-
import {
|
|
2
|
+
import { T as traceMachineEnabled } from "./review-home-paths-Y9mYWkCI.js";
|
|
3
|
+
import { a as toolResultText, i as connectReviewInstance, s as ReviewApiError } from "./agent-client-P3J4y8Zn.js";
|
|
3
4
|
import { A as devReviewHome } from "./s3-config-CAxhO9u_.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { n as reviewSessionAgent } from "./review-telemetry-DBy3eVCo.js";
|
|
5
|
+
import { d as selectReviewInstance, t as REVIEW_INSTANCE_ENV } from "./desktop-discovery-Ba3dD5Cn.js";
|
|
6
|
+
import { n as reviewSessionAgent } from "./review-telemetry-CmM6tCbj.js";
|
|
7
7
|
import { n as REVIEW_VIA_HEADER, t as REVIEW_AGENT_HEADER } from "./request-origin-DA4K1qWY.js";
|
|
8
|
-
import { i as publicTool, n as RECOVERY, r as callPublicTool, t as toolFailure } from "./tool-failure-
|
|
8
|
+
import { i as publicTool, n as RECOVERY, r as callPublicTool, t as toolFailure } from "./tool-failure-CJHBCHMh.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";
|
|
11
11
|
async function runReviewAgentCli(input) {
|
|
@@ -23,7 +23,7 @@ async function runReviewAgentCli(input) {
|
|
|
23
23
|
[REVIEW_AGENT_HEADER]: reviewSessionAgent(env)
|
|
24
24
|
};
|
|
25
25
|
if (mode === "mcp") {
|
|
26
|
-
const { serveReviewMcp } = await import("./mcp-
|
|
26
|
+
const { serveReviewMcp } = await import("./mcp-t7VN9R3k.js");
|
|
27
27
|
await serveReviewMcp(async (key, agentKind) => {
|
|
28
28
|
const connected = await connectReviewInstance(key ? {
|
|
29
29
|
...env,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { C as ReviewInputError } from "./src-DiHP11l3.js";
|
|
1
2
|
import { d as isBooleanValue, f as isNumberValue, m as isStringValue, u as parseJsonText } from "./src-X9phtB2j.js";
|
|
2
3
|
import "./src-WCbabvdS.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { a as reviewServerIsHealthy, n as readReviewServerDiscovery, o as reviewServerStateDir, s as serverNotReady } from "./server-discovery-Dbzn3w6Z.js";
|
|
4
|
+
import { d as selectReviewInstance, i as healthyReviewInstance, n as ReviewInstanceUnavailableError, u as reviewInstanceUnavailable } from "./desktop-discovery-Ba3dD5Cn.js";
|
|
5
|
+
import { a as reviewServerIsHealthy, n as readReviewServerDiscovery, o as reviewServerStateDir, s as serverNotReady } from "./server-discovery-ZVi8Ay8J.js";
|
|
6
6
|
//#region ../review-protocol/src/review-api-client.ts
|
|
7
7
|
const defaultRequest = (url, init) => fetch(url, init);
|
|
8
8
|
/** A non-2xx reply; the status tells a caller whether retrying can help. */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { t as findReviewPackageRoot } from "./package-paths-
|
|
1
|
+
import { C as ReviewInputError } from "./src-DiHP11l3.js";
|
|
2
|
+
import { g as activityUpdateSchema, h as activityEndSchema, i as commandSchema, m as activityBeginSchema, n as uploadSchema } from "./local-data-BlERtVm2.js";
|
|
3
|
+
import { x as publishedEditSchema, y as pathTargetSchema } from "./stored-document-migration-u4L_1VZa.js";
|
|
4
|
+
import { t as findReviewPackageRoot } from "./package-paths-B9PDoAl6.js";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { readFile } from "node:fs/promises";
|
|
7
7
|
import path from "node:path";
|
|
@@ -92,7 +92,7 @@ const COMPONENT_REFERENCE = [
|
|
|
92
92
|
"- call_stack_diff {title, base: frame[], head: frame[], pins?}; either side may be empty",
|
|
93
93
|
"- frame {source: anchor, label?, key?, parentKey? (an earlier frame on that side), callSite?: anchor, contextSources?: anchor[], via?: {kind: call|queue|callback|rpc, reason}, pins?}",
|
|
94
94
|
"- database_lens {title, actors: {key: label}, stores: {key: store}, useCases: useCase[] (1 or more), pins?}",
|
|
95
|
-
"- store {label, storage: relational|document, collections: {key: {label, fields: {key: field}}}, dataStoreKind?: database|objectStore|bucket|artifactStore|fileStore}",
|
|
95
|
+
"- store {label, storage: relational|document, collections: {key: {label, fields: {key: field}, source?: anchor of its schema declaration}}, dataStoreKind?: database|objectStore|bucket|artifactStore|fileStore}",
|
|
96
96
|
"- field {label, dataType, nullable?, primaryKey?, references?: {store, collection, field}, fields?: {key: field}}",
|
|
97
97
|
"- useCase {label, summary?, operations: operation[] (1 or more)}; operation {kind: read|write, actor, store, collection, label, source: anchor, field?, detail?, pins?}, naming declared keys",
|
|
98
98
|
"",
|
|
@@ -166,7 +166,7 @@ function authoringTools(scratchpadAvailable = false, traceEnabled = false) {
|
|
|
166
166
|
kind: true
|
|
167
167
|
});
|
|
168
168
|
const descriptions = {
|
|
169
|
-
create: "Create a review of saved working files, immutable commits or a GitHub PR. Revisions are resolved on acceptance. A worktree target reviews the saved files in its checkout, uncommitted ones included and untracked ones left out (git add -N a new file to include it), against base: the branch to compare against, by default the default branch of the repository. The diff starts at the merge base of base and HEAD, which follows rebases. Omitted commits base means source at head with no diff; supply the parent to review introduced changes. For a GitHub PR, pullRequestUrl alone is enough: target and title become optional, and the host fetches the PR into a registered checkout of its repository and pins the current PR head and GitHub diff base, titled from the PR. When
|
|
169
|
+
create: "Create a review of saved working files, immutable commits or a GitHub PR. Revisions are resolved on acceptance. A worktree target reviews the saved files in its checkout, uncommitted ones included and untracked ones left out (git add -N a new file to include it), against base: the branch to compare against, by default the default branch of the repository. The diff starts at the merge base of base and HEAD, which follows rebases. Omitted commits base means source at head with no diff; supply the parent to review introduced changes. For a GitHub PR, pullRequestUrl alone is enough: target and title become optional, and the host fetches the PR into a registered checkout of its repository and pins the current PR head and GitHub diff base, titled from the PR. When the existing review for that PR is in Trash, creation reports its ID; restore it with review_lifecycle state:\"active\" before continuing. When an active review for that PR exists, it is returned instead, reporting whether its head moved and whether an agent is working on it; update it in place, move its target with review_set_target, or create a separate review with reuseExisting. kind:\"scratchpad\" names the one scratchpad, which the host creates itself. The result carries review, the review as review_list shows it: its target with resolved commits, origin (its PR), repositoryName and repositoryPath, so no follow-up read is needed before diffing. When Desktop is available the review opens there and the result reports opened, softwareMapEnabled and environmentIssues, as review_open does; set open:false to author in the background without taking over Desktop.",
|
|
170
170
|
set_target: "Move the review to a new target, such as the commits after a rebase or amend, preserving the document and component IDs. Revisions are resolved on acceptance. Returns warnings for retained source ranges in files the new commits changed, to verify, and resources that no longer match; fix them with review_edit. Earlier versions keep their source. Omitted pullRequestUrl keeps the PR within the same repository; changing repositories clears it. Supply a URL to replace it or null to detach.",
|
|
171
171
|
edit: [
|
|
172
172
|
"Edit one document component. content is one component, named by its type; each type's fields are in the Components section of session_get_instructions (authoring or scratchpad).",
|
|
@@ -178,11 +178,12 @@ function authoringTools(scratchpadAvailable = false, traceEnabled = false) {
|
|
|
178
178
|
lens_edit: "Edit one Diff-view lens. Lenses partition the review's change for the Diff view; they sit beside the document (never in it) and version with it. The host assigns durable lens IDs; updates replace only the fields supplied. Write one lens per call while a reader may be watching; each draws in on the Diffs page. Pass your activityId so your courier draws each lens. The result identifies the lens and reports uncategorized: changed lines no lens selects yet, grouped by file. Keep adding lenses until it is empty or what remains is deliberate. review_lens_get reads the current lenses and gaps.",
|
|
179
179
|
rename: "Change the review title.",
|
|
180
180
|
restore: "Restore title, source pins, PR identity and content from a saved version.",
|
|
181
|
-
attention: "Mark
|
|
182
|
-
|
|
181
|
+
attention: "Mark an active review viewed without changing its content or lifecycle. Restore a review from Trash before marking it viewed.",
|
|
182
|
+
lifecycle: "Move a review between active and trash. Trash retains the review for 30 days before automatic deletion. Moving it back to active restores it; moving it to trash again does not restart that period.",
|
|
183
|
+
delete: "Permanently delete a review and its history. The review must be in Trash. This cannot be undone."
|
|
183
184
|
};
|
|
184
185
|
const tool = (name, description, schema, method, path, commandType) => ({
|
|
185
|
-
name: `review_${name}`,
|
|
186
|
+
name: `review_${name === "restore" ? "restore_version" : name}`,
|
|
186
187
|
description,
|
|
187
188
|
inputSchema: {
|
|
188
189
|
...z.toJSONSchema(schema, { io: "input" }),
|
|
@@ -220,7 +221,7 @@ function authoringTools(scratchpadAvailable = false, traceEnabled = false) {
|
|
|
220
221
|
}), "GET", "/:reviewId/inspect"),
|
|
221
222
|
tool("lens_get", "Read the review's Diff-view lenses as authored (ids, titles, targets), each lens's resolved fileCount (and unavailable reason, if any), and uncategorized: the changed lines no lens selects yet, by file.", z.strictObject(review), "GET", "/:reviewId/lenses"),
|
|
222
223
|
tool("history", "List saved document versions.", z.strictObject(review), "GET", "/:reviewId/history"),
|
|
223
|
-
tool("open", "Show an
|
|
224
|
+
tool("open", "Show an active review immediately; restore it from Trash before opening it. Prepare current pinned checkouts in the background. Returns softwareMapEnabled and any already-recorded environmentIssues. Missing optional setup is not an issue; use review_environment to recheck.", z.strictObject(review), "POST", "/:reviewId/open"),
|
|
224
225
|
tool("environment", "Acquire and recheck this review's current base/head language checkouts (not historical or selected commits). Returns acquisition issues, not full LSP health. Missing optional setup and failed setup with a usable checkout stay silent. Set retry:true to rerun failed preparation after an actual language-feature failure; preparation runs in the background.", z.strictObject({
|
|
225
226
|
...review,
|
|
226
227
|
retry: z.boolean().optional()
|
package/dist/build-info.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"0.2.
|
|
1
|
+
{"version":"0.2.5-preview.20261013.109","commit":"a3d88565d0643e8a8f9e80f24a9b9d29b6a97e3d","dirty":true,"builtAt":"2026-10-13T01:39:18.933Z"}
|
|
@@ -1,19 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { E as __toESM, S as setLocalVcsCommandObserver, T as __require, w as __commonJSMin } from "./src-DiHP11l3.js";
|
|
2
2
|
import { c as jsonString, n as isJsonObject, u as parseJsonText } from "./src-X9phtB2j.js";
|
|
3
3
|
import { a as parseReviewVerbResponse } from "./src-WCbabvdS.js";
|
|
4
|
-
import { $ as
|
|
5
|
-
import { o as ReviewApiClient, s as ReviewApiError } from "./agent-client-
|
|
4
|
+
import { $ as resolveTraceCommand, A as runTraceDeny, E as traceMachineStatus, F as describeSelection, H as resolveTraceRepositoryTarget, J as HOSTED_CAPTURE_SCOPE_DESCRIPTION, K as traceRepositoryStatus, L as loadS3TraceStorage, M as runTraceSessions, N as runTraceStoreDelete, P as runTraceStoreInfo, T as traceMachineEnabled, V as requireTraceConsent, _ as runTraceRepair, b as runTraceGitHook, c as registerTraceCommands, ct as runStoreLogout, d as runTraceList$1, dt as StoreClient, f as runTracePull$1, ft as withStoreAuthorization, g as runTraceInstallMachine, gt as jsonRequestedInArgv, h as runTraceEnable, ht as humanStream, j as runTraceOnboard, k as runTraceAllow, l as resolveTraceReadStorage, lt as runStoreWhoami, m as runTraceDisable, mt as failWithJsonError, nt as traceScope, ot as readStoreAuth, p as runTraceShow, pt as emitJsonEvent, q as readTraceUserConfig, rt as DEFAULT_STORE_ORIGIN, st as runStoreLogin, tt as traceHomeDir, u as runTraceBlame, ut as StoreApiError, v as runTraceStatus, w as readLegacyCaptureSettings, x as runTraceHook, y as runTraceSync, z as selectTraceStorage } from "./review-home-paths-Y9mYWkCI.js";
|
|
5
|
+
import { o as ReviewApiClient, s as ReviewApiError } from "./agent-client-P3J4y8Zn.js";
|
|
6
6
|
import { t as resolveReviewRoot } from "./runtime-CKiWhGrf.js";
|
|
7
7
|
import { A as devReviewHome, C as s3ProfileSchema, D as processIsAlive, E as writeTraceConfigFile, S as readTraceConfigFile, T as sameS3Profile, _ as emptyTraceConfig, c as resolveS3Setup, g as currentStore, h as TraceConfigurationError, i as isS3MockMode, j as normalizeStoreOrigin, k as DEV_REVIEW_HOME_ENV, n as clearTraceEnvCache, o as readTraceEnvFile, p as traceSettingsPath, w as s3Store } from "./s3-config-CAxhO9u_.js";
|
|
8
8
|
import { t as errorMessage } from "./error-message-OtiDonty.js";
|
|
9
|
-
import {
|
|
10
|
-
import { i as
|
|
11
|
-
import {
|
|
12
|
-
import { t as
|
|
13
|
-
import { a as isOwnedShim, f as windowsInstallerCommand, m as connectPrompts, o as pathShimPath, p as scanLegacySkills, t as aliasInstallationToAccount } from "./account-alias-_1_7vROx.js";
|
|
9
|
+
import { i as readReviewPackageVersion, r as readBuildInfo, t as findReviewPackageRoot } from "./package-paths-B9PDoAl6.js";
|
|
10
|
+
import { a as readDefaultReviewInstance, d as selectReviewInstance, f as writeDefaultReviewInstance, i as healthyReviewInstance, l as reviewInstanceStartHint, n as ReviewInstanceUnavailableError, o as readReviewInstances, r as clearDefaultReviewInstance, s as requireHealthyReviewDesktop, t as REVIEW_INSTANCE_ENV, u as reviewInstanceUnavailable } from "./desktop-discovery-Ba3dD5Cn.js";
|
|
11
|
+
import { t as ReviewTelemetry } from "./review-telemetry-CmM6tCbj.js";
|
|
12
|
+
import { a as isOwnedShim, f as windowsInstallerCommand, m as connectPrompts, o as pathShimPath, p as scanLegacySkills, t as aliasInstallationToAccount } from "./account-alias-D0hF0sKk.js";
|
|
14
13
|
import { t as fuzzyRank } from "./fuzzy-match-BoAmcyak.js";
|
|
15
|
-
import { n as readReviewServerDiscovery, o as reviewServerStateDir, r as readReviewServerHealth, s as serverNotReady } from "./server-discovery-
|
|
16
|
-
import { t as reviewAgentCliHelp } from "./agent-cli-
|
|
14
|
+
import { n as readReviewServerDiscovery, o as reviewServerStateDir, r as readReviewServerHealth, s as serverNotReady } from "./server-discovery-ZVi8Ay8J.js";
|
|
15
|
+
import { t as reviewAgentCliHelp } from "./agent-cli-BBPxwUOd.js";
|
|
17
16
|
import { closeSync, existsSync, fstatSync, mkdirSync, mkdtempSync, openSync, readSync, renameSync, writeFileSync } from "node:fs";
|
|
18
17
|
import { realpath } from "node:fs/promises";
|
|
19
18
|
import path from "node:path";
|
|
@@ -394,7 +393,7 @@ async function runReviewAppPick(input, overrides = {}) {
|
|
|
394
393
|
else {
|
|
395
394
|
if (!input.stdin.isTTY) throw new ReviewAppUsageError("whiteboard app pick needs a terminal without --session. Pass --session <uuid> or run it in a terminal.");
|
|
396
395
|
const root = await runtime.resolveReviewRoot(input.cwd);
|
|
397
|
-
const reviews = (await client.read("")).filter((review) => review.repositoryPath === root && !review.
|
|
396
|
+
const reviews = (await client.read("")).filter((review) => review.repositoryPath === root && !review.trashedAt).sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
398
397
|
if (!reviews.length) throw new ReviewAppStateError("No review to show.");
|
|
399
398
|
const picked = await runtime.pickReview(reviews.map((review) => ({
|
|
400
399
|
uuid: review.reviewId,
|
|
@@ -440,7 +439,7 @@ async function runReviewInfo(input, runtime = {
|
|
|
440
439
|
const root = await runtime.resolveReviewRoot(input.cwd);
|
|
441
440
|
return {
|
|
442
441
|
event: "info",
|
|
443
|
-
reviews: reviews.filter((review) => review.repositoryPath === root && (input.all || !review.
|
|
442
|
+
reviews: reviews.filter((review) => review.repositoryPath === root && (input.all || !review.trashedAt))
|
|
444
443
|
};
|
|
445
444
|
}
|
|
446
445
|
//#endregion
|
|
@@ -4495,7 +4494,7 @@ async function runReviewCli(input) {
|
|
|
4495
4494
|
process.once("SIGINT", stop);
|
|
4496
4495
|
process.once("SIGTERM", stop);
|
|
4497
4496
|
try {
|
|
4498
|
-
const { runHeadlessServer } = await import("./headless-host-
|
|
4497
|
+
const { runHeadlessServer } = await import("./headless-host-BHD_Vg5F.js");
|
|
4499
4498
|
await runHeadlessServer({
|
|
4500
4499
|
stateDir,
|
|
4501
4500
|
port,
|
|
@@ -4546,7 +4545,7 @@ async function runReviewCli(input) {
|
|
|
4546
4545
|
if (problem) throw new Error(`Cannot tell whether a Whiteboard Desktop is using ${stateDir}: ${problem.message}`);
|
|
4547
4546
|
const inUse = () => /* @__PURE__ */ new Error(`A Whiteboard server is using ${stateDir}. Stop it first, then run whiteboard server reset-id again.`);
|
|
4548
4547
|
if (desktops.instances.some(({ discovery }) => [discovery.appPid, discovery.serverPid].some((pid) => processIsAlive(pid)))) throw inUse();
|
|
4549
|
-
const [{ openReviewProfile }, { withHeadlessServerLock }] = await Promise.all([import("./profile-
|
|
4548
|
+
const [{ openReviewProfile }, { withHeadlessServerLock }] = await Promise.all([import("./profile-j97aRTS7.js"), import("./headless-host-BHD_Vg5F.js")]);
|
|
4550
4549
|
const reset = await withHeadlessServerLock(await realpath(stateDir), async () => {
|
|
4551
4550
|
const local = await openReviewProfile(stateDir, { manageWorkspaces: false });
|
|
4552
4551
|
try {
|
|
@@ -4686,14 +4685,14 @@ async function runReviewCli(input) {
|
|
|
4686
4685
|
command.showHelpAfterError(false).error("Markdown review migration is no longer supported. Ask your agent to migrate your old Whiteboard reviews.");
|
|
4687
4686
|
});
|
|
4688
4687
|
configureJsonOutput(configureJsonOutput(program.command("share").description("Upload an immutable review snapshot and return its share link"), "plain").option("--review <id>", "review ID").option("--version <number>", "Saved version to share").option("--preview", "Open the share link in Whiteboard Preview by default").option("--request-id <uuid>", "Reuse this ID when retrying the same immutable upload").action(async (options) => {
|
|
4689
|
-
const { runShareCli } = await import("./cli-
|
|
4688
|
+
const { runShareCli } = await import("./cli-C0ziP6hg.js");
|
|
4690
4689
|
state.exitCode = await runShareCli({
|
|
4691
4690
|
...input,
|
|
4692
4691
|
...options,
|
|
4693
4692
|
env: authoringEnv()
|
|
4694
4693
|
});
|
|
4695
4694
|
}).command("revoke <share-id>").description("Revoke future downloads of a share"), "plain").action(async (shareId, options) => {
|
|
4696
|
-
const { runShareCli } = await import("./cli-
|
|
4695
|
+
const { runShareCli } = await import("./cli-C0ziP6hg.js");
|
|
4697
4696
|
state.exitCode = await runShareCli({
|
|
4698
4697
|
...input,
|
|
4699
4698
|
...options,
|
|
@@ -4774,7 +4773,7 @@ async function runReviewCli(input) {
|
|
|
4774
4773
|
return commands;
|
|
4775
4774
|
} });
|
|
4776
4775
|
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) => {
|
|
4777
|
-
const { runReviewAgentCli } = await import("./agent-cli-
|
|
4776
|
+
const { runReviewAgentCli } = await import("./agent-cli-YSuhE5X8.js");
|
|
4778
4777
|
state.exitCode = await runReviewAgentCli({
|
|
4779
4778
|
...input,
|
|
4780
4779
|
env: authoringEnv(),
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { d as gitAt } from "./src-
|
|
1
|
+
import { C as ReviewInputError, d as gitAt } from "./src-DiHP11l3.js";
|
|
2
2
|
import { n as isJsonObject, u as parseJsonText } from "./src-X9phtB2j.js";
|
|
3
3
|
import "./src-WCbabvdS.js";
|
|
4
|
-
import { B as parseMarkdown, C as resourceReferences, E as sourceReferences, K as sourceAnchors, M as lensSchema, N as lensSelections, O as checkReferences, S as resourceReference, _ as hasCodeReferences, b as pinsSchema, c as traceSchema, h as elements, l as textIncludesQuote, n as migrateStoredDocument, o as normalizedSoftwareElementSchema, p as documentSchema, r as migrateStoredLenses, s as normalizedSoftwareRelationshipSchema, t as liftFileLenses, u as anchorPins, z as markdownNodes } from "./stored-document-migration-
|
|
5
|
-
import { t as ReviewInputError } from "./input-error-OLgB_h31.js";
|
|
4
|
+
import { B as parseMarkdown, C as resourceReferences, E as sourceReferences, K as sourceAnchors, M as lensSchema, N as lensSelections, O as checkReferences, S as resourceReference, _ as hasCodeReferences, b as pinsSchema, c as traceSchema, h as elements, l as textIncludesQuote, n as migrateStoredDocument, o as normalizedSoftwareElementSchema, p as documentSchema, r as migrateStoredLenses, s as normalizedSoftwareRelationshipSchema, t as liftFileLenses, u as anchorPins, z as markdownNodes } from "./stored-document-migration-u4L_1VZa.js";
|
|
6
5
|
import { createHash, randomUUID } from "node:crypto";
|
|
7
6
|
import { z } from "zod";
|
|
8
7
|
import { existsSync } from "node:fs";
|
|
@@ -127,7 +126,7 @@ function validateShareSources(snapshot) {
|
|
|
127
126
|
}
|
|
128
127
|
/** Freeze one stored version before any asynchronous source reads. */
|
|
129
128
|
async function exportShare(input) {
|
|
130
|
-
const { target, kind: _kind, staleSources: _staleSources, sourceUnavailable: _sourceUnavailable, lastEdit: _lastEdit, ...snapshot } = structuredClone(input.store.read(input.reviewId, input.version));
|
|
129
|
+
const { target, kind: _kind, staleSources: _staleSources, sourceUnavailable: _sourceUnavailable, lastEdit: _lastEdit, trashedAt: _trashedAt, ...snapshot } = structuredClone(input.store.read(input.reviewId, input.version));
|
|
131
130
|
if (target?.kind === "worktree") throw new ReviewInputError("Pin this review to commits before sharing it.");
|
|
132
131
|
documentSchema.parse(snapshot.document);
|
|
133
132
|
checkReferences(snapshot.document);
|
|
@@ -439,12 +438,16 @@ var SharedReviewStore = class {
|
|
|
439
438
|
attention = /* @__PURE__ */ new Map();
|
|
440
439
|
listeners = /* @__PURE__ */ new Set();
|
|
441
440
|
catalogLoaded = false;
|
|
441
|
+
purgeTimer;
|
|
442
|
+
purgePending;
|
|
442
443
|
downloads = /* @__PURE__ */ new Set();
|
|
443
444
|
trackImport(job) {
|
|
444
445
|
this.downloads.add(job);
|
|
445
446
|
job.finally(() => this.downloads.delete(job));
|
|
446
447
|
}
|
|
447
448
|
async close() {
|
|
449
|
+
clearInterval(this.purgeTimer);
|
|
450
|
+
await this.purgePending;
|
|
448
451
|
await Promise.allSettled([...this.downloads, ...this.jobs.values()]);
|
|
449
452
|
}
|
|
450
453
|
local;
|
|
@@ -454,12 +457,28 @@ var SharedReviewStore = class {
|
|
|
454
457
|
constructor(root, fetchRepository = fetchPinnedRepository) {
|
|
455
458
|
this.root = root;
|
|
456
459
|
this.fetchRepository = fetchRepository;
|
|
460
|
+
this.purgeTimer = setInterval(() => {
|
|
461
|
+
this.purgeExpired().catch((error) => console.error("Could not purge expired shared whiteboards:", error));
|
|
462
|
+
}, 6e4);
|
|
463
|
+
this.purgeTimer.unref();
|
|
464
|
+
}
|
|
465
|
+
purgeExpired() {
|
|
466
|
+
if (this.purgePending) return this.purgePending;
|
|
467
|
+
const expired = [...this.attention].filter(([, state]) => state.trashedAt && Date.parse(state.trashedAt) <= Date.now() - 2592e6);
|
|
468
|
+
const pending = (async () => {
|
|
469
|
+
for (const [id] of expired) await this.removeLocal(id);
|
|
470
|
+
})();
|
|
471
|
+
this.purgePending = pending.finally(() => {
|
|
472
|
+
this.purgePending = void 0;
|
|
473
|
+
});
|
|
474
|
+
return this.purgePending;
|
|
457
475
|
}
|
|
458
476
|
connect(store, data) {
|
|
459
477
|
this.local = {
|
|
460
478
|
store,
|
|
461
479
|
data
|
|
462
480
|
};
|
|
481
|
+
store.askHistory.setExternalWriteGuard((id) => this.assertWritable(id));
|
|
463
482
|
data.workspaces.attachExternalReviews({
|
|
464
483
|
has: (id) => this.has(id) || !this.catalogLoaded && id.startsWith("shared-"),
|
|
465
484
|
subscribe: (listener) => this.subscribe(listener)
|
|
@@ -602,16 +621,32 @@ var SharedReviewStore = class {
|
|
|
602
621
|
this.repositories.set(id, repository.id);
|
|
603
622
|
this.setStatus(id, "ready");
|
|
604
623
|
} else this.setStatus(id, "error", "Reopen the share link to fetch its repository.");
|
|
605
|
-
|
|
606
|
-
|
|
624
|
+
const attentionPath = path.join(this.root, id, "attention.json");
|
|
625
|
+
if (existsSync(attentionPath)) {
|
|
626
|
+
const raw = JSON.parse(await readFile(attentionPath, "utf8"));
|
|
627
|
+
const migrated = Object.hasOwn(raw, "dismissedAt") || Object.hasOwn(raw, "deletedAt");
|
|
628
|
+
const state = z.strictObject({
|
|
607
629
|
viewedAt: z.string().nullable(),
|
|
608
|
-
|
|
609
|
-
}).parse(
|
|
610
|
-
|
|
630
|
+
trashedAt: z.string().nullable()
|
|
631
|
+
}).parse(migrated ? {
|
|
632
|
+
viewedAt: raw.viewedAt,
|
|
633
|
+
trashedAt: Object.hasOwn(raw, "deletedAt") ? raw.deletedAt : raw.dismissedAt ? (/* @__PURE__ */ new Date()).toISOString() : null
|
|
634
|
+
} : raw);
|
|
635
|
+
this.attention.set(id, state);
|
|
636
|
+
if (migrated) await writeFile(attentionPath, JSON.stringify(state), { mode: 384 });
|
|
637
|
+
}
|
|
611
638
|
}
|
|
639
|
+
await this.purgeExpired();
|
|
612
640
|
this.catalogLoaded = true;
|
|
613
641
|
for (const listener of this.listeners) listener();
|
|
614
642
|
}
|
|
643
|
+
assertWritable(id) {
|
|
644
|
+
const trashedAt = this.attention.get(id)?.trashedAt;
|
|
645
|
+
if (trashedAt) throw new ReviewInputError(`This whiteboard was moved to Trash on ${new Date(trashedAt).toLocaleDateString("en-US", {
|
|
646
|
+
month: "short",
|
|
647
|
+
day: "numeric"
|
|
648
|
+
})}. Restore it with session_lifecycle({"sessionId":"${id}","state":"active"}) to continue.`, 409);
|
|
649
|
+
}
|
|
615
650
|
get(id) {
|
|
616
651
|
const bundle = this.loaded.get(id);
|
|
617
652
|
if (!bundle) throw new ReviewInputError("Shared review is not available.", 404);
|
|
@@ -623,6 +658,7 @@ var SharedReviewStore = class {
|
|
|
623
658
|
snapshot: {
|
|
624
659
|
...validated.snapshot,
|
|
625
660
|
reviewId: id,
|
|
661
|
+
trashedAt: this.attention.get(id)?.trashedAt ?? null,
|
|
626
662
|
pins: validated.snapshot.pins ? {
|
|
627
663
|
...validated.snapshot.pins,
|
|
628
664
|
repositoryId
|
|
@@ -647,7 +683,7 @@ var SharedReviewStore = class {
|
|
|
647
683
|
firstCreatedAt: snapshot.version === 0 ? snapshot.createdAt : void 0,
|
|
648
684
|
repositoryName: "Shared review",
|
|
649
685
|
viewedAt: this.attention.get(id)?.viewedAt ?? null,
|
|
650
|
-
|
|
686
|
+
trashedAt: this.attention.get(id)?.trashedAt ?? null
|
|
651
687
|
};
|
|
652
688
|
}).toArray();
|
|
653
689
|
return this.local?.store.withDiffStats(reviews, mode) ?? reviews;
|
|
@@ -680,19 +716,32 @@ var SharedReviewStore = class {
|
|
|
680
716
|
recursive: true,
|
|
681
717
|
force: true
|
|
682
718
|
});
|
|
719
|
+
this.local?.store.askHistory.removeReview(id);
|
|
683
720
|
this.loaded.delete(id);
|
|
684
721
|
this.validated.delete(id);
|
|
685
722
|
this.attention.delete(id);
|
|
686
723
|
for (const listener of this.listeners) listener();
|
|
687
724
|
}
|
|
688
|
-
async setAttention(id
|
|
725
|
+
async setAttention(id) {
|
|
726
|
+
await this.updateAttention(id, "view");
|
|
727
|
+
}
|
|
728
|
+
async setLifecycle(id, state) {
|
|
729
|
+
await this.updateAttention(id, state);
|
|
730
|
+
}
|
|
731
|
+
async updateAttention(id, action) {
|
|
689
732
|
this.get(id);
|
|
733
|
+
const trashedAt = this.attention.get(id)?.trashedAt;
|
|
734
|
+
if (trashedAt && Date.parse(trashedAt) <= Date.now() - 2592e6) {
|
|
735
|
+
await this.removeLocal(id);
|
|
736
|
+
throw new ReviewInputError("The 30-day recovery period has ended. This whiteboard was permanently deleted.", 404);
|
|
737
|
+
}
|
|
738
|
+
if (action === "view") this.assertWritable(id);
|
|
690
739
|
const state = this.attention.get(id) ?? {
|
|
691
740
|
viewedAt: null,
|
|
692
|
-
|
|
741
|
+
trashedAt: null
|
|
693
742
|
};
|
|
694
743
|
if (action === "view") state.viewedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
695
|
-
else state.
|
|
744
|
+
else state.trashedAt = action === "trash" ? state.trashedAt ?? (/* @__PURE__ */ new Date()).toISOString() : null;
|
|
696
745
|
await writeFile(path.join(this.root, id, "attention.json"), JSON.stringify(state), { mode: 384 });
|
|
697
746
|
this.attention.set(id, state);
|
|
698
747
|
for (const listener of this.listeners) listener();
|
|
@@ -700,6 +749,7 @@ var SharedReviewStore = class {
|
|
|
700
749
|
async import(origin, shareId, bundle) {
|
|
701
750
|
const validated = validateShareBundle(bundle);
|
|
702
751
|
const id = sharedReviewId(origin, shareId);
|
|
752
|
+
this.assertWritable(id);
|
|
703
753
|
await mkdir(this.root, {
|
|
704
754
|
recursive: true,
|
|
705
755
|
mode: 448
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as jsonNumber, n as isJsonObject, s as jsonProperty, u as parseJsonText } from "./src-X9phtB2j.js";
|
|
2
2
|
import { n as parseReviewDesktopDiscovery } from "./src-WCbabvdS.js";
|
|
3
|
-
import { a as reviewInstancesDir, o as reviewLegacyDiscoveryPath, r as reviewDevInstanceKey, t as reviewDefaultInstancePath } from "./review-home-paths-
|
|
3
|
+
import { a as reviewInstancesDir, o as reviewLegacyDiscoveryPath, r as reviewDevInstanceKey, t as reviewDefaultInstancePath } from "./review-home-paths-Y9mYWkCI.js";
|
|
4
4
|
import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
//#region src/desktop-discovery.ts
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { p as isObjectValue } from "./src-X9phtB2j.js";
|
|
2
|
+
import "./review-home-paths-Y9mYWkCI.js";
|
|
2
3
|
import { O as withFileLock, P as writePrivateJsonAtomic } from "./s3-config-CAxhO9u_.js";
|
|
3
|
-
import "./
|
|
4
|
-
import { t as
|
|
5
|
-
import { i as
|
|
6
|
-
import { i as reviewServerDiscoveryPath, t as headlessServerLockPath } from "./server-discovery-Dbzn3w6Z.js";
|
|
4
|
+
import { t as openReviewProfile } from "./profile-BsYDBr7t.js";
|
|
5
|
+
import { i as createWhiteboardCore, l as createNodeRequestListener, m as migrateDiffrConfig, n as installProcessErrorTelemetry, p as GlobalReviewDesktopVerbRelay, t as drainServerCrashReport } from "./process-error-telemetry-C0swByfp.js";
|
|
6
|
+
import { i as reviewServerDiscoveryPath, t as headlessServerLockPath } from "./server-discovery-ZVi8Ay8J.js";
|
|
7
7
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
8
8
|
import { mkdir, realpath, rm } from "node:fs/promises";
|
|
9
9
|
import { createServer } from "node:http";
|