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,501 +0,0 @@
1
- /**
2
- * Phase 3 tests — collab-state computation, lease store, X-Collab-* headers,
3
- * and R6 TOCTOU enforcement on raw .md PUT.
4
- */
5
- import { test, before, after, describe } from "node:test";
6
- import assert from "node:assert/strict";
7
- import {
8
- mkdtemp, rm, writeFile, mkdir,
9
- } from "node:fs/promises";
10
- import { tmpdir } from "node:os";
11
- import path from "node:path";
12
- import { createHash, randomBytes } from "node:crypto";
13
-
14
- import { setRootDir } from "../../lib/root-dir.js";
15
- import { ensureRegistry, addAgent, hashToken } from "../../lib/proof/registry.js";
16
- import { writeSidecar, emptySidecar } from "../../lib/proof/sidecar.js";
17
- import { setLease, clearLease, leaseGeneration, hasActiveLease, _resetLeaseStore, LEASE_TTL_MS } from "../../lib/proof/lease.js";
18
- import { computeCollabState } from "../../lib/proof/collab-state.js";
19
- import { _resetAuditDb } from "../../lib/proof/audit.js";
20
- import type { Sidecar, Suggestion, Comment } from "../../lib/proof/types.js";
21
-
22
- // ── Route handlers ────────────────────────────────────────────────────────────
23
- let fileGET: (req: Request, ctx: { params: Promise<{ path: string[] }> }) => Promise<Response>;
24
- let filePUT: (req: Request, ctx: { params: Promise<{ path: string[] }> }) => Promise<Response>;
25
- let tier2GET: (req: Request, ctx: { params: Promise<{ path: string[] }> }) => Promise<Response>;
26
-
27
- let tmpHome: string;
28
- let tmpRoot: string;
29
- let MUTATE_TOKEN: string;
30
- let READ_TOKEN: string;
31
-
32
- function sha256hex(buf: Buffer | string): string {
33
- const b = typeof buf === "string" ? Buffer.from(buf) : buf;
34
- return "sha256:" + createHash("sha256").update(b).digest("hex");
35
- }
36
-
37
- function agentHeaders(token: string, id: string, extra: Record<string, string> = {}): Record<string, string> {
38
- return { Authorization: `Bearer ${token}`, "X-Agent-Id": id, ...extra };
39
- }
40
-
41
- function makeCtx(segments: string[]): { params: Promise<{ path: string[] }> } {
42
- return { params: Promise.resolve({ path: segments }) };
43
- }
44
-
45
- function fileUrl(rel: string, qs = ""): string {
46
- return `http://localhost/api/agent/fs/file/${rel}${qs}`;
47
- }
48
-
49
- function tier2Url(rel: string): string {
50
- return `http://localhost/api/agent/files/${rel}`;
51
- }
52
-
53
- before(async () => {
54
- tmpHome = await mkdtemp(path.join(tmpdir(), "collab-state-home-"));
55
- tmpRoot = await mkdtemp(path.join(tmpdir(), "collab-state-root-"));
56
-
57
- process.env.HOME = tmpHome;
58
- setRootDir(tmpRoot);
59
- _resetAuditDb();
60
- _resetLeaseStore();
61
-
62
- await ensureRegistry();
63
-
64
- MUTATE_TOKEN = randomBytes(32).toString("hex");
65
- READ_TOKEN = randomBytes(32).toString("hex");
66
-
67
- await addAgent({
68
- id: "ai:mutate",
69
- displayName: "Mutate",
70
- tokenHash: hashToken(MUTATE_TOKEN),
71
- scope: { paths: ["**/*"], ops: ["read", "mutate", "delete"] },
72
- createdAt: new Date().toISOString(),
73
- lastSeen: new Date().toISOString(),
74
- });
75
-
76
- await addAgent({
77
- id: "ai:reader",
78
- displayName: "Reader",
79
- tokenHash: hashToken(READ_TOKEN),
80
- scope: { paths: ["**/*"], ops: ["read"] },
81
- createdAt: new Date().toISOString(),
82
- lastSeen: new Date().toISOString(),
83
- });
84
-
85
- const fileRoute = await import("../../app/api/agent/fs/file/[...path]/route.js");
86
- fileGET = fileRoute.GET;
87
- filePUT = fileRoute.PUT;
88
-
89
- const tier2Route = await import("../../app/api/agent/files/[...path]/route.js");
90
- tier2GET = tier2Route.GET;
91
- });
92
-
93
- after(async () => {
94
- _resetLeaseStore();
95
- await rm(tmpHome, { recursive: true, force: true });
96
- await rm(tmpRoot, { recursive: true, force: true });
97
- });
98
-
99
- // ── Lease store unit tests ────────────────────────────────────────────────────
100
-
101
- const TEST_NS = "/test-ns";
102
-
103
- describe("lease store", () => {
104
- before(() => _resetLeaseStore());
105
- after(() => _resetLeaseStore());
106
-
107
- test("new path has generation 0, no active lease", () => {
108
- _resetLeaseStore();
109
- assert.equal(leaseGeneration(TEST_NS, "docs/a.md"), 0);
110
- assert.equal(hasActiveLease(TEST_NS, "docs/a.md"), false);
111
- });
112
-
113
- test("setLease makes lease active, bumps generation 0→1", () => {
114
- _resetLeaseStore();
115
- setLease(TEST_NS, "docs/a.md", "u1");
116
- assert.equal(hasActiveLease(TEST_NS, "docs/a.md"), true);
117
- assert.equal(leaseGeneration(TEST_NS, "docs/a.md"), 1);
118
- });
119
-
120
- test("second setLease (heartbeat) does NOT bump generation again", () => {
121
- _resetLeaseStore();
122
- setLease(TEST_NS, "docs/a.md", "u1");
123
- const gen = leaseGeneration(TEST_NS, "docs/a.md");
124
- setLease(TEST_NS, "docs/a.md", "u1"); // heartbeat
125
- assert.equal(leaseGeneration(TEST_NS, "docs/a.md"), gen); // unchanged
126
- });
127
-
128
- test("clearLease removes active lease and bumps generation 1→2", () => {
129
- _resetLeaseStore();
130
- setLease(TEST_NS, "docs/a.md", "u1");
131
- assert.equal(leaseGeneration(TEST_NS, "docs/a.md"), 1);
132
- clearLease(TEST_NS, "docs/a.md", "u1");
133
- assert.equal(hasActiveLease(TEST_NS, "docs/a.md"), false);
134
- assert.equal(leaseGeneration(TEST_NS, "docs/a.md"), 2);
135
- });
136
-
137
- test("clearLease by different user is no-op", () => {
138
- _resetLeaseStore();
139
- setLease(TEST_NS, "docs/a.md", "u1");
140
- clearLease(TEST_NS, "docs/a.md", "u-other");
141
- assert.equal(hasActiveLease(TEST_NS, "docs/a.md"), true);
142
- assert.equal(leaseGeneration(TEST_NS, "docs/a.md"), 1);
143
- });
144
-
145
- test("expired lease (via short TTL) returns false and bumps generation", async () => {
146
- _resetLeaseStore();
147
- setLease(TEST_NS, "docs/expire.md", "u1", 10); // 10ms TTL
148
- assert.equal(hasActiveLease(TEST_NS, "docs/expire.md"), true);
149
- await new Promise((r) => setTimeout(r, 20));
150
- assert.equal(hasActiveLease(TEST_NS, "docs/expire.md"), false);
151
- // generation bumped on expiry check
152
- assert.ok(leaseGeneration(TEST_NS, "docs/expire.md") >= 2);
153
- });
154
-
155
- test("set after expiry = new 0→1 transition, bumps again", async () => {
156
- _resetLeaseStore();
157
- setLease(TEST_NS, "docs/exp2.md", "u1", 10);
158
- await new Promise((r) => setTimeout(r, 20));
159
- hasActiveLease(TEST_NS, "docs/exp2.md"); // triggers sweep
160
- const genAfterExpiry = leaseGeneration(TEST_NS, "docs/exp2.md");
161
- setLease(TEST_NS, "docs/exp2.md", "u1"); // fresh open
162
- assert.equal(leaseGeneration(TEST_NS, "docs/exp2.md"), genAfterExpiry + 1);
163
- });
164
- });
165
-
166
- // ── computeCollabState matrix ─────────────────────────────────────────────────
167
-
168
- describe("computeCollabState", () => {
169
- before(() => _resetLeaseStore());
170
- after(() => _resetLeaseStore());
171
-
172
- test("not-markdown: txt file", async () => {
173
- const result = await computeCollabState(tmpRoot, "file.txt");
174
- assert.equal(result.state, "not-markdown");
175
- assert.equal(result.revision, 0);
176
- assert.equal(result.snapshotUrl, null);
177
- });
178
-
179
- test("not-markdown: ts file", async () => {
180
- const result = await computeCollabState(tmpRoot, "src/app.ts");
181
- assert.equal(result.state, "not-markdown");
182
- });
183
-
184
- test("untracked: .md, no sidecar, no lease", async () => {
185
- _resetLeaseStore();
186
- await writeFile(path.join(tmpRoot, "untracked.md"), "# hello");
187
- const result = await computeCollabState(tmpRoot, "untracked.md");
188
- assert.equal(result.state, "untracked");
189
- assert.equal(result.snapshotUrl, "/api/agent/files/untracked.md");
190
- });
191
-
192
- test("tracked: .md with sidecar, no artifacts, no lease", async () => {
193
- _resetLeaseStore();
194
- const mdPath = "tracked.md";
195
- await writeFile(path.join(tmpRoot, mdPath), "# tracked");
196
- const sc: Sidecar = {
197
- ...emptySidecar(mdPath),
198
- revision: 3,
199
- suggestions: [],
200
- comments: [],
201
- blockProvenance: {},
202
- };
203
- await writeSidecar(tmpRoot, mdPath, sc);
204
- const result = await computeCollabState(tmpRoot, mdPath);
205
- assert.equal(result.state, "tracked");
206
- assert.equal(result.revision, 3); // sidecar.revision + leaseGen(0)
207
- });
208
-
209
- test("active: .md with pending suggestion", async () => {
210
- _resetLeaseStore();
211
- const mdPath = "active-suggestion.md";
212
- await writeFile(path.join(tmpRoot, mdPath), "# active");
213
- const sc: Sidecar = {
214
- ...emptySidecar(mdPath),
215
- revision: 5,
216
- suggestions: [
217
- {
218
- id: "s0001", ref: "b000001", kind: "replace", status: "pending",
219
- by: "ai:test", createdAt: new Date().toISOString(),
220
- } as Suggestion,
221
- ],
222
- comments: [],
223
- blockProvenance: {},
224
- };
225
- await writeSidecar(tmpRoot, mdPath, sc);
226
- const result = await computeCollabState(tmpRoot, mdPath);
227
- assert.equal(result.state, "active");
228
- assert.equal(result.revision, 5);
229
- });
230
-
231
- test("active: .md with unresolved comment", async () => {
232
- _resetLeaseStore();
233
- const mdPath = "active-comment.md";
234
- await writeFile(path.join(tmpRoot, mdPath), "# active");
235
- const sc: Sidecar = {
236
- ...emptySidecar(mdPath),
237
- revision: 2,
238
- suggestions: [],
239
- comments: [
240
- {
241
- id: "c0001", ref: "b000002", resolved: false,
242
- createdAt: new Date().toISOString(), turns: [],
243
- } as Comment,
244
- ],
245
- blockProvenance: {},
246
- };
247
- await writeSidecar(tmpRoot, mdPath, sc);
248
- const result = await computeCollabState(tmpRoot, mdPath);
249
- assert.equal(result.state, "active");
250
- });
251
-
252
- test("active: .md via lease only (no sidecar)", async () => {
253
- _resetLeaseStore();
254
- const mdPath = "lease-only.md";
255
- await writeFile(path.join(tmpRoot, mdPath), "# lease only");
256
- // No sidecar; human opens it
257
- setLease(tmpRoot, mdPath, "human-user-1");
258
- const result = await computeCollabState(tmpRoot, mdPath);
259
- assert.equal(result.state, "active");
260
- assert.equal(result.revision, 1); // 0 + gen(1)
261
- clearLease(tmpRoot, mdPath, "human-user-1");
262
- });
263
-
264
- test("revision = sidecar.revision + leaseGeneration", async () => {
265
- _resetLeaseStore();
266
- const mdPath = "revision-test.md";
267
- await writeFile(path.join(tmpRoot, mdPath), "# rev");
268
- const sc: Sidecar = { ...emptySidecar(mdPath), revision: 7 };
269
- await writeSidecar(tmpRoot, mdPath, sc);
270
- // no lease: gen=0, revision=7
271
- const r1 = await computeCollabState(tmpRoot, mdPath);
272
- assert.equal(r1.revision, 7);
273
- // open lease: gen=1, revision=8
274
- setLease(tmpRoot, mdPath, "u1");
275
- const r2 = await computeCollabState(tmpRoot, mdPath);
276
- assert.equal(r2.revision, 8);
277
- clearLease(tmpRoot, mdPath, "u1");
278
- });
279
-
280
- test("stale pending suggestion does NOT count as active artifact", async () => {
281
- _resetLeaseStore();
282
- const mdPath = "stale-sug.md";
283
- await writeFile(path.join(tmpRoot, mdPath), "# stale");
284
- const sc: Sidecar = {
285
- ...emptySidecar(mdPath),
286
- revision: 1,
287
- suggestions: [
288
- {
289
- id: "s0002", ref: "b000003", kind: "replace", status: "pending",
290
- by: "ai:test", createdAt: new Date().toISOString(),
291
- stale: true,
292
- } as Suggestion,
293
- ],
294
- comments: [],
295
- blockProvenance: {},
296
- };
297
- await writeSidecar(tmpRoot, mdPath, sc);
298
- const result = await computeCollabState(tmpRoot, mdPath);
299
- assert.equal(result.state, "tracked"); // stale suggestion = no artifact
300
- });
301
- });
302
-
303
- // ── X-Collab-* headers on GET (fs/file) ──────────────────────────────────────
304
-
305
- describe("X-Collab headers on GET fs/file", () => {
306
- before(() => _resetLeaseStore());
307
- after(() => _resetLeaseStore());
308
-
309
- test("non-markdown returns X-Collab-State: not-markdown, no snapshot header", async () => {
310
- await writeFile(path.join(tmpRoot, "code.ts"), "export const x = 1;");
311
- const req = new Request(fileUrl("code.ts"), {
312
- headers: agentHeaders(READ_TOKEN, "ai:reader"),
313
- });
314
- const res = await fileGET(req, makeCtx(["code.ts"]));
315
- assert.equal(res.status, 200);
316
- assert.equal(res.headers.get("x-collab-state"), "not-markdown");
317
- assert.equal(res.headers.get("x-collab-snapshot"), null);
318
- });
319
-
320
- test("untracked .md returns X-Collab-State: untracked + snapshot URL", async () => {
321
- _resetLeaseStore();
322
- await writeFile(path.join(tmpRoot, "hdr-untracked.md"), "# hello");
323
- const req = new Request(fileUrl("hdr-untracked.md"), {
324
- headers: agentHeaders(READ_TOKEN, "ai:reader"),
325
- });
326
- const res = await fileGET(req, makeCtx(["hdr-untracked.md"]));
327
- assert.equal(res.status, 200);
328
- assert.equal(res.headers.get("x-collab-state"), "untracked");
329
- assert.ok(res.headers.get("x-collab-snapshot")?.includes("hdr-untracked.md"));
330
- assert.ok(res.headers.get("x-collab-revision") !== null);
331
- });
332
-
333
- test("active lease makes X-Collab-State: active on GET", async () => {
334
- _resetLeaseStore();
335
- const mdPath = "hdr-active.md";
336
- await writeFile(path.join(tmpRoot, mdPath), "# active");
337
- setLease(tmpRoot, mdPath, "human-1");
338
- const req = new Request(fileUrl(mdPath), {
339
- headers: agentHeaders(READ_TOKEN, "ai:reader"),
340
- });
341
- const res = await fileGET(req, makeCtx([mdPath]));
342
- assert.equal(res.status, 200);
343
- assert.equal(res.headers.get("x-collab-state"), "active");
344
- clearLease(tmpRoot, mdPath, "human-1");
345
- });
346
- });
347
-
348
- // ── X-Collab-* headers on GET agent/files (Tier-2) ────────────────────────────
349
-
350
- describe("X-Collab headers on Tier-2 GET agent/files", () => {
351
- before(() => _resetLeaseStore());
352
- after(() => _resetLeaseStore());
353
-
354
- test("Tier-2 GET returns X-Collab-State + revision headers", async () => {
355
- _resetLeaseStore();
356
- const mdPath = "tier2-hdr.md";
357
- await writeFile(path.join(tmpRoot, mdPath), "# tier2");
358
- const req = new Request(tier2Url(mdPath), {
359
- headers: agentHeaders(READ_TOKEN, "ai:reader"),
360
- });
361
- const res = await tier2GET(req, makeCtx([mdPath]));
362
- assert.equal(res.status, 200);
363
- assert.ok(res.headers.get("x-collab-state") !== null, "X-Collab-State present");
364
- assert.ok(res.headers.get("x-collab-revision") !== null, "X-Collab-Revision present");
365
- assert.ok(res.headers.get("x-collab-snapshot") !== null, "X-Collab-Snapshot present");
366
- });
367
-
368
- test("Tier-2 GET returns active when lease set", async () => {
369
- _resetLeaseStore();
370
- const mdPath = "tier2-active.md";
371
- await writeFile(path.join(tmpRoot, mdPath), "# active");
372
- setLease(tmpRoot, mdPath, "h1");
373
- const req = new Request(tier2Url(mdPath), {
374
- headers: agentHeaders(READ_TOKEN, "ai:reader"),
375
- });
376
- const res = await tier2GET(req, makeCtx([mdPath]));
377
- assert.equal(res.headers.get("x-collab-state"), "active");
378
- clearLease(tmpRoot, mdPath, "h1");
379
- });
380
- });
381
-
382
- // ── R6 TOCTOU enforcement ─────────────────────────────────────────────────────
383
-
384
- describe("R6 TOCTOU enforcement on raw .md PUT", () => {
385
- before(() => _resetLeaseStore());
386
- after(() => _resetLeaseStore());
387
-
388
- test("PUT .md with no lease (untracked) → 200 no If-Collab-Match needed", async () => {
389
- _resetLeaseStore();
390
- const mdPath = "r6-untracked.md";
391
- await writeFile(path.join(tmpRoot, mdPath), "# hello");
392
- const content = Buffer.from("# hello updated");
393
- const oldSha = sha256hex(Buffer.from("# hello"));
394
- const req = new Request(fileUrl(mdPath), {
395
- method: "PUT",
396
- headers: agentHeaders(MUTATE_TOKEN, "ai:mutate", {
397
- "If-Match": oldSha,
398
- "Content-Type": "text/markdown",
399
- }),
400
- body: content,
401
- });
402
- const res = await filePUT(req, makeCtx([mdPath]));
403
- assert.equal(res.status, 200, "untracked md PUT should succeed");
404
- });
405
-
406
- test("PUT .md: doc goes active (lease set) between read and write → 409 COLLAB_ACTIVE", async () => {
407
- _resetLeaseStore();
408
- const mdPath = "r6-race.md";
409
- const initial = "# race test";
410
- await writeFile(path.join(tmpRoot, mdPath), initial);
411
- const oldSha = sha256hex(Buffer.from(initial));
412
-
413
- // Simulate: agent read the file, then human opens it (lease set)
414
- setLease(tmpRoot, mdPath, "human-racer");
415
-
416
- // Agent tries raw PUT without If-Collab-Match
417
- const req = new Request(fileUrl(mdPath), {
418
- method: "PUT",
419
- headers: agentHeaders(MUTATE_TOKEN, "ai:mutate", {
420
- "If-Match": oldSha,
421
- "Content-Type": "text/markdown",
422
- }),
423
- body: Buffer.from("# overwritten"),
424
- });
425
- const res = await filePUT(req, makeCtx([mdPath]));
426
- assert.equal(res.status, 409, "should 409 when doc went active mid-flight");
427
- const body = await res.json() as { error: string; snapshotUrl: string; revision: number };
428
- assert.equal(body.error, "COLLAB_ACTIVE");
429
- assert.ok(body.snapshotUrl, "snapshotUrl in response");
430
- assert.ok(typeof body.revision === "number", "revision in response");
431
-
432
- clearLease(tmpRoot, mdPath, "human-racer");
433
- });
434
-
435
- test("PUT .md with matching If-Collab-Match → 200", async () => {
436
- _resetLeaseStore();
437
- const mdPath = "r6-match.md";
438
- const initial = "# match test";
439
- await writeFile(path.join(tmpRoot, mdPath), initial);
440
- const oldSha = sha256hex(Buffer.from(initial));
441
-
442
- setLease(tmpRoot, mdPath, "human-match");
443
- // Get the current revision
444
- const { revision } = await computeCollabState(tmpRoot, mdPath);
445
-
446
- const req = new Request(fileUrl(mdPath), {
447
- method: "PUT",
448
- headers: agentHeaders(MUTATE_TOKEN, "ai:mutate", {
449
- "If-Match": oldSha,
450
- "If-Collab-Match": String(revision),
451
- "Content-Type": "text/markdown",
452
- }),
453
- body: Buffer.from("# matched and written"),
454
- });
455
- const res = await filePUT(req, makeCtx([mdPath]));
456
- assert.equal(res.status, 200, "matching If-Collab-Match should allow write");
457
-
458
- clearLease(tmpRoot, mdPath, "human-match");
459
- });
460
-
461
- test("PUT .md with ?force=true bypasses R6 even on active doc → 200", async () => {
462
- _resetLeaseStore();
463
- const mdPath = "r6-force.md";
464
- const initial = "# force test";
465
- await writeFile(path.join(tmpRoot, mdPath), initial);
466
- const oldSha = sha256hex(Buffer.from(initial));
467
-
468
- setLease(tmpRoot, mdPath, "human-force");
469
-
470
- const req = new Request(fileUrl(mdPath, "?force=true"), {
471
- method: "PUT",
472
- headers: agentHeaders(MUTATE_TOKEN, "ai:mutate", {
473
- "If-Match": oldSha,
474
- "Content-Type": "text/markdown",
475
- }),
476
- body: Buffer.from("# forced overwrite"),
477
- });
478
- const res = await filePUT(req, makeCtx([mdPath]));
479
- assert.equal(res.status, 200, "?force=true should bypass R6");
480
-
481
- clearLease(tmpRoot, mdPath, "human-force");
482
- });
483
-
484
- test("PUT non-.md file is never blocked by R6 (no collab state)", async () => {
485
- _resetLeaseStore();
486
- const tsPath = "r6-noblock.ts";
487
- await writeFile(path.join(tmpRoot, tsPath), "const x = 1;");
488
- const oldSha = sha256hex(Buffer.from("const x = 1;"));
489
-
490
- const req = new Request(fileUrl(tsPath), {
491
- method: "PUT",
492
- headers: agentHeaders(MUTATE_TOKEN, "ai:mutate", {
493
- "If-Match": oldSha,
494
- "Content-Type": "text/plain",
495
- }),
496
- body: Buffer.from("const x = 2;"),
497
- });
498
- const res = await filePUT(req, makeCtx([tsPath]));
499
- assert.equal(res.status, 200, "non-md should never hit R6");
500
- });
501
- });
@@ -1,177 +0,0 @@
1
- import { test, before, after } from "node:test";
2
- import assert from "node:assert/strict";
3
- import { mkdtemp, writeFile, rm } from "node:fs/promises";
4
- import { tmpdir } from "node:os";
5
- import path from "node:path";
6
- import { applyOps, readSnapshot } from "../../lib/proof/ops-applier.js";
7
- import { setRootDir } from "../../lib/root-dir.js";
8
-
9
- let tmpRoot: string;
10
-
11
- before(async () => {
12
- tmpRoot = await mkdtemp(path.join(tmpdir(), "wiki-comment-test-"));
13
- setRootDir(tmpRoot);
14
- });
15
-
16
- after(async () => {
17
- await rm(tmpRoot, { recursive: true, force: true });
18
- });
19
-
20
- async function writeDoc(name: string, content: string): Promise<void> {
21
- await writeFile(path.join(tmpRoot, name), content, "utf-8");
22
- }
23
-
24
- test("comment.add — sidecar has comment with one turn", async () => {
25
- await writeDoc("cadd.md", "# Title\n\nA paragraph.\n");
26
- const snap = await readSnapshot(tmpRoot, "cadd.md");
27
- assert.ok(snap !== null);
28
- const paraRef = snap!.blocks[1].ref;
29
-
30
- const result = await applyOps({
31
- rootDir: tmpRoot,
32
- mdPath: "cadd.md",
33
- baseRevision: 0,
34
- by: "human",
35
- ops: [{ type: "comment.add", ref: paraRef, text: "First comment." }],
36
- });
37
-
38
- assert.ok(result.ok, `expected ok: ${JSON.stringify(result)}`);
39
- assert.equal(result.ok ? result.snapshot.comments.length : -1, 1);
40
- const c = result.ok ? result.snapshot.comments[0] : null;
41
- assert.ok(c !== null);
42
- assert.equal(c!.resolved, false);
43
- assert.equal(c!.ref, paraRef);
44
- assert.equal(c!.turns.length, 1);
45
- assert.equal(c!.turns[0].text, "First comment.");
46
- assert.equal(c!.turns[0].by, "human");
47
- });
48
-
49
- test("comment.reply — existing comment gains second turn", async () => {
50
- await writeDoc("creply.md", "# Title\n\nParagraph.\n");
51
- const snap = await readSnapshot(tmpRoot, "creply.md");
52
- const paraRef = snap!.blocks[1].ref;
53
-
54
- const addResult = await applyOps({
55
- rootDir: tmpRoot,
56
- mdPath: "creply.md",
57
- baseRevision: 0,
58
- by: "human",
59
- ops: [{ type: "comment.add", ref: paraRef, text: "Why?" }],
60
- });
61
- assert.ok(addResult.ok);
62
- const commentId = addResult.ok ? addResult.snapshot.comments[0]?.id : null;
63
- assert.ok(commentId);
64
-
65
- const replyResult = await applyOps({
66
- rootDir: tmpRoot,
67
- mdPath: "creply.md",
68
- baseRevision: 1,
69
- by: "ai:claude",
70
- ops: [{ type: "comment.reply", commentId: commentId!, text: "Because reasons." }],
71
- });
72
- assert.ok(replyResult.ok, `expected ok: ${JSON.stringify(replyResult)}`);
73
- const c = replyResult.ok
74
- ? replyResult.snapshot.comments.find((x) => x.id === commentId)
75
- : null;
76
- assert.ok(c, "comment should be in snapshot");
77
- assert.equal(c!.turns.length, 2);
78
- assert.equal(c!.turns[1].text, "Because reasons.");
79
- assert.equal(c!.turns[1].by, "ai:claude");
80
- });
81
-
82
- test("comment.resolve — resolved=true + event emitted", async () => {
83
- await writeDoc("cresolve.md", "# Title\n\nParagraph.\n");
84
- const snap = await readSnapshot(tmpRoot, "cresolve.md");
85
- const paraRef = snap!.blocks[1].ref;
86
-
87
- const addResult = await applyOps({
88
- rootDir: tmpRoot,
89
- mdPath: "cresolve.md",
90
- baseRevision: 0,
91
- by: "human",
92
- ops: [{ type: "comment.add", ref: paraRef, text: "Open thread." }],
93
- });
94
- assert.ok(addResult.ok);
95
- const commentId = addResult.ok ? addResult.snapshot.comments[0]?.id : null;
96
- assert.ok(commentId);
97
-
98
- const resolveResult = await applyOps({
99
- rootDir: tmpRoot,
100
- mdPath: "cresolve.md",
101
- baseRevision: 1,
102
- by: "human",
103
- ops: [{ type: "comment.resolve", commentId: commentId! }],
104
- });
105
- assert.ok(resolveResult.ok, `expected ok: ${JSON.stringify(resolveResult)}`);
106
- const c = resolveResult.ok
107
- ? resolveResult.snapshot.comments.find((x) => x.id === commentId)
108
- : null;
109
- assert.ok(c, "comment still present in snapshot");
110
- assert.equal(c!.resolved, true);
111
- // event emitted
112
- const evt = resolveResult.ok
113
- ? resolveResult.emittedEvents.find((e) => e.type === "comment.resolved")
114
- : null;
115
- assert.ok(evt, "comment.resolved event should be emitted");
116
- assert.equal((evt as unknown as { commentId: string } | null)?.commentId, commentId);
117
- });
118
-
119
- test("comment.reopen — resolved=false + event emitted", async () => {
120
- await writeDoc("creopen.md", "# Title\n\nParagraph.\n");
121
- const snap = await readSnapshot(tmpRoot, "creopen.md");
122
- const paraRef = snap!.blocks[1].ref;
123
-
124
- // add then resolve
125
- const addResult = await applyOps({
126
- rootDir: tmpRoot,
127
- mdPath: "creopen.md",
128
- baseRevision: 0,
129
- by: "human",
130
- ops: [{ type: "comment.add", ref: paraRef, text: "Thread." }],
131
- });
132
- assert.ok(addResult.ok);
133
- const commentId = addResult.ok ? addResult.snapshot.comments[0]?.id : null;
134
- assert.ok(commentId);
135
-
136
- const resolveResult = await applyOps({
137
- rootDir: tmpRoot,
138
- mdPath: "creopen.md",
139
- baseRevision: 1,
140
- by: "human",
141
- ops: [{ type: "comment.resolve", commentId: commentId! }],
142
- });
143
- assert.ok(resolveResult.ok);
144
-
145
- const reopenResult = await applyOps({
146
- rootDir: tmpRoot,
147
- mdPath: "creopen.md",
148
- baseRevision: 2,
149
- by: "human",
150
- ops: [{ type: "comment.reopen", commentId: commentId! }],
151
- });
152
- assert.ok(reopenResult.ok, `expected ok: ${JSON.stringify(reopenResult)}`);
153
- const c = reopenResult.ok
154
- ? reopenResult.snapshot.comments.find((x) => x.id === commentId)
155
- : null;
156
- assert.ok(c);
157
- assert.equal(c!.resolved, false);
158
- // event emitted
159
- const evt = reopenResult.ok
160
- ? reopenResult.emittedEvents.find((e) => e.type === "comment.reopened")
161
- : null;
162
- assert.ok(evt, "comment.reopened event should be emitted");
163
- });
164
-
165
- test("comment.reply to nonexistent commentId → 409 COMMENT_NOT_FOUND", async () => {
166
- await writeDoc("cnotfound.md", "# Title\n\nParagraph.\n");
167
- const result = await applyOps({
168
- rootDir: tmpRoot,
169
- mdPath: "cnotfound.md",
170
- baseRevision: 0,
171
- by: "human",
172
- ops: [{ type: "comment.reply", commentId: "cdeadbeef", text: "Ghost reply." }],
173
- });
174
- assert.ok(!result.ok);
175
- assert.equal(result.ok ? "" : result.code, "COMMENT_NOT_FOUND");
176
- assert.equal(result.ok ? 0 : result.status, 409);
177
- });