@dev.fast/whiteboard 0.2.5-preview.20261013.112 → 0.2.5-preview.20261015.115

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.
Files changed (130) hide show
  1. package/THIRD_PARTY_NOTICES.md +29 -0
  2. package/dist/{account-alias-D0hF0sKk.js → account-alias-ChZR3RIU.js} +94 -8
  3. package/dist/{agent-cli-BBPxwUOd.js → agent-cli-CR2PnA9G.js} +9 -12
  4. package/dist/agent-cli-CRPPmS3l.js +2 -0
  5. package/dist/{agent-client-P3J4y8Zn.js → agent-client-DVd-prfp.js} +31 -14
  6. package/dist/{authoring-tools-D8WXsm_g.js → authoring-tools-BXKEwhfi.js} +5 -5
  7. package/dist/background-server-Cw7CcfaZ.js +156 -0
  8. package/dist/background-server-D2Rrr_e2.js +2 -0
  9. package/dist/build-info.json +1 -1
  10. package/dist/{cli-C0ziP6hg.js → cli-CSrz_wGk.js} +1 -1
  11. package/dist/{cli-runner-C1gY-HAI.js → cli-runner-PlGqBeMw.js} +368 -252
  12. package/dist/cli.js +3 -2
  13. package/dist/{client-DzcSt6pV.js → client-DhZzPePs.js} +5 -3
  14. package/dist/{process-error-telemetry-C0swByfp.js → headless-host-CVXTSIlx.js} +3285 -2585
  15. package/dist/headless-host-Cp37C-v0.js +2 -0
  16. package/dist/input-error-OLgB_h31.js +11 -0
  17. package/dist/{local-data-BlERtVm2.js → local-data-yfLp5PiJ.js} +237 -157
  18. package/dist/{mcp-t7VN9R3k.js → mcp-DBbDwG4y.js} +4 -4
  19. package/dist/{package-paths-B9PDoAl6.js → package-paths-BsuI4WUf.js} +1 -1
  20. package/dist/profile-BSOkA6A-.js +2 -0
  21. package/dist/{profile-BsYDBr7t.js → profile-pAzg7fxC.js} +3 -3
  22. package/dist/remote-attach-BAt2eZx3.js +137 -0
  23. package/dist/remote-extensions-2Cxf3hMo.js +2 -0
  24. package/dist/remote-extensions-BiNx6NQK.js +323 -0
  25. package/dist/remote-language-server-DQgWUNeV.js +252 -0
  26. package/dist/remote-uninstall-DLtDG0o7.js +153 -0
  27. package/dist/{request-origin-DA4K1qWY.js → request-origin-DaRIV3cB.js} +5 -2
  28. package/dist/review-app-launcher-D7I4DGoH.js +222 -0
  29. package/dist/{review-home-paths-Y9mYWkCI.js → review-home-paths-zwevIq4I.js} +7 -7
  30. package/dist/{review-telemetry-CmM6tCbj.js → review-telemetry-BqB4CiTD.js} +5 -5
  31. package/dist/{s3-SzLpeCG6.js → s3-77-qkEhs.js} +1 -1
  32. package/dist/{s3-config-BgxkSoOy.js → s3-config-0xuCh-F_.js} +1 -1
  33. package/dist/{s3-config-CAxhO9u_.js → s3-config-DDWWMh5x.js} +5 -1
  34. package/dist/server/desktop-host.js +1663 -266
  35. package/dist/{desktop-discovery-Ba3dD5Cn.js → server-discovery-CifQ3yQS.js} +88 -3
  36. package/dist/sharing/index.d.ts +88 -32
  37. package/dist/sharing/index.js +1 -1
  38. package/dist/{src-DiHP11l3.js → src-BMPuxWv4.js} +6 -11
  39. package/dist/{src-WCbabvdS.js → src-Bgvf1sEN.js} +128 -8
  40. package/dist/{stored-document-migration-u4L_1VZa.js → stored-document-migration-CFOvjRwW.js} +5 -18
  41. package/dist/{tool-failure-CJHBCHMh.js → tool-failure-BXWzQG8T.js} +2 -2
  42. package/instructions/authoring.md +16 -12
  43. package/instructions/file-lenses.md +4 -2
  44. package/package.json +9 -14
  45. package/src/agent-connect.ts +507 -0
  46. package/src/agent-selection.ts +4 -0
  47. package/src/ask/agents.ts +59 -13
  48. package/src/ask/pi-mcp.ts +7 -3
  49. package/src/ask/thread-state.ts +9 -4
  50. package/src/ask/thread.ts +88 -50
  51. package/src/ask/threads.ts +53 -7
  52. package/src/cli-install.ts +3 -1
  53. package/src/cli-runner.ts +472 -81
  54. package/src/cli.ts +1 -1
  55. package/src/connect-agents.ts +285 -0
  56. package/src/connect-prompts.ts +60 -6
  57. package/src/desktop-discovery.ts +24 -0
  58. package/src/pinned-download.ts +118 -0
  59. package/src/remote-attach.ts +130 -0
  60. package/src/remote-extensions.ts +359 -0
  61. package/src/remote-language-server.ts +428 -0
  62. package/src/remote-toolchains.ts +107 -0
  63. package/src/remote-uninstall.ts +280 -0
  64. package/src/review-api/README.md +1 -3
  65. package/src/review-api/agent-cli.ts +4 -4
  66. package/src/review-api/agent-client.ts +23 -0
  67. package/src/review-api/ask-history.ts +31 -16
  68. package/src/review-api/authoring-tools.ts +1 -1
  69. package/src/review-api/blocks/index.ts +2 -4
  70. package/src/review-api/document.ts +1 -4
  71. package/src/review-api/github-provider.ts +154 -0
  72. package/src/review-api/http.ts +265 -237
  73. package/src/review-api/local-data.ts +34 -17
  74. package/src/review-api/onboarding.ts +478 -0
  75. package/src/review-api/origin.ts +10 -6
  76. package/src/review-api/provider.ts +44 -0
  77. package/src/review-api/pull-request.ts +15 -146
  78. package/src/review-api/recent-folders.ts +173 -0
  79. package/src/review-api/store.ts +56 -10
  80. package/src/review-api/workspaces.ts +56 -11
  81. package/src/review-app-launcher.ts +61 -3
  82. package/src/review-stack.ts +162 -36
  83. package/src/server/background-server.ts +250 -0
  84. package/src/server/desktop-host-shutdown.ts +24 -0
  85. package/src/server/desktop-host.ts +39 -24
  86. package/src/server/desktop-server.ts +68 -118
  87. package/src/server/global-verb-relay.ts +16 -0
  88. package/src/server/headless-host.ts +128 -3
  89. package/src/server/hono-http.ts +6 -1
  90. package/src/server/legacy-tutorial-cleanup.ts +38 -0
  91. package/src/server/review-gateway-hosts.ts +379 -0
  92. package/src/server/review-gateway-list.ts +109 -0
  93. package/src/server/review-gateway-memory.ts +130 -0
  94. package/src/server/review-gateway-pushes.ts +142 -0
  95. package/src/server/review-gateway-streams.ts +415 -0
  96. package/src/server/review-gateway-transport.ts +204 -0
  97. package/src/server/review-gateway.ts +433 -0
  98. package/src/server/review-server-core.ts +36 -6
  99. package/src/server-discovery.ts +11 -0
  100. package/src/sharing/import.ts +1 -0
  101. package/src/ui-telemetry-events.ts +5 -1
  102. package/src/vsix.ts +122 -0
  103. package/dist/agent-cli-YSuhE5X8.js +0 -2
  104. package/dist/headless-host-BHD_Vg5F.js +0 -95
  105. package/dist/profile-j97aRTS7.js +0 -2
  106. package/dist/server-discovery-ZVi8Ay8J.js +0 -66
  107. package/src/fixtures/blocks/tutorial.json +0 -14
  108. package/src/review-api/blocks/tutorial.ts +0 -23
  109. package/src/server/tutorial-service.ts +0 -217
  110. package/tutorial/document.json +0 -216
  111. package/tutorial/lenses.json +0 -10
  112. package/tutorial/runtime-manifest.json +0 -11
  113. package/tutorial/sample-service/package.json +0 -9
  114. package/tutorial/sample-service/src/api/checkout-api.ts +0 -17
  115. package/tutorial/sample-service/src/app.ts +0 -26
  116. package/tutorial/sample-service/src/database/drizzle-orm.d.ts +0 -16
  117. package/tutorial/sample-service/src/database/schema.ts +0 -9
  118. package/tutorial/sample-service/src/fulfillment/fulfillment-queue.ts +0 -15
  119. package/tutorial/sample-service/src/fulfillment/fulfillment-worker.ts +0 -24
  120. package/tutorial/sample-service/src/inventory/forklift-mood.ts +0 -4
  121. package/tutorial/sample-service/src/inventory/inventory-service.ts +0 -28
  122. package/tutorial/sample-service/src/inventory/warehouse-lore.ts +0 -11
  123. package/tutorial/sample-service/src/orders/order-service.ts +0 -35
  124. package/tutorial/sample-service/src/orders/order.ts +0 -43
  125. package/tutorial/sample-service/src/orders/orders-repository.ts +0 -24
  126. package/tutorial/sample-service/src/payments/fraud-vibes.ts +0 -4
  127. package/tutorial/sample-service/src/payments/payment-gateway.ts +0 -29
  128. package/tutorial/sample-service/src/payments/raccoon-ledger.ts +0 -9
  129. package/tutorial/sample-service/src/shipping/shipping-gateway.ts +0 -15
  130. package/tutorial/sample-service/tsconfig.json +0 -12
@@ -91,3 +91,32 @@ Direct third-party runtime/UI dependencies currently include:
91
91
  - `semver` (`ISC`)
92
92
  - `zod` (`MIT`)
93
93
  - `zustand` (`MIT`)
94
+ - `yauzl` (`MIT`)
95
+
96
+ ## Bundled VS Code Server
97
+
98
+ The published package carries `vscode-server/`, staged by
99
+ `apps/review-desktop/scripts/stage-vscode-server.mjs`. It is built from the
100
+ Code OSS fork (`MIT`) and carries the fork's `LICENSE.txt` and
101
+ `ThirdPartyNotices.txt`. It bundles:
102
+
103
+ - in the server and extension host (`MIT` unless noted): `@vscode/proxy-agent`,
104
+ `agent-base`, `cookie`, `debug`, `http-proxy-agent`, `https-proxy-agent`,
105
+ `ip-address`, `minimist`, `ms`, `smart-buffer`, `socks`,
106
+ `socks-proxy-agent`, `supports-color`, `undici`, `vscode-regexpp` and
107
+ `tslib` (`0BSD`)
108
+ - in the built-in language extensions (`MIT` unless noted): `@vscode/l10n`,
109
+ `@vscode/sync-api-client`, `@vscode/sync-api-common`,
110
+ `@vscode/sync-api-service`, `@vscode/ts-package-manager`, `jsonc-parser`,
111
+ `request-light`, `semver` (`ISC`), `vscode-css-languageservice`,
112
+ `vscode-html-languageservice`, `vscode-json-languageservice`,
113
+ `vscode-languageclient`, `vscode-languageserver`,
114
+ `vscode-languageserver-textdocument`, `vscode-tas-client` and `vscode-uri`
115
+ - `typescript` (`Apache-2.0`), for the built-in TypeScript extension
116
+ - `@vscode/ripgrep-universal` (`MIT`), whose `rg` binaries are ripgrep
117
+ (`MIT OR Unlicense`)
118
+ - `@parcel/watcher` and its Linux prebuilds (`MIT`), with `detect-libc`
119
+ (`Apache-2.0`), `is-glob`, `is-extglob` and `picomatch` (`MIT`)
120
+
121
+ Curated extensions are not bundled; `whiteboard remote extensions ensure`
122
+ downloads them from Open VSX on the remote.
@@ -1,7 +1,7 @@
1
- import { h as ReviewCliInstallStampSchema } from "./src-WCbabvdS.js";
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
- import { A as devReviewHome, N as writeFileAtomicAsync, O as withFileLock, P as writePrivateJsonAtomic } from "./s3-config-CAxhO9u_.js";
4
- import { i as readReviewPackageVersion } from "./package-paths-B9PDoAl6.js";
1
+ import { w as ReviewCliInstallStampSchema } from "./src-Bgvf1sEN.js";
2
+ import { $ as removeAgentTraceHook, C as disableTraceMachine, E as traceMachineStatus, G as listTraceRepositoryRoots, K as traceRepositoryStatus, Q as installHarnessHooks, S as configureTraceMachine, T as traceMachineEnabled, U as disableAllTraceRepositories, W as enableTraceRepository, Y as AGENT_TRACE_HOOK_AGENTS, Z as describeTraceHookOwners, ft as StoreClient, n as reviewDesktopStateDir, rt as traceScope, st as readStoreAuth } from "./review-home-paths-zwevIq4I.js";
3
+ import { A as withFileLock, F as writeFileAtomicAsync, I as writePrivateJsonAtomic, M as devReviewHome } from "./s3-config-DDWWMh5x.js";
4
+ import { i as readReviewPackageVersion } from "./package-paths-BsuI4WUf.js";
5
5
  import { n as isFile, t as isDirectory } from "./fs-utils-BMPLt0cr.js";
6
6
  import { createHash } from "node:crypto";
7
7
  import { constants } from "node:fs";
@@ -75,12 +75,84 @@ function fffSteps(input, target) {
75
75
  const CLAUDE_WINDOWS_MCP_ADD = `claude mcp add -s user whiteboard -- ${WINDOWS_MCP_LAUNCH.command} ${WINDOWS_MCP_LAUNCH.args.join(" ")}`;
76
76
  /** Copilot CLI loads the Claude plugin, so on Windows it too registers the server directly. */
77
77
  const COPILOT_WINDOWS_MCP_ADD = `copilot mcp add whiteboard -- ${WINDOWS_MCP_LAUNCH.command} ${WINDOWS_MCP_LAUNCH.args.join(" ")}`;
78
+ const CONNECT_COMMANDS = {
79
+ claude: [
80
+ { argv: [
81
+ "claude",
82
+ "plugin",
83
+ "marketplace",
84
+ "add",
85
+ "devdotfast/whiteboard"
86
+ ] },
87
+ { argv: [
88
+ "claude",
89
+ "plugin",
90
+ "install",
91
+ "whiteboard@devfast",
92
+ "--scope",
93
+ "user"
94
+ ] },
95
+ {
96
+ argv: [
97
+ "claude",
98
+ "mcp",
99
+ "remove",
100
+ "-s",
101
+ "user",
102
+ "whiteboard"
103
+ ],
104
+ ifAny: true
105
+ }
106
+ ],
107
+ codex: [
108
+ { argv: [
109
+ "codex",
110
+ "plugin",
111
+ "marketplace",
112
+ "add",
113
+ "devdotfast/whiteboard"
114
+ ] },
115
+ { argv: [
116
+ "codex",
117
+ "plugin",
118
+ "add",
119
+ "whiteboard@devfast"
120
+ ] },
121
+ {
122
+ argv: [
123
+ "codex",
124
+ "mcp",
125
+ "remove",
126
+ "whiteboard"
127
+ ],
128
+ ifAny: true
129
+ }
130
+ ],
131
+ opencode: [{ argv: [
132
+ "opencode",
133
+ "mcp",
134
+ "add",
135
+ "--global",
136
+ "whiteboard",
137
+ "--",
138
+ REVIEW_MCP_LAUNCH.command,
139
+ ...REVIEW_MCP_LAUNCH.args
140
+ ] }],
141
+ pi: [{ argv: [
142
+ "pi",
143
+ "install",
144
+ PI_WHITEBOARD_PACKAGE
145
+ ] }]
146
+ };
147
+ function runBlock(commands) {
148
+ return `Run:\n\n\`\`\`sh\n${commands.map(({ argv, ifAny }) => `${argv.join(" ")}${ifAny ? " # old manual registration, if any" : ""}`).join("\n")}\n\`\`\``;
149
+ }
78
150
  function pluginSteps(target, platform) {
79
151
  switch (target) {
80
152
  case "claude":
81
153
  if (platform === "win32") return [`Run:\n\n\`\`\`sh\nclaude plugin uninstall whiteboard@devfast # its launch cannot start on Windows, if installed\nclaude mcp remove -s user whiteboard # old registration, if any\n${CLAUDE_WINDOWS_MCP_ADD}\n\`\`\``];
82
- return ["Run:\n\n```sh\nclaude plugin marketplace add devdotfast/whiteboard\nclaude plugin install whiteboard@devfast --scope user\nclaude mcp remove -s user whiteboard # old manual registration, if any\n```"];
83
- case "codex": return ["Run:\n\n```sh\ncodex plugin marketplace add devdotfast/whiteboard\ncodex plugin add whiteboard@devfast\ncodex mcp remove whiteboard # old manual registration, if any\n```"];
154
+ return [runBlock(CONNECT_COMMANDS.claude)];
155
+ case "codex": return [runBlock(CONNECT_COMMANDS.codex)];
84
156
  case "opencode": {
85
157
  const launch = reviewMcpLaunch(true, platform);
86
158
  const entry = JSON.stringify({ whiteboard: {
@@ -145,6 +217,20 @@ function connectPrompts(input) {
145
217
  };
146
218
  }
147
219
  //#endregion
220
+ //#region src/install.ts
221
+ const ALL_INSTALL_TARGETS = [
222
+ "claude",
223
+ "codex",
224
+ "cursor",
225
+ "opencode",
226
+ "pi",
227
+ "omp",
228
+ "copilot"
229
+ ];
230
+ function isInstallTarget(value) {
231
+ return ALL_INSTALL_TARGETS.some((target) => target === value);
232
+ }
233
+ //#endregion
148
234
  //#region src/legacy-skills.ts
149
235
  const LEGACY_SKILL_NAMES = [
150
236
  "whiteboard",
@@ -316,7 +402,7 @@ async function windowsUserPathContains(directory, key = "HKCU\\Environment") {
316
402
  const installErrors = /* @__PURE__ */ new Map();
317
403
  const SHIM_MARKER = "Managed by Whiteboard";
318
404
  function hasManagedShimMarker(source) {
319
- return source.includes(SHIM_MARKER) || source.includes("Managed by Review Desktop") || source.includes("Managed by Whiteboard Desktop");
405
+ return source.includes(SHIM_MARKER) || source.includes("Managed by Review Desktop") || source.includes("Managed by Whiteboard Desktop") || source.includes("# Written by Whiteboard Desktop, which replaces it with each install.");
320
406
  }
321
407
  const PROFILE_MARKER = "# Managed by Review Desktop: review command PATH. Do not edit.";
322
408
  const PROFILE_BLOCK = `\n${PROFILE_MARKER}\nexport PATH="\$HOME/.local/bin:\$PATH"\n`;
@@ -969,4 +1055,4 @@ async function aliasInstallationToAccount(telemetry, env = process.env, fetchImp
969
1055
  } catch {}
970
1056
  }
971
1057
  //#endregion
972
- export { isOwnedShim as a, removeLegacyReviewSkills as c, skipCliInstall as d, windowsInstallerCommand as f, finishCliInstallUpdate as i, resetCliInstall as l, connectPrompts as m, applyCliInstall as n, pathShimPath as o, scanLegacySkills as p, declineCliInstall as r, removeCliInstall as s, aliasInstallationToAccount as t, resolveCliInstallStatus as u };
1058
+ export { connectPrompts as _, isOwnedShim as a, removeLegacyReviewSkills as c, skipCliInstall as d, windowsInstallerCommand as f, CONNECT_COMMANDS as g, isInstallTarget as h, finishCliInstallUpdate as i, resetCliInstall as l, ALL_INSTALL_TARGETS as m, applyCliInstall as n, pathShimPath as o, scanLegacySkills as p, declineCliInstall as r, removeCliInstall as s, aliasInstallationToAccount as t, resolveCliInstallStatus as u, reviewMcpLaunch as v, cursorInstallDeeplink as y };
@@ -1,11 +1,11 @@
1
1
  import { n as isJsonObject, u as parseJsonText } from "./src-X9phtB2j.js";
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";
4
- import { A as devReviewHome } from "./s3-config-CAxhO9u_.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
- 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-CJHBCHMh.js";
2
+ import { T as traceMachineEnabled } from "./review-home-paths-zwevIq4I.js";
3
+ import { a as toolResultText, i as connectReviewInstance, s as ReviewApiError } from "./agent-client-DVd-prfp.js";
4
+ import { M as devReviewHome } from "./s3-config-DDWWMh5x.js";
5
+ import { b as selectReviewInstance, u as REVIEW_INSTANCE_ENV } from "./server-discovery-CifQ3yQS.js";
6
+ import { n as reviewSessionAgent } from "./review-telemetry-BqB4CiTD.js";
7
+ import { n as REVIEW_VIA_HEADER, t as REVIEW_AGENT_HEADER } from "./request-origin-DaRIV3cB.js";
8
+ import { i as publicTool, n as RECOVERY, r as callPublicTool, t as toolFailure } from "./tool-failure-BXWzQG8T.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) {
@@ -18,12 +18,9 @@ async function runReviewAgentCli(input) {
18
18
  return 0;
19
19
  }
20
20
  if (extra.length || mode === "mcp" && name) throw new Error("Unexpected arguments. Use whiteboard api --help.");
21
- const headers = {
22
- [REVIEW_VIA_HEADER]: mode === "mcp" ? "mcp" : "api",
23
- [REVIEW_AGENT_HEADER]: reviewSessionAgent(env)
24
- };
21
+ const headers = Object.fromEntries([[REVIEW_VIA_HEADER, mode === "mcp" ? "mcp" : "api"], [REVIEW_AGENT_HEADER, reviewSessionAgent(env)]]);
25
22
  if (mode === "mcp") {
26
- const { serveReviewMcp } = await import("./mcp-t7VN9R3k.js");
23
+ const { serveReviewMcp } = await import("./mcp-DBbDwG4y.js");
27
24
  await serveReviewMcp(async (key, agentKind) => {
28
25
  const connected = await connectReviewInstance(key ? {
29
26
  ...env,
@@ -0,0 +1,2 @@
1
+ import { n as runReviewAgentCli } from "./agent-cli-CR2PnA9G.js";
2
+ export { runReviewAgentCli };
@@ -1,8 +1,7 @@
1
- import { C as ReviewInputError } from "./src-DiHP11l3.js";
2
1
  import { d as isBooleanValue, f as isNumberValue, m as isStringValue, u as parseJsonText } from "./src-X9phtB2j.js";
3
- import "./src-WCbabvdS.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";
2
+ import "./src-Bgvf1sEN.js";
3
+ import { t as ReviewInputError } from "./input-error-OLgB_h31.js";
4
+ import { b as selectReviewInstance, c as reviewServerStateDir, d as ReviewInstanceUnavailableError, i as readReviewServerDiscovery, l as serverNotReady, m as healthyReviewInstance, s as reviewServerIsHealthy, y as reviewInstanceUnavailable } from "./server-discovery-CifQ3yQS.js";
6
5
  //#region ../review-protocol/src/review-api-client.ts
7
6
  const defaultRequest = (url, init) => fetch(url, init);
8
7
  /** A non-2xx reply; the status tells a caller whether retrying can help. */
@@ -44,8 +43,8 @@ var ReviewApiClient = class {
44
43
  signal
45
44
  })).json();
46
45
  }
47
- async *watch(reviewId, signal) {
48
- const reader = (await this.response(Array.isArray(reviewId) ? `/watch?subscriptions=${encodeURIComponent(JSON.stringify(reviewId))}` : reviewId === null ? "/watch" : `/${encodeURIComponent(reviewId)}/watch`, { signal })).body.pipeThrough(new TextDecoderStream()).getReader();
46
+ async *watch(subscriptions, signal) {
47
+ const reader = (await this.response(`/watch?subscriptions=${encodeURIComponent(JSON.stringify(subscriptions))}`, { signal })).body.pipeThrough(new TextDecoderStream()).getReader();
49
48
  const cancel = () => {
50
49
  reader.cancel().catch(() => {});
51
50
  };
@@ -73,7 +72,7 @@ var ReviewApiClient = class {
73
72
  if (signal.aborted) return;
74
73
  let connections = liveConnections.get(this.request);
75
74
  if (!connections) liveConnections.set(this.request, connections = /* @__PURE__ */ new Map());
76
- const key = JSON.stringify([this.connection.serverUrl, this.connection.token]);
75
+ const key = this.liveKey();
77
76
  let live = connections.get(key);
78
77
  if (!live) {
79
78
  live = new LiveConnection(this, () => connections.delete(key));
@@ -83,6 +82,13 @@ var ReviewApiClient = class {
83
82
  if (mode) subscription.mode = mode;
84
83
  return live.add(subscription, signal, (value) => accept(value), disconnected);
85
84
  }
85
+ /** Reopen the shared stream now rather than after its backoff. */
86
+ reconnect() {
87
+ liveConnections.get(this.request)?.get(this.liveKey())?.reconnect();
88
+ }
89
+ liveKey() {
90
+ return JSON.stringify([this.connection.serverUrl, this.connection.token]);
91
+ }
86
92
  };
87
93
  const restartDelayMs = 20;
88
94
  const retryDelayMs = 1e3;
@@ -97,6 +103,9 @@ function sleep(ms, signal) {
97
103
  signal.addEventListener("abort", done, { once: true });
98
104
  });
99
105
  }
106
+ function concerns(line, subscription) {
107
+ return line.kind === "list" ? subscription.reviewId === null && (subscription.mode ?? "structural") === line.mode : subscription.reviewId === line.reviewId;
108
+ }
100
109
  function report(listener, cause) {
101
110
  if (listener.signal.aborted) return;
102
111
  try {
@@ -165,13 +174,11 @@ var LiveConnection = class {
165
174
  let delay = 1e3;
166
175
  while (!signal.aborted) {
167
176
  try {
168
- for await (const results of this.client.watch(listeners.map((item) => item.subscription), signal)) {
177
+ for await (const line of this.client.watch(listeners.map((item) => item.subscription), signal)) {
169
178
  if (signal.aborted) break;
170
179
  delay = 1e3;
171
- listeners.forEach((listener, index) => {
172
- const result = results[index];
173
- if (result) this.deliver(listener, result);
174
- });
180
+ const result = line.kind === "list" ? { value: line.reviews } : line;
181
+ for (const listener of listeners) if (concerns(line, listener.subscription)) this.deliver(listener, result);
175
182
  }
176
183
  if (!signal.aborted) disconnected(/* @__PURE__ */ new Error("Connection closed."));
177
184
  } catch (error) {
@@ -195,7 +202,7 @@ var LiveConnection = class {
195
202
  while (listener.queued && !listener.signal.aborted) {
196
203
  const next = listener.queued;
197
204
  listener.queued = void 0;
198
- if (next.error) {
205
+ if ("error" in next) {
199
206
  report(listener, new Error(next.error));
200
207
  continue;
201
208
  }
@@ -222,7 +229,7 @@ const TEXT_TOOLS = /* @__PURE__ */ new Set([
222
229
  async function connectReviewApi(env = process.env, headers = {}) {
223
230
  return (await connectReviewInstance(env, headers)).client;
224
231
  }
225
- async function connectReviewInstance(env = process.env, headers = {}) {
232
+ async function connectReviewInstance(env = process.env, headers = {}, options = {}) {
226
233
  const request = (url, init) => {
227
234
  const merged = new Headers(init?.headers);
228
235
  for (const [key, value] of Object.entries(headers)) merged.set(key, value);
@@ -243,6 +250,16 @@ async function connectReviewInstance(env = process.env, headers = {}) {
243
250
  const selection = await selectReviewInstance({ env });
244
251
  const discovery = healthyReviewInstance(selection);
245
252
  if (!discovery) {
253
+ const { ensureServerWithoutDesktop } = await import("./background-server-D2Rrr_e2.js");
254
+ const server = await ensureServerWithoutDesktop({
255
+ selection,
256
+ env,
257
+ ...options
258
+ });
259
+ if (server) return { client: new ReviewApiClient({
260
+ serverUrl: server.url,
261
+ token: server.token
262
+ }, request) };
246
263
  const unavailable = reviewInstanceUnavailable(selection);
247
264
  const message = `${unavailable.message} For headless authoring, select a running server with --state-dir or DEV_REVIEW_SERVER_DIR.`;
248
265
  if (unavailable instanceof ReviewInstanceUnavailableError) throw new ReviewInstanceUnavailableError(message);
@@ -1,7 +1,7 @@
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";
1
+ import { _ as activityUpdateSchema, g as activityEndSchema, h as activityBeginSchema, i as commandSchema, n as uploadSchema } from "./local-data-yfLp5PiJ.js";
2
+ import { x as publishedEditSchema, y as pathTargetSchema } from "./stored-document-migration-CFOvjRwW.js";
3
+ import { t as ReviewInputError } from "./input-error-OLgB_h31.js";
4
+ import { t as findReviewPackageRoot } from "./package-paths-BsuI4WUf.js";
5
5
  import { z } from "zod";
6
6
  import { readFile } from "node:fs/promises";
7
7
  import path from "node:path";
@@ -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 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.",
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 branch stacked on another, pass the branch below it as base; Desktop links reviews into a stack through their bases. 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).",
@@ -0,0 +1,156 @@
1
+ import "./review-home-paths-zwevIq4I.js";
2
+ import { D as liveLockOwner, O as processIsAlive } from "./s3-config-DDWWMh5x.js";
3
+ import { t as findReviewPackageRoot } from "./package-paths-BsuI4WUf.js";
4
+ import { a as readReviewServerHealth, c as reviewServerStateDir, i as readReviewServerDiscovery, n as desktopOwnsHome, p as desktopUsesHome, r as headlessServerLockPath } from "./server-discovery-CifQ3yQS.js";
5
+ import { t as desktopApplicationInstalled } from "./review-app-launcher-D7I4DGoH.js";
6
+ import { mkdir, open, readFile, realpath, stat } from "node:fs/promises";
7
+ import path from "node:path";
8
+ import { spawn } from "node:child_process";
9
+ import { setTimeout } from "node:timers/promises";
10
+ //#region src/server/background-server.ts
11
+ function backgroundServerLogPath(stateDir) {
12
+ return path.join(stateDir, "review-server", "server.log");
13
+ }
14
+ async function ensureBackgroundServer(input) {
15
+ const stateDir = path.resolve(input.stateDir);
16
+ const running = await healthyDiscovery(stateDir);
17
+ if (running) return {
18
+ discovery: running,
19
+ started: false
20
+ };
21
+ if (await desktopUsesHome(stateDir, input.env)) throw new Error(desktopOwnsHome(stateDir));
22
+ const logPath = backgroundServerLogPath(stateDir);
23
+ await mkdir(path.dirname(logPath), {
24
+ recursive: true,
25
+ mode: 448
26
+ });
27
+ const logStart = (await stat(logPath).catch(() => null))?.size ?? 0;
28
+ const deadline = Date.now() + (input.timeoutMs ?? 15e3);
29
+ let child = await spawnServer(stateDir, logPath, input);
30
+ let respawned = false;
31
+ while (Date.now() < deadline) {
32
+ const discovery = await healthyDiscovery(stateDir);
33
+ if (discovery) return {
34
+ discovery,
35
+ started: discovery.serverPid === child.pid
36
+ };
37
+ if (child.error) throw new Error(`Could not start the Whiteboard server: ${child.error.message}`);
38
+ if (child.exited && await headlessServerOwner(stateDir) === void 0) {
39
+ if (respawned) break;
40
+ respawned = true;
41
+ child = await spawnServer(stateDir, logPath, input);
42
+ }
43
+ await setTimeout(100);
44
+ }
45
+ const owner = await headlessServerOwner(stateDir);
46
+ throw new Error(`The Whiteboard server did not become ready${child.exited ? "" : ` within ${Math.round((input.timeoutMs ?? 15e3) / 1e3)} s; process ${child.pid} is still starting`}.${owner !== void 0 && owner !== child.pid ? ` Process ${owner} holds its state directory without answering; \`whiteboard server stop\` ends it.` : ""} The end of ${logPath}:\n${await logTail(logPath, logStart)}`);
47
+ }
48
+ async function ensureServerWithoutDesktop(input) {
49
+ const { selection, env } = input;
50
+ if (selection.source !== "fallback" || selection.instances.length !== 0 || selection.problem || (input.desktopInstalled ?? (() => desktopApplicationInstalled({ env })))()) return void 0;
51
+ const { discovery } = await ensureBackgroundServer({
52
+ stateDir: reviewServerStateDir(env),
53
+ env,
54
+ cli: input.cli
55
+ });
56
+ return discovery;
57
+ }
58
+ async function headlessServerOwner(stateDir) {
59
+ const resolved = await realpath(stateDir).catch(() => path.resolve(stateDir));
60
+ return liveLockOwner(headlessServerLockPath(resolved));
61
+ }
62
+ async function recordedBackgroundServer(stateDir) {
63
+ const discovery = await readReviewServerDiscovery(stateDir).catch(() => null);
64
+ const health = discovery && await readReviewServerHealth(discovery);
65
+ return discovery && health?.serverPid === discovery.serverPid ? {
66
+ discovery,
67
+ health
68
+ } : void 0;
69
+ }
70
+ async function stopBackgroundServer(discovery, first = "SIGTERM") {
71
+ const { serverPid } = discovery;
72
+ for (const [signal, waitMs] of [[first, 1e4], ["SIGKILL", 2e3]]) {
73
+ try {
74
+ process.kill(serverPid, signal);
75
+ } catch (error) {
76
+ if (error instanceof Error && "code" in error && error.code === "ESRCH") return;
77
+ throw error;
78
+ }
79
+ for (let waited = 0; waited < waitMs; waited += 100) {
80
+ if (!processIsAlive(serverPid)) return;
81
+ await setTimeout(100);
82
+ }
83
+ }
84
+ throw new Error(`The Whiteboard server (process ${serverPid}) did not stop.`);
85
+ }
86
+ async function spawnDetached(input) {
87
+ const log = await open(input.log, "a", 384);
88
+ const child = spawn(input.command, input.args, {
89
+ cwd: input.cwd,
90
+ detached: true,
91
+ env: input.env,
92
+ stdio: [
93
+ "ignore",
94
+ log.fd,
95
+ log.fd
96
+ ]
97
+ });
98
+ const state = {
99
+ pid: child.pid,
100
+ exited: false
101
+ };
102
+ child.once("exit", () => state.exited = true);
103
+ child.once("error", (error) => {
104
+ state.exited = true;
105
+ state.error = error;
106
+ });
107
+ child.unref();
108
+ await log.close();
109
+ return state;
110
+ }
111
+ function spawnServer(stateDir, logPath, input) {
112
+ const { command, args, env } = cliSpawn(input.cli, input.env ?? process.env);
113
+ return spawnDetached({
114
+ command,
115
+ args: [
116
+ ...args,
117
+ "server",
118
+ "start",
119
+ "--state-dir",
120
+ stateDir,
121
+ "--started-by",
122
+ input.startedBy ?? "cli",
123
+ ...input.args ?? []
124
+ ],
125
+ cwd: stateDir,
126
+ env,
127
+ log: logPath
128
+ });
129
+ }
130
+ function cliSpawn(cli, env) {
131
+ const [command, ...args] = cli ?? currentCli();
132
+ return {
133
+ command,
134
+ args,
135
+ env: args.at(-1)?.endsWith(".ts") && !env.TSX_TSCONFIG_PATH ? {
136
+ ...env,
137
+ TSX_TSCONFIG_PATH: path.join(findReviewPackageRoot(import.meta.url), "tsconfig.json")
138
+ } : env
139
+ };
140
+ }
141
+ function currentCli() {
142
+ return [
143
+ process.execPath,
144
+ ...process.execArgv,
145
+ path.resolve(process.argv[1])
146
+ ];
147
+ }
148
+ async function healthyDiscovery(stateDir) {
149
+ const discovery = await readReviewServerDiscovery(stateDir).catch(() => null);
150
+ return discovery && await readReviewServerHealth(discovery) ? discovery : null;
151
+ }
152
+ async function logTail(logPath, from) {
153
+ return (await readFile(logPath)).subarray(from).toString("utf8").trimEnd().split("\n").slice(-20).join("\n");
154
+ }
155
+ //#endregion
156
+ export { headlessServerOwner as a, stopBackgroundServer as c, ensureServerWithoutDesktop as i, cliSpawn as n, recordedBackgroundServer as o, ensureBackgroundServer as r, spawnDetached as s, backgroundServerLogPath as t };
@@ -0,0 +1,2 @@
1
+ import { a as headlessServerOwner, c as stopBackgroundServer, i as ensureServerWithoutDesktop, r as ensureBackgroundServer } from "./background-server-Cw7CcfaZ.js";
2
+ export { ensureBackgroundServer, ensureServerWithoutDesktop, headlessServerOwner, stopBackgroundServer };
@@ -1 +1 @@
1
- {"version":"0.2.5-preview.20261013.112","commit":"4e32ec3f86a57d0ed72ae2d23f3f45fcc0cfa1eb","dirty":true,"builtAt":"2026-10-13T06:13:17.195Z"}
1
+ {"version":"0.2.5-preview.20261015.115","commit":"fd78e6a852a7f20798854059c5196c661f0df44f","dirty":true,"builtAt":"2026-10-15T00:45:01.986Z"}
@@ -1,4 +1,4 @@
1
- import { r as connectReviewApi } from "./agent-client-P3J4y8Zn.js";
1
+ import { r as connectReviewApi } from "./agent-client-DVd-prfp.js";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { z } from "zod";
4
4
  //#region src/sharing/cli.ts