@dev.fast/whiteboard 0.0.0-stage → 0.2.1-preview.20261005.98

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 (247) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +146 -2
  3. package/THIRD_PARTY_NOTICES.md +93 -0
  4. package/dist/account-alias-DOHN1RSH.js +973 -0
  5. package/dist/agent-cli-ChOq0ZuO.js +117 -0
  6. package/dist/agent-cli-DzWfZr6G.js +2 -0
  7. package/dist/agent-client-CPQo7iTI.js +305 -0
  8. package/dist/authoring-tools-Cr6Kpjsx.js +234 -0
  9. package/dist/build-info.json +1 -0
  10. package/dist/cli-hVgHcdsv.js +47 -0
  11. package/dist/cli-runner-D8y2_luU.js +5095 -0
  12. package/dist/cli.d.ts +1 -0
  13. package/dist/cli.js +128 -0
  14. package/dist/client-DFoh50W3.js +950 -0
  15. package/dist/desktop-discovery-DBO-PM2V.js +164 -0
  16. package/dist/error-message-OtiDonty.js +6 -0
  17. package/dist/fs-utils-BMPLt0cr.js +22 -0
  18. package/dist/fuzzy-match-BoAmcyak.js +30 -0
  19. package/dist/headless-host-BJxf4dUU.js +94 -0
  20. package/dist/input-error-OLgB_h31.js +11 -0
  21. package/dist/local-data-CxLk75rx.js +4491 -0
  22. package/dist/mcp-QeF8vkdf.js +140 -0
  23. package/dist/package-paths-B6-zxvIO.js +47 -0
  24. package/dist/process-error-telemetry-v9e5h6D7.js +3952 -0
  25. package/dist/profile-4ry2f3AM.js +76 -0
  26. package/dist/profile-Bh5FIrmf.js +2 -0
  27. package/dist/request-origin-D_4QIdoN.js +811 -0
  28. package/dist/review-agent-traces-DNJFYzc8.js +3866 -0
  29. package/dist/review-home-paths-6zZH-1c9.js +2560 -0
  30. package/dist/review-telemetry-DEFnQsQ2.js +1195 -0
  31. package/dist/runtime-CKiWhGrf.js +52 -0
  32. package/dist/runtime.d.ts +9 -0
  33. package/dist/runtime.js +2 -0
  34. package/dist/s3-SzLpeCG6.js +345 -0
  35. package/dist/s3-config-BgxkSoOy.js +2 -0
  36. package/dist/s3-config-CAxhO9u_.js +676 -0
  37. package/dist/server/desktop-host.d.ts +4 -0
  38. package/dist/server/desktop-host.js +1702 -0
  39. package/dist/server-discovery-Dbzn3w6Z.js +66 -0
  40. package/dist/sharing/index.d.ts +1977 -0
  41. package/dist/sharing/index.js +2 -0
  42. package/dist/src-CGP5ytbV.js +283 -0
  43. package/dist/src-CmdiBL20.js +3676 -0
  44. package/dist/src-DnwdaQ2r.js +865 -0
  45. package/dist/src-X9phtB2j.js +68 -0
  46. package/dist/stored-document-migration-DHeMpLMb.js +2671 -0
  47. package/dist/tool-failure-C8zB73HV.js +98 -0
  48. package/dist/tutorial-trace-DrBvkaeL.js +43 -0
  49. package/instructions/authoring.md +36 -0
  50. package/instructions/file-lenses.md +13 -0
  51. package/instructions/scratchpad.md +23 -0
  52. package/instructions/trace-archaeology.md +113 -0
  53. package/onboarding.md +8 -0
  54. package/package.json +106 -3
  55. package/src/agent-selection.ts +100 -0
  56. package/src/agent-session-ref.ts +80 -0
  57. package/src/ask/agents.ts +351 -0
  58. package/src/ask/checkout-files.ts +47 -0
  59. package/src/ask/file-refs.ts +111 -0
  60. package/src/ask/pi-mcp.ts +154 -0
  61. package/src/ask/protocol.ts +244 -0
  62. package/src/ask/thread-state.ts +350 -0
  63. package/src/ask/thread.ts +1400 -0
  64. package/src/ask/threads.ts +219 -0
  65. package/src/ask/watch.ts +79 -0
  66. package/src/cli-install.ts +1041 -0
  67. package/src/cli-runner.ts +1461 -0
  68. package/src/cli-runtime-info.ts +35 -0
  69. package/src/cli.ts +222 -0
  70. package/src/connect-prompts.ts +248 -0
  71. package/src/cursor-deeplink.ts +11 -0
  72. package/src/desktop-discovery.ts +355 -0
  73. package/src/diff-selection-migration.ts +63 -0
  74. package/src/embedded-posthog-key.ts +6 -0
  75. package/src/error-telemetry.ts +247 -0
  76. package/src/evidence.ts +14 -0
  77. package/src/exception-telemetry.ts +126 -0
  78. package/src/fixtures/blocks/call_stack_diff.json +27 -0
  79. package/src/fixtures/blocks/callout.json +11 -0
  80. package/src/fixtures/blocks/code.json +9 -0
  81. package/src/fixtures/blocks/code_peek.json +8 -0
  82. package/src/fixtures/blocks/database_lens.json +51 -0
  83. package/src/fixtures/blocks/divider.json +1 -0
  84. package/src/fixtures/blocks/fixtures.ts +33 -0
  85. package/src/fixtures/blocks/flow_diagram.json +36 -0
  86. package/src/fixtures/blocks/ids.ts +8 -0
  87. package/src/fixtures/blocks/image.json +9 -0
  88. package/src/fixtures/blocks/markdown.json +7 -0
  89. package/src/fixtures/blocks/section.json +11 -0
  90. package/src/fixtures/blocks/sequence.json +31 -0
  91. package/src/fixtures/blocks/software_map.json +7 -0
  92. package/src/fixtures/blocks/trace_quote.json +9 -0
  93. package/src/fixtures/blocks/tutorial.json +51 -0
  94. package/src/fs-utils.ts +32 -0
  95. package/src/fuzzy-match.ts +94 -0
  96. package/src/install.ts +29 -0
  97. package/src/legacy-skills.ts +133 -0
  98. package/src/lens-selection.ts +230 -0
  99. package/src/markdown-latex-math.ts +230 -0
  100. package/src/markdown.ts +81 -0
  101. package/src/package-paths.ts +53 -0
  102. package/src/posthog-capture-client.ts +610 -0
  103. package/src/review-api/README.md +295 -0
  104. package/src/review-api/activity.ts +340 -0
  105. package/src/review-api/agent-cli.ts +219 -0
  106. package/src/review-api/agent-client.ts +188 -0
  107. package/src/review-api/anchor-quotes.ts +88 -0
  108. package/src/review-api/ask-history.ts +242 -0
  109. package/src/review-api/authoring-tools.ts +211 -0
  110. package/src/review-api/blocks/call_stack_diff.ts +75 -0
  111. package/src/review-api/blocks/callout.ts +24 -0
  112. package/src/review-api/blocks/code.ts +9 -0
  113. package/src/review-api/blocks/code_peek.ts +13 -0
  114. package/src/review-api/blocks/database_lens.ts +150 -0
  115. package/src/review-api/blocks/definition.ts +40 -0
  116. package/src/review-api/blocks/divider.ts +6 -0
  117. package/src/review-api/blocks/flow_diagram.ts +111 -0
  118. package/src/review-api/blocks/image.ts +10 -0
  119. package/src/review-api/blocks/index.ts +90 -0
  120. package/src/review-api/blocks/markdown.ts +17 -0
  121. package/src/review-api/blocks/section.ts +24 -0
  122. package/src/review-api/blocks/sequence.ts +56 -0
  123. package/src/review-api/blocks/software_map.ts +9 -0
  124. package/src/review-api/blocks/trace_quote.ts +10 -0
  125. package/src/review-api/blocks/tutorial.ts +39 -0
  126. package/src/review-api/checkout-fs.ts +14 -0
  127. package/src/review-api/client.ts +1 -0
  128. package/src/review-api/comparison-coverage.ts +304 -0
  129. package/src/review-api/component-reference.ts +30 -0
  130. package/src/review-api/diff-lenses.ts +175 -0
  131. package/src/review-api/document-headings.ts +51 -0
  132. package/src/review-api/document-text.ts +200 -0
  133. package/src/review-api/document.ts +906 -0
  134. package/src/review-api/file-lenses.ts +100 -0
  135. package/src/review-api/http.ts +1877 -0
  136. package/src/review-api/image-decode.ts +29 -0
  137. package/src/review-api/input-error.ts +9 -0
  138. package/src/review-api/instructions.ts +89 -0
  139. package/src/review-api/lens-alignment.ts +52 -0
  140. package/src/review-api/local-data.ts +1837 -0
  141. package/src/review-api/map-input.ts +154 -0
  142. package/src/review-api/mcp-client-agent.ts +32 -0
  143. package/src/review-api/mcp.ts +240 -0
  144. package/src/review-api/origin.ts +43 -0
  145. package/src/review-api/profile.ts +146 -0
  146. package/src/review-api/public-tools.ts +102 -0
  147. package/src/review-api/pull-request.ts +389 -0
  148. package/src/review-api/read-schemas.ts +85 -0
  149. package/src/review-api/recovery.ts +2 -0
  150. package/src/review-api/request-origin.ts +33 -0
  151. package/src/review-api/review-progress.ts +382 -0
  152. package/src/review-api/status-tool.ts +10 -0
  153. package/src/review-api/store-schema.ts +22 -0
  154. package/src/review-api/store.ts +1647 -0
  155. package/src/review-api/tool-failure.ts +64 -0
  156. package/src/review-api/trace-schema.ts +13 -0
  157. package/src/review-api/traces.ts +119 -0
  158. package/src/review-api/unsupported-files.integration.ts +91 -0
  159. package/src/review-api/workspaces.ts +692 -0
  160. package/src/review-api/worktree-source.ts +170 -0
  161. package/src/review-api/worktree-structural.integration.ts +320 -0
  162. package/src/review-app-launcher.ts +432 -0
  163. package/src/review-app-picker.ts +168 -0
  164. package/src/review-app.ts +134 -0
  165. package/src/review-bundled-tools.ts +249 -0
  166. package/src/review-checkout-paths.ts +37 -0
  167. package/src/review-diff-files.ts +89 -0
  168. package/src/review-head-checkout.ts +300 -0
  169. package/src/review-home-paths.ts +73 -0
  170. package/src/review-info.ts +59 -0
  171. package/src/review-instances.ts +113 -0
  172. package/src/review-logger.ts +183 -0
  173. package/src/review-preferences.ts +88 -0
  174. package/src/review-prepare.ts +291 -0
  175. package/src/review-stack.ts +112 -0
  176. package/src/review-telemetry.ts +1066 -0
  177. package/src/runtime.ts +74 -0
  178. package/src/server/account-alias.ts +30 -0
  179. package/src/server/bounded-stream.ts +34 -0
  180. package/src/server/bug-report.ts +301 -0
  181. package/src/server/client-error-budget.ts +45 -0
  182. package/src/server/crash-report.ts +273 -0
  183. package/src/server/desktop-host-shutdown.ts +64 -0
  184. package/src/server/desktop-host.ts +190 -0
  185. package/src/server/desktop-server.ts +703 -0
  186. package/src/server/diffr-config.ts +509 -0
  187. package/src/server/diffr-languages.ts +97 -0
  188. package/src/server/global-verb-relay.ts +190 -0
  189. package/src/server/headless-host.ts +149 -0
  190. package/src/server/hono-http.ts +162 -0
  191. package/src/server/http-json.ts +24 -0
  192. package/src/server/json-review-reporting.ts +174 -0
  193. package/src/server/process-error-telemetry.ts +174 -0
  194. package/src/server/review-api-parsers.ts +90 -0
  195. package/src/server/review-lifecycle-telemetry.ts +73 -0
  196. package/src/server/review-open-watchdog.ts +46 -0
  197. package/src/server/review-server-core.ts +290 -0
  198. package/src/server/structural-comparisons.ts +153 -0
  199. package/src/server/structural-diff.ts +186 -0
  200. package/src/server/tutorial-service.ts +241 -0
  201. package/src/server/ui-telemetry.ts +198 -0
  202. package/src/server-discovery.ts +95 -0
  203. package/src/session-markers.ts +132 -0
  204. package/src/sharing/auth.ts +41 -0
  205. package/src/sharing/cli.ts +83 -0
  206. package/src/sharing/client.ts +334 -0
  207. package/src/sharing/export.ts +195 -0
  208. package/src/sharing/host.ts +316 -0
  209. package/src/sharing/import.ts +787 -0
  210. package/src/sharing/index.ts +16 -0
  211. package/src/sharing/repository.ts +145 -0
  212. package/src/sharing/routes.ts +34 -0
  213. package/src/slug.ts +23 -0
  214. package/src/software-map-diff-counts.ts +517 -0
  215. package/src/software-map-model.ts +1147 -0
  216. package/src/software-map-topology-diff.ts +260 -0
  217. package/src/source.ts +92 -0
  218. package/src/startup-trace.ts +232 -0
  219. package/src/stored-document-migration.ts +151 -0
  220. package/src/telemetry-clean-text.ts +257 -0
  221. package/src/telemetry-config.ts +298 -0
  222. package/src/telemetry-debug-sink.ts +38 -0
  223. package/src/telemetry.ts +13 -0
  224. package/src/trace-cli.ts +156 -0
  225. package/src/trace-storage-cli.ts +509 -0
  226. package/src/tutorial-conversation.ts +18 -0
  227. package/src/ui-telemetry-events.ts +765 -0
  228. package/src/unified-diff.ts +71 -0
  229. package/src/viewed-coverage.ts +259 -0
  230. package/src/windows-cli.ts +125 -0
  231. package/tutorial/document.json +275 -0
  232. package/tutorial/runtime-manifest.json +12 -0
  233. package/tutorial/sample-service/package.json +9 -0
  234. package/tutorial/sample-service/src/api/checkout-api.ts +17 -0
  235. package/tutorial/sample-service/src/app.ts +26 -0
  236. package/tutorial/sample-service/src/database/schema.ts +10 -0
  237. package/tutorial/sample-service/src/fulfillment/fulfillment-queue.ts +15 -0
  238. package/tutorial/sample-service/src/fulfillment/fulfillment-worker.ts +24 -0
  239. package/tutorial/sample-service/src/inventory/inventory-service.ts +11 -0
  240. package/tutorial/sample-service/src/orders/order-service.ts +34 -0
  241. package/tutorial/sample-service/src/orders/order.ts +21 -0
  242. package/tutorial/sample-service/src/orders/orders-repository.ts +24 -0
  243. package/tutorial/sample-service/src/payments/payment-gateway.ts +12 -0
  244. package/tutorial/sample-service/src/shipping/shipping-gateway.ts +15 -0
  245. package/tutorial/sample-service/tsconfig.json +12 -0
  246. package/tutorial/software-map.json +139 -0
  247. package/tutorial/trace.json +20 -0
@@ -0,0 +1,295 @@
1
+ # JSON review API
2
+
3
+ Desktop and `whiteboard server start` share `review-api.db` under `DEV_REVIEW_HOME`.
4
+ A headless `--state-dir` or `DEV_REVIEW_SERVER_DIR` selects an isolated profile;
5
+ Desktop can view it by using the same directory as `DEV_REVIEW_HOME`.
6
+ Both hosts mount the same routes behind token authentication and a bounded JSON request reader.
7
+ The canvas and Home read only the native JSON store. `POST /:id/open` opens a review
8
+ in Desktop, and pinned tabs reopen after restart. The startup importer migrates
9
+ saved MDX reviews before the server starts; there is no legacy runtime or second
10
+ catalog. Tests inject the native store and source-data provider.
11
+
12
+ ## Storage and ownership
13
+
14
+ - `reviews`: current version and one increasing ID counter per review.
15
+ - `versions`: complete JSON snapshots, including title, source pins, and content.
16
+ - `authoring_presences`: one row per agent working on a review (focus, color slot, where it last wrote, expiry).
17
+ - `repositories`: server-only local paths; clients receive an ID and display name.
18
+ - `resources`: immutable image, trace and software-map bytes, scoped to a repository.
19
+ - `review_attention`: viewed/dismissed timestamps, separate from document history.
20
+
21
+ One host-owned store serializes writes, including asynchronous validation.
22
+ Presences show who is working across database connections and never block a
23
+ write. Mutation commits recheck the current version after asynchronous
24
+ validation, so independent connections cannot overwrite a newer version.
25
+ Each connection checks SQLite `data_version` every 250 ms and refreshes document,
26
+ catalog and activity subscriptions after another connection commits. Desktop is
27
+ the sole owner of workspace preparation and cleanup; headless connections never
28
+ instantiate that manager. A database-backed process claim prevents a second
29
+ Desktop from resetting live workspace generations or running duplicate jobs.
30
+ The caller closes the store after closing the HTTP server.
31
+
32
+ The document is a tree of Markdown and self-contained components. The server
33
+ adds IDs directly to those objects. No content hashes, manifests, global
34
+ definition tables, retired-ID scans, or second authoring representation.
35
+ Updates/moves retain IDs; replacement retains the outer ID but creates fresh
36
+ child IDs. Restoring an old snapshot does not roll back the ID counter.
37
+
38
+ ## API
39
+
40
+ All paths below are relative to `/reviews-api`.
41
+
42
+ | Request | Result |
43
+ | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
44
+ | `GET /` | Current review summaries |
45
+ | `GET /authoring` | Tool names, host input schemas and HTTP mappings for CLI/MCP adapters |
46
+ | `GET /capabilities` | Desktop availability and permission for optional software-map generation, independent of opening a review |
47
+ | `GET /:id/activity` | Currently reported authoring work, not stored in document history |
48
+ | `POST /:id/activity/{begin,update,end} {activityId?,focus?}` | Begin a presence (returns its `activityId`), update its focus and expiry, or end it; each returns the review's live presences |
49
+ | `GET /watch` | NDJSON review summaries: initial list, then saved changes |
50
+ | `GET /watch?subscriptions=…` | One NDJSON connection for multiple `{reviewId}` subscriptions; `reviewId:null` selects the catalog. Each line is an ordered array of `{value}` or `{error}` results, with `null` where a subscription is unchanged since the previous line. |
51
+ | `GET /:id` | Compact outline |
52
+ | `GET /:id?targetId=step-3` | Full block, sequence step, flow node or flow edge |
53
+ | `GET /:id?full=true` | Full snapshot |
54
+ | `GET /:id?version=2&full=true` | Historical snapshot |
55
+ | `GET /:id/history` | Saved versions with titles and timestamps |
56
+ | `GET /:id/inspect` | Agent reading view: nested text outline with IDs; `targetId` reads one component completely, `full=true` includes all content, `version` selects history. `format=json` returns raw data instead. |
57
+ | `POST /:id/open` | Open the review in the attached Desktop; report an error when none is attached |
58
+ | `GET /:id/watch` | NDJSON snapshots: current state immediately, then committed updates |
59
+ | `POST /commands` | Apply one command; return review ID, version, and for an edit the target ID, its `type`, and — after an insert or replace — `children`: its first-level children as `{id,type}` (a container's blocks; a diagram's steps, or nodes then edges), so new components are addressable without a read. A `create` with `pullRequestUrl` returns the newest existing review for that PR instead (owner/repository matched case-insensitively) unless `operation.reuseExisting` is `false`: `created:false`, a `note`, its stored `target`, `headMoved`, and `working`/`otherReviewIds` when they apply; its target is never moved. A new review reports `created:true`. Either way the result carries `review`, the review's `GET /` catalog entry (target, origin, repository name and path). An interactive `create` also opens the new review in an attached Desktop unless `operation.open` is `false`, and reports `opened` with the open result or an `openError`; the review is saved either way |
60
+ | `POST /commands {operation:{type:"lens_edit",reviewId,edit}}` | Write one file lens, credited to `activityId` when given: `insert {title,targets,afterId?}` (host id `lens-N`), `update {targetId,title?,targets?}` or `remove {targetId}`. Returns `{targetId, type:"lens", uncategorized}`, where `uncategorized` lists changed files and ranges no lens covers yet (at most 50 files) |
61
+ | `GET /:id/lenses` | The current version's file lenses with each one's file count, plus the same `uncategorized` report |
62
+ | `POST /repositories {path}` | Register a local Git/jj repository; return ID/name |
63
+ | `POST /resources` | Upload an image, trace, or map; return resource ID/kind/MIME type |
64
+ | `GET /:id/resources/:resourceId` | Read retained bytes scoped to the review repository; desktop authentication required |
65
+ | `GET /:id/maps/:resourceId?version=0` | Read a pinned map with source-change counts for that review version |
66
+ | `GET /:id/file?side=head&file=src/app.ts` | Read current target source; version selects authored content; live source always follows the checkout |
67
+ | `GET /:id/tree?path=src&side=head` | Immediate target directory entries; path defaults to root, side to head; optional version/commit |
68
+ | `GET /:id/commits?version=0` | List commits and their first-parent statistics for that review version |
69
+ | `GET /:id/diff` | Changed-file summaries `[{path, previousPath?, status, additions, deletions}]`; optional version and commit |
70
+
71
+ Example request:
72
+
73
+ `review_get` uses `/inspect`. MCP returns its text directly, and
74
+ `whiteboard api review_get '{"reviewId":"…","full":true}'` prints it without JSON
75
+ escaping. Use `format:"json"` (or CLI `--json`) when raw objects are needed.
76
+ The canvas continues to use the JSON snapshot routes above.
77
+
78
+ ```json
79
+ {
80
+ "operation": {
81
+ "type": "edit",
82
+ "reviewId": "<returned by create>",
83
+ "edit": {
84
+ "type": "insert",
85
+ "content": {
86
+ "type": "markdown",
87
+ "markdown": "# Summary\n\nWhat changed."
88
+ }
89
+ }
90
+ }
91
+ }
92
+ ```
93
+
94
+ Commands: `create {title,target,pullRequestUrl?,reuseExisting?}` or `create {pullRequestUrl,title?,repositoryId?,reuseExisting?}`, `set_target {reviewId,target,pullRequestUrl?}`, `edit {reviewId,edit}`, `rename {reviewId,title}`,
95
+ `restore {reviewId,version}`. A review's pins, `{repositoryId,base,head}`, are its target resolved to immutable commits.
96
+ Agents name the checkout by `repositoryPath` in a target, or on a create from a PR alone; `/commands` registers the path and passes the store its id. Retargeting preserves content and component IDs. Restore restores title, target, PR identity, and content. Live targets still read the current checkout.
97
+ PR URLs must be canonical `https://github.com/owner/repository/pull/123` URLs. The PR number is derived from the URL; identity is metadata alongside immutable pins, not a moving source reference. A `create` with a target keeps that target and treats the URL as identity only. A `create` with the URL and no target resolves the PR when accepted: it reads the PR with `gh pr view` (falling back to the public GitHub API), picks the registered checkout named by `repositoryId`, else the checkout of the PR's existing review, else the first registered checkout with a remote whose configured URL is `github.com/owner/repository`, and fetches `refs/pull/N/head` and the base branch from that remote into `refs/review/github/owner/repository/pull/N/*`, never moving branches or bookmarks (a jj repository indexes the commits through a transient tag). It pins that head and its merge base with the base branch; for a PR absorbed by a merge commit it uses the merge base with GitHub's frozen base commit instead. The title defaults to the PR title. A repeat resolves the PR again, so `headMoved` compares the existing review with the PR's current head. `set_target` preserves the document and component IDs, including when source commits change. Its response reports retained source ranges to verify, those in files the new commits changed, and resources that no longer match the pins; agents repair these with `edit`. Existing versions keep their original pins and content. It preserves omitted PR identity within one repository, clears it when switching repositories, and accepts an explicit URL or null.
98
+
99
+ `attention {reviewId,action:"view"|"dismiss"|"restore"}` records viewing or
100
+ reversible dismissal without creating a document version. Home summaries include
101
+ the repository name and attention timestamps.
102
+ The list stream is separate from document streams. Dismissal closes
103
+ the native tab and can be undone from Home. Dismissed API reviews stay saved;
104
+ `delete {reviewId}` permanently removes their versions. Old command
105
+ inputs are erased but their IDs remain, so delayed retries cannot resurrect content.
106
+ Repository resources remain shared. Home and the canvas open a pinned, read-only
107
+ source tree. Each source tab names its review version; files opened from it use
108
+ the same version and side through the API, without a client-side checkout path.
109
+
110
+ Edits: `insert {content,parentId?,afterId?}`, `update {targetId,changes}`,
111
+ `move {targetId,parentId?,afterId?}`, `remove {targetId}`,
112
+ `replace {targetId,content}`. Omitted placement appends to the root; on the
113
+ scratchpad it prepends instead, so the pad reads newest first. Diagram
114
+ units (a `step` in a sequence, a `flow_node` or `flow_edge` in a flow diagram)
115
+ require their diagram as the parent and can move within it, but not between
116
+ diagrams; removing a flow node removes the edges that touched it. A new
117
+ `flow_node` may carry `link:{from|to,label?,style?}` naming a node already
118
+ drawn: the node and its edge are saved in one version, the edge stored as an
119
+ ordinary `flow_edge`, and the version's `lastEdit.linkId` names it so the
120
+ canvas draws the node in its final place and then the edge. Field patches
121
+ preserve omitted values; null removes optional fields. Child collections use
122
+ structural edits or replacement. Use fresh content without IDs for insert/replace.
123
+
124
+ Each accepted edit is one saved version, and the version carries
125
+ `lastEdit: {type, targetId, blockId, kind, unit?, linkId?, fields?, units?}`:
126
+ the edit's kind, the element it landed on, what that element is, and the block
127
+ it belongs to (`unit` names a step, flow node or flow edge inside `blockId`;
128
+ `fields` lists an update's patched keys, so a `defaultCollapsed` patch draws nothing;
129
+ `units` lists a diagram's steps, or its nodes and edges, in drawing order when
130
+ the diagram was inserted or replaced whole, each edge once both of its nodes
131
+ are drawn). Versions made by rename, set_target, restore or import carry none.
132
+ While a reader is watching, the canvas draws each version's edit as it lands:
133
+ a paragraph lands, a unit added to a diagram is traced where it attaches, and a
134
+ diagram written whole is traced in one quick pass.
135
+
136
+ There is no expected-version parameter. Later same-field edits win. A command
137
+ whose response was lost may or may not have applied; read the review before
138
+ retrying.
139
+
140
+ ## Validation and remaining work
141
+
142
+ Markdown source links use `[label](review-source:head/src/save.ts#L10-L24)`
143
+ (or `base`, or `#L10` for one line). Paths are repository-relative and URL-encoded
144
+ where needed. Inline and reference-style links open the existing native side peek.
145
+ The same Markdown parser feeds the host's source checks and the renderer, so code
146
+ examples and unused definitions do not become source requests. Invalid paths or
147
+ ranges reject the edit before saving. No extra node type or endpoint is needed.
148
+
149
+ Heading ids are `slugify(text)` made unique in document order over section
150
+ titles and the root-level h2/h3 of Markdown blocks, and `[text](#slug)` links
151
+ scroll to them. Markdown images with `https:` sources render inline.
152
+
153
+ The component schema checks inputs; field patches are checked after merging
154
+ with the target. A small relationship pass checks diagram actors, store fields,
155
+ and base/head frame sides. Sources and resource references use required host
156
+ providers before a version is saved; unchanged references at unchanged pins
157
+ are not checked again. Provider errors must use `ReviewInputError` for messages
158
+ safe to show to clients; unexpected provider/storage failures return HTTP 500.
159
+
160
+ The local provider uses existing Git/jj helpers to read committed objects, not
161
+ working-copy files. It checks code ranges and resource ownership before saving.
162
+ Images are fully decoded to PNG; traces retain supplied text with an explicit
163
+ client-supplied provenance label. Map uploads use the existing nested map format,
164
+ with a JSON shape check followed by the existing relationship/coverage validator
165
+ and pinned source-range checks. Uploads take `{id,repositoryId,kind,...}` with
166
+ `base64` for images, `trace:{label,events:[{id,role,text}]}` for traces, or
167
+ `pins,side,model` for maps. Reusing an upload ID requires identical content.
168
+
169
+ The canvas preserves React identities during updates. The stream coalesces
170
+ updates when a reader falls behind; reconnecting starts with the current saved
171
+ snapshot. Historical views read a fixed snapshot and do not follow live edits.
172
+ Call-stack frames can supply a component-local `key` to align the same frame
173
+ across base/head despite moved source ranges. Without a key, matching uses the
174
+ file and range. This is separate from each frame's durable element identity.
175
+
176
+ File and diff reads also accept `commit` to compare one listed commit against
177
+ its first parent. It must belong to the requested review version; an unrelated
178
+ commit returns 404. Without it, the comparison is the review's base and head.
179
+
180
+ Native code-peek and diff widgets can now consume API-backed read-only models,
181
+ including renamed files and absent diff sides. Native opening supplies this
182
+ adapter to the API canvas. Inline maps use the same pinned-source API for their
183
+ code inspectors, including unchanged mapped ranges. Immutable map resources
184
+ change through document edits, so these maps do not expose the old artifact
185
+ refresh action. Fullscreen uses the existing canvas-root overlay.
186
+ The Map tab uses the retained head/base maps and updates as they arrive.
187
+ The Trace tab and quote side panels read retained trace resources; imported
188
+ labels are preserved without claiming a harness, commit association, or timestamps.
189
+
190
+ The thin agent clients use `whiteboard api <tool-name> '<json>'` (or `-` for stdin)
191
+ and `whiteboard mcp` (stdio). `whiteboard api tools` lists the host's tools, one line each, and `whiteboard api tools <name>` prints one tool's schema.
192
+ Both adapters use existing desktop discovery/authentication and the same HTTP
193
+ routes as the canvas. Neither imports the store or validates document content.
194
+ Command/resource schemas come from the server's existing Zod definitions and
195
+ the read routes share their query schemas with the catalog (`read-schemas.ts`);
196
+ the MCP SDK handles framing. The checkout skill describes this JSON workflow while
197
+ preserving the writing guidance. No integration is installed automatically.
198
+
199
+ The Review tab counts a review as ready once it has content and no authoring
200
+ presence is live. The last presence ending (or expiring) is the only completion
201
+ signal; there is no per-section progress state. Versions and share bundles
202
+ saved while sections carried a `status` field are read and imported without it;
203
+ new edits that send one are rejected by the strict section
204
+ schema.
205
+
206
+ Activity is presence, not ownership. Begin returns a host-assigned `activityId`
207
+ and a color slot (the lowest one free on that review, kept until it ends);
208
+ update changes the focus and extends the presence; end removes it. `edit` and
209
+ `lens_edit` accept an optional `activityId`: the write renews that presence,
210
+ records where it last wrote (`document` or `lenses`), and stamps the version's
211
+ `lastEdit.activityId` so the canvas knows whose courier draws it. Without one,
212
+ a write is credited to the review's only presence when there is exactly one. No
213
+ write is ever refused because another agent is working. A presence expires 3
214
+ minutes after its last credited write or update; deletion removes it. Uploads
215
+ are immutable repository resources and do not require a presence.
216
+ The existing document stream includes an `activity` snapshot and also sends on
217
+ activity changes; activity-only sends reuse the loaded document, and the canvas
218
+ only loads document data when its version changes.
219
+ This avoids another long-lived browser connection. The badge is hidden while
220
+ idle or viewing history, and reports unknown activity on a lost connection.
221
+ Optional `focus:{description,targetId?}` identifies the current work; description is 1–160 characters and targetId is an existing component ID. Omitted focus retains the current focus; null clears it. Snapshots list `activities` (`activityId`, `slot`, `focus?`, `surface?`) while any are live. The header shows descriptions, and matching components show an inline working indicator. Focus is ephemeral, disappears when its presence ends or expires, and is hidden when activity is unknown or history is displayed.
222
+ There is no applying-update state. CLI/MCP expose this as `review_activity_begin`, `review_activity_update` and `review_activity_end`.
223
+
224
+ Profile migration remains later work.
225
+
226
+ The focused test file exercises all twelve block kinds, edits and identity,
227
+ history/restart, retries, asynchronous validation, isolation, and the actual
228
+ desktop HTTP route. The local-data tests use a real Git repository with dirty
229
+ working-copy files, decoded images and saved trace/map evidence, including real
230
+ HTTP requests and restart. Existing desktop-server tests remain unchanged.
231
+
232
+ ### Language information and committed source
233
+
234
+ Committed reviews use Review-owned worktrees at their base/head commits for
235
+ language services. The displayed source remains the immutable Git source.
236
+ Existing matching managed checkouts are reused; an equal base/head shares one
237
+ checkout. Opening a review prepares its current sides in the background; older
238
+ versions and selected commits acquire environments on demand.
239
+
240
+ Configure preparation through the repository's existing Git configuration:
241
+
242
+ ```sh
243
+ git config devfast.prepare 'pnpm install --frozen-lockfile'
244
+ git config --add devfast.prepare 'pnpm generate'
245
+ ```
246
+
247
+ Commands run in order inside each managed checkout, never in the invoking user
248
+ checkout. Successful preparation is cached by checkout and command-list hash;
249
+ changed commands or recreated checkouts invalidate it. Preparation has no canvas
250
+ disclosure. `review_open`, and `review_create` when it opens the review, starts acquisition in the background and returns any
251
+ already-recorded acquisition issues. `review_environment` rechecks current base/head
252
+ checkouts; `retry:true` explicitly reruns failed preparation. Missing setup, pending preparation,
253
+ and failed commands with a usable checkout do not produce issues. These checks
254
+ report acquisition failures (including transient errors), not end-to-end LSP health.
255
+ `review_workspace_cleanup` lists failed cleanup of retired checkouts and accepts
256
+ `workspaceId` to retry their removal. Reading and authoring stay available
257
+ while preparation runs. Language requests wait for preparation; no command or a
258
+ failed command leaves best-effort language services in that same pinned checkout,
259
+ without silently borrowing another checkout. Timeout and shutdown stop command
260
+ process groups, leave no successful marker, and allow retry.
261
+
262
+ Language queries require the displayed file to exactly match the file in the
263
+ language environment. A changed file suppresses queries even on unchanged lines;
264
+ matching contents use the same positions directly. Stale-request checks discard
265
+ answers if the source or environment changes during a request.
266
+
267
+ Definitions, type definitions, implementations, and references stay in the same
268
+ review version, side, and selected commit when the destination file matches its
269
+ saved source. Preparation may generate or modify files: changed or absent saved
270
+ destinations retain their native managed-checkout URIs.
271
+
272
+ Preparation does not guarantee reproducibility unless the configured commands
273
+ also reproduce dependencies, generated files, and the toolchain. Historical
274
+ checkouts remain until their owning review is deleted. Environment state and
275
+ commands are local and are never authored into review documents.
276
+
277
+ ## Review targets
278
+
279
+ `target` is either `{kind:"worktree",repositoryId,base?}` or
280
+ `{kind:"commits",repositoryId,head,base?}`. Commit revisions resolve on acceptance.
281
+ Omitted commit base means source at head with no diff, exactly as base=head;
282
+ supply its parent to review the changes introduced by a single commit.
283
+
284
+ A worktree target follows saved files in that registered checkout, including
285
+ staged and unstaged changes. Git's untracked files are left out; `git add -N` a
286
+ new file to include it (jj tracks new files itself). The Diff view counts the
287
+ untracked files left out. `base` names the branch to
288
+ compare against, by default the default branch (`origin/HEAD`, `origin/main`,
289
+ `origin/master`, `main`, then `master`); an unborn repository compares with
290
+ empty source. The comparison starts at the merge base of `base` and HEAD,
291
+ resolved again whenever the checkout or its refs change, so it follows a rebase;
292
+ if `base` stops resolving, the last merge base stays. No checkout is created.
293
+ Source ranges default to the head side. File saves refresh source without changing
294
+ authored history. All versions of a live target read the current checkout; authors
295
+ maintain their source references. Use a commit target for fixed source.