@dev.fast/whiteboard 0.2.5-preview.20261015.119 → 0.2.5-preview.20261016.121

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 (69) hide show
  1. package/dist/{account-alias-C1ixP6bt.js → account-alias-CwNaMOwU.js} +372 -85
  2. package/dist/agent-cli-NWQPsL0W.js +2 -0
  3. package/dist/{agent-cli-CPSnWc9V.js → agent-cli-S0bt9I7V.js} +7 -7
  4. package/dist/{agent-client-Dogh8I83.js → agent-client-DjXQy6CL.js} +5 -6
  5. package/dist/{authoring-tools-CtsslOEf.js → authoring-tools-CjFAGHBa.js} +5 -4
  6. package/dist/{background-server-BKR_lpYb.js → background-server-CVL7QpsL.js} +1 -1
  7. package/dist/{background-server-DJT0CnYH.js → background-server-ONy-xKJ1.js} +4 -4
  8. package/dist/build-info.json +1 -1
  9. package/dist/{cli-Df6p-C19.js → cli-Cko4zfif.js} +1 -1
  10. package/dist/{cli-runner-ZktCwlLk.js → cli-runner-BhBnAC_R.js} +51 -187
  11. package/dist/cli.js +2 -2
  12. package/dist/{client-_ltX1mah.js → client-CLqKkzOc.js} +4 -4
  13. package/dist/fuzzy-match-DFPKdSLR.js +335 -0
  14. package/dist/{headless-host-Pj2xfGAo.js → headless-host-BNF-TR3x.js} +1 -1
  15. package/dist/{headless-host-ZNZ_6ZRo.js → headless-host-mg9sQG6H.js} +53 -345
  16. package/dist/{local-data-D_9S--yI.js → local-data-DN-A5p0K.js} +57 -415
  17. package/dist/{mcp-Blb7rzGw.js → mcp-BY4ExeMQ.js} +3 -3
  18. package/dist/{package-paths-BsuI4WUf.js → package-paths-jMg6JxDP.js} +1 -1
  19. package/dist/profile-BBw-jMW3.js +2 -0
  20. package/dist/{profile-CKSB6UDi.js → profile-Dm6irjbg.js} +2 -2
  21. package/dist/{remote-attach-CiOwonJ3.js → remote-attach-DJxW9402.js} +4 -4
  22. package/dist/{remote-extensions-D_4DSOhO.js → remote-extensions-BCAbQZTv.js} +2 -2
  23. package/dist/{remote-extensions-ByiuSl1D.js → remote-extensions-Cf3L-ZGG.js} +1 -1
  24. package/dist/{remote-language-server-BQjBk81F.js → remote-language-server-CGsCaqro.js} +4 -4
  25. package/dist/{remote-uninstall-pzHb-Hfd.js → remote-uninstall-DYmNOetF.js} +5 -5
  26. package/dist/{request-origin-C-V9f3Fr.js → request-origin-D1RNVSeK.js} +2 -7
  27. package/dist/{review-app-launcher-S2FZBY4W.js → review-app-launcher-i1hmxOZA.js} +2 -2
  28. package/dist/{review-home-paths-zwevIq4I.js → review-home-paths-Lc02WFuX.js} +1 -1
  29. package/dist/{review-telemetry-9ceqh4wz.js → review-telemetry-DnQNwgR1.js} +4 -4
  30. package/dist/server/desktop-host.js +99 -445
  31. package/dist/{server-discovery-CqRxbsER.js → server-discovery-DVqrcIDT.js} +2 -2
  32. package/dist/sharing/index.d.ts +17 -13
  33. package/dist/sharing/index.js +1 -1
  34. package/dist/{src-HnIPjtjx.js → src-DZG1xAqW.js} +4 -1
  35. package/dist/{stored-document-migration-DenDEYdI.js → stored-document-migration-DLBhkSfp.js} +46 -6
  36. package/dist/thread-state-CaQ2lGdj.js +400 -0
  37. package/dist/{tool-failure-aSYcHDxP.js → tool-failure-CVJrfi5s.js} +1 -1
  38. package/package.json +3 -3
  39. package/src/agent-connect.ts +29 -106
  40. package/src/cli-install.ts +13 -11
  41. package/src/cli-runner.ts +51 -24
  42. package/src/connect-prompts.ts +135 -71
  43. package/src/review-api/README.md +1 -1
  44. package/src/review-api/azure-devops-provider.ts +4 -0
  45. package/src/review-api/blocks/definition.ts +3 -1
  46. package/src/review-api/blocks/index.ts +19 -0
  47. package/src/review-api/blocks/sequence.ts +80 -2
  48. package/src/review-api/comparison-coverage.ts +0 -13
  49. package/src/review-api/component-reference.ts +2 -1
  50. package/src/review-api/document-text.ts +7 -2
  51. package/src/review-api/document.ts +13 -9
  52. package/src/review-api/github-provider.ts +21 -3
  53. package/src/review-api/http.ts +22 -41
  54. package/src/review-api/local-data.ts +22 -27
  55. package/src/review-api/pull-request.ts +2 -0
  56. package/src/review-api/review-progress.ts +6 -8
  57. package/src/review-api/store.ts +36 -25
  58. package/src/review-stack.ts +3 -2
  59. package/src/server/review-gateway-hosts.ts +8 -1
  60. package/src/server/review-gateway-list.ts +4 -10
  61. package/src/server/review-gateway-memory.ts +6 -19
  62. package/src/server/review-gateway-streams.ts +32 -46
  63. package/src/sharing/import.ts +2 -2
  64. package/src/ui-telemetry-events.ts +1 -2
  65. package/dist/agent-cli-CGapivA1.js +0 -2
  66. package/dist/fs-utils-BMPLt0cr.js +0 -22
  67. package/dist/fuzzy-match-BoAmcyak.js +0 -30
  68. package/dist/profile-BUoTujrK.js +0 -2
  69. package/src/connect-agents.ts +0 -285
@@ -1 +1 @@
1
- {"version":"0.2.5-preview.20261015.119","commit":"9fec707cf268ad13594e3d0cf90d69c294a1c4ca","dirty":true,"builtAt":"2026-10-15T18:38:14.546Z"}
1
+ {"version":"0.2.5-preview.20261016.121","commit":"3c1b0477310222ab5a70d7c52b66f65dc62ffc5d","dirty":true,"builtAt":"2026-10-16T14:28:51.746Z"}
@@ -1,4 +1,4 @@
1
- import { r as connectReviewApi } from "./agent-client-Dogh8I83.js";
1
+ import { r as connectReviewApi } from "./agent-client-DjXQy6CL.js";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { z } from "zod";
4
4
  //#region src/sharing/cli.ts
@@ -1,31 +1,27 @@
1
1
  import { C as setLocalVcsCommandObserver, E as __toESM, T as __require, w as __commonJSMin } from "./src-BMPuxWv4.js";
2
2
  import { c as jsonString, n as isJsonObject, u as parseJsonText } from "./src-X9phtB2j.js";
3
- import { _ as REVIEW_REMOTE_AGENT_IDS, p as REVIEW_CLI_INSTALL_TARGET_LABELS, v as REVIEW_REMOTE_ATTACH_BEGIN, y as REVIEW_REMOTE_ATTACH_END } from "./src-HnIPjtjx.js";
4
- import { 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, X as agentTraceHomeDirectory, _ as runTraceRepair, _t as jsonRequestedInArgv, b as runTraceGitHook, c as registerTraceCommands, ct as runStoreLogin, d as runTraceList$1, dt as StoreApiError, et as resolveTraceCommand, f as runTracePull$1, ft as StoreClient, g as runTraceInstallMachine, gt as humanStream, h as runTraceEnable, ht as failWithJsonError, it as DEFAULT_STORE_ORIGIN, j as runTraceOnboard, k as runTraceAllow, l as resolveTraceReadStorage, lt as runStoreLogout, m as runTraceDisable, mt as emitJsonEvent, nt as traceHomeDir, p as runTraceShow, pt as withStoreAuthorization, q as readTraceUserConfig, rt as traceScope, st as readStoreAuth, u as runTraceBlame, ut as runStoreWhoami, v as runTraceStatus, w as readLegacyCaptureSettings, x as runTraceHook, y as runTraceSync, z as selectTraceStorage } from "./review-home-paths-zwevIq4I.js";
5
- import { o as ReviewApiClient, s as ReviewApiError } from "./agent-client-Dogh8I83.js";
3
+ import { _ as REVIEW_REMOTE_AGENT_IDS, p as REVIEW_CLI_INSTALL_TARGET_LABELS, v as REVIEW_REMOTE_ATTACH_BEGIN, y as REVIEW_REMOTE_ATTACH_END } from "./src-DZG1xAqW.js";
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-Lc02WFuX.js";
5
+ import { o as ReviewApiClient, s as ReviewApiError } from "./agent-client-DjXQy6CL.js";
6
6
  import { t as resolveReviewRoot } from "./runtime-CKiWhGrf.js";
7
7
  import { C as s3ProfileSchema, E as writeTraceConfigFile, M as devReviewHome, N as normalizeStoreOrigin, S as readTraceConfigFile, T as sameS3Profile, _ as emptyTraceConfig, c as resolveS3Setup, g as currentStore, h as TraceConfigurationError, i as isS3MockMode, n as clearTraceEnvCache, o as readTraceEnvFile, p as traceSettingsPath, w as s3Store } from "./s3-config-DDWWMh5x.js";
8
8
  import { t as errorMessage } from "./error-message-OtiDonty.js";
9
- import { i as readReviewPackageVersion, r as readBuildInfo, t as findReviewPackageRoot } from "./package-paths-BsuI4WUf.js";
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-CqRxbsER.js";
11
- import { t as isDirectory } from "./fs-utils-BMPLt0cr.js";
12
- import { t as ReviewTelemetry } from "./review-telemetry-9ceqh4wz.js";
13
- import { _ as connectPrompts, a as isOwnedShim, f as windowsInstallerCommand, g as CONNECT_COMMANDS, h as isInstallTarget, m as ALL_INSTALL_TARGETS, o as pathShimPath, p as scanLegacySkills, t as aliasInstallationToAccount } from "./account-alias-C1ixP6bt.js";
14
- import { t as fuzzyRank } from "./fuzzy-match-BoAmcyak.js";
15
- import { n as focusReviewDesktop, r as runReviewAppLaunch } from "./review-app-launcher-S2FZBY4W.js";
16
- import { t as reviewAgentCliHelp } from "./agent-cli-CPSnWc9V.js";
17
- import { z } from "zod";
18
- import { constants, existsSync, mkdirSync, renameSync, writeFileSync } from "node:fs";
19
- import { access, readFile, realpath } from "node:fs/promises";
9
+ import { i as readReviewPackageVersion, r as readBuildInfo, t as findReviewPackageRoot } from "./package-paths-jMg6JxDP.js";
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-DnQNwgR1.js";
12
+ import { t as fuzzyRank } from "./fuzzy-match-DFPKdSLR.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-CwNaMOwU.js";
14
+ import { n as focusReviewDesktop, r as runReviewAppLaunch } from "./review-app-launcher-i1hmxOZA.js";
15
+ import { t as reviewAgentCliHelp } from "./agent-cli-S0bt9I7V.js";
16
+ import { existsSync, mkdirSync, renameSync, writeFileSync } from "node:fs";
17
+ import { realpath } from "node:fs/promises";
20
18
  import path from "node:path";
21
19
  import os from "node:os";
22
- import { spawn } from "node:child_process";
23
20
  import { fileURLToPath } from "node:url";
24
21
  import { Writable } from "node:stream";
25
22
  import { AsyncLocalStorage } from "node:async_hooks";
26
23
  import { Argument, Command, CommanderError, Option } from "commander";
27
24
  import { emitKeypressEvents } from "node:readline";
28
- import { parse } from "smol-toml";
29
25
  import { createInterface as createInterface$1 } from "node:readline/promises";
30
26
  import pino from "pino";
31
27
  import { performance } from "node:perf_hooks";
@@ -48,156 +44,6 @@ function describeCliRuntime(info) {
48
44
  return `CLI: ${info.effectivePath}${info.delegated ? ` (delegated from ${info.requestedPath})` : " (direct)"}\nBuild: ${info.version ?? "unknown"}, commit ${info.commit ?? "unknown"}, dirty ${info.dirty ?? "unknown"}, built ${info.builtAt ?? "unknown"}\n`;
49
45
  }
50
46
  //#endregion
51
- //#region src/connect-agents.ts
52
- const AGENT_CONNECT_TARGETS = REVIEW_REMOTE_AGENT_IDS;
53
- async function detectAgents(scope) {
54
- const found = [];
55
- for (const id of AGENT_CONNECT_TARGETS) {
56
- if (!await isDirectory(agentTraceHomeDirectory(id, scope.homeDir, scope.env))) continue;
57
- const manual = !await onPath(CONNECT_COMMANDS[id][0].argv[0], scope.env);
58
- found.push({
59
- id,
60
- name: REVIEW_CLI_INSTALL_TARGET_LABELS[id],
61
- connected: await connected(id, scope),
62
- ...manual && { manual: true }
63
- });
64
- }
65
- return found;
66
- }
67
- async function connectAgents(input) {
68
- const results = [];
69
- for (const id of input.agents) {
70
- const deadline = Date.now() + (input.timeoutMs ?? 12e4);
71
- let output = "";
72
- const commands = CONNECT_COMMANDS[id];
73
- for (const { argv, ifAny } of commands) {
74
- const left = deadline - Date.now();
75
- if (left <= 0) break;
76
- const step = await run(argv, input.env, left);
77
- output += `$ ${argv.join(" ")}\n${step.output}`;
78
- if (!step.ok && !ifAny) {
79
- output += `Stopped: ${argv.join(" ")} failed.\n`;
80
- break;
81
- }
82
- }
83
- results.push({
84
- id,
85
- name: REVIEW_CLI_INSTALL_TARGET_LABELS[id],
86
- connected: await connected(id, input),
87
- output: output.slice(-4e3)
88
- });
89
- }
90
- return results;
91
- }
92
- const WHITEBOARD_PLUGIN = "whiteboard@devfast";
93
- const ClaudePluginsSchema = z.object({ plugins: z.record(z.string(), z.unknown()) });
94
- const CodexConfigSchema = z.object({ plugins: z.record(z.string(), z.unknown()).optional() });
95
- const CodexPluginSchema = z.object({ enabled: z.boolean().optional() });
96
- const PiSettingsSchema = z.object({ packages: z.array(z.union([z.string(), z.object({ source: z.string() }).transform((entry) => entry.source)])) });
97
- const PI_PACKAGE = /^npm:@dev\.fast\/pi-whiteboard(@.*)?$/;
98
- const OPENCODE_PLUGIN = /"plugin"\s*:\s*\[[^\]]*"@dev\.fast\/opencode-whiteboard(@[^"]*)?"/;
99
- const OpenCodeConfigSchema = z.object({ mcp: z.object({
100
- whiteboard: z.unknown().optional(),
101
- servers: z.object({ whiteboard: z.unknown().optional() }).optional()
102
- }) });
103
- /** OpenCode's config is JSONC: drop comments and trailing commas, keep strings. */
104
- const JSONC_EXTRAS = /("(?:\\.|[^"\\])*")|\/\/[^\n]*|\/\*[\s\S]*?\*\/|,(?=\s*[}\]])/g;
105
- function openCodeConnected(text) {
106
- if (OPENCODE_PLUGIN.test(text)) return true;
107
- try {
108
- const { mcp } = OpenCodeConfigSchema.parse(JSON.parse(text.replace(JSONC_EXTRAS, "$1")));
109
- return mcp.whiteboard !== void 0 || mcp.servers?.whiteboard !== void 0;
110
- } catch {
111
- return false;
112
- }
113
- }
114
- async function connected(id, scope) {
115
- const home = agentTraceHomeDirectory(id, scope.homeDir, scope.env);
116
- const read = (...parts) => readFile(path.join(home, ...parts), "utf8");
117
- try {
118
- switch (id) {
119
- case "claude": {
120
- const installs = ClaudePluginsSchema.parse(JSON.parse(await read("plugins", "installed_plugins.json"))).plugins[WHITEBOARD_PLUGIN];
121
- return Array.isArray(installs) ? installs.length > 0 : Boolean(installs);
122
- }
123
- case "codex": {
124
- const entry = CodexConfigSchema.parse(parse(await read("config.toml"))).plugins?.[WHITEBOARD_PLUGIN];
125
- return entry !== void 0 && CodexPluginSchema.parse(entry).enabled !== false;
126
- }
127
- case "opencode":
128
- for (const name of [
129
- "opencode.json",
130
- "opencode.jsonc",
131
- "config.json"
132
- ]) if (openCodeConnected(await read(name).catch(() => ""))) return true;
133
- return false;
134
- case "pi": return PiSettingsSchema.parse(JSON.parse(await read("agent", "settings.json"))).packages.some((entry) => PI_PACKAGE.test(entry));
135
- }
136
- } catch {
137
- return false;
138
- }
139
- }
140
- async function onPath(command, env) {
141
- for (const directory of (env.PATH ?? "").split(path.delimiter)) {
142
- if (!path.isAbsolute(directory)) continue;
143
- const candidate = path.join(directory, command);
144
- try {
145
- await access(candidate, constants.X_OK);
146
- return candidate;
147
- } catch {}
148
- }
149
- }
150
- async function run(argv, env, timeoutMs) {
151
- const [command = "", ...args] = argv;
152
- const file = await onPath(command, env);
153
- if (!file) return {
154
- output: `${command} was not found on PATH.\n`,
155
- ok: false
156
- };
157
- return new Promise((resolve) => {
158
- let output = "";
159
- const keep = (chunk) => {
160
- output = (output + chunk.toString("utf8")).slice(-4e3);
161
- };
162
- const child = spawn(file, args, {
163
- env,
164
- stdio: [
165
- "ignore",
166
- "pipe",
167
- "pipe"
168
- ],
169
- detached: true
170
- });
171
- const timer = setTimeout(() => {
172
- output += `\n${command} did not finish within ${Math.round(timeoutMs / 1e3)} seconds.\n`;
173
- try {
174
- process.kill(-child.pid, "SIGKILL");
175
- } catch {
176
- child.kill("SIGKILL");
177
- }
178
- }, timeoutMs);
179
- child.stdout.on("data", keep);
180
- child.stderr.on("data", keep);
181
- child.once("error", (error) => {
182
- clearTimeout(timer);
183
- resolve({
184
- output: `${output}${error.message}\n`,
185
- ok: false
186
- });
187
- });
188
- child.once("close", (code) => {
189
- clearTimeout(timer);
190
- resolve(code === 0 ? {
191
- output,
192
- ok: true
193
- } : {
194
- output: `${output}${output.endsWith("\n") || !output ? "" : "\n"}(exit ${code ?? "signal"})\n`,
195
- ok: false
196
- });
197
- });
198
- });
199
- }
200
- //#endregion
201
47
  //#region src/review-app-picker.ts
202
48
  const MAX_VISIBLE_ROWS = 10;
203
49
  /**
@@ -4451,7 +4297,7 @@ async function runReviewCli(input) {
4451
4297
  if (!Number.isInteger(port) || port < 0 || port > 65535) throw new ReviewCliUsageError("--port must be an integer between 0 and 65535.");
4452
4298
  const stateDir = reviewServerStateDir(authoringEnv(options.stateDir));
4453
4299
  if (options.detach) {
4454
- const { ensureBackgroundServer } = await import("./background-server-BKR_lpYb.js");
4300
+ const { ensureBackgroundServer } = await import("./background-server-CVL7QpsL.js");
4455
4301
  const { discovery, started } = await ensureBackgroundServer({
4456
4302
  stateDir,
4457
4303
  env,
@@ -4473,7 +4319,7 @@ async function runReviewCli(input) {
4473
4319
  process.once("SIGINT", stop);
4474
4320
  process.once("SIGTERM", stop);
4475
4321
  process.once(DESKTOP_TAKEOVER_SIGNAL, takeover);
4476
- const { HeadlessServerBusyError, runHeadlessServer } = await import("./headless-host-Pj2xfGAo.js");
4322
+ const { HeadlessServerBusyError, runHeadlessServer } = await import("./headless-host-BNF-TR3x.js");
4477
4323
  try {
4478
4324
  await runHeadlessServer({
4479
4325
  stateDir,
@@ -4510,7 +4356,7 @@ async function runReviewCli(input) {
4510
4356
  configureJsonOutput(serverCommand.command("stop").description("Stop a background server started by --detach, the CLI, or Desktop").option("--state-dir <path>", "directory selected when starting the server"), "plain").action(async (_options, command) => {
4511
4357
  const options = command.optsWithGlobals();
4512
4358
  const stateDir = reviewServerStateDir(authoringEnv(options.stateDir));
4513
- const { headlessServerOwner, stopBackgroundServer } = await import("./background-server-BKR_lpYb.js");
4359
+ const { headlessServerOwner, stopBackgroundServer } = await import("./background-server-CVL7QpsL.js");
4514
4360
  const owner = await headlessServerOwner(stateDir);
4515
4361
  const discovery = await readReviewServerDiscovery(stateDir);
4516
4362
  if (owner === void 0) {
@@ -4538,7 +4384,7 @@ async function runReviewCli(input) {
4538
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.`);
4539
4385
  const inUse = `A Whiteboard server is using ${stateDir}. Stop it first, then run whiteboard server reset-id again.`;
4540
4386
  if (await desktopUsesHome(stateDir, env)) return refuse(inUse, options.json);
4541
- const [{ openReviewProfile }, { withHeadlessServerLock }] = await Promise.all([import("./profile-BUoTujrK.js"), import("./headless-host-Pj2xfGAo.js")]);
4387
+ const [{ openReviewProfile }, { withHeadlessServerLock }] = await Promise.all([import("./profile-BBw-jMW3.js"), import("./headless-host-BNF-TR3x.js")]);
4542
4388
  const reset = await withHeadlessServerLock(await realpath(stateDir), async () => {
4543
4389
  const local = await openReviewProfile(stateDir, { manageWorkspaces: false });
4544
4390
  try {
@@ -4560,7 +4406,7 @@ async function runReviewCli(input) {
4560
4406
  configureJsonOutput(remote.command("attach").description("Start a background server if none is healthy and report how to reach it").option("--state-dir <path>", "directory for saved reviews and server discovery").option("--groups <groups>", "comma-separated optional extension groups the Desktop has enabled, such as go").option("--replace", "stop a running server of another version that the CLI or Desktop started, and start this one"), "plain").action(async (_options, command) => {
4561
4407
  const options = command.optsWithGlobals();
4562
4408
  const stateDir = reviewServerStateDir(authoringEnv(options.stateDir));
4563
- const { remoteAttach } = await import("./remote-attach-CiOwonJ3.js");
4409
+ const { remoteAttach } = await import("./remote-attach-DJxW9402.js");
4564
4410
  let attach;
4565
4411
  try {
4566
4412
  attach = await remoteAttach({
@@ -4587,7 +4433,7 @@ async function runReviewCli(input) {
4587
4433
  });
4588
4434
  configureJsonOutput(remote.command("extensions").description("Language extensions for the language server on a remote").command("ensure").description("Download the curated extensions for this machine and list them for the language server").option("--groups <groups>", "comma-separated optional extension groups the Desktop has enabled, such as go"), "plain").action(async (_options, command) => {
4589
4435
  const { json, groups } = command.optsWithGlobals();
4590
- const { ensureRemoteExtensions } = await import("./remote-extensions-ByiuSl1D.js");
4436
+ const { ensureRemoteExtensions } = await import("./remote-extensions-Cf3L-ZGG.js");
4591
4437
  const result = await ensureRemoteExtensions({
4592
4438
  env,
4593
4439
  groups: groups?.split(",").map((group) => group.trim())
@@ -4602,7 +4448,7 @@ async function runReviewCli(input) {
4602
4448
  configureJsonOutput(remote.command("uninstall").description("Remove what Whiteboard Desktop installed on this host, stopping a server it started").addOption(new Option("--keep-reviews", "leave the saved reviews in place").conflicts("deleteReviews")).addOption(new Option("--delete-reviews", "also delete the saved reviews")).option("--state-dir <path>", "directory for saved reviews and server discovery"), "plain").action(async (_options, command) => {
4603
4449
  const options = command.optsWithGlobals();
4604
4450
  const stateDir = reviewServerStateDir(authoringEnv(options.stateDir));
4605
- const { remoteUninstall } = await import("./remote-uninstall-pzHb-Hfd.js");
4451
+ const { remoteUninstall } = await import("./remote-uninstall-DYmNOetF.js");
4606
4452
  let deleteReviews = options.deleteReviews ? true : options.keepReviews ? false : void 0;
4607
4453
  if (deleteReviews === void 0 && !options.json && input.stdin?.isTTY) {
4608
4454
  const prompt = createInterface$1({
@@ -4744,17 +4590,21 @@ async function runReviewCli(input) {
4744
4590
  "omp",
4745
4591
  "copilot",
4746
4592
  "all"
4747
- ])).addOption(new Option("--detect", "list the agents on this machine and whether each is connected; changes nothing").conflicts("yes")).option("--yes", "run the commands the prompt gives, without an agent: claude, codex, opencode or pi"), "plain").action(async (targets, options) => {
4593
+ ])).addOption(new Option("--detect", "list the agents here that --yes can connect, and whether each is; changes nothing").conflicts("yes")).option("--yes", "connect the named agents here, as Desktop does, without an agent"), "plain").action(async (targets, options) => {
4748
4594
  const output = {
4749
4595
  json: options.json,
4750
4596
  stdout: input.stdout,
4751
4597
  stderr: input.stderr
4752
4598
  };
4753
4599
  if (options.detect) {
4754
- const agents = await detectAgents({
4600
+ const agents = (await detectConnectAgents({
4755
4601
  homeDir: scope.homeDir,
4756
4602
  env
4757
- });
4603
+ })).flatMap(({ target, name, found, connected }) => found && REVIEW_REMOTE_AGENT_IDS.some((id) => id === target) ? [{
4604
+ id: target,
4605
+ name,
4606
+ connected
4607
+ }] : []);
4758
4608
  if (options.json) {
4759
4609
  emitJsonEvent(output, {
4760
4610
  event: "connect.detect",
@@ -4762,17 +4612,27 @@ async function runReviewCli(input) {
4762
4612
  });
4763
4613
  return;
4764
4614
  }
4765
- humanStream(output).write(agents.length ? `${agents.map((agent) => `${agent.name}: ${agent.connected ? "connected" : "not connected"}${agent.manual ? " (its command is not on PATH)" : ""}`).join("\n")}\n` : "No agents found.\n");
4615
+ humanStream(output).write(agents.length ? `${agents.map((agent) => `${agent.name}: ${agent.connected ? "connected" : "not connected"}`).join("\n")}\n` : "No agents found.\n");
4766
4616
  return;
4767
4617
  }
4768
4618
  if (options.yes) {
4769
4619
  const agents = parseTargets(targets);
4770
- if (targets.length === 0 || !agents.every((target) => AGENT_CONNECT_TARGETS.some((known) => known === target))) throw new Error("connect --yes takes one or more of claude, codex, opencode or pi.");
4771
- const results = await connectAgents({
4772
- agents,
4773
- homeDir: scope.homeDir,
4774
- env
4775
- });
4620
+ if (targets.length === 0 || !agents.every((target) => REVIEW_REMOTE_AGENT_IDS.some((known) => known === target))) throw new Error(`connect --yes takes one or more of ${REVIEW_REMOTE_AGENT_IDS.join(", ")}.`);
4621
+ const hasShim = await shimLaunchable(scope.homeDir, env);
4622
+ const results = [];
4623
+ for (const target of agents) {
4624
+ const result = await connectAgent(target, {
4625
+ homeDir: scope.homeDir,
4626
+ env,
4627
+ hasShim
4628
+ });
4629
+ results.push({
4630
+ id: target,
4631
+ name: REVIEW_CLI_INSTALL_TARGET_LABELS[target],
4632
+ connected: result.state === "connected",
4633
+ output: result.output ? `${result.output.slice(-CONNECT_OUTPUT_LIMIT)}\n` : ""
4634
+ });
4635
+ }
4776
4636
  state.exitCode = results.every((result) => result.connected) ? 0 : 1;
4777
4637
  if (options.json) {
4778
4638
  emitJsonEvent(output, {
@@ -4788,7 +4648,7 @@ async function runReviewCli(input) {
4788
4648
  const { homeDir, devHome } = scope;
4789
4649
  const prompts = connectPrompts({
4790
4650
  legacyPaths: await scanLegacySkills(homeDir),
4791
- hasShim: await isOwnedShim(pathShimPath(homeDir)) || await windowsInstallerCommand(findReviewPackageRoot(import.meta.url), env) !== void 0,
4651
+ hasShim: await shimLaunchable(homeDir, env),
4792
4652
  traceEnabled: await traceMachineEnabled({
4793
4653
  homeDir,
4794
4654
  env
@@ -4810,14 +4670,14 @@ async function runReviewCli(input) {
4810
4670
  command.showHelpAfterError(false).error("Markdown review migration is no longer supported. Ask your agent to migrate your old Whiteboard reviews.");
4811
4671
  });
4812
4672
  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) => {
4813
- const { runShareCli } = await import("./cli-Df6p-C19.js");
4673
+ const { runShareCli } = await import("./cli-Cko4zfif.js");
4814
4674
  state.exitCode = await runShareCli({
4815
4675
  ...input,
4816
4676
  ...options,
4817
4677
  env: authoringEnv()
4818
4678
  });
4819
4679
  }).command("revoke <share-id>").description("Revoke future downloads of a share"), "plain").action(async (shareId, options) => {
4820
- const { runShareCli } = await import("./cli-Df6p-C19.js");
4680
+ const { runShareCli } = await import("./cli-Cko4zfif.js");
4821
4681
  state.exitCode = await runShareCli({
4822
4682
  ...input,
4823
4683
  ...options,
@@ -4898,7 +4758,7 @@ async function runReviewCli(input) {
4898
4758
  return commands;
4899
4759
  } });
4900
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) => {
4901
- const { runReviewAgentCli } = await import("./agent-cli-CGapivA1.js");
4761
+ const { runReviewAgentCli } = await import("./agent-cli-NWQPsL0W.js");
4902
4762
  state.exitCode = await runReviewAgentCli({
4903
4763
  ...input,
4904
4764
  env: authoringEnv(),
@@ -4992,6 +4852,10 @@ async function runReviewCli(input) {
4992
4852
  await attemptTelemetry(() => telemetry.shutdown(1e3));
4993
4853
  }
4994
4854
  }
4855
+ const CONNECT_OUTPUT_LIMIT = 4e3;
4856
+ async function shimLaunchable(homeDir, env) {
4857
+ return await isOwnedShim(pathShimPath(homeDir)) || await windowsInstallerCommand(findReviewPackageRoot(import.meta.url), env) !== void 0;
4858
+ }
4995
4859
  function parseTargets(targets) {
4996
4860
  if (targets.length === 0 || targets.includes("all")) return [...ALL_INSTALL_TARGETS];
4997
4861
  return [...new Set(targets.values().map((target) => target === "claude-code" ? "claude" : target).filter(isInstallTarget))];
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { a as jsonNumber, c as jsonString, o as jsonObject, u as parseJsonText } from "./src-X9phtB2j.js";
3
- import "./src-HnIPjtjx.js";
3
+ import "./src-DZG1xAqW.js";
4
4
  import { existsSync, readFileSync, readdirSync, realpathSync } from "node:fs";
5
5
  import path from "node:path";
6
6
  import os from "node:os";
@@ -17,7 +17,7 @@ async function runCli(effectivePath) {
17
17
  `);
18
18
  return 1;
19
19
  }
20
- const { runReviewCli } = await import("./cli-runner-ZktCwlLk.js");
20
+ const { runReviewCli } = await import("./cli-runner-BhBnAC_R.js");
21
21
  return runReviewCli({
22
22
  argv,
23
23
  cliPaths: {
@@ -1,7 +1,7 @@
1
1
  import { f as gitAt } from "./src-BMPuxWv4.js";
2
2
  import { n as isJsonObject, u as parseJsonText } from "./src-X9phtB2j.js";
3
- import "./src-HnIPjtjx.js";
4
- import { B as markdownNodes, C as resourceReference, D as sourceReferences, N as lensSchema, P as lensSelections, V as parseMarkdown, _ as hasCodeReferences, c as traceSchema, h as elements, k as checkReferences, l as textIncludesQuote, n as migrateStoredDocument, o as normalizedSoftwareElementSchema, p as documentSchema, q as sourceAnchors, r as migrateStoredLenses, s as normalizedSoftwareRelationshipSchema, t as liftFileLenses, u as anchorPins, w as resourceReferences, x as pinsSchema } from "./stored-document-migration-DenDEYdI.js";
3
+ import "./src-DZG1xAqW.js";
4
+ import { C as resourceReference, D as sourceReferences, F as lensSchema, H as markdownNodes, I as lensSelections, U as parseMarkdown, Y as sourceAnchors, _ as hasCodeReferences, c as traceSchema, h as elements, k as checkReferences, l as textIncludesQuote, n as migrateStoredDocument, o as normalizedSoftwareElementSchema, p as documentSchema, r as migrateStoredLenses, s as normalizedSoftwareRelationshipSchema, t as liftFileLenses, u as anchorPins, w as resourceReferences, x as pinsSchema } from "./stored-document-migration-DLBhkSfp.js";
5
5
  import { t as ReviewInputError } from "./input-error-OLgB_h31.js";
6
6
  import { createHash, randomUUID } from "node:crypto";
7
7
  import { z } from "zod";
@@ -677,7 +677,7 @@ var SharedReviewStore = class {
677
677
  }
678
678
  };
679
679
  }
680
- list(mode = "structural") {
680
+ list() {
681
681
  const reviews = this.loaded.keys().filter((id) => this.status(id).stage === "ready" && (!this.validated.get(id)?.snapshot.pins || existsSync(path.join(this.repositoryRoot(id), ".git")))).map((id) => {
682
682
  const { document: _document, ...snapshot } = this.get(id).snapshot;
683
683
  return {
@@ -688,7 +688,7 @@ var SharedReviewStore = class {
688
688
  trashedAt: this.attention.get(id)?.trashedAt ?? null
689
689
  };
690
690
  }).toArray();
691
- return this.local?.store.withDiffStats(reviews, mode) ?? reviews;
691
+ return this.local?.store.withDiffStats(reviews) ?? reviews;
692
692
  }
693
693
  async readObject(id, objectId) {
694
694
  const entry = this.get(id).manifest.objects.find((object) => object.id === objectId);