wiki-viewer 1.14.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- 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_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- 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 +2 -2
- 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 +2 -2
- package/.next/standalone/.next/server/app/api/agent/activity/route.js +6 -6
- package/.next/standalone/.next/server/app/api/agent/activity/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/events/[...path]/route.js +8 -8
- 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 +9 -9
- 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.js +8 -8
- package/.next/standalone/.next/server/app/api/agent/fs/file/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route.js +8 -8
- package/.next/standalone/.next/server/app/api/agent/fs/ls/[[...path]]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/fs/move/route.js +8 -8
- package/.next/standalone/.next/server/app/api/agent/fs/move/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/agent/fs/search/route.js +9 -9
- package/.next/standalone/.next/server/app/api/agent/fs/search/route.js.nft.json +1 -1
- 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 +7 -7
- 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 +6 -6
- 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.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/assets/[...path]/route.js +5 -5
- package/.next/standalone/.next/server/app/api/assets/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/share/[token]/route.js +6 -5
- package/.next/standalone/.next/server/app/api/share/[token]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/share/route.js +4 -4
- package/.next/standalone/.next/server/app/api/share/route.js.nft.json +1 -1
- 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.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/reveal/route.js +6 -6
- 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.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/set-root/route.js +6 -5
- package/.next/standalone/.next/server/app/api/system/set-root/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route.js +5 -4
- package/.next/standalone/.next/server/app/api/system/workspaces/[id]/open/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/workspaces/[id]/refresh/route.js +6 -5
- package/.next/standalone/.next/server/app/api/system/workspaces/[id]/refresh/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route.js +5 -4
- package/.next/standalone/.next/server/app/api/system/workspaces/[id]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/system/workspaces/route.js +7 -6
- package/.next/standalone/.next/server/app/api/system/workspaces/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/upload/[...path]/route.js +5 -5
- 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 +7 -7
- package/.next/standalone/.next/server/app/api/wiki/app/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/backlinks/route.js +7 -7
- package/.next/standalone/.next/server/app/api/wiki/backlinks/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/content/route.js +7 -7
- package/.next/standalone/.next/server/app/api/wiki/content/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/download/route.js +6 -6
- package/.next/standalone/.next/server/app/api/wiki/download/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/file/route.js +5 -5
- 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/git-branches/route.js +4 -4
- package/.next/standalone/.next/server/app/api/wiki/git-branches/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/git-checkout/route.js +6 -6
- package/.next/standalone/.next/server/app/api/wiki/git-checkout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/git-diff/route.js +4 -4
- package/.next/standalone/.next/server/app/api/wiki/git-diff/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/git-file-info/route.js +4 -4
- package/.next/standalone/.next/server/app/api/wiki/git-file-info/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/git-history/route.js +4 -4
- package/.next/standalone/.next/server/app/api/wiki/git-history/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/wiki/git-pull/route.js +8 -8
- package/.next/standalone/.next/server/app/api/wiki/git-pull/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/outlinks/route.js +7 -7
- package/.next/standalone/.next/server/app/api/wiki/outlinks/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.js +6 -6
- package/.next/standalone/.next/server/app/api/wiki/presence/route.js.nft.json +1 -1
- 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/search/route.js +5 -5
- package/.next/standalone/.next/server/app/api/wiki/search/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 +5 -5
- 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 +3 -3
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- 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/s/[token]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/signin/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-jzw2_._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0.-oq-7._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__000spch._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__01oin-a._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__01qcera._.js +16 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__02.uul~._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__024967n._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__06booxp._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__071_pmz._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0bqpg._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_1f2cw._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0a6j6r4._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0aoqat-._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0as-u6z._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0bvtbax._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0c-ee48._.js +5 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e_9pc5._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0esmskc._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0fshk._._.js +20 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0fu72o7._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0k9mili._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0l-wu5u._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0lvz22t._.js +20 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0n-chxk._.js +16 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0n9zdf0._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0nmx3k2._.js +12 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0nzlmkb._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o0v6hf._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0s38pid._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0s_8poz._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0sfrx~.._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0sggstu._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0u81k~2._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0uibxf_._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0wfv_by._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0wlj-yw._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0w~__xz._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0yat~ul._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0yxauu6._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zbkgnr._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zv_j05._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0~rntxj._.js +3 -0
- package/.next/standalone/.next/server/chunks/src_lib_search_0d-_j3u._.js +4 -4
- package/.next/standalone/.next/server/chunks/src_lib_search_0ymmp0c._.js +3 -3
- package/.next/standalone/.next/server/chunks/src_lib_workspaces_ts_0qon40u._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{0~w0_katex_dist_katex_mjs_029cdbg._.js → 0~w0_katex_dist_katex_mjs_0s4yb1t._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0z41nrr._.js → [root-of-the-server]__10te1ye._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_13p348f._.js → node_modules__pnpm_0-a_zjq._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0gos._c._.js → node_modules__pnpm_02l_1_8._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0ru1i2-._.js → node_modules__pnpm_03rzttw._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_08xpp3w._.js → node_modules__pnpm_04frxp9._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0b8odbc._.js → node_modules__pnpm_057-t6m._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0f_n_zp._.js → node_modules__pnpm_05_oahi._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0~i3a.i._.js → node_modules__pnpm_05ans~m._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0i2m0b.._.js → node_modules__pnpm_06-2ia.._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0aha1~u._.js → node_modules__pnpm_086.ow4._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0w.kwue._.js → node_modules__pnpm_0cahog3._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0e0r_qk._.js → node_modules__pnpm_0cxanql._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0ajqqlq._.js → node_modules__pnpm_0e09gmf._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0hzzx9d._.js → node_modules__pnpm_0eqjo2f._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_02bje_g._.js → node_modules__pnpm_0f-yazg._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0xk042~._.js → node_modules__pnpm_0iu44jv._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_11ede0p._.js → node_modules__pnpm_0jh8q66._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0k-7uzm._.js → node_modules__pnpm_0m39f~t._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0xr.ztu._.js → node_modules__pnpm_0ma-8l.._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0i6_kfe._.js → node_modules__pnpm_0met6sx._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_04v1_ty._.js → node_modules__pnpm_0mtrsi0._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0607~kg._.js → node_modules__pnpm_0n_swwn._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0t4l89_._.js → node_modules__pnpm_0ndyy93._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0-_58b8._.js → node_modules__pnpm_0s-cj7c._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0y2h_cz._.js → node_modules__pnpm_0tr41-t._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_08edl1n._.js → node_modules__pnpm_0u.uija._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_0026mgr._.js → node_modules__pnpm_0wiyn6d._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules__pnpm_09o_spj._.js → node_modules__pnpm_0ygzt82._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_app_page_tsx_0ss2.w7._.js +2 -2
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/middleware-manifest.json +1 -1
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/static/chunks/0ci7khnv7i~7_.js +17 -0
- package/.next/standalone/.next/static/chunks/0sx~65~lg4mgl.css +5 -0
- package/.next/standalone/package.json +1 -1
- package/README.md +88 -17
- package/bin/postbuild.js +21 -0
- package/bin/wiki-viewer.js +198 -6
- package/package.json +1 -1
- package/.next/standalone/.github/workflows/publish.yml +0 -37
- package/.next/standalone/.handoffs/archive/handoff-20260612-113332.md +0 -98
- package/.next/standalone/.handoffs/archive/handoff-20260612-141032.md +0 -73
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-.y6im._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-3_t2y._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-kjkzt._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-puax4._.js +0 -4
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__01h996g._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0329ktu._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__03_xj4r._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__05398dt._.js +0 -4
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__06lfvxh._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__06w0aet._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__070_p2a._.js +0 -4
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0905hi1._.js +0 -21
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0aa63~j._.js +0 -5
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0avcplk._.js +0 -4
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0b8_kyo._.js +0 -16
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0bticq1._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0bwevvu._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0c__k3q._.js +0 -4
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cp~z4x._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0fmdv9h._.js +0 -20
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0h0qbwr._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0jk~oyi._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ndq77b._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0nvgpuk._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ocvng2._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ps4h~.._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q7jqwp._.js +0 -12
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0qew~6p._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0s_9f-a._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0uv7b8u._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0uv8.9i._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0vfe2io._.js +0 -4
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0w11kjy._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0wc-.e4._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ymovmp._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0~c6ouv._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0~rhs0u._.js +0 -16
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__10h9tid._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__10yk-u1._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__11105ew._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__11a3dhw._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__13420tt._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__13h~pdf._.js +0 -3
- package/.next/standalone/.next/static/chunks/02kg.lbkfi1yc.css +0 -5
- package/.next/standalone/.next/static/chunks/0rcwd6-.iu~nd.js +0 -17
- package/.next/standalone/.pi/ownership.json +0 -3
- package/.next/standalone/AGENTS.md +0 -114
- package/.next/standalone/DESIGN.md +0 -521
- package/.next/standalone/README.md +0 -821
- package/.next/standalone/TODO.md +0 -20
- package/.next/standalone/agents/bootstrap-prompt.md +0 -14
- package/.next/standalone/agents/wiki-viewer-skill/SKILL.md +0 -456
- package/.next/standalone/bin/postbuild.js +0 -78
- package/.next/standalone/bin/wiki-viewer.js +0 -922
- package/.next/standalone/certificates/localhost-key.pem +0 -28
- package/.next/standalone/certificates/localhost.pem +0 -24
- package/.next/standalone/docs/agent-collab-plan.md +0 -1615
- package/.next/standalone/docs/agent-collab-v2-plan.md +0 -771
- package/.next/standalone/docs/agent-fs-plan.md +0 -232
- package/.next/standalone/docs/editorial-skin-spec.md +0 -242
- package/.next/standalone/docs/file-vs-collab-authority.md +0 -124
- package/.next/standalone/docs/mobile-readiness-spec.md +0 -229
- package/.next/standalone/docs/workspacing-plan.md +0 -364
- package/.next/standalone/packages/wiki-viewer-mcp/README.md +0 -195
- package/.next/standalone/packages/wiki-viewer-mcp/bench-e2e.mjs +0 -166
- package/.next/standalone/packages/wiki-viewer-mcp/bench-latency.mjs +0 -87
- package/.next/standalone/packages/wiki-viewer-mcp/bench-payload.mjs +0 -45
- package/.next/standalone/packages/wiki-viewer-mcp/dist/http-client.js +0 -331
- package/.next/standalone/packages/wiki-viewer-mcp/dist/index.js +0 -531
- package/.next/standalone/packages/wiki-viewer-mcp/dist/register.js +0 -94
- package/.next/standalone/packages/wiki-viewer-mcp/dist/state-cache.js +0 -28
- package/.next/standalone/packages/wiki-viewer-mcp/package-lock.json +0 -1716
- package/.next/standalone/packages/wiki-viewer-mcp/package.json +0 -41
- package/.next/standalone/packages/wiki-viewer-mcp/src/http-client.ts +0 -459
- package/.next/standalone/packages/wiki-viewer-mcp/src/index.ts +0 -638
- package/.next/standalone/packages/wiki-viewer-mcp/src/register.ts +0 -144
- package/.next/standalone/packages/wiki-viewer-mcp/src/state-cache.ts +0 -55
- package/.next/standalone/packages/wiki-viewer-mcp/tsconfig.json +0 -19
- package/.next/standalone/pnpm-lock.yaml +0 -6697
- package/.next/standalone/pnpm-workspace.yaml +0 -8
- package/.next/standalone/postcss.config.mjs +0 -2
- package/.next/standalone/src/app/api/agent/activity/route.ts +0 -59
- package/.next/standalone/src/app/api/agent/admin/agents/[agentId]/revoke/route.ts +0 -40
- package/.next/standalone/src/app/api/agent/admin/agents/route.ts +0 -33
- package/.next/standalone/src/app/api/agent/admin/registrations/[regId]/approve/route.ts +0 -83
- package/.next/standalone/src/app/api/agent/admin/registrations/[regId]/deny/route.ts +0 -36
- package/.next/standalone/src/app/api/agent/admin/registrations/route.ts +0 -27
- package/.next/standalone/src/app/api/agent/events/[...path]/route.ts +0 -148
- package/.next/standalone/src/app/api/agent/files/[...path]/route.ts +0 -219
- package/.next/standalone/src/app/api/agent/fs/file/[...path]/route.ts +0 -446
- package/.next/standalone/src/app/api/agent/fs/ls/[[...path]]/route.ts +0 -152
- package/.next/standalone/src/app/api/agent/fs/move/route.ts +0 -130
- package/.next/standalone/src/app/api/agent/fs/search/route.ts +0 -272
- package/.next/standalone/src/app/api/agent/internal/span/route.ts +0 -121
- package/.next/standalone/src/app/api/agent/register/[regId]/route.ts +0 -50
- package/.next/standalone/src/app/api/agent/register/route.ts +0 -118
- package/.next/standalone/src/app/api/agent/settings/route.ts +0 -34
- package/.next/standalone/src/app/api/agent/settings/token/regenerate/route.ts +0 -20
- package/.next/standalone/src/app/api/agent/sidecar/[...path]/route.ts +0 -53
- package/.next/standalone/src/app/api/agents/install/route.ts +0 -143
- package/.next/standalone/src/app/api/agents/skill/route.ts +0 -20
- package/.next/standalone/src/app/api/agents/skill.tar.gz/route.ts +0 -87
- package/.next/standalone/src/app/api/app-proxy/[...path]/route.ts +0 -247
- package/.next/standalone/src/app/api/assets/[...path]/route.ts +0 -75
- package/.next/standalone/src/app/api/auth/[...all]/route.ts +0 -7
- package/.next/standalone/src/app/api/owner/init/route.ts +0 -14
- package/.next/standalone/src/app/api/share/[token]/route.ts +0 -269
- package/.next/standalone/src/app/api/share/route.ts +0 -127
- package/.next/standalone/src/app/api/system/admins/route.ts +0 -103
- package/.next/standalone/src/app/api/system/auth-config/route.ts +0 -22
- package/.next/standalone/src/app/api/system/auth-settings/route.ts +0 -86
- package/.next/standalone/src/app/api/system/browse/route.ts +0 -82
- package/.next/standalone/src/app/api/system/clear-root/route.ts +0 -16
- package/.next/standalone/src/app/api/system/config/route.ts +0 -14
- package/.next/standalone/src/app/api/system/pins/route.ts +0 -38
- package/.next/standalone/src/app/api/system/reveal/route.ts +0 -36
- package/.next/standalone/src/app/api/system/root-status/route.ts +0 -13
- package/.next/standalone/src/app/api/system/set-root/route.ts +0 -53
- package/.next/standalone/src/app/api/system/users/route.ts +0 -120
- package/.next/standalone/src/app/api/system/workspaces/[id]/open/route.ts +0 -34
- package/.next/standalone/src/app/api/system/workspaces/[id]/refresh/route.ts +0 -32
- package/.next/standalone/src/app/api/system/workspaces/[id]/route.ts +0 -78
- package/.next/standalone/src/app/api/system/workspaces/route.ts +0 -128
- package/.next/standalone/src/app/api/upload/[...path]/route.ts +0 -85
- package/.next/standalone/src/app/api/wiki/app/route.ts +0 -60
- package/.next/standalone/src/app/api/wiki/backlinks/route.ts +0 -29
- package/.next/standalone/src/app/api/wiki/content/route.ts +0 -159
- package/.next/standalone/src/app/api/wiki/download/route.ts +0 -100
- package/.next/standalone/src/app/api/wiki/file/route.ts +0 -57
- package/.next/standalone/src/app/api/wiki/folder/route.ts +0 -34
- package/.next/standalone/src/app/api/wiki/git-branches/route.ts +0 -32
- package/.next/standalone/src/app/api/wiki/git-checkout/route.ts +0 -45
- package/.next/standalone/src/app/api/wiki/git-diff/route.ts +0 -33
- package/.next/standalone/src/app/api/wiki/git-file-info/route.ts +0 -27
- package/.next/standalone/src/app/api/wiki/git-history/route.ts +0 -27
- package/.next/standalone/src/app/api/wiki/git-pull/route.ts +0 -48
- package/.next/standalone/src/app/api/wiki/move/route.ts +0 -61
- package/.next/standalone/src/app/api/wiki/new-file/route.ts +0 -56
- package/.next/standalone/src/app/api/wiki/outlinks/route.ts +0 -76
- package/.next/standalone/src/app/api/wiki/page/route.ts +0 -92
- package/.next/standalone/src/app/api/wiki/presence/route.ts +0 -56
- package/.next/standalone/src/app/api/wiki/route.ts +0 -116
- package/.next/standalone/src/app/api/wiki/search/route.ts +0 -44
- package/.next/standalone/src/app/api/wiki/slugs/route.ts +0 -54
- package/.next/standalone/src/app/api/wiki/upload/route.ts +0 -95
- package/.next/standalone/src/app/api/wiki/watch/route.ts +0 -67
- package/.next/standalone/src/app/globals.css +0 -1249
- package/.next/standalone/src/app/icon.svg +0 -11
- package/.next/standalone/src/app/layout.tsx +0 -78
- package/.next/standalone/src/app/manifest.ts +0 -30
- package/.next/standalone/src/app/page.tsx +0 -3260
- package/.next/standalone/src/app/s/[token]/page.tsx +0 -357
- package/.next/standalone/src/app/signin/page.tsx +0 -16
- package/.next/standalone/src/app/signin/signin-form.tsx +0 -238
- package/.next/standalone/src/components/ai-panel/activity-row.tsx +0 -284
- package/.next/standalone/src/components/ai-panel/ai-panel.tsx +0 -311
- package/.next/standalone/src/components/ai-panel/token-section.tsx +0 -313
- package/.next/standalone/src/components/auth-settings-sheet.tsx +0 -474
- package/.next/standalone/src/components/confirm-dialog.tsx +0 -56
- package/.next/standalone/src/components/dir-picker.tsx +0 -606
- package/.next/standalone/src/components/editor/backlinks-panel.tsx +0 -139
- package/.next/standalone/src/components/editor/bubble-menu.tsx +0 -346
- package/.next/standalone/src/components/editor/callout-extension.ts +0 -36
- package/.next/standalone/src/components/editor/comment-pip.tsx +0 -56
- package/.next/standalone/src/components/editor/comment-thread.tsx +0 -254
- package/.next/standalone/src/components/editor/csv-viewer.tsx +0 -379
- package/.next/standalone/src/components/editor/document-outline.tsx +0 -230
- package/.next/standalone/src/components/editor/editor-toolbar.tsx +0 -564
- package/.next/standalone/src/components/editor/editor.tsx +0 -1327
- package/.next/standalone/src/components/editor/extensions/drag-handle.ts +0 -325
- package/.next/standalone/src/components/editor/extensions/heading-anchors.ts +0 -55
- package/.next/standalone/src/components/editor/extensions/proof-span.ts +0 -60
- package/.next/standalone/src/components/editor/extensions/resizable-image.tsx +0 -159
- package/.next/standalone/src/components/editor/extensions.ts +0 -150
- package/.next/standalone/src/components/editor/file-fallback-viewer.tsx +0 -75
- package/.next/standalone/src/components/editor/folder-index.tsx +0 -236
- package/.next/standalone/src/components/editor/google-doc-viewer.tsx +0 -73
- package/.next/standalone/src/components/editor/image-viewer.tsx +0 -57
- package/.next/standalone/src/components/editor/large-file-gate.tsx +0 -108
- package/.next/standalone/src/components/editor/link-popover.tsx +0 -111
- package/.next/standalone/src/components/editor/media-popover.tsx +0 -212
- package/.next/standalone/src/components/editor/media-viewer.tsx +0 -70
- package/.next/standalone/src/components/editor/mermaid-viewer.tsx +0 -286
- package/.next/standalone/src/components/editor/node-app-viewer.tsx +0 -328
- package/.next/standalone/src/components/editor/notebook-viewer.tsx +0 -371
- package/.next/standalone/src/components/editor/office/docx-viewer.tsx +0 -93
- package/.next/standalone/src/components/editor/office/office-chrome.tsx +0 -83
- package/.next/standalone/src/components/editor/office/pptx-viewer.tsx +0 -104
- package/.next/standalone/src/components/editor/office/xlsx-viewer.tsx +0 -192
- package/.next/standalone/src/components/editor/pdf-viewer.tsx +0 -32
- package/.next/standalone/src/components/editor/proof-span-popover.tsx +0 -162
- package/.next/standalone/src/components/editor/slash-commands.tsx +0 -629
- package/.next/standalone/src/components/editor/source-viewer.tsx +0 -289
- package/.next/standalone/src/components/editor/suggest-edit-popover.tsx +0 -229
- package/.next/standalone/src/components/editor/suggestion-card.tsx +0 -206
- package/.next/standalone/src/components/editor/table-menu.tsx +0 -232
- package/.next/standalone/src/components/editor/view-mode-comment-button.tsx +0 -77
- package/.next/standalone/src/components/editor/website-viewer.tsx +0 -75
- package/.next/standalone/src/components/editor/wiki-link-create-dialog.tsx +0 -189
- package/.next/standalone/src/components/editor/wiki-link-decorator.ts +0 -79
- package/.next/standalone/src/components/editor/wiki-link-extension.ts +0 -120
- package/.next/standalone/src/components/editor/wiki-link-picker.tsx +0 -250
- package/.next/standalone/src/components/layout/viewer-toolbar.tsx +0 -54
- package/.next/standalone/src/components/search/search-command-dialog.tsx +0 -246
- package/.next/standalone/src/components/search/sidebar-search-box.tsx +0 -121
- package/.next/standalone/src/components/search/snippet-text.tsx +0 -48
- package/.next/standalone/src/components/share-dialog.tsx +0 -307
- package/.next/standalone/src/components/theme-provider.tsx +0 -16
- package/.next/standalone/src/components/theme-toggle.tsx +0 -24
- package/.next/standalone/src/components/ui/badge.tsx +0 -35
- package/.next/standalone/src/components/ui/button.tsx +0 -56
- package/.next/standalone/src/components/ui/card.tsx +0 -63
- package/.next/standalone/src/components/ui/collapsible.tsx +0 -9
- package/.next/standalone/src/components/ui/command.tsx +0 -151
- package/.next/standalone/src/components/ui/context-menu.tsx +0 -191
- package/.next/standalone/src/components/ui/dialog.tsx +0 -119
- package/.next/standalone/src/components/ui/dropdown-menu.tsx +0 -194
- package/.next/standalone/src/components/ui/input.tsx +0 -22
- package/.next/standalone/src/components/ui/label.tsx +0 -25
- package/.next/standalone/src/components/ui/popover.tsx +0 -33
- package/.next/standalone/src/components/ui/scroll-area.tsx +0 -47
- package/.next/standalone/src/components/ui/select.tsx +0 -156
- package/.next/standalone/src/components/ui/separator.tsx +0 -30
- package/.next/standalone/src/components/ui/sheet.tsx +0 -140
- package/.next/standalone/src/components/ui/skeleton.tsx +0 -15
- package/.next/standalone/src/components/ui/switch.tsx +0 -28
- package/.next/standalone/src/components/ui/tabs.tsx +0 -54
- package/.next/standalone/src/components/ui/textarea.tsx +0 -21
- package/.next/standalone/src/components/ui/tip.tsx +0 -23
- package/.next/standalone/src/components/ui/toggle-group.tsx +0 -41
- package/.next/standalone/src/components/ui/tooltip.tsx +0 -27
- package/.next/standalone/src/components/view-width-toggle.tsx +0 -70
- package/.next/standalone/src/components/wiki/frontmatter-header.tsx +0 -164
- package/.next/standalone/src/hooks/use-is-mobile.ts +0 -14
- package/.next/standalone/src/lib/app-runner.ts +0 -272
- package/.next/standalone/src/lib/auth/admin.ts +0 -120
- package/.next/standalone/src/lib/auth/allowlist.ts +0 -50
- package/.next/standalone/src/lib/auth/client.ts +0 -4
- package/.next/standalone/src/lib/auth/csrf.ts +0 -68
- package/.next/standalone/src/lib/auth/server.ts +0 -215
- package/.next/standalone/src/lib/cabinets/tree.ts +0 -75
- package/.next/standalone/src/lib/config.ts +0 -114
- package/.next/standalone/src/lib/embeds/detect.ts +0 -142
- package/.next/standalone/src/lib/git-secrets.ts +0 -65
- package/.next/standalone/src/lib/git.ts +0 -503
- package/.next/standalone/src/lib/google/detect.ts +0 -107
- package/.next/standalone/src/lib/markdown/parse-frontmatter.ts +0 -104
- package/.next/standalone/src/lib/markdown/remark-wikilinks.ts +0 -100
- package/.next/standalone/src/lib/markdown/sanitize-schema.ts +0 -106
- package/.next/standalone/src/lib/markdown/to-html.ts +0 -282
- package/.next/standalone/src/lib/markdown/to-markdown.ts +0 -252
- package/.next/standalone/src/lib/proof/activity-shared.ts +0 -31
- package/.next/standalone/src/lib/proof/activity.ts +0 -74
- package/.next/standalone/src/lib/proof/audit.ts +0 -88
- package/.next/standalone/src/lib/proof/auth.ts +0 -143
- package/.next/standalone/src/lib/proof/block-refs.ts +0 -133
- package/.next/standalone/src/lib/proof/blocks.ts +0 -73
- package/.next/standalone/src/lib/proof/client-auth.ts +0 -23
- package/.next/standalone/src/lib/proof/collab-state.ts +0 -81
- package/.next/standalone/src/lib/proof/event-bus.ts +0 -47
- package/.next/standalone/src/lib/proof/file-lock.ts +0 -43
- package/.next/standalone/src/lib/proof/glob.ts +0 -51
- package/.next/standalone/src/lib/proof/idempotency.ts +0 -37
- package/.next/standalone/src/lib/proof/lease.ts +0 -117
- package/.next/standalone/src/lib/proof/mutex.ts +0 -36
- package/.next/standalone/src/lib/proof/ops-applier.ts +0 -727
- package/.next/standalone/src/lib/proof/owner-auth.ts +0 -2
- package/.next/standalone/src/lib/proof/pending.ts +0 -97
- package/.next/standalone/src/lib/proof/proof-span.ts +0 -141
- package/.next/standalone/src/lib/proof/rate-limit.ts +0 -53
- package/.next/standalone/src/lib/proof/raw-fs.ts +0 -197
- package/.next/standalone/src/lib/proof/register-rate-limit.ts +0 -53
- package/.next/standalone/src/lib/proof/registry.ts +0 -195
- package/.next/standalone/src/lib/proof/sidecar.ts +0 -103
- package/.next/standalone/src/lib/proof/suggest-capture.ts +0 -69
- package/.next/standalone/src/lib/proof/types.ts +0 -182
- package/.next/standalone/src/lib/proof-config.ts +0 -14
- package/.next/standalone/src/lib/root-dir.ts +0 -35
- package/.next/standalone/src/lib/search/indexable-exts.ts +0 -25
- package/.next/standalone/src/lib/search/indexer.ts +0 -634
- package/.next/standalone/src/lib/search/sanitize.ts +0 -35
- package/.next/standalone/src/lib/search/search-db.ts +0 -57
- package/.next/standalone/src/lib/search/watcher-pool.ts +0 -79
- package/.next/standalone/src/lib/shared-docs/db.ts +0 -177
- package/.next/standalone/src/lib/toast.ts +0 -9
- package/.next/standalone/src/lib/utils.ts +0 -6
- package/.next/standalone/src/lib/wiki-helpers.ts +0 -36
- package/.next/standalone/src/lib/workspace-client.ts +0 -82
- package/.next/standalone/src/lib/workspace-context.ts +0 -173
- package/.next/standalone/src/lib/workspaces.ts +0 -400
- package/.next/standalone/src/middleware.ts +0 -44
- package/.next/standalone/src/stores/ai-panel-store.ts +0 -79
- package/.next/standalone/src/stores/editor-store.ts +0 -439
- package/.next/standalone/src/stores/pin-store.ts +0 -56
- package/.next/standalone/src/stores/proof-store.ts +0 -124
- package/.next/standalone/src/stores/recent-store.ts +0 -51
- package/.next/standalone/src/stores/search-store.ts +0 -104
- package/.next/standalone/src/stores/show-hidden-store.ts +0 -26
- package/.next/standalone/src/stores/sidebar-width-store.ts +0 -39
- package/.next/standalone/src/stores/skin-store.ts +0 -42
- package/.next/standalone/src/stores/tree-store.ts +0 -52
- package/.next/standalone/src/stores/view-width-store.ts +0 -101
- package/.next/standalone/src/stores/wiki-slugs-store.ts +0 -75
- package/.next/standalone/src/tests/proof/activity-aggregator.test.ts +0 -146
- package/.next/standalone/src/tests/proof/admin-create-user.test.ts +0 -43
- package/.next/standalone/src/tests/proof/agent-fs.test.ts +0 -973
- package/.next/standalone/src/tests/proof/agent-ownership.test.ts +0 -140
- package/.next/standalone/src/tests/proof/agent-workspace-scope.test.ts +0 -134
- package/.next/standalone/src/tests/proof/agents-install.test.ts +0 -110
- package/.next/standalone/src/tests/proof/bench-write.ts +0 -179
- package/.next/standalone/src/tests/proof/better-auth.test.ts +0 -68
- package/.next/standalone/src/tests/proof/block-refs.test.ts +0 -108
- package/.next/standalone/src/tests/proof/blocks.test.ts +0 -92
- package/.next/standalone/src/tests/proof/collab-state.test.ts +0 -501
- package/.next/standalone/src/tests/proof/comments-ops.test.ts +0 -177
- package/.next/standalone/src/tests/proof/editor-roundtrip.test.ts +0 -85
- package/.next/standalone/src/tests/proof/external-edit.test.ts +0 -58
- package/.next/standalone/src/tests/proof/file-lock.test.ts +0 -80
- package/.next/standalone/src/tests/proof/git-branches-checkout.test.ts +0 -136
- package/.next/standalone/src/tests/proof/git-read-features.test.ts +0 -473
- package/.next/standalone/src/tests/proof/git-secrets.test.ts +0 -138
- package/.next/standalone/src/tests/proof/git-sparse.test.ts +0 -257
- package/.next/standalone/src/tests/proof/git-workspace.test.ts +0 -135
- package/.next/standalone/src/tests/proof/git.test.ts +0 -243
- package/.next/standalone/src/tests/proof/glob.test.ts +0 -82
- package/.next/standalone/src/tests/proof/helpers/auth-session.ts +0 -27
- package/.next/standalone/src/tests/proof/markdown-to-html.test.ts +0 -46
- package/.next/standalone/src/tests/proof/ops-applier.test.ts +0 -368
- package/.next/standalone/src/tests/proof/owner-init.test.ts +0 -2
- package/.next/standalone/src/tests/proof/parse-frontmatter.test.ts +0 -60
- package/.next/standalone/src/tests/proof/preload.ts +0 -21
- package/.next/standalone/src/tests/proof/proof-span.test.ts +0 -98
- package/.next/standalone/src/tests/proof/rate-limit.test.ts +0 -54
- package/.next/standalone/src/tests/proof/readonly-enforcement.test.ts +0 -161
- package/.next/standalone/src/tests/proof/reconcile-sidecar.test.ts +0 -195
- package/.next/standalone/src/tests/proof/registration-flow.test.ts +0 -330
- package/.next/standalone/src/tests/proof/registry.test.ts +0 -169
- package/.next/standalone/src/tests/proof/routes.test.ts +0 -516
- package/.next/standalone/src/tests/proof/search-index.test.ts +0 -376
- package/.next/standalone/src/tests/proof/sidecar-lifecycle.test.ts +0 -177
- package/.next/standalone/src/tests/proof/sidecar-trim.test.ts +0 -58
- package/.next/standalone/src/tests/proof/suggestion-ops.test.ts +0 -280
- package/.next/standalone/src/tests/proof/wiki-content-put.test.ts +0 -140
- package/.next/standalone/src/tests/proof/wiki-routes-auth.test.ts +0 -208
- package/.next/standalone/src/tests/proof/workspace-isolation.test.ts +0 -87
- package/.next/standalone/src/tests/proof/workspaces-api.test.ts +0 -227
- package/.next/standalone/src/types/index.ts +0 -47
- package/.next/standalone/tailwind.config.ts +0 -191
- package/.next/standalone/tsconfig.json +0 -41
- package/.next/standalone/tsconfig.tsbuildinfo +0 -1
- /package/.next/standalone/.next/static/{WMOTgfV82apmdovxzgbMx → ecpoWt_SP3WkUTh0NsnuT}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{WMOTgfV82apmdovxzgbMx → ecpoWt_SP3WkUTh0NsnuT}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{WMOTgfV82apmdovxzgbMx → ecpoWt_SP3WkUTh0NsnuT}/_ssgManifest.js +0 -0
|
@@ -1,634 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FTS5 full-text search indexer.
|
|
3
|
-
*
|
|
4
|
-
* Lifecycle:
|
|
5
|
-
* - ensureIndexer(wsId, rootDir) -- idempotent; starts background initial scan once
|
|
6
|
-
* - indexFile / deleteFile -- incremental updates (called by chokidar listener)
|
|
7
|
-
* - ftsSearch -- BM25 search query
|
|
8
|
-
* - purgeWorkspace -- called on workspace delete
|
|
9
|
-
*
|
|
10
|
-
* Thread safety: better-sqlite3 is synchronous and single-threaded. All DB
|
|
11
|
-
* writes are serialised through JS's single thread. Event-loop blocking from the
|
|
12
|
-
* initial scan is avoided by yielding via setImmediate every INITIAL_YIELD_EVERY files.
|
|
13
|
-
*/
|
|
14
|
-
import { createHash } from "node:crypto";
|
|
15
|
-
import { readFile, readdir, stat } from "node:fs/promises";
|
|
16
|
-
import type { Dirent } from "node:fs";
|
|
17
|
-
import path from "node:path";
|
|
18
|
-
import { getSearchDb } from "./search-db";
|
|
19
|
-
import { sanitizeFtsQuery } from "./sanitize";
|
|
20
|
-
import { isIndexableExt, isMarkdownExt } from "./indexable-exts";
|
|
21
|
-
import { isDeniedRelPath, looksLikeBinary, safeAbsPath } from "../proof/raw-fs";
|
|
22
|
-
import { isNodeApp, isAppFolder } from "../wiki-helpers";
|
|
23
|
-
import { parseFrontmatter } from "../markdown/parse-frontmatter";
|
|
24
|
-
import { subscribe } from "./watcher-pool";
|
|
25
|
-
|
|
26
|
-
// ── Constants ──────────────────────────────────────────────────────────────────
|
|
27
|
-
|
|
28
|
-
const MAX_INDEX_BYTES = 1024 * 1024; // 1 MiB body cap
|
|
29
|
-
const BATCH_SIZE = 50; // max files per DB transaction
|
|
30
|
-
const BATCH_TIMEOUT_MS = 2000; // flush pending queue after this many ms
|
|
31
|
-
const INITIAL_YIELD_EVERY = 64; // setImmediate yield every N files
|
|
32
|
-
|
|
33
|
-
const SKIP_DIRS = new Set([".proof", ".git", "node_modules", ".next"]);
|
|
34
|
-
|
|
35
|
-
// ── Per-workspace state ────────────────────────────────────────────────────────
|
|
36
|
-
|
|
37
|
-
interface WsState {
|
|
38
|
-
rootDir: string;
|
|
39
|
-
initialScanDone: boolean;
|
|
40
|
-
initialScanPromise: Promise<void> | null;
|
|
41
|
-
pendingPaths: Set<string>;
|
|
42
|
-
pendingTimer: ReturnType<typeof setTimeout> | null;
|
|
43
|
-
unsubscribeWatcher: (() => void) | null;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const states = new Map<string, WsState>();
|
|
47
|
-
|
|
48
|
-
function getState(wsId: string, rootDir: string): WsState {
|
|
49
|
-
let s = states.get(wsId);
|
|
50
|
-
if (!s) {
|
|
51
|
-
s = {
|
|
52
|
-
rootDir,
|
|
53
|
-
initialScanDone: false,
|
|
54
|
-
initialScanPromise: null,
|
|
55
|
-
pendingPaths: new Set(),
|
|
56
|
-
pendingTimer: null,
|
|
57
|
-
unsubscribeWatcher: null,
|
|
58
|
-
};
|
|
59
|
-
states.set(wsId, s);
|
|
60
|
-
}
|
|
61
|
-
return s;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// ── DB helpers ─────────────────────────────────────────────────────────────────
|
|
65
|
-
|
|
66
|
-
function upsertDoc(
|
|
67
|
-
wsId: string,
|
|
68
|
-
relPath: string,
|
|
69
|
-
name: string,
|
|
70
|
-
frontmatter: string,
|
|
71
|
-
body: string,
|
|
72
|
-
size: number,
|
|
73
|
-
mtimeNs: bigint,
|
|
74
|
-
sha: string,
|
|
75
|
-
): void {
|
|
76
|
-
const db = getSearchDb();
|
|
77
|
-
// DELETE + INSERT because FTS5 has no native UPSERT.
|
|
78
|
-
db.prepare(`DELETE FROM docs WHERE ws = ? AND path = ?`).run(wsId, relPath);
|
|
79
|
-
db.prepare(`INSERT INTO docs (ws, path, name, frontmatter, body) VALUES (?, ?, ?, ?, ?)`)
|
|
80
|
-
.run(wsId, relPath, name, frontmatter, body);
|
|
81
|
-
db.prepare(`
|
|
82
|
-
INSERT INTO docs_meta (ws, path, size, mtime_ns, sha, indexed_at)
|
|
83
|
-
VALUES (?, ?, ?, ?, ?, ?)
|
|
84
|
-
ON CONFLICT(ws, path) DO UPDATE SET
|
|
85
|
-
size = excluded.size,
|
|
86
|
-
mtime_ns = excluded.mtime_ns,
|
|
87
|
-
sha = excluded.sha,
|
|
88
|
-
indexed_at = excluded.indexed_at
|
|
89
|
-
`).run(wsId, relPath, size, String(mtimeNs), sha, new Date().toISOString());
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function removeDoc(wsId: string, relPath: string): void {
|
|
93
|
-
const db = getSearchDb();
|
|
94
|
-
db.prepare(`DELETE FROM docs WHERE ws = ? AND path = ?`).run(wsId, relPath);
|
|
95
|
-
db.prepare(`DELETE FROM docs_meta WHERE ws = ? AND path = ?`).run(wsId, relPath);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// ── Text extraction ────────────────────────────────────────────────────────────
|
|
99
|
-
|
|
100
|
-
async function extractText(
|
|
101
|
-
absPath: string,
|
|
102
|
-
relPath: string,
|
|
103
|
-
): Promise<{ name: string; frontmatter: string; body: string; sha: string; size: number; mtimeNs: bigint } | null> {
|
|
104
|
-
let st: Awaited<ReturnType<typeof stat>>;
|
|
105
|
-
try {
|
|
106
|
-
st = await stat(absPath);
|
|
107
|
-
} catch {
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const size = st.size;
|
|
112
|
-
const mtimeNs = BigInt(Math.round(st.mtimeMs * 1_000_000));
|
|
113
|
-
const name = path.basename(relPath);
|
|
114
|
-
|
|
115
|
-
if (size > MAX_INDEX_BYTES) {
|
|
116
|
-
// Too large: index filename only, no body.
|
|
117
|
-
return { name, frontmatter: "", body: "", sha: "", size, mtimeNs };
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
let buf: Buffer;
|
|
121
|
-
try {
|
|
122
|
-
buf = await readFile(absPath);
|
|
123
|
-
} catch {
|
|
124
|
-
return null;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const sha = "sha256:" + createHash("sha256").update(buf).digest("hex");
|
|
128
|
-
|
|
129
|
-
if (looksLikeBinary(buf)) {
|
|
130
|
-
return { name, frontmatter: "", body: "", sha, size, mtimeNs };
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const text = buf.toString("utf-8");
|
|
134
|
-
|
|
135
|
-
if (isMarkdownExt(name)) {
|
|
136
|
-
const parsed = parseFrontmatter(text);
|
|
137
|
-
const fmStr = Object.entries(parsed.data)
|
|
138
|
-
.map(([k, v]) => `${k} ${Array.isArray(v) ? (v as unknown[]).join(" ") : String(v)}`)
|
|
139
|
-
.join(" ");
|
|
140
|
-
return { name, frontmatter: fmStr, body: parsed.body, sha, size, mtimeNs };
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return { name, frontmatter: "", body: text, sha, size, mtimeNs };
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// ── Index one file ─────────────────────────────────────────────────────────────
|
|
147
|
-
|
|
148
|
-
async function indexOnePath(wsId: string, rootDir: string, relPath: string): Promise<void> {
|
|
149
|
-
if (isDeniedRelPath(relPath)) return;
|
|
150
|
-
|
|
151
|
-
// App-dir contents are opaque leaves; never index files inside an app folder.
|
|
152
|
-
if (await isUnderApp(rootDir, relPath)) {
|
|
153
|
-
removeDoc(wsId, relPath);
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// Symlink-escape guard: resolve the realpath and confirm it stays under root.
|
|
158
|
-
// A symlink whose target escapes the workspace must never be indexed.
|
|
159
|
-
const absPath = await safeAbsPath(rootDir, relPath);
|
|
160
|
-
if (!absPath) {
|
|
161
|
-
removeDoc(wsId, relPath);
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
const db = getSearchDb();
|
|
165
|
-
|
|
166
|
-
// Fast-path: check size+mtime against existing meta
|
|
167
|
-
let st: Awaited<ReturnType<typeof stat>>;
|
|
168
|
-
try {
|
|
169
|
-
st = await stat(absPath);
|
|
170
|
-
} catch {
|
|
171
|
-
// File gone - remove it
|
|
172
|
-
removeDoc(wsId, relPath);
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (!st.isFile()) return;
|
|
177
|
-
|
|
178
|
-
const size = st.size;
|
|
179
|
-
const mtimeNs = BigInt(Math.round(st.mtimeMs * 1_000_000));
|
|
180
|
-
|
|
181
|
-
const meta = db.prepare(`SELECT size, mtime_ns, sha FROM docs_meta WHERE ws = ? AND path = ?`)
|
|
182
|
-
.get(wsId, relPath) as { size: number; mtime_ns: string; sha: string } | undefined;
|
|
183
|
-
|
|
184
|
-
if (meta && meta.size === size && BigInt(meta.mtime_ns) === mtimeNs) {
|
|
185
|
-
// Unchanged - skip
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const extracted = await extractText(absPath, relPath);
|
|
190
|
-
if (!extracted) return;
|
|
191
|
-
|
|
192
|
-
// If we got a sha and it matches the existing meta, just touch indexed_at
|
|
193
|
-
if (meta && extracted.sha && extracted.sha === meta.sha) {
|
|
194
|
-
db.prepare(`UPDATE docs_meta SET indexed_at = ? WHERE ws = ? AND path = ?`)
|
|
195
|
-
.run(new Date().toISOString(), wsId, relPath);
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const name = path.basename(relPath);
|
|
200
|
-
if (!isIndexableExt(name) && !isMarkdownExt(name)) {
|
|
201
|
-
// Non-text: index name only so filename searches work
|
|
202
|
-
upsertDoc(wsId, relPath, name, "", "", size, mtimeNs, extracted.sha);
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
upsertDoc(wsId, relPath, extracted.name, extracted.frontmatter, extracted.body, extracted.size, extracted.mtimeNs, extracted.sha);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// ── File tree walker ───────────────────────────────────────────────────────────
|
|
210
|
-
|
|
211
|
-
async function* walkFiles(rootDir: string, relDir: string): AsyncGenerator<string> {
|
|
212
|
-
let items: Dirent[];
|
|
213
|
-
try {
|
|
214
|
-
items = await readdir(path.join(rootDir, relDir), { withFileTypes: true });
|
|
215
|
-
} catch {
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
for (const item of items) {
|
|
219
|
-
if (SKIP_DIRS.has(item.name)) continue;
|
|
220
|
-
const childRel = relDir ? `${relDir}/${item.name}` : item.name;
|
|
221
|
-
if (item.isDirectory()) {
|
|
222
|
-
// App dirs (package.json or index.html) are opaque leaves in the UI:
|
|
223
|
-
// clicking runs the app, it is not a browsable folder. Do not index
|
|
224
|
-
// their contents so search does not surface bundled app internals.
|
|
225
|
-
if (await isNodeApp(rootDir, childRel) || await isAppFolder(rootDir, childRel)) {
|
|
226
|
-
continue;
|
|
227
|
-
}
|
|
228
|
-
yield* walkFiles(rootDir, childRel);
|
|
229
|
-
} else if (item.isFile() || item.isSymbolicLink()) {
|
|
230
|
-
yield childRel;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* True if any ancestor directory of relPath is an app folder (node-app or
|
|
237
|
-
* static app). Used by the incremental path so file events inside an app dir
|
|
238
|
-
* are ignored, matching the initial-scan walker which does not recurse into
|
|
239
|
-
* app dirs.
|
|
240
|
-
*/
|
|
241
|
-
async function isUnderApp(rootDir: string, relPath: string): Promise<boolean> {
|
|
242
|
-
const parts = relPath.split("/");
|
|
243
|
-
for (let i = 1; i < parts.length; i++) {
|
|
244
|
-
const ancestor = parts.slice(0, i).join("/");
|
|
245
|
-
if (await isNodeApp(rootDir, ancestor) || await isAppFolder(rootDir, ancestor)) {
|
|
246
|
-
return true;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
return false;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// ── Initial scan ───────────────────────────────────────────────────────────────
|
|
253
|
-
|
|
254
|
-
async function initialScan(wsId: string, rootDir: string): Promise<void> {
|
|
255
|
-
const db = getSearchDb();
|
|
256
|
-
let batch: Array<() => void> = [];
|
|
257
|
-
let fileCount = 0;
|
|
258
|
-
|
|
259
|
-
async function flushBatch() {
|
|
260
|
-
if (batch.length === 0) return;
|
|
261
|
-
const ops = batch;
|
|
262
|
-
batch = [];
|
|
263
|
-
db.transaction(() => {
|
|
264
|
-
for (const op of ops) op();
|
|
265
|
-
})();
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
for await (const relPath of walkFiles(rootDir, "")) {
|
|
269
|
-
if (isDeniedRelPath(relPath)) continue;
|
|
270
|
-
|
|
271
|
-
// Schedule the actual index work
|
|
272
|
-
const relPathCopy = relPath;
|
|
273
|
-
|
|
274
|
-
// Symlink-escape guard: skip anything whose realpath leaves the workspace.
|
|
275
|
-
const absPath = await safeAbsPath(rootDir, relPathCopy);
|
|
276
|
-
if (!absPath) continue;
|
|
277
|
-
|
|
278
|
-
// Stat + read inline (can't easily capture async in sync txn)
|
|
279
|
-
// We collect the data async, then write in a batch txn
|
|
280
|
-
let st: Awaited<ReturnType<typeof stat>>;
|
|
281
|
-
try {
|
|
282
|
-
st = await stat(absPath);
|
|
283
|
-
} catch {
|
|
284
|
-
continue;
|
|
285
|
-
}
|
|
286
|
-
if (!st.isFile()) continue;
|
|
287
|
-
|
|
288
|
-
const size = st.size;
|
|
289
|
-
const mtimeNs = BigInt(Math.round(st.mtimeMs * 1_000_000));
|
|
290
|
-
|
|
291
|
-
const meta = db.prepare(`SELECT size, mtime_ns FROM docs_meta WHERE ws = ? AND path = ?`)
|
|
292
|
-
.get(wsId, relPathCopy) as { size: number; mtime_ns: string } | undefined;
|
|
293
|
-
|
|
294
|
-
if (meta && meta.size === size && BigInt(meta.mtime_ns) === mtimeNs) {
|
|
295
|
-
fileCount++;
|
|
296
|
-
if (fileCount % INITIAL_YIELD_EVERY === 0) {
|
|
297
|
-
await new Promise<void>((r) => setImmediate(r));
|
|
298
|
-
}
|
|
299
|
-
continue;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
const extracted = await extractText(absPath, relPathCopy);
|
|
303
|
-
if (!extracted) continue;
|
|
304
|
-
|
|
305
|
-
const name = path.basename(relPathCopy);
|
|
306
|
-
const shouldIndexBody = isIndexableExt(name) || isMarkdownExt(name);
|
|
307
|
-
const fBody = shouldIndexBody ? extracted.body : "";
|
|
308
|
-
const fFm = shouldIndexBody ? extracted.frontmatter : "";
|
|
309
|
-
|
|
310
|
-
const capSize = extracted.size;
|
|
311
|
-
const capMtime = extracted.mtimeNs;
|
|
312
|
-
const capSha = extracted.sha;
|
|
313
|
-
|
|
314
|
-
batch.push(() => {
|
|
315
|
-
db.prepare(`DELETE FROM docs WHERE ws = ? AND path = ?`).run(wsId, relPathCopy);
|
|
316
|
-
db.prepare(`INSERT INTO docs (ws, path, name, frontmatter, body) VALUES (?, ?, ?, ?, ?)`)
|
|
317
|
-
.run(wsId, relPathCopy, extracted.name, fFm, fBody);
|
|
318
|
-
db.prepare(`
|
|
319
|
-
INSERT INTO docs_meta (ws, path, size, mtime_ns, sha, indexed_at)
|
|
320
|
-
VALUES (?, ?, ?, ?, ?, ?)
|
|
321
|
-
ON CONFLICT(ws, path) DO UPDATE SET
|
|
322
|
-
size = excluded.size,
|
|
323
|
-
mtime_ns = excluded.mtime_ns,
|
|
324
|
-
sha = excluded.sha,
|
|
325
|
-
indexed_at = excluded.indexed_at
|
|
326
|
-
`).run(wsId, relPathCopy, capSize, String(capMtime), capSha, new Date().toISOString());
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
fileCount++;
|
|
330
|
-
|
|
331
|
-
if (batch.length >= BATCH_SIZE) {
|
|
332
|
-
await flushBatch();
|
|
333
|
-
await new Promise<void>((r) => setImmediate(r));
|
|
334
|
-
} else if (fileCount % INITIAL_YIELD_EVERY === 0) {
|
|
335
|
-
await new Promise<void>((r) => setImmediate(r));
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
await flushBatch();
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// ── Batch queue (incremental updates from chokidar) ────────────────────────────
|
|
343
|
-
|
|
344
|
-
function enqueueIndex(wsId: string, relPath: string): void {
|
|
345
|
-
const s = states.get(wsId);
|
|
346
|
-
if (!s) return;
|
|
347
|
-
s.pendingPaths.add(relPath);
|
|
348
|
-
if (s.pendingTimer) return; // already scheduled
|
|
349
|
-
s.pendingTimer = setTimeout(() => flushQueue(wsId), BATCH_TIMEOUT_MS);
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
function flushQueue(wsId: string): void {
|
|
353
|
-
const s = states.get(wsId);
|
|
354
|
-
if (!s || s.pendingPaths.size === 0) return;
|
|
355
|
-
s.pendingTimer = null;
|
|
356
|
-
const paths = Array.from(s.pendingPaths);
|
|
357
|
-
s.pendingPaths.clear();
|
|
358
|
-
|
|
359
|
-
// Index each in a background promise; errors are logged not thrown.
|
|
360
|
-
// Work is chunked at BATCH_SIZE with a setImmediate yield between chunks so a
|
|
361
|
-
// large burst of file changes can never block the event loop in one big
|
|
362
|
-
// synchronous transaction.
|
|
363
|
-
const db = getSearchDb();
|
|
364
|
-
const rootDir = s.rootDir;
|
|
365
|
-
void (async () => {
|
|
366
|
-
let ops: Array<() => void> = [];
|
|
367
|
-
|
|
368
|
-
const flushOps = async () => {
|
|
369
|
-
if (ops.length === 0) return;
|
|
370
|
-
const chunk = ops;
|
|
371
|
-
ops = [];
|
|
372
|
-
db.transaction(() => { for (const op of chunk) op(); })();
|
|
373
|
-
await new Promise<void>((r) => setImmediate(r));
|
|
374
|
-
};
|
|
375
|
-
|
|
376
|
-
for (const relPath of paths) {
|
|
377
|
-
// App-dir contents are opaque leaves; never index files inside one.
|
|
378
|
-
if (await isUnderApp(rootDir, relPath)) {
|
|
379
|
-
ops.push(() => removeDoc(wsId, relPath));
|
|
380
|
-
if (ops.length >= BATCH_SIZE) await flushOps();
|
|
381
|
-
continue;
|
|
382
|
-
}
|
|
383
|
-
// Symlink-escape guard before any read.
|
|
384
|
-
const absPath = await safeAbsPath(rootDir, relPath);
|
|
385
|
-
if (!absPath) {
|
|
386
|
-
ops.push(() => removeDoc(wsId, relPath));
|
|
387
|
-
if (ops.length >= BATCH_SIZE) await flushOps();
|
|
388
|
-
continue;
|
|
389
|
-
}
|
|
390
|
-
const extracted = await extractText(absPath, relPath).catch(() => null);
|
|
391
|
-
if (!extracted) {
|
|
392
|
-
ops.push(() => removeDoc(wsId, relPath));
|
|
393
|
-
if (ops.length >= BATCH_SIZE) await flushOps();
|
|
394
|
-
continue;
|
|
395
|
-
}
|
|
396
|
-
const name = path.basename(relPath);
|
|
397
|
-
const shouldIndexBody = isIndexableExt(name) || isMarkdownExt(name);
|
|
398
|
-
const capSize = extracted.size;
|
|
399
|
-
const capMtime = extracted.mtimeNs;
|
|
400
|
-
const capSha = extracted.sha;
|
|
401
|
-
const fBody = shouldIndexBody ? extracted.body : "";
|
|
402
|
-
const fFm = shouldIndexBody ? extracted.frontmatter : "";
|
|
403
|
-
ops.push(() => {
|
|
404
|
-
db.prepare(`DELETE FROM docs WHERE ws = ? AND path = ?`).run(wsId, relPath);
|
|
405
|
-
db.prepare(`INSERT INTO docs (ws, path, name, frontmatter, body) VALUES (?, ?, ?, ?, ?)`)
|
|
406
|
-
.run(wsId, relPath, extracted.name, fFm, fBody);
|
|
407
|
-
db.prepare(`
|
|
408
|
-
INSERT INTO docs_meta (ws, path, size, mtime_ns, sha, indexed_at)
|
|
409
|
-
VALUES (?, ?, ?, ?, ?, ?)
|
|
410
|
-
ON CONFLICT(ws, path) DO UPDATE SET
|
|
411
|
-
size = excluded.size,
|
|
412
|
-
mtime_ns = excluded.mtime_ns,
|
|
413
|
-
sha = excluded.sha,
|
|
414
|
-
indexed_at = excluded.indexed_at
|
|
415
|
-
`).run(wsId, relPath, capSize, String(capMtime), capSha, new Date().toISOString());
|
|
416
|
-
});
|
|
417
|
-
if (ops.length >= BATCH_SIZE) await flushOps();
|
|
418
|
-
}
|
|
419
|
-
await flushOps();
|
|
420
|
-
})().catch((e) => console.error("[search] flushQueue error", e));
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
// ── Public API ─────────────────────────────────────────────────────────────────
|
|
424
|
-
|
|
425
|
-
/**
|
|
426
|
-
* Ensure the indexer is running for this workspace.
|
|
427
|
-
* Idempotent: concurrent calls share one initial-scan promise.
|
|
428
|
-
* Fire-and-forget from request handlers (catch the promise externally).
|
|
429
|
-
*/
|
|
430
|
-
export async function ensureIndexer(wsId: string, rootDir: string): Promise<void> {
|
|
431
|
-
const s = getState(wsId, rootDir);
|
|
432
|
-
|
|
433
|
-
if (s.initialScanDone) return;
|
|
434
|
-
|
|
435
|
-
if (!s.initialScanPromise) {
|
|
436
|
-
// Subscribe to chokidar (permanent listener -- watcher stays alive while indexer exists).
|
|
437
|
-
if (!s.unsubscribeWatcher) {
|
|
438
|
-
s.unsubscribeWatcher = subscribe(wsId, rootDir, (ev, relPath) => {
|
|
439
|
-
if (!relPath || isDeniedRelPath(relPath)) return;
|
|
440
|
-
if (ev === "add" || ev === "change") {
|
|
441
|
-
enqueueIndex(wsId, relPath);
|
|
442
|
-
} else if (ev === "unlink") {
|
|
443
|
-
void deleteFile(wsId, relPath);
|
|
444
|
-
}
|
|
445
|
-
});
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
// Kick off the scan in the background via setImmediate to not block the
|
|
449
|
-
// calling request. The promise is stored so subsequent ensureIndexer calls
|
|
450
|
-
// await the same scan instead of spawning a second one.
|
|
451
|
-
s.initialScanPromise = new Promise<void>((resolve) => {
|
|
452
|
-
setImmediate(() => {
|
|
453
|
-
void initialScan(wsId, rootDir).then(() => {
|
|
454
|
-
s.initialScanDone = true;
|
|
455
|
-
resolve();
|
|
456
|
-
}).catch((e) => {
|
|
457
|
-
console.error("[search] initial scan error", e);
|
|
458
|
-
s.initialScanPromise = null; // allow retry
|
|
459
|
-
resolve();
|
|
460
|
-
});
|
|
461
|
-
});
|
|
462
|
-
});
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
// Do NOT await: callers call fire-and-forget. Search works on whatever is already indexed.
|
|
466
|
-
// (Tests use _waitForIdle to synchronise.)
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
/** Index a single file (called on chokidar change/add events). */
|
|
470
|
-
export async function indexFile(wsId: string, rootDir: string, relPath: string): Promise<void> {
|
|
471
|
-
await indexOnePath(wsId, rootDir, relPath);
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
/** Remove a single file from the index. */
|
|
475
|
-
export async function deleteFile(wsId: string, relPath: string): Promise<void> {
|
|
476
|
-
removeDoc(wsId, relPath);
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
/** Remove all indexed data for a workspace (called on workspace delete). */
|
|
480
|
-
export async function purgeWorkspace(wsId: string): Promise<void> {
|
|
481
|
-
const db = getSearchDb();
|
|
482
|
-
db.transaction(() => {
|
|
483
|
-
db.prepare(`DELETE FROM docs WHERE ws = ?`).run(wsId);
|
|
484
|
-
db.prepare(`DELETE FROM docs_meta WHERE ws = ?`).run(wsId);
|
|
485
|
-
})();
|
|
486
|
-
// Clean up module state
|
|
487
|
-
const s = states.get(wsId);
|
|
488
|
-
if (s) {
|
|
489
|
-
if (s.pendingTimer) clearTimeout(s.pendingTimer);
|
|
490
|
-
s.unsubscribeWatcher?.();
|
|
491
|
-
states.delete(wsId);
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
export interface IndexedMatch {
|
|
496
|
-
path: string;
|
|
497
|
-
score: number; // negated BM25 rank (higher = better)
|
|
498
|
-
snippet: string;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
export interface SearchResult {
|
|
502
|
-
matches: IndexedMatch[];
|
|
503
|
-
truncated: boolean;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
/**
|
|
507
|
-
* Full-text search within a single workspace.
|
|
508
|
-
*
|
|
509
|
-
* CRITICAL: ws isolation is enforced by `WHERE ws = ?` on every query.
|
|
510
|
-
* This is the ONLY place in the codebase that executes SELECT ... FROM docs
|
|
511
|
-
* returning rows to callers. The ws column is always bound as the first param.
|
|
512
|
-
*/
|
|
513
|
-
export function ftsSearch(wsId: string, query: string, limit: number): SearchResult {
|
|
514
|
-
const sanitized = sanitizeFtsQuery(query);
|
|
515
|
-
if (!sanitized) return { matches: [], truncated: false };
|
|
516
|
-
|
|
517
|
-
const hardLimit = Math.min(Math.max(1, limit), 200);
|
|
518
|
-
const db = getSearchDb();
|
|
519
|
-
|
|
520
|
-
let rows: Array<{ path: string; score: number; snippet: string }>;
|
|
521
|
-
try {
|
|
522
|
-
rows = db.prepare(`
|
|
523
|
-
SELECT path,
|
|
524
|
-
rank AS score,
|
|
525
|
-
snippet(docs, 4, '<mark>', '</mark>', '\u2026', 12) AS snippet
|
|
526
|
-
FROM docs
|
|
527
|
-
WHERE ws = ? AND docs MATCH ?
|
|
528
|
-
ORDER BY rank
|
|
529
|
-
LIMIT ?
|
|
530
|
-
`).all(wsId, sanitized, hardLimit + 1) as typeof rows;
|
|
531
|
-
} catch (e) {
|
|
532
|
-
console.error("[search] ftsSearch error", e);
|
|
533
|
-
return { matches: [], truncated: false };
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
const truncated = rows.length > hardLimit;
|
|
537
|
-
return {
|
|
538
|
-
matches: rows.slice(0, hardLimit).map((r) => ({
|
|
539
|
-
path: r.path,
|
|
540
|
-
score: -r.score,
|
|
541
|
-
snippet: r.snippet ?? "",
|
|
542
|
-
})),
|
|
543
|
-
truncated,
|
|
544
|
-
};
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
// ── Backlinks ────────────────────────────────────────────────────────────────
|
|
548
|
-
|
|
549
|
-
export interface Backlink {
|
|
550
|
-
path: string;
|
|
551
|
-
snippet: string;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
/**
|
|
555
|
-
* True if `body` contains an actual wiki-link to `slug`: `[[slug]]`,
|
|
556
|
-
* `[[slug|alias]]`, or `[[slug#anchor]]`. FTS matches tokenised prose, so we
|
|
557
|
-
* re-check the raw text to drop false positives (a page merely mentioning the
|
|
558
|
-
* word, not linking to it).
|
|
559
|
-
*/
|
|
560
|
-
function hasWikiLinkTo(body: string, slug: string): boolean {
|
|
561
|
-
const esc = slug.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
562
|
-
const re = new RegExp(`\\[\\[${esc}(?:\\|[^\\]#|]+|#[a-z0-9-]+)?\\]\\]`, "i");
|
|
563
|
-
return re.test(body);
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
/**
|
|
567
|
-
* Resolve confirmed backlinks to a page in one in-process pass.
|
|
568
|
-
*
|
|
569
|
-
* Replaces the old client-side N+1 (search → fetch each candidate's content over
|
|
570
|
-
* HTTP). FTS is a coarse candidate filter; we read each candidate's `body` column
|
|
571
|
-
* directly from SQLite and confirm a literal `[[slug]]` link. No file I/O, no
|
|
572
|
-
* HTTP round-trips.
|
|
573
|
-
*
|
|
574
|
-
* ws isolation enforced by `WHERE ws = ?` (see ftsSearch contract).
|
|
575
|
-
*/
|
|
576
|
-
export function resolveBacklinks(
|
|
577
|
-
wsId: string,
|
|
578
|
-
slug: string,
|
|
579
|
-
excludePath: string,
|
|
580
|
-
limit: number,
|
|
581
|
-
): Backlink[] {
|
|
582
|
-
const sanitized = sanitizeFtsQuery(slug);
|
|
583
|
-
if (!sanitized) return [];
|
|
584
|
-
|
|
585
|
-
const candidateCap = Math.min(Math.max(1, limit), 200);
|
|
586
|
-
const db = getSearchDb();
|
|
587
|
-
|
|
588
|
-
let rows: Array<{ path: string; snippet: string; body: string }>;
|
|
589
|
-
try {
|
|
590
|
-
rows = db.prepare(`
|
|
591
|
-
SELECT path,
|
|
592
|
-
snippet(docs, 4, '<mark>', '</mark>', '…', 12) AS snippet,
|
|
593
|
-
body
|
|
594
|
-
FROM docs
|
|
595
|
-
WHERE ws = ? AND docs MATCH ?
|
|
596
|
-
ORDER BY rank
|
|
597
|
-
LIMIT ?
|
|
598
|
-
`).all(wsId, sanitized, candidateCap) as typeof rows;
|
|
599
|
-
} catch (e) {
|
|
600
|
-
console.error("[search] resolveBacklinks error", e);
|
|
601
|
-
return [];
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
const out: Backlink[] = [];
|
|
605
|
-
for (const r of rows) {
|
|
606
|
-
if (r.path === excludePath) continue;
|
|
607
|
-
if (!/\.md$/i.test(r.path)) continue;
|
|
608
|
-
if (!hasWikiLinkTo(r.body, slug)) continue;
|
|
609
|
-
out.push({ path: r.path, snippet: r.snippet ?? "" });
|
|
610
|
-
}
|
|
611
|
-
return out;
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
// ── Test hooks ─────────────────────────────────────────────────────────────────
|
|
615
|
-
|
|
616
|
-
/** Reset all module-level state (for tests). */
|
|
617
|
-
export function _resetIndexer(): void {
|
|
618
|
-
for (const s of states.values()) {
|
|
619
|
-
if (s.pendingTimer) clearTimeout(s.pendingTimer);
|
|
620
|
-
s.unsubscribeWatcher?.();
|
|
621
|
-
}
|
|
622
|
-
states.clear();
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
/**
|
|
626
|
-
* Wait until the initial scan for wsId has completed (for tests).
|
|
627
|
-
* Resolves immediately if the scan is already done.
|
|
628
|
-
*/
|
|
629
|
-
export async function _waitForIdle(wsId: string): Promise<void> {
|
|
630
|
-
const s = states.get(wsId);
|
|
631
|
-
if (!s) return;
|
|
632
|
-
if (s.initialScanDone) return;
|
|
633
|
-
if (s.initialScanPromise) await s.initialScanPromise;
|
|
634
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FTS5 user-query sanitizer.
|
|
3
|
-
*
|
|
4
|
-
* Converts raw user input into a safe FTS5 MATCH expression.
|
|
5
|
-
* Strategy: whitelist alphanumerics + hyphen + underscore, double-quote
|
|
6
|
-
* every token, optionally preserve trailing * for prefix search.
|
|
7
|
-
* This neutralizes ALL FTS5 operators (AND, OR, NOT, NEAR, (, ), ^)
|
|
8
|
-
* because quoted tokens are treated as literal phrases, not operators.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/** Match Unicode letters, numbers, hyphen, underscore, optionally followed by *. */
|
|
12
|
-
const TOKEN_RE = /[\p{L}\p{N}_-]+\*?/gu;
|
|
13
|
-
|
|
14
|
-
/** Max tokens accepted per query (prevents degenerate query bombs). */
|
|
15
|
-
const MAX_TOKENS = 16;
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Returns a sanitized FTS5 query string, or "" if the input is empty
|
|
19
|
-
* or contains no valid tokens. An empty return means the caller should
|
|
20
|
-
* short-circuit and return no results without hitting FTS5.
|
|
21
|
-
*/
|
|
22
|
-
export function sanitizeFtsQuery(raw: string): string {
|
|
23
|
-
const tokens = (raw.match(TOKEN_RE) ?? []).slice(0, MAX_TOKENS);
|
|
24
|
-
if (tokens.length === 0) return "";
|
|
25
|
-
return tokens
|
|
26
|
-
.map((t) => {
|
|
27
|
-
const star = t.endsWith("*");
|
|
28
|
-
const core = star ? t.slice(0, -1) : t;
|
|
29
|
-
if (!core) return null; // trailing * with empty body
|
|
30
|
-
const escaped = core.replace(/"/g, '""');
|
|
31
|
-
return `"${escaped}"` + (star ? "*" : "");
|
|
32
|
-
})
|
|
33
|
-
.filter(Boolean)
|
|
34
|
-
.join(" ");
|
|
35
|
-
}
|