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.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-path-routes-manifest.json +5 -0
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -27
- package/.next/standalone/.next/routes-manifest.json +34 -0
- package/.next/standalone/.next/server/app/_global-error/page.js +2 -2
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js +4 -4
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/api/agent/activity/route.js +5 -5
- package/.next/standalone/.next/server/app/api/agent/activity/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/admin/agents/[agentId]/revoke/route.js +6 -6
- package/.next/standalone/.next/server/app/api/agent/admin/agents/[agentId]/revoke/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/admin/agents/route.js +6 -6
- package/.next/standalone/.next/server/app/api/agent/admin/agents/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/admin/registrations/[regId]/approve/route.js +6 -6
- package/.next/standalone/.next/server/app/api/agent/admin/registrations/[regId]/approve/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/admin/registrations/[regId]/deny/route.js +4 -4
- package/.next/standalone/.next/server/app/api/agent/admin/registrations/[regId]/deny/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/admin/registrations/route.js +4 -4
- package/.next/standalone/.next/server/app/api/agent/admin/registrations/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/events/[...path]/route.js +5 -5
- package/.next/standalone/.next/server/app/api/agent/events/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/files/[...path]/route.js +11 -10
- package/.next/standalone/.next/server/app/api/agent/files/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js +17 -0
- package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route.js +15 -0
- package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/agent/fs/move/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/agent/fs/move/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/agent/fs/move/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/agent/fs/move/route.js +15 -0
- package/.next/standalone/.next/server/app/api/agent/fs/move/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/agent/fs/move/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/agent/fs/move/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/agent/fs/search/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/agent/fs/search/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/agent/fs/search/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/agent/fs/search/route.js +15 -0
- package/.next/standalone/.next/server/app/api/agent/fs/search/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/agent/fs/search/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/agent/fs/search/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/agent/internal/span/route.js +8 -8
- package/.next/standalone/.next/server/app/api/agent/internal/span/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/settings/route.js +8 -8
- package/.next/standalone/.next/server/app/api/agent/settings/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/sidecar/[...path]/route.js +7 -7
- package/.next/standalone/.next/server/app/api/agent/sidecar/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/app-proxy/[...path]/route.js +1 -1
- package/.next/standalone/.next/server/app/api/app-proxy/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/assets/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/[...all]/route.js +3 -3
- package/.next/standalone/.next/server/app/api/auth/[...all]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/auth-config/route.js +5 -5
- package/.next/standalone/.next/server/app/api/system/auth-config/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/auth-settings/route.js +4 -4
- package/.next/standalone/.next/server/app/api/system/auth-settings/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/browse/route.js +6 -6
- package/.next/standalone/.next/server/app/api/system/browse/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/clear-root/route.js +5 -5
- package/.next/standalone/.next/server/app/api/system/clear-root/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/config/route.js +5 -5
- package/.next/standalone/.next/server/app/api/system/config/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/pins/route.js +4 -4
- package/.next/standalone/.next/server/app/api/system/pins/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/reveal/route.js +4 -4
- package/.next/standalone/.next/server/app/api/system/reveal/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/root-status/route.js +4 -4
- package/.next/standalone/.next/server/app/api/system/root-status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/set-root/route.js +5 -5
- package/.next/standalone/.next/server/app/api/system/set-root/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/upload/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/app/route.js +6 -6
- package/.next/standalone/.next/server/app/api/wiki/app/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/content/route.js +6 -6
- package/.next/standalone/.next/server/app/api/wiki/content/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/file/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/folder/route.js +5 -5
- package/.next/standalone/.next/server/app/api/wiki/folder/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/move/route.js +6 -6
- package/.next/standalone/.next/server/app/api/wiki/move/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/new-file/route.js +5 -5
- package/.next/standalone/.next/server/app/api/wiki/new-file/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/page/route.js +5 -5
- package/.next/standalone/.next/server/app/api/wiki/page/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/presence/route/app-paths-manifest.json +3 -0
- package/.next/standalone/.next/server/app/api/wiki/presence/route/build-manifest.json +9 -0
- package/.next/standalone/.next/server/app/api/wiki/presence/route/server-reference-manifest.json +4 -0
- package/.next/standalone/.next/server/app/api/wiki/presence/route.js +14 -0
- package/.next/standalone/.next/server/app/api/wiki/presence/route.js.map +5 -0
- package/.next/standalone/.next/server/app/api/wiki/presence/route.js.nft.json +1 -0
- package/.next/standalone/.next/server/app/api/wiki/presence/route_client-reference-manifest.js +3 -0
- package/.next/standalone/.next/server/app/api/wiki/route.js +5 -5
- package/.next/standalone/.next/server/app/api/wiki/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/slugs/route.js +5 -5
- package/.next/standalone/.next/server/app/api/wiki/slugs/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/upload/route.js +5 -5
- package/.next/standalone/.next/server/app/api/wiki/upload/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/watch/route.js +6 -6
- package/.next/standalone/.next/server/app/api/wiki/watch/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/page.js +4 -4
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/signin/page.js +9 -4
- package/.next/standalone/.next/server/app/signin/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/signin/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app-paths-manifest.json +5 -0
- package/.next/standalone/.next/server/chunks/0p91_next_dist_esm_build_templates_app-route_0d2jbo5.js +3 -0
- package/.next/standalone/.next/server/chunks/0p91_next_dist_esm_build_templates_app-route_0ytral2.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0269d2e._.js +1 -1
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__03h3~3e._.js → [root-of-the-server]__04udrya._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__05f6x0i._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__06-dtd0._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__06sek6_._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__09s9qkd._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d75a5q._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d_da6q._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e7si9p._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0hhhvm7._.js +1 -1
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__04g0j8i._.js → [root-of-the-server]__0kdn1le._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0kk26wc._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0kur4ro._.js +15 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0p12-6~._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0qc2~6l._.js +15 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0s~i040._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0w47wil._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0xq124z._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0l..bxz._.js → [root-of-the-server]__0xz-_0v._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__10w2q~o._.js +1 -1
- package/.next/standalone/.next/server/chunks/_079xuln._.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_agent_fs_file_[___path]_route_actions_0gb11t~.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_agent_fs_ls_[[___path]]_route_actions_0wfg4nl.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_agent_fs_move_route_actions_0z34mqq.js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_agent_fs_search_route_actions_0ut_ug..js +3 -0
- package/.next/standalone/.next/server/chunks/_next-internal_server_app_api_wiki_presence_route_actions_0x9d7f4.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0d89o98._.js → src_lib_auth_server_ts_00f4e0h._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/0biy_@better-auth_core_dist_121m_lh._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/0dhv_better-auth_dist_adapters_kysely-adapter_index_mjs_08ymlcb._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/0dti_kysely_dist_esm_0-t3o9q._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/0dti_kysely_dist_esm_01._58q._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/0p91_next_0f40gy0._.js +6 -0
- package/.next/standalone/.next/server/chunks/ssr/{0p91_next_dist_0~2d1tl._.js → 0p91_next_dist_10ud_sa._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/0sag_@better-auth_memory-adapter_dist_index_mjs_07-_ka6._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/0ugq_@better-auth_kysely-adapter_dist_bun-sqlite-dialect-DzNwOpKv_mjs_0lruvb8._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/0ugq_@better-auth_kysely-adapter_dist_d1-sqlite-dialect-C2B7YsIT_mjs_03n6~tc._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/0ugq_@better-auth_kysely-adapter_dist_index_mjs_0gi5w.w._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/0ugq_@better-auth_kysely-adapter_dist_node-sqlite-dialect_mjs_0l4.y~0._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_diagram-OG6HWLK6_mjs_0t5sus6._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/12y~_mermaid_dist_chunks_mermaid_core_sankeyDiagram-5OEKKPKP_mjs_11ifrnu._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__026s8~z._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__06mzg2t._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0btcd4o._.js +12 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0c~og-9._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__134_q7l._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0pqaawz._.js +3 -3
- package/.next/standalone/.next/server/chunks/ssr/node_modules__pnpm_051tcva._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/node_modules__pnpm_0o~d81.._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules__pnpm_0y9k6h~._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules__pnpm_0znncy9._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules__pnpm_12-ni1n._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_app_signin_00yk0vm._.js +452 -0
- package/.next/standalone/.next/server/chunks/ssr/src_app_signin_signin-form_tsx_0eznlbd._.js +3 -0
- package/.next/standalone/.next/server/functions-config-manifest.json +5 -0
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/middleware-manifest.json +5 -5
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/static/chunks/09-jtayuhrq~b.js +1 -0
- package/.next/standalone/.next/static/chunks/0uv7ozzpiyp2_.js +1 -0
- package/.next/standalone/.next/static/chunks/135c~rq_ux73w.js +1 -0
- package/.next/standalone/.next/static/chunks/{11s9zwr7edrs7.js → 14luv~jq7e6-n.js} +12 -12
- package/.next/standalone/README.md +79 -16
- package/.next/standalone/agents/bootstrap-prompt.md +12 -1
- package/.next/standalone/agents/wiki-viewer-skill/SKILL.md +199 -6
- package/.next/standalone/docs/agent-fs-plan.md +65 -7
- package/.next/standalone/docs/file-vs-collab-authority.md +124 -0
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/packages/wiki-viewer-mcp/README.md +194 -0
- package/.next/standalone/packages/wiki-viewer-mcp/dist/http-client.js +220 -0
- package/.next/standalone/packages/wiki-viewer-mcp/dist/index.js +472 -0
- package/.next/standalone/packages/wiki-viewer-mcp/dist/register.js +94 -0
- package/.next/standalone/packages/wiki-viewer-mcp/dist/state-cache.js +26 -0
- package/.next/standalone/packages/wiki-viewer-mcp/package-lock.json +1716 -0
- package/.next/standalone/packages/wiki-viewer-mcp/package.json +41 -0
- package/.next/standalone/packages/wiki-viewer-mcp/src/http-client.ts +344 -0
- package/.next/standalone/packages/wiki-viewer-mcp/src/index.ts +575 -0
- package/.next/standalone/packages/wiki-viewer-mcp/src/register.ts +144 -0
- package/.next/standalone/packages/wiki-viewer-mcp/src/state-cache.ts +45 -0
- package/.next/standalone/packages/wiki-viewer-mcp/tsconfig.json +19 -0
- package/.next/standalone/pnpm-lock.yaml +9 -9
- package/.next/standalone/src/app/api/agent/files/[...path]/route.ts +11 -1
- package/.next/standalone/src/app/api/agent/fs/file/[...path]/route.ts +344 -0
- package/.next/standalone/src/app/api/agent/fs/ls/[[...path]]/route.ts +147 -0
- package/.next/standalone/src/app/api/agent/fs/move/route.ts +125 -0
- package/.next/standalone/src/app/api/agent/fs/search/route.ts +236 -0
- package/.next/standalone/src/app/api/agent/register/route.ts +3 -3
- package/.next/standalone/src/app/api/agents/install/route.ts +44 -2
- package/.next/standalone/src/app/api/wiki/move/route.ts +10 -1
- package/.next/standalone/src/app/api/wiki/presence/route.ts +55 -0
- package/.next/standalone/src/app/signin/page.tsx +10 -225
- package/.next/standalone/src/app/signin/signin-form.tsx +238 -0
- package/.next/standalone/src/components/ai-panel/ai-panel.tsx +49 -0
- package/.next/standalone/src/components/editor/editor.tsx +38 -0
- package/.next/standalone/src/lib/proof/audit.ts +79 -0
- package/.next/standalone/src/lib/proof/auth.ts +2 -2
- package/.next/standalone/src/lib/proof/collab-state.ts +79 -0
- package/.next/standalone/src/lib/proof/lease.ts +104 -0
- package/.next/standalone/src/lib/proof/ops-applier.ts +74 -25
- package/.next/standalone/src/lib/proof/raw-fs.ts +198 -0
- package/.next/standalone/src/lib/proof/registry.ts +1 -1
- package/.next/standalone/src/lib/proof/sidecar.ts +38 -1
- package/.next/standalone/src/lib/proof/types.ts +13 -1
- package/.next/standalone/src/tests/proof/agent-fs.test.ts +824 -0
- package/.next/standalone/src/tests/proof/agents-install.test.ts +53 -0
- package/.next/standalone/src/tests/proof/collab-state.test.ts +499 -0
- package/.next/standalone/src/tests/proof/reconcile-sidecar.test.ts +195 -0
- package/.next/standalone/src/tests/proof/sidecar-lifecycle.test.ts +177 -0
- package/.next/standalone/tsconfig.tsbuildinfo +1 -1
- package/README.md +79 -16
- package/package.json +1 -1
- package/.next/standalone/.next/server/app/signin.html +0 -1
- package/.next/standalone/.next/server/app/signin.meta +0 -15
- package/.next/standalone/.next/server/app/signin.rsc +0 -23
- package/.next/standalone/.next/server/app/signin.segments/_full.segment.rsc +0 -23
- package/.next/standalone/.next/server/app/signin.segments/_head.segment.rsc +0 -6
- package/.next/standalone/.next/server/app/signin.segments/_index.segment.rsc +0 -7
- package/.next/standalone/.next/server/app/signin.segments/_tree.segment.rsc +0 -3
- package/.next/standalone/.next/server/app/signin.segments/signin/__PAGE__.segment.rsc +0 -9
- package/.next/standalone/.next/server/app/signin.segments/signin.segment.rsc +0 -5
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__09~~-nd._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0w87kiz._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__12ssbhv._.js +0 -3
- package/.next/standalone/.next/server/chunks/node_modules__pnpm_0g0fhfk._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__088hqzy._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0c147fo._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0z.1v1z._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12zp2dm._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/node_modules__pnpm_0exqvyf._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/src_app_signin_page_tsx_1143y49._.js +0 -3
- package/.next/standalone/.next/static/chunks/0-_39e4awbk8y.js +0 -1
- package/.next/standalone/.next/static/chunks/02bxx~2cg~s6~.js +0 -1
- package/.next/standalone/.next/static/chunks/0mj_f8ncf2tks.js +0 -1
- /package/.next/standalone/.next/static/{OwXjVuoXDC_gda_BKji1J → 19j4-_brJLoulXAMekpM2}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{OwXjVuoXDC_gda_BKji1J → 19j4-_brJLoulXAMekpM2}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{OwXjVuoXDC_gda_BKji1J → 19j4-_brJLoulXAMekpM2}/_ssgManifest.js +0 -0
|
@@ -1,231 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
import SignInForm from "./signin-form";
|
|
2
|
+
import { passwordAuthEnabled } from "@/lib/auth/server";
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
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
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
<
|
|
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 & 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(
|