wiki-viewer 1.7.2 → 1.8.1

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 (424) hide show
  1. package/.next/standalone/.github/workflows/publish.yml +1 -1
  2. package/.next/standalone/.next/BUILD_ID +1 -1
  3. package/.next/standalone/.next/app-path-routes-manifest.json +6 -0
  4. package/.next/standalone/.next/build-manifest.json +3 -3
  5. package/.next/standalone/.next/prerender-manifest.json +3 -3
  6. package/.next/standalone/.next/routes-manifest.json +40 -0
  7. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  11. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  12. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  15. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  16. package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
  17. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  18. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  19. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  20. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  21. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  22. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  23. package/.next/standalone/.next/server/app/api/agent/activity/route.js +6 -6
  24. package/.next/standalone/.next/server/app/api/agent/activity/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/agent/admin/agents/[agentId]/revoke/route.js +6 -6
  26. package/.next/standalone/.next/server/app/api/agent/admin/agents/[agentId]/revoke/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/agent/admin/agents/route.js +6 -6
  28. package/.next/standalone/.next/server/app/api/agent/admin/agents/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/agent/admin/registrations/[regId]/approve/route.js +7 -7
  30. package/.next/standalone/.next/server/app/api/agent/admin/registrations/[regId]/approve/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/agent/admin/registrations/[regId]/deny/route.js +5 -5
  32. package/.next/standalone/.next/server/app/api/agent/admin/registrations/[regId]/deny/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/api/agent/admin/registrations/route.js +5 -5
  34. package/.next/standalone/.next/server/app/api/agent/admin/registrations/route.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/api/agent/events/[...path]/route.js +8 -7
  36. package/.next/standalone/.next/server/app/api/agent/events/[...path]/route.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/api/agent/files/[...path]/route.js +9 -8
  38. package/.next/standalone/.next/server/app/api/agent/files/[...path]/route.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js +8 -7
  40. package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js.nft.json +1 -1
  41. package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route.js +7 -7
  42. package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route.js.nft.json +1 -1
  43. package/.next/standalone/.next/server/app/api/agent/fs/move/route.js +6 -5
  44. package/.next/standalone/.next/server/app/api/agent/fs/move/route.js.nft.json +1 -1
  45. package/.next/standalone/.next/server/app/api/agent/fs/search/route.js +7 -6
  46. package/.next/standalone/.next/server/app/api/agent/fs/search/route.js.nft.json +1 -1
  47. package/.next/standalone/.next/server/app/api/agent/internal/span/route.js +6 -5
  48. package/.next/standalone/.next/server/app/api/agent/internal/span/route.js.nft.json +1 -1
  49. package/.next/standalone/.next/server/app/api/agent/settings/route.js +7 -7
  50. package/.next/standalone/.next/server/app/api/agent/settings/route.js.nft.json +1 -1
  51. package/.next/standalone/.next/server/app/api/agent/sidecar/[...path]/route.js +8 -7
  52. package/.next/standalone/.next/server/app/api/agent/sidecar/[...path]/route.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/api/app-proxy/[...path]/route.js +2 -2
  54. package/.next/standalone/.next/server/app/api/app-proxy/[...path]/route.js.nft.json +1 -1
  55. package/.next/standalone/.next/server/app/api/assets/[...path]/route.js +8 -2
  56. package/.next/standalone/.next/server/app/api/assets/[...path]/route.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/api/auth/[...all]/route.js +5 -5
  58. package/.next/standalone/.next/server/app/api/auth/[...all]/route.js.nft.json +1 -1
  59. package/.next/standalone/.next/server/app/api/system/admins/route/app-paths-manifest.json +3 -0
  60. package/.next/standalone/.next/server/app/api/system/admins/route/build-manifest.json +9 -0
  61. package/.next/standalone/.next/server/app/api/system/admins/route/server-reference-manifest.json +4 -0
  62. package/.next/standalone/.next/server/app/api/system/admins/route.js +14 -0
  63. package/.next/standalone/.next/server/app/api/system/admins/route.js.map +5 -0
  64. package/.next/standalone/.next/server/app/api/system/admins/route.js.nft.json +1 -0
  65. package/.next/standalone/.next/server/app/api/system/admins/route_client-reference-manifest.js +3 -0
  66. package/.next/standalone/.next/server/app/api/system/auth-config/route.js +6 -6
  67. package/.next/standalone/.next/server/app/api/system/auth-config/route.js.nft.json +1 -1
  68. package/.next/standalone/.next/server/app/api/system/auth-settings/route.js +4 -4
  69. package/.next/standalone/.next/server/app/api/system/auth-settings/route.js.nft.json +1 -1
  70. package/.next/standalone/.next/server/app/api/system/browse/route.js +4 -4
  71. package/.next/standalone/.next/server/app/api/system/browse/route.js.nft.json +1 -1
  72. package/.next/standalone/.next/server/app/api/system/clear-root/route.js +5 -5
  73. package/.next/standalone/.next/server/app/api/system/clear-root/route.js.nft.json +1 -1
  74. package/.next/standalone/.next/server/app/api/system/config/route.js +6 -6
  75. package/.next/standalone/.next/server/app/api/system/config/route.js.nft.json +1 -1
  76. package/.next/standalone/.next/server/app/api/system/pins/route.js +4 -4
  77. package/.next/standalone/.next/server/app/api/system/pins/route.js.nft.json +1 -1
  78. package/.next/standalone/.next/server/app/api/system/reveal/route.js +6 -6
  79. package/.next/standalone/.next/server/app/api/system/reveal/route.js.nft.json +1 -1
  80. package/.next/standalone/.next/server/app/api/system/root-status/route.js +5 -5
  81. package/.next/standalone/.next/server/app/api/system/root-status/route.js.nft.json +1 -1
  82. package/.next/standalone/.next/server/app/api/system/set-root/route.js +6 -6
  83. package/.next/standalone/.next/server/app/api/system/set-root/route.js.nft.json +1 -1
  84. package/.next/standalone/.next/server/app/api/system/users/route/app-paths-manifest.json +3 -0
  85. package/.next/standalone/.next/server/app/api/system/users/route/build-manifest.json +9 -0
  86. package/.next/standalone/.next/server/app/api/system/users/route/server-reference-manifest.json +4 -0
  87. package/.next/standalone/.next/server/app/api/system/users/route.js +14 -0
  88. package/.next/standalone/.next/server/app/api/system/users/route.js.map +5 -0
  89. package/.next/standalone/.next/server/app/api/system/users/route.js.nft.json +1 -0
  90. package/.next/standalone/.next/server/app/api/system/users/route_client-reference-manifest.js +3 -0
  91. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route/app-paths-manifest.json +3 -0
  92. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route/build-manifest.json +9 -0
  93. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route/server-reference-manifest.json +4 -0
  94. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route.js +14 -0
  95. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route.js.map +5 -0
  96. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route.js.nft.json +1 -0
  97. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route_client-reference-manifest.js +3 -0
  98. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route/app-paths-manifest.json +3 -0
  99. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route/build-manifest.json +9 -0
  100. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route/server-reference-manifest.json +4 -0
  101. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route.js +14 -0
  102. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route.js.map +5 -0
  103. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route.js.nft.json +1 -0
  104. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route_client-reference-manifest.js +3 -0
  105. package/.next/standalone/.next/server/app/api/system/workspaces/route/app-paths-manifest.json +3 -0
  106. package/.next/standalone/.next/server/app/api/system/workspaces/route/build-manifest.json +9 -0
  107. package/.next/standalone/.next/server/app/api/system/workspaces/route/server-reference-manifest.json +4 -0
  108. package/.next/standalone/.next/server/app/api/system/workspaces/route.js +14 -0
  109. package/.next/standalone/.next/server/app/api/system/workspaces/route.js.map +5 -0
  110. package/.next/standalone/.next/server/app/api/system/workspaces/route.js.nft.json +1 -0
  111. package/.next/standalone/.next/server/app/api/system/workspaces/route_client-reference-manifest.js +3 -0
  112. package/.next/standalone/.next/server/app/api/upload/[...path]/route.js +8 -2
  113. package/.next/standalone/.next/server/app/api/upload/[...path]/route.js.nft.json +1 -1
  114. package/.next/standalone/.next/server/app/api/wiki/app/route.js +5 -5
  115. package/.next/standalone/.next/server/app/api/wiki/app/route.js.nft.json +1 -1
  116. package/.next/standalone/.next/server/app/api/wiki/content/route.js +6 -6
  117. package/.next/standalone/.next/server/app/api/wiki/content/route.js.nft.json +1 -1
  118. package/.next/standalone/.next/server/app/api/wiki/download/route.js +7 -7
  119. package/.next/standalone/.next/server/app/api/wiki/download/route.js.nft.json +1 -1
  120. package/.next/standalone/.next/server/app/api/wiki/file/route.js +8 -2
  121. package/.next/standalone/.next/server/app/api/wiki/file/route.js.nft.json +1 -1
  122. package/.next/standalone/.next/server/app/api/wiki/folder/route.js +6 -6
  123. package/.next/standalone/.next/server/app/api/wiki/folder/route.js.nft.json +1 -1
  124. package/.next/standalone/.next/server/app/api/wiki/move/route.js +6 -6
  125. package/.next/standalone/.next/server/app/api/wiki/move/route.js.nft.json +1 -1
  126. package/.next/standalone/.next/server/app/api/wiki/new-file/route.js +7 -7
  127. package/.next/standalone/.next/server/app/api/wiki/new-file/route.js.nft.json +1 -1
  128. package/.next/standalone/.next/server/app/api/wiki/page/route.js +7 -7
  129. package/.next/standalone/.next/server/app/api/wiki/page/route.js.nft.json +1 -1
  130. package/.next/standalone/.next/server/app/api/wiki/presence/route.js +7 -7
  131. package/.next/standalone/.next/server/app/api/wiki/presence/route.js.nft.json +1 -1
  132. package/.next/standalone/.next/server/app/api/wiki/route.js +6 -6
  133. package/.next/standalone/.next/server/app/api/wiki/route.js.nft.json +1 -1
  134. package/.next/standalone/.next/server/app/api/wiki/search/route/app-paths-manifest.json +3 -0
  135. package/.next/standalone/.next/server/app/api/wiki/search/route/build-manifest.json +9 -0
  136. package/.next/standalone/.next/server/app/api/wiki/search/route/server-reference-manifest.json +4 -0
  137. package/.next/standalone/.next/server/app/api/wiki/search/route.js +15 -0
  138. package/.next/standalone/.next/server/app/api/wiki/search/route.js.map +5 -0
  139. package/.next/standalone/.next/server/app/api/wiki/search/route.js.nft.json +1 -0
  140. package/.next/standalone/.next/server/app/api/wiki/search/route_client-reference-manifest.js +3 -0
  141. package/.next/standalone/.next/server/app/api/wiki/slugs/route.js +6 -6
  142. package/.next/standalone/.next/server/app/api/wiki/slugs/route.js.nft.json +1 -1
  143. package/.next/standalone/.next/server/app/api/wiki/upload/route.js +7 -7
  144. package/.next/standalone/.next/server/app/api/wiki/upload/route.js.nft.json +1 -1
  145. package/.next/standalone/.next/server/app/api/wiki/watch/route.js +7 -9
  146. package/.next/standalone/.next/server/app/api/wiki/watch/route.js.nft.json +1 -1
  147. package/.next/standalone/.next/server/app/index.html +1 -1
  148. package/.next/standalone/.next/server/app/index.rsc +3 -3
  149. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  150. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
  151. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  152. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
  153. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  154. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  155. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  156. package/.next/standalone/.next/server/app/signin/page.js +1 -1
  157. package/.next/standalone/.next/server/app/signin/page.js.nft.json +1 -1
  158. package/.next/standalone/.next/server/app/signin/page_client-reference-manifest.js +1 -1
  159. package/.next/standalone/.next/server/app-paths-manifest.json +6 -0
  160. package/.next/standalone/.next/server/chunks/0p91_next_dist_esm_build_templates_app-route_0d2jbo5.js +1 -1
  161. package/.next/standalone/.next/server/chunks/0p91_next_dist_esm_build_templates_app-route_0ytral2.js +1 -1
  162. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-244bv._.js +16 -0
  163. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0xz-_0v._.js → [root-of-the-server]__0-inabx._.js} +2 -2
  164. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0-ao6a_._.js → [root-of-the-server]__0.-9jt0._.js} +1 -1
  165. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0~-r-8f._.js → [root-of-the-server]__00c1-dr._.js} +1 -1
  166. package/.next/standalone/.next/server/chunks/[root-of-the-server]__00lep-u._.js +3 -0
  167. package/.next/standalone/.next/server/chunks/[root-of-the-server]__00mtevo._.js +3 -0
  168. package/.next/standalone/.next/server/chunks/[root-of-the-server]__00qu86p._.js +3 -0
  169. package/.next/standalone/.next/server/chunks/[root-of-the-server]__012753j._.js +3 -0
  170. package/.next/standalone/.next/server/chunks/[root-of-the-server]__01hp8ax._.js +3 -0
  171. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0269d2e._.js +1 -1
  172. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0jhr.ex._.js → [root-of-the-server]__02n6z97._.js} +1 -1
  173. package/.next/standalone/.next/server/chunks/[root-of-the-server]__036mhjp._.js +5 -0
  174. package/.next/standalone/.next/server/chunks/[root-of-the-server]__03p0ob1._.js +16 -0
  175. package/.next/standalone/.next/server/chunks/[root-of-the-server]__05t~v6l._.js +3 -0
  176. package/.next/standalone/.next/server/chunks/[root-of-the-server]__068ni_k._.js +3 -0
  177. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__082nhm6._.js → [root-of-the-server]__07vphbd._.js} +1 -1
  178. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0pg6dn-._.js → [root-of-the-server]__08lkuwa._.js} +1 -1
  179. package/.next/standalone/.next/server/chunks/[root-of-the-server]__09cqzem._.js +3 -0
  180. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0p_ox-k._.js → [root-of-the-server]__09k4q9e._.js} +1 -1
  181. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0_601._.js +3 -0
  182. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ae3dk6._.js +3 -0
  183. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0s28.4-._.js → [root-of-the-server]__0af-x45._.js} +1 -1
  184. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cqu-wm._.js +3 -0
  185. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d75a5q._.js +1 -1
  186. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d7x3e1._.js +3 -0
  187. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d7zxm_._.js +3 -0
  188. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e7vs98._.js +3 -0
  189. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0fxzg4v._.js +3 -0
  190. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0gda_iu._.js +3 -0
  191. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0hu~q20._.js +3 -0
  192. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0jk1uf4._.js +3 -0
  193. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0l-8clq._.js +3 -0
  194. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0lhka0x._.js +3 -0
  195. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0kdn1le._.js → [root-of-the-server]__0na11h0._.js} +2 -2
  196. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0nd.b_c._.js +3 -0
  197. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0otb8ra._.js +3 -0
  198. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0p0-p__._.js +3 -0
  199. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0piofm3._.js +3 -0
  200. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0rrf-jr._.js +3 -0
  201. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0s6_lzw._.js +3 -0
  202. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0sh13v5._.js +3 -0
  203. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ta~flu._.js +3 -0
  204. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0v4im4p._.js +3 -0
  205. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0qn8e~s._.js → [root-of-the-server]__0v_kyp-._.js} +1 -1
  206. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0vatqe-._.js +3 -0
  207. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0vdb2nr._.js +3 -0
  208. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0wdh63w._.js +3 -0
  209. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0z3wg9x._.js +12 -0
  210. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0mzo03s._.js → [root-of-the-server]__0~.-3yk._.js} +1 -1
  211. package/.next/standalone/.next/server/chunks/[root-of-the-server]__123._fe._.js +3 -0
  212. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__12800b1._.js → [root-of-the-server]__12ee_s6._.js} +1 -1
  213. package/.next/standalone/.next/server/chunks/[root-of-the-server]__12onytt._.js +3 -0
  214. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__04udrya._.js → [root-of-the-server]__12q8ch8._.js} +2 -2
  215. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1377.79._.js +3 -0
  216. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1378-ox._.js +3 -0
  217. package/.next/standalone/.next/server/chunks/[root-of-the-server]__13aid91._.js +3 -0
  218. package/.next/standalone/.next/server/chunks/[root-of-the-server]__13hp4tw._.js +12 -0
  219. package/.next/standalone/.next/server/chunks/_079xuln._.js +1 -1
  220. package/.next/standalone/.next/server/chunks/_0dr1r1g._.js +452 -0
  221. package/.next/standalone/.next/server/chunks/_101exke._.js +452 -0
  222. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_system_admins_route_actions_0dsm7cx.js +3 -0
  223. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_system_users_route_actions_0whj5cy.js +3 -0
  224. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_system_workspaces_[id]_open_route_actions_1087xu7.js +3 -0
  225. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_system_workspaces_[id]_route_actions_0~h7-8s.js +3 -0
  226. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_system_workspaces_route_actions_0mkalc3.js +3 -0
  227. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_wiki_search_route_actions_0inxu93.js +3 -0
  228. package/.next/standalone/.next/server/chunks/node_modules__pnpm_0aj5g-w._.js +1 -1
  229. package/.next/standalone/.next/server/chunks/src_lib_search_0d-_j3u._.js +46 -0
  230. package/.next/standalone/.next/server/chunks/src_lib_search_0ymmp0c._.js +46 -0
  231. package/.next/standalone/.next/server/chunks/ssr/{0~w0_katex_dist_katex_mjs_0b8ra51._.js → 0~w0_katex_dist_katex_mjs_04mhawr._.js} +1 -1
  232. package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_erDiagram-TEJ5UH35_mjs_0v6rnqy._.js +1 -1
  233. package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_mermaid_core_mjs_0hj_n-~._.js +1 -1
  234. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0btcd4o._.js → [root-of-the-server]__02twzph._.js} +2 -2
  235. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0ytvlzs._.js → [root-of-the-server]__09~x2v~._.js} +2 -2
  236. package/.next/standalone/.next/server/chunks/ssr/_0pqaawz._.js +18 -18
  237. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0c71i8a._.js → node_modules__pnpm_0.96tmo._.js} +1 -1
  238. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0lm8e2c._.js → node_modules__pnpm_011vy_q._.js} +2 -2
  239. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0ezm2us._.js → node_modules__pnpm_01o_5qt._.js} +1 -1
  240. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0j3mvgg._.js → node_modules__pnpm_04n0h6.._.js} +1 -1
  241. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0~ln0by._.js → node_modules__pnpm_093dp2q._.js} +1 -1
  242. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_11e~j49._.js → node_modules__pnpm_09ej62_._.js} +1 -1
  243. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0de8xt-._.js → node_modules__pnpm_09ljbdz._.js} +2 -2
  244. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0-x6zex._.js → node_modules__pnpm_09~_ob2._.js} +1 -1
  245. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0yq5z.h._.js → node_modules__pnpm_0a01ng7._.js} +2 -2
  246. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0kwc-vs._.js → node_modules__pnpm_0b8qx0g._.js} +1 -1
  247. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0hrbz84._.js → node_modules__pnpm_0bbc---._.js} +1 -1
  248. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0hobcbs._.js → node_modules__pnpm_0c.309.._.js} +1 -1
  249. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0rw91-f._.js → node_modules__pnpm_0c8aunj._.js} +1 -1
  250. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0o.c1z8._.js → node_modules__pnpm_0hk6xys._.js} +2 -2
  251. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0dboa_e._.js → node_modules__pnpm_0hlzy8f._.js} +1 -1
  252. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0j53hti._.js → node_modules__pnpm_0nw5ou2._.js} +1 -1
  253. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0xrmzh1._.js → node_modules__pnpm_0o.dn8o._.js} +1 -1
  254. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0cxwhfd._.js → node_modules__pnpm_0s0ur~d._.js} +1 -1
  255. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_07rxv2x._.js → node_modules__pnpm_0shlang._.js} +1 -1
  256. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0i.pw_m._.js → node_modules__pnpm_0sq3c2r._.js} +1 -1
  257. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0ajzar9._.js → node_modules__pnpm_0t9jb7d._.js} +1 -1
  258. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_012nt.s._.js → node_modules__pnpm_0wmx9kq._.js} +2 -2
  259. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0z~h2ow._.js → node_modules__pnpm_0xfx0sf._.js} +1 -1
  260. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0cbsnwf._.js → node_modules__pnpm_0yiz.-t._.js} +1 -1
  261. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0bum3-3._.js → node_modules__pnpm_11sut1u._.js} +1 -1
  262. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0mdo4i3._.js → node_modules__pnpm_124u4o2._.js} +2 -2
  263. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0il8j.j._.js → node_modules__pnpm_13tajgx._.js} +2 -2
  264. package/.next/standalone/.next/server/chunks/ssr/src_app_signin_00yk0vm._.js +2 -2
  265. package/.next/standalone/.next/server/edge/chunks/{08yl_next_dist_esm_build_templates_edge-wrapper_0o9h3w_.js → 08yl_next_dist_esm_build_templates_edge-wrapper_0xbpts6.js} +2 -2
  266. package/.next/standalone/.next/server/edge/chunks/[root-of-the-server]__0.pmgt2._.js +3 -0
  267. package/.next/standalone/.next/server/functions-config-manifest.json +6 -0
  268. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  269. package/.next/standalone/.next/server/middleware-manifest.json +8 -8
  270. package/.next/standalone/.next/server/pages/404.html +1 -1
  271. package/.next/standalone/.next/server/pages/500.html +1 -1
  272. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  273. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  274. package/.next/standalone/.next/static/chunks/0c_~zevf2n0r4.css +2 -0
  275. package/.next/standalone/.next/static/chunks/0l4842ez-0_66.js +129 -0
  276. package/.next/standalone/README.md +46 -2
  277. package/.next/standalone/agents/bootstrap-prompt.md +3 -1
  278. package/.next/standalone/agents/wiki-viewer-skill/SKILL.md +38 -11
  279. package/.next/standalone/docs/workspacing-plan.md +364 -0
  280. package/.next/standalone/package.json +2 -2
  281. package/.next/standalone/packages/wiki-viewer-mcp/README.md +6 -5
  282. package/.next/standalone/packages/wiki-viewer-mcp/dist/http-client.js +4 -0
  283. package/.next/standalone/packages/wiki-viewer-mcp/dist/index.js +4 -0
  284. package/.next/standalone/packages/wiki-viewer-mcp/src/http-client.ts +6 -0
  285. package/.next/standalone/packages/wiki-viewer-mcp/src/index.ts +5 -0
  286. package/.next/standalone/src/app/api/agent/activity/route.ts +9 -8
  287. package/.next/standalone/src/app/api/agent/events/[...path]/route.ts +20 -8
  288. package/.next/standalone/src/app/api/agent/files/[...path]/route.ts +16 -9
  289. package/.next/standalone/src/app/api/agent/fs/file/[...path]/route.ts +28 -18
  290. package/.next/standalone/src/app/api/agent/fs/ls/[[...path]]/route.ts +12 -7
  291. package/.next/standalone/src/app/api/agent/fs/move/route.ts +16 -11
  292. package/.next/standalone/src/app/api/agent/fs/search/route.ts +49 -13
  293. package/.next/standalone/src/app/api/agent/internal/span/route.ts +9 -5
  294. package/.next/standalone/src/app/api/agent/register/route.ts +9 -1
  295. package/.next/standalone/src/app/api/agent/settings/route.ts +7 -3
  296. package/.next/standalone/src/app/api/agent/sidecar/[...path]/route.ts +8 -4
  297. package/.next/standalone/src/app/api/agents/install/route.ts +20 -2
  298. package/.next/standalone/src/app/api/assets/[...path]/route.ts +9 -4
  299. package/.next/standalone/src/app/api/system/admins/route.ts +103 -0
  300. package/.next/standalone/src/app/api/system/reveal/route.ts +7 -6
  301. package/.next/standalone/src/app/api/system/set-root/route.ts +24 -1
  302. package/.next/standalone/src/app/api/system/users/route.ts +120 -0
  303. package/.next/standalone/src/app/api/system/workspaces/[id]/open/route.ts +34 -0
  304. package/.next/standalone/src/app/api/system/workspaces/[id]/route.ts +74 -0
  305. package/.next/standalone/src/app/api/system/workspaces/route.ts +67 -0
  306. package/.next/standalone/src/app/api/upload/[...path]/route.ts +10 -5
  307. package/.next/standalone/src/app/api/wiki/app/route.ts +10 -9
  308. package/.next/standalone/src/app/api/wiki/content/route.ts +14 -14
  309. package/.next/standalone/src/app/api/wiki/download/route.ts +7 -6
  310. package/.next/standalone/src/app/api/wiki/file/route.ts +7 -2
  311. package/.next/standalone/src/app/api/wiki/folder/route.ts +6 -5
  312. package/.next/standalone/src/app/api/wiki/move/route.ts +7 -7
  313. package/.next/standalone/src/app/api/wiki/new-file/route.ts +7 -6
  314. package/.next/standalone/src/app/api/wiki/page/route.ts +6 -5
  315. package/.next/standalone/src/app/api/wiki/presence/route.ts +8 -7
  316. package/.next/standalone/src/app/api/wiki/route.ts +13 -11
  317. package/.next/standalone/src/app/api/wiki/search/route.ts +44 -0
  318. package/.next/standalone/src/app/api/wiki/slugs/route.ts +8 -8
  319. package/.next/standalone/src/app/api/wiki/upload/route.ts +6 -5
  320. package/.next/standalone/src/app/api/wiki/watch/route.ts +16 -40
  321. package/.next/standalone/src/app/globals.css +484 -484
  322. package/.next/standalone/src/app/page.tsx +163 -49
  323. package/.next/standalone/src/components/auth-settings-sheet.tsx +171 -2
  324. package/.next/standalone/src/components/dir-picker.tsx +8 -6
  325. package/.next/standalone/src/components/editor/comment-thread.tsx +2 -1
  326. package/.next/standalone/src/components/editor/csv-viewer.tsx +3 -2
  327. package/.next/standalone/src/components/editor/editor-toolbar.tsx +2 -2
  328. package/.next/standalone/src/components/editor/editor.tsx +6 -5
  329. package/.next/standalone/src/components/editor/file-fallback-viewer.tsx +3 -2
  330. package/.next/standalone/src/components/editor/folder-index.tsx +2 -1
  331. package/.next/standalone/src/components/editor/image-viewer.tsx +2 -1
  332. package/.next/standalone/src/components/editor/media-popover.tsx +2 -1
  333. package/.next/standalone/src/components/editor/media-viewer.tsx +2 -1
  334. package/.next/standalone/src/components/editor/mermaid-viewer.tsx +3 -2
  335. package/.next/standalone/src/components/editor/node-app-viewer.tsx +4 -3
  336. package/.next/standalone/src/components/editor/notebook-viewer.tsx +3 -2
  337. package/.next/standalone/src/components/editor/office/docx-viewer.tsx +2 -1
  338. package/.next/standalone/src/components/editor/office/office-chrome.tsx +3 -2
  339. package/.next/standalone/src/components/editor/office/pptx-viewer.tsx +2 -1
  340. package/.next/standalone/src/components/editor/office/xlsx-viewer.tsx +2 -1
  341. package/.next/standalone/src/components/editor/pdf-viewer.tsx +2 -1
  342. package/.next/standalone/src/components/editor/proof-span-popover.tsx +2 -1
  343. package/.next/standalone/src/components/editor/source-viewer.tsx +3 -2
  344. package/.next/standalone/src/components/editor/suggest-edit-popover.tsx +2 -1
  345. package/.next/standalone/src/components/editor/suggestion-card.tsx +2 -1
  346. package/.next/standalone/src/components/editor/website-viewer.tsx +2 -1
  347. package/.next/standalone/src/components/editor/wiki-link-create-dialog.tsx +2 -1
  348. package/.next/standalone/src/components/search/search-command-dialog.tsx +109 -0
  349. package/.next/standalone/src/components/search/sidebar-search-box.tsx +121 -0
  350. package/.next/standalone/src/components/search/snippet-text.tsx +48 -0
  351. package/.next/standalone/src/components/ui/command.tsx +3 -2
  352. package/.next/standalone/src/lib/auth/admin.ts +112 -0
  353. package/.next/standalone/src/lib/auth/server.ts +13 -2
  354. package/.next/standalone/src/lib/config.ts +56 -4
  355. package/.next/standalone/src/lib/proof/audit.ts +19 -10
  356. package/.next/standalone/src/lib/proof/auth.ts +11 -0
  357. package/.next/standalone/src/lib/proof/collab-state.ts +4 -2
  358. package/.next/standalone/src/lib/proof/file-lock.ts +5 -0
  359. package/.next/standalone/src/lib/proof/idempotency.ts +5 -0
  360. package/.next/standalone/src/lib/proof/lease.ts +40 -27
  361. package/.next/standalone/src/lib/proof/mutex.ts +4 -0
  362. package/.next/standalone/src/lib/proof/raw-fs.ts +2 -3
  363. package/.next/standalone/src/lib/proof/registry.ts +5 -0
  364. package/.next/standalone/src/lib/search/indexable-exts.ts +25 -0
  365. package/.next/standalone/src/lib/search/indexer.ts +567 -0
  366. package/.next/standalone/src/lib/search/sanitize.ts +35 -0
  367. package/.next/standalone/src/lib/search/search-db.ts +57 -0
  368. package/.next/standalone/src/lib/search/watcher-pool.ts +79 -0
  369. package/.next/standalone/src/lib/workspace-client.ts +82 -0
  370. package/.next/standalone/src/lib/workspace-context.ts +142 -0
  371. package/.next/standalone/src/lib/workspaces.ts +196 -0
  372. package/.next/standalone/src/stores/ai-panel-store.ts +3 -2
  373. package/.next/standalone/src/stores/editor-store.ts +4 -3
  374. package/.next/standalone/src/stores/proof-store.ts +4 -3
  375. package/.next/standalone/src/stores/search-store.ts +86 -0
  376. package/.next/standalone/src/stores/wiki-slugs-store.ts +2 -1
  377. package/.next/standalone/src/tests/proof/admin-create-user.test.ts +43 -0
  378. package/.next/standalone/src/tests/proof/agent-workspace-scope.test.ts +134 -0
  379. package/.next/standalone/src/tests/proof/collab-state.test.ts +43 -41
  380. package/.next/standalone/src/tests/proof/preload.ts +21 -0
  381. package/.next/standalone/src/tests/proof/search-index.test.ts +339 -0
  382. package/.next/standalone/src/tests/proof/workspace-isolation.test.ts +87 -0
  383. package/.next/standalone/src/tests/proof/workspaces-api.test.ts +227 -0
  384. package/.next/standalone/tsconfig.tsbuildinfo +1 -1
  385. package/README.md +46 -2
  386. package/package.json +2 -2
  387. package/.next/standalone/.next/server/chunks/0p91_next_dist_esm_build_templates_app-route_0o~h4zq.js +0 -5
  388. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0.hb9q2._.js +0 -3
  389. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0.uux34._.js +0 -3
  390. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0092hkp._.js +0 -3
  391. package/.next/standalone/.next/server/chunks/[root-of-the-server]__05f6x0i._.js +0 -3
  392. package/.next/standalone/.next/server/chunks/[root-of-the-server]__05idwm9._.js +0 -3
  393. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06-dtd0._.js +0 -3
  394. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06sek6_._.js +0 -3
  395. package/.next/standalone/.next/server/chunks/[root-of-the-server]__07fpqks._.js +0 -3
  396. package/.next/standalone/.next/server/chunks/[root-of-the-server]__094q5bj._.js +0 -3
  397. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0awzyon._.js +0 -3
  398. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d_da6q._.js +0 -3
  399. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0hhhvm7._.js +0 -3
  400. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0kk26wc._.js +0 -3
  401. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0km8suj._.js +0 -3
  402. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0kur4ro._.js +0 -15
  403. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0mkwoul._.js +0 -12
  404. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0qc2~6l._.js +0 -15
  405. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0qyd-o8._.js +0 -3
  406. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0rkve~v._.js +0 -3
  407. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0rzo40z._.js +0 -3
  408. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0sjocwy._.js +0 -3
  409. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ssj9~d._.js +0 -3
  410. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0s~i040._.js +0 -3
  411. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t220d-._.js +0 -3
  412. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t5mg.n._.js +0 -3
  413. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0trsqf4._.js +0 -3
  414. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0xq124z._.js +0 -3
  415. package/.next/standalone/.next/server/chunks/[root-of-the-server]__106uw_c._.js +0 -3
  416. package/.next/standalone/.next/server/chunks/[root-of-the-server]__10w2q~o._.js +0 -3
  417. package/.next/standalone/.next/server/chunks/[root-of-the-server]__13w-0iy._.js +0 -3
  418. package/.next/standalone/.next/server/chunks/src_lib_auth_server_ts_00f4e0h._.js +0 -452
  419. package/.next/standalone/.next/server/edge/chunks/[root-of-the-server]__0ug2rvl._.js +0 -3
  420. package/.next/standalone/.next/static/chunks/0vwkqw_rofm-c.js +0 -129
  421. package/.next/standalone/.next/static/chunks/0zay6349~v_wc.css +0 -2
  422. /package/.next/standalone/.next/static/{0XvNCOSEq7cbARTLtAolL → 17VWCQ9_AhwJBT4yjkvWG}/_buildManifest.js +0 -0
  423. /package/.next/standalone/.next/static/{0XvNCOSEq7cbARTLtAolL → 17VWCQ9_AhwJBT4yjkvWG}/_clientMiddlewareManifest.js +0 -0
  424. /package/.next/standalone/.next/static/{0XvNCOSEq7cbARTLtAolL → 17VWCQ9_AhwJBT4yjkvWG}/_ssgManifest.js +0 -0
@@ -9,6 +9,7 @@
9
9
  * WIKI_VIEWER_URL Base URL of wiki-viewer instance (required)
10
10
  * WIKI_VIEWER_TOKEN Bearer token from TOFU registration (required)
11
11
  * WIKI_VIEWER_AGENT_ID X-Agent-Id header value (required)
12
+ * WIKI_VIEWER_WORKSPACE Workspace id for X-Workspace header (optional; targets one workspace)
12
13
  *
13
14
  * Mode-awareness:
14
15
  * Before any raw write to a .md file, the shim checks the cached
@@ -76,12 +77,14 @@ export function createClient(overrides?: {
76
77
  baseUrl?: string;
77
78
  token?: string;
78
79
  agentId?: string;
80
+ workspace?: string;
79
81
  fetch?: typeof fetch;
80
82
  }): WikiViewerClient {
81
83
  return new WikiViewerClient({
82
84
  baseUrl: overrides?.baseUrl ?? requireEnv("WIKI_VIEWER_URL"),
83
85
  token: overrides?.token ?? requireEnv("WIKI_VIEWER_TOKEN"),
84
86
  agentId: overrides?.agentId ?? requireEnv("WIKI_VIEWER_AGENT_ID"),
87
+ workspace: overrides?.workspace ?? process.env.WIKI_VIEWER_WORKSPACE,
85
88
  fetch: overrides?.fetch,
86
89
  });
87
90
  }
@@ -524,6 +527,7 @@ async function runRegister() {
524
527
  "scope-paths": { type: "string", default: "**/*" },
525
528
  ops: { type: "string", default: "read,mutate" },
526
529
  timeout: { type: "string", default: "300" },
530
+ workspace: { type: "string" },
527
531
  },
528
532
  allowPositionals: true,
529
533
  });
@@ -595,6 +599,7 @@ async function runRegister() {
595
599
  WIKI_VIEWER_URL: values.url,
596
600
  WIKI_VIEWER_TOKEN: result.token,
597
601
  WIKI_VIEWER_AGENT_ID: result.agentId,
602
+ ...(values.workspace ? { WIKI_VIEWER_WORKSPACE: values.workspace } : {}),
598
603
  },
599
604
  },
600
605
  },
@@ -1,6 +1,6 @@
1
1
  import { NextResponse } from "next/server";
2
2
  import { checkAuth, enforceScope } from "@/lib/proof/auth";
3
- import { getRootDir } from "@/lib/root-dir";
3
+ import { resolveWorkspaceForAgent } from "@/lib/workspace-context";
4
4
  import {
5
5
  aggregateActivity,
6
6
  ACTIVITY_DEFAULT_LIMIT,
@@ -16,14 +16,15 @@ export async function GET(req: Request): Promise<NextResponse> {
16
16
  return NextResponse.json({ error: "UNAUTHORIZED" }, { status: 401 });
17
17
  }
18
18
 
19
- const scopeCheck = enforceScope(auth.agent, { op: "read" });
20
- if (!scopeCheck.ok) {
21
- return NextResponse.json({ error: scopeCheck.code, message: scopeCheck.message }, { status: 403 });
19
+ const wsx = await resolveWorkspaceForAgent(req);
20
+ if (!wsx.ok) {
21
+ return NextResponse.json({ error: wsx.code }, { status: wsx.status });
22
22
  }
23
+ const { ws, rootDir } = wsx;
23
24
 
24
- const rootDir = getRootDir();
25
- if (!rootDir) {
26
- return NextResponse.json({ error: "ROOT_NOT_SET" }, { status: 503 });
25
+ const scopeCheck = enforceScope(auth.agent, { op: "read", workspaceId: ws.id });
26
+ if (!scopeCheck.ok) {
27
+ return NextResponse.json({ error: scopeCheck.code, message: scopeCheck.message }, { status: 403 });
27
28
  }
28
29
 
29
30
  const url = new URL(req.url);
@@ -32,7 +33,7 @@ export async function GET(req: Request): Promise<NextResponse> {
32
33
 
33
34
  // Enforce scope on explicit file query parameter
34
35
  if (fileFilter) {
35
- const fileScope = enforceScope(auth.agent, { filePath: fileFilter, op: "read" });
36
+ const fileScope = enforceScope(auth.agent, { filePath: fileFilter, op: "read", workspaceId: ws.id });
36
37
  if (!fileScope.ok) {
37
38
  return NextResponse.json({ error: fileScope.code, message: fileScope.message }, { status: 403 });
38
39
  }
@@ -3,7 +3,8 @@ import { checkAuth, enforceScope, verifyBy } from "@/lib/proof/auth";
3
3
  import { readSidecar, writeSidecar, emptySidecar } from "@/lib/proof/sidecar";
4
4
  import { pollEvents } from "@/lib/proof/event-bus";
5
5
  import { withFileMutex } from "@/lib/proof/mutex";
6
- import { getRootDir, safeRootPath } from "@/lib/root-dir";
6
+ import { resolveWorkspaceForAgent } from "@/lib/workspace-context";
7
+ import { safeWorkspacePath } from "@/lib/workspaces";
7
8
 
8
9
  export const runtime = "nodejs";
9
10
 
@@ -28,6 +29,12 @@ export async function GET(
28
29
  return NextResponse.json({ error: "UNAUTHORIZED" }, { status: 401 });
29
30
  }
30
31
 
32
+ const wsx = await resolveWorkspaceForAgent(req);
33
+ if (!wsx.ok) {
34
+ return NextResponse.json({ error: wsx.code }, { status: wsx.status });
35
+ }
36
+ const { ws, rootDir } = wsx;
37
+
31
38
  const { path: segments } = await params;
32
39
  const rel = mdPath(segments);
33
40
 
@@ -38,12 +45,12 @@ export async function GET(
38
45
  return NextResponse.json({ error: "INVALID_PATH", message: "Path must be .md or .markdown" }, { status: 400 });
39
46
  }
40
47
 
41
- const absPath = safeRootPath(rel);
48
+ const absPath = safeWorkspacePath(rootDir, rel);
42
49
  if (!absPath) {
43
50
  return NextResponse.json({ error: "INVALID_PATH", message: "Path traversal rejected" }, { status: 400 });
44
51
  }
45
52
 
46
- const scopeCheck = enforceScope(auth.agent, { filePath: rel, op: "read" });
53
+ const scopeCheck = enforceScope(auth.agent, { filePath: rel, op: "read", workspaceId: ws.id });
47
54
  if (!scopeCheck.ok) {
48
55
  return NextResponse.json({ error: scopeCheck.code, message: scopeCheck.message }, { status: 403 });
49
56
  }
@@ -65,7 +72,6 @@ export async function GET(
65
72
  limit = MAX_LIMIT;
66
73
  }
67
74
 
68
- const rootDir = getRootDir();
69
75
  const sidecar = (await readSidecar(rootDir, rel)) ?? emptySidecar(rel);
70
76
  const events = pollEvents(sidecar, after, limit);
71
77
  const lastEventId = sidecar.nextEventId - 1;
@@ -83,6 +89,12 @@ export async function POST(
83
89
  return NextResponse.json({ error: "UNAUTHORIZED" }, { status: 401 });
84
90
  }
85
91
 
92
+ const wsx = await resolveWorkspaceForAgent(req);
93
+ if (!wsx.ok) {
94
+ return NextResponse.json({ error: wsx.code }, { status: wsx.status });
95
+ }
96
+ const { ws, rootDir } = wsx;
97
+
86
98
  const { path: segments } = await params;
87
99
  const rel = mdPath(segments);
88
100
 
@@ -93,12 +105,12 @@ export async function POST(
93
105
  return NextResponse.json({ error: "INVALID_PATH", message: "Path must be .md or .markdown" }, { status: 400 });
94
106
  }
95
107
 
96
- const absPath = safeRootPath(rel);
108
+ const absPath = safeWorkspacePath(rootDir, rel);
97
109
  if (!absPath) {
98
110
  return NextResponse.json({ error: "INVALID_PATH", message: "Path traversal rejected" }, { status: 400 });
99
111
  }
100
112
 
101
- const scopeCheck = enforceScope(auth.agent, { filePath: rel, op: "mutate" });
113
+ const scopeCheck = enforceScope(auth.agent, { filePath: rel, op: "mutate", workspaceId: ws.id });
102
114
  if (!scopeCheck.ok) {
103
115
  return NextResponse.json({ error: scopeCheck.code, message: scopeCheck.message }, { status: 403 });
104
116
  }
@@ -122,11 +134,11 @@ export async function POST(
122
134
  return NextResponse.json({ error: byCheck.code, message: byCheck.message }, { status: 403 });
123
135
  }
124
136
 
125
- const rootDir = getRootDir();
126
137
  const upToId = body.upToId as number;
127
138
  const by = body.by as string;
128
139
 
129
- await withFileMutex(rel, async () => {
140
+ // Namespace mutex key with rootDir to prevent cross-workspace lock contention.
141
+ await withFileMutex(`${rootDir}\0${rel}`, async () => {
130
142
  const sidecar = (await readSidecar(rootDir, rel)) ?? emptySidecar(rel);
131
143
  sidecar.lastAck[by] = upToId;
132
144
  await writeSidecar(rootDir, rel, sidecar);
@@ -18,7 +18,8 @@ import { NextResponse } from "next/server";
18
18
  import { checkAuth, enforceScope, verifyBy } from "@/lib/proof/auth";
19
19
  import { applyOps, readSnapshot } from "@/lib/proof/ops-applier";
20
20
  import { idempotency } from "@/lib/proof/idempotency";
21
- import { getRootDir, safeRootPath } from "@/lib/root-dir";
21
+ import { resolveWorkspaceForAgent } from "@/lib/workspace-context";
22
+ import { safeWorkspacePath } from "@/lib/workspaces";
22
23
  import type { Op } from "@/lib/proof/types";
23
24
  import { checkAndConsume } from "@/lib/proof/rate-limit";
24
25
  import { computeCollabState } from "@/lib/proof/collab-state";
@@ -52,17 +53,20 @@ export async function GET(
52
53
  return NextResponse.json({ error: "INVALID_PATH", message: "Path must be .md or .markdown" }, { status: 400 });
53
54
  }
54
55
 
55
- const absPath = safeRootPath(rel);
56
+ const wsx = await resolveWorkspaceForAgent(req);
57
+ if (!wsx.ok) return NextResponse.json({ error: wsx.code }, { status: wsx.status });
58
+ const { ws, rootDir } = wsx;
59
+
60
+ const absPath = safeWorkspacePath(rootDir, rel);
56
61
  if (!absPath) {
57
62
  return NextResponse.json({ error: "INVALID_PATH", message: "Path traversal rejected" }, { status: 400 });
58
63
  }
59
64
 
60
- const scopeCheck = enforceScope(auth.agent, { filePath: rel, op: "read" });
65
+ const scopeCheck = enforceScope(auth.agent, { filePath: rel, op: "read", workspaceId: ws.id });
61
66
  if (!scopeCheck.ok) {
62
67
  return NextResponse.json({ error: scopeCheck.code, message: scopeCheck.message }, { status: 403 });
63
68
  }
64
69
 
65
- const rootDir = getRootDir();
66
70
  const snapshot = await readSnapshot(rootDir, rel);
67
71
  if (!snapshot) {
68
72
  return NextResponse.json({ error: "NOT_FOUND", message: "File not found" }, { status: 404 });
@@ -107,7 +111,11 @@ export async function POST(
107
111
  return NextResponse.json({ error: "INVALID_PATH", message: "Path must be .md or .markdown" }, { status: 400 });
108
112
  }
109
113
 
110
- const absPath = safeRootPath(rel);
114
+ const wsx = await resolveWorkspaceForAgent(req);
115
+ if (!wsx.ok) return NextResponse.json({ error: wsx.code }, { status: wsx.status });
116
+ const { ws, rootDir } = wsx;
117
+
118
+ const absPath = safeWorkspacePath(rootDir, rel);
111
119
  if (!absPath) {
112
120
  return NextResponse.json({ error: "INVALID_PATH", message: "Path traversal rejected" }, { status: 400 });
113
121
  }
@@ -123,7 +131,7 @@ export async function POST(
123
131
  const payloadHash = createHash("sha256").update(rawBody, "utf8").digest("hex");
124
132
 
125
133
  // Check idempotency cache
126
- const cached = idempotency.get(idempotencyKey);
134
+ const cached = idempotency.get(`${rootDir}\u0000${idempotencyKey}`);
127
135
  if (cached) {
128
136
  if (cached.payloadHash !== payloadHash) {
129
137
  return NextResponse.json(
@@ -154,7 +162,7 @@ export async function POST(
154
162
  return NextResponse.json({ error: "INVALID_PAYLOAD", message: "ops (array) required" }, { status: 400 });
155
163
  }
156
164
 
157
- const scopeCheck = enforceScope(auth.agent, { filePath: rel, op: "mutate" });
165
+ const scopeCheck = enforceScope(auth.agent, { filePath: rel, op: "mutate", workspaceId: ws.id });
158
166
  if (!scopeCheck.ok) {
159
167
  return NextResponse.json({ error: scopeCheck.code, message: scopeCheck.message }, { status: 403 });
160
168
  }
@@ -181,7 +189,6 @@ export async function POST(
181
189
  );
182
190
  }
183
191
 
184
- const rootDir = getRootDir();
185
192
  const result = await applyOps({
186
193
  rootDir,
187
194
  mdPath: rel,
@@ -203,7 +210,7 @@ export async function POST(
203
210
  responseBody = JSON.stringify(payload);
204
211
  }
205
212
 
206
- idempotency.set(idempotencyKey, { payloadHash, status, body: responseBody });
213
+ idempotency.set(`${rootDir}\u0000${idempotencyKey}`, { payloadHash, status, body: responseBody });
207
214
 
208
215
  return new NextResponse(responseBody, {
209
216
  status,
@@ -11,7 +11,8 @@ import { readFile, stat, unlink, rm } from "node:fs/promises";
11
11
  import path from "node:path";
12
12
  import { NextResponse } from "next/server";
13
13
  import { checkAuth, enforceScope } from "@/lib/proof/auth";
14
- import { getRootDir, safeRootPath } from "@/lib/root-dir";
14
+ import { resolveWorkspaceForAgent } from "@/lib/workspace-context";
15
+ import { safeWorkspacePath } from "@/lib/workspaces";
15
16
  import { withFileMutex } from "@/lib/proof/mutex";
16
17
  import { readSidecar, emptySidecar, deleteSidecar } from "@/lib/proof/sidecar";
17
18
  import { reconcileSidecar } from "@/lib/proof/ops-applier";
@@ -50,13 +51,17 @@ export async function GET(
50
51
  const { path: segments } = await params;
51
52
  const relPath = rel(segments);
52
53
 
53
- const basic = safeRootPath(relPath);
54
+ const wsx = await resolveWorkspaceForAgent(req);
55
+ if (!wsx.ok) return errJson(wsx.code, wsx.code, wsx.status);
56
+ const { ws, rootDir } = wsx;
57
+
58
+ const basic = safeWorkspacePath(rootDir, relPath);
54
59
  if (!basic) return errJson("INVALID_PATH", "Path traversal rejected", 400);
55
60
 
56
- const absPath = await safeAbsPath(relPath);
61
+ const absPath = await safeAbsPath(rootDir, relPath);
57
62
  if (!absPath) return errJson("INVALID_PATH", "Path rejected (symlink escape or denied)", 400);
58
63
 
59
- const scope = enforceScope(auth.agent, { filePath: relPath, op: "read" });
64
+ const scope = enforceScope(auth.agent, { filePath: relPath, op: "read", workspaceId: ws.id });
60
65
  if (!scope.ok) return errJson(scope.code, scope.message, 403);
61
66
 
62
67
  let data: Buffer;
@@ -84,7 +89,6 @@ export async function GET(
84
89
  };
85
90
 
86
91
  // X-Collab-* headers (§3.5 mode signal)
87
- const rootDir = getRootDir();
88
92
  const collab = await computeCollabState(rootDir, relPath);
89
93
  if (collab.state !== "not-markdown") {
90
94
  baseHeaders["X-Collab-State"] = collab.state;
@@ -148,23 +152,26 @@ async function applyMutation(
148
152
  const auth = await checkAuth(req);
149
153
  if (!auth.ok) return errJson("UNAUTHORIZED", auth.message ?? "Unauthorized", 401);
150
154
 
155
+ const wsx = await resolveWorkspaceForAgent(req);
156
+ if (!wsx.ok) return errJson(wsx.code, wsx.code, wsx.status);
157
+ const { ws, rootDir } = wsx;
158
+
151
159
  const relPath = rel(segments);
152
160
  const url = new URL(req.url);
153
161
  const mkdirs = url.searchParams.get("mkdirs") === "true";
154
162
  const force = url.searchParams.get("force") === "true";
155
163
 
156
- const basic = safeRootPath(relPath);
164
+ const basic = safeWorkspacePath(rootDir, relPath);
157
165
  if (!basic) return errJson("INVALID_PATH", "Path traversal rejected", 400);
158
166
 
159
- const absPath = await safeAbsPath(relPath);
167
+ const absPath = await safeAbsPath(rootDir, relPath);
160
168
  if (!absPath) return errJson("INVALID_PATH", "Path rejected (symlink escape or denied)", 400);
161
169
 
162
- const scope = enforceScope(auth.agent, { filePath: relPath, op: "mutate" });
170
+ const scope = enforceScope(auth.agent, { filePath: relPath, op: "mutate", workspaceId: ws.id });
163
171
  if (!scope.ok) return errJson(scope.code, scope.message, 403);
164
172
 
165
173
  const ifMatch = req.headers.get("if-match");
166
174
  const ifCollabMatch = req.headers.get("if-collab-match");
167
- const rootDir = getRootDir();
168
175
 
169
176
  // The whole read-existing → precondition → compute → write → reconcile → audit
170
177
  // sequence runs inside the mutex for .md (so R6 and reconcile are atomic with
@@ -256,6 +263,7 @@ async function applyMutation(
256
263
  oldSha: existingSha,
257
264
  newSha,
258
265
  forced: force,
266
+ workspaceId: ws.id,
259
267
  });
260
268
 
261
269
  const st = await stat(absPath);
@@ -268,7 +276,7 @@ async function applyMutation(
268
276
  });
269
277
  };
270
278
 
271
- return isMarkdown(relPath) ? withFileMutex(relPath, doMutation) : doMutation();
279
+ return isMarkdown(relPath) ? withFileMutex(`${rootDir}\u0000${relPath}`, doMutation) : doMutation();
272
280
  }
273
281
 
274
282
  // ── PUT ──────────────────────────────────────────────────────────────────────
@@ -377,14 +385,18 @@ export async function DELETE(
377
385
  const url = new URL(req.url);
378
386
  const recursive = url.searchParams.get("recursive") === "true";
379
387
 
380
- const basic = safeRootPath(relPath);
388
+ const wsx = await resolveWorkspaceForAgent(req);
389
+ if (!wsx.ok) return errJson(wsx.code, wsx.code, wsx.status);
390
+ const { ws, rootDir } = wsx;
391
+
392
+ const basic = safeWorkspacePath(rootDir, relPath);
381
393
  if (!basic) return errJson("INVALID_PATH", "Path traversal rejected", 400);
382
394
 
383
- const absPath = await safeAbsPath(relPath);
395
+ const absPath = await safeAbsPath(rootDir, relPath);
384
396
  if (!absPath) return errJson("INVALID_PATH", "Path rejected (symlink escape or denied)", 400);
385
397
 
386
398
  // Requires "delete" scope op
387
- const scope = enforceScope(auth.agent, { filePath: relPath, op: "delete" });
399
+ const scope = enforceScope(auth.agent, { filePath: relPath, op: "delete", workspaceId: ws.id });
388
400
  if (!scope.ok) return errJson(scope.code, scope.message, 403);
389
401
 
390
402
  const ifMatch = req.headers.get("if-match");
@@ -405,7 +417,7 @@ export async function DELETE(
405
417
  }
406
418
  // Directory delete — no single sha, skip If-Match; require recursive flag as confirmation
407
419
  await rm(absPath, { recursive: true, force: true });
408
- writeAuditRow({ agentId: auth.agent.id, op: "delete", path: relPath, forced: false });
420
+ writeAuditRow({ agentId: auth.agent.id, op: "delete", path: relPath, forced: false, workspaceId: ws.id });
409
421
  return NextResponse.json({ deleted: relPath });
410
422
  }
411
423
 
@@ -420,10 +432,8 @@ export async function DELETE(
420
432
  return errJson("PRECONDITION_FAILED", "If-Match sha256 mismatch", 412);
421
433
  }
422
434
 
423
- const rootDir = getRootDir();
424
-
425
435
  if (isMarkdown(relPath)) {
426
- await withFileMutex(relPath, async () => {
436
+ await withFileMutex(`${rootDir}\u0000${relPath}`, async () => {
427
437
  await unlink(absPath);
428
438
  await deleteSidecar(rootDir, relPath);
429
439
  });
@@ -431,6 +441,6 @@ export async function DELETE(
431
441
  await unlink(absPath);
432
442
  }
433
443
 
434
- writeAuditRow({ agentId: auth.agent.id, op: "delete", path: relPath, oldSha: existingSha, forced: false });
444
+ writeAuditRow({ agentId: auth.agent.id, op: "delete", path: relPath, oldSha: existingSha, forced: false, workspaceId: ws.id });
435
445
  return NextResponse.json({ deleted: relPath });
436
446
  }
@@ -13,7 +13,8 @@ import { readdir, stat } from "node:fs/promises";
13
13
  import path from "node:path";
14
14
  import { NextResponse } from "next/server";
15
15
  import { checkAuth, enforceScope } from "@/lib/proof/auth";
16
- import { getRootDir, safeRootPath } from "@/lib/root-dir";
16
+ import { resolveWorkspaceForAgent } from "@/lib/workspace-context";
17
+ import { safeWorkspacePath } from "@/lib/workspaces";
17
18
  import { safeAbsPath } from "@/lib/proof/raw-fs";
18
19
  import type { Agent } from "@/lib/proof/registry";
19
20
 
@@ -44,6 +45,7 @@ async function walkDir(
44
45
  maxDepth: number,
45
46
  limit: number,
46
47
  results: LsEntry[],
48
+ workspaceId?: string,
47
49
  ): Promise<void> {
48
50
  if (depth > maxDepth || results.length >= limit) return;
49
51
 
@@ -63,7 +65,7 @@ async function walkDir(
63
65
  const childRel = relDir ? `${relDir}/${item.name}` : item.name;
64
66
 
65
67
  // Scope check per entry
66
- const sc = enforceScope(agent, { filePath: childRel, op: "read" });
68
+ const sc = enforceScope(agent, { filePath: childRel, op: "read", workspaceId });
67
69
  if (!sc.ok) continue;
68
70
 
69
71
  let type: LsEntry["type"];
@@ -88,7 +90,7 @@ async function walkDir(
88
90
  results.push({ name: item.name, path: childRel, type, size, mtime });
89
91
 
90
92
  if (recursive && type === "dir") {
91
- await walkDir(rootDir, childRel, agent, recursive, depth + 1, maxDepth, limit, results);
93
+ await walkDir(rootDir, childRel, agent, recursive, depth + 1, maxDepth, limit, results, workspaceId);
92
94
  }
93
95
  }
94
96
  }
@@ -103,10 +105,14 @@ export async function GET(
103
105
  const { path: segments } = await params;
104
106
  const relPath = segments ? segments.join("/") : "";
105
107
 
108
+ const wsx = await resolveWorkspaceForAgent(req);
109
+ if (!wsx.ok) return errJson(wsx.code, wsx.code, wsx.status);
110
+ const { ws, rootDir } = wsx;
111
+
106
112
  if (relPath) {
107
- const basic = safeRootPath(relPath);
113
+ const basic = safeWorkspacePath(rootDir, relPath);
108
114
  if (!basic) return errJson("INVALID_PATH", "Path traversal rejected", 400);
109
- const safe = await safeAbsPath(relPath);
115
+ const safe = await safeAbsPath(rootDir, relPath);
110
116
  if (!safe) return errJson("INVALID_PATH", "Path rejected (symlink escape or denied)", 400);
111
117
  }
112
118
 
@@ -122,7 +128,6 @@ export async function GET(
122
128
  );
123
129
 
124
130
  // Verify the dir actually exists
125
- const rootDir = getRootDir();
126
131
  const absDir = relPath ? path.join(rootDir, relPath) : rootDir;
127
132
  try {
128
133
  const st = await stat(absDir);
@@ -137,7 +142,7 @@ export async function GET(
137
142
  }
138
143
 
139
144
  const entries: LsEntry[] = [];
140
- await walkDir(rootDir, relPath, auth.agent, recursive, 0, depth, limit, entries);
145
+ await walkDir(rootDir, relPath, auth.agent, recursive, 0, depth, limit, entries, ws.id);
141
146
 
142
147
  return NextResponse.json({
143
148
  path: relPath,
@@ -14,7 +14,8 @@ import { rename, stat } from "node:fs/promises";
14
14
  import path from "node:path";
15
15
  import { NextResponse } from "next/server";
16
16
  import { checkAuth, enforceScope } from "@/lib/proof/auth";
17
- import { getRootDir, safeRootPath } from "@/lib/root-dir";
17
+ import { resolveWorkspaceForAgent } from "@/lib/workspace-context";
18
+ import { safeWorkspacePath } from "@/lib/workspaces";
18
19
  import { withFileMutex } from "@/lib/proof/mutex";
19
20
  import { moveSidecar } from "@/lib/proof/sidecar";
20
21
  import { writeAuditRow } from "@/lib/proof/audit";
@@ -47,13 +48,17 @@ export async function POST(req: Request): Promise<NextResponse> {
47
48
  const toRel = body.to;
48
49
  const ifMatch = typeof body.ifMatch === "string" ? body.ifMatch : undefined;
49
50
 
51
+ const wsx = await resolveWorkspaceForAgent(req);
52
+ if (!wsx.ok) return errJson(wsx.code, wsx.code, wsx.status);
53
+ const { ws, rootDir } = wsx;
54
+
50
55
  // Basic traversal
51
- if (!safeRootPath(fromRel)) return errJson("INVALID_PATH", "from: path traversal rejected", 400);
52
- if (!safeRootPath(toRel)) return errJson("INVALID_PATH", "to: path traversal rejected", 400);
56
+ if (!safeWorkspacePath(rootDir, fromRel)) return errJson("INVALID_PATH", "from: path traversal rejected", 400);
57
+ if (!safeWorkspacePath(rootDir, toRel)) return errJson("INVALID_PATH", "to: path traversal rejected", 400);
53
58
 
54
- const fromAbs = await safeAbsPath(fromRel);
59
+ const fromAbs = await safeAbsPath(rootDir, fromRel);
55
60
  if (!fromAbs) return errJson("INVALID_PATH", "from: path rejected (symlink escape or denied)", 400);
56
- const toAbs = await safeAbsPath(toRel);
61
+ const toAbs = await safeAbsPath(rootDir, toRel);
57
62
  if (!toAbs) return errJson("INVALID_PATH", "to: path rejected (symlink escape or denied)", 400);
58
63
 
59
64
  // Self-move guard
@@ -63,11 +68,11 @@ export async function POST(req: Request): Promise<NextResponse> {
63
68
  }
64
69
 
65
70
  // Scope: source requires read+mutate; dest requires mutate
66
- const sc1 = enforceScope(auth.agent, { filePath: fromRel, op: "read" });
71
+ const sc1 = enforceScope(auth.agent, { filePath: fromRel, op: "read", workspaceId: ws.id });
67
72
  if (!sc1.ok) return errJson(sc1.code, sc1.message, 403);
68
- const sc2 = enforceScope(auth.agent, { filePath: fromRel, op: "mutate" });
73
+ const sc2 = enforceScope(auth.agent, { filePath: fromRel, op: "mutate", workspaceId: ws.id });
69
74
  if (!sc2.ok) return errJson(sc2.code, sc2.message, 403);
70
- const sc3 = enforceScope(auth.agent, { filePath: toRel, op: "mutate" });
75
+ const sc3 = enforceScope(auth.agent, { filePath: toRel, op: "mutate", workspaceId: ws.id });
71
76
  if (!sc3.ok) return errJson(sc3.code, sc3.message, 403);
72
77
 
73
78
  // Verify source exists
@@ -95,7 +100,6 @@ export async function POST(req: Request): Promise<NextResponse> {
95
100
  }
96
101
  }
97
102
 
98
- const rootDir = getRootDir();
99
103
  const isMd = isMarkdown(fromRel);
100
104
 
101
105
  // Lock source + dest in sorted order to avoid deadlock
@@ -112,13 +116,14 @@ export async function POST(req: Request): Promise<NextResponse> {
112
116
  path: fromRel,
113
117
  newSha: toRel, // store destination in newSha field for audit trail
114
118
  forced: false,
119
+ workspaceId: ws.id,
115
120
  });
116
121
  };
117
122
 
118
123
  if (first === fromRel) {
119
- await withFileMutex(first, () => withFileMutex(second, doMove));
124
+ await withFileMutex(`${rootDir}\u0000${first}`, () => withFileMutex(`${rootDir}\u0000${second}`, doMove));
120
125
  } else {
121
- await withFileMutex(first, () => withFileMutex(second, doMove));
126
+ await withFileMutex(`${rootDir}\u0000${first}`, () => withFileMutex(`${rootDir}\u0000${second}`, doMove));
122
127
  }
123
128
 
124
129
  return NextResponse.json({ from: fromRel, to: toRel });
@@ -19,10 +19,12 @@
19
19
  export const runtime = "nodejs";
20
20
 
21
21
  import { readdir, readFile, stat } from "node:fs/promises";
22
+ import { ensureIndexer, ftsSearch } from "@/lib/search/indexer";
22
23
  import path from "node:path";
23
24
  import { NextResponse } from "next/server";
24
25
  import { checkAuth, enforceScope } from "@/lib/proof/auth";
25
- import { getRootDir, safeRootPath } from "@/lib/root-dir";
26
+ import { resolveWorkspaceForAgent } from "@/lib/workspace-context";
27
+ import { safeWorkspacePath } from "@/lib/workspaces";
26
28
  import { safeAbsPath, looksLikeBinary } from "@/lib/proof/raw-fs";
27
29
  import { matchGlob } from "@/lib/proof/glob";
28
30
  import type { Agent } from "@/lib/proof/registry";
@@ -36,6 +38,8 @@ export interface SearchMatch {
36
38
  line?: number;
37
39
  col?: number;
38
40
  text?: string;
41
+ score?: number;
42
+ snippet?: string;
39
43
  }
40
44
 
41
45
  function errJson(code: string, message: string, status: number): NextResponse {
@@ -74,6 +78,7 @@ async function grepSearch(
74
78
  limit: number,
75
79
  agent: Agent,
76
80
  deadline: number,
81
+ workspaceId?: string,
77
82
  ): Promise<{ matches: SearchMatch[]; truncated: boolean }> {
78
83
  let regex: RegExp;
79
84
  try {
@@ -94,7 +99,7 @@ async function grepSearch(
94
99
  if (matches.length >= limit) return { matches, truncated: true };
95
100
  if (Date.now() > deadline) return { matches, truncated: true };
96
101
 
97
- const sc = enforceScope(agent, { filePath: fileRel, op: "read" });
102
+ const sc = enforceScope(agent, { filePath: fileRel, op: "read", workspaceId });
98
103
  if (!sc.ok) continue;
99
104
 
100
105
  let buf: Buffer;
@@ -140,6 +145,7 @@ async function globSearch(
140
145
  limit: number,
141
146
  agent: Agent,
142
147
  deadline: number,
148
+ workspaceId?: string,
143
149
  ): Promise<{ matches: SearchMatch[]; truncated: boolean }> {
144
150
  const matches: SearchMatch[] = [];
145
151
 
@@ -151,7 +157,7 @@ async function globSearch(
151
157
  const baseName = path.basename(fileRel);
152
158
  if (!matchGlob(pattern, fileRel) && !matchGlob(pattern, baseName)) continue;
153
159
 
154
- const sc = enforceScope(agent, { filePath: fileRel, op: "read" });
160
+ const sc = enforceScope(agent, { filePath: fileRel, op: "read", workspaceId });
155
161
  if (!sc.ok) continue;
156
162
 
157
163
  matches.push({ path: fileRel });
@@ -173,14 +179,17 @@ export async function POST(req: Request): Promise<NextResponse> {
173
179
  return errJson("INVALID_PAYLOAD", "Invalid JSON body", 400);
174
180
  }
175
181
 
176
- if (body.kind !== "grep" && body.kind !== "glob") {
177
- return errJson("INVALID_PAYLOAD", 'kind must be "grep" or "glob"', 400);
182
+ if (body.kind !== "grep" && body.kind !== "glob" && body.kind !== "fts") {
183
+ return errJson("INVALID_PAYLOAD", 'kind must be "grep", "glob", or "fts"', 400);
178
184
  }
179
- if (typeof body.query !== "string" || !body.query) {
185
+ if (typeof body.query !== "string") {
186
+ return errJson("INVALID_PAYLOAD", "query (string) required", 400);
187
+ }
188
+ if (body.kind !== "fts" && !body.query) {
180
189
  return errJson("INVALID_PAYLOAD", "query (string) required", 400);
181
190
  }
182
191
 
183
- const kind = body.kind as "grep" | "glob";
192
+ const kind = body.kind as "grep" | "glob" | "fts";
184
193
  const query = body.query as string;
185
194
  const startRelRaw = typeof body.path === "string" ? body.path : "";
186
195
  const limit = Math.min(
@@ -188,17 +197,19 @@ export async function POST(req: Request): Promise<NextResponse> {
188
197
  HARD_MAX_MATCHES,
189
198
  );
190
199
 
200
+ const wsx = await resolveWorkspaceForAgent(req);
201
+ if (!wsx.ok) return errJson(wsx.code, wsx.code, wsx.status);
202
+ const { ws, rootDir } = wsx;
203
+
191
204
  // Validate start path
192
205
  if (startRelRaw) {
193
- if (!safeRootPath(startRelRaw)) {
206
+ if (!safeWorkspacePath(rootDir, startRelRaw)) {
194
207
  return errJson("INVALID_PATH", "path: traversal rejected", 400);
195
208
  }
196
- const safe = await safeAbsPath(startRelRaw);
209
+ const safe = await safeAbsPath(rootDir, startRelRaw);
197
210
  if (!safe) return errJson("INVALID_PATH", "path: rejected (symlink escape or denied)", 400);
198
211
  }
199
212
 
200
- const rootDir = getRootDir();
201
-
202
213
  // Verify start path is a directory
203
214
  if (startRelRaw) {
204
215
  try {
@@ -214,14 +225,39 @@ export async function POST(req: Request): Promise<NextResponse> {
214
225
  }
215
226
  }
216
227
 
228
+ // FTS branch -- handled before the grep/glob path validation below.
229
+ if (kind === "fts") {
230
+ const sc = enforceScope(auth.agent, { op: "read", workspaceId: ws.id });
231
+ if (!sc.ok) return errJson("FORBIDDEN", sc.message ?? "Forbidden", 403);
232
+
233
+ ensureIndexer(ws.id, rootDir).catch((e) =>
234
+ console.error("[search] ensureIndexer failed", e),
235
+ );
236
+
237
+ // Over-fetch so the post-filter (path scope + start-path restriction) can
238
+ // still return up to `limit` results when some top-ranked hits are denied.
239
+ const startPrefix = startRelRaw ? `${startRelRaw.replace(/\/+$/, "")}/` : "";
240
+ const fts = ftsSearch(ws.id, query, Math.min(limit * 4, HARD_MAX_MATCHES));
241
+ const filtered = fts.matches.filter((m) => {
242
+ if (startPrefix && !m.path.startsWith(startPrefix)) return false;
243
+ return enforceScope(auth.agent, { filePath: m.path, op: "read", workspaceId: ws.id }).ok;
244
+ });
245
+ const matches = filtered
246
+ .slice(0, limit)
247
+ .map((m) => ({ path: m.path, score: m.score, snippet: m.snippet }));
248
+ // truncated if the DB itself capped, or the scoped set still exceeds limit.
249
+ const truncated = fts.truncated || filtered.length > limit;
250
+ return NextResponse.json({ kind, query, matches, truncated });
251
+ }
252
+
217
253
  const deadline = Date.now() + SEARCH_TIMEOUT_MS;
218
254
  let result: { matches: SearchMatch[]; truncated: boolean };
219
255
 
220
256
  try {
221
257
  if (kind === "grep") {
222
- result = await grepSearch(rootDir, startRelRaw, query, limit, auth.agent, deadline);
258
+ result = await grepSearch(rootDir, startRelRaw, query, limit, auth.agent, deadline, ws.id);
223
259
  } else {
224
- result = await globSearch(rootDir, startRelRaw, query, limit, auth.agent, deadline);
260
+ result = await globSearch(rootDir, startRelRaw, query, limit, auth.agent, deadline, ws.id);
225
261
  }
226
262
  } catch (e) {
227
263
  return errJson("SEARCH_ERROR", (e as Error).message, 400);