wiki-viewer 1.14.1 → 2.0.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 (559) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  4. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  5. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  6. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  7. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  10. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  11. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  12. package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
  13. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  14. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  15. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  16. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  17. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  18. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  19. package/.next/standalone/.next/server/app/api/agent/activity/route.js +6 -6
  20. package/.next/standalone/.next/server/app/api/agent/activity/route.js.nft.json +1 -1
  21. package/.next/standalone/.next/server/app/api/agent/events/[...path]/route.js +8 -8
  22. package/.next/standalone/.next/server/app/api/agent/events/[...path]/route.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/api/agent/files/[...path]/route.js +9 -9
  24. package/.next/standalone/.next/server/app/api/agent/files/[...path]/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js +8 -8
  26. package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route.js +8 -8
  28. package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/agent/fs/move/route.js +8 -8
  30. package/.next/standalone/.next/server/app/api/agent/fs/move/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/agent/fs/search/route.js +9 -9
  32. package/.next/standalone/.next/server/app/api/agent/fs/search/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/api/agent/internal/span/route.js +8 -8
  34. package/.next/standalone/.next/server/app/api/agent/internal/span/route.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/api/agent/settings/route.js +7 -7
  36. package/.next/standalone/.next/server/app/api/agent/settings/route.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/api/agent/sidecar/[...path]/route.js +6 -6
  38. package/.next/standalone/.next/server/app/api/agent/sidecar/[...path]/route.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/api/app-proxy/[...path]/route.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/api/assets/[...path]/route.js +5 -5
  41. package/.next/standalone/.next/server/app/api/assets/[...path]/route.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/api/share/[token]/route.js +6 -5
  43. package/.next/standalone/.next/server/app/api/share/[token]/route.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/api/share/route.js +4 -4
  45. package/.next/standalone/.next/server/app/api/share/route.js.nft.json +1 -1
  46. package/.next/standalone/.next/server/app/api/system/browse/route.js.nft.json +1 -1
  47. package/.next/standalone/.next/server/app/api/system/clear-root/route.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/api/system/reveal/route.js +6 -6
  49. package/.next/standalone/.next/server/app/api/system/reveal/route.js.nft.json +1 -1
  50. package/.next/standalone/.next/server/app/api/system/root-status/route.js.nft.json +1 -1
  51. package/.next/standalone/.next/server/app/api/system/set-root/route.js +6 -5
  52. package/.next/standalone/.next/server/app/api/system/set-root/route.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route.js +5 -4
  54. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route.js.nft.json +1 -1
  55. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/refresh/route.js +6 -5
  56. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/refresh/route.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route.js +5 -4
  58. package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route.js.nft.json +1 -1
  59. package/.next/standalone/.next/server/app/api/system/workspaces/route.js +7 -6
  60. package/.next/standalone/.next/server/app/api/system/workspaces/route.js.nft.json +1 -1
  61. package/.next/standalone/.next/server/app/api/upload/[...path]/route.js +5 -5
  62. package/.next/standalone/.next/server/app/api/upload/[...path]/route.js.nft.json +1 -1
  63. package/.next/standalone/.next/server/app/api/wiki/app/route.js +7 -7
  64. package/.next/standalone/.next/server/app/api/wiki/app/route.js.nft.json +1 -1
  65. package/.next/standalone/.next/server/app/api/wiki/backlinks/route.js +7 -7
  66. package/.next/standalone/.next/server/app/api/wiki/backlinks/route.js.nft.json +1 -1
  67. package/.next/standalone/.next/server/app/api/wiki/content/route.js +7 -7
  68. package/.next/standalone/.next/server/app/api/wiki/content/route.js.nft.json +1 -1
  69. package/.next/standalone/.next/server/app/api/wiki/download/route.js +6 -6
  70. package/.next/standalone/.next/server/app/api/wiki/download/route.js.nft.json +1 -1
  71. package/.next/standalone/.next/server/app/api/wiki/file/route.js +5 -5
  72. package/.next/standalone/.next/server/app/api/wiki/file/route.js.nft.json +1 -1
  73. package/.next/standalone/.next/server/app/api/wiki/folder/route.js +5 -5
  74. package/.next/standalone/.next/server/app/api/wiki/folder/route.js.nft.json +1 -1
  75. package/.next/standalone/.next/server/app/api/wiki/git-branches/route.js +4 -4
  76. package/.next/standalone/.next/server/app/api/wiki/git-branches/route.js.nft.json +1 -1
  77. package/.next/standalone/.next/server/app/api/wiki/git-checkout/route.js +6 -6
  78. package/.next/standalone/.next/server/app/api/wiki/git-checkout/route.js.nft.json +1 -1
  79. package/.next/standalone/.next/server/app/api/wiki/git-diff/route.js +4 -4
  80. package/.next/standalone/.next/server/app/api/wiki/git-diff/route.js.nft.json +1 -1
  81. package/.next/standalone/.next/server/app/api/wiki/git-file-info/route.js +4 -4
  82. package/.next/standalone/.next/server/app/api/wiki/git-file-info/route.js.nft.json +1 -1
  83. package/.next/standalone/.next/server/app/api/wiki/git-history/route.js +4 -4
  84. package/.next/standalone/.next/server/app/api/wiki/git-history/route.js.nft.json +1 -1
  85. package/.next/standalone/.next/server/app/api/wiki/git-pull/route.js +8 -8
  86. package/.next/standalone/.next/server/app/api/wiki/git-pull/route.js.nft.json +1 -1
  87. package/.next/standalone/.next/server/app/api/wiki/move/route.js +6 -6
  88. package/.next/standalone/.next/server/app/api/wiki/move/route.js.nft.json +1 -1
  89. package/.next/standalone/.next/server/app/api/wiki/new-file/route.js +5 -5
  90. package/.next/standalone/.next/server/app/api/wiki/new-file/route.js.nft.json +1 -1
  91. package/.next/standalone/.next/server/app/api/wiki/outlinks/route.js +7 -7
  92. package/.next/standalone/.next/server/app/api/wiki/outlinks/route.js.nft.json +1 -1
  93. package/.next/standalone/.next/server/app/api/wiki/page/route.js +5 -5
  94. package/.next/standalone/.next/server/app/api/wiki/page/route.js.nft.json +1 -1
  95. package/.next/standalone/.next/server/app/api/wiki/presence/route.js +6 -6
  96. package/.next/standalone/.next/server/app/api/wiki/presence/route.js.nft.json +1 -1
  97. package/.next/standalone/.next/server/app/api/wiki/route.js +5 -5
  98. package/.next/standalone/.next/server/app/api/wiki/route.js.nft.json +1 -1
  99. package/.next/standalone/.next/server/app/api/wiki/search/route.js +5 -5
  100. package/.next/standalone/.next/server/app/api/wiki/search/route.js.nft.json +1 -1
  101. package/.next/standalone/.next/server/app/api/wiki/slugs/route.js +5 -5
  102. package/.next/standalone/.next/server/app/api/wiki/slugs/route.js.nft.json +1 -1
  103. package/.next/standalone/.next/server/app/api/wiki/upload/route.js +5 -5
  104. package/.next/standalone/.next/server/app/api/wiki/upload/route.js.nft.json +1 -1
  105. package/.next/standalone/.next/server/app/api/wiki/watch/route.js +5 -5
  106. package/.next/standalone/.next/server/app/api/wiki/watch/route.js.nft.json +1 -1
  107. package/.next/standalone/.next/server/app/index.html +1 -1
  108. package/.next/standalone/.next/server/app/index.rsc +3 -3
  109. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  110. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
  111. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  112. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
  113. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  114. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  115. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  116. package/.next/standalone/.next/server/app/s/[token]/page_client-reference-manifest.js +1 -1
  117. package/.next/standalone/.next/server/app/signin/page_client-reference-manifest.js +1 -1
  118. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-jzw2_._.js +3 -0
  119. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0.-oq-7._.js +3 -0
  120. package/.next/standalone/.next/server/chunks/[root-of-the-server]__000spch._.js +3 -0
  121. package/.next/standalone/.next/server/chunks/[root-of-the-server]__01oin-a._.js +3 -0
  122. package/.next/standalone/.next/server/chunks/[root-of-the-server]__01qcera._.js +16 -0
  123. package/.next/standalone/.next/server/chunks/[root-of-the-server]__02.uul~._.js +3 -0
  124. package/.next/standalone/.next/server/chunks/[root-of-the-server]__024967n._.js +3 -0
  125. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06booxp._.js +3 -0
  126. package/.next/standalone/.next/server/chunks/[root-of-the-server]__071_pmz._.js +3 -0
  127. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0bqpg._.js +3 -0
  128. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_1f2cw._.js +3 -0
  129. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0a6j6r4._.js +3 -0
  130. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0aoqat-._.js +3 -0
  131. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0as-u6z._.js +3 -0
  132. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0bvtbax._.js +3 -0
  133. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0c-ee48._.js +5 -0
  134. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e_9pc5._.js +3 -0
  135. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0esmskc._.js +3 -0
  136. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0fshk._._.js +20 -0
  137. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0fu72o7._.js +3 -0
  138. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0k9mili._.js +3 -0
  139. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0l-wu5u._.js +3 -0
  140. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0lvz22t._.js +20 -0
  141. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0n-chxk._.js +16 -0
  142. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0n9zdf0._.js +3 -0
  143. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0nmx3k2._.js +12 -0
  144. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0nzlmkb._.js +3 -0
  145. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o0v6hf._.js +3 -0
  146. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0s38pid._.js +3 -0
  147. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0s_8poz._.js +3 -0
  148. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0sfrx~.._.js +3 -0
  149. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0sggstu._.js +3 -0
  150. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0u81k~2._.js +3 -0
  151. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0uibxf_._.js +3 -0
  152. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0wfv_by._.js +3 -0
  153. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0wlj-yw._.js +3 -0
  154. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0w~__xz._.js +3 -0
  155. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0yat~ul._.js +3 -0
  156. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0yxauu6._.js +3 -0
  157. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zbkgnr._.js +3 -0
  158. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zv_j05._.js +3 -0
  159. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0~rntxj._.js +3 -0
  160. package/.next/standalone/.next/server/chunks/src_lib_search_0d-_j3u._.js +4 -4
  161. package/.next/standalone/.next/server/chunks/src_lib_search_0ymmp0c._.js +3 -3
  162. package/.next/standalone/.next/server/chunks/src_lib_workspaces_ts_0qon40u._.js +4 -0
  163. package/.next/standalone/.next/server/chunks/ssr/{0~w0_katex_dist_katex_mjs_029cdbg._.js → 0~w0_katex_dist_katex_mjs_0s4yb1t._.js} +1 -1
  164. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0z41nrr._.js → [root-of-the-server]__10te1ye._.js} +2 -2
  165. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_13p348f._.js → node_modules__pnpm_0-a_zjq._.js} +1 -1
  166. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0gos._c._.js → node_modules__pnpm_02l_1_8._.js} +1 -1
  167. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0ru1i2-._.js → node_modules__pnpm_03rzttw._.js} +2 -2
  168. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_08xpp3w._.js → node_modules__pnpm_04frxp9._.js} +1 -1
  169. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0b8odbc._.js → node_modules__pnpm_057-t6m._.js} +1 -1
  170. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0f_n_zp._.js → node_modules__pnpm_05_oahi._.js} +1 -1
  171. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0~i3a.i._.js → node_modules__pnpm_05ans~m._.js} +1 -1
  172. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0i2m0b.._.js → node_modules__pnpm_06-2ia.._.js} +2 -2
  173. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0aha1~u._.js → node_modules__pnpm_086.ow4._.js} +1 -1
  174. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0w.kwue._.js → node_modules__pnpm_0cahog3._.js} +1 -1
  175. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0e0r_qk._.js → node_modules__pnpm_0cxanql._.js} +2 -2
  176. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0ajqqlq._.js → node_modules__pnpm_0e09gmf._.js} +1 -1
  177. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0hzzx9d._.js → node_modules__pnpm_0eqjo2f._.js} +1 -1
  178. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_02bje_g._.js → node_modules__pnpm_0f-yazg._.js} +1 -1
  179. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0xk042~._.js → node_modules__pnpm_0iu44jv._.js} +1 -1
  180. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_11ede0p._.js → node_modules__pnpm_0jh8q66._.js} +2 -2
  181. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0k-7uzm._.js → node_modules__pnpm_0m39f~t._.js} +1 -1
  182. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0xr.ztu._.js → node_modules__pnpm_0ma-8l.._.js} +1 -1
  183. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0i6_kfe._.js → node_modules__pnpm_0met6sx._.js} +2 -2
  184. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_04v1_ty._.js → node_modules__pnpm_0mtrsi0._.js} +2 -2
  185. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0607~kg._.js → node_modules__pnpm_0n_swwn._.js} +2 -2
  186. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0t4l89_._.js → node_modules__pnpm_0ndyy93._.js} +1 -1
  187. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0-_58b8._.js → node_modules__pnpm_0s-cj7c._.js} +1 -1
  188. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0y2h_cz._.js → node_modules__pnpm_0tr41-t._.js} +1 -1
  189. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_08edl1n._.js → node_modules__pnpm_0u.uija._.js} +1 -1
  190. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0026mgr._.js → node_modules__pnpm_0wiyn6d._.js} +1 -1
  191. package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_09o_spj._.js → node_modules__pnpm_0ygzt82._.js} +1 -1
  192. package/.next/standalone/.next/server/chunks/ssr/src_app_page_tsx_0ss2.w7._.js +2 -2
  193. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  194. package/.next/standalone/.next/server/middleware-manifest.json +1 -1
  195. package/.next/standalone/.next/server/pages/404.html +1 -1
  196. package/.next/standalone/.next/server/pages/500.html +1 -1
  197. package/.next/standalone/.next/static/chunks/0ci7khnv7i~7_.js +17 -0
  198. package/.next/standalone/.next/static/chunks/0sx~65~lg4mgl.css +5 -0
  199. package/.next/standalone/package.json +1 -1
  200. package/README.md +88 -17
  201. package/bin/postbuild.js +21 -0
  202. package/bin/wiki-viewer.js +198 -6
  203. package/package.json +1 -1
  204. package/.next/standalone/.github/workflows/publish.yml +0 -37
  205. package/.next/standalone/.handoffs/archive/handoff-20260612-113332.md +0 -98
  206. package/.next/standalone/.handoffs/archive/handoff-20260612-141032.md +0 -73
  207. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-.y6im._.js +0 -3
  208. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-3_t2y._.js +0 -3
  209. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-kjkzt._.js +0 -3
  210. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-puax4._.js +0 -4
  211. package/.next/standalone/.next/server/chunks/[root-of-the-server]__01h996g._.js +0 -3
  212. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0329ktu._.js +0 -3
  213. package/.next/standalone/.next/server/chunks/[root-of-the-server]__03_xj4r._.js +0 -3
  214. package/.next/standalone/.next/server/chunks/[root-of-the-server]__05398dt._.js +0 -4
  215. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06lfvxh._.js +0 -3
  216. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06w0aet._.js +0 -3
  217. package/.next/standalone/.next/server/chunks/[root-of-the-server]__070_p2a._.js +0 -4
  218. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0905hi1._.js +0 -21
  219. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0aa63~j._.js +0 -5
  220. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0avcplk._.js +0 -4
  221. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0b8_kyo._.js +0 -16
  222. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0bticq1._.js +0 -3
  223. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0bwevvu._.js +0 -3
  224. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0c__k3q._.js +0 -4
  225. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cp~z4x._.js +0 -3
  226. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0fmdv9h._.js +0 -20
  227. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0h0qbwr._.js +0 -3
  228. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0jk~oyi._.js +0 -3
  229. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ndq77b._.js +0 -3
  230. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0nvgpuk._.js +0 -3
  231. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ocvng2._.js +0 -3
  232. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ps4h~.._.js +0 -3
  233. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q7jqwp._.js +0 -12
  234. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0qew~6p._.js +0 -3
  235. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0s_9f-a._.js +0 -3
  236. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0uv7b8u._.js +0 -3
  237. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0uv8.9i._.js +0 -3
  238. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0vfe2io._.js +0 -4
  239. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0w11kjy._.js +0 -3
  240. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0wc-.e4._.js +0 -3
  241. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ymovmp._.js +0 -3
  242. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0~c6ouv._.js +0 -3
  243. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0~rhs0u._.js +0 -16
  244. package/.next/standalone/.next/server/chunks/[root-of-the-server]__10h9tid._.js +0 -3
  245. package/.next/standalone/.next/server/chunks/[root-of-the-server]__10yk-u1._.js +0 -3
  246. package/.next/standalone/.next/server/chunks/[root-of-the-server]__11105ew._.js +0 -3
  247. package/.next/standalone/.next/server/chunks/[root-of-the-server]__11a3dhw._.js +0 -3
  248. package/.next/standalone/.next/server/chunks/[root-of-the-server]__13420tt._.js +0 -3
  249. package/.next/standalone/.next/server/chunks/[root-of-the-server]__13h~pdf._.js +0 -3
  250. package/.next/standalone/.next/static/chunks/02kg.lbkfi1yc.css +0 -5
  251. package/.next/standalone/.next/static/chunks/0rcwd6-.iu~nd.js +0 -17
  252. package/.next/standalone/.pi/ownership.json +0 -3
  253. package/.next/standalone/AGENTS.md +0 -114
  254. package/.next/standalone/DESIGN.md +0 -521
  255. package/.next/standalone/README.md +0 -821
  256. package/.next/standalone/TODO.md +0 -20
  257. package/.next/standalone/agents/bootstrap-prompt.md +0 -14
  258. package/.next/standalone/agents/wiki-viewer-skill/SKILL.md +0 -456
  259. package/.next/standalone/bin/postbuild.js +0 -78
  260. package/.next/standalone/bin/wiki-viewer.js +0 -922
  261. package/.next/standalone/certificates/localhost-key.pem +0 -28
  262. package/.next/standalone/certificates/localhost.pem +0 -24
  263. package/.next/standalone/docs/agent-collab-plan.md +0 -1615
  264. package/.next/standalone/docs/agent-collab-v2-plan.md +0 -771
  265. package/.next/standalone/docs/agent-fs-plan.md +0 -232
  266. package/.next/standalone/docs/editorial-skin-spec.md +0 -242
  267. package/.next/standalone/docs/file-vs-collab-authority.md +0 -124
  268. package/.next/standalone/docs/mobile-readiness-spec.md +0 -229
  269. package/.next/standalone/docs/workspacing-plan.md +0 -364
  270. package/.next/standalone/packages/wiki-viewer-mcp/README.md +0 -195
  271. package/.next/standalone/packages/wiki-viewer-mcp/bench-e2e.mjs +0 -166
  272. package/.next/standalone/packages/wiki-viewer-mcp/bench-latency.mjs +0 -87
  273. package/.next/standalone/packages/wiki-viewer-mcp/bench-payload.mjs +0 -45
  274. package/.next/standalone/packages/wiki-viewer-mcp/dist/http-client.js +0 -331
  275. package/.next/standalone/packages/wiki-viewer-mcp/dist/index.js +0 -531
  276. package/.next/standalone/packages/wiki-viewer-mcp/dist/register.js +0 -94
  277. package/.next/standalone/packages/wiki-viewer-mcp/dist/state-cache.js +0 -28
  278. package/.next/standalone/packages/wiki-viewer-mcp/package-lock.json +0 -1716
  279. package/.next/standalone/packages/wiki-viewer-mcp/package.json +0 -41
  280. package/.next/standalone/packages/wiki-viewer-mcp/src/http-client.ts +0 -459
  281. package/.next/standalone/packages/wiki-viewer-mcp/src/index.ts +0 -638
  282. package/.next/standalone/packages/wiki-viewer-mcp/src/register.ts +0 -144
  283. package/.next/standalone/packages/wiki-viewer-mcp/src/state-cache.ts +0 -55
  284. package/.next/standalone/packages/wiki-viewer-mcp/tsconfig.json +0 -19
  285. package/.next/standalone/pnpm-lock.yaml +0 -6697
  286. package/.next/standalone/pnpm-workspace.yaml +0 -8
  287. package/.next/standalone/postcss.config.mjs +0 -2
  288. package/.next/standalone/src/app/api/agent/activity/route.ts +0 -59
  289. package/.next/standalone/src/app/api/agent/admin/agents/[agentId]/revoke/route.ts +0 -40
  290. package/.next/standalone/src/app/api/agent/admin/agents/route.ts +0 -33
  291. package/.next/standalone/src/app/api/agent/admin/registrations/[regId]/approve/route.ts +0 -83
  292. package/.next/standalone/src/app/api/agent/admin/registrations/[regId]/deny/route.ts +0 -36
  293. package/.next/standalone/src/app/api/agent/admin/registrations/route.ts +0 -27
  294. package/.next/standalone/src/app/api/agent/events/[...path]/route.ts +0 -148
  295. package/.next/standalone/src/app/api/agent/files/[...path]/route.ts +0 -219
  296. package/.next/standalone/src/app/api/agent/fs/file/[...path]/route.ts +0 -446
  297. package/.next/standalone/src/app/api/agent/fs/ls/[[...path]]/route.ts +0 -152
  298. package/.next/standalone/src/app/api/agent/fs/move/route.ts +0 -130
  299. package/.next/standalone/src/app/api/agent/fs/search/route.ts +0 -272
  300. package/.next/standalone/src/app/api/agent/internal/span/route.ts +0 -121
  301. package/.next/standalone/src/app/api/agent/register/[regId]/route.ts +0 -50
  302. package/.next/standalone/src/app/api/agent/register/route.ts +0 -118
  303. package/.next/standalone/src/app/api/agent/settings/route.ts +0 -34
  304. package/.next/standalone/src/app/api/agent/settings/token/regenerate/route.ts +0 -20
  305. package/.next/standalone/src/app/api/agent/sidecar/[...path]/route.ts +0 -53
  306. package/.next/standalone/src/app/api/agents/install/route.ts +0 -143
  307. package/.next/standalone/src/app/api/agents/skill/route.ts +0 -20
  308. package/.next/standalone/src/app/api/agents/skill.tar.gz/route.ts +0 -87
  309. package/.next/standalone/src/app/api/app-proxy/[...path]/route.ts +0 -247
  310. package/.next/standalone/src/app/api/assets/[...path]/route.ts +0 -75
  311. package/.next/standalone/src/app/api/auth/[...all]/route.ts +0 -7
  312. package/.next/standalone/src/app/api/owner/init/route.ts +0 -14
  313. package/.next/standalone/src/app/api/share/[token]/route.ts +0 -269
  314. package/.next/standalone/src/app/api/share/route.ts +0 -127
  315. package/.next/standalone/src/app/api/system/admins/route.ts +0 -103
  316. package/.next/standalone/src/app/api/system/auth-config/route.ts +0 -22
  317. package/.next/standalone/src/app/api/system/auth-settings/route.ts +0 -86
  318. package/.next/standalone/src/app/api/system/browse/route.ts +0 -82
  319. package/.next/standalone/src/app/api/system/clear-root/route.ts +0 -16
  320. package/.next/standalone/src/app/api/system/config/route.ts +0 -14
  321. package/.next/standalone/src/app/api/system/pins/route.ts +0 -38
  322. package/.next/standalone/src/app/api/system/reveal/route.ts +0 -36
  323. package/.next/standalone/src/app/api/system/root-status/route.ts +0 -13
  324. package/.next/standalone/src/app/api/system/set-root/route.ts +0 -53
  325. package/.next/standalone/src/app/api/system/users/route.ts +0 -120
  326. package/.next/standalone/src/app/api/system/workspaces/[id]/open/route.ts +0 -34
  327. package/.next/standalone/src/app/api/system/workspaces/[id]/refresh/route.ts +0 -32
  328. package/.next/standalone/src/app/api/system/workspaces/[id]/route.ts +0 -78
  329. package/.next/standalone/src/app/api/system/workspaces/route.ts +0 -128
  330. package/.next/standalone/src/app/api/upload/[...path]/route.ts +0 -85
  331. package/.next/standalone/src/app/api/wiki/app/route.ts +0 -60
  332. package/.next/standalone/src/app/api/wiki/backlinks/route.ts +0 -29
  333. package/.next/standalone/src/app/api/wiki/content/route.ts +0 -159
  334. package/.next/standalone/src/app/api/wiki/download/route.ts +0 -100
  335. package/.next/standalone/src/app/api/wiki/file/route.ts +0 -57
  336. package/.next/standalone/src/app/api/wiki/folder/route.ts +0 -34
  337. package/.next/standalone/src/app/api/wiki/git-branches/route.ts +0 -32
  338. package/.next/standalone/src/app/api/wiki/git-checkout/route.ts +0 -45
  339. package/.next/standalone/src/app/api/wiki/git-diff/route.ts +0 -33
  340. package/.next/standalone/src/app/api/wiki/git-file-info/route.ts +0 -27
  341. package/.next/standalone/src/app/api/wiki/git-history/route.ts +0 -27
  342. package/.next/standalone/src/app/api/wiki/git-pull/route.ts +0 -48
  343. package/.next/standalone/src/app/api/wiki/move/route.ts +0 -61
  344. package/.next/standalone/src/app/api/wiki/new-file/route.ts +0 -56
  345. package/.next/standalone/src/app/api/wiki/outlinks/route.ts +0 -76
  346. package/.next/standalone/src/app/api/wiki/page/route.ts +0 -92
  347. package/.next/standalone/src/app/api/wiki/presence/route.ts +0 -56
  348. package/.next/standalone/src/app/api/wiki/route.ts +0 -116
  349. package/.next/standalone/src/app/api/wiki/search/route.ts +0 -44
  350. package/.next/standalone/src/app/api/wiki/slugs/route.ts +0 -54
  351. package/.next/standalone/src/app/api/wiki/upload/route.ts +0 -95
  352. package/.next/standalone/src/app/api/wiki/watch/route.ts +0 -67
  353. package/.next/standalone/src/app/globals.css +0 -1249
  354. package/.next/standalone/src/app/icon.svg +0 -11
  355. package/.next/standalone/src/app/layout.tsx +0 -78
  356. package/.next/standalone/src/app/manifest.ts +0 -30
  357. package/.next/standalone/src/app/page.tsx +0 -3260
  358. package/.next/standalone/src/app/s/[token]/page.tsx +0 -357
  359. package/.next/standalone/src/app/signin/page.tsx +0 -16
  360. package/.next/standalone/src/app/signin/signin-form.tsx +0 -238
  361. package/.next/standalone/src/components/ai-panel/activity-row.tsx +0 -284
  362. package/.next/standalone/src/components/ai-panel/ai-panel.tsx +0 -311
  363. package/.next/standalone/src/components/ai-panel/token-section.tsx +0 -313
  364. package/.next/standalone/src/components/auth-settings-sheet.tsx +0 -474
  365. package/.next/standalone/src/components/confirm-dialog.tsx +0 -56
  366. package/.next/standalone/src/components/dir-picker.tsx +0 -606
  367. package/.next/standalone/src/components/editor/backlinks-panel.tsx +0 -139
  368. package/.next/standalone/src/components/editor/bubble-menu.tsx +0 -346
  369. package/.next/standalone/src/components/editor/callout-extension.ts +0 -36
  370. package/.next/standalone/src/components/editor/comment-pip.tsx +0 -56
  371. package/.next/standalone/src/components/editor/comment-thread.tsx +0 -254
  372. package/.next/standalone/src/components/editor/csv-viewer.tsx +0 -379
  373. package/.next/standalone/src/components/editor/document-outline.tsx +0 -230
  374. package/.next/standalone/src/components/editor/editor-toolbar.tsx +0 -564
  375. package/.next/standalone/src/components/editor/editor.tsx +0 -1327
  376. package/.next/standalone/src/components/editor/extensions/drag-handle.ts +0 -325
  377. package/.next/standalone/src/components/editor/extensions/heading-anchors.ts +0 -55
  378. package/.next/standalone/src/components/editor/extensions/proof-span.ts +0 -60
  379. package/.next/standalone/src/components/editor/extensions/resizable-image.tsx +0 -159
  380. package/.next/standalone/src/components/editor/extensions.ts +0 -150
  381. package/.next/standalone/src/components/editor/file-fallback-viewer.tsx +0 -75
  382. package/.next/standalone/src/components/editor/folder-index.tsx +0 -236
  383. package/.next/standalone/src/components/editor/google-doc-viewer.tsx +0 -73
  384. package/.next/standalone/src/components/editor/image-viewer.tsx +0 -57
  385. package/.next/standalone/src/components/editor/large-file-gate.tsx +0 -108
  386. package/.next/standalone/src/components/editor/link-popover.tsx +0 -111
  387. package/.next/standalone/src/components/editor/media-popover.tsx +0 -212
  388. package/.next/standalone/src/components/editor/media-viewer.tsx +0 -70
  389. package/.next/standalone/src/components/editor/mermaid-viewer.tsx +0 -286
  390. package/.next/standalone/src/components/editor/node-app-viewer.tsx +0 -328
  391. package/.next/standalone/src/components/editor/notebook-viewer.tsx +0 -371
  392. package/.next/standalone/src/components/editor/office/docx-viewer.tsx +0 -93
  393. package/.next/standalone/src/components/editor/office/office-chrome.tsx +0 -83
  394. package/.next/standalone/src/components/editor/office/pptx-viewer.tsx +0 -104
  395. package/.next/standalone/src/components/editor/office/xlsx-viewer.tsx +0 -192
  396. package/.next/standalone/src/components/editor/pdf-viewer.tsx +0 -32
  397. package/.next/standalone/src/components/editor/proof-span-popover.tsx +0 -162
  398. package/.next/standalone/src/components/editor/slash-commands.tsx +0 -629
  399. package/.next/standalone/src/components/editor/source-viewer.tsx +0 -289
  400. package/.next/standalone/src/components/editor/suggest-edit-popover.tsx +0 -229
  401. package/.next/standalone/src/components/editor/suggestion-card.tsx +0 -206
  402. package/.next/standalone/src/components/editor/table-menu.tsx +0 -232
  403. package/.next/standalone/src/components/editor/view-mode-comment-button.tsx +0 -77
  404. package/.next/standalone/src/components/editor/website-viewer.tsx +0 -75
  405. package/.next/standalone/src/components/editor/wiki-link-create-dialog.tsx +0 -189
  406. package/.next/standalone/src/components/editor/wiki-link-decorator.ts +0 -79
  407. package/.next/standalone/src/components/editor/wiki-link-extension.ts +0 -120
  408. package/.next/standalone/src/components/editor/wiki-link-picker.tsx +0 -250
  409. package/.next/standalone/src/components/layout/viewer-toolbar.tsx +0 -54
  410. package/.next/standalone/src/components/search/search-command-dialog.tsx +0 -246
  411. package/.next/standalone/src/components/search/sidebar-search-box.tsx +0 -121
  412. package/.next/standalone/src/components/search/snippet-text.tsx +0 -48
  413. package/.next/standalone/src/components/share-dialog.tsx +0 -307
  414. package/.next/standalone/src/components/theme-provider.tsx +0 -16
  415. package/.next/standalone/src/components/theme-toggle.tsx +0 -24
  416. package/.next/standalone/src/components/ui/badge.tsx +0 -35
  417. package/.next/standalone/src/components/ui/button.tsx +0 -56
  418. package/.next/standalone/src/components/ui/card.tsx +0 -63
  419. package/.next/standalone/src/components/ui/collapsible.tsx +0 -9
  420. package/.next/standalone/src/components/ui/command.tsx +0 -151
  421. package/.next/standalone/src/components/ui/context-menu.tsx +0 -191
  422. package/.next/standalone/src/components/ui/dialog.tsx +0 -119
  423. package/.next/standalone/src/components/ui/dropdown-menu.tsx +0 -194
  424. package/.next/standalone/src/components/ui/input.tsx +0 -22
  425. package/.next/standalone/src/components/ui/label.tsx +0 -25
  426. package/.next/standalone/src/components/ui/popover.tsx +0 -33
  427. package/.next/standalone/src/components/ui/scroll-area.tsx +0 -47
  428. package/.next/standalone/src/components/ui/select.tsx +0 -156
  429. package/.next/standalone/src/components/ui/separator.tsx +0 -30
  430. package/.next/standalone/src/components/ui/sheet.tsx +0 -140
  431. package/.next/standalone/src/components/ui/skeleton.tsx +0 -15
  432. package/.next/standalone/src/components/ui/switch.tsx +0 -28
  433. package/.next/standalone/src/components/ui/tabs.tsx +0 -54
  434. package/.next/standalone/src/components/ui/textarea.tsx +0 -21
  435. package/.next/standalone/src/components/ui/tip.tsx +0 -23
  436. package/.next/standalone/src/components/ui/toggle-group.tsx +0 -41
  437. package/.next/standalone/src/components/ui/tooltip.tsx +0 -27
  438. package/.next/standalone/src/components/view-width-toggle.tsx +0 -70
  439. package/.next/standalone/src/components/wiki/frontmatter-header.tsx +0 -164
  440. package/.next/standalone/src/hooks/use-is-mobile.ts +0 -14
  441. package/.next/standalone/src/lib/app-runner.ts +0 -272
  442. package/.next/standalone/src/lib/auth/admin.ts +0 -120
  443. package/.next/standalone/src/lib/auth/allowlist.ts +0 -50
  444. package/.next/standalone/src/lib/auth/client.ts +0 -4
  445. package/.next/standalone/src/lib/auth/csrf.ts +0 -68
  446. package/.next/standalone/src/lib/auth/server.ts +0 -215
  447. package/.next/standalone/src/lib/cabinets/tree.ts +0 -75
  448. package/.next/standalone/src/lib/config.ts +0 -114
  449. package/.next/standalone/src/lib/embeds/detect.ts +0 -142
  450. package/.next/standalone/src/lib/git-secrets.ts +0 -65
  451. package/.next/standalone/src/lib/git.ts +0 -503
  452. package/.next/standalone/src/lib/google/detect.ts +0 -107
  453. package/.next/standalone/src/lib/markdown/parse-frontmatter.ts +0 -104
  454. package/.next/standalone/src/lib/markdown/remark-wikilinks.ts +0 -100
  455. package/.next/standalone/src/lib/markdown/sanitize-schema.ts +0 -106
  456. package/.next/standalone/src/lib/markdown/to-html.ts +0 -282
  457. package/.next/standalone/src/lib/markdown/to-markdown.ts +0 -252
  458. package/.next/standalone/src/lib/proof/activity-shared.ts +0 -31
  459. package/.next/standalone/src/lib/proof/activity.ts +0 -74
  460. package/.next/standalone/src/lib/proof/audit.ts +0 -88
  461. package/.next/standalone/src/lib/proof/auth.ts +0 -143
  462. package/.next/standalone/src/lib/proof/block-refs.ts +0 -133
  463. package/.next/standalone/src/lib/proof/blocks.ts +0 -73
  464. package/.next/standalone/src/lib/proof/client-auth.ts +0 -23
  465. package/.next/standalone/src/lib/proof/collab-state.ts +0 -81
  466. package/.next/standalone/src/lib/proof/event-bus.ts +0 -47
  467. package/.next/standalone/src/lib/proof/file-lock.ts +0 -43
  468. package/.next/standalone/src/lib/proof/glob.ts +0 -51
  469. package/.next/standalone/src/lib/proof/idempotency.ts +0 -37
  470. package/.next/standalone/src/lib/proof/lease.ts +0 -117
  471. package/.next/standalone/src/lib/proof/mutex.ts +0 -36
  472. package/.next/standalone/src/lib/proof/ops-applier.ts +0 -727
  473. package/.next/standalone/src/lib/proof/owner-auth.ts +0 -2
  474. package/.next/standalone/src/lib/proof/pending.ts +0 -97
  475. package/.next/standalone/src/lib/proof/proof-span.ts +0 -141
  476. package/.next/standalone/src/lib/proof/rate-limit.ts +0 -53
  477. package/.next/standalone/src/lib/proof/raw-fs.ts +0 -197
  478. package/.next/standalone/src/lib/proof/register-rate-limit.ts +0 -53
  479. package/.next/standalone/src/lib/proof/registry.ts +0 -195
  480. package/.next/standalone/src/lib/proof/sidecar.ts +0 -103
  481. package/.next/standalone/src/lib/proof/suggest-capture.ts +0 -69
  482. package/.next/standalone/src/lib/proof/types.ts +0 -182
  483. package/.next/standalone/src/lib/proof-config.ts +0 -14
  484. package/.next/standalone/src/lib/root-dir.ts +0 -35
  485. package/.next/standalone/src/lib/search/indexable-exts.ts +0 -25
  486. package/.next/standalone/src/lib/search/indexer.ts +0 -634
  487. package/.next/standalone/src/lib/search/sanitize.ts +0 -35
  488. package/.next/standalone/src/lib/search/search-db.ts +0 -57
  489. package/.next/standalone/src/lib/search/watcher-pool.ts +0 -79
  490. package/.next/standalone/src/lib/shared-docs/db.ts +0 -177
  491. package/.next/standalone/src/lib/toast.ts +0 -9
  492. package/.next/standalone/src/lib/utils.ts +0 -6
  493. package/.next/standalone/src/lib/wiki-helpers.ts +0 -36
  494. package/.next/standalone/src/lib/workspace-client.ts +0 -82
  495. package/.next/standalone/src/lib/workspace-context.ts +0 -173
  496. package/.next/standalone/src/lib/workspaces.ts +0 -400
  497. package/.next/standalone/src/middleware.ts +0 -44
  498. package/.next/standalone/src/stores/ai-panel-store.ts +0 -79
  499. package/.next/standalone/src/stores/editor-store.ts +0 -439
  500. package/.next/standalone/src/stores/pin-store.ts +0 -56
  501. package/.next/standalone/src/stores/proof-store.ts +0 -124
  502. package/.next/standalone/src/stores/recent-store.ts +0 -51
  503. package/.next/standalone/src/stores/search-store.ts +0 -104
  504. package/.next/standalone/src/stores/show-hidden-store.ts +0 -26
  505. package/.next/standalone/src/stores/sidebar-width-store.ts +0 -39
  506. package/.next/standalone/src/stores/skin-store.ts +0 -42
  507. package/.next/standalone/src/stores/tree-store.ts +0 -52
  508. package/.next/standalone/src/stores/view-width-store.ts +0 -101
  509. package/.next/standalone/src/stores/wiki-slugs-store.ts +0 -75
  510. package/.next/standalone/src/tests/proof/activity-aggregator.test.ts +0 -146
  511. package/.next/standalone/src/tests/proof/admin-create-user.test.ts +0 -43
  512. package/.next/standalone/src/tests/proof/agent-fs.test.ts +0 -973
  513. package/.next/standalone/src/tests/proof/agent-ownership.test.ts +0 -140
  514. package/.next/standalone/src/tests/proof/agent-workspace-scope.test.ts +0 -134
  515. package/.next/standalone/src/tests/proof/agents-install.test.ts +0 -110
  516. package/.next/standalone/src/tests/proof/bench-write.ts +0 -179
  517. package/.next/standalone/src/tests/proof/better-auth.test.ts +0 -68
  518. package/.next/standalone/src/tests/proof/block-refs.test.ts +0 -108
  519. package/.next/standalone/src/tests/proof/blocks.test.ts +0 -92
  520. package/.next/standalone/src/tests/proof/collab-state.test.ts +0 -501
  521. package/.next/standalone/src/tests/proof/comments-ops.test.ts +0 -177
  522. package/.next/standalone/src/tests/proof/editor-roundtrip.test.ts +0 -85
  523. package/.next/standalone/src/tests/proof/external-edit.test.ts +0 -58
  524. package/.next/standalone/src/tests/proof/file-lock.test.ts +0 -80
  525. package/.next/standalone/src/tests/proof/git-branches-checkout.test.ts +0 -136
  526. package/.next/standalone/src/tests/proof/git-read-features.test.ts +0 -473
  527. package/.next/standalone/src/tests/proof/git-secrets.test.ts +0 -138
  528. package/.next/standalone/src/tests/proof/git-sparse.test.ts +0 -257
  529. package/.next/standalone/src/tests/proof/git-workspace.test.ts +0 -135
  530. package/.next/standalone/src/tests/proof/git.test.ts +0 -243
  531. package/.next/standalone/src/tests/proof/glob.test.ts +0 -82
  532. package/.next/standalone/src/tests/proof/helpers/auth-session.ts +0 -27
  533. package/.next/standalone/src/tests/proof/markdown-to-html.test.ts +0 -46
  534. package/.next/standalone/src/tests/proof/ops-applier.test.ts +0 -368
  535. package/.next/standalone/src/tests/proof/owner-init.test.ts +0 -2
  536. package/.next/standalone/src/tests/proof/parse-frontmatter.test.ts +0 -60
  537. package/.next/standalone/src/tests/proof/preload.ts +0 -21
  538. package/.next/standalone/src/tests/proof/proof-span.test.ts +0 -98
  539. package/.next/standalone/src/tests/proof/rate-limit.test.ts +0 -54
  540. package/.next/standalone/src/tests/proof/readonly-enforcement.test.ts +0 -161
  541. package/.next/standalone/src/tests/proof/reconcile-sidecar.test.ts +0 -195
  542. package/.next/standalone/src/tests/proof/registration-flow.test.ts +0 -330
  543. package/.next/standalone/src/tests/proof/registry.test.ts +0 -169
  544. package/.next/standalone/src/tests/proof/routes.test.ts +0 -516
  545. package/.next/standalone/src/tests/proof/search-index.test.ts +0 -376
  546. package/.next/standalone/src/tests/proof/sidecar-lifecycle.test.ts +0 -177
  547. package/.next/standalone/src/tests/proof/sidecar-trim.test.ts +0 -58
  548. package/.next/standalone/src/tests/proof/suggestion-ops.test.ts +0 -280
  549. package/.next/standalone/src/tests/proof/wiki-content-put.test.ts +0 -140
  550. package/.next/standalone/src/tests/proof/wiki-routes-auth.test.ts +0 -208
  551. package/.next/standalone/src/tests/proof/workspace-isolation.test.ts +0 -87
  552. package/.next/standalone/src/tests/proof/workspaces-api.test.ts +0 -227
  553. package/.next/standalone/src/types/index.ts +0 -47
  554. package/.next/standalone/tailwind.config.ts +0 -191
  555. package/.next/standalone/tsconfig.json +0 -41
  556. package/.next/standalone/tsconfig.tsbuildinfo +0 -1
  557. /package/.next/standalone/.next/static/{WMOTgfV82apmdovxzgbMx → ecpoWt_SP3WkUTh0NsnuT}/_buildManifest.js +0 -0
  558. /package/.next/standalone/.next/static/{WMOTgfV82apmdovxzgbMx → ecpoWt_SP3WkUTh0NsnuT}/_clientMiddlewareManifest.js +0 -0
  559. /package/.next/standalone/.next/static/{WMOTgfV82apmdovxzgbMx → ecpoWt_SP3WkUTh0NsnuT}/_ssgManifest.js +0 -0
@@ -1,973 +0,0 @@
1
- /**
2
- * Phase 2 — Tier-1 Raw FS API tests.
3
- *
4
- * Covers: GET bytes/ETag/Range, PUT create/overwrite/If-Match, create-collision,
5
- * .md PUT triggers file.rawWritten+reconcile, DELETE scope+If-Match, ls scope-filter/limits,
6
- * move+sidecar, search grep/glob+binary-skip+scope, traversal+symlink-escape rejection.
7
- */
8
- import { test, before, after } from "node:test";
9
- import assert from "node:assert/strict";
10
- import {
11
- mkdtemp, rm, writeFile, readFile, mkdir, symlink,
12
- } from "node:fs/promises";
13
- import { tmpdir } from "node:os";
14
- import path from "node:path";
15
- import { createHash } from "node:crypto";
16
- import { randomBytes } from "node:crypto";
17
-
18
- import { setRootDir } from "../../lib/root-dir.js";
19
- import { ensureRegistry, addAgent, hashToken } from "../../lib/proof/registry.js";
20
- import { writeSidecar, readSidecar, emptySidecar } from "../../lib/proof/sidecar.js";
21
- import { _resetAuditDb } from "../../lib/proof/audit.js";
22
-
23
- // Route handlers (loaded after env is set)
24
- let fileGET: (req: Request, ctx: { params: Promise<{ path: string[] }> }) => Promise<Response>;
25
- let filePUT: (req: Request, ctx: { params: Promise<{ path: string[] }> }) => Promise<Response>;
26
- let filePATCH: (req: Request, ctx: { params: Promise<{ path: string[] }> }) => Promise<Response>;
27
- let fileDELETE: (req: Request, ctx: { params: Promise<{ path: string[] }> }) => Promise<Response>;
28
- let lsGET: (req: Request, ctx: { params: Promise<{ path?: string[] }> }) => Promise<Response>;
29
- let movePOST: (req: Request) => Promise<Response>;
30
- let searchPOST: (req: Request) => Promise<Response>;
31
-
32
- let tmpHome: string;
33
- let tmpRoot: string;
34
-
35
- // Tokens
36
- let READ_TOKEN: string;
37
- let MUTATE_TOKEN: string;
38
- let DELETE_TOKEN: string;
39
- let RESTRICTED_TOKEN: string;
40
-
41
- function sha256(buf: Buffer): string {
42
- return "sha256:" + createHash("sha256").update(buf).digest("hex");
43
- }
44
-
45
- function agentHeaders(token: string, id: string): Record<string, string> {
46
- return {
47
- Authorization: `Bearer ${token}`,
48
- "X-Agent-Id": id,
49
- };
50
- }
51
-
52
- before(async () => {
53
- tmpHome = await mkdtemp(path.join(tmpdir(), "agent-fs-home-"));
54
- tmpRoot = await mkdtemp(path.join(tmpdir(), "agent-fs-root-"));
55
-
56
- process.env.HOME = tmpHome;
57
- setRootDir(tmpRoot);
58
- _resetAuditDb();
59
-
60
- await ensureRegistry();
61
-
62
- READ_TOKEN = randomBytes(32).toString("hex");
63
- MUTATE_TOKEN = randomBytes(32).toString("hex");
64
- DELETE_TOKEN = randomBytes(32).toString("hex");
65
- RESTRICTED_TOKEN = randomBytes(32).toString("hex");
66
-
67
- await addAgent({
68
- id: "ai:read-agent",
69
- displayName: "Read Agent",
70
- tokenHash: hashToken(READ_TOKEN),
71
- scope: { paths: ["**/*"], ops: ["read"] },
72
- createdAt: new Date().toISOString(),
73
- lastSeen: new Date().toISOString(),
74
- });
75
-
76
- await addAgent({
77
- id: "ai:mutate-agent",
78
- displayName: "Mutate Agent",
79
- tokenHash: hashToken(MUTATE_TOKEN),
80
- scope: { paths: ["**/*"], ops: ["read", "mutate"] },
81
- createdAt: new Date().toISOString(),
82
- lastSeen: new Date().toISOString(),
83
- });
84
-
85
- await addAgent({
86
- id: "ai:delete-agent",
87
- displayName: "Delete Agent",
88
- tokenHash: hashToken(DELETE_TOKEN),
89
- scope: { paths: ["**/*"], ops: ["read", "mutate", "delete"] },
90
- createdAt: new Date().toISOString(),
91
- lastSeen: new Date().toISOString(),
92
- });
93
-
94
- await addAgent({
95
- id: "ai:restricted",
96
- displayName: "Restricted",
97
- tokenHash: hashToken(RESTRICTED_TOKEN),
98
- scope: { paths: ["allowed/**"], ops: ["read", "mutate", "delete"] },
99
- createdAt: new Date().toISOString(),
100
- lastSeen: new Date().toISOString(),
101
- });
102
-
103
- // Load route handlers after env is set
104
- const fileRoute = await import("../../app/api/agent/fs/file/[...path]/route.js");
105
- fileGET = fileRoute.GET;
106
- filePUT = fileRoute.PUT;
107
- filePATCH = fileRoute.PATCH;
108
- fileDELETE = fileRoute.DELETE;
109
-
110
- const lsRoute = await import("../../app/api/agent/fs/ls/[[...path]]/route.js");
111
- lsGET = lsRoute.GET;
112
-
113
- const moveRoute = await import("../../app/api/agent/fs/move/route.js");
114
- movePOST = moveRoute.POST;
115
-
116
- const searchRoute = await import("../../app/api/agent/fs/search/route.js");
117
- searchPOST = searchRoute.POST;
118
- });
119
-
120
- after(async () => {
121
- await rm(tmpHome, { recursive: true, force: true });
122
- await rm(tmpRoot, { recursive: true, force: true });
123
- });
124
-
125
- // ── Helpers ──────────────────────────────────────────────────────────────────
126
-
127
- function makeCtx(segments: string[]): { params: Promise<{ path: string[] }> } {
128
- return { params: Promise.resolve({ path: segments }) };
129
- }
130
-
131
- function makeLsCtx(segments?: string[]): { params: Promise<{ path?: string[] }> } {
132
- return { params: Promise.resolve({ path: segments }) };
133
- }
134
-
135
- function fileUrl(rel: string, qs = ""): string {
136
- return `http://localhost/api/agent/fs/file/${rel}${qs}`;
137
- }
138
-
139
- function lsUrl(rel: string, qs = ""): string {
140
- return `http://localhost/api/agent/fs/ls/${rel}${qs}`;
141
- }
142
-
143
- // ── GET tests ────────────────────────────────────────────────────────────────
144
-
145
- test("GET: returns raw bytes with ETag, X-File-Size, X-File-Mtime, Content-Type", async () => {
146
- const content = Buffer.from("hello world");
147
- await writeFile(path.join(tmpRoot, "hello.txt"), content);
148
-
149
- const req = new Request(fileUrl("hello.txt"), {
150
- headers: agentHeaders(READ_TOKEN, "ai:read-agent"),
151
- });
152
- const res = await fileGET(req, makeCtx(["hello.txt"]));
153
- assert.equal(res.status, 200);
154
-
155
- const body = Buffer.from(await res.arrayBuffer());
156
- assert.deepEqual(body, content);
157
-
158
- const etag = res.headers.get("etag");
159
- assert.ok(etag, "ETag header present");
160
- assert.ok(etag!.includes(createHash("sha256").update(content).digest("hex")), "ETag contains sha256 hex");
161
-
162
- assert.equal(res.headers.get("x-file-size"), String(content.length));
163
- assert.ok(res.headers.get("x-file-mtime"), "X-File-Mtime present");
164
- assert.ok(res.headers.get("content-type")?.includes("text/plain"), "Content-Type text/plain for .txt");
165
- });
166
-
167
- test("GET: 404 for missing file", async () => {
168
- const req = new Request(fileUrl("missing.txt"), {
169
- headers: agentHeaders(READ_TOKEN, "ai:read-agent"),
170
- });
171
- const res = await fileGET(req, makeCtx(["missing.txt"]));
172
- assert.equal(res.status, 404);
173
- });
174
-
175
- test("GET: supports HTTP Range", async () => {
176
- const content = Buffer.from("0123456789");
177
- await writeFile(path.join(tmpRoot, "range.txt"), content);
178
-
179
- const req = new Request(fileUrl("range.txt"), {
180
- headers: {
181
- ...agentHeaders(READ_TOKEN, "ai:read-agent"),
182
- Range: "bytes=2-5",
183
- },
184
- });
185
- const res = await fileGET(req, makeCtx(["range.txt"]));
186
- assert.equal(res.status, 206);
187
-
188
- const slice = Buffer.from(await res.arrayBuffer());
189
- assert.deepEqual(slice, Buffer.from("2345"));
190
- assert.ok(res.headers.get("content-range")?.startsWith("bytes 2-5/"), "Content-Range header");
191
- });
192
-
193
- test("GET: rejects path traversal", async () => {
194
- const req = new Request(fileUrl("../etc/passwd"), {
195
- headers: agentHeaders(READ_TOKEN, "ai:read-agent"),
196
- });
197
- const res = await fileGET(req, makeCtx(["../etc/passwd"]));
198
- assert.equal(res.status, 400);
199
- });
200
-
201
- test("GET: rejects .proof path", async () => {
202
- const req = new Request(fileUrl(".proof/something.json"), {
203
- headers: agentHeaders(READ_TOKEN, "ai:read-agent"),
204
- });
205
- const res = await fileGET(req, makeCtx([".proof", "something.json"]));
206
- assert.equal(res.status, 400);
207
- });
208
-
209
- test("GET: 401 without auth", async () => {
210
- const req = new Request(fileUrl("hello.txt"));
211
- const res = await fileGET(req, makeCtx(["hello.txt"]));
212
- assert.equal(res.status, 401);
213
- });
214
-
215
- test("GET: scope-filtered — restricted agent denied out-of-scope path", async () => {
216
- await writeFile(path.join(tmpRoot, "secret.txt"), "top secret");
217
-
218
- const req = new Request(fileUrl("secret.txt"), {
219
- headers: agentHeaders(RESTRICTED_TOKEN, "ai:restricted"),
220
- });
221
- const res = await fileGET(req, makeCtx(["secret.txt"]));
222
- assert.equal(res.status, 403);
223
- });
224
-
225
- // ── PUT tests ────────────────────────────────────────────────────────────────
226
-
227
- test("PUT: create new file (no If-Match)", async () => {
228
- const content = Buffer.from("brand new file");
229
- const req = new Request(fileUrl("new-file.txt"), {
230
- method: "PUT",
231
- headers: agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"),
232
- body: content,
233
- });
234
- const res = await filePUT(req, makeCtx(["new-file.txt"]));
235
- assert.equal(res.status, 200);
236
- const json = await res.json() as { path: string; created: boolean; sha256: string };
237
- assert.equal(json.path, "new-file.txt");
238
- assert.equal(json.created, true);
239
-
240
- const written = await readFile(path.join(tmpRoot, "new-file.txt"));
241
- assert.deepEqual(written, content);
242
- });
243
-
244
- test("PUT: overwrite requires If-Match", async () => {
245
- await writeFile(path.join(tmpRoot, "existing.txt"), "original");
246
-
247
- const req = new Request(fileUrl("existing.txt"), {
248
- method: "PUT",
249
- headers: agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"),
250
- body: Buffer.from("updated"),
251
- });
252
- const res = await filePUT(req, makeCtx(["existing.txt"]));
253
- assert.equal(res.status, 412);
254
- const json = await res.json() as { error: string };
255
- assert.equal(json.error, "PRECONDITION_REQUIRED");
256
- });
257
-
258
- test("PUT: create-collision — file exists, no If-Match → 412", async () => {
259
- await writeFile(path.join(tmpRoot, "collision.txt"), "existing content");
260
- // Sending PUT without If-Match to an existing file = 412 PRECONDITION_REQUIRED
261
- const req = new Request(fileUrl("collision.txt"), {
262
- method: "PUT",
263
- headers: agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"),
264
- body: Buffer.from("new content"),
265
- });
266
- const res = await filePUT(req, makeCtx(["collision.txt"]));
267
- assert.equal(res.status, 412);
268
- });
269
-
270
- test("PUT: overwrite with correct If-Match succeeds", async () => {
271
- const original = Buffer.from("original content");
272
- await writeFile(path.join(tmpRoot, "ifmatch.txt"), original);
273
- const sha = sha256(original);
274
-
275
- const req = new Request(fileUrl("ifmatch.txt"), {
276
- method: "PUT",
277
- headers: {
278
- ...agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"),
279
- "If-Match": `"${sha}"`,
280
- },
281
- body: Buffer.from("updated content"),
282
- });
283
- const res = await filePUT(req, makeCtx(["ifmatch.txt"]));
284
- assert.equal(res.status, 200);
285
- const json = await res.json() as { created: boolean };
286
- assert.equal(json.created, false);
287
- });
288
-
289
- test("PUT: If-Match mismatch → 412 PRECONDITION_FAILED", async () => {
290
- await writeFile(path.join(tmpRoot, "mismatch.txt"), "content");
291
-
292
- const req = new Request(fileUrl("mismatch.txt"), {
293
- method: "PUT",
294
- headers: {
295
- ...agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"),
296
- "If-Match": `"sha256:${"0".repeat(64)}"`,
297
- },
298
- body: Buffer.from("new"),
299
- });
300
- const res = await filePUT(req, makeCtx(["mismatch.txt"]));
301
- assert.equal(res.status, 412);
302
- const json = await res.json() as { error: string };
303
- assert.equal(json.error, "PRECONDITION_FAILED");
304
- });
305
-
306
- test("PUT: ?force=true bypasses If-Match for overwrite", async () => {
307
- await writeFile(path.join(tmpRoot, "force.txt"), "original");
308
-
309
- const req = new Request(fileUrl("force.txt", "?force=true"), {
310
- method: "PUT",
311
- headers: agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"),
312
- body: Buffer.from("forced update"),
313
- });
314
- const res = await filePUT(req, makeCtx(["force.txt"]));
315
- assert.equal(res.status, 200);
316
- });
317
-
318
- test("PUT: ?mkdirs=true creates intermediate directories", async () => {
319
- const req = new Request(fileUrl("deep/nested/dir/file.txt", "?mkdirs=true"), {
320
- method: "PUT",
321
- headers: agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"),
322
- body: Buffer.from("deep file"),
323
- });
324
- const res = await filePUT(req, makeCtx(["deep", "nested", "dir", "file.txt"]));
325
- assert.equal(res.status, 200);
326
- const written = await readFile(path.join(tmpRoot, "deep/nested/dir/file.txt"));
327
- assert.deepEqual(written, Buffer.from("deep file"));
328
- });
329
-
330
- test("PUT: parent dir missing without ?mkdirs → 400", async () => {
331
- const req = new Request(fileUrl("nonexistent-dir/file.txt"), {
332
- method: "PUT",
333
- headers: agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"),
334
- body: Buffer.from("content"),
335
- });
336
- const res = await filePUT(req, makeCtx(["nonexistent-dir", "file.txt"]));
337
- assert.equal(res.status, 400);
338
- const json = await res.json() as { error: string };
339
- assert.equal(json.error, "PARENT_NOT_FOUND");
340
- });
341
-
342
- test("PUT: .md write triggers file.rawWritten event and reconcile", async () => {
343
- const mdContent = "# Hello\n\nThis is a test.\n";
344
- const mdPath = "raw-written.md";
345
-
346
- const req = new Request(fileUrl(mdPath), {
347
- method: "PUT",
348
- headers: agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"),
349
- body: Buffer.from(mdContent),
350
- });
351
- const res = await filePUT(req, makeCtx([mdPath]));
352
- assert.equal(res.status, 200);
353
-
354
- // Sidecar should be created with file.rawWritten event
355
- const sidecar = await readSidecar(tmpRoot, mdPath);
356
- assert.ok(sidecar, "sidecar created after .md PUT");
357
- const rawWrittenEvents = sidecar!.events.filter((e) => e.type === "file.rawWritten");
358
- assert.ok(rawWrittenEvents.length > 0, "file.rawWritten event in sidecar");
359
- assert.equal(rawWrittenEvents[0]!.by, "ai:mutate-agent");
360
- // Fingerprint set correctly
361
- const fileBuf = await readFile(path.join(tmpRoot, mdPath));
362
- const expectedSha = sha256(fileBuf);
363
- assert.equal(sidecar!.fingerprint, expectedSha);
364
- });
365
-
366
- test("PUT: .md overwrite updates sidecar fingerprint eagerly (R2 no lazy mismatch)", async () => {
367
- const mdPath = "eager-reconcile.md";
368
- const initial = "# Initial\n";
369
- const updated = "# Updated\n\nNew paragraph.\n";
370
-
371
- // Create with initial content
372
- await writeFile(path.join(tmpRoot, mdPath), initial);
373
- const sc = emptySidecar(mdPath);
374
- sc.fingerprint = sha256(Buffer.from(initial));
375
- await writeSidecar(tmpRoot, mdPath, sc);
376
-
377
- // PUT updated content with If-Match
378
- const initialSha = sha256(Buffer.from(initial));
379
- const req = new Request(fileUrl(mdPath), {
380
- method: "PUT",
381
- headers: {
382
- ...agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"),
383
- "If-Match": `"${initialSha}"`,
384
- },
385
- body: Buffer.from(updated),
386
- });
387
- const res = await filePUT(req, makeCtx([mdPath]));
388
- assert.equal(res.status, 200);
389
-
390
- const sidecar = await readSidecar(tmpRoot, mdPath);
391
- const newFileSha = sha256(Buffer.from(updated));
392
- // Fingerprint MUST equal new sha (not old), proving eager reconcile ran
393
- assert.equal(sidecar!.fingerprint, newFileSha, "fingerprint updated eagerly");
394
- });
395
-
396
- test("PUT: mutate scope required (read-only agent rejected)", async () => {
397
- const req = new Request(fileUrl("some.txt"), {
398
- method: "PUT",
399
- headers: agentHeaders(READ_TOKEN, "ai:read-agent"),
400
- body: Buffer.from("data"),
401
- });
402
- const res = await filePUT(req, makeCtx(["some.txt"]));
403
- assert.equal(res.status, 403);
404
- });
405
-
406
- // ── DELETE tests ──────────────────────────────────────────────────────────────
407
-
408
- test("DELETE: requires delete scope — mutate-only agent gets 403", async () => {
409
- await writeFile(path.join(tmpRoot, "del-scope.txt"), "content");
410
- const buf = await readFile(path.join(tmpRoot, "del-scope.txt"));
411
- const sha = sha256(buf);
412
-
413
- const req = new Request(fileUrl("del-scope.txt"), {
414
- method: "DELETE",
415
- headers: {
416
- ...agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"),
417
- "If-Match": `"${sha}"`,
418
- },
419
- });
420
- const res = await fileDELETE(req, makeCtx(["del-scope.txt"]));
421
- assert.equal(res.status, 403);
422
- });
423
-
424
- test("DELETE: requires If-Match header", async () => {
425
- await writeFile(path.join(tmpRoot, "del-nomatch.txt"), "content");
426
- const req = new Request(fileUrl("del-nomatch.txt"), {
427
- method: "DELETE",
428
- headers: agentHeaders(DELETE_TOKEN, "ai:delete-agent"),
429
- });
430
- const res = await fileDELETE(req, makeCtx(["del-nomatch.txt"]));
431
- assert.equal(res.status, 412);
432
- const json = await res.json() as { error: string };
433
- assert.equal(json.error, "PRECONDITION_REQUIRED");
434
- });
435
-
436
- test("DELETE: If-Match mismatch → 412", async () => {
437
- await writeFile(path.join(tmpRoot, "del-mismatch.txt"), "content");
438
- const req = new Request(fileUrl("del-mismatch.txt"), {
439
- method: "DELETE",
440
- headers: {
441
- ...agentHeaders(DELETE_TOKEN, "ai:delete-agent"),
442
- "If-Match": `"sha256:${"0".repeat(64)}"`,
443
- },
444
- });
445
- const res = await fileDELETE(req, makeCtx(["del-mismatch.txt"]));
446
- assert.equal(res.status, 412);
447
- });
448
-
449
- test("DELETE: file with correct If-Match deleted", async () => {
450
- const content = Buffer.from("to be deleted");
451
- await writeFile(path.join(tmpRoot, "deleteme.txt"), content);
452
- const sha = sha256(content);
453
-
454
- const req = new Request(fileUrl("deleteme.txt"), {
455
- method: "DELETE",
456
- headers: {
457
- ...agentHeaders(DELETE_TOKEN, "ai:delete-agent"),
458
- "If-Match": `"${sha}"`,
459
- },
460
- });
461
- const res = await fileDELETE(req, makeCtx(["deleteme.txt"]));
462
- assert.equal(res.status, 200);
463
-
464
- // File gone
465
- await assert.rejects(
466
- () => readFile(path.join(tmpRoot, "deleteme.txt")),
467
- { code: "ENOENT" },
468
- );
469
- });
470
-
471
- test("DELETE: .md deletion also removes sidecar", async () => {
472
- const mdPath = "delete-with-sidecar.md";
473
- const content = Buffer.from("# Delete me\n");
474
- await writeFile(path.join(tmpRoot, mdPath), content);
475
- const sc = emptySidecar(mdPath);
476
- await writeSidecar(tmpRoot, mdPath, sc);
477
- const sha = sha256(content);
478
-
479
- const req = new Request(fileUrl(mdPath), {
480
- method: "DELETE",
481
- headers: {
482
- ...agentHeaders(DELETE_TOKEN, "ai:delete-agent"),
483
- "If-Match": `"${sha}"`,
484
- },
485
- });
486
- const res = await fileDELETE(req, makeCtx([mdPath]));
487
- assert.equal(res.status, 200);
488
-
489
- // Both file and sidecar gone
490
- await assert.rejects(
491
- () => readFile(path.join(tmpRoot, mdPath)),
492
- { code: "ENOENT" },
493
- );
494
- const sidecarAfter = await readSidecar(tmpRoot, mdPath);
495
- assert.equal(sidecarAfter, null, "sidecar deleted alongside .md");
496
- });
497
-
498
- test("DELETE: directory without ?recursive → 400", async () => {
499
- await mkdir(path.join(tmpRoot, "nodirdel"), { recursive: true });
500
- const req = new Request(fileUrl("nodirdel"), {
501
- method: "DELETE",
502
- headers: {
503
- ...agentHeaders(DELETE_TOKEN, "ai:delete-agent"),
504
- "If-Match": '"anything"',
505
- },
506
- });
507
- const res = await fileDELETE(req, makeCtx(["nodirdel"]));
508
- assert.equal(res.status, 400);
509
- const json = await res.json() as { error: string };
510
- assert.equal(json.error, "IS_DIRECTORY");
511
- });
512
-
513
- test("DELETE: directory with ?recursive=true succeeds", async () => {
514
- await mkdir(path.join(tmpRoot, "recdel"), { recursive: true });
515
- await writeFile(path.join(tmpRoot, "recdel/file.txt"), "hi");
516
- const req = new Request(fileUrl("recdel", "?recursive=true"), {
517
- method: "DELETE",
518
- headers: agentHeaders(DELETE_TOKEN, "ai:delete-agent"),
519
- });
520
- const res = await fileDELETE(req, makeCtx(["recdel"]));
521
- assert.equal(res.status, 200);
522
- });
523
-
524
- // ── ls tests ──────────────────────────────────────────────────────────────────
525
-
526
- test("ls: lists files in directory", async () => {
527
- await mkdir(path.join(tmpRoot, "ls-dir"), { recursive: true });
528
- await writeFile(path.join(tmpRoot, "ls-dir/a.txt"), "a");
529
- await writeFile(path.join(tmpRoot, "ls-dir/b.md"), "# b");
530
-
531
- const req = new Request(lsUrl("ls-dir"), {
532
- headers: agentHeaders(READ_TOKEN, "ai:read-agent"),
533
- });
534
- const res = await lsGET(req, makeLsCtx(["ls-dir"]));
535
- assert.equal(res.status, 200);
536
- const json = await res.json() as { entries: Array<{ name: string }> };
537
- const names = json.entries.map((e) => e.name).sort();
538
- assert.deepEqual(names, ["a.txt", "b.md"]);
539
- });
540
-
541
- test("ls: excludes .proof/ from results", async () => {
542
- // .proof dir may already exist from other tests — just check it's not listed
543
- await mkdir(path.join(tmpRoot, ".proof"), { recursive: true });
544
- await writeFile(path.join(tmpRoot, ".proof/test.json"), "{}");
545
-
546
- const req = new Request(lsUrl(""), {
547
- headers: agentHeaders(READ_TOKEN, "ai:read-agent"),
548
- });
549
- const res = await lsGET(req, makeLsCtx([]));
550
- assert.equal(res.status, 200);
551
- const json = await res.json() as { entries: Array<{ name: string }> };
552
- const hasProof = json.entries.some((e) => e.name === ".proof");
553
- assert.equal(hasProof, false, ".proof should be excluded");
554
- });
555
-
556
- test("ls: scope-filters entries — restricted agent only sees allowed/", async () => {
557
- await mkdir(path.join(tmpRoot, "allowed"), { recursive: true });
558
- await writeFile(path.join(tmpRoot, "allowed/ok.txt"), "yes");
559
- await writeFile(path.join(tmpRoot, "not-allowed.txt"), "no");
560
-
561
- const req = new Request(lsUrl(""), {
562
- headers: agentHeaders(RESTRICTED_TOKEN, "ai:restricted"),
563
- });
564
- const res = await lsGET(req, makeLsCtx([]));
565
- assert.equal(res.status, 200);
566
- const json = await res.json() as { entries: Array<{ name: string; path: string }> };
567
- // Restricted agent has scope "allowed/**" — not-allowed.txt should be absent
568
- const notAllowed = json.entries.find((e) => e.name === "not-allowed.txt");
569
- assert.equal(notAllowed, undefined, "out-of-scope file hidden from restricted agent");
570
- });
571
-
572
- test("ls: recursive=true traverses subdirs", async () => {
573
- await mkdir(path.join(tmpRoot, "rec/sub"), { recursive: true });
574
- await writeFile(path.join(tmpRoot, "rec/top.txt"), "top");
575
- await writeFile(path.join(tmpRoot, "rec/sub/deep.txt"), "deep");
576
-
577
- const req = new Request(lsUrl("rec", "?recursive"), {
578
- headers: agentHeaders(READ_TOKEN, "ai:read-agent"),
579
- });
580
- const res = await lsGET(req, makeLsCtx(["rec"]));
581
- assert.equal(res.status, 200);
582
- const json = await res.json() as { entries: Array<{ path: string }> };
583
- const paths = json.entries.map((e) => e.path);
584
- assert.ok(paths.some((p) => p.includes("deep.txt")), "deep.txt found in recursive listing");
585
- });
586
-
587
- test("ls: limit is respected", async () => {
588
- await mkdir(path.join(tmpRoot, "limit-dir"), { recursive: true });
589
- for (let i = 0; i < 10; i++) {
590
- await writeFile(path.join(tmpRoot, `limit-dir/f${i}.txt`), String(i));
591
- }
592
-
593
- const req = new Request(lsUrl("limit-dir", "?limit=3"), {
594
- headers: agentHeaders(READ_TOKEN, "ai:read-agent"),
595
- });
596
- const res = await lsGET(req, makeLsCtx(["limit-dir"]));
597
- assert.equal(res.status, 200);
598
- const json = await res.json() as { entries: unknown[]; truncated: boolean };
599
- assert.equal(json.entries.length, 3);
600
- assert.equal(json.truncated, true);
601
- });
602
-
603
- // ── move tests ────────────────────────────────────────────────────────────────
604
-
605
- test("move: renames a file", async () => {
606
- await writeFile(path.join(tmpRoot, "move-src.txt"), "data");
607
-
608
- const req = new Request("http://localhost/api/agent/fs/move", {
609
- method: "POST",
610
- headers: {
611
- ...agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"),
612
- "Content-Type": "application/json",
613
- },
614
- body: JSON.stringify({ from: "move-src.txt", to: "move-dst.txt" }),
615
- });
616
- const res = await movePOST(req);
617
- assert.equal(res.status, 200);
618
-
619
- const dst = await readFile(path.join(tmpRoot, "move-dst.txt"), "utf-8");
620
- assert.equal(dst, "data");
621
- await assert.rejects(
622
- () => readFile(path.join(tmpRoot, "move-src.txt")),
623
- { code: "ENOENT" },
624
- );
625
- });
626
-
627
- test("move: moves sidecar alongside .md", async () => {
628
- const fromMd = "move-from.md";
629
- const toMd = "move-to.md";
630
- await writeFile(path.join(tmpRoot, fromMd), "# From\n");
631
- const sc = emptySidecar(fromMd);
632
- sc.revision = 5;
633
- await writeSidecar(tmpRoot, fromMd, sc);
634
-
635
- const req = new Request("http://localhost/api/agent/fs/move", {
636
- method: "POST",
637
- headers: {
638
- ...agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"),
639
- "Content-Type": "application/json",
640
- },
641
- body: JSON.stringify({ from: fromMd, to: toMd }),
642
- });
643
- const res = await movePOST(req);
644
- assert.equal(res.status, 200);
645
-
646
- // Source sidecar gone, dest sidecar present with correct data
647
- const fromSidecar = await readSidecar(tmpRoot, fromMd);
648
- assert.equal(fromSidecar, null, "source sidecar removed");
649
- const toSidecar = await readSidecar(tmpRoot, toMd);
650
- assert.ok(toSidecar, "destination sidecar present");
651
- assert.equal(toSidecar!.revision, 5);
652
- });
653
-
654
- test("move: If-Match mismatch → 412", async () => {
655
- await writeFile(path.join(tmpRoot, "move-ifmatch.txt"), "content");
656
-
657
- const req = new Request("http://localhost/api/agent/fs/move", {
658
- method: "POST",
659
- headers: {
660
- ...agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"),
661
- "Content-Type": "application/json",
662
- },
663
- body: JSON.stringify({ from: "move-ifmatch.txt", to: "move-ifmatch-dst.txt", ifMatch: "sha256:" + "0".repeat(64) }),
664
- });
665
- const res = await movePOST(req);
666
- assert.equal(res.status, 412);
667
- });
668
-
669
- test("move: 404 when source doesn't exist", async () => {
670
- const req = new Request("http://localhost/api/agent/fs/move", {
671
- method: "POST",
672
- headers: {
673
- ...agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"),
674
- "Content-Type": "application/json",
675
- },
676
- body: JSON.stringify({ from: "no-such-file.txt", to: "dst.txt" }),
677
- });
678
- const res = await movePOST(req);
679
- assert.equal(res.status, 404);
680
- });
681
-
682
- // ── search tests ──────────────────────────────────────────────────────────────
683
-
684
- test("search grep: finds pattern in files", async () => {
685
- await mkdir(path.join(tmpRoot, "grep-dir"), { recursive: true });
686
- await writeFile(path.join(tmpRoot, "grep-dir/alpha.txt"), "hello world\nfoo bar\n");
687
- await writeFile(path.join(tmpRoot, "grep-dir/beta.txt"), "no match here\nhello again\n");
688
-
689
- const req = new Request("http://localhost/api/agent/fs/search", {
690
- method: "POST",
691
- headers: {
692
- ...agentHeaders(READ_TOKEN, "ai:read-agent"),
693
- "Content-Type": "application/json",
694
- },
695
- body: JSON.stringify({ kind: "grep", query: "hello", path: "grep-dir" }),
696
- });
697
- const res = await searchPOST(req);
698
- assert.equal(res.status, 200);
699
- const json = await res.json() as { matches: Array<{ path: string; line: number }> };
700
- assert.ok(json.matches.length >= 2, "both matches found");
701
- assert.ok(json.matches.every((m) => m.path.startsWith("grep-dir/")));
702
- });
703
-
704
- test("search grep: skips binary files", async () => {
705
- await mkdir(path.join(tmpRoot, "bin-dir"), { recursive: true });
706
- // Binary file (has null byte)
707
- const binBuf = Buffer.from([0x00, 0x01, 0x02, 0x68, 0x65, 0x6c, 0x6c, 0x6f]); // null + "hello"
708
- await writeFile(path.join(tmpRoot, "bin-dir/binary.bin"), binBuf);
709
- await writeFile(path.join(tmpRoot, "bin-dir/text.txt"), "hello from text");
710
-
711
- const req = new Request("http://localhost/api/agent/fs/search", {
712
- method: "POST",
713
- headers: {
714
- ...agentHeaders(READ_TOKEN, "ai:read-agent"),
715
- "Content-Type": "application/json",
716
- },
717
- body: JSON.stringify({ kind: "grep", query: "hello", path: "bin-dir" }),
718
- });
719
- const res = await searchPOST(req);
720
- assert.equal(res.status, 200);
721
- const json = await res.json() as { matches: Array<{ path: string }> };
722
- // Binary file skipped, only text.txt matches
723
- assert.ok(json.matches.every((m) => !m.path.endsWith(".bin")), "binary file skipped");
724
- assert.ok(json.matches.some((m) => m.path.endsWith("text.txt")), "text file found");
725
- });
726
-
727
- test("search glob: finds files matching pattern", async () => {
728
- await mkdir(path.join(tmpRoot, "glob-dir"), { recursive: true });
729
- await writeFile(path.join(tmpRoot, "glob-dir/a.md"), "# A");
730
- await writeFile(path.join(tmpRoot, "glob-dir/b.ts"), "const x = 1;");
731
- await writeFile(path.join(tmpRoot, "glob-dir/c.md"), "# C");
732
-
733
- const req = new Request("http://localhost/api/agent/fs/search", {
734
- method: "POST",
735
- headers: {
736
- ...agentHeaders(READ_TOKEN, "ai:read-agent"),
737
- "Content-Type": "application/json",
738
- },
739
- body: JSON.stringify({ kind: "glob", query: "*.md", path: "glob-dir" }),
740
- });
741
- const res = await searchPOST(req);
742
- assert.equal(res.status, 200);
743
- const json = await res.json() as { matches: Array<{ path: string }> };
744
- assert.ok(json.matches.length >= 2, "both .md files found");
745
- assert.ok(json.matches.every((m) => m.path.endsWith(".md")), "only .md files returned");
746
- });
747
-
748
- test("search: scope-rechecks each result — restricted agent only sees allowed/ files", async () => {
749
- await mkdir(path.join(tmpRoot, "allowed/search-sub"), { recursive: true });
750
- await writeFile(path.join(tmpRoot, "allowed/search-sub/in-scope.txt"), "find me");
751
- await writeFile(path.join(tmpRoot, "out-of-scope-search.txt"), "find me too");
752
-
753
- const req = new Request("http://localhost/api/agent/fs/search", {
754
- method: "POST",
755
- headers: {
756
- ...agentHeaders(RESTRICTED_TOKEN, "ai:restricted"),
757
- "Content-Type": "application/json",
758
- },
759
- body: JSON.stringify({ kind: "grep", query: "find me" }),
760
- });
761
- const res = await searchPOST(req);
762
- assert.equal(res.status, 200);
763
- const json = await res.json() as { matches: Array<{ path: string }> };
764
- // out-of-scope-search.txt must not appear
765
- const hasOutOfScope = json.matches.some((m) => m.path.includes("out-of-scope-search"));
766
- assert.equal(hasOutOfScope, false, "out-of-scope file hidden from restricted agent");
767
- });
768
-
769
- test("search: invalid regex → 400", async () => {
770
- const req = new Request("http://localhost/api/agent/fs/search", {
771
- method: "POST",
772
- headers: {
773
- ...agentHeaders(READ_TOKEN, "ai:read-agent"),
774
- "Content-Type": "application/json",
775
- },
776
- body: JSON.stringify({ kind: "grep", query: "[invalid" }),
777
- });
778
- const res = await searchPOST(req);
779
- assert.equal(res.status, 400);
780
- });
781
-
782
- // ── Path safety (traversal + symlink) ────────────────────────────────────────
783
-
784
- test("traversal: PUT rejects ../ path", async () => {
785
- const req = new Request(fileUrl("../outside.txt"), {
786
- method: "PUT",
787
- headers: agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"),
788
- body: Buffer.from("escape attempt"),
789
- });
790
- const res = await filePUT(req, makeCtx(["../outside.txt"]));
791
- assert.equal(res.status, 400);
792
- });
793
-
794
- test("symlink escape: PUT rejects symlink pointing outside root", async () => {
795
- // Create a symlink inside root pointing outside
796
- const escapedDir = await mkdtemp(path.join(tmpdir(), "escape-target-"));
797
- try {
798
- const symlinkPath = path.join(tmpRoot, "escape-link");
799
- try {
800
- await symlink(escapedDir, symlinkPath);
801
- } catch {
802
- // symlink already exists from prior run
803
- }
804
-
805
- const req = new Request(fileUrl("escape-link/secret.txt"), {
806
- method: "PUT",
807
- headers: agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"),
808
- body: Buffer.from("escaped!"),
809
- });
810
- const res = await filePUT(req, makeCtx(["escape-link", "secret.txt"]));
811
- // Should reject: symlink escapes root
812
- assert.equal(res.status, 400);
813
- } finally {
814
- await rm(escapedDir, { recursive: true, force: true });
815
- }
816
- });
817
-
818
- test("traversal: .proof/ denied on PUT", async () => {
819
- const req = new Request(fileUrl(".proof/inject.json"), {
820
- method: "PUT",
821
- headers: agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"),
822
- body: Buffer.from("{}"),
823
- });
824
- const res = await filePUT(req, makeCtx([".proof", "inject.json"]));
825
- assert.equal(res.status, 400);
826
- });
827
-
828
- // ── PATCH (server-side str-replace) ──────────────────────────────────────────
829
-
830
- test("PATCH: str-replace on .md succeeds, sends only find/replace", async () => {
831
- const orig = Buffer.from("# Title\n\nHello world. Keep this.\n");
832
- await writeFile(path.join(tmpRoot, "patch1.md"), orig);
833
- const req = new Request(fileUrl("patch1.md"), {
834
- method: "PATCH",
835
- headers: { ...agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"), "Content-Type": "application/json", "If-Match": sha256(orig) },
836
- body: JSON.stringify({ find: "Hello world", replace: "Goodbye moon" }),
837
- });
838
- const res = await filePATCH(req, makeCtx(["patch1.md"]));
839
- assert.equal(res.status, 200, await res.text());
840
- const out = await readFile(path.join(tmpRoot, "patch1.md"), "utf-8");
841
- assert.equal(out, "# Title\n\nGoodbye moon. Keep this.\n");
842
- });
843
-
844
- test("PATCH: missing If-Match → 412", async () => {
845
- const orig = Buffer.from("alpha beta gamma");
846
- await writeFile(path.join(tmpRoot, "patch2.txt"), orig);
847
- const req = new Request(fileUrl("patch2.txt"), {
848
- method: "PATCH",
849
- headers: { ...agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"), "Content-Type": "application/json" },
850
- body: JSON.stringify({ find: "beta", replace: "BETA" }),
851
- });
852
- const res = await filePATCH(req, makeCtx(["patch2.txt"]));
853
- assert.equal(res.status, 412);
854
- });
855
-
856
- test("PATCH: If-Match mismatch → 412", async () => {
857
- const orig = Buffer.from("alpha beta gamma");
858
- await writeFile(path.join(tmpRoot, "patch3.txt"), orig);
859
- const req = new Request(fileUrl("patch3.txt"), {
860
- method: "PATCH",
861
- headers: { ...agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"), "Content-Type": "application/json", "If-Match": "sha256:deadbeef" },
862
- body: JSON.stringify({ find: "beta", replace: "BETA" }),
863
- });
864
- const res = await filePATCH(req, makeCtx(["patch3.txt"]));
865
- assert.equal(res.status, 412);
866
- });
867
-
868
- test("PATCH: zero matches → 422 MATCH_COUNT_MISMATCH", async () => {
869
- const orig = Buffer.from("alpha beta gamma");
870
- await writeFile(path.join(tmpRoot, "patch4.txt"), orig);
871
- const req = new Request(fileUrl("patch4.txt"), {
872
- method: "PATCH",
873
- headers: { ...agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"), "Content-Type": "application/json", "If-Match": sha256(orig) },
874
- body: JSON.stringify({ find: "nonexistent", replace: "x" }),
875
- });
876
- const res = await filePATCH(req, makeCtx(["patch4.txt"]));
877
- assert.equal(res.status, 422);
878
- const j = await res.json();
879
- assert.equal(j.error, "MATCH_COUNT_MISMATCH");
880
- assert.equal(j.found, 0);
881
- });
882
-
883
- test("PATCH: multiple matches but expected 1 → 422", async () => {
884
- const orig = Buffer.from("foo bar foo baz foo");
885
- await writeFile(path.join(tmpRoot, "patch5.txt"), orig);
886
- const req = new Request(fileUrl("patch5.txt"), {
887
- method: "PATCH",
888
- headers: { ...agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"), "Content-Type": "application/json", "If-Match": sha256(orig) },
889
- body: JSON.stringify({ find: "foo", replace: "X" }),
890
- });
891
- const res = await filePATCH(req, makeCtx(["patch5.txt"]));
892
- assert.equal(res.status, 422);
893
- const j = await res.json();
894
- assert.equal(j.found, 3);
895
- });
896
-
897
- test("PATCH: expectedOccurrences matching multi replaces all", async () => {
898
- const orig = Buffer.from("foo bar foo baz foo");
899
- await writeFile(path.join(tmpRoot, "patch6.txt"), orig);
900
- const req = new Request(fileUrl("patch6.txt"), {
901
- method: "PATCH",
902
- headers: { ...agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"), "Content-Type": "application/json", "If-Match": sha256(orig) },
903
- body: JSON.stringify({ find: "foo", replace: "X", expectedOccurrences: 3 }),
904
- });
905
- const res = await filePATCH(req, makeCtx(["patch6.txt"]));
906
- assert.equal(res.status, 200, await res.text());
907
- const out = await readFile(path.join(tmpRoot, "patch6.txt"), "utf-8");
908
- assert.equal(out, "X bar X baz X");
909
- });
910
-
911
- test("PATCH: empty find → 400", async () => {
912
- const orig = Buffer.from("abc");
913
- await writeFile(path.join(tmpRoot, "patch7.txt"), orig);
914
- const req = new Request(fileUrl("patch7.txt"), {
915
- method: "PATCH",
916
- headers: { ...agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"), "Content-Type": "application/json", "If-Match": sha256(orig) },
917
- body: JSON.stringify({ find: "", replace: "x" }),
918
- });
919
- const res = await filePATCH(req, makeCtx(["patch7.txt"]));
920
- assert.equal(res.status, 400);
921
- });
922
-
923
- test("PATCH: binary file → 415", async () => {
924
- const orig = Buffer.from([0x00, 0x01, 0x02, 0xff, 0xfe, 0x00, 0x10]);
925
- await writeFile(path.join(tmpRoot, "patch8.bin"), orig);
926
- const req = new Request(fileUrl("patch8.bin"), {
927
- method: "PATCH",
928
- headers: { ...agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"), "Content-Type": "application/json", "If-Match": sha256(orig) },
929
- body: JSON.stringify({ find: "x", replace: "y" }),
930
- });
931
- const res = await filePATCH(req, makeCtx(["patch8.bin"]));
932
- assert.equal(res.status, 415);
933
- });
934
-
935
- test("PATCH: nonexistent file → 404 (no create)", async () => {
936
- const req = new Request(fileUrl("patch-missing.txt"), {
937
- method: "PATCH",
938
- headers: { ...agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"), "Content-Type": "application/json", "If-Match": "sha256:abc" },
939
- body: JSON.stringify({ find: "a", replace: "b" }),
940
- });
941
- const res = await filePATCH(req, makeCtx(["patch-missing.txt"]));
942
- assert.equal(res.status, 404);
943
- });
944
-
945
- test("PATCH: .md emits file.rawWritten + reconciles (same path as PUT)", async () => {
946
- const orig = Buffer.from("# H\n\noriginal paragraph here\n");
947
- await writeFile(path.join(tmpRoot, "patch-md.md"), orig);
948
- const req = new Request(fileUrl("patch-md.md"), {
949
- method: "PATCH",
950
- headers: { ...agentHeaders(MUTATE_TOKEN, "ai:mutate-agent"), "Content-Type": "application/json", "If-Match": sha256(orig) },
951
- body: JSON.stringify({ find: "original", replace: "updated" }),
952
- });
953
- const res = await filePATCH(req, makeCtx(["patch-md.md"]));
954
- assert.equal(res.status, 200, await res.text());
955
- const sidecar = await readSidecar(tmpRoot, "patch-md.md");
956
- assert.ok(sidecar, "sidecar created");
957
- const events = sidecar!.events.filter((e) => e.type === "file.rawWritten");
958
- assert.ok(events.length > 0, "file.rawWritten event present");
959
- const newContent = await readFile(path.join(tmpRoot, "patch-md.md"), "utf-8");
960
- assert.equal(sidecar!.fingerprint, sha256(Buffer.from(newContent)), "fingerprint matches new content (eager reconcile)");
961
- });
962
-
963
- test("PATCH: requires mutate scope", async () => {
964
- const orig = Buffer.from("hello");
965
- await writeFile(path.join(tmpRoot, "patch-scope.txt"), orig);
966
- const req = new Request(fileUrl("patch-scope.txt"), {
967
- method: "PATCH",
968
- headers: { ...agentHeaders(READ_TOKEN, "ai:read-agent"), "Content-Type": "application/json", "If-Match": sha256(orig) },
969
- body: JSON.stringify({ find: "hello", replace: "hi" }),
970
- });
971
- const res = await filePATCH(req, makeCtx(["patch-scope.txt"]));
972
- assert.equal(res.status, 403);
973
- });