wiki-viewer 1.14.1 → 1.14.2

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 (384) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  4. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  5. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  6. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  7. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  10. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  11. package/.next/standalone/.next/server/app/_not-found.rsc +1 -1
  12. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  13. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  15. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  16. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  17. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  18. package/.next/standalone/.next/server/app/api/agent/activity/route.js.nft.json +1 -1
  19. package/.next/standalone/.next/server/app/api/agent/events/[...path]/route.js.nft.json +1 -1
  20. package/.next/standalone/.next/server/app/api/agent/files/[...path]/route.js.nft.json +1 -1
  21. package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/api/agent/fs/move/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/agent/fs/search/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/agent/internal/span/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/agent/settings/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/agent/sidecar/[...path]/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/assets/[...path]/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/share/[token]/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/share/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/system/reveal/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/system/set-root/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/refresh/route.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/system/workspaces/route.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/api/upload/[...path]/route.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/api/wiki/app/route.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/api/wiki/backlinks/route.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/api/wiki/content/route.js.nft.json +1 -1
  41. package/.next/standalone/.next/server/app/api/wiki/download/route.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/api/wiki/file/route.js.nft.json +1 -1
  43. package/.next/standalone/.next/server/app/api/wiki/folder/route.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/api/wiki/git-branches/route.js.nft.json +1 -1
  45. package/.next/standalone/.next/server/app/api/wiki/git-checkout/route.js.nft.json +1 -1
  46. package/.next/standalone/.next/server/app/api/wiki/git-diff/route.js.nft.json +1 -1
  47. package/.next/standalone/.next/server/app/api/wiki/git-file-info/route.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/api/wiki/git-history/route.js.nft.json +1 -1
  49. package/.next/standalone/.next/server/app/api/wiki/git-pull/route.js.nft.json +1 -1
  50. package/.next/standalone/.next/server/app/api/wiki/move/route.js.nft.json +1 -1
  51. package/.next/standalone/.next/server/app/api/wiki/new-file/route.js.nft.json +1 -1
  52. package/.next/standalone/.next/server/app/api/wiki/outlinks/route.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/api/wiki/page/route.js.nft.json +1 -1
  54. package/.next/standalone/.next/server/app/api/wiki/presence/route.js.nft.json +1 -1
  55. package/.next/standalone/.next/server/app/api/wiki/route.js.nft.json +1 -1
  56. package/.next/standalone/.next/server/app/api/wiki/search/route.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/api/wiki/slugs/route.js.nft.json +1 -1
  58. package/.next/standalone/.next/server/app/api/wiki/upload/route.js.nft.json +1 -1
  59. package/.next/standalone/.next/server/app/api/wiki/watch/route.js.nft.json +1 -1
  60. package/.next/standalone/.next/server/app/index.html +1 -1
  61. package/.next/standalone/.next/server/app/index.rsc +1 -1
  62. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  63. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  64. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  65. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  66. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  67. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  68. package/.next/standalone/.next/server/middleware-manifest.json +1 -1
  69. package/.next/standalone/.next/server/pages/404.html +1 -1
  70. package/.next/standalone/.next/server/pages/500.html +1 -1
  71. package/.next/standalone/package.json +1 -1
  72. package/bin/postbuild.js +21 -0
  73. package/package.json +1 -1
  74. package/.next/standalone/.github/workflows/publish.yml +0 -37
  75. package/.next/standalone/.handoffs/archive/handoff-20260612-113332.md +0 -98
  76. package/.next/standalone/.handoffs/archive/handoff-20260612-141032.md +0 -73
  77. package/.next/standalone/.pi/ownership.json +0 -3
  78. package/.next/standalone/AGENTS.md +0 -114
  79. package/.next/standalone/DESIGN.md +0 -521
  80. package/.next/standalone/README.md +0 -821
  81. package/.next/standalone/TODO.md +0 -20
  82. package/.next/standalone/agents/bootstrap-prompt.md +0 -14
  83. package/.next/standalone/agents/wiki-viewer-skill/SKILL.md +0 -456
  84. package/.next/standalone/bin/postbuild.js +0 -78
  85. package/.next/standalone/bin/wiki-viewer.js +0 -922
  86. package/.next/standalone/certificates/localhost-key.pem +0 -28
  87. package/.next/standalone/certificates/localhost.pem +0 -24
  88. package/.next/standalone/docs/agent-collab-plan.md +0 -1615
  89. package/.next/standalone/docs/agent-collab-v2-plan.md +0 -771
  90. package/.next/standalone/docs/agent-fs-plan.md +0 -232
  91. package/.next/standalone/docs/editorial-skin-spec.md +0 -242
  92. package/.next/standalone/docs/file-vs-collab-authority.md +0 -124
  93. package/.next/standalone/docs/mobile-readiness-spec.md +0 -229
  94. package/.next/standalone/docs/workspacing-plan.md +0 -364
  95. package/.next/standalone/packages/wiki-viewer-mcp/README.md +0 -195
  96. package/.next/standalone/packages/wiki-viewer-mcp/bench-e2e.mjs +0 -166
  97. package/.next/standalone/packages/wiki-viewer-mcp/bench-latency.mjs +0 -87
  98. package/.next/standalone/packages/wiki-viewer-mcp/bench-payload.mjs +0 -45
  99. package/.next/standalone/packages/wiki-viewer-mcp/dist/http-client.js +0 -331
  100. package/.next/standalone/packages/wiki-viewer-mcp/dist/index.js +0 -531
  101. package/.next/standalone/packages/wiki-viewer-mcp/dist/register.js +0 -94
  102. package/.next/standalone/packages/wiki-viewer-mcp/dist/state-cache.js +0 -28
  103. package/.next/standalone/packages/wiki-viewer-mcp/package-lock.json +0 -1716
  104. package/.next/standalone/packages/wiki-viewer-mcp/package.json +0 -41
  105. package/.next/standalone/packages/wiki-viewer-mcp/src/http-client.ts +0 -459
  106. package/.next/standalone/packages/wiki-viewer-mcp/src/index.ts +0 -638
  107. package/.next/standalone/packages/wiki-viewer-mcp/src/register.ts +0 -144
  108. package/.next/standalone/packages/wiki-viewer-mcp/src/state-cache.ts +0 -55
  109. package/.next/standalone/packages/wiki-viewer-mcp/tsconfig.json +0 -19
  110. package/.next/standalone/pnpm-lock.yaml +0 -6697
  111. package/.next/standalone/pnpm-workspace.yaml +0 -8
  112. package/.next/standalone/postcss.config.mjs +0 -2
  113. package/.next/standalone/src/app/api/agent/activity/route.ts +0 -59
  114. package/.next/standalone/src/app/api/agent/admin/agents/[agentId]/revoke/route.ts +0 -40
  115. package/.next/standalone/src/app/api/agent/admin/agents/route.ts +0 -33
  116. package/.next/standalone/src/app/api/agent/admin/registrations/[regId]/approve/route.ts +0 -83
  117. package/.next/standalone/src/app/api/agent/admin/registrations/[regId]/deny/route.ts +0 -36
  118. package/.next/standalone/src/app/api/agent/admin/registrations/route.ts +0 -27
  119. package/.next/standalone/src/app/api/agent/events/[...path]/route.ts +0 -148
  120. package/.next/standalone/src/app/api/agent/files/[...path]/route.ts +0 -219
  121. package/.next/standalone/src/app/api/agent/fs/file/[...path]/route.ts +0 -446
  122. package/.next/standalone/src/app/api/agent/fs/ls/[[...path]]/route.ts +0 -152
  123. package/.next/standalone/src/app/api/agent/fs/move/route.ts +0 -130
  124. package/.next/standalone/src/app/api/agent/fs/search/route.ts +0 -272
  125. package/.next/standalone/src/app/api/agent/internal/span/route.ts +0 -121
  126. package/.next/standalone/src/app/api/agent/register/[regId]/route.ts +0 -50
  127. package/.next/standalone/src/app/api/agent/register/route.ts +0 -118
  128. package/.next/standalone/src/app/api/agent/settings/route.ts +0 -34
  129. package/.next/standalone/src/app/api/agent/settings/token/regenerate/route.ts +0 -20
  130. package/.next/standalone/src/app/api/agent/sidecar/[...path]/route.ts +0 -53
  131. package/.next/standalone/src/app/api/agents/install/route.ts +0 -143
  132. package/.next/standalone/src/app/api/agents/skill/route.ts +0 -20
  133. package/.next/standalone/src/app/api/agents/skill.tar.gz/route.ts +0 -87
  134. package/.next/standalone/src/app/api/app-proxy/[...path]/route.ts +0 -247
  135. package/.next/standalone/src/app/api/assets/[...path]/route.ts +0 -75
  136. package/.next/standalone/src/app/api/auth/[...all]/route.ts +0 -7
  137. package/.next/standalone/src/app/api/owner/init/route.ts +0 -14
  138. package/.next/standalone/src/app/api/share/[token]/route.ts +0 -269
  139. package/.next/standalone/src/app/api/share/route.ts +0 -127
  140. package/.next/standalone/src/app/api/system/admins/route.ts +0 -103
  141. package/.next/standalone/src/app/api/system/auth-config/route.ts +0 -22
  142. package/.next/standalone/src/app/api/system/auth-settings/route.ts +0 -86
  143. package/.next/standalone/src/app/api/system/browse/route.ts +0 -82
  144. package/.next/standalone/src/app/api/system/clear-root/route.ts +0 -16
  145. package/.next/standalone/src/app/api/system/config/route.ts +0 -14
  146. package/.next/standalone/src/app/api/system/pins/route.ts +0 -38
  147. package/.next/standalone/src/app/api/system/reveal/route.ts +0 -36
  148. package/.next/standalone/src/app/api/system/root-status/route.ts +0 -13
  149. package/.next/standalone/src/app/api/system/set-root/route.ts +0 -53
  150. package/.next/standalone/src/app/api/system/users/route.ts +0 -120
  151. package/.next/standalone/src/app/api/system/workspaces/[id]/open/route.ts +0 -34
  152. package/.next/standalone/src/app/api/system/workspaces/[id]/refresh/route.ts +0 -32
  153. package/.next/standalone/src/app/api/system/workspaces/[id]/route.ts +0 -78
  154. package/.next/standalone/src/app/api/system/workspaces/route.ts +0 -128
  155. package/.next/standalone/src/app/api/upload/[...path]/route.ts +0 -85
  156. package/.next/standalone/src/app/api/wiki/app/route.ts +0 -60
  157. package/.next/standalone/src/app/api/wiki/backlinks/route.ts +0 -29
  158. package/.next/standalone/src/app/api/wiki/content/route.ts +0 -159
  159. package/.next/standalone/src/app/api/wiki/download/route.ts +0 -100
  160. package/.next/standalone/src/app/api/wiki/file/route.ts +0 -57
  161. package/.next/standalone/src/app/api/wiki/folder/route.ts +0 -34
  162. package/.next/standalone/src/app/api/wiki/git-branches/route.ts +0 -32
  163. package/.next/standalone/src/app/api/wiki/git-checkout/route.ts +0 -45
  164. package/.next/standalone/src/app/api/wiki/git-diff/route.ts +0 -33
  165. package/.next/standalone/src/app/api/wiki/git-file-info/route.ts +0 -27
  166. package/.next/standalone/src/app/api/wiki/git-history/route.ts +0 -27
  167. package/.next/standalone/src/app/api/wiki/git-pull/route.ts +0 -48
  168. package/.next/standalone/src/app/api/wiki/move/route.ts +0 -61
  169. package/.next/standalone/src/app/api/wiki/new-file/route.ts +0 -56
  170. package/.next/standalone/src/app/api/wiki/outlinks/route.ts +0 -76
  171. package/.next/standalone/src/app/api/wiki/page/route.ts +0 -92
  172. package/.next/standalone/src/app/api/wiki/presence/route.ts +0 -56
  173. package/.next/standalone/src/app/api/wiki/route.ts +0 -116
  174. package/.next/standalone/src/app/api/wiki/search/route.ts +0 -44
  175. package/.next/standalone/src/app/api/wiki/slugs/route.ts +0 -54
  176. package/.next/standalone/src/app/api/wiki/upload/route.ts +0 -95
  177. package/.next/standalone/src/app/api/wiki/watch/route.ts +0 -67
  178. package/.next/standalone/src/app/globals.css +0 -1249
  179. package/.next/standalone/src/app/icon.svg +0 -11
  180. package/.next/standalone/src/app/layout.tsx +0 -78
  181. package/.next/standalone/src/app/manifest.ts +0 -30
  182. package/.next/standalone/src/app/page.tsx +0 -3260
  183. package/.next/standalone/src/app/s/[token]/page.tsx +0 -357
  184. package/.next/standalone/src/app/signin/page.tsx +0 -16
  185. package/.next/standalone/src/app/signin/signin-form.tsx +0 -238
  186. package/.next/standalone/src/components/ai-panel/activity-row.tsx +0 -284
  187. package/.next/standalone/src/components/ai-panel/ai-panel.tsx +0 -311
  188. package/.next/standalone/src/components/ai-panel/token-section.tsx +0 -313
  189. package/.next/standalone/src/components/auth-settings-sheet.tsx +0 -474
  190. package/.next/standalone/src/components/confirm-dialog.tsx +0 -56
  191. package/.next/standalone/src/components/dir-picker.tsx +0 -606
  192. package/.next/standalone/src/components/editor/backlinks-panel.tsx +0 -139
  193. package/.next/standalone/src/components/editor/bubble-menu.tsx +0 -346
  194. package/.next/standalone/src/components/editor/callout-extension.ts +0 -36
  195. package/.next/standalone/src/components/editor/comment-pip.tsx +0 -56
  196. package/.next/standalone/src/components/editor/comment-thread.tsx +0 -254
  197. package/.next/standalone/src/components/editor/csv-viewer.tsx +0 -379
  198. package/.next/standalone/src/components/editor/document-outline.tsx +0 -230
  199. package/.next/standalone/src/components/editor/editor-toolbar.tsx +0 -564
  200. package/.next/standalone/src/components/editor/editor.tsx +0 -1327
  201. package/.next/standalone/src/components/editor/extensions/drag-handle.ts +0 -325
  202. package/.next/standalone/src/components/editor/extensions/heading-anchors.ts +0 -55
  203. package/.next/standalone/src/components/editor/extensions/proof-span.ts +0 -60
  204. package/.next/standalone/src/components/editor/extensions/resizable-image.tsx +0 -159
  205. package/.next/standalone/src/components/editor/extensions.ts +0 -150
  206. package/.next/standalone/src/components/editor/file-fallback-viewer.tsx +0 -75
  207. package/.next/standalone/src/components/editor/folder-index.tsx +0 -236
  208. package/.next/standalone/src/components/editor/google-doc-viewer.tsx +0 -73
  209. package/.next/standalone/src/components/editor/image-viewer.tsx +0 -57
  210. package/.next/standalone/src/components/editor/large-file-gate.tsx +0 -108
  211. package/.next/standalone/src/components/editor/link-popover.tsx +0 -111
  212. package/.next/standalone/src/components/editor/media-popover.tsx +0 -212
  213. package/.next/standalone/src/components/editor/media-viewer.tsx +0 -70
  214. package/.next/standalone/src/components/editor/mermaid-viewer.tsx +0 -286
  215. package/.next/standalone/src/components/editor/node-app-viewer.tsx +0 -328
  216. package/.next/standalone/src/components/editor/notebook-viewer.tsx +0 -371
  217. package/.next/standalone/src/components/editor/office/docx-viewer.tsx +0 -93
  218. package/.next/standalone/src/components/editor/office/office-chrome.tsx +0 -83
  219. package/.next/standalone/src/components/editor/office/pptx-viewer.tsx +0 -104
  220. package/.next/standalone/src/components/editor/office/xlsx-viewer.tsx +0 -192
  221. package/.next/standalone/src/components/editor/pdf-viewer.tsx +0 -32
  222. package/.next/standalone/src/components/editor/proof-span-popover.tsx +0 -162
  223. package/.next/standalone/src/components/editor/slash-commands.tsx +0 -629
  224. package/.next/standalone/src/components/editor/source-viewer.tsx +0 -289
  225. package/.next/standalone/src/components/editor/suggest-edit-popover.tsx +0 -229
  226. package/.next/standalone/src/components/editor/suggestion-card.tsx +0 -206
  227. package/.next/standalone/src/components/editor/table-menu.tsx +0 -232
  228. package/.next/standalone/src/components/editor/view-mode-comment-button.tsx +0 -77
  229. package/.next/standalone/src/components/editor/website-viewer.tsx +0 -75
  230. package/.next/standalone/src/components/editor/wiki-link-create-dialog.tsx +0 -189
  231. package/.next/standalone/src/components/editor/wiki-link-decorator.ts +0 -79
  232. package/.next/standalone/src/components/editor/wiki-link-extension.ts +0 -120
  233. package/.next/standalone/src/components/editor/wiki-link-picker.tsx +0 -250
  234. package/.next/standalone/src/components/layout/viewer-toolbar.tsx +0 -54
  235. package/.next/standalone/src/components/search/search-command-dialog.tsx +0 -246
  236. package/.next/standalone/src/components/search/sidebar-search-box.tsx +0 -121
  237. package/.next/standalone/src/components/search/snippet-text.tsx +0 -48
  238. package/.next/standalone/src/components/share-dialog.tsx +0 -307
  239. package/.next/standalone/src/components/theme-provider.tsx +0 -16
  240. package/.next/standalone/src/components/theme-toggle.tsx +0 -24
  241. package/.next/standalone/src/components/ui/badge.tsx +0 -35
  242. package/.next/standalone/src/components/ui/button.tsx +0 -56
  243. package/.next/standalone/src/components/ui/card.tsx +0 -63
  244. package/.next/standalone/src/components/ui/collapsible.tsx +0 -9
  245. package/.next/standalone/src/components/ui/command.tsx +0 -151
  246. package/.next/standalone/src/components/ui/context-menu.tsx +0 -191
  247. package/.next/standalone/src/components/ui/dialog.tsx +0 -119
  248. package/.next/standalone/src/components/ui/dropdown-menu.tsx +0 -194
  249. package/.next/standalone/src/components/ui/input.tsx +0 -22
  250. package/.next/standalone/src/components/ui/label.tsx +0 -25
  251. package/.next/standalone/src/components/ui/popover.tsx +0 -33
  252. package/.next/standalone/src/components/ui/scroll-area.tsx +0 -47
  253. package/.next/standalone/src/components/ui/select.tsx +0 -156
  254. package/.next/standalone/src/components/ui/separator.tsx +0 -30
  255. package/.next/standalone/src/components/ui/sheet.tsx +0 -140
  256. package/.next/standalone/src/components/ui/skeleton.tsx +0 -15
  257. package/.next/standalone/src/components/ui/switch.tsx +0 -28
  258. package/.next/standalone/src/components/ui/tabs.tsx +0 -54
  259. package/.next/standalone/src/components/ui/textarea.tsx +0 -21
  260. package/.next/standalone/src/components/ui/tip.tsx +0 -23
  261. package/.next/standalone/src/components/ui/toggle-group.tsx +0 -41
  262. package/.next/standalone/src/components/ui/tooltip.tsx +0 -27
  263. package/.next/standalone/src/components/view-width-toggle.tsx +0 -70
  264. package/.next/standalone/src/components/wiki/frontmatter-header.tsx +0 -164
  265. package/.next/standalone/src/hooks/use-is-mobile.ts +0 -14
  266. package/.next/standalone/src/lib/app-runner.ts +0 -272
  267. package/.next/standalone/src/lib/auth/admin.ts +0 -120
  268. package/.next/standalone/src/lib/auth/allowlist.ts +0 -50
  269. package/.next/standalone/src/lib/auth/client.ts +0 -4
  270. package/.next/standalone/src/lib/auth/csrf.ts +0 -68
  271. package/.next/standalone/src/lib/auth/server.ts +0 -215
  272. package/.next/standalone/src/lib/cabinets/tree.ts +0 -75
  273. package/.next/standalone/src/lib/config.ts +0 -114
  274. package/.next/standalone/src/lib/embeds/detect.ts +0 -142
  275. package/.next/standalone/src/lib/git-secrets.ts +0 -65
  276. package/.next/standalone/src/lib/git.ts +0 -503
  277. package/.next/standalone/src/lib/google/detect.ts +0 -107
  278. package/.next/standalone/src/lib/markdown/parse-frontmatter.ts +0 -104
  279. package/.next/standalone/src/lib/markdown/remark-wikilinks.ts +0 -100
  280. package/.next/standalone/src/lib/markdown/sanitize-schema.ts +0 -106
  281. package/.next/standalone/src/lib/markdown/to-html.ts +0 -282
  282. package/.next/standalone/src/lib/markdown/to-markdown.ts +0 -252
  283. package/.next/standalone/src/lib/proof/activity-shared.ts +0 -31
  284. package/.next/standalone/src/lib/proof/activity.ts +0 -74
  285. package/.next/standalone/src/lib/proof/audit.ts +0 -88
  286. package/.next/standalone/src/lib/proof/auth.ts +0 -143
  287. package/.next/standalone/src/lib/proof/block-refs.ts +0 -133
  288. package/.next/standalone/src/lib/proof/blocks.ts +0 -73
  289. package/.next/standalone/src/lib/proof/client-auth.ts +0 -23
  290. package/.next/standalone/src/lib/proof/collab-state.ts +0 -81
  291. package/.next/standalone/src/lib/proof/event-bus.ts +0 -47
  292. package/.next/standalone/src/lib/proof/file-lock.ts +0 -43
  293. package/.next/standalone/src/lib/proof/glob.ts +0 -51
  294. package/.next/standalone/src/lib/proof/idempotency.ts +0 -37
  295. package/.next/standalone/src/lib/proof/lease.ts +0 -117
  296. package/.next/standalone/src/lib/proof/mutex.ts +0 -36
  297. package/.next/standalone/src/lib/proof/ops-applier.ts +0 -727
  298. package/.next/standalone/src/lib/proof/owner-auth.ts +0 -2
  299. package/.next/standalone/src/lib/proof/pending.ts +0 -97
  300. package/.next/standalone/src/lib/proof/proof-span.ts +0 -141
  301. package/.next/standalone/src/lib/proof/rate-limit.ts +0 -53
  302. package/.next/standalone/src/lib/proof/raw-fs.ts +0 -197
  303. package/.next/standalone/src/lib/proof/register-rate-limit.ts +0 -53
  304. package/.next/standalone/src/lib/proof/registry.ts +0 -195
  305. package/.next/standalone/src/lib/proof/sidecar.ts +0 -103
  306. package/.next/standalone/src/lib/proof/suggest-capture.ts +0 -69
  307. package/.next/standalone/src/lib/proof/types.ts +0 -182
  308. package/.next/standalone/src/lib/proof-config.ts +0 -14
  309. package/.next/standalone/src/lib/root-dir.ts +0 -35
  310. package/.next/standalone/src/lib/search/indexable-exts.ts +0 -25
  311. package/.next/standalone/src/lib/search/indexer.ts +0 -634
  312. package/.next/standalone/src/lib/search/sanitize.ts +0 -35
  313. package/.next/standalone/src/lib/search/search-db.ts +0 -57
  314. package/.next/standalone/src/lib/search/watcher-pool.ts +0 -79
  315. package/.next/standalone/src/lib/shared-docs/db.ts +0 -177
  316. package/.next/standalone/src/lib/toast.ts +0 -9
  317. package/.next/standalone/src/lib/utils.ts +0 -6
  318. package/.next/standalone/src/lib/wiki-helpers.ts +0 -36
  319. package/.next/standalone/src/lib/workspace-client.ts +0 -82
  320. package/.next/standalone/src/lib/workspace-context.ts +0 -173
  321. package/.next/standalone/src/lib/workspaces.ts +0 -400
  322. package/.next/standalone/src/middleware.ts +0 -44
  323. package/.next/standalone/src/stores/ai-panel-store.ts +0 -79
  324. package/.next/standalone/src/stores/editor-store.ts +0 -439
  325. package/.next/standalone/src/stores/pin-store.ts +0 -56
  326. package/.next/standalone/src/stores/proof-store.ts +0 -124
  327. package/.next/standalone/src/stores/recent-store.ts +0 -51
  328. package/.next/standalone/src/stores/search-store.ts +0 -104
  329. package/.next/standalone/src/stores/show-hidden-store.ts +0 -26
  330. package/.next/standalone/src/stores/sidebar-width-store.ts +0 -39
  331. package/.next/standalone/src/stores/skin-store.ts +0 -42
  332. package/.next/standalone/src/stores/tree-store.ts +0 -52
  333. package/.next/standalone/src/stores/view-width-store.ts +0 -101
  334. package/.next/standalone/src/stores/wiki-slugs-store.ts +0 -75
  335. package/.next/standalone/src/tests/proof/activity-aggregator.test.ts +0 -146
  336. package/.next/standalone/src/tests/proof/admin-create-user.test.ts +0 -43
  337. package/.next/standalone/src/tests/proof/agent-fs.test.ts +0 -973
  338. package/.next/standalone/src/tests/proof/agent-ownership.test.ts +0 -140
  339. package/.next/standalone/src/tests/proof/agent-workspace-scope.test.ts +0 -134
  340. package/.next/standalone/src/tests/proof/agents-install.test.ts +0 -110
  341. package/.next/standalone/src/tests/proof/bench-write.ts +0 -179
  342. package/.next/standalone/src/tests/proof/better-auth.test.ts +0 -68
  343. package/.next/standalone/src/tests/proof/block-refs.test.ts +0 -108
  344. package/.next/standalone/src/tests/proof/blocks.test.ts +0 -92
  345. package/.next/standalone/src/tests/proof/collab-state.test.ts +0 -501
  346. package/.next/standalone/src/tests/proof/comments-ops.test.ts +0 -177
  347. package/.next/standalone/src/tests/proof/editor-roundtrip.test.ts +0 -85
  348. package/.next/standalone/src/tests/proof/external-edit.test.ts +0 -58
  349. package/.next/standalone/src/tests/proof/file-lock.test.ts +0 -80
  350. package/.next/standalone/src/tests/proof/git-branches-checkout.test.ts +0 -136
  351. package/.next/standalone/src/tests/proof/git-read-features.test.ts +0 -473
  352. package/.next/standalone/src/tests/proof/git-secrets.test.ts +0 -138
  353. package/.next/standalone/src/tests/proof/git-sparse.test.ts +0 -257
  354. package/.next/standalone/src/tests/proof/git-workspace.test.ts +0 -135
  355. package/.next/standalone/src/tests/proof/git.test.ts +0 -243
  356. package/.next/standalone/src/tests/proof/glob.test.ts +0 -82
  357. package/.next/standalone/src/tests/proof/helpers/auth-session.ts +0 -27
  358. package/.next/standalone/src/tests/proof/markdown-to-html.test.ts +0 -46
  359. package/.next/standalone/src/tests/proof/ops-applier.test.ts +0 -368
  360. package/.next/standalone/src/tests/proof/owner-init.test.ts +0 -2
  361. package/.next/standalone/src/tests/proof/parse-frontmatter.test.ts +0 -60
  362. package/.next/standalone/src/tests/proof/preload.ts +0 -21
  363. package/.next/standalone/src/tests/proof/proof-span.test.ts +0 -98
  364. package/.next/standalone/src/tests/proof/rate-limit.test.ts +0 -54
  365. package/.next/standalone/src/tests/proof/readonly-enforcement.test.ts +0 -161
  366. package/.next/standalone/src/tests/proof/reconcile-sidecar.test.ts +0 -195
  367. package/.next/standalone/src/tests/proof/registration-flow.test.ts +0 -330
  368. package/.next/standalone/src/tests/proof/registry.test.ts +0 -169
  369. package/.next/standalone/src/tests/proof/routes.test.ts +0 -516
  370. package/.next/standalone/src/tests/proof/search-index.test.ts +0 -376
  371. package/.next/standalone/src/tests/proof/sidecar-lifecycle.test.ts +0 -177
  372. package/.next/standalone/src/tests/proof/sidecar-trim.test.ts +0 -58
  373. package/.next/standalone/src/tests/proof/suggestion-ops.test.ts +0 -280
  374. package/.next/standalone/src/tests/proof/wiki-content-put.test.ts +0 -140
  375. package/.next/standalone/src/tests/proof/wiki-routes-auth.test.ts +0 -208
  376. package/.next/standalone/src/tests/proof/workspace-isolation.test.ts +0 -87
  377. package/.next/standalone/src/tests/proof/workspaces-api.test.ts +0 -227
  378. package/.next/standalone/src/types/index.ts +0 -47
  379. package/.next/standalone/tailwind.config.ts +0 -191
  380. package/.next/standalone/tsconfig.json +0 -41
  381. package/.next/standalone/tsconfig.tsbuildinfo +0 -1
  382. /package/.next/standalone/.next/static/{WMOTgfV82apmdovxzgbMx → rRyvFORvJoc5OWbCR2A_P}/_buildManifest.js +0 -0
  383. /package/.next/standalone/.next/static/{WMOTgfV82apmdovxzgbMx → rRyvFORvJoc5OWbCR2A_P}/_clientMiddlewareManifest.js +0 -0
  384. /package/.next/standalone/.next/static/{WMOTgfV82apmdovxzgbMx → rRyvFORvJoc5OWbCR2A_P}/_ssgManifest.js +0 -0
@@ -1,229 +0,0 @@
1
- # Mobile-readiness spec
2
-
3
- Implementation-ready spec for making wiki-viewer usable on phones/tablets. Desktop layout and behavior stay visually unchanged. Mobile is additive, gated behind a breakpoint.
4
-
5
- Stack: Next.js 16, React 19, Tailwind 3, Radix/shadcn, TipTap 3, Zustand.
6
-
7
- ## Design principle
8
-
9
- The app already has the two primitives we need:
10
-
11
- 1. Sidebar already has a **collapse/expand** state (`sidebarCollapsed`, local `useState` in `src/app/page.tsx:405`). When collapsed, the sidebar `Card` is unmounted and a reopen button appears top-left of the editor area (`page.tsx:~2057`).
12
- 2. AI panel is already a **fixed overlay + backdrop** driven by zustand (`useAIPanelStore.isOpen`), not part of the flex row (`src/components/ai-panel/ai-panel.tsx:152`).
13
-
14
- So mobile work is mostly: (a) make the sidebar **overlay instead of push** on small screens, (b) auto-collapse it on mobile, (c) add a hamburger affordance, (d) cap fixed panel widths, (e) make touch-only affordances reachable, (f) fix the viewport meta. We do NOT introduce a new layout engine.
15
-
16
- ---
17
-
18
- ## 1. Breakpoint strategy
19
-
20
- Single breakpoint. Mobile = viewport `< 768px` (Tailwind `md`). At/above `md` = desktop, unchanged.
21
-
22
- - Tailwind prefix: `md:` is the desktop gate. Mobile styles are the unprefixed base; `md:` restores desktop.
23
- - Rationale: one breakpoint keeps the matrix small and matches the real failure mode (3 panels do not fit on a phone; they fit fine on a ≥768px tablet in landscape and on iPad portrait). Tablets ≥768px keep the desktop 3-panel layout, which is acceptable.
24
- - No second tier. Phone-vs-tablet nuance is not worth the complexity here.
25
-
26
- A JS boolean is needed in a few places (auto-collapse on mount, "opening sidebar closes AI panel" logic, ignoring the resize handle). Add a `useIsMobile()` hook (section 7) backed by `matchMedia("(max-width: 767px)")`. Everything purely visual stays in Tailwind `md:` classes; only logic that branches on the boolean uses the hook.
27
-
28
- ---
29
-
30
- ## 2. Layout transformation
31
-
32
- Desktop (`md` and up): unchanged. `flex h-screen overflow-hidden` row of [sidebar (resizable, pushes content)] + [editor flex-1] + [AI panel overlay].
33
-
34
- Mobile (`< md`):
35
-
36
- ### Sidebar → overlay drawer (left)
37
-
38
- - Sidebar must **overlay** the editor, not occupy a flex column. On mobile the sidebar `Card` becomes `fixed inset-y-0 left-0 z-50` with its own backdrop (`fixed inset-0 z-40`, tap-to-close). On desktop it stays in-flow (`md:static md:z-auto`, no backdrop).
39
- - Width on mobile: `w-[85vw] max-w-[20rem]` (≈ phone-width minus a peek of the editor). Ignore the `sidebarWidth` store on mobile (section 9). On desktop keep `style={{ width: sidebarWidth }}` and `md:w-[var(...)]` is not needed because the inline style wins; instead gate the inline width so it only applies at `md+` (section 7 / component table).
40
- - Default state on mobile: **collapsed** (closed). On first mount at mobile width, force `sidebarCollapsed = true`.
41
- - Open trigger: hamburger button in the mobile top bar (section 3).
42
- - Close: tap backdrop, tap a file (navigating opens the file then closes the drawer on mobile), or the existing collapse button in the sidebar header.
43
- - Backdrop: only rendered on mobile (`md:hidden`) and only when sidebar open.
44
- - z-index: backdrop `z-40`, sidebar `z-50`. AI panel uses backdrop `z-40` / panel `z-50` too; they are mutually exclusive on mobile (opening one closes the other, section 8) so no stacking conflict.
45
-
46
- ### AI panel → full-ish width sheet (right)
47
-
48
- - Already an overlay. Only change: width. `w-80` becomes `w-[90vw] max-w-sm md:w-80` so it never exceeds viewport on small screens. Everything else (backdrop, Esc, focus trap) already works.
49
-
50
- ### Editor → full width
51
-
52
- - Editor area is already `flex-1 min-w-0`. With the sidebar overlaying instead of pushing, it naturally spans full width on mobile. No change beyond the top-bar offset (section 3).
53
-
54
- ### Body scroll
55
-
56
- - Keep `h-screen overflow-hidden` on the shell on all breakpoints. The editor body already scrolls internally (`overflow-y-auto`). Do not switch to body scroll. Reason: the editor toolbar and doc header are sticky chrome; body scroll would detach them and complicate the on-screen-keyboard case. The editor's own scroll container handles long docs.
57
-
58
- ---
59
-
60
- ## 3. Mobile top bar / chrome
61
-
62
- Desktop has no global header; do not add one there. The editor's doc-header row already exists per-view (`page.tsx:2086`, `:2198`) and hosts the collapsed-sidebar reopen button via `pl-11` padding.
63
-
64
- Mobile approach: **reuse the existing reopen-button slot, add an AI-panel toggle next to it.** No new full-width header bar.
65
-
66
- - The existing `sidebarCollapsed && <PanelLeftOpen>` button (top-left, `absolute left-2 top-2`) already serves as the hamburger. On mobile the sidebar is always collapsed-by-default, so this button is the persistent menu affordance. Change: render it whenever `isMobile || sidebarCollapsed` (so it shows on mobile even though state is "collapsed"), icon stays `PanelLeftOpen` (menu-like). Keep `pl-11` header offset logic but key it on the same condition.
67
- - Add an **AI panel toggle** button: top-right of the editor area, `absolute right-2 top-2 z-10`, `md:hidden` (desktop opens AI panel via existing mechanism/keyboard; do not change desktop). Icon: `Bot` (already imported in ai-panel; import in page). `onClick={() => useAIPanelStore.getState().open()}`. 44px tap target on mobile (section 5).
68
- - These two floating buttons sit above the editor doc-header. They must not overlap the doc title; the existing `pl-11` already reserves left space, add matching `pr-11` on mobile when the AI toggle shows.
69
-
70
- Rationale for no dedicated header: the per-view doc headers already carry title + actions. A second global bar would eat vertical space (precious with the on-screen keyboard up) and duplicate chrome. Floating buttons over existing chrome is the minimal, non-regressing change.
71
-
72
- ---
73
-
74
- ## 4. Touch interaction replacements
75
-
76
- Decisive choice per item:
77
-
78
- ### Hover-gated sidebar row actions (`page.tsx:1326`, `:1861`)
79
-
80
- - Make them **always visible on coarse pointers**. Use `@media (hover: none)` to neutralize the `opacity-0 ... group-hover:opacity-100` reveal. Add a global CSS rule in `globals.css`:
81
- ```css
82
- @media (hover: none) {
83
- .hover-reveal {
84
- opacity: 1 !important;
85
- max-width: none !important;
86
- }
87
- }
88
- ```
89
- Add class `hover-reveal` to the two reveal wrappers. Keeps desktop hover behavior intact; on touch the actions are simply always shown. Chosen over a per-row "..." menu because the actions already collapse cleanly and always-visible is zero new UI.
90
-
91
- ### Image resize handles (`resizable-image.tsx:100-107`)
92
-
93
- - Same `@media (hover: none)` always-visible treatment via the `hover-reveal` class. Handles already use `onPointerDown` (touch-capable) so once visible they work. Bump handle hit area on coarse pointers to ≥24px (visually can stay small via a transparent padded hit zone) so they are tappable.
94
-
95
- ### Tree drag-reorder (`page.tsx:1202`, HTML5 `draggable`)
96
-
97
- - **Disable on touch.** HTML5 DnD is not touch-capable and a touch DnD lib is out of scope. Set `draggable={!isMobile}`. Reordering on mobile is done via the existing context menu (long-press opens Radix `ContextMenu`, already wired at `page.tsx:1189`) which exposes move/rename actions. No new UI.
98
-
99
- ### Sidebar resize handle (`page.tsx:2009`, `onMouseDown`)
100
-
101
- - **Hide on mobile.** The mobile sidebar is a fixed-width drawer; resizing is meaningless. Add `md:block hidden` (or render-gate on `!isMobile`). No touch handler added.
102
-
103
- ---
104
-
105
- ## 5. Tap targets
106
-
107
- Target: 44×44 CSS px on touch (iOS HIG; covers Android 48 in practice with padding). Apply **only on coarse pointers** so desktop density is unchanged.
108
-
109
- - Current `h-7 w-7` (28px) and `h-8 w-8` (32px) icon buttons are below target. Do not resize globally.
110
- - Add a global rule:
111
- ```css
112
- @media (hover: none) and (pointer: coarse) {
113
- button,
114
- [role="button"],
115
- a.btn {
116
- min-height: 44px;
117
- min-width: 44px;
118
- }
119
- }
120
- ```
121
- Scope carefully: this can distort dense editor toolbar. Prefer a utility class `touch-target` applied to the specific mobile-critical controls (hamburger, AI toggle, sidebar row primary tap, file-tree rows) rather than all buttons, if the blanket rule visually breaks the toolbar. Implementer picks blanket vs scoped after a quick visual check; default to **scoped** to avoid toolbar regressions.
122
- - File-tree rows: ensure row height ≥44px on coarse pointers (they are currently compact). Add `touch-target`-style min-height to the row container on mobile.
123
-
124
- ---
125
-
126
- ## 6. Viewport meta
127
-
128
- `src/app/layout.tsx:43`, replace:
129
-
130
- ```ts
131
- export const viewport: Viewport = {
132
- themeColor: "#0c0a09",
133
- width: "device-width",
134
- initialScale: 1,
135
- viewportFit: "cover",
136
- };
137
- ```
138
-
139
- - `width: device-width`, `initialScale: 1`: standard responsive baseline.
140
- - `viewportFit: "cover"`: needed for notch / safe-area on installed iOS PWA (status bar is `black-translucent`). Pairs with safe-area insets (section 9).
141
- - **Do NOT set `maximumScale` or `userScalable: false`.** This is a text editor; pinch-zoom is an accessibility requirement. Allow zoom.
142
-
143
- ---
144
-
145
- ## 7. Component-by-component change list
146
-
147
- New shared hook: `src/hooks/use-is-mobile.ts` (create `src/hooks/`).
148
-
149
- ```ts
150
- "use client";
151
- import { useEffect, useState } from "react";
152
- export function useIsMobile(query = "(max-width: 767px)") {
153
- const [isMobile, setIsMobile] = useState(false); // SSR-safe default
154
- useEffect(() => {
155
- const mql = window.matchMedia(query);
156
- const on = () => setIsMobile(mql.matches);
157
- on();
158
- mql.addEventListener("change", on);
159
- return () => mql.removeEventListener("change", on);
160
- }, [query]);
161
- return isMobile;
162
- }
163
- ```
164
-
165
- SSR returns `false` (desktop) to avoid hydration mismatch; corrects on mount. Acceptable: first paint is desktop layout, snaps to mobile in one frame.
166
-
167
- | File | Change | Verdict gate |
168
- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
169
- | `src/app/layout.tsx` | Expand `viewport` export (section 6). Add safe-area CSS hook if needed. | always |
170
- | `src/hooks/use-is-mobile.ts` | New hook. | new |
171
- | `src/app/page.tsx` | Consume `useIsMobile()`. Force `sidebarCollapsed=true` on mobile mount. Sidebar `Card`: add `fixed inset-y-0 left-0 z-50 w-[85vw] max-w-[20rem] md:static md:z-auto md:w-auto` and gate inline `style={{width}}` to desktop only (apply `width` only when `!isMobile`). Render a `md:hidden` backdrop when sidebar open on mobile. Hamburger button shows when `isMobile | | sidebarCollapsed`. Add `md:hidden`AI-panel toggle button (top-right). Resize handle`hidden md:block`. Tree items `draggable={!isMobile}`. On mobile, selecting a file closes the sidebar drawer. `pr-11` doc-header offset when AI toggle visible. | `md:` + hook |
172
- | `src/components/ai-panel/ai-panel.tsx` | Panel width `w-80` → `w-[90vw] max-w-sm md:w-80`. No other change. | `md:` only |
173
- | `src/components/auth-settings-sheet.tsx` | Width `w-80` → `w-[90vw] max-w-sm md:w-80` (line ~158). | `md:` only |
174
- | `src/components/editor/extensions/resizable-image.tsx` | Add `hover-reveal` class to the resize-handle wrapper(s) (lines ~100-107). Enlarge touch hit area on coarse pointers. | CSS `@media (hover:none)` |
175
- | `src/components/editor/editor-toolbar.tsx` | Verify `overflow-x-scroll` still works with larger touch targets; if blanket 44px rule breaks it, keep toolbar buttons out of the touch-target scope. Likely no code change. | verify only |
176
- | `src/app/globals.css` | Add `@media (hover: none)` always-visible rule for `.hover-reveal`; add scoped `touch-target` min-size rule; add safe-area padding utilities for notch (section 9). | CSS |
177
-
178
- Sidebar row reveal wrappers (`page.tsx:1326`, `:1861`): add `hover-reveal` class.
179
-
180
- ---
181
-
182
- ## 8. State management
183
-
184
- - **Mobile sidebar drawer** reuses the existing `sidebarCollapsed` local state. No new store. `collapsed === closed` on mobile; `collapsed === pushed-off` on desktop. Same boolean, different presentation (overlay vs in-flow), gated by `md:`/`useIsMobile`.
185
- - **AI panel** keeps its zustand `isOpen`.
186
- - **Mutual exclusion on mobile only:** opening the sidebar calls `useAIPanelStore.getState().close()`; opening the AI panel sets `sidebarCollapsed=true`. Only do this when `isMobile` (desktop can show both). Wire in the respective open handlers in `page.tsx`.
187
- - Persist nothing new. `sidebarWidth` store stays for desktop.
188
-
189
- ---
190
-
191
- ## 9. Edge cases
192
-
193
- - **Orientation change:** `matchMedia` change listener re-evaluates `isMobile`; rotating a phone to landscape ≥768px wide will switch to desktop layout. Acceptable and correct. Ensure the sidebar `style` width gate re-reads `isMobile` on render (it will, via hook).
194
- - **On-screen keyboard:** editor focus raises the keyboard, shrinking visual viewport. Because the shell is `h-screen overflow-hidden` and the editor scrolls internally, the focused caret stays in view via native scroll-into-view. Do not add JS viewport-resize handling. Verify the sticky toolbar does not cover the caret; if it does, that is a follow-up, not a blocker.
195
- - **Safe-area insets (notch)** given `viewportFit: cover`: add safe-area padding so chrome is not under the notch/home indicator. In `globals.css`:
196
- ```css
197
- @supports (padding: max(0px)) {
198
- .safe-top {
199
- padding-top: max(0.5rem, env(safe-area-inset-top));
200
- }
201
- .safe-bottom {
202
- padding-bottom: env(safe-area-inset-bottom);
203
- }
204
- }
205
- ```
206
- Apply `safe-top` to the mobile floating buttons / sidebar header, `safe-bottom` to the AI panel and any bottom-anchored sheet. Desktop unaffected (`env()` is 0).
207
- - **`sidebarWidth` store on mobile:** ignored. The drawer uses `w-[85vw] max-w-[20rem]`. Do not write to the store from mobile; do not clamp. On return to desktop the stored width applies again unchanged.
208
-
209
- ---
210
-
211
- ## Implementation order
212
-
213
- 1. `useIsMobile` hook + viewport meta (`layout.tsx`). Foundational, zero risk.
214
- 2. Width caps: `ai-panel.tsx`, `auth-settings-sheet.tsx` (`w-[90vw] max-w-sm md:w-80`). Independent, low risk, immediate win.
215
- 3. globals.css: `.hover-reveal` always-visible rule, `touch-target` scoped rule, safe-area utilities.
216
- 4. Sidebar overlay + auto-collapse + backdrop + hamburger in `page.tsx`. Core layout change.
217
- 5. AI-panel mobile toggle + mutual exclusion in `page.tsx`.
218
- 6. Touch fixes: `draggable={!isMobile}`, resize handle `hidden md:block`, `hover-reveal` on reveal wrappers + resizable-image, tree row min-height.
219
- 7. Verify editor toolbar + tap-target scoping doesn't regress desktop.
220
-
221
- ## Out of scope
222
-
223
- - Touch drag-and-drop reordering of the file tree (use context menu instead).
224
- - Touch-resizable sidebar (fixed-width drawer on mobile).
225
- - Bottom-sheet redesign of the AI panel (side sheet with width cap is enough).
226
- - Any change to desktop layout, spacing, or behavior.
227
- - Editor on-screen-keyboard caret-tracking JS.
228
- - New global mobile header bar.
229
- - PWA/manifest changes (already solid).
@@ -1,364 +0,0 @@
1
- # Workspacing plan
2
-
3
- > **Status: IMPLEMENTED.** Phases A–E complete. 294 tests pass, tsc clean.
4
- > Key files: `src/lib/workspaces.ts`, `src/lib/workspace-context.ts`,
5
- > `src/lib/auth/admin.ts`, `src/lib/workspace-client.ts`, workspace + admin
6
- > APIs under `src/app/api/system/`, agent scope via `scope.workspaceId`.
7
- > The legacy `src/lib/root-dir.ts` global is retained as a fallback source
8
- > (synthetic default workspace) for `ROOT_DIR`/CLI/tests — not yet deleted.
9
-
10
- ## Goal
11
-
12
- Let one running wiki-viewer serve multiple root directories ("workspaces")
13
- concurrently, with zero state bleed between them. A user can have two tabs open
14
- on two different workspaces at once. AI agents target a specific workspace.
15
-
16
- Decisions (locked):
17
-
18
- - **Selection**: URL/query carries `ws=<wsId>` for browser routes; agents send
19
- an `X-Workspace: <wsId>` header. No process-global "current root".
20
- - **Agents are workspace-scoped**: every agent request resolves a workspace and
21
- is denied if it has no grant for it.
22
- - **Isolation type**: organizational, not OS-level ACL. We add an explicit
23
- per-workspace access list (which users / which agents may use a workspace).
24
- We do NOT add per-user filesystem path restrictions on the directory browser.
25
-
26
- ## Why the current code bleeds
27
-
28
- `src/lib/root-dir.ts` keeps a single `globalThis.__wikiRootDir`. Every route
29
- calls `getRootDir()` / `safeRootPath()` against that one value, so:
30
-
31
- - "Change" (`/api/system/clear-root`) wipes the root for every user/tab.
32
- - Only one root can be active per process. No concurrency at all.
33
-
34
- In-memory stores keyed by **relPath only** (collide across roots once more than
35
- one root is live):
36
-
37
- - `src/lib/proof/lease.ts` — `leases` + `generations` maps keyed by relPath.
38
- - `src/lib/proof/idempotency.ts` — single LRU keyed by idempotency key.
39
- - `src/lib/proof/mutex.ts` — in-process lock map keyed by relPath / mdPath.
40
- - `src/lib/proof/file-lock.ts` — cross-process sentinel hashed from lockKey
41
- (relPath). Two workspaces with `notes.md` share one lock.
42
-
43
- Config is single-root shaped:
44
-
45
- - `src/lib/config.ts` — one `lastOpenedPath`, one flat `pinnedPaths`.
46
-
47
- Already correctly scoped (these take `rootDir` as a param, keep as-is):
48
-
49
- - `src/lib/proof/sidecar.ts`, `activity.ts` — read/write under
50
- `<rootDir>/.proof/`. Naturally isolated once `rootDir` is per-workspace.
51
-
52
- Global, needs a `workspaceId` column / field:
53
-
54
- - `src/lib/proof/audit.ts` — `agent_fs_audit` table mixes paths from all roots.
55
- - `src/lib/proof/registry.ts` — `agents.json`; agent scope is path globs with
56
- no workspace dimension.
57
-
58
- ## Target architecture
59
-
60
- ### 0. Admin role (new prerequisite)
61
-
62
- No admin concept exists today: every signed-in user is equal, and the settings
63
- routes just `requireUser`. Workspace access management is admin-gated, so we
64
- introduce a minimal global admin role.
65
-
66
- New `src/lib/auth/admin.ts`:
67
-
68
- ```ts
69
- isAdmin(userId, email): Promise<boolean>
70
- listAdmins(): Promise<string[]> // user ids
71
- addAdmin(userId): Promise<void>
72
- removeAdmin(userId): Promise<void> // refuse to remove the last admin
73
- requireAdmin(req): Promise<{ ok: true; user } | { ok: false; status; code }>
74
- ```
75
-
76
- Resolution:
77
-
78
- - `adminUserIds: string[]` stored in `config.json`.
79
- - `WIKI_ADMIN_EMAILS` (csv) env: any matching signed-in user is treated as
80
- admin regardless of config (seed/override, headless-friendly).
81
- - **Bootstrap**: if `adminUserIds` is empty AND no `WIKI_ADMIN_EMAILS`, the
82
- first user to sign up is written into `adminUserIds`. Hook the better-auth
83
- signup path, or do it lazily on the first authenticated request when the
84
- admin set is empty (behind the config write mutex). Log once.
85
- - `requireAdmin` returns 403 `ADMIN_REQUIRED` for non-admins.
86
-
87
- Admin management API: `GET/POST/DELETE /api/system/admins` (admin-gated; list
88
- users, promote, demote). `DELETE` refuses to remove the last admin (lockout
89
- guard). A small Admins section in the settings sheet lists users (from the
90
- better-auth `user` table) with promote/demote toggles.
91
-
92
- Non-admin users keep full file access to workspaces they are granted; admin is
93
- only about creating workspaces and editing access lists (and promoting admins).
94
-
95
- ### 1. Workspace registry (replaces single rootDir)
96
-
97
- New `src/lib/workspaces.ts`. Persisted in `~/.wiki-viewer/config.json` under a
98
- new `workspaces` array. Each entry:
99
-
100
- ```ts
101
- interface Workspace {
102
- id: string; // "ws_" + short random; stable, URL-safe
103
- name: string; // display label, defaults to basename(rootDir)
104
- rootDir: string; // absolute, resolved
105
- createdAt: string;
106
- lastOpenedAt?: string;
107
- pinnedPaths?: string[]; // moved here from the flat top-level list
108
- createdBy?: string; // user id of the admin who created it
109
- // access management (organizational, admin-edited only):
110
- allowedUserIds?: string[]; // empty/undefined = any signed-in user
111
- // agent grants live in the agent registry, keyed by workspaceId
112
- }
113
- ```
114
-
115
- API surface (pure functions, no globalThis root):
116
-
117
- ```ts
118
- listWorkspaces(): Promise<Workspace[]>
119
- getWorkspace(id): Promise<Workspace | null>
120
- createWorkspace({ rootDir, name? }): Promise<Workspace>
121
- renameWorkspace(id, name): Promise<void>
122
- removeWorkspace(id): Promise<void> // does NOT touch the directory
123
- setWorkspaceAccess(id, userIds): Promise<void> // admin-only, edits allowedUserIds
124
- userCanAccess(ws, userId): boolean // admins always pass; else allowedUserIds check
125
- resolveWorkspaceRoot(id): Promise<string|null>
126
- safeWorkspacePath(rootDir, rel): string|null // the old safeRootPath logic
127
- ```
128
-
129
- `safeRootPath` logic moves here as `safeWorkspacePath(rootDir, rel)` (takes an
130
- explicit root instead of reading the global). Keep `root-dir.ts` as a thin
131
- deprecated shim during migration if helpful, then delete.
132
-
133
- ### 2. Request-scoped workspace resolution
134
-
135
- New `src/lib/workspace-context.ts`:
136
-
137
- ```ts
138
- // Browser/session routes
139
- async function resolveWorkspaceForUser(
140
- req,
141
- ): Promise<
142
- | { ok: true; ws: Workspace; rootDir: string }
143
- | { ok: false; status: number; code: string }
144
- >;
145
- ```
146
-
147
- Resolution order for browser routes:
148
-
149
- 1. `ws` query param (preferred) or `x-workspace` header.
150
- 2. If absent, fall back to the user's `lastOpenedAt` workspace (back-compat,
151
- single-workspace users never notice).
152
- 3. 400 `WORKSPACE_REQUIRED` if none and more than one workspace exists.
153
-
154
- Then enforce `userCanAccess(ws, user.id)` → 403 `WORKSPACE_FORBIDDEN`.
155
-
156
- For agent routes, `checkAuth` (in `src/lib/proof/auth.ts`) additionally reads
157
- `X-Workspace`, looks up the workspace, and checks the agent's grant for it
158
- (see §5). Returns `{ ok, agent, workspace, rootDir }`.
159
-
160
- ### 3. Namespacing the in-memory stores
161
-
162
- Every store keyed by relPath becomes keyed by `wsId + "\0" + relPath` (the
163
- workspace id is a stable prefix, NUL separator avoids collisions).
164
-
165
- - `lease.ts`: `setLease`, `hasActiveLease`, `clearLease`, `leaseGeneration`
166
- gain a `wsId` first arg → internal key `${wsId}\0${relPath}`.
167
- `computeCollabState(rootDir, relPath)` already has rootDir; add `wsId` (or
168
- derive a key from rootDir — but explicit wsId is cleaner). Update
169
- `collab-state.ts` and `presence/route.ts` callers.
170
- - `mutex.ts` / `file-lock.ts`: callers pass a key already; change every call
171
- site to prefix with `wsId` (e.g. `withFileMutex(`${wsId}\0${relPath}`, ...)`).
172
- Cross-process sentinel hash then differs per workspace automatically.
173
- - `idempotency.ts`: prefix the key with `wsId` at the call site
174
- (`events/[...path]/route.ts`, `files/[...path]/route.ts`).
175
- - `registry.ts` `lastSeenWriteAt` throttle map is keyed by agentId — fine, no
176
- change.
177
-
178
- ### 4. Threading rootDir through routes (29 files)
179
-
180
- Pattern, every session route:
181
-
182
- ```ts
183
- const ctx = await resolveWorkspaceForUser(request);
184
- if (!ctx.ok)
185
- return NextResponse.json({ error: ctx.code }, { status: ctx.status });
186
- const { ws, rootDir } = ctx;
187
- const filePath = safeWorkspacePath(rootDir, rel);
188
- ```
189
-
190
- Replace all `getRootDir()` → `ctx.rootDir`, `safeRootPath(rel)` →
191
- `safeWorkspacePath(rootDir, rel)`, `isRootDirSet()` → existence of ctx.
192
-
193
- Route inventory (all under `src/app/api`):
194
-
195
- - `wiki/route.ts`, `wiki/content/route.ts`, `wiki/page/route.ts`,
196
- `wiki/slugs/route.ts`, `wiki/file/route.ts`, `wiki/new-file/route.ts`,
197
- `wiki/folder/route.ts`, `wiki/move/route.ts`, `wiki/upload/route.ts`,
198
- `wiki/download/route.ts`, `wiki/app/route.ts`, `wiki/watch/route.ts`,
199
- `wiki/presence/route.ts`
200
- - `assets/[...path]/route.ts`, `upload/[...path]/route.ts`
201
- - `system/reveal/route.ts`
202
- - agent: `fs/file`, `fs/ls`, `fs/move`, `fs/search`, `files`, `events`,
203
- `sidecar`, `activity`, `settings`, `internal/span`
204
-
205
- `watch/route.ts` (SSE / chokidar): watcher must watch `ws.rootDir`. Each EventSource
206
- connection is per-workspace; the client opens `/api/wiki/watch?ws=<id>`.
207
-
208
- ### 5. Workspace-scoped agents
209
-
210
- Agent grants gain a workspace dimension. In `registry.ts`:
211
-
212
- ```ts
213
- interface AgentScope {
214
- workspaceId: string; // NEW — the workspace this grant applies to
215
- paths: string[];
216
- ops: Array<"read" | "mutate" | "delete">;
217
- }
218
- ```
219
-
220
- (An agent id may appear once per workspace, or scope becomes an array of
221
- per-workspace grants. Simpler: one registry row per (agentId, workspaceId).
222
- Recommend: keep `Agent.id` unique, add `workspaceId` to the record; an agent
223
- that needs two workspaces registers twice.)
224
-
225
- - `register` route: request body includes target `workspaceId`. Approval UI in
226
- the AI panel shows which workspace the request is for.
227
- - `checkAuth`: resolve `X-Workspace`, then `enforceScope` also checks
228
- `agent.scope.workspaceId === ws.id`. Mismatch → 403.
229
- - Browser session users (`user:<id>`) are synthesized in `checkAuth` with full
230
- scope; gate them with `userCanAccess(ws, userId)` instead.
231
- - `audit.ts`: add `workspace_id` column to `agent_fs_audit`
232
- (`ALTER TABLE ... ADD COLUMN`; tolerate existing DBs). Write it on every row.
233
-
234
- ### 6. Config migration
235
-
236
- On first read of `config.json` with the new code:
237
-
238
- - If `workspaces` is absent but `lastOpenedPath` exists, synthesize one
239
- workspace `{ id: ws_*, rootDir: lastOpenedPath, name: basename, pinnedPaths:
240
- config.pinnedPaths }` and mark it lastOpened. Keep old fields for one release
241
- for rollback safety; new writes use `workspaces`.
242
- - `agents.json`: existing agents have no `workspaceId`. On load, backfill them
243
- to the migrated default workspace id (and log once, mirroring the existing
244
- legacy `ownerUserId` handling in the README checklist).
245
-
246
- ### 7. API: workspace management routes
247
-
248
- New under `src/app/api/system/workspaces`:
249
-
250
- - `GET /api/system/workspaces` — list workspaces visible to the user
251
- (filtered by `userCanAccess`).
252
- - `POST /api/system/workspaces` — create `{ rootDir, name? }` (validates dir
253
- exists, isDirectory). Replaces `set-root` semantics.
254
- - `PATCH /api/system/workspaces/<id>` — rename / pin-unpin allowed for any
255
- user with access; **editing `allowedUserIds` is admin-only** (enforced field
256
- by field in the handler).
257
- - `DELETE /api/system/workspaces/<id>` — **admin-only**. Unregister (directory
258
- untouched).
259
-
260
- Workspace create (`POST`) is **admin-only** and sets `createdBy`. `GET` is open
261
- to any signed-in user but filtered: admins see all, others see only workspaces
262
- they can access. Admins management: `GET/POST/DELETE /api/system/admins`.
263
-
264
- Deprecate / re-point: `set-root`, `clear-root`, `root-status`, `pins`. Keep
265
- thin back-compat shims that operate on "the user's current/last workspace" so
266
- nothing 404s mid-migration, then remove in a follow-up.
267
-
268
- ### 8. Client (browser)
269
-
270
- - `src/app/page.tsx`: hold `activeWorkspaceId` in state. Read from URL `?ws=`
271
- first, else last opened. Put `ws` into every fetch (`/api/wiki?ws=...`,
272
- watch URL, presence body). Cleanest: a small `wsFetch(path, init)` helper /
273
- thin client store (`workspace-store.ts`) that injects `ws` automatically so
274
- we are not editing dozens of `fetch` calls by hand.
275
- - Sidebar footer "Change" → opens a workspace switcher (list of workspaces the
276
- user may access). "Add workspace" (reuses `DirPicker`) is shown **only to
277
- admins**. Switching navigates to `?ws=<id>` (and `path` resets). Two tabs
278
- with different `?ws=` are fully independent.
279
- - `DirPicker` (`src/components/dir-picker.tsx`): admin-only path. "Select" now
280
- POSTs `/api/system/workspaces` (create) instead of `set-root`, then routes
281
- to `?ws=<newId>`. Pins move under the chosen workspace.
282
- - Settings sheet, admins only: an **Admins** section (promote/demote users)
283
- and a per-workspace **Access** editor (`allowedUserIds`). The client reads an
284
- `isAdmin` flag (from `/api/system/admins` or root-status) to gate this UI.
285
- - `wiki-slugs-store`, `editor-store`, `tree-store`: any cached state that is
286
- keyed by path must also be reset on workspace switch (cheap: remount the
287
- page subtree on `ws` change via a React `key={activeWorkspaceId}`).
288
-
289
- ### 9. CLI / startup (`bin/wiki-viewer.js`, `ROOT_DIR`)
290
-
291
- - `ROOT_DIR` (and `wiki-viewer ~/dir`) still works: on boot, if no workspaces
292
- exist, auto-create one from `ROOT_DIR` and mark it default/lastOpened. So the
293
- zero-config single-dir path is unchanged for existing users.
294
- - README "switch the served directory" copy updates to mention multiple
295
- concurrent workspaces.
296
-
297
- ## Isolation guarantees (the "no bleed" contract)
298
-
299
- | Surface | Before | After |
300
- | -------------------- | ----------------- | ------------------------------- |
301
- | Root dir | one global | per request, from `ws` |
302
- | Sidecars / activity | `<root>/.proof/` | unchanged (already per-root) |
303
- | Edit leases | key=relPath | key=`wsId\0relPath` |
304
- | In-proc + file locks | key=relPath | key=`wsId\0relPath` |
305
- | Idempotency LRU | key=idemKey | key=`wsId\0idemKey` |
306
- | Audit DB | path only | `+ workspace_id` column |
307
- | Agents | global path globs | `+ workspaceId` grant, enforced |
308
- | Access control | any signed-in | admin-set `allowedUserIds`/ws |
309
-
310
- Two workspaces sharing the same relative path (`notes.md`) can be edited
311
- simultaneously without lock contention, lease confusion, or idempotency
312
- cross-talk.
313
-
314
- ## Testing
315
-
316
- Extend `src/tests/proof/*`:
317
-
318
- - Two-workspace lease test: lease on `(wsA, x.md)` does not make
319
- `(wsB, x.md)` active.
320
- - Mutex/lock test: concurrent writes to same relPath in two workspaces do not
321
- serialize against each other (or at least do not corrupt).
322
- - Idempotency: same key in two workspaces are independent.
323
- - Scope test: agent granted `wsA` is 403 on `X-Workspace: wsB`.
324
- - Access test: user not in `allowedUserIds` is 403; admin always passes.
325
- - Admin test: non-admin POST /workspaces is 403; last-admin DELETE refused;
326
- first-signup bootstrap promotes one admin.
327
- - Migration test: old config.json (lastOpenedPath + pinnedPaths) yields one
328
- workspace; old agents.json backfills workspaceId.
329
- - Update existing tests: `setRootDir(tmpRoot)` calls in test setup become
330
- "create a workspace + resolve it" (helper).
331
-
332
- ## Rollout / sequencing
333
-
334
- 0. Admin role: `auth/admin.ts`, `/api/system/admins`, bootstrap, settings UI
335
- section. Independent, shippable alone.
336
- 1. `workspaces.ts` + `workspace-context.ts` + config migration (no route
337
- changes yet; default workspace mirrors old behavior).
338
- 2. Namespacing stores (lease, mutex, file-lock, idempotency) with `wsId` arg,
339
- defaulting to the single default workspace so nothing breaks.
340
- 3. Thread `ctx.rootDir` through all 29 routes; delete `getRootDir` global.
341
- 4. Agent workspace scoping + audit column.
342
- 5. Workspace management API + client switcher + DirPicker repoint.
343
- 6. Tests, README, CLI copy.
344
-
345
- Steps 1-2 are non-breaking and shippable alone. Step 3 is the big mechanical
346
- diff (good candidate for a `worker` pass with explicit outcomes per route).
347
-
348
- ## Open questions / risks
349
-
350
- - **`pnpm-workspace.yaml` naming clash**: this repo is itself a pnpm workspace.
351
- Use "workspace" in UI/API, but consider an internal code name like `space` or
352
- keep `workspace` and just be careful in docs. Low risk, naming only.
353
- - **SSE watcher fan-out**: one chokidar watcher per (connection, workspace).
354
- Many open tabs on the same workspace = many watchers. Acceptable now;
355
- optimize later with a shared per-workspace watcher + ref count if needed.
356
- - **Admin bootstrap timing**: writing the first user into `adminUserIds` must
357
- happen exactly once. Better-auth has no built-in "first user" hook, so
358
- either tap the signup callback or do it lazily on the first authenticated
359
- request when the admin set is empty (race-safe behind the config write
360
- mutex). Decide during step 0.
361
- - **`allowedUserIds` default**: empty = any signed-in user (matches today's
362
- behavior). Admins tighten per workspace via the Access editor.
363
- - Removing a workspace leaves `.proof/` and `.locks/` sentinels on disk; fine
364
- (directory untouched by design), but document it.