wiki-viewer 1.7.2 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (414) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +6 -0
  3. package/.next/standalone/.next/build-manifest.json +3 -3
  4. package/.next/standalone/.next/prerender-manifest.json +3 -3
  5. package/.next/standalone/.next/routes-manifest.json +40 -0
  6. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  7. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  11. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  12. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  14. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  15. package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
  16. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  17. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  18. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  19. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  20. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  21. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  22. package/.next/standalone/.next/server/app/api/agent/activity/route.js +6 -6
  23. package/.next/standalone/.next/server/app/api/agent/activity/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/agent/admin/agents/[agentId]/revoke/route.js +6 -6
  25. package/.next/standalone/.next/server/app/api/agent/admin/agents/[agentId]/revoke/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/agent/admin/agents/route.js +6 -6
  27. package/.next/standalone/.next/server/app/api/agent/admin/agents/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/agent/admin/registrations/[regId]/approve/route.js +7 -7
  29. package/.next/standalone/.next/server/app/api/agent/admin/registrations/[regId]/approve/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/agent/admin/registrations/[regId]/deny/route.js +5 -5
  31. package/.next/standalone/.next/server/app/api/agent/admin/registrations/[regId]/deny/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/agent/admin/registrations/route.js +5 -5
  33. package/.next/standalone/.next/server/app/api/agent/admin/registrations/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/agent/events/[...path]/route.js +8 -7
  35. package/.next/standalone/.next/server/app/api/agent/events/[...path]/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/agent/files/[...path]/route.js +9 -8
  37. package/.next/standalone/.next/server/app/api/agent/files/[...path]/route.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js +8 -7
  39. package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route.js +7 -7
  41. package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/api/agent/fs/move/route.js +6 -5
  43. package/.next/standalone/.next/server/app/api/agent/fs/move/route.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/api/agent/fs/search/route.js +7 -6
  45. package/.next/standalone/.next/server/app/api/agent/fs/search/route.js.nft.json +1 -1
  46. package/.next/standalone/.next/server/app/api/agent/internal/span/route.js +6 -5
  47. package/.next/standalone/.next/server/app/api/agent/internal/span/route.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/api/agent/settings/route.js +7 -7
  49. package/.next/standalone/.next/server/app/api/agent/settings/route.js.nft.json +1 -1
  50. package/.next/standalone/.next/server/app/api/agent/sidecar/[...path]/route.js +8 -7
  51. package/.next/standalone/.next/server/app/api/agent/sidecar/[...path]/route.js.nft.json +1 -1
  52. package/.next/standalone/.next/server/app/api/app-proxy/[...path]/route.js +2 -2
  53. package/.next/standalone/.next/server/app/api/app-proxy/[...path]/route.js.nft.json +1 -1
  54. package/.next/standalone/.next/server/app/api/assets/[...path]/route.js +8 -2
  55. package/.next/standalone/.next/server/app/api/assets/[...path]/route.js.nft.json +1 -1
  56. package/.next/standalone/.next/server/app/api/auth/[...all]/route.js +5 -5
  57. package/.next/standalone/.next/server/app/api/auth/[...all]/route.js.nft.json +1 -1
  58. package/.next/standalone/.next/server/app/api/system/admins/route/app-paths-manifest.json +3 -0
  59. package/.next/standalone/.next/server/app/api/system/admins/route/build-manifest.json +9 -0
  60. package/.next/standalone/.next/server/app/api/system/admins/route/server-reference-manifest.json +4 -0
  61. package/.next/standalone/.next/server/app/api/system/admins/route.js +14 -0
  62. package/.next/standalone/.next/server/app/api/system/admins/route.js.map +5 -0
  63. package/.next/standalone/.next/server/app/api/system/admins/route.js.nft.json +1 -0
  64. package/.next/standalone/.next/server/app/api/system/admins/route_client-reference-manifest.js +3 -0
  65. package/.next/standalone/.next/server/app/api/system/auth-config/route.js +6 -6
  66. package/.next/standalone/.next/server/app/api/system/auth-config/route.js.nft.json +1 -1
  67. package/.next/standalone/.next/server/app/api/system/auth-settings/route.js +4 -4
  68. package/.next/standalone/.next/server/app/api/system/auth-settings/route.js.nft.json +1 -1
  69. package/.next/standalone/.next/server/app/api/system/browse/route.js +4 -4
  70. package/.next/standalone/.next/server/app/api/system/browse/route.js.nft.json +1 -1
  71. package/.next/standalone/.next/server/app/api/system/clear-root/route.js +5 -5
  72. package/.next/standalone/.next/server/app/api/system/clear-root/route.js.nft.json +1 -1
  73. package/.next/standalone/.next/server/app/api/system/config/route.js +6 -6
  74. package/.next/standalone/.next/server/app/api/system/config/route.js.nft.json +1 -1
  75. package/.next/standalone/.next/server/app/api/system/pins/route.js +4 -4
  76. package/.next/standalone/.next/server/app/api/system/pins/route.js.nft.json +1 -1
  77. package/.next/standalone/.next/server/app/api/system/reveal/route.js +6 -6
  78. package/.next/standalone/.next/server/app/api/system/reveal/route.js.nft.json +1 -1
  79. package/.next/standalone/.next/server/app/api/system/root-status/route.js +5 -5
  80. package/.next/standalone/.next/server/app/api/system/root-status/route.js.nft.json +1 -1
  81. package/.next/standalone/.next/server/app/api/system/set-root/route.js +6 -6
  82. package/.next/standalone/.next/server/app/api/system/set-root/route.js.nft.json +1 -1
  83. package/.next/standalone/.next/server/app/api/system/users/route/app-paths-manifest.json +3 -0
  84. package/.next/standalone/.next/server/app/api/system/users/route/build-manifest.json +9 -0
  85. package/.next/standalone/.next/server/app/api/system/users/route/server-reference-manifest.json +4 -0
  86. package/.next/standalone/.next/server/app/api/system/users/route.js +14 -0
  87. package/.next/standalone/.next/server/app/api/system/users/route.js.map +5 -0
  88. package/.next/standalone/.next/server/app/api/system/users/route.js.nft.json +1 -0
  89. package/.next/standalone/.next/server/app/api/system/users/route_client-reference-manifest.js +3 -0
  90. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route/app-paths-manifest.json +3 -0
  91. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route/build-manifest.json +9 -0
  92. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route/server-reference-manifest.json +4 -0
  93. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route.js +14 -0
  94. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route.js.map +5 -0
  95. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route.js.nft.json +1 -0
  96. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route_client-reference-manifest.js +3 -0
  97. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route/app-paths-manifest.json +3 -0
  98. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route/build-manifest.json +9 -0
  99. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route/server-reference-manifest.json +4 -0
  100. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route.js +14 -0
  101. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route.js.map +5 -0
  102. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route.js.nft.json +1 -0
  103. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route_client-reference-manifest.js +3 -0
  104. package/.next/standalone/.next/server/app/api/system/workspaces/route/app-paths-manifest.json +3 -0
  105. package/.next/standalone/.next/server/app/api/system/workspaces/route/build-manifest.json +9 -0
  106. package/.next/standalone/.next/server/app/api/system/workspaces/route/server-reference-manifest.json +4 -0
  107. package/.next/standalone/.next/server/app/api/system/workspaces/route.js +14 -0
  108. package/.next/standalone/.next/server/app/api/system/workspaces/route.js.map +5 -0
  109. package/.next/standalone/.next/server/app/api/system/workspaces/route.js.nft.json +1 -0
  110. package/.next/standalone/.next/server/app/api/system/workspaces/route_client-reference-manifest.js +3 -0
  111. package/.next/standalone/.next/server/app/api/upload/[...path]/route.js +8 -2
  112. package/.next/standalone/.next/server/app/api/upload/[...path]/route.js.nft.json +1 -1
  113. package/.next/standalone/.next/server/app/api/wiki/app/route.js +5 -5
  114. package/.next/standalone/.next/server/app/api/wiki/app/route.js.nft.json +1 -1
  115. package/.next/standalone/.next/server/app/api/wiki/content/route.js +6 -6
  116. package/.next/standalone/.next/server/app/api/wiki/content/route.js.nft.json +1 -1
  117. package/.next/standalone/.next/server/app/api/wiki/download/route.js +7 -7
  118. package/.next/standalone/.next/server/app/api/wiki/download/route.js.nft.json +1 -1
  119. package/.next/standalone/.next/server/app/api/wiki/file/route.js +8 -2
  120. package/.next/standalone/.next/server/app/api/wiki/file/route.js.nft.json +1 -1
  121. package/.next/standalone/.next/server/app/api/wiki/folder/route.js +6 -6
  122. package/.next/standalone/.next/server/app/api/wiki/folder/route.js.nft.json +1 -1
  123. package/.next/standalone/.next/server/app/api/wiki/move/route.js +6 -6
  124. package/.next/standalone/.next/server/app/api/wiki/move/route.js.nft.json +1 -1
  125. package/.next/standalone/.next/server/app/api/wiki/new-file/route.js +7 -7
  126. package/.next/standalone/.next/server/app/api/wiki/new-file/route.js.nft.json +1 -1
  127. package/.next/standalone/.next/server/app/api/wiki/page/route.js +7 -7
  128. package/.next/standalone/.next/server/app/api/wiki/page/route.js.nft.json +1 -1
  129. package/.next/standalone/.next/server/app/api/wiki/presence/route.js +7 -7
  130. package/.next/standalone/.next/server/app/api/wiki/presence/route.js.nft.json +1 -1
  131. package/.next/standalone/.next/server/app/api/wiki/route.js +6 -6
  132. package/.next/standalone/.next/server/app/api/wiki/route.js.nft.json +1 -1
  133. package/.next/standalone/.next/server/app/api/wiki/search/route/app-paths-manifest.json +3 -0
  134. package/.next/standalone/.next/server/app/api/wiki/search/route/build-manifest.json +9 -0
  135. package/.next/standalone/.next/server/app/api/wiki/search/route/server-reference-manifest.json +4 -0
  136. package/.next/standalone/.next/server/app/api/wiki/search/route.js +15 -0
  137. package/.next/standalone/.next/server/app/api/wiki/search/route.js.map +5 -0
  138. package/.next/standalone/.next/server/app/api/wiki/search/route.js.nft.json +1 -0
  139. package/.next/standalone/.next/server/app/api/wiki/search/route_client-reference-manifest.js +3 -0
  140. package/.next/standalone/.next/server/app/api/wiki/slugs/route.js +6 -6
  141. package/.next/standalone/.next/server/app/api/wiki/slugs/route.js.nft.json +1 -1
  142. package/.next/standalone/.next/server/app/api/wiki/upload/route.js +7 -7
  143. package/.next/standalone/.next/server/app/api/wiki/upload/route.js.nft.json +1 -1
  144. package/.next/standalone/.next/server/app/api/wiki/watch/route.js +7 -9
  145. package/.next/standalone/.next/server/app/api/wiki/watch/route.js.nft.json +1 -1
  146. package/.next/standalone/.next/server/app/index.html +1 -1
  147. package/.next/standalone/.next/server/app/index.rsc +3 -3
  148. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  149. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
  150. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  151. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
  152. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  153. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  154. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  155. package/.next/standalone/.next/server/app/signin/page.js +1 -1
  156. package/.next/standalone/.next/server/app/signin/page.js.nft.json +1 -1
  157. package/.next/standalone/.next/server/app/signin/page_client-reference-manifest.js +1 -1
  158. package/.next/standalone/.next/server/app-paths-manifest.json +6 -0
  159. package/.next/standalone/.next/server/chunks/0p91_next_dist_esm_build_templates_app-route_0d2jbo5.js +1 -1
  160. package/.next/standalone/.next/server/chunks/0p91_next_dist_esm_build_templates_app-route_0ytral2.js +1 -1
  161. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-244bv._.js +16 -0
  162. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0xz-_0v._.js → [root-of-the-server]__0-inabx._.js} +2 -2
  163. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0-ao6a_._.js → [root-of-the-server]__0.-9jt0._.js} +1 -1
  164. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0~-r-8f._.js → [root-of-the-server]__00c1-dr._.js} +1 -1
  165. package/.next/standalone/.next/server/chunks/[root-of-the-server]__00lep-u._.js +3 -0
  166. package/.next/standalone/.next/server/chunks/[root-of-the-server]__00mtevo._.js +3 -0
  167. package/.next/standalone/.next/server/chunks/[root-of-the-server]__00qu86p._.js +3 -0
  168. package/.next/standalone/.next/server/chunks/[root-of-the-server]__012753j._.js +3 -0
  169. package/.next/standalone/.next/server/chunks/[root-of-the-server]__01hp8ax._.js +3 -0
  170. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0jhr.ex._.js → [root-of-the-server]__02n6z97._.js} +1 -1
  171. package/.next/standalone/.next/server/chunks/[root-of-the-server]__036mhjp._.js +5 -0
  172. package/.next/standalone/.next/server/chunks/[root-of-the-server]__03p0ob1._.js +16 -0
  173. package/.next/standalone/.next/server/chunks/[root-of-the-server]__05t~v6l._.js +3 -0
  174. package/.next/standalone/.next/server/chunks/[root-of-the-server]__068ni_k._.js +3 -0
  175. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__082nhm6._.js → [root-of-the-server]__07vphbd._.js} +1 -1
  176. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0pg6dn-._.js → [root-of-the-server]__08lkuwa._.js} +1 -1
  177. package/.next/standalone/.next/server/chunks/[root-of-the-server]__09cqzem._.js +3 -0
  178. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0p_ox-k._.js → [root-of-the-server]__09k4q9e._.js} +1 -1
  179. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0_601._.js +3 -0
  180. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ae3dk6._.js +3 -0
  181. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0s28.4-._.js → [root-of-the-server]__0af-x45._.js} +1 -1
  182. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cqu-wm._.js +3 -0
  183. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d75a5q._.js +1 -1
  184. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d7x3e1._.js +3 -0
  185. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d7zxm_._.js +3 -0
  186. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e7vs98._.js +3 -0
  187. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0fxzg4v._.js +3 -0
  188. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0gda_iu._.js +3 -0
  189. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0hu~q20._.js +3 -0
  190. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0jk1uf4._.js +3 -0
  191. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0l-8clq._.js +3 -0
  192. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0lhka0x._.js +3 -0
  193. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0kdn1le._.js → [root-of-the-server]__0na11h0._.js} +2 -2
  194. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0nd.b_c._.js +3 -0
  195. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0otb8ra._.js +3 -0
  196. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0p0-p__._.js +3 -0
  197. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0piofm3._.js +3 -0
  198. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0rrf-jr._.js +3 -0
  199. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0s6_lzw._.js +3 -0
  200. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0sh13v5._.js +3 -0
  201. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ta~flu._.js +3 -0
  202. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0v4im4p._.js +3 -0
  203. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0qn8e~s._.js → [root-of-the-server]__0v_kyp-._.js} +1 -1
  204. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0vatqe-._.js +3 -0
  205. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0vdb2nr._.js +3 -0
  206. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0wdh63w._.js +3 -0
  207. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0z3wg9x._.js +12 -0
  208. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0mzo03s._.js → [root-of-the-server]__0~.-3yk._.js} +1 -1
  209. package/.next/standalone/.next/server/chunks/[root-of-the-server]__123._fe._.js +3 -0
  210. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__12800b1._.js → [root-of-the-server]__12ee_s6._.js} +1 -1
  211. package/.next/standalone/.next/server/chunks/[root-of-the-server]__12onytt._.js +3 -0
  212. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__04udrya._.js → [root-of-the-server]__12q8ch8._.js} +2 -2
  213. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1377.79._.js +3 -0
  214. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1378-ox._.js +3 -0
  215. package/.next/standalone/.next/server/chunks/[root-of-the-server]__13aid91._.js +3 -0
  216. package/.next/standalone/.next/server/chunks/[root-of-the-server]__13hp4tw._.js +12 -0
  217. package/.next/standalone/.next/server/chunks/_079xuln._.js +1 -1
  218. package/.next/standalone/.next/server/chunks/_0dr1r1g._.js +452 -0
  219. package/.next/standalone/.next/server/chunks/_101exke._.js +452 -0
  220. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_system_admins_route_actions_0dsm7cx.js +3 -0
  221. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_system_users_route_actions_0whj5cy.js +3 -0
  222. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_system_workspaces_[id]_open_route_actions_1087xu7.js +3 -0
  223. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_system_workspaces_[id]_route_actions_0~h7-8s.js +3 -0
  224. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_system_workspaces_route_actions_0mkalc3.js +3 -0
  225. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_wiki_search_route_actions_0inxu93.js +3 -0
  226. package/.next/standalone/.next/server/chunks/node_modules__pnpm_0aj5g-w._.js +1 -1
  227. package/.next/standalone/.next/server/chunks/src_lib_search_0d-_j3u._.js +46 -0
  228. package/.next/standalone/.next/server/chunks/src_lib_search_0ymmp0c._.js +46 -0
  229. 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
  230. package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_erDiagram-TEJ5UH35_mjs_0v6rnqy._.js +1 -1
  231. package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_mermaid_core_mjs_0hj_n-~._.js +1 -1
  232. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0btcd4o._.js → [root-of-the-server]__02twzph._.js} +2 -2
  233. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0ytvlzs._.js → [root-of-the-server]__09~x2v~._.js} +2 -2
  234. package/.next/standalone/.next/server/chunks/ssr/_0pqaawz._.js +18 -18
  235. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0c71i8a._.js → node_modules__pnpm_0.96tmo._.js} +1 -1
  236. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0lm8e2c._.js → node_modules__pnpm_011vy_q._.js} +2 -2
  237. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0ezm2us._.js → node_modules__pnpm_01o_5qt._.js} +1 -1
  238. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0j3mvgg._.js → node_modules__pnpm_04n0h6.._.js} +1 -1
  239. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0~ln0by._.js → node_modules__pnpm_093dp2q._.js} +1 -1
  240. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_11e~j49._.js → node_modules__pnpm_09ej62_._.js} +1 -1
  241. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0de8xt-._.js → node_modules__pnpm_09ljbdz._.js} +2 -2
  242. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0-x6zex._.js → node_modules__pnpm_09~_ob2._.js} +1 -1
  243. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0yq5z.h._.js → node_modules__pnpm_0a01ng7._.js} +2 -2
  244. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0kwc-vs._.js → node_modules__pnpm_0b8qx0g._.js} +1 -1
  245. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0hrbz84._.js → node_modules__pnpm_0bbc---._.js} +1 -1
  246. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0hobcbs._.js → node_modules__pnpm_0c.309.._.js} +1 -1
  247. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0rw91-f._.js → node_modules__pnpm_0c8aunj._.js} +1 -1
  248. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0o.c1z8._.js → node_modules__pnpm_0hk6xys._.js} +2 -2
  249. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0dboa_e._.js → node_modules__pnpm_0hlzy8f._.js} +1 -1
  250. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0j53hti._.js → node_modules__pnpm_0nw5ou2._.js} +1 -1
  251. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0xrmzh1._.js → node_modules__pnpm_0o.dn8o._.js} +1 -1
  252. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0cxwhfd._.js → node_modules__pnpm_0s0ur~d._.js} +1 -1
  253. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_07rxv2x._.js → node_modules__pnpm_0shlang._.js} +1 -1
  254. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0i.pw_m._.js → node_modules__pnpm_0sq3c2r._.js} +1 -1
  255. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0ajzar9._.js → node_modules__pnpm_0t9jb7d._.js} +1 -1
  256. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_012nt.s._.js → node_modules__pnpm_0wmx9kq._.js} +2 -2
  257. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0z~h2ow._.js → node_modules__pnpm_0xfx0sf._.js} +1 -1
  258. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0cbsnwf._.js → node_modules__pnpm_0yiz.-t._.js} +1 -1
  259. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0bum3-3._.js → node_modules__pnpm_11sut1u._.js} +1 -1
  260. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0mdo4i3._.js → node_modules__pnpm_124u4o2._.js} +2 -2
  261. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0il8j.j._.js → node_modules__pnpm_13tajgx._.js} +2 -2
  262. package/.next/standalone/.next/server/chunks/ssr/src_app_signin_00yk0vm._.js +2 -2
  263. 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
  264. package/.next/standalone/.next/server/edge/chunks/[root-of-the-server]__0.pmgt2._.js +3 -0
  265. package/.next/standalone/.next/server/functions-config-manifest.json +6 -0
  266. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  267. package/.next/standalone/.next/server/middleware-manifest.json +8 -8
  268. package/.next/standalone/.next/server/pages/404.html +1 -1
  269. package/.next/standalone/.next/server/pages/500.html +1 -1
  270. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  271. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  272. package/.next/standalone/.next/static/chunks/0c_~zevf2n0r4.css +2 -0
  273. package/.next/standalone/.next/static/chunks/0l4842ez-0_66.js +129 -0
  274. package/.next/standalone/README.md +46 -2
  275. package/.next/standalone/docs/workspacing-plan.md +364 -0
  276. package/.next/standalone/package.json +2 -2
  277. package/.next/standalone/src/app/api/agent/activity/route.ts +9 -8
  278. package/.next/standalone/src/app/api/agent/events/[...path]/route.ts +20 -8
  279. package/.next/standalone/src/app/api/agent/files/[...path]/route.ts +16 -9
  280. package/.next/standalone/src/app/api/agent/fs/file/[...path]/route.ts +28 -18
  281. package/.next/standalone/src/app/api/agent/fs/ls/[[...path]]/route.ts +12 -7
  282. package/.next/standalone/src/app/api/agent/fs/move/route.ts +16 -11
  283. package/.next/standalone/src/app/api/agent/fs/search/route.ts +49 -13
  284. package/.next/standalone/src/app/api/agent/internal/span/route.ts +9 -5
  285. package/.next/standalone/src/app/api/agent/register/route.ts +9 -1
  286. package/.next/standalone/src/app/api/agent/settings/route.ts +7 -3
  287. package/.next/standalone/src/app/api/agent/sidecar/[...path]/route.ts +8 -4
  288. package/.next/standalone/src/app/api/assets/[...path]/route.ts +9 -4
  289. package/.next/standalone/src/app/api/system/admins/route.ts +103 -0
  290. package/.next/standalone/src/app/api/system/reveal/route.ts +7 -6
  291. package/.next/standalone/src/app/api/system/set-root/route.ts +24 -1
  292. package/.next/standalone/src/app/api/system/users/route.ts +120 -0
  293. package/.next/standalone/src/app/api/system/workspaces/[id]/open/route.ts +34 -0
  294. package/.next/standalone/src/app/api/system/workspaces/[id]/route.ts +74 -0
  295. package/.next/standalone/src/app/api/system/workspaces/route.ts +67 -0
  296. package/.next/standalone/src/app/api/upload/[...path]/route.ts +10 -5
  297. package/.next/standalone/src/app/api/wiki/app/route.ts +10 -9
  298. package/.next/standalone/src/app/api/wiki/content/route.ts +14 -14
  299. package/.next/standalone/src/app/api/wiki/download/route.ts +7 -6
  300. package/.next/standalone/src/app/api/wiki/file/route.ts +7 -2
  301. package/.next/standalone/src/app/api/wiki/folder/route.ts +6 -5
  302. package/.next/standalone/src/app/api/wiki/move/route.ts +7 -7
  303. package/.next/standalone/src/app/api/wiki/new-file/route.ts +7 -6
  304. package/.next/standalone/src/app/api/wiki/page/route.ts +6 -5
  305. package/.next/standalone/src/app/api/wiki/presence/route.ts +8 -7
  306. package/.next/standalone/src/app/api/wiki/route.ts +13 -11
  307. package/.next/standalone/src/app/api/wiki/search/route.ts +44 -0
  308. package/.next/standalone/src/app/api/wiki/slugs/route.ts +8 -8
  309. package/.next/standalone/src/app/api/wiki/upload/route.ts +6 -5
  310. package/.next/standalone/src/app/api/wiki/watch/route.ts +16 -40
  311. package/.next/standalone/src/app/globals.css +484 -484
  312. package/.next/standalone/src/app/page.tsx +163 -49
  313. package/.next/standalone/src/components/auth-settings-sheet.tsx +171 -2
  314. package/.next/standalone/src/components/dir-picker.tsx +8 -6
  315. package/.next/standalone/src/components/editor/comment-thread.tsx +2 -1
  316. package/.next/standalone/src/components/editor/csv-viewer.tsx +3 -2
  317. package/.next/standalone/src/components/editor/editor-toolbar.tsx +2 -2
  318. package/.next/standalone/src/components/editor/editor.tsx +6 -5
  319. package/.next/standalone/src/components/editor/file-fallback-viewer.tsx +3 -2
  320. package/.next/standalone/src/components/editor/folder-index.tsx +2 -1
  321. package/.next/standalone/src/components/editor/image-viewer.tsx +2 -1
  322. package/.next/standalone/src/components/editor/media-popover.tsx +2 -1
  323. package/.next/standalone/src/components/editor/media-viewer.tsx +2 -1
  324. package/.next/standalone/src/components/editor/mermaid-viewer.tsx +3 -2
  325. package/.next/standalone/src/components/editor/node-app-viewer.tsx +4 -3
  326. package/.next/standalone/src/components/editor/notebook-viewer.tsx +3 -2
  327. package/.next/standalone/src/components/editor/office/docx-viewer.tsx +2 -1
  328. package/.next/standalone/src/components/editor/office/office-chrome.tsx +3 -2
  329. package/.next/standalone/src/components/editor/office/pptx-viewer.tsx +2 -1
  330. package/.next/standalone/src/components/editor/office/xlsx-viewer.tsx +2 -1
  331. package/.next/standalone/src/components/editor/pdf-viewer.tsx +2 -1
  332. package/.next/standalone/src/components/editor/proof-span-popover.tsx +2 -1
  333. package/.next/standalone/src/components/editor/source-viewer.tsx +3 -2
  334. package/.next/standalone/src/components/editor/suggest-edit-popover.tsx +2 -1
  335. package/.next/standalone/src/components/editor/suggestion-card.tsx +2 -1
  336. package/.next/standalone/src/components/editor/website-viewer.tsx +2 -1
  337. package/.next/standalone/src/components/editor/wiki-link-create-dialog.tsx +2 -1
  338. package/.next/standalone/src/components/search/search-command-dialog.tsx +109 -0
  339. package/.next/standalone/src/components/search/sidebar-search-box.tsx +121 -0
  340. package/.next/standalone/src/components/search/snippet-text.tsx +48 -0
  341. package/.next/standalone/src/components/ui/command.tsx +3 -2
  342. package/.next/standalone/src/lib/auth/admin.ts +112 -0
  343. package/.next/standalone/src/lib/auth/server.ts +13 -2
  344. package/.next/standalone/src/lib/config.ts +56 -4
  345. package/.next/standalone/src/lib/proof/audit.ts +19 -10
  346. package/.next/standalone/src/lib/proof/auth.ts +11 -0
  347. package/.next/standalone/src/lib/proof/collab-state.ts +4 -2
  348. package/.next/standalone/src/lib/proof/file-lock.ts +5 -0
  349. package/.next/standalone/src/lib/proof/idempotency.ts +5 -0
  350. package/.next/standalone/src/lib/proof/lease.ts +40 -27
  351. package/.next/standalone/src/lib/proof/mutex.ts +4 -0
  352. package/.next/standalone/src/lib/proof/raw-fs.ts +2 -3
  353. package/.next/standalone/src/lib/proof/registry.ts +5 -0
  354. package/.next/standalone/src/lib/search/indexable-exts.ts +25 -0
  355. package/.next/standalone/src/lib/search/indexer.ts +567 -0
  356. package/.next/standalone/src/lib/search/sanitize.ts +35 -0
  357. package/.next/standalone/src/lib/search/search-db.ts +57 -0
  358. package/.next/standalone/src/lib/search/watcher-pool.ts +79 -0
  359. package/.next/standalone/src/lib/workspace-client.ts +82 -0
  360. package/.next/standalone/src/lib/workspace-context.ts +142 -0
  361. package/.next/standalone/src/lib/workspaces.ts +196 -0
  362. package/.next/standalone/src/stores/ai-panel-store.ts +3 -2
  363. package/.next/standalone/src/stores/editor-store.ts +4 -3
  364. package/.next/standalone/src/stores/proof-store.ts +4 -3
  365. package/.next/standalone/src/stores/search-store.ts +86 -0
  366. package/.next/standalone/src/stores/wiki-slugs-store.ts +2 -1
  367. package/.next/standalone/src/tests/proof/admin-create-user.test.ts +43 -0
  368. package/.next/standalone/src/tests/proof/agent-workspace-scope.test.ts +134 -0
  369. package/.next/standalone/src/tests/proof/collab-state.test.ts +43 -41
  370. package/.next/standalone/src/tests/proof/preload.ts +21 -0
  371. package/.next/standalone/src/tests/proof/search-index.test.ts +339 -0
  372. package/.next/standalone/src/tests/proof/workspace-isolation.test.ts +87 -0
  373. package/.next/standalone/src/tests/proof/workspaces-api.test.ts +227 -0
  374. package/.next/standalone/tsconfig.tsbuildinfo +1 -1
  375. package/README.md +46 -2
  376. package/package.json +2 -2
  377. package/.next/standalone/.next/server/chunks/0p91_next_dist_esm_build_templates_app-route_0o~h4zq.js +0 -5
  378. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0.hb9q2._.js +0 -3
  379. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0.uux34._.js +0 -3
  380. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0092hkp._.js +0 -3
  381. package/.next/standalone/.next/server/chunks/[root-of-the-server]__05f6x0i._.js +0 -3
  382. package/.next/standalone/.next/server/chunks/[root-of-the-server]__05idwm9._.js +0 -3
  383. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06-dtd0._.js +0 -3
  384. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06sek6_._.js +0 -3
  385. package/.next/standalone/.next/server/chunks/[root-of-the-server]__07fpqks._.js +0 -3
  386. package/.next/standalone/.next/server/chunks/[root-of-the-server]__094q5bj._.js +0 -3
  387. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0awzyon._.js +0 -3
  388. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d_da6q._.js +0 -3
  389. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0hhhvm7._.js +0 -3
  390. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0kk26wc._.js +0 -3
  391. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0km8suj._.js +0 -3
  392. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0kur4ro._.js +0 -15
  393. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0mkwoul._.js +0 -12
  394. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0qc2~6l._.js +0 -15
  395. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0qyd-o8._.js +0 -3
  396. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0rkve~v._.js +0 -3
  397. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0rzo40z._.js +0 -3
  398. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0sjocwy._.js +0 -3
  399. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ssj9~d._.js +0 -3
  400. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0s~i040._.js +0 -3
  401. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t220d-._.js +0 -3
  402. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0t5mg.n._.js +0 -3
  403. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0trsqf4._.js +0 -3
  404. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0xq124z._.js +0 -3
  405. package/.next/standalone/.next/server/chunks/[root-of-the-server]__106uw_c._.js +0 -3
  406. package/.next/standalone/.next/server/chunks/[root-of-the-server]__10w2q~o._.js +0 -3
  407. package/.next/standalone/.next/server/chunks/[root-of-the-server]__13w-0iy._.js +0 -3
  408. package/.next/standalone/.next/server/chunks/src_lib_auth_server_ts_00f4e0h._.js +0 -452
  409. package/.next/standalone/.next/server/edge/chunks/[root-of-the-server]__0ug2rvl._.js +0 -3
  410. package/.next/standalone/.next/static/chunks/0vwkqw_rofm-c.js +0 -129
  411. package/.next/standalone/.next/static/chunks/0zay6349~v_wc.css +0 -2
  412. /package/.next/standalone/.next/static/{0XvNCOSEq7cbARTLtAolL → t7B6nXaoD1jo9f61t3aeK}/_buildManifest.js +0 -0
  413. /package/.next/standalone/.next/static/{0XvNCOSEq7cbARTLtAolL → t7B6nXaoD1jo9f61t3aeK}/_clientMiddlewareManifest.js +0 -0
  414. /package/.next/standalone/.next/static/{0XvNCOSEq7cbARTLtAolL → t7B6nXaoD1jo9f61t3aeK}/_ssgManifest.js +0 -0
@@ -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);
@@ -8,7 +8,8 @@ import { revertProofSpan } from "@/lib/proof/proof-span";
8
8
  import { readSidecar, writeSidecar, emptySidecar } from "@/lib/proof/sidecar";
9
9
  import { withFileMutex } from "@/lib/proof/mutex";
10
10
  import { emitEvents } from "@/lib/proof/event-bus";
11
- import { getRootDir, safeRootPath } from "@/lib/root-dir";
11
+ import { resolveWorkspaceForAgent } from "@/lib/workspace-context";
12
+ import { safeWorkspacePath } from "@/lib/workspaces";
12
13
  import { checkAuth, enforceScope } from "@/lib/proof/auth";
13
14
 
14
15
  export const runtime = "nodejs";
@@ -63,22 +64,25 @@ export async function POST(req: Request): Promise<NextResponse> {
63
64
  return NextResponse.json({ error: "INVALID_PATH", message: "Path must be .md or .markdown" }, { status: 400 });
64
65
  }
65
66
 
66
- const absPath = safeRootPath(rel);
67
+ const wsx = await resolveWorkspaceForAgent(req);
68
+ if (!wsx.ok) return NextResponse.json({ error: wsx.code }, { status: wsx.status });
69
+ const { ws, rootDir } = wsx;
70
+
71
+ const absPath = safeWorkspacePath(rootDir, rel);
67
72
  if (!absPath) {
68
73
  return NextResponse.json({ error: "INVALID_PATH", message: "Path traversal rejected" }, { status: 400 });
69
74
  }
70
75
 
71
- const scopeCheck = enforceScope(authResult.agent, { filePath: rel, op: "mutate" });
76
+ const scopeCheck = enforceScope(authResult.agent, { filePath: rel, op: "mutate", workspaceId: ws.id });
72
77
  if (!scopeCheck.ok) {
73
78
  return NextResponse.json({ error: scopeCheck.code, message: scopeCheck.message }, { status: 403 });
74
79
  }
75
80
 
76
- const rootDir = getRootDir();
77
81
  const actorId = authResult.agent.id;
78
82
 
79
83
  let notFound = false;
80
84
  try {
81
- await withFileMutex(rel, async () => {
85
+ await withFileMutex(`${rootDir}\u0000${rel}`, async () => {
82
86
  let content: string;
83
87
  try {
84
88
  content = await readFile(absPath, "utf-8");
@@ -31,7 +31,15 @@ function validateScope(s: Record<string, unknown>): AgentScope | { error: string
31
31
  return { error: `scope.ops values must be "read", "mutate", or "delete"` };
32
32
  }
33
33
  }
34
- return { paths: s.paths as string[], ops: s.ops as Array<"read" | "mutate" | "delete"> };
34
+ // Optional workspaceId: if present must be a non-empty string 64 chars.
35
+ let workspaceId: string | undefined;
36
+ if (s.workspaceId !== undefined) {
37
+ if (typeof s.workspaceId !== "string" || s.workspaceId.length < 1 || s.workspaceId.length > 64) {
38
+ return { error: "scope.workspaceId must be a string of 1\u201364 characters" };
39
+ }
40
+ workspaceId = s.workspaceId;
41
+ }
42
+ return { paths: s.paths as string[], ops: s.ops as Array<"read" | "mutate" | "delete">, ...(workspaceId !== undefined ? { workspaceId } : {}) };
35
43
  }
36
44
 
37
45
  /** Exported for reuse in approve route. */
@@ -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 { readRegistry } from "@/lib/proof/registry";
5
5
  import { listPendingRegistrations } from "@/lib/proof/pending";
6
6
 
@@ -12,7 +12,11 @@ export async function GET(req: Request): Promise<NextResponse> {
12
12
  return NextResponse.json({ error: "UNAUTHORIZED" }, { status: 401 });
13
13
  }
14
14
 
15
- const scopeCheck = enforceScope(auth.agent, { op: "read" });
15
+ const wsx = await resolveWorkspaceForAgent(req);
16
+ if (!wsx.ok) return NextResponse.json({ error: wsx.code }, { status: wsx.status });
17
+ const { ws, rootDir } = wsx;
18
+
19
+ const scopeCheck = enforceScope(auth.agent, { op: "read", workspaceId: ws.id });
16
20
  if (!scopeCheck.ok) {
17
21
  return NextResponse.json({ error: scopeCheck.code, message: scopeCheck.message }, { status: 403 });
18
22
  }
@@ -23,7 +27,7 @@ export async function GET(req: Request): Promise<NextResponse> {
23
27
 
24
28
  return NextResponse.json({
25
29
  rateLimit: Number(process.env.AGENT_RATE_LIMIT) || 60,
26
- root: getRootDir(),
30
+ root: rootDir,
27
31
  registeredAgents,
28
32
  pendingRegistrations,
29
33
  });
@@ -1,7 +1,8 @@
1
1
  import { NextResponse } from "next/server";
2
2
  import { checkAuth, enforceScope } from "@/lib/proof/auth";
3
3
  import { readSidecar, emptySidecar } from "@/lib/proof/sidecar";
4
- import { getRootDir, safeRootPath } from "@/lib/root-dir";
4
+ import { resolveWorkspaceForAgent } from "@/lib/workspace-context";
5
+ import { safeWorkspacePath } from "@/lib/workspaces";
5
6
 
6
7
  export const runtime = "nodejs";
7
8
 
@@ -32,17 +33,20 @@ export async function GET(
32
33
  return NextResponse.json({ error: "INVALID_PATH", message: "Path must be .md or .markdown" }, { status: 400 });
33
34
  }
34
35
 
35
- const absPath = safeRootPath(rel);
36
+ const wsx = await resolveWorkspaceForAgent(req);
37
+ if (!wsx.ok) return NextResponse.json({ error: wsx.code }, { status: wsx.status });
38
+ const { ws, rootDir } = wsx;
39
+
40
+ const absPath = safeWorkspacePath(rootDir, rel);
36
41
  if (!absPath) {
37
42
  return NextResponse.json({ error: "INVALID_PATH", message: "Path traversal rejected" }, { status: 400 });
38
43
  }
39
44
 
40
- const scopeCheck = enforceScope(auth.agent, { filePath: rel, op: "read" });
45
+ const scopeCheck = enforceScope(auth.agent, { filePath: rel, op: "read", workspaceId: ws.id });
41
46
  if (!scopeCheck.ok) {
42
47
  return NextResponse.json({ error: scopeCheck.code, message: scopeCheck.message }, { status: 403 });
43
48
  }
44
49
 
45
- const rootDir = getRootDir();
46
50
  const sidecar = (await readSidecar(rootDir, rel)) ?? emptySidecar(rel);
47
51
 
48
52
  return NextResponse.json(sidecar);
@@ -1,7 +1,8 @@
1
1
  import { readFile, stat } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { NextResponse } from "next/server";
4
- import { getRootDir } from "@/lib/root-dir";
4
+ import { resolveWorkspaceForAgent } from "@/lib/workspace-context";
5
+ import { safeWorkspacePath } from "@/lib/workspaces";
5
6
 
6
7
  const MIME_MAP: Record<string, string> = {
7
8
  jpg: "image/jpeg",
@@ -38,15 +39,19 @@ const MIME_MAP: Record<string, string> = {
38
39
  };
39
40
 
40
41
  export async function GET(
41
- _request: Request,
42
+ request: Request,
42
43
  { params }: { params: Promise<{ path: string[] }> },
43
44
  ) {
45
+ const wsx = await resolveWorkspaceForAgent(request);
46
+ if (!wsx.ok) return NextResponse.json({ error: wsx.code }, { status: wsx.status });
47
+ const { rootDir } = wsx;
48
+
44
49
  const segments = (await params).path;
45
50
  const rel = segments.join("/");
46
51
 
47
52
  // Path traversal guard
48
- const resolved = path.resolve(getRootDir(), rel);
49
- if (resolved !== getRootDir() && !resolved.startsWith(getRootDir() + path.sep)) {
53
+ const resolved = safeWorkspacePath(rootDir, rel);
54
+ if (!resolved) {
50
55
  return NextResponse.json({ error: "Invalid path" }, { status: 400 });
51
56
  }
52
57