pmx-canvas 0.8.0 → 0.9.0

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 (341) hide show
  1. package/.github/extensions/pmx-canvas/runtime.json +1 -1
  2. package/.github/extensions/pmx-canvas/tools.json +601 -22
  3. package/CHANGELOG.md +66 -0
  4. package/Readme.md +131 -532
  5. package/dist/canvas/global.css +2759 -510
  6. package/dist/canvas/index.js +168 -107
  7. package/dist/canvas/mcp-app.html +2936 -632
  8. package/dist/json-render/index.css +81 -1
  9. package/dist/json-render/index.js +20 -20
  10. package/dist/types/client/canvas/BarHint.d.ts +12 -2
  11. package/dist/types/client/canvas/BoardLinkDialog.d.ts +3 -1
  12. package/dist/types/client/canvas/BoardPinButton.d.ts +10 -0
  13. package/dist/types/client/canvas/BoardSwitcher.d.ts +1 -1
  14. package/dist/types/client/canvas/CanvasViewport.d.ts +1 -1
  15. package/dist/types/client/canvas/CommandBar.d.ts +3 -4
  16. package/dist/types/client/canvas/ConnectionBanner.d.ts +2 -1
  17. package/dist/types/client/canvas/ContextChip.d.ts +3 -0
  18. package/dist/types/client/canvas/CrossBoardReferences.d.ts +5 -0
  19. package/dist/types/client/canvas/EdgeLayer.d.ts +14 -3
  20. package/dist/types/client/canvas/EmptyState.d.ts +4 -4
  21. package/dist/types/client/canvas/HomeGraphView.d.ts +2 -0
  22. package/dist/types/client/canvas/HomeMapView.d.ts +1 -0
  23. package/dist/types/client/canvas/HomeReviewView.d.ts +6 -0
  24. package/dist/types/client/canvas/HomeView.d.ts +9 -7
  25. package/dist/types/client/canvas/KnowledgeDialog.d.ts +4 -0
  26. package/dist/types/client/canvas/LifecycleChrome.d.ts +5 -0
  27. package/dist/types/client/canvas/LifecycleFields.d.ts +7 -0
  28. package/dist/types/client/canvas/LifecyclePanel.d.ts +1 -0
  29. package/dist/types/client/canvas/MemoryInspector.d.ts +7 -0
  30. package/dist/types/client/canvas/NearPinLayer.d.ts +14 -0
  31. package/dist/types/client/canvas/NodeContextMark.d.ts +40 -7
  32. package/dist/types/client/canvas/RelationPresetsDialog.d.ts +4 -0
  33. package/dist/types/client/canvas/RelationsPanel.d.ts +4 -0
  34. package/dist/types/client/canvas/SessionPanel.d.ts +2 -0
  35. package/dist/types/client/canvas/canvas-area.d.ts +1 -1
  36. package/dist/types/client/canvas/graph-geometry.d.ts +27 -0
  37. package/dist/types/client/canvas/graph-model.d.ts +37 -0
  38. package/dist/types/client/canvas/memory-layout.d.ts +23 -0
  39. package/dist/types/client/canvas/use-chrome-height.d.ts +2 -0
  40. package/dist/types/client/canvas/use-focus-trap.d.ts +1 -0
  41. package/dist/types/client/canvas/use-memory-graph.d.ts +8 -0
  42. package/dist/types/client/canvas/use-pan-zoom.d.ts +4 -1
  43. package/dist/types/client/icons.d.ts +0 -10
  44. package/dist/types/client/nodes/AxStepControls.d.ts +1 -1
  45. package/dist/types/client/nodes/HtmlNode.d.ts +1 -0
  46. package/dist/types/client/nodes/InlineMarkdownEditor.d.ts +4 -4
  47. package/dist/types/client/nodes/MarkdownNode.d.ts +5 -1
  48. package/dist/types/client/nodes/McpAppNode.d.ts +4 -4
  49. package/dist/types/client/nodes/viewer-runtime-state.d.ts +1 -1
  50. package/dist/types/client/state/boards-store.d.ts +81 -9
  51. package/dist/types/client/state/canvas-store.d.ts +14 -1
  52. package/dist/types/client/state/context-chip-store.d.ts +22 -0
  53. package/dist/types/client/state/context-status-store.d.ts +35 -0
  54. package/dist/types/client/state/intent-bridge.d.ts +11 -8
  55. package/dist/types/client/state/knowledge-store.d.ts +22 -0
  56. package/dist/types/client/state/near-pin-store.d.ts +44 -1
  57. package/dist/types/client/state/presence-store.d.ts +4 -4
  58. package/dist/types/client/state/presentation.d.ts +28 -0
  59. package/dist/types/client/state/relation-store.d.ts +10 -0
  60. package/dist/types/client/state/session-store.d.ts +41 -2
  61. package/dist/types/client/state/workspace-settings.d.ts +7 -0
  62. package/dist/types/client/types.d.ts +13 -1
  63. package/dist/types/client/utils/keyboard.d.ts +2 -0
  64. package/dist/types/client/utils/time-ago.d.ts +4 -0
  65. package/dist/types/mcp/context-uri-template.d.ts +3 -1
  66. package/dist/types/server/agent-presence.d.ts +10 -3
  67. package/dist/types/server/ax-context.d.ts +1 -1
  68. package/dist/types/server/canvas-db.d.ts +30 -7
  69. package/dist/types/server/canvas-operations.d.ts +24 -2
  70. package/dist/types/server/canvas-provenance.d.ts +22 -2
  71. package/dist/types/server/canvas-serialization.d.ts +2 -0
  72. package/dist/types/server/canvas-state.d.ts +93 -15
  73. package/dist/types/server/canvas-validation.d.ts +1 -1
  74. package/dist/types/server/context-brief.d.ts +94 -6
  75. package/dist/types/server/context-reads.d.ts +33 -7
  76. package/dist/types/server/edit-summary.d.ts +20 -0
  77. package/dist/types/server/index.d.ts +71 -10
  78. package/dist/types/server/knowledge-lifecycle.d.ts +221 -0
  79. package/dist/types/server/lifecycle-status.d.ts +10 -0
  80. package/dist/types/server/memory-graph.d.ts +9 -0
  81. package/dist/types/server/mutation-history.d.ts +2 -0
  82. package/dist/types/server/operations/ops/ax-shared.d.ts +1 -1
  83. package/dist/types/server/operations/ops/boards.d.ts +2 -1
  84. package/dist/types/server/operations/ops/lifecycle.d.ts +2 -0
  85. package/dist/types/server/operations/ops/memory-graph.d.ts +2 -0
  86. package/dist/types/server/operations/ops/nodes.d.ts +5 -0
  87. package/dist/types/server/operations/ops/query.d.ts +23 -0
  88. package/dist/types/server/operations/registry.d.ts +1 -0
  89. package/dist/types/server/placement.d.ts +7 -0
  90. package/dist/types/server/scope-fence.d.ts +2 -1
  91. package/dist/types/server/spatial-analysis.d.ts +6 -3
  92. package/dist/types/server/tour-control.d.ts +32 -0
  93. package/dist/types/server/wiki-links.d.ts +14 -0
  94. package/dist/types/server/workbench-auth.d.ts +2 -0
  95. package/dist/types/shared/agent-context.d.ts +2 -0
  96. package/dist/types/shared/agent-presence.d.ts +15 -12
  97. package/dist/types/shared/auto-arrange.d.ts +1 -0
  98. package/dist/types/shared/boards.d.ts +4 -4
  99. package/dist/types/shared/knowledge-lifecycle.d.ts +41 -0
  100. package/dist/types/shared/knowledge-presets.d.ts +6 -0
  101. package/dist/types/shared/lifecycle-status.d.ts +24 -0
  102. package/dist/types/shared/memory-graph.d.ts +53 -0
  103. package/dist/types/shared/relations.d.ts +68 -0
  104. package/dist/types/shared/semantic-attention.d.ts +2 -0
  105. package/dist/types/shared/tour.d.ts +38 -0
  106. package/dist/types/shared/workspace-settings.d.ts +11 -0
  107. package/docs/RELEASE.md +21 -3
  108. package/docs/adr-001-bun-only-runtime.md +7 -1
  109. package/docs/adr-002-shared-product-separate-runtimes.md +93 -0
  110. package/docs/api-reference.md +109 -0
  111. package/docs/ax-host-adapter-contract.md +1 -1
  112. package/docs/ax-state-contract.md +5 -4
  113. package/docs/cli.md +153 -15
  114. package/docs/demos/pmx-canvas-demo.mp4 +0 -0
  115. package/docs/design/AgentContext.dc.html +3 -3
  116. package/docs/design/BoardPins.dc.html +37 -22
  117. package/docs/design/Categories.dc.html +208 -0
  118. package/docs/design/CategoryEditor.dc.html +33 -0
  119. package/docs/design/Chrome.dc.html +55 -9
  120. package/docs/design/ContextChip.dc.html +224 -0
  121. package/docs/design/ContextChip600.dc.html +136 -0
  122. package/docs/design/EmptyState.dc.html +45 -0
  123. package/docs/design/Flows.dc.html +23 -1
  124. package/docs/design/HeaderMarks.dc.html +183 -0
  125. package/docs/design/Home.dc.html +19 -1
  126. package/docs/design/HomeGraph.dc.html +86 -202
  127. package/docs/design/HomeMap.dc.html +23 -1
  128. package/docs/design/HomeTeam.dc.html +32 -14
  129. package/docs/design/Lifecycle.dc.html +22 -0
  130. package/docs/design/Lifecycle600.dc.html +18 -0
  131. package/docs/design/LifecycleVariants.dc.html +157 -0
  132. package/docs/design/LinkAuthorship.dc.html +139 -0
  133. package/docs/design/LinksChanged.dc.html +203 -0
  134. package/docs/design/LinksOptions.dc.html +137 -0
  135. package/docs/design/LinksOptions600.dc.html +134 -0
  136. package/docs/design/NearPin.dc.html +9 -10
  137. package/docs/design/Pane600.dc.html +4 -3
  138. package/docs/design/Relations.dc.html +3 -2
  139. package/docs/design/Restore.dc.html +152 -0
  140. package/docs/design/SeeChange.dc.html +267 -0
  141. package/docs/design/Uses.dc.html +12 -6
  142. package/docs/design/canvas.json +146 -19
  143. package/docs/design.md +454 -18
  144. package/docs/environment.md +0 -1
  145. package/docs/evals/curation-effect.md +128 -0
  146. package/docs/http-api.md +465 -38
  147. package/docs/mcp.md +150 -19
  148. package/docs/node-types.md +58 -3
  149. package/docs/plans/design-gaps-2026-10-08.md +53 -0
  150. package/docs/plans/plan-009-tech-debt-backlog.md +379 -0
  151. package/docs/plans/plan-016-context-made-visible-wave-1.md +150 -5
  152. package/docs/plans/plan-017-knowledge-categories-and-lifecycle.md +175 -0
  153. package/docs/plans/plan-018-connected-memory-wave-2.md +594 -0
  154. package/docs/plans/plan-019-post-0.9-roadmap.md +198 -0
  155. package/docs/product-context-vision-2026-09.md +17 -1
  156. package/docs/product-vision-2026-09.md +1082 -43
  157. package/docs/product-vision-review-2026-09.md +13 -1
  158. package/docs/screenshots/workbench-live-dark.png +0 -0
  159. package/docs/screenshots/workbench-live-light.png +0 -0
  160. package/docs/sdk.md +62 -2
  161. package/package.json +1 -1
  162. package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/runtime.json +1 -1
  163. package/plugins/pmx-canvas/plugin.json +1 -1
  164. package/plugins/pmx-canvas/runtime.json +1 -1
  165. package/plugins/pmx-canvas/tools.json +601 -22
  166. package/skills/pmx-canvas/SKILL.md +234 -43
  167. package/skills/pmx-canvas/evals/evals.json +62 -0
  168. package/skills/pmx-canvas/references/ax-html-control-surface.md +6 -0
  169. package/skills/pmx-canvas/references/full-reference.md +120 -21
  170. package/skills/pmx-canvas/references/github-copilot-app-adapter.md +2 -2
  171. package/skills/pmx-canvas/references/importing-context.md +132 -0
  172. package/skills/pmx-canvas/references/installing-pmx-canvas.md +6 -6
  173. package/skills/pmx-canvas/references/tours-and-recording.md +16 -1
  174. package/skills/pmx-canvas-testing/SKILL.md +20 -0
  175. package/src/cli/agent.ts +2 -0
  176. package/src/cli/commands/ax.ts +12 -0
  177. package/src/cli/commands/boards.ts +87 -11
  178. package/src/cli/commands/edges.ts +28 -0
  179. package/src/cli/commands/groups.ts +7 -0
  180. package/src/cli/commands/nodes.ts +4 -2
  181. package/src/cli/commands/query.ts +34 -2
  182. package/src/cli/commands/record.ts +199 -48
  183. package/src/cli/index.ts +7 -1
  184. package/src/client/App.tsx +177 -70
  185. package/src/client/canvas/AttentionHistory.tsx +0 -2
  186. package/src/client/canvas/BarHint.tsx +40 -2
  187. package/src/client/canvas/BoardCopyDialog.tsx +1 -1
  188. package/src/client/canvas/BoardFolderDialog.tsx +7 -7
  189. package/src/client/canvas/BoardLinkDialog.tsx +138 -33
  190. package/src/client/canvas/BoardPinButton.tsx +33 -0
  191. package/src/client/canvas/BoardSwitcher.tsx +26 -40
  192. package/src/client/canvas/CanvasNode.tsx +360 -237
  193. package/src/client/canvas/CanvasViewport.tsx +45 -7
  194. package/src/client/canvas/CommandBar.tsx +29 -23
  195. package/src/client/canvas/CommandPalette.tsx +5 -12
  196. package/src/client/canvas/ConnectionBanner.tsx +3 -3
  197. package/src/client/canvas/ContextChip.tsx +296 -0
  198. package/src/client/canvas/ContextMenu.tsx +63 -5
  199. package/src/client/canvas/CrossBoardReferences.tsx +60 -0
  200. package/src/client/canvas/EdgeLayer.tsx +339 -76
  201. package/src/client/canvas/EmptyState.tsx +33 -18
  202. package/src/client/canvas/ExpandedNodeOverlay.tsx +72 -40
  203. package/src/client/canvas/ExternalWriters.tsx +57 -42
  204. package/src/client/canvas/HomeGraphView.tsx +942 -0
  205. package/src/client/canvas/HomeMapView.tsx +641 -0
  206. package/src/client/canvas/HomeReviewView.tsx +167 -0
  207. package/src/client/canvas/HomeView.tsx +687 -160
  208. package/src/client/canvas/IntentLayer.tsx +19 -12
  209. package/src/client/canvas/KnowledgeDialog.tsx +488 -0
  210. package/src/client/canvas/LifecycleChrome.tsx +133 -0
  211. package/src/client/canvas/LifecycleFields.tsx +91 -0
  212. package/src/client/canvas/LifecyclePanel.tsx +533 -0
  213. package/src/client/canvas/MemoryInspector.tsx +104 -0
  214. package/src/client/canvas/Minimap.tsx +3 -3
  215. package/src/client/canvas/NearPinLayer.tsx +187 -0
  216. package/src/client/canvas/NodeContextMark.tsx +175 -97
  217. package/src/client/canvas/Presentation.tsx +23 -57
  218. package/src/client/canvas/RelationPresetsDialog.tsx +413 -0
  219. package/src/client/canvas/RelationsPanel.tsx +82 -0
  220. package/src/client/canvas/SelectionBar.tsx +3 -6
  221. package/src/client/canvas/SessionPanel.tsx +90 -50
  222. package/src/client/canvas/SessionReceipt.tsx +311 -39
  223. package/src/client/canvas/ShortcutOverlay.tsx +1 -1
  224. package/src/client/canvas/SnapshotPanel.tsx +27 -36
  225. package/src/client/canvas/ToolRail.tsx +367 -192
  226. package/src/client/canvas/TopBar.tsx +354 -124
  227. package/src/client/canvas/canvas-area.ts +10 -3
  228. package/src/client/canvas/graph-geometry.ts +195 -0
  229. package/src/client/canvas/graph-model.ts +254 -0
  230. package/src/client/canvas/memory-layout.ts +106 -0
  231. package/src/client/canvas/use-chrome-height.ts +20 -0
  232. package/src/client/canvas/use-focus-trap.ts +31 -5
  233. package/src/client/canvas/use-memory-graph.ts +58 -0
  234. package/src/client/canvas/use-node-drag.ts +2 -1
  235. package/src/client/canvas/use-pan-zoom.ts +64 -7
  236. package/src/client/icons.tsx +0 -63
  237. package/src/client/mcp-app/style.css +0 -6
  238. package/src/client/nodes/AxStepControls.tsx +74 -50
  239. package/src/client/nodes/BoardNode.tsx +5 -1
  240. package/src/client/nodes/ContextNode.tsx +18 -11
  241. package/src/client/nodes/ExtAppFrame.tsx +0 -1
  242. package/src/client/nodes/FileNode.tsx +46 -42
  243. package/src/client/nodes/HtmlNode.tsx +44 -2
  244. package/src/client/nodes/ImageNode.tsx +1 -1
  245. package/src/client/nodes/InlineFormatBar.tsx +6 -9
  246. package/src/client/nodes/InlineMarkdownEditor.tsx +56 -17
  247. package/src/client/nodes/MarkdownNode.tsx +377 -109
  248. package/src/client/nodes/McpAppNode.tsx +50 -20
  249. package/src/client/nodes/MdFormatBar.tsx +21 -18
  250. package/src/client/nodes/PromptNode.tsx +1 -1
  251. package/src/client/nodes/ResponseNode.tsx +1 -1
  252. package/src/client/nodes/viewer-runtime-state.ts +54 -22
  253. package/src/client/state/attention-bridge.ts +64 -15
  254. package/src/client/state/boards-store.ts +193 -39
  255. package/src/client/state/canvas-store.ts +99 -12
  256. package/src/client/state/context-chip-store.ts +70 -0
  257. package/src/client/state/context-status-store.ts +53 -0
  258. package/src/client/state/intent-bridge.ts +51 -30
  259. package/src/client/state/knowledge-store.ts +43 -0
  260. package/src/client/state/near-pin-store.ts +115 -6
  261. package/src/client/state/presence-store.ts +7 -10
  262. package/src/client/state/presentation.ts +91 -0
  263. package/src/client/state/relation-store.ts +81 -0
  264. package/src/client/state/session-store.ts +144 -18
  265. package/src/client/state/sse-bridge.ts +206 -29
  266. package/src/client/state/workspace-settings.ts +11 -0
  267. package/src/client/theme/global.css +2759 -510
  268. package/src/client/types.ts +12 -0
  269. package/src/client/utils/keyboard.ts +10 -0
  270. package/src/client/utils/time-ago.ts +14 -0
  271. package/src/json-render/renderer/index.css +6 -1
  272. package/src/json-render/renderer/index.tsx +31 -1
  273. package/src/mcp/canvas-app.ts +12 -2
  274. package/src/mcp/context-uri-template.ts +7 -4
  275. package/src/mcp/server.ts +63 -41
  276. package/src/mcp/workbench-app.ts +39 -6
  277. package/src/server/agent-presence.ts +128 -28
  278. package/src/server/ax-context.ts +27 -13
  279. package/src/server/board-export.ts +12 -1
  280. package/src/server/canvas-db.ts +331 -42
  281. package/src/server/canvas-operations.ts +196 -84
  282. package/src/server/canvas-provenance.ts +53 -22
  283. package/src/server/canvas-serialization.ts +2 -0
  284. package/src/server/canvas-state.ts +950 -122
  285. package/src/server/canvas-validation.ts +9 -2
  286. package/src/server/context-brief.ts +345 -38
  287. package/src/server/context-reads.ts +179 -30
  288. package/src/server/demo-state.json +355 -24
  289. package/src/server/edit-summary.ts +74 -0
  290. package/src/server/html-surface.ts +8 -1
  291. package/src/server/index.ts +203 -13
  292. package/src/server/knowledge-lifecycle.ts +304 -0
  293. package/src/server/lifecycle-status.ts +232 -0
  294. package/src/server/memory-graph.ts +166 -0
  295. package/src/server/mutation-history.ts +18 -6
  296. package/src/server/operations/composites.ts +32 -11
  297. package/src/server/operations/http.ts +7 -2
  298. package/src/server/operations/index.ts +4 -0
  299. package/src/server/operations/mcp.ts +32 -1
  300. package/src/server/operations/ops/ax-presence.ts +1 -1
  301. package/src/server/operations/ops/ax-read.ts +57 -6
  302. package/src/server/operations/ops/ax-timeline.ts +28 -2
  303. package/src/server/operations/ops/backup.ts +5 -3
  304. package/src/server/operations/ops/batch.ts +35 -4
  305. package/src/server/operations/ops/boards.ts +188 -47
  306. package/src/server/operations/ops/canvas-wire.ts +31 -1
  307. package/src/server/operations/ops/edges.ts +36 -2
  308. package/src/server/operations/ops/groups.ts +6 -1
  309. package/src/server/operations/ops/json-render.ts +5 -1
  310. package/src/server/operations/ops/lifecycle.ts +262 -0
  311. package/src/server/operations/ops/memory-graph.ts +45 -0
  312. package/src/server/operations/ops/nodes.ts +107 -24
  313. package/src/server/operations/ops/query.ts +281 -68
  314. package/src/server/operations/ops/snapshots.ts +73 -1
  315. package/src/server/operations/ops/validate.ts +5 -1
  316. package/src/server/operations/ops/viewport.ts +97 -3
  317. package/src/server/operations/registry.ts +77 -26
  318. package/src/server/placement.ts +29 -0
  319. package/src/server/scope-fence.ts +78 -6
  320. package/src/server/server.ts +115 -16
  321. package/src/server/spatial-analysis.ts +48 -23
  322. package/src/server/tour-control.ts +82 -0
  323. package/src/server/wiki-links.ts +137 -0
  324. package/src/server/workbench-auth.ts +11 -0
  325. package/src/shared/agent-context.ts +3 -0
  326. package/src/shared/agent-presence.ts +15 -15
  327. package/src/shared/auto-arrange.ts +2 -0
  328. package/src/shared/boards.ts +4 -4
  329. package/src/shared/knowledge-lifecycle.ts +22 -0
  330. package/src/shared/knowledge-presets.ts +80 -0
  331. package/src/shared/lifecycle-status.ts +26 -0
  332. package/src/shared/memory-graph.ts +74 -0
  333. package/src/shared/relations.ts +98 -0
  334. package/src/shared/semantic-attention.ts +15 -1
  335. package/src/shared/tour.ts +23 -5
  336. package/src/shared/workspace-settings.ts +13 -0
  337. package/dist/types/client/canvas/ContextPinBar.d.ts +0 -1
  338. package/dist/types/client/canvas/FocusFieldLayer.d.ts +0 -1
  339. package/dist/types/client/canvas/kind-colors.d.ts +0 -3
  340. package/dist/types/server/agent-context.d.ts +0 -22
  341. package/src/client/canvas/ContextPinBar.tsx +0 -25
@@ -1,4 +1,5 @@
1
- import { useCallback, useEffect, useRef, useState } from 'preact/hooks';
1
+ import { computed } from '@preact/signals';
2
+ import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'preact/hooks';
2
3
  import { Presentation } from './canvas/Presentation';
3
4
  import { presenting } from './state/presentation';
4
5
  import { AttentionHistory } from './canvas/AttentionHistory';
@@ -6,26 +7,36 @@ import { AttentionToast } from './canvas/AttentionToast';
6
7
  import { registerCanvasArea, canvasArea } from './canvas/canvas-area';
7
8
  import { CanvasViewport } from './canvas/CanvasViewport';
8
9
  import { CommandBar } from './canvas/CommandBar';
10
+ import { ContextPinBar } from './canvas/ContextChip';
9
11
  import { ConnectionBanner } from './canvas/ConnectionBanner';
10
12
  import { CommandPalette } from './canvas/CommandPalette';
11
13
  import { BoardLinkDialog } from './canvas/BoardLinkDialog';
14
+ import { LifecyclePanel } from './canvas/LifecyclePanel';
15
+ import { KnowledgeSync, LifecycleFilters } from './canvas/LifecycleChrome';
12
16
  import { ContextMenu, useContextMenu } from './canvas/ContextMenu';
13
- import { ContextPinBar } from './canvas/ContextPinBar';
14
17
  import { EmptyState } from './canvas/EmptyState';
15
18
  import { HomeView } from './canvas/HomeView';
16
19
  import { ExportDialog } from './canvas/ExportDialog';
17
- import { activeBoardId, boardsLoaded } from './state/boards-store';
20
+ import { activeBoardId, boardsLoaded, browsingMemory, boardIncarnation } from './state/boards-store';
18
21
  import { createNodeInView } from './canvas/create-in-view';
19
- import { undoFromKeyboard } from './state/session-store';
22
+ import {
23
+ activityLens,
24
+ heldGates,
25
+ pendingGates,
26
+ scopeFence,
27
+ sessionPanelOpened,
28
+ undoFromKeyboard,
29
+ } from './state/session-store';
20
30
  import { ActivityFeed, WritersSheet } from './canvas/ExternalWriters';
21
31
  import { ExpandedNodeOverlay } from './canvas/ExpandedNodeOverlay';
22
32
  import { Minimap } from './canvas/Minimap';
23
33
  import { SelectionBar } from './canvas/SelectionBar';
24
- import { SessionPanel } from './canvas/SessionPanel';
34
+ import { AgentControls, SessionPanel } from './canvas/SessionPanel';
25
35
  import { SessionReceipt } from './canvas/SessionReceipt';
26
36
  import { ShortcutOverlay } from './canvas/ShortcutOverlay';
27
37
  import { SnapshotPanel } from './canvas/SnapshotPanel';
28
38
  import { promptedCreate, ToolRail } from './canvas/ToolRail';
39
+ import { EdgeHint, RelationLegend } from './canvas/EdgeLayer';
29
40
  import { TextPrompt } from './canvas/TextPrompt';
30
41
  import { TopBar } from './canvas/TopBar';
31
42
  import {
@@ -39,6 +50,7 @@ import {
39
50
  edges,
40
51
  expandedNodeId,
41
52
  fitAll,
53
+ focusNode,
42
54
  hasInitialServerLayout,
43
55
  nodes,
44
56
  pendingExpandedNodeCloseId,
@@ -53,7 +65,8 @@ import {
53
65
  } from './state/canvas-store';
54
66
  import { connectSSE } from './state/sse-bridge';
55
67
  import { intents } from './state/intent-store';
56
- import { sessionActive } from './state/presence-store';
68
+ import { sessionActive, sessionChromeActive } from './state/presence-store';
69
+ import { agentSessionsEnabled, knowledgeLifecycleEnabled } from './state/workspace-settings';
57
70
  import { isHostedWorkbench } from './state/workbench-transport';
58
71
  import {
59
72
  createGroupFromClient,
@@ -63,31 +76,73 @@ import {
63
76
  ungroupFromClient,
64
77
  } from './state/intent-bridge';
65
78
  import type { AnnotationTool } from './types';
79
+ import { lifecycleFilter, lifecycleTarget } from './state/knowledge-store';
80
+ import { relationFilter } from './state/relation-store';
81
+ import { isSelectionEscape } from './utils/keyboard';
66
82
 
67
83
  function logAppError(action: string, error: unknown): void {
68
84
  console.error(`[app] ${action} failed`, error);
69
85
  }
70
86
 
87
+ /**
88
+ * App needs only whether the board is empty. Reading the nodes map itself
89
+ * would re-render the whole shell (and re-measure the canvas) on every drag frame.
90
+ */
91
+ const boardIsEmpty = computed(() => nodes.value.size === 0);
92
+ const validReviewTarget = computed(() => {
93
+ const target = lifecycleTarget.value;
94
+ return (
95
+ !!target &&
96
+ !browsingMemory.value &&
97
+ activeBoardId.value === target.boardId &&
98
+ boardIncarnation === target.incarnation &&
99
+ nodes.value.has(target.nodeId)
100
+ );
101
+ });
102
+ const reviewIsOpen = computed(() => knowledgeLifecycleEnabled.value && validReviewTarget.value);
103
+
71
104
  export function App() {
72
- const [minimapVisible, setMinimapVisible] = useState(true);
105
+ // Off by default in a narrow pane (Pane600.dc.html); the Settings menu turns it on.
106
+ const [minimapVisible, setMinimapVisible] = useState(() => window.innerWidth >= 700);
73
107
  const [snapshotOpen, setSnapshotOpen] = useState(false);
74
108
  const [paletteOpen, setPaletteOpen] = useState(false);
75
109
  const [boardLinkOpen, setBoardLinkOpen] = useState(false);
110
+ const [boardLinkSource, setBoardLinkSource] = useState<{ sourceNodeId?: string; wikiRef?: string }>({});
76
111
  const [shortcutsOpen, setShortcutsOpen] = useState(false);
77
112
  const [annotationTool, setAnnotationTool] = useState<AnnotationTool>(null);
78
113
  const snapshotBtnRef = useRef<HTMLButtonElement>(null);
114
+ const canvasRegionRef = useRef<HTMLDivElement>(null);
115
+ const [area, setArea] = useState(canvasArea);
79
116
  const { menu, openNodeMenu, openCanvasMenu, openEdgeMenu, closeMenu } = useContextMenu();
80
117
  const hasInitialLayout = hasInitialServerLayout.value;
81
- const onHome = boardsLoaded.value && activeBoardId.value === null;
118
+ const onHome = boardsLoaded.value && (activeBoardId.value === null || browsingMemory.value);
82
119
  // rail-chrome-v2: the one selector every agent surface mounts on. Exposed
83
120
  // as a data attribute so styling and tests can key on it; the quiet board
84
121
  // (no attached session) must stay byte-clean of agent chrome.
85
- const sessionIsActive = sessionActive.value;
122
+ const sessionIsActive = sessionChromeActive.value;
123
+ const sessionsEnabled = agentSessionsEnabled.value;
124
+ const hasAgentControls =
125
+ sessionActive.value || pendingGates.value.length > 0 || heldGates.value.length > 0 || !!scopeFence.value;
126
+ const reviewOpen = reviewIsOpen.value;
127
+
128
+ useLayoutEffect(() => {
129
+ if (!sessionsEnabled) {
130
+ activityLens.value = null;
131
+ sessionPanelOpened.value = false;
132
+ if (document.activeElement?.closest('.command-bar, .session-panel, .agent-popover')) {
133
+ snapshotBtnRef.current?.focus({ preventScroll: true });
134
+ }
135
+ }
136
+ }, [sessionsEnabled]);
86
137
 
87
138
  const handleToggleMinimap = useCallback(() => setMinimapVisible((v) => !v), []);
88
139
  const handleToggleSnapshot = useCallback(() => setSnapshotOpen((v) => !v), []);
89
140
  const handleCloseSnapshot = useCallback(() => setSnapshotOpen(false), []);
90
141
  const handleSetAnnotationTool = useCallback((tool: AnnotationTool) => setAnnotationTool(tool), []);
142
+ const handleCanvasRegion = useCallback((el: HTMLDivElement | null) => {
143
+ registerCanvasArea(el);
144
+ canvasRegionRef.current = el;
145
+ }, []);
91
146
 
92
147
  const handleMinimapNavigate = useCallback((x: number, y: number) => {
93
148
  animateViewport({ x, y, scale: viewport.value.scale }, 200);
@@ -98,7 +153,11 @@ export function App() {
98
153
  }, []);
99
154
 
100
155
  useEffect(() => {
101
- const open = () => setBoardLinkOpen(true);
156
+ const open = (event: Event) => {
157
+ const detail = (event as CustomEvent<{ sourceNodeId?: string; wikiRef?: string }>).detail;
158
+ setBoardLinkSource(detail ?? {});
159
+ setBoardLinkOpen(true);
160
+ };
102
161
  window.addEventListener('pmx-open-board-link', open);
103
162
  return () => window.removeEventListener('pmx-open-board-link', open);
104
163
  }, []);
@@ -123,12 +182,24 @@ export function App() {
123
182
  };
124
183
  }, []);
125
184
 
126
- useEffect(() => {
185
+ // Keyboard ownership must match the committed UI before another key can arrive.
186
+ useLayoutEffect(() => {
127
187
  const handleKeyDown = (e: KeyboardEvent) => {
128
188
  // AltGr on European Windows layouts reports Ctrl+Alt — never treat it
129
189
  // as the shortcut modifier, or AltGr+Z (ż, ź…) fires undo.
130
190
  const mod = (e.metaKey || e.ctrlKey) && !e.altKey;
131
191
 
192
+ // The shortcut reference is available on Home too.
193
+ if (shortcutsOpen && (e.key === 'Escape' || e.key === '?' || (e.key === '/' && e.shiftKey))) {
194
+ e.preventDefault();
195
+ setShortcutsOpen(false);
196
+ return;
197
+ }
198
+
199
+ // The library owns its keyboard. Never edit the agent's hidden active board.
200
+ if (browsingMemory.value || activeBoardId.value === null) return;
201
+ if (e.defaultPrevented) return;
202
+
132
203
  // Cmd/Ctrl+K toggles command palette (works from anywhere, including inputs)
133
204
  if (mod && e.key === 'k') {
134
205
  e.preventDefault();
@@ -143,7 +214,15 @@ export function App() {
143
214
  return;
144
215
  }
145
216
 
146
- // Esc always collapses expanded node first (even from inside inputs)
217
+ // A companion review closes before expansion or the underlying selection.
218
+ if (e.key === 'Escape' && reviewIsOpen.value) {
219
+ if ((e.target as HTMLElement | null)?.closest('[role="menu"], [role="alertdialog"]')) return;
220
+ e.preventDefault();
221
+ lifecycleTarget.value = null;
222
+ return;
223
+ }
224
+
225
+ // Esc collapses expansion after its companion review.
147
226
  if (e.key === 'Escape' && expandedNodeId.value && !pendingExpandedNodeCloseId.value) {
148
227
  e.preventDefault();
149
228
  collapseExpandedNode();
@@ -157,13 +236,6 @@ export function App() {
157
236
  return;
158
237
  }
159
238
 
160
- // Esc closes shortcut overlay
161
- if (e.key === 'Escape' && shortcutsOpen) {
162
- e.preventDefault();
163
- setShortcutsOpen(false);
164
- return;
165
- }
166
-
167
239
  // Ignore other shortcuts when inside inputs or editable content — the
168
240
  // single-key rail shortcuts below would otherwise eat characters typed
169
241
  // into the inline markdown editor (contenteditable), which INPUT/TEXTAREA
@@ -171,9 +243,16 @@ export function App() {
171
243
  const target = e.target as HTMLElement | null;
172
244
  const tag = target?.tagName;
173
245
  if (tag === 'INPUT' || tag === 'TEXTAREA' || target?.isContentEditable) return;
246
+ // Menus own every shortcut; dialogs retain global undo, zoom and help.
247
+ if (target?.closest('[role="menu"]')) return;
248
+ const inDialog = target?.closest('[role="dialog"]');
249
+ // Chrome owns its arrow keys and Tab order, rather than board navigation.
250
+ if ((e.key === 'Tab' || e.key.startsWith('Arrow')) && target?.closest('.tool-rail, .top-bar')) {
251
+ return;
252
+ }
174
253
 
175
254
  // Held Space = temporary pan tool (released on keyup below).
176
- if (e.key === ' ' && !e.repeat && !mod) {
255
+ if (e.key === ' ' && !e.repeat && !mod && !inDialog) {
177
256
  e.preventDefault();
178
257
  spacePanHeld.value = true;
179
258
  return;
@@ -207,11 +286,15 @@ export function App() {
207
286
  } else if (mod && e.key === '-') {
208
287
  e.preventDefault();
209
288
  zoomByFactor(1 / 1.25);
289
+ } else if (inDialog) {
290
+ // Dialog controls keep navigation and board-editing keys to themselves.
291
+ return;
210
292
  } else if (e.key === 'Escape') {
211
- if (selectedNodeIds.value.size > 0 || selectedEdgeId.value !== null) {
212
- clearSelection();
213
- return;
214
- }
293
+ if (!isSelectionEscape(e)) return;
294
+ e.preventDefault();
295
+ if (relationFilter.value?.boardId === activeBoardId.value) relationFilter.value = null;
296
+ lifecycleFilter.value = 'All';
297
+ clearSelection();
215
298
  activeNodeId.value = null;
216
299
  closeMenu();
217
300
  } else if (e.key === 'Tab') {
@@ -327,22 +410,32 @@ export function App() {
327
410
  return () => window.clearTimeout(timer);
328
411
  }, [sessionIsActive]);
329
412
 
413
+ useLayoutEffect(() => {
414
+ const region = canvasRegionRef.current;
415
+ if (!region) return;
416
+ const observer = new ResizeObserver(() => {
417
+ setArea(canvasArea());
418
+ void reportClientViewportSize();
419
+ const review = lifecycleTarget.value;
420
+ if (review && reviewIsOpen.value) focusNode(review.nodeId, { recordHistory: false });
421
+ });
422
+ observer.observe(region);
423
+ return () => observer.disconnect();
424
+ }, []);
425
+
330
426
  useEffect(() => {
331
427
  if (!hasInitialLayout) return;
332
428
  const ready = (window as Window & { __pmxCanvasBootstrapReady?: () => void }).__pmxCanvasBootstrapReady;
333
429
  if (typeof ready === 'function') ready();
334
430
  }, [hasInitialLayout]);
335
431
 
336
- const allNodes = Array.from(nodes.value.values());
337
-
338
- const area = canvasArea();
339
-
340
432
  return (
341
433
  <div
342
434
  class={`app-shell${presenting.value ? ' is-presenting' : ''}`}
343
435
  data-session-active={sessionIsActive ? 'true' : 'false'}
344
436
  >
345
437
  <Presentation />
438
+ <EdgeHint />
346
439
  <ToolRail
347
440
  minimapVisible={minimapVisible}
348
441
  onToggleMinimap={handleToggleMinimap}
@@ -357,52 +450,66 @@ export function App() {
357
450
  <div class="app-main">
358
451
  <TopBar />
359
452
  <ConnectionBanner />
360
- <div class="canvas-region" ref={(el) => registerCanvasArea(el)}>
361
- <CanvasViewport
362
- onNodeContextMenu={openNodeMenu}
363
- onCanvasContextMenu={openCanvasMenu}
364
- onEdgeContextMenu={openEdgeMenu}
365
- annotationMode={annotationTool !== null}
366
- annotationTool={annotationTool}
367
- />
368
- <AttentionToast />
369
- <AttentionHistory />
370
- <ActivityFeed />
371
- <WritersSheet />
372
- {onHome ? (
373
- <HomeView />
374
- ) : (
375
- hasInitialLayout &&
376
- allNodes.length === 0 &&
377
- intents.value.size === 0 && <EmptyState onOpenPalette={() => setPaletteOpen(true)} />
378
- )}
379
- {selectedNodeIds.value.size > 0 && <SelectionBar />}
380
- {sessionIsActive && !isHostedWorkbench() ? (
381
- <CommandBar />
382
- ) : (
383
- contextPinnedNodeIds.value.size > 0 && <ContextPinBar />
384
- )}
385
- <SessionReceipt onOpenSnapshots={() => setSnapshotOpen(true)} />
386
- <TextPrompt />
387
- <ExportDialog />
388
- {expandedNodeId.value && <ExpandedNodeOverlay />}
389
- <SnapshotPanel open={snapshotOpen} onClose={handleCloseSnapshot} anchorRef={snapshotBtnRef} />
390
- {minimapVisible && !onHome && (
391
- <Minimap
392
- viewport={viewport}
393
- nodes={nodes}
394
- edges={edges}
395
- onNavigate={handleMinimapNavigate}
396
- containerWidth={area.width}
397
- containerHeight={area.height}
453
+ <div class={`workspace${reviewOpen ? ' is-reviewing' : ''}`}>
454
+ <div class="canvas-region" ref={handleCanvasRegion}>
455
+ {!browsingMemory.value && (
456
+ <CanvasViewport
457
+ onNodeContextMenu={openNodeMenu}
458
+ onCanvasContextMenu={openCanvasMenu}
459
+ onEdgeContextMenu={openEdgeMenu}
460
+ annotationMode={annotationTool !== null}
461
+ annotationTool={annotationTool}
462
+ />
463
+ )}
464
+ <AttentionToast />
465
+ <KnowledgeSync />
466
+ {!onHome && <LifecycleFilters />}
467
+ {!onHome && <RelationLegend />}
468
+ <AttentionHistory />
469
+ <ActivityFeed />
470
+ <WritersSheet />
471
+ {onHome ? (
472
+ <HomeView />
473
+ ) : (
474
+ hasInitialLayout &&
475
+ boardIsEmpty.value &&
476
+ intents.value.size === 0 && <EmptyState onOpenPalette={() => setPaletteOpen(true)} />
477
+ )}
478
+ {!onHome && selectedNodeIds.value.size > 0 && <SelectionBar />}
479
+ {!onHome && !sessionsEnabled && <ContextPinBar />}
480
+ {!onHome && sessionActive.value && !isHostedWorkbench() && <CommandBar />}
481
+ {!onHome && <SessionReceipt onOpenSnapshots={() => setSnapshotOpen(true)} />}
482
+ <TextPrompt />
483
+ {!browsingMemory.value && <ExportDialog />}
484
+ {!onHome && expandedNodeId.value && <ExpandedNodeOverlay />}
485
+ <SnapshotPanel
486
+ open={snapshotOpen && !browsingMemory.value}
487
+ onClose={handleCloseSnapshot}
488
+ anchorRef={snapshotBtnRef}
398
489
  />
399
- )}
490
+ {minimapVisible && !onHome && (
491
+ <Minimap
492
+ viewport={viewport}
493
+ nodes={nodes}
494
+ edges={edges}
495
+ onNavigate={handleMinimapNavigate}
496
+ containerWidth={area.width}
497
+ containerHeight={area.height}
498
+ />
499
+ )}
500
+ </div>
501
+ {validReviewTarget.value && <LifecyclePanel />}
400
502
  </div>
401
503
  </div>
402
504
  {sessionIsActive && <SessionPanel />}
403
- {menu && <ContextMenu menu={menu} onClose={closeMenu} />}
404
- {paletteOpen && <CommandPalette onClose={() => setPaletteOpen(false)} onToggleMinimap={handleToggleMinimap} />}
405
- {boardLinkOpen && <BoardLinkDialog onClose={() => setBoardLinkOpen(false)} />}
505
+ {!sessionIsActive && hasAgentControls && <AgentControls />}
506
+ {!browsingMemory.value && menu && <ContextMenu menu={menu} onClose={closeMenu} />}
507
+ {!browsingMemory.value && paletteOpen && (
508
+ <CommandPalette onClose={() => setPaletteOpen(false)} onToggleMinimap={handleToggleMinimap} />
509
+ )}
510
+ {!browsingMemory.value && boardLinkOpen && (
511
+ <BoardLinkDialog {...boardLinkSource} onClose={() => setBoardLinkOpen(false)} />
512
+ )}
406
513
  {shortcutsOpen && <ShortcutOverlay onClose={() => setShortcutsOpen(false)} />}
407
514
  </div>
408
515
  );
@@ -31,7 +31,6 @@ export function AttentionHistory() {
31
31
  class="attention-history-tab"
32
32
  onClick={handleOpenUpdates}
33
33
  aria-label={unread > 0 ? `Recent updates — ${unread} new` : 'Recent updates'}
34
- title={unread > 0 ? `${unread} new updates since last viewed` : 'Recent updates'}
35
34
  >
36
35
  <svg
37
36
  width="14"
@@ -72,7 +71,6 @@ export function AttentionHistory() {
72
71
  class="attention-history-close"
73
72
  onClick={closeAttentionHistory}
74
73
  aria-label="Collapse changes panel"
75
- title="Collapse"
76
74
  >
77
75
  <IconClose />
78
76
  </button>
@@ -1,4 +1,19 @@
1
- import type { ComponentChildren } from 'preact';
1
+ import { render, type ComponentChildren, type VNode } from 'preact';
2
+ import { useLayoutEffect, useMemo, useState } from 'preact/hooks';
3
+
4
+ /** Escape a bar's filter/clip without installing React-compat event hooks. */
5
+ export function BarPortal({ children }: { children: VNode }) {
6
+ const host = useMemo(() => document.createElement('div'), []);
7
+ useLayoutEffect(() => {
8
+ document.body.appendChild(host);
9
+ return () => {
10
+ render(null, host);
11
+ host.remove();
12
+ };
13
+ }, [host]);
14
+ useLayoutEffect(() => render(children, host), [children, host]);
15
+ return null;
16
+ }
2
17
 
3
18
  /**
4
19
  * Styled hover/focus tooltip for bar controls — the replacement for native
@@ -11,6 +26,7 @@ export function BarHint({
11
26
  align = 'center',
12
27
  side = 'down',
13
28
  tapToOpen = false,
29
+ fitWithin,
14
30
  children,
15
31
  }: {
16
32
  label: string;
@@ -27,12 +43,34 @@ export function BarHint({
27
43
  * after the click, not linger on focus.
28
44
  */
29
45
  tapToOpen?: boolean;
46
+ /**
47
+ * The clipping box to stay inside (a CSS selector for an ancestor). As the
48
+ * tooltip opens it takes whichever of end/start alignment fits — a node
49
+ * header chip sits anywhere along a card that clips its contents.
50
+ */
51
+ fitWithin?: string;
30
52
  children: ComponentChildren;
31
53
  }) {
54
+ const [fitted, setFitted] = useState<'start' | 'end' | null>(null);
55
+ const fit = (event: Event) => {
56
+ if (!fitWithin) return;
57
+ const anchor = event.currentTarget as HTMLElement;
58
+ const box = anchor.closest(fitWithin)?.getBoundingClientRect();
59
+ const tip = anchor.querySelector('.toolbar-tooltip')?.getBoundingClientRect();
60
+ if (!box || !tip) return;
61
+ const self = anchor.getBoundingClientRect();
62
+ // Opening from the anchor's right edge leftwards (end) or its left edge rightwards (start).
63
+ const endFits = self.right - tip.width >= box.left;
64
+ const startFits = self.left + tip.width <= box.right;
65
+ setFitted(endFits || !startFits ? 'end' : 'start');
66
+ };
67
+ const placed = fitted ?? align;
32
68
  return (
33
69
  <span
34
- class={`toolbar-tooltip-anchor toolbar-tooltip-anchor-${align}${side === 'up' ? ' toolbar-tooltip-anchor-up' : ''}${tapToOpen ? ' toolbar-tooltip-anchor-tap' : ''}`}
70
+ class={`toolbar-tooltip-anchor toolbar-tooltip-anchor-${placed}${side === 'up' ? ' toolbar-tooltip-anchor-up' : ''}${tapToOpen ? ' toolbar-tooltip-anchor-tap' : ''}`}
35
71
  tabIndex={tapToOpen ? -1 : undefined}
72
+ onPointerEnter={fitWithin ? fit : undefined}
73
+ onFocusIn={fitWithin ? fit : undefined}
36
74
  >
37
75
  {children}
38
76
  <span class="toolbar-tooltip" role="tooltip">
@@ -42,7 +42,7 @@ export function BoardCopyDialog({ board, onClose }: { board: BoardSummary; onClo
42
42
  const created = await createBoardFrom({
43
43
  sourceBoardId: board.id,
44
44
  name: name.trim(),
45
- ...(board.category ? { category: board.category } : {}),
45
+ ...(board.folder ? { folder: board.folder } : {}),
46
46
  nodeIds: [...selected],
47
47
  includeReadme,
48
48
  includeStructure,
@@ -1,5 +1,5 @@
1
1
  import { useEffect, useRef, useState } from 'preact/hooks';
2
- import { normalizeBoardCategory } from '../../shared/boards.js';
2
+ import { normalizeBoardFolder } from '../../shared/boards.js';
3
3
  import { boardList, updateBoard, type BoardSummary } from '../state/boards-store';
4
4
  import { useFocusTrap } from './use-focus-trap';
5
5
 
@@ -14,7 +14,7 @@ export function BoardFolderDialog({
14
14
  onClose: () => void;
15
15
  }) {
16
16
  const ref = useRef<HTMLDivElement>(null);
17
- const [parent, setParent] = useState(board.category ?? '');
17
+ const [parent, setParent] = useState(board.folder ?? '');
18
18
  const [name, setName] = useState('');
19
19
  const [busy, setBusy] = useState(false);
20
20
  const [error, setError] = useState('');
@@ -32,18 +32,18 @@ export function BoardFolderDialog({
32
32
 
33
33
  const destination = name.trim() ? [parent, name.trim()].filter(Boolean).join('/') : parent;
34
34
  const move = async () => {
35
- let category: string | null;
35
+ let folder: string | null;
36
36
  try {
37
37
  if (name.includes('/')) throw new Error('Use one folder name; choose its parent above.');
38
- category = normalizeBoardCategory(destination);
38
+ folder = normalizeBoardFolder(destination);
39
39
  } catch (cause) {
40
40
  setError(cause instanceof Error ? cause.message : String(cause));
41
41
  return;
42
42
  }
43
43
  setBusy(true);
44
44
  setError('');
45
- await updateBoard(board.id, { category });
46
- if (boardList.value.find((entry) => entry.id === board.id)?.category === category) onClose();
45
+ await updateBoard(board.id, { folder });
46
+ if (boardList.value.find((entry) => entry.id === board.id)?.folder === folder) onClose();
47
47
  else setError('Could not move this board. Try again.');
48
48
  setBusy(false);
49
49
  };
@@ -108,7 +108,7 @@ export function BoardFolderDialog({
108
108
  <button
109
109
  type="button"
110
110
  class="text-prompt-confirm"
111
- disabled={busy || destination === (board.category ?? '')}
111
+ disabled={busy || destination === (board.folder ?? '')}
112
112
  onClick={() => void move()}
113
113
  >
114
114
  {busy ? 'Moving…' : 'Move board'}