wiki-viewer 1.4.2 → 1.5.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 (280) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +5 -0
  3. package/.next/standalone/.next/build-manifest.json +3 -3
  4. package/.next/standalone/.next/prerender-manifest.json +3 -27
  5. package/.next/standalone/.next/routes-manifest.json +34 -0
  6. package/.next/standalone/.next/server/app/_global-error/page.js +2 -2
  7. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  11. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  12. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  13. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page.js +4 -4
  16. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  17. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  18. package/.next/standalone/.next/server/app/_not-found.rsc +1 -1
  19. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  20. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  21. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  22. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  23. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  24. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  25. package/.next/standalone/.next/server/app/api/agent/activity/route.js +5 -5
  26. package/.next/standalone/.next/server/app/api/agent/activity/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/agent/admin/agents/[agentId]/revoke/route.js +6 -6
  28. package/.next/standalone/.next/server/app/api/agent/admin/agents/[agentId]/revoke/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/agent/admin/agents/route.js +6 -6
  30. package/.next/standalone/.next/server/app/api/agent/admin/agents/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/agent/admin/registrations/[regId]/approve/route.js +6 -6
  32. package/.next/standalone/.next/server/app/api/agent/admin/registrations/[regId]/approve/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/api/agent/admin/registrations/[regId]/deny/route.js +4 -4
  34. package/.next/standalone/.next/server/app/api/agent/admin/registrations/[regId]/deny/route.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/api/agent/admin/registrations/route.js +4 -4
  36. package/.next/standalone/.next/server/app/api/agent/admin/registrations/route.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/api/agent/events/[...path]/route.js +5 -5
  38. package/.next/standalone/.next/server/app/api/agent/events/[...path]/route.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/api/agent/files/[...path]/route.js +11 -10
  40. package/.next/standalone/.next/server/app/api/agent/files/[...path]/route.js.nft.json +1 -1
  41. package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route/app-paths-manifest.json +3 -0
  42. package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route/build-manifest.json +9 -0
  43. package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route/server-reference-manifest.json +4 -0
  44. package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js +17 -0
  45. package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js.map +5 -0
  46. package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js.nft.json +1 -0
  47. package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route_client-reference-manifest.js +3 -0
  48. package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route/app-paths-manifest.json +3 -0
  49. package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route/build-manifest.json +9 -0
  50. package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route/server-reference-manifest.json +4 -0
  51. package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route.js +15 -0
  52. package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route.js.map +5 -0
  53. package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route.js.nft.json +1 -0
  54. package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route_client-reference-manifest.js +3 -0
  55. package/.next/standalone/.next/server/app/api/agent/fs/move/route/app-paths-manifest.json +3 -0
  56. package/.next/standalone/.next/server/app/api/agent/fs/move/route/build-manifest.json +9 -0
  57. package/.next/standalone/.next/server/app/api/agent/fs/move/route/server-reference-manifest.json +4 -0
  58. package/.next/standalone/.next/server/app/api/agent/fs/move/route.js +15 -0
  59. package/.next/standalone/.next/server/app/api/agent/fs/move/route.js.map +5 -0
  60. package/.next/standalone/.next/server/app/api/agent/fs/move/route.js.nft.json +1 -0
  61. package/.next/standalone/.next/server/app/api/agent/fs/move/route_client-reference-manifest.js +3 -0
  62. package/.next/standalone/.next/server/app/api/agent/fs/search/route/app-paths-manifest.json +3 -0
  63. package/.next/standalone/.next/server/app/api/agent/fs/search/route/build-manifest.json +9 -0
  64. package/.next/standalone/.next/server/app/api/agent/fs/search/route/server-reference-manifest.json +4 -0
  65. package/.next/standalone/.next/server/app/api/agent/fs/search/route.js +15 -0
  66. package/.next/standalone/.next/server/app/api/agent/fs/search/route.js.map +5 -0
  67. package/.next/standalone/.next/server/app/api/agent/fs/search/route.js.nft.json +1 -0
  68. package/.next/standalone/.next/server/app/api/agent/fs/search/route_client-reference-manifest.js +3 -0
  69. package/.next/standalone/.next/server/app/api/agent/internal/span/route.js +8 -8
  70. package/.next/standalone/.next/server/app/api/agent/internal/span/route.js.nft.json +1 -1
  71. package/.next/standalone/.next/server/app/api/agent/settings/route.js +8 -8
  72. package/.next/standalone/.next/server/app/api/agent/settings/route.js.nft.json +1 -1
  73. package/.next/standalone/.next/server/app/api/agent/sidecar/[...path]/route.js +7 -7
  74. package/.next/standalone/.next/server/app/api/agent/sidecar/[...path]/route.js.nft.json +1 -1
  75. package/.next/standalone/.next/server/app/api/app-proxy/[...path]/route.js +1 -1
  76. package/.next/standalone/.next/server/app/api/app-proxy/[...path]/route.js.nft.json +1 -1
  77. package/.next/standalone/.next/server/app/api/assets/[...path]/route.js.nft.json +1 -1
  78. package/.next/standalone/.next/server/app/api/auth/[...all]/route.js +3 -3
  79. package/.next/standalone/.next/server/app/api/auth/[...all]/route.js.nft.json +1 -1
  80. package/.next/standalone/.next/server/app/api/system/auth-config/route.js +5 -5
  81. package/.next/standalone/.next/server/app/api/system/auth-config/route.js.nft.json +1 -1
  82. package/.next/standalone/.next/server/app/api/system/auth-settings/route.js +4 -4
  83. package/.next/standalone/.next/server/app/api/system/auth-settings/route.js.nft.json +1 -1
  84. package/.next/standalone/.next/server/app/api/system/browse/route.js +6 -6
  85. package/.next/standalone/.next/server/app/api/system/browse/route.js.nft.json +1 -1
  86. package/.next/standalone/.next/server/app/api/system/clear-root/route.js +5 -5
  87. package/.next/standalone/.next/server/app/api/system/clear-root/route.js.nft.json +1 -1
  88. package/.next/standalone/.next/server/app/api/system/config/route.js +5 -5
  89. package/.next/standalone/.next/server/app/api/system/config/route.js.nft.json +1 -1
  90. package/.next/standalone/.next/server/app/api/system/pins/route.js +4 -4
  91. package/.next/standalone/.next/server/app/api/system/pins/route.js.nft.json +1 -1
  92. package/.next/standalone/.next/server/app/api/system/reveal/route.js +4 -4
  93. package/.next/standalone/.next/server/app/api/system/reveal/route.js.nft.json +1 -1
  94. package/.next/standalone/.next/server/app/api/system/root-status/route.js +4 -4
  95. package/.next/standalone/.next/server/app/api/system/root-status/route.js.nft.json +1 -1
  96. package/.next/standalone/.next/server/app/api/system/set-root/route.js +5 -5
  97. package/.next/standalone/.next/server/app/api/system/set-root/route.js.nft.json +1 -1
  98. package/.next/standalone/.next/server/app/api/upload/[...path]/route.js.nft.json +1 -1
  99. package/.next/standalone/.next/server/app/api/wiki/app/route.js +6 -6
  100. package/.next/standalone/.next/server/app/api/wiki/app/route.js.nft.json +1 -1
  101. package/.next/standalone/.next/server/app/api/wiki/content/route.js +6 -6
  102. package/.next/standalone/.next/server/app/api/wiki/content/route.js.nft.json +1 -1
  103. package/.next/standalone/.next/server/app/api/wiki/file/route.js.nft.json +1 -1
  104. package/.next/standalone/.next/server/app/api/wiki/folder/route.js +5 -5
  105. package/.next/standalone/.next/server/app/api/wiki/folder/route.js.nft.json +1 -1
  106. package/.next/standalone/.next/server/app/api/wiki/move/route.js +6 -6
  107. package/.next/standalone/.next/server/app/api/wiki/move/route.js.nft.json +1 -1
  108. package/.next/standalone/.next/server/app/api/wiki/new-file/route.js +5 -5
  109. package/.next/standalone/.next/server/app/api/wiki/new-file/route.js.nft.json +1 -1
  110. package/.next/standalone/.next/server/app/api/wiki/page/route.js +5 -5
  111. package/.next/standalone/.next/server/app/api/wiki/page/route.js.nft.json +1 -1
  112. package/.next/standalone/.next/server/app/api/wiki/presence/route/app-paths-manifest.json +3 -0
  113. package/.next/standalone/.next/server/app/api/wiki/presence/route/build-manifest.json +9 -0
  114. package/.next/standalone/.next/server/app/api/wiki/presence/route/server-reference-manifest.json +4 -0
  115. package/.next/standalone/.next/server/app/api/wiki/presence/route.js +14 -0
  116. package/.next/standalone/.next/server/app/api/wiki/presence/route.js.map +5 -0
  117. package/.next/standalone/.next/server/app/api/wiki/presence/route.js.nft.json +1 -0
  118. package/.next/standalone/.next/server/app/api/wiki/presence/route_client-reference-manifest.js +3 -0
  119. package/.next/standalone/.next/server/app/api/wiki/route.js +5 -5
  120. package/.next/standalone/.next/server/app/api/wiki/route.js.nft.json +1 -1
  121. package/.next/standalone/.next/server/app/api/wiki/slugs/route.js +5 -5
  122. package/.next/standalone/.next/server/app/api/wiki/slugs/route.js.nft.json +1 -1
  123. package/.next/standalone/.next/server/app/api/wiki/upload/route.js +5 -5
  124. package/.next/standalone/.next/server/app/api/wiki/upload/route.js.nft.json +1 -1
  125. package/.next/standalone/.next/server/app/api/wiki/watch/route.js +6 -6
  126. package/.next/standalone/.next/server/app/api/wiki/watch/route.js.nft.json +1 -1
  127. package/.next/standalone/.next/server/app/index.html +1 -1
  128. package/.next/standalone/.next/server/app/index.rsc +2 -2
  129. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  130. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
  131. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  132. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  133. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  134. package/.next/standalone/.next/server/app/page.js +4 -4
  135. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  136. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  137. package/.next/standalone/.next/server/app/signin/page.js +9 -4
  138. package/.next/standalone/.next/server/app/signin/page.js.nft.json +1 -1
  139. package/.next/standalone/.next/server/app/signin/page_client-reference-manifest.js +1 -1
  140. package/.next/standalone/.next/server/app-paths-manifest.json +5 -0
  141. package/.next/standalone/.next/server/chunks/0p91_next_dist_esm_build_templates_app-route_0d2jbo5.js +3 -0
  142. package/.next/standalone/.next/server/chunks/0p91_next_dist_esm_build_templates_app-route_0ytral2.js +3 -0
  143. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0269d2e._.js +1 -1
  144. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__03h3~3e._.js → [root-of-the-server]__04udrya._.js} +2 -2
  145. package/.next/standalone/.next/server/chunks/[root-of-the-server]__05f6x0i._.js +3 -0
  146. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06-dtd0._.js +3 -0
  147. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06sek6_._.js +1 -1
  148. package/.next/standalone/.next/server/chunks/[root-of-the-server]__09s9qkd._.js +1 -1
  149. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d75a5q._.js +1 -1
  150. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d_da6q._.js +3 -0
  151. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e7si9p._.js +1 -1
  152. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0hhhvm7._.js +1 -1
  153. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__04g0j8i._.js → [root-of-the-server]__0kdn1le._.js} +2 -2
  154. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0kk26wc._.js +3 -0
  155. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0kur4ro._.js +15 -0
  156. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0p12-6~._.js +1 -1
  157. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0qc2~6l._.js +15 -0
  158. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0s~i040._.js +3 -0
  159. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0w47wil._.js +1 -1
  160. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0xq124z._.js +3 -0
  161. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0l..bxz._.js → [root-of-the-server]__0xz-_0v._.js} +2 -2
  162. package/.next/standalone/.next/server/chunks/[root-of-the-server]__10w2q~o._.js +1 -1
  163. package/.next/standalone/.next/server/chunks/_079xuln._.js +3 -0
  164. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_agent_fs_file_[___path]_route_actions_0gb11t~.js +3 -0
  165. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_agent_fs_ls_[[___path]]_route_actions_0wfg4nl.js +3 -0
  166. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_agent_fs_move_route_actions_0z34mqq.js +3 -0
  167. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_agent_fs_search_route_actions_0ut_ug..js +3 -0
  168. package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_wiki_presence_route_actions_0x9d7f4.js +3 -0
  169. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0d89o98._.js → src_lib_auth_server_ts_00f4e0h._.js} +2 -2
  170. package/.next/standalone/.next/server/chunks/ssr/0biy_@better-auth_core_dist_121m_lh._.js +5 -0
  171. package/.next/standalone/.next/server/chunks/ssr/0dhv_better-auth_dist_adapters_kysely-adapter_index_mjs_08ymlcb._.js +3 -0
  172. package/.next/standalone/.next/server/chunks/ssr/0dti_kysely_dist_esm_0-t3o9q._.js +3 -0
  173. package/.next/standalone/.next/server/chunks/ssr/0dti_kysely_dist_esm_01._58q._.js +3 -0
  174. package/.next/standalone/.next/server/chunks/ssr/0p91_next_0f40gy0._.js +6 -0
  175. package/.next/standalone/.next/server/chunks/ssr/{0p91_next_dist_0~2d1tl._.js → 0p91_next_dist_10ud_sa._.js} +2 -2
  176. package/.next/standalone/.next/server/chunks/ssr/0sag_@better-auth_memory-adapter_dist_index_mjs_07-_ka6._.js +3 -0
  177. package/.next/standalone/.next/server/chunks/ssr/0ugq_@better-auth_kysely-adapter_dist_bun-sqlite-dialect-DzNwOpKv_mjs_0lruvb8._.js +3 -0
  178. package/.next/standalone/.next/server/chunks/ssr/0ugq_@better-auth_kysely-adapter_dist_d1-sqlite-dialect-C2B7YsIT_mjs_03n6~tc._.js +3 -0
  179. package/.next/standalone/.next/server/chunks/ssr/0ugq_@better-auth_kysely-adapter_dist_index_mjs_0gi5w.w._.js +4 -0
  180. package/.next/standalone/.next/server/chunks/ssr/0ugq_@better-auth_kysely-adapter_dist_node-sqlite-dialect_mjs_0l4.y~0._.js +3 -0
  181. package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_diagram-OG6HWLK6_mjs_0t5sus6._.js +1 -1
  182. package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_sankeyDiagram-5OEKKPKP_mjs_11ifrnu._.js +1 -1
  183. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__026s8~z._.js +3 -0
  184. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__06mzg2t._.js +3 -0
  185. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0btcd4o._.js +12 -0
  186. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0c~og-9._.js +3 -0
  187. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__134_q7l._.js +1 -1
  188. package/.next/standalone/.next/server/chunks/ssr/_0pqaawz._.js +3 -3
  189. package/.next/standalone/.next/server/chunks/ssr/node_modules__pnpm_051tcva._.js +3 -0
  190. package/.next/standalone/.next/server/chunks/ssr/node_modules__pnpm_0o~d81.._.js +1 -1
  191. package/.next/standalone/.next/server/chunks/ssr/node_modules__pnpm_0y9k6h~._.js +1 -1
  192. package/.next/standalone/.next/server/chunks/ssr/node_modules__pnpm_0znncy9._.js +1 -1
  193. package/.next/standalone/.next/server/chunks/ssr/node_modules__pnpm_12-ni1n._.js +1 -1
  194. package/.next/standalone/.next/server/chunks/ssr/src_app_signin_00yk0vm._.js +452 -0
  195. package/.next/standalone/.next/server/chunks/ssr/src_app_signin_signin-form_tsx_0eznlbd._.js +3 -0
  196. package/.next/standalone/.next/server/functions-config-manifest.json +5 -0
  197. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  198. package/.next/standalone/.next/server/middleware-manifest.json +5 -5
  199. package/.next/standalone/.next/server/pages/404.html +1 -1
  200. package/.next/standalone/.next/server/pages/500.html +1 -1
  201. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  202. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  203. package/.next/standalone/.next/static/chunks/09-jtayuhrq~b.js +1 -0
  204. package/.next/standalone/.next/static/chunks/0uv7ozzpiyp2_.js +1 -0
  205. package/.next/standalone/.next/static/chunks/135c~rq_ux73w.js +1 -0
  206. package/.next/standalone/.next/static/chunks/{11s9zwr7edrs7.js → 14luv~jq7e6-n.js} +12 -12
  207. package/.next/standalone/README.md +79 -16
  208. package/.next/standalone/agents/bootstrap-prompt.md +12 -1
  209. package/.next/standalone/agents/wiki-viewer-skill/SKILL.md +199 -6
  210. package/.next/standalone/docs/agent-fs-plan.md +65 -7
  211. package/.next/standalone/docs/file-vs-collab-authority.md +124 -0
  212. package/.next/standalone/package.json +1 -1
  213. package/.next/standalone/packages/wiki-viewer-mcp/README.md +194 -0
  214. package/.next/standalone/packages/wiki-viewer-mcp/dist/http-client.js +220 -0
  215. package/.next/standalone/packages/wiki-viewer-mcp/dist/index.js +472 -0
  216. package/.next/standalone/packages/wiki-viewer-mcp/dist/register.js +94 -0
  217. package/.next/standalone/packages/wiki-viewer-mcp/dist/state-cache.js +26 -0
  218. package/.next/standalone/packages/wiki-viewer-mcp/package-lock.json +1716 -0
  219. package/.next/standalone/packages/wiki-viewer-mcp/package.json +41 -0
  220. package/.next/standalone/packages/wiki-viewer-mcp/src/http-client.ts +344 -0
  221. package/.next/standalone/packages/wiki-viewer-mcp/src/index.ts +575 -0
  222. package/.next/standalone/packages/wiki-viewer-mcp/src/register.ts +144 -0
  223. package/.next/standalone/packages/wiki-viewer-mcp/src/state-cache.ts +45 -0
  224. package/.next/standalone/packages/wiki-viewer-mcp/tsconfig.json +19 -0
  225. package/.next/standalone/pnpm-lock.yaml +9 -9
  226. package/.next/standalone/src/app/api/agent/files/[...path]/route.ts +11 -1
  227. package/.next/standalone/src/app/api/agent/fs/file/[...path]/route.ts +344 -0
  228. package/.next/standalone/src/app/api/agent/fs/ls/[[...path]]/route.ts +147 -0
  229. package/.next/standalone/src/app/api/agent/fs/move/route.ts +125 -0
  230. package/.next/standalone/src/app/api/agent/fs/search/route.ts +236 -0
  231. package/.next/standalone/src/app/api/agent/register/route.ts +3 -3
  232. package/.next/standalone/src/app/api/agents/install/route.ts +44 -2
  233. package/.next/standalone/src/app/api/wiki/move/route.ts +10 -1
  234. package/.next/standalone/src/app/api/wiki/presence/route.ts +55 -0
  235. package/.next/standalone/src/app/signin/page.tsx +10 -225
  236. package/.next/standalone/src/app/signin/signin-form.tsx +238 -0
  237. package/.next/standalone/src/components/ai-panel/ai-panel.tsx +49 -0
  238. package/.next/standalone/src/components/editor/editor.tsx +38 -0
  239. package/.next/standalone/src/lib/proof/audit.ts +79 -0
  240. package/.next/standalone/src/lib/proof/auth.ts +2 -2
  241. package/.next/standalone/src/lib/proof/collab-state.ts +79 -0
  242. package/.next/standalone/src/lib/proof/lease.ts +104 -0
  243. package/.next/standalone/src/lib/proof/ops-applier.ts +74 -25
  244. package/.next/standalone/src/lib/proof/raw-fs.ts +198 -0
  245. package/.next/standalone/src/lib/proof/registry.ts +1 -1
  246. package/.next/standalone/src/lib/proof/sidecar.ts +38 -1
  247. package/.next/standalone/src/lib/proof/types.ts +13 -1
  248. package/.next/standalone/src/tests/proof/agent-fs.test.ts +824 -0
  249. package/.next/standalone/src/tests/proof/agents-install.test.ts +53 -0
  250. package/.next/standalone/src/tests/proof/collab-state.test.ts +499 -0
  251. package/.next/standalone/src/tests/proof/reconcile-sidecar.test.ts +195 -0
  252. package/.next/standalone/src/tests/proof/sidecar-lifecycle.test.ts +177 -0
  253. package/.next/standalone/tsconfig.tsbuildinfo +1 -1
  254. package/README.md +79 -16
  255. package/package.json +1 -1
  256. package/.next/standalone/.next/server/app/signin.html +0 -1
  257. package/.next/standalone/.next/server/app/signin.meta +0 -15
  258. package/.next/standalone/.next/server/app/signin.rsc +0 -23
  259. package/.next/standalone/.next/server/app/signin.segments/_full.segment.rsc +0 -23
  260. package/.next/standalone/.next/server/app/signin.segments/_head.segment.rsc +0 -6
  261. package/.next/standalone/.next/server/app/signin.segments/_index.segment.rsc +0 -7
  262. package/.next/standalone/.next/server/app/signin.segments/_tree.segment.rsc +0 -3
  263. package/.next/standalone/.next/server/app/signin.segments/signin/__PAGE__.segment.rsc +0 -9
  264. package/.next/standalone/.next/server/app/signin.segments/signin.segment.rsc +0 -5
  265. package/.next/standalone/.next/server/chunks/[root-of-the-server]__09~~-nd._.js +0 -3
  266. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0w87kiz._.js +0 -3
  267. package/.next/standalone/.next/server/chunks/[root-of-the-server]__12ssbhv._.js +0 -3
  268. package/.next/standalone/.next/server/chunks/node_modules__pnpm_0g0fhfk._.js +0 -3
  269. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__088hqzy._.js +0 -3
  270. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0c147fo._.js +0 -3
  271. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0z.1v1z._.js +0 -3
  272. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12zp2dm._.js +0 -3
  273. package/.next/standalone/.next/server/chunks/ssr/node_modules__pnpm_0exqvyf._.js +0 -3
  274. package/.next/standalone/.next/server/chunks/ssr/src_app_signin_page_tsx_1143y49._.js +0 -3
  275. package/.next/standalone/.next/static/chunks/0-_39e4awbk8y.js +0 -1
  276. package/.next/standalone/.next/static/chunks/02bxx~2cg~s6~.js +0 -1
  277. package/.next/standalone/.next/static/chunks/0mj_f8ncf2tks.js +0 -1
  278. /package/.next/standalone/.next/static/{OwXjVuoXDC_gda_BKji1J → 19j4-_brJLoulXAMekpM2}/_buildManifest.js +0 -0
  279. /package/.next/standalone/.next/static/{OwXjVuoXDC_gda_BKji1J → 19j4-_brJLoulXAMekpM2}/_clientMiddlewareManifest.js +0 -0
  280. /package/.next/standalone/.next/static/{OwXjVuoXDC_gda_BKji1J → 19j4-_brJLoulXAMekpM2}/_ssgManifest.js +0 -0
@@ -1,231 +1,16 @@
1
- "use client";
1
+ import SignInForm from "./signin-form";
2
+ import { passwordAuthEnabled } from "@/lib/auth/server";
2
3
 
3
- import { useState, useEffect, type FormEvent } from "react";
4
- import { authClient } from "@/lib/auth/client";
4
+ // Server component: resolve the available auth methods at render time so the
5
+ // initial HTML already reflects the configuration. This prevents the password
6
+ // form from flashing on load when it is disabled (AUTH_DISABLE_PASSWORD=1).
7
+ export const dynamic = "force-dynamic";
5
8
 
6
9
  export default function SignInPage() {
7
- const [mode, setMode] = useState<"signin" | "signup">("signin");
8
- const [email, setEmail] = useState("");
9
- const [password, setPassword] = useState("");
10
- const [name, setName] = useState("");
11
- const [error, setError] = useState<string | null>(null);
12
- const [loading, setLoading] = useState(false);
13
- const [hasGoogle, setHasGoogle] = useState(false);
14
- const [passwordAuth, setPasswordAuth] = useState(true);
15
- const [callbackURL, setCallbackURL] = useState("/");
16
-
17
- useEffect(() => {
18
- // Learn which auth methods to show. Public endpoint, no session needed.
19
- fetch("/api/system/auth-config", { credentials: "include" })
20
- .then((r) => r.json())
21
- .then((data: unknown) => {
22
- if (data && typeof data === "object") {
23
- const cfg = data as { google?: boolean; passwordAuth?: boolean };
24
- setHasGoogle(Boolean(cfg.google));
25
- // Default to showing the password form unless told otherwise, so a
26
- // failed fetch never leaves the user with no way to sign in.
27
- setPasswordAuth(cfg.passwordAuth !== false);
28
- }
29
- })
30
- .catch(() => {});
31
-
32
- // Honour ?next= redirect param
33
- const params = new URLSearchParams(window.location.search);
34
- const next = params.get("next");
35
- if (next && next.startsWith("/")) setCallbackURL(next);
36
- }, []);
37
-
38
- async function handleSubmit(e: FormEvent) {
39
- e.preventDefault();
40
- setError(null);
41
- setLoading(true);
42
- try {
43
- if (mode === "signup") {
44
- const res = await authClient.signUp.email({
45
- email,
46
- password,
47
- name,
48
- callbackURL,
49
- });
50
- if (res.error) {
51
- setError(res.error.message ?? "Sign-up failed");
52
- } else {
53
- window.location.href = callbackURL;
54
- }
55
- } else {
56
- const res = await authClient.signIn.email({
57
- email,
58
- password,
59
- callbackURL,
60
- });
61
- if (res.error) {
62
- const status = res.error.status;
63
- if (status === 429) {
64
- setError("Too many sign-in attempts. Wait a minute and try again.");
65
- } else {
66
- setError(res.error.message ?? "Sign-in failed");
67
- }
68
- } else {
69
- window.location.href = callbackURL;
70
- }
71
- }
72
- } catch (err: unknown) {
73
- setError(err instanceof Error ? err.message : "Unexpected error");
74
- } finally {
75
- setLoading(false);
76
- }
77
- }
78
-
79
- async function handleGoogle() {
80
- setError(null);
81
- setLoading(true);
82
- try {
83
- await authClient.signIn.social({ provider: "google", callbackURL });
84
- } catch (err: unknown) {
85
- setError(err instanceof Error ? err.message : "Google sign-in failed");
86
- setLoading(false);
87
- }
88
- }
89
-
10
+ const google = Boolean(
11
+ process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET,
12
+ );
90
13
  return (
91
- <div className="min-h-screen flex items-center justify-center bg-background">
92
- <div className="w-full max-w-sm rounded-lg border border-border bg-card p-8 shadow-sm">
93
- <h1 className="mb-6 text-xl font-semibold text-foreground">Sign in to wiki-viewer</h1>
94
-
95
- {hasGoogle && (
96
- <>
97
- <button
98
- type="button"
99
- onClick={handleGoogle}
100
- disabled={loading}
101
- className="flex w-full items-center justify-center gap-2 rounded-md border border-border px-4 py-2 text-sm font-medium hover:bg-accent disabled:opacity-50"
102
- >
103
- <svg viewBox="0 0 24 24" className="h-4 w-4" aria-hidden="true">
104
- <path
105
- fill="#4285F4"
106
- d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
107
- />
108
- <path
109
- fill="#34A853"
110
- d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
111
- />
112
- <path
113
- fill="#FBBC05"
114
- d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l3.66-2.84z"
115
- />
116
- <path
117
- fill="#EA4335"
118
- d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
119
- />
120
- </svg>
121
- Continue with Google
122
- </button>
123
- {passwordAuth && (
124
- <div className="my-4 flex items-center gap-3">
125
- <hr className="flex-1 border-border" />
126
- <span className="text-xs text-muted-foreground">or</span>
127
- <hr className="flex-1 border-border" />
128
- </div>
129
- )}
130
- </>
131
- )}
132
-
133
- {!passwordAuth && !hasGoogle && (
134
- <p className="rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive">
135
- No sign-in method is configured. Set GOOGLE_CLIENT_ID and
136
- GOOGLE_CLIENT_SECRET, or enable email/password auth.
137
- </p>
138
- )}
139
-
140
- {passwordAuth && (
141
- <form onSubmit={handleSubmit} className="space-y-4">
142
- {mode === "signup" && (
143
- <div>
144
- <label className="mb-1 block text-sm font-medium text-foreground" htmlFor="name">
145
- Name
146
- </label>
147
- <input
148
- id="name"
149
- type="text"
150
- autoComplete="name"
151
- value={name}
152
- onChange={(e) => setName(e.target.value)}
153
- required
154
- className="w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
155
- />
156
- </div>
157
- )}
158
- <div>
159
- <label className="mb-1 block text-sm font-medium text-foreground" htmlFor="email">
160
- Email
161
- </label>
162
- <input
163
- id="email"
164
- type="email"
165
- autoComplete="email"
166
- value={email}
167
- onChange={(e) => setEmail(e.target.value)}
168
- required
169
- className="w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
170
- />
171
- </div>
172
- <div>
173
- <label
174
- className="mb-1 block text-sm font-medium text-foreground"
175
- htmlFor="password"
176
- >
177
- Password
178
- </label>
179
- <input
180
- id="password"
181
- type="password"
182
- autoComplete={mode === "signup" ? "new-password" : "current-password"}
183
- value={password}
184
- onChange={(e) => setPassword(e.target.value)}
185
- required
186
- minLength={8}
187
- className="w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
188
- />
189
- </div>
190
-
191
- {error && (
192
- <p className="rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive">
193
- {error}
194
- </p>
195
- )}
196
-
197
- <button
198
- type="submit"
199
- disabled={loading}
200
- className="w-full rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50"
201
- >
202
- {loading
203
- ? mode === "signup"
204
- ? "Creating account..."
205
- : "Signing in..."
206
- : mode === "signup"
207
- ? "Create account"
208
- : "Sign in"}
209
- </button>
210
- </form>
211
- )}
212
-
213
- {passwordAuth && (
214
- <p className="mt-4 text-center text-sm text-muted-foreground">
215
- {mode === "signin" ? "No account?" : "Already have an account?"}{" "}
216
- <button
217
- type="button"
218
- onClick={() => {
219
- setMode(mode === "signin" ? "signup" : "signin");
220
- setError(null);
221
- }}
222
- className="font-medium text-foreground underline-offset-4 hover:underline"
223
- >
224
- {mode === "signin" ? "Sign up" : "Sign in"}
225
- </button>
226
- </p>
227
- )}
228
- </div>
229
- </div>
14
+ <SignInForm initialPasswordAuth={passwordAuthEnabled} initialGoogle={google} />
230
15
  );
231
16
  }
@@ -0,0 +1,238 @@
1
+ "use client";
2
+
3
+ import { useState, useEffect, type FormEvent } from "react";
4
+ import { authClient } from "@/lib/auth/client";
5
+
6
+ export default function SignInForm({
7
+ initialPasswordAuth,
8
+ initialGoogle,
9
+ }: {
10
+ initialPasswordAuth: boolean;
11
+ initialGoogle: boolean;
12
+ }) {
13
+ const [mode, setMode] = useState<"signin" | "signup">("signin");
14
+ const [email, setEmail] = useState("");
15
+ const [password, setPassword] = useState("");
16
+ const [name, setName] = useState("");
17
+ const [error, setError] = useState<string | null>(null);
18
+ const [loading, setLoading] = useState(false);
19
+ // Seed from server-rendered values so the first paint already matches the
20
+ // configured auth methods. This avoids a flash of the password form when it
21
+ // is disabled. The fetch below only refreshes in case config changed.
22
+ const [hasGoogle, setHasGoogle] = useState(initialGoogle);
23
+ const [passwordAuth, setPasswordAuth] = useState(initialPasswordAuth);
24
+ const [callbackURL, setCallbackURL] = useState("/");
25
+
26
+ useEffect(() => {
27
+ // Refresh which auth methods to show. Public endpoint, no session needed.
28
+ fetch("/api/system/auth-config", { credentials: "include" })
29
+ .then((r) => r.json())
30
+ .then((data: unknown) => {
31
+ if (data && typeof data === "object") {
32
+ const cfg = data as { google?: boolean; passwordAuth?: boolean };
33
+ setHasGoogle(Boolean(cfg.google));
34
+ setPasswordAuth(cfg.passwordAuth !== false);
35
+ }
36
+ })
37
+ .catch(() => {});
38
+
39
+ // Honour ?next= redirect param
40
+ const params = new URLSearchParams(window.location.search);
41
+ const next = params.get("next");
42
+ if (next && next.startsWith("/")) setCallbackURL(next);
43
+ }, []);
44
+
45
+ async function handleSubmit(e: FormEvent) {
46
+ e.preventDefault();
47
+ setError(null);
48
+ setLoading(true);
49
+ try {
50
+ if (mode === "signup") {
51
+ const res = await authClient.signUp.email({
52
+ email,
53
+ password,
54
+ name,
55
+ callbackURL,
56
+ });
57
+ if (res.error) {
58
+ setError(res.error.message ?? "Sign-up failed");
59
+ } else {
60
+ window.location.href = callbackURL;
61
+ }
62
+ } else {
63
+ const res = await authClient.signIn.email({
64
+ email,
65
+ password,
66
+ callbackURL,
67
+ });
68
+ if (res.error) {
69
+ const status = res.error.status;
70
+ if (status === 429) {
71
+ setError("Too many sign-in attempts. Wait a minute and try again.");
72
+ } else {
73
+ setError(res.error.message ?? "Sign-in failed");
74
+ }
75
+ } else {
76
+ window.location.href = callbackURL;
77
+ }
78
+ }
79
+ } catch (err: unknown) {
80
+ setError(err instanceof Error ? err.message : "Unexpected error");
81
+ } finally {
82
+ setLoading(false);
83
+ }
84
+ }
85
+
86
+ async function handleGoogle() {
87
+ setError(null);
88
+ setLoading(true);
89
+ try {
90
+ await authClient.signIn.social({ provider: "google", callbackURL });
91
+ } catch (err: unknown) {
92
+ setError(err instanceof Error ? err.message : "Google sign-in failed");
93
+ setLoading(false);
94
+ }
95
+ }
96
+
97
+ return (
98
+ <div className="min-h-screen flex items-center justify-center bg-background">
99
+ <div className="w-full max-w-sm rounded-lg border border-border bg-card p-8 shadow-sm">
100
+ <h1 className="mb-6 text-xl font-semibold text-foreground">Sign in to wiki-viewer</h1>
101
+
102
+ {hasGoogle && (
103
+ <>
104
+ <button
105
+ type="button"
106
+ onClick={handleGoogle}
107
+ disabled={loading}
108
+ className="flex w-full items-center justify-center gap-2 rounded-md border border-border px-4 py-2 text-sm font-medium hover:bg-accent disabled:opacity-50"
109
+ >
110
+ <svg viewBox="0 0 24 24" className="h-4 w-4" aria-hidden="true">
111
+ <path
112
+ fill="#4285F4"
113
+ d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
114
+ />
115
+ <path
116
+ fill="#34A853"
117
+ d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
118
+ />
119
+ <path
120
+ fill="#FBBC05"
121
+ d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l3.66-2.84z"
122
+ />
123
+ <path
124
+ fill="#EA4335"
125
+ d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
126
+ />
127
+ </svg>
128
+ Continue with Google
129
+ </button>
130
+ {passwordAuth && (
131
+ <div className="my-4 flex items-center gap-3">
132
+ <hr className="flex-1 border-border" />
133
+ <span className="text-xs text-muted-foreground">or</span>
134
+ <hr className="flex-1 border-border" />
135
+ </div>
136
+ )}
137
+ </>
138
+ )}
139
+
140
+ {!passwordAuth && !hasGoogle && (
141
+ <p className="rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive">
142
+ No sign-in method is configured. Set GOOGLE_CLIENT_ID and
143
+ GOOGLE_CLIENT_SECRET, or enable email/password auth.
144
+ </p>
145
+ )}
146
+
147
+ {passwordAuth && (
148
+ <form onSubmit={handleSubmit} className="space-y-4">
149
+ {mode === "signup" && (
150
+ <div>
151
+ <label className="mb-1 block text-sm font-medium text-foreground" htmlFor="name">
152
+ Name
153
+ </label>
154
+ <input
155
+ id="name"
156
+ type="text"
157
+ autoComplete="name"
158
+ value={name}
159
+ onChange={(e) => setName(e.target.value)}
160
+ required
161
+ className="w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
162
+ />
163
+ </div>
164
+ )}
165
+ <div>
166
+ <label className="mb-1 block text-sm font-medium text-foreground" htmlFor="email">
167
+ Email
168
+ </label>
169
+ <input
170
+ id="email"
171
+ type="email"
172
+ autoComplete="email"
173
+ value={email}
174
+ onChange={(e) => setEmail(e.target.value)}
175
+ required
176
+ className="w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
177
+ />
178
+ </div>
179
+ <div>
180
+ <label
181
+ className="mb-1 block text-sm font-medium text-foreground"
182
+ htmlFor="password"
183
+ >
184
+ Password
185
+ </label>
186
+ <input
187
+ id="password"
188
+ type="password"
189
+ autoComplete={mode === "signup" ? "new-password" : "current-password"}
190
+ value={password}
191
+ onChange={(e) => setPassword(e.target.value)}
192
+ required
193
+ minLength={8}
194
+ className="w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
195
+ />
196
+ </div>
197
+
198
+ {error && (
199
+ <p className="rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive">
200
+ {error}
201
+ </p>
202
+ )}
203
+
204
+ <button
205
+ type="submit"
206
+ disabled={loading}
207
+ className="w-full rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50"
208
+ >
209
+ {loading
210
+ ? mode === "signup"
211
+ ? "Creating account..."
212
+ : "Signing in..."
213
+ : mode === "signup"
214
+ ? "Create account"
215
+ : "Sign in"}
216
+ </button>
217
+ </form>
218
+ )}
219
+
220
+ {passwordAuth && (
221
+ <p className="mt-4 text-center text-sm text-muted-foreground">
222
+ {mode === "signin" ? "No account?" : "Already have an account?"}{" "}
223
+ <button
224
+ type="button"
225
+ onClick={() => {
226
+ setMode(mode === "signin" ? "signup" : "signin");
227
+ setError(null);
228
+ }}
229
+ className="font-medium text-foreground underline-offset-4 hover:underline"
230
+ >
231
+ {mode === "signin" ? "Sign up" : "Sign in"}
232
+ </button>
233
+ </p>
234
+ )}
235
+ </div>
236
+ </div>
237
+ );
238
+ }
@@ -68,8 +68,36 @@ export function AIPanel({ currentPath }: { currentPath?: string | null }) {
68
68
  () => bootstrapPrompt.replace(/\$WIKI_URL/g, origin),
69
69
  [bootstrapPrompt, origin]
70
70
  );
71
+ const getMcpRegister = useCallback(
72
+ () =>
73
+ `npx wiki-viewer-mcp register --url ${origin} --id ai:myagent --name "My Agent"`,
74
+ [origin]
75
+ );
76
+ const getMcpJson = useCallback(
77
+ () =>
78
+ JSON.stringify(
79
+ {
80
+ servers: {
81
+ "wiki-viewer": {
82
+ command: "npx",
83
+ args: ["wiki-viewer-mcp"],
84
+ env: {
85
+ WIKI_VIEWER_URL: origin,
86
+ WIKI_VIEWER_TOKEN: "<token from register>",
87
+ WIKI_VIEWER_AGENT_ID: "ai:myagent",
88
+ },
89
+ },
90
+ },
91
+ },
92
+ null,
93
+ 2
94
+ ),
95
+ [origin]
96
+ );
71
97
  const skillCli = useCopyButton(getSkillCli);
72
98
  const bootstrapCopy = useCopyButton(getBootstrapPrompt);
99
+ const mcpRegister = useCopyButton(getMcpRegister);
100
+ const mcpJson = useCopyButton(getMcpJson);
73
101
 
74
102
  // Keyboard: Esc closes
75
103
  useEffect(() => {
@@ -182,6 +210,27 @@ export function AIPanel({ currentPath }: { currentPath?: string | null }) {
182
210
  Install for AI Agents
183
211
  </h3>
184
212
  <div className="rounded-md border border-border bg-muted/40 p-3 space-y-3">
213
+ <div className="space-y-1">
214
+ <p className="text-[10px] text-muted-foreground/70">
215
+ MCP server <span className="text-muted-foreground/50">(Claude Code, Cursor, Codex):</span>
216
+ </p>
217
+ <p className="text-[10px] text-muted-foreground/50">1. Register &amp; get a token:</p>
218
+ <div className="flex items-center gap-2">
219
+ <code className="flex-1 text-[10px] font-mono text-foreground/80 truncate bg-muted rounded px-1 py-0.5">
220
+ {getMcpRegister()}
221
+ </code>
222
+ <Button size="sm" variant="ghost" className="h-6 w-6 p-0 shrink-0" title="Copy register command" onClick={() => void mcpRegister.copy()}>
223
+ {mcpRegister.copied ? <Check className="h-3.5 w-3.5 text-green-500" /> : <Copy className="h-3.5 w-3.5" />}
224
+ </Button>
225
+ </div>
226
+ <p className="text-[10px] text-muted-foreground/50 pt-1">2. Approve below, then add to your <code className="bg-muted px-0.5 rounded">mcp.json</code>:</p>
227
+ <Button size="sm" variant="outline" className="h-7 w-full text-xs gap-1.5" onClick={() => void mcpJson.copy()}>
228
+ {mcpJson.copied
229
+ ? <><Check className="h-3.5 w-3.5 text-green-500" /> Copied!</>
230
+ : <><Copy className="h-3.5 w-3.5" /> Copy mcp.json</>}
231
+ </Button>
232
+ </div>
233
+ <div className="h-px bg-border/60" />
185
234
  <div className="space-y-1">
186
235
  <p className="text-[10px] text-muted-foreground/70">Agent Skills standard:</p>
187
236
  <div className="flex items-center gap-2">
@@ -184,6 +184,44 @@ export function KBEditor() {
184
184
  void useProofStore.getState().loadSidecar(currentPath);
185
185
  }, [currentPath]);
186
186
 
187
+ // Human edit-lease heartbeat: tell the server a human has this markdown doc
188
+ // open so computeCollabState() reports "active" even before the first
189
+ // suggestion/comment. This is what makes raw-fs writes from agents defer to
190
+ // the collaborative (Tier-2) path while a human is editing. Only markdown
191
+ // files participate in the collab-state machine.
192
+ useEffect(() => {
193
+ if (typeof window === "undefined") return;
194
+ if (!currentPath) return;
195
+ if (!/\.(md|markdown)$/i.test(currentPath)) return;
196
+
197
+ const path = currentPath;
198
+ const ping = (action: "open" | "heartbeat" | "close") => {
199
+ // keepalive lets the "close" beacon survive page unload.
200
+ void fetch("/api/wiki/presence", {
201
+ method: "POST",
202
+ headers: { "Content-Type": "application/json" },
203
+ body: JSON.stringify({ path, action }),
204
+ keepalive: action === "close",
205
+ }).catch(() => {
206
+ /* presence is best-effort; ignore failures */
207
+ });
208
+ };
209
+
210
+ ping("open");
211
+ // Refresh well within the 90s server lease TTL.
212
+ const id = setInterval(() => ping("heartbeat"), 30_000);
213
+ const onHidden = () => {
214
+ if (document.visibilityState === "hidden") ping("heartbeat");
215
+ };
216
+ document.addEventListener("visibilitychange", onHidden);
217
+
218
+ return () => {
219
+ clearInterval(id);
220
+ document.removeEventListener("visibilitychange", onHidden);
221
+ ping("close");
222
+ };
223
+ }, [currentPath]);
224
+
187
225
  // Subscribe to chokidar SSE: when current file changes on disk, reload sidecar.
188
226
  useEffect(() => {
189
227
  if (typeof window === "undefined") return;
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Minimal durable audit log for raw-fs mutations (Tier 1).
3
+ *
4
+ * Uses the same ~/.wiki-viewer/auth.db already opened by better-auth.
5
+ * Table: agent_fs_audit
6
+ *
7
+ * For .md files the sidecar event covers provenance; this covers ALL types.
8
+ */
9
+ import Database from "better-sqlite3";
10
+ import path from "node:path";
11
+ import os from "node:os";
12
+ import { mkdirSync } from "node:fs";
13
+
14
+ function dataDir(): string {
15
+ return path.join(process.env.HOME ?? os.homedir(), ".wiki-viewer");
16
+ }
17
+
18
+ // Lazily initialised so tests can set HOME before first import.
19
+ let _db: InstanceType<typeof Database> | null = null;
20
+
21
+ function getDb(): InstanceType<typeof Database> {
22
+ if (_db) return _db;
23
+ const dir = dataDir();
24
+ mkdirSync(dir, { recursive: true });
25
+ const dbPath = path.join(dir, "auth.db");
26
+ _db = new Database(dbPath);
27
+ _db.pragma("journal_mode = WAL");
28
+ _db.exec(`
29
+ CREATE TABLE IF NOT EXISTS agent_fs_audit (
30
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
31
+ agent_id TEXT NOT NULL,
32
+ op TEXT NOT NULL,
33
+ path TEXT NOT NULL,
34
+ old_sha TEXT,
35
+ new_sha TEXT,
36
+ forced INTEGER NOT NULL DEFAULT 0,
37
+ at TEXT NOT NULL
38
+ )
39
+ `);
40
+ return _db;
41
+ }
42
+
43
+ export interface AuditRow {
44
+ agentId: string;
45
+ op: string;
46
+ path: string;
47
+ oldSha?: string;
48
+ newSha?: string;
49
+ forced?: boolean;
50
+ }
51
+
52
+ /**
53
+ * Write one audit row synchronously (SQLite sync is fine here — it's a WAL journal append).
54
+ * Fire-and-forget: never throws; logs to stderr on error.
55
+ */
56
+ export function writeAuditRow(row: AuditRow): void {
57
+ try {
58
+ const db = getDb();
59
+ db.prepare(
60
+ `INSERT INTO agent_fs_audit (agent_id, op, path, old_sha, new_sha, forced, at)
61
+ VALUES (?, ?, ?, ?, ?, ?, ?)`,
62
+ ).run(
63
+ row.agentId,
64
+ row.op,
65
+ row.path,
66
+ row.oldSha ?? null,
67
+ row.newSha ?? null,
68
+ row.forced ? 1 : 0,
69
+ new Date().toISOString(),
70
+ );
71
+ } catch (e) {
72
+ console.error("[agent-fs audit] write failed:", e);
73
+ }
74
+ }
75
+
76
+ /** Reset cached DB handle (used by tests to pick up new HOME). */
77
+ export function _resetAuditDb(): void {
78
+ _db = null;
79
+ }
@@ -34,7 +34,7 @@ export async function checkAuth(req: Request): Promise<CheckAuthResult> {
34
34
  id: `user:${u.id}`,
35
35
  displayName: u.name,
36
36
  tokenHash: "",
37
- scope: { paths: ["**/*"], ops: ["read", "mutate"] },
37
+ scope: { paths: ["**/*"], ops: ["read", "mutate", "delete"] },
38
38
  createdAt: "",
39
39
  lastSeen: "",
40
40
  },
@@ -71,7 +71,7 @@ export async function checkAuth(req: Request): Promise<CheckAuthResult> {
71
71
 
72
72
  export interface ScopeParams {
73
73
  filePath?: string;
74
- op: "read" | "mutate";
74
+ op: "read" | "mutate" | "delete";
75
75
  }
76
76
 
77
77
  export function enforceScope(