threadshelf 1.2.1 → 1.2.2
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/CHANGELOG.md +23 -0
- package/README.md +1 -1
- package/bin/threadshelf.js +20 -3
- package/dist/src/paths.js +13 -5
- package/package.json +1 -1
- package/public/assets/{index-B7GRXu5E.js → index-TIPW3iTR.js} +1 -1
- package/public/index.html +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to ThreadShelf are documented here.
|
|
4
4
|
|
|
5
|
+
## 1.2.2 — 2026-09-20
|
|
6
|
+
|
|
7
|
+
### Packaging review follow-ups
|
|
8
|
+
|
|
9
|
+
- Resolve the package root by looking for the manifest rather than for a
|
|
10
|
+
directory named `dist`, so a repository cloned into a directory called `dist`
|
|
11
|
+
no longer anchors every path one level too high. `dist/` must stay free of a
|
|
12
|
+
stray `package.json` for this, which `test/packaging.test.js` now asserts.
|
|
13
|
+
- Detect a checkout by the presence of `src/` rather than of `src/server.ts`,
|
|
14
|
+
so renaming or splitting an entry point cannot silently move a developer's
|
|
15
|
+
archive out of the repository.
|
|
16
|
+
- Add `npx threadshelf mcp` next to the existing `threadshelf-mcp` executable.
|
|
17
|
+
It starts the server explicitly instead of relying on the MCP module's own
|
|
18
|
+
entry-point detection, which compares URLs in a way that is fragile on
|
|
19
|
+
Windows.
|
|
20
|
+
- Widen the `process.cwd()` guard in `test/packaging.test.js` to cover `bin/`
|
|
21
|
+
(the npx entry point) and `src/paths.ts`. It previously scanned only `.ts`
|
|
22
|
+
files and exempted `paths.ts` outright, so it would have passed while the two
|
|
23
|
+
files most able to break every path did the wrong thing.
|
|
24
|
+
- Exercise the compiled `dist/src/paths.js` from `npm test`, and the `mcp`
|
|
25
|
+
subcommand from `npm run pack:verify`. Both were previously covered only by
|
|
26
|
+
the five-minute packaging run, or not at all.
|
|
27
|
+
|
|
5
28
|
## 1.2.1 — 2026-09-20
|
|
6
29
|
|
|
7
30
|
### Install with `npx threadshelf`
|
package/README.md
CHANGED
|
@@ -585,7 +585,7 @@ ThreadShelf exposes your local index to MCP clients (e.g. Claude Desktop, or any
|
|
|
585
585
|
MCP-capable agent) over stdio — so a model can search your past chats as a tool.
|
|
586
586
|
|
|
587
587
|
```bash
|
|
588
|
-
npx threadshelf
|
|
588
|
+
npx threadshelf mcp # installed package (npx threadshelf-mcp is equivalent)
|
|
589
589
|
npm run mcp # from a clone
|
|
590
590
|
```
|
|
591
591
|
|
package/bin/threadshelf.js
CHANGED
|
@@ -22,6 +22,20 @@ const SUBCOMMANDS = {
|
|
|
22
22
|
search: '../dist/src/search-cli.js',
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
+
// `mcp` is handled separately: dist/mcp/server.js only starts itself when it
|
|
26
|
+
// decides it is the process entry point, and that check compares URLs in a way
|
|
27
|
+
// that is easy to get wrong on Windows. Start it explicitly instead, exactly as
|
|
28
|
+
// bin/threadshelf-mcp.js does.
|
|
29
|
+
const startMcpServer = async () => {
|
|
30
|
+
const [{ runServer }, { startIndexRecovery }] = await Promise.all([
|
|
31
|
+
import('../dist/mcp/server.js'),
|
|
32
|
+
import('../dist/src/store.js'),
|
|
33
|
+
]);
|
|
34
|
+
const stopRecovery = startIndexRecovery();
|
|
35
|
+
process.stdin.once('end', stopRecovery);
|
|
36
|
+
runServer();
|
|
37
|
+
};
|
|
38
|
+
|
|
25
39
|
const args = process.argv.slice(2);
|
|
26
40
|
|
|
27
41
|
const usage = `ThreadShelf ${pkg.version} - local semantic search for your AI chats
|
|
@@ -31,7 +45,8 @@ Usage:
|
|
|
31
45
|
npx threadshelf search "<query>" [...] Search the archive from the terminal
|
|
32
46
|
npx threadshelf ingest <folder> [...] Ingest a folder of exports
|
|
33
47
|
npx threadshelf parse <file> [...] Parse one export to normalized JSON
|
|
34
|
-
npx threadshelf
|
|
48
|
+
npx threadshelf mcp Start the MCP stdio server
|
|
49
|
+
(npx threadshelf-mcp is equivalent)
|
|
35
50
|
|
|
36
51
|
Options:
|
|
37
52
|
-p, --port <port> Port to listen on (default 3000, or $PORT)
|
|
@@ -66,7 +81,7 @@ const takeValue = (flag, index) => {
|
|
|
66
81
|
|
|
67
82
|
for (let i = 0; i < args.length; i += 1) {
|
|
68
83
|
const arg = args[i];
|
|
69
|
-
if (Object.hasOwn(SUBCOMMANDS, arg)) {
|
|
84
|
+
if (arg === 'mcp' || Object.hasOwn(SUBCOMMANDS, arg)) {
|
|
70
85
|
// Everything after the subcommand belongs to it, untouched.
|
|
71
86
|
subcommand = arg;
|
|
72
87
|
subcommandArgs = args.slice(i + 1);
|
|
@@ -105,7 +120,9 @@ if (showWhere) {
|
|
|
105
120
|
process.exit(0);
|
|
106
121
|
}
|
|
107
122
|
|
|
108
|
-
if (subcommand) {
|
|
123
|
+
if (subcommand === 'mcp') {
|
|
124
|
+
await startMcpServer();
|
|
125
|
+
} else if (subcommand) {
|
|
109
126
|
// The compiled CLIs read process.argv.slice(2) at module load, so present
|
|
110
127
|
// them the argv they would have seen if they had been invoked directly.
|
|
111
128
|
const entry = fileURLToPath(new URL(SUBCOMMANDS[subcommand], import.meta.url));
|
package/dist/src/paths.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
|
-
import {
|
|
3
|
+
import { dirname, join, resolve } from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
/**
|
|
6
6
|
* Single source of truth for "where does ThreadShelf read and write things".
|
|
@@ -24,10 +24,16 @@ const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
|
24
24
|
* This module lives at `<root>/src/paths.ts` in development and at
|
|
25
25
|
* `<root>/dist/src/paths.js` once compiled, so the package root is one or two
|
|
26
26
|
* levels up depending on which copy is running.
|
|
27
|
+
*
|
|
28
|
+
* The two cases are told apart by which candidate holds the manifest, not by
|
|
29
|
+
* the directory being named `dist`: a repository cloned into a directory that
|
|
30
|
+
* happens to be called `dist` would fool a name check and send every path one
|
|
31
|
+
* level too high. The build must therefore keep `dist/` free of a stray
|
|
32
|
+
* `package.json` — `test/packaging.test.js` asserts that.
|
|
27
33
|
*/
|
|
28
34
|
const resolvePackageRoot = (dir) => {
|
|
29
35
|
const parent = dirname(dir);
|
|
30
|
-
return
|
|
36
|
+
return existsSync(join(parent, 'package.json')) ? parent : dirname(parent);
|
|
31
37
|
};
|
|
32
38
|
const PACKAGE_ROOT = resolvePackageRoot(moduleDir);
|
|
33
39
|
/** Root of the installed package (or the repo in development). Static assets only. */
|
|
@@ -36,10 +42,12 @@ export const packageRoot = () => PACKAGE_ROOT;
|
|
|
36
42
|
export const packagePath = (...segments) => join(PACKAGE_ROOT, ...segments);
|
|
37
43
|
/**
|
|
38
44
|
* True when running from a source checkout rather than an installed package.
|
|
39
|
-
* The published tarball ships `dist
|
|
40
|
-
*
|
|
45
|
+
* The published tarball ships `dist/` and never `src/`, so an end user's
|
|
46
|
+
* install cannot be mistaken for a checkout. The whole directory is the marker
|
|
47
|
+
* rather than one file inside it, so renaming or splitting an entry point
|
|
48
|
+
* cannot silently move every developer's data out of their repository.
|
|
41
49
|
*/
|
|
42
|
-
export const isRepoCheckout = () => existsSync(join(PACKAGE_ROOT, 'src'
|
|
50
|
+
export const isRepoCheckout = () => existsSync(join(PACKAGE_ROOT, 'src'));
|
|
43
51
|
/** Per-user data directory for an installed package. */
|
|
44
52
|
export const userDataDir = (env = process.env, platform = process.platform, home = homedir()) => {
|
|
45
53
|
if (platform === 'win32') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "threadshelf",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "Local semantic search, backup, and RAG for your AI chats — ChatGPT, Claude, Google AI Studio, OpenRouter, LM Studio, and Grok — searchable from a web UI, HTTP API, or MCP",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -14,7 +14,7 @@ Error generating stack: `+e.message+`
|
|
|
14
14
|
`).trim()+`
|
|
15
15
|
`},_o=e=>(e||`conversation`).toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``).slice(0,60)||`conversation`,vo=(e,t,n=`text/markdown;charset=utf-8`)=>{let r=new Blob([t],{type:n}),i=URL.createObjectURL(r),a=document.createElement(`a`);a.href=i,a.download=e,document.body.appendChild(a),a.click(),a.remove(),URL.revokeObjectURL(i)},yo=e=>!e||e<=0?`—`:e>=1024**3?`${(e/1024**3).toFixed(e>=10*1024**3?0:1)} GB`:e>=1024**2?`${Math.round(e/1024**2)} MB`:`${Math.round(e/1024)} KB`,bo=e=>!e||e<=0?`0`:e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${Math.round(e/1e3)}k`:String(e);function xo({variant:e=`full`}){let t=B(e=>e.theme),n=B(e=>e.toggleTheme),r=t===`dark`,i=r?`light`:`dark`;return(0,R.jsxs)(`button`,{className:`theme-toggle ${e}`,onClick:n,title:`Switch to ${i} theme`,"aria-label":`Switch to ${i} theme`,children:[(0,R.jsx)(`span`,{className:`tt-ico`,children:r?W.sun:W.moon}),e===`full`&&(0,R.jsx)(`span`,{className:`tt-label`,children:r?`Light`:`Dark`})]})}var So=1,Co=4e3,wo=Ta((e,t)=>({toasts:[],confirmState:null,pushToast:(n,r=`info`)=>{let i=So++;e(e=>({toasts:[...e.toasts,{id:i,type:r,text:n}]})),setTimeout(()=>t().dismissToast(i),Co)},dismissToast:t=>{e(e=>({toasts:e.toasts.filter(e=>e.id!==t)}))},confirm:n=>new Promise(r=>{let i=t().confirmState;i&&i.resolve(!1),e({confirmState:{...n,id:So++,resolve:r}})}),resolveConfirm:n=>{let r=t().confirmState;r&&r.resolve(n),e({confirmState:null})}})),q={info:e=>wo.getState().pushToast(e,`info`),success:e=>wo.getState().pushToast(e,`success`),error:e=>wo.getState().pushToast(e,`error`)},To=e=>wo.getState().confirm(e),Eo=e=>{if(!e)return``;let t=e.split(/[\\/]/);return t[t.length-1]||e};function Do({detailed:e=!1}){let[t,n]=(0,L.useState)(null),[r,i]=(0,L.useState)(null),[a,o]=(0,L.useState)(!1),s=(0,L.useCallback)(async()=>{try{let[e,t]=await Promise.all([H.generationRuntime(),H.generationLlamaLogs().catch(()=>null)]);n(e.runtime),t&&i(t)}catch{n(null)}},[]);(0,L.useEffect)(()=>{let e=window.setTimeout(()=>void s(),0),t=window.setInterval(()=>void s(),3e3),r=e=>{if(e instanceof CustomEvent&&e.detail){n(e.detail),H.generationLlamaLogs().then(i).catch(()=>void 0);return}s()};return window.addEventListener(`threadshelf:generation-runtime-changed`,r),()=>{window.clearTimeout(e),window.clearInterval(t),window.removeEventListener(`threadshelf:generation-runtime-changed`,r)}},[s]);let c=async()=>{o(!0);try{let e=await H.ejectGenerationModel(t?.model);n(e.runtime),window.dispatchEvent(new Event(`threadshelf:generation-runtime-changed`)),q.success(`llama.cpp model ejected from memory.`)}catch(e){q.error(e instanceof Error?e.message:`Could not eject the model.`)}finally{o(!1)}},l=t&&(t.state===`starting`||t.state===`ready`||t.state===`external`&&!!t.model),u=r?.devices[0]?.id.replace(/\d+$/,``).toUpperCase(),d=!t||!r?`unknown`:t.state===`stopped`?r.devices.length>0?`idle · GPU (${u||`accelerator`})`:`idle · CPU`:r.offload.mode===`hybrid`?`hybrid ${r.offload.gpuPercent}% GPU`:r.offload.mode===`gpu`?`GPU · ${u||`accelerator`}`:r.offload.mode===`cpu`?`CPU`:r.devices.length>0?`GPU · ${u||`accelerator`}`:r.deviceDetectionSupported?`CPU`:`unknown`,f=[r?.executable?`Selected executable: ${r.executable}`:void 0,`Detected compute: ${d}`,``,`Check for a newer stable llama.cpp build:`,`npm run setup:llama -- -- --check`,``,`Install CPU:`,`npm run setup:llama -- -- --install --variant cpu`,``,`Install NVIDIA CUDA:`,`npm run setup:llama -- -- --install --variant cuda`,``,`Install Vulkan GPU:`,`npm run setup:llama -- -- --install --variant vulkan`,``,`macOS: use the cpu variant; Metal is included automatically.`].filter(e=>e!==void 0).join(`
|
|
16
16
|
`),p=Object.entries(r?.offload.deviceBufferMiB??{}).filter(([e])=>!e.toUpperCase().startsWith(`CPU`)).reduce((e,[,t])=>e+t,0),m=(r?.profile??[]).filter(e=>e.applied),h=m.length>0&&t?.state!==`stopped`?[d,...m.map(e=>`${e.setting} ${e.value}`),p>0?`GPU weights ${(p/1024).toFixed(1)} GiB`:``].filter(Boolean).join(` · `):``,g=(r?.profile??[]).filter(e=>e.note).map(e=>`${e.setting}: ${e.applied?``:`skipped, `}${e.note}`).join(`
|
|
17
|
-
`);return(0,R.jsxs)(`div`,{className:`global-runtime`,"data-state":t?.state||`unknown`,title:t?.detail,children:[(0,R.jsx)(`span`,{className:`runtime-dot`,"aria-hidden":`true`}),(0,R.jsxs)(`span`,{className:`global-runtime-copy`,children:[(0,R.jsxs)(`b`,{children:[(0,R.jsx)(`span`,{children:t?.state===`starting`?`llama.cpp · loading`:`llama.cpp`}),(0,R.jsx)(`em`,{children:d}),(0,R.jsx)(`span`,{className:`runtime-install-help`,tabIndex:0,role:`img`,"aria-label":`llama.cpp CPU and GPU install commands`,title:f,children:`?`})]}),(0,R.jsx)(`span`,{children:t?.model?Eo(t.model):t?`no model loaded`:`status unavailable`}),e&&t?.detail&&(0,R.jsx)(`small`,{children:t.detail}),e&&h&&(0,R.jsx)(`small`,{className:`runtime-profile`,title:g||void 0,children:h})]}),l&&(0,R.jsx)(`button`,{type:`button`,disabled:a,onClick:()=>void c(),children:a?`…`:`Eject`})]})}var Oo=[{id:`/search`,viewKey:`search`,label:`Search archive`,icon:W.search},{id:`/insights`,viewKey:`insights`,label:`Insights`,icon:W.chart}],ko=[{id:`/indexing`,viewKey:`indexing`,label:`Add data`,icon:W.download},{id:`/mcp`,viewKey:`mcp`,label:`MCP`,icon:W.plug},{id:`/settings`,viewKey:`settings`,label:`Settings`,icon:W.settings}];function Ao({view:e,setView:t,activeColl:n,setActiveColl:r,onNewChat:i,onNewPrivateChat:a,onOpenChat:o,activeChatId:s,onCmdK:c,onNewColl:l,onDeleteCollection:u,collections:d,stats:f}){let[p,m]=(0,L.useState)(!1),[h,g]=(0,L.useState)(e===`chat`),{data:_,isLoading:v,refetch:y}=Ha(),b=_?.threads??[],x=d.filter(e=>e!==`all`),S=x.reduce((e,t)=>e+(f[t]?.files??0),0),C=x.reduce((e,t)=>e+(f[t]?.chunks??0),0),w=e=>{let t=f[e];return(t?.chunks??0)===0&&(t?.files??0)===0&&(t?.conversations??0)===0},T=x.filter(e=>w(e)&&e!==n),E=x.filter(e=>p||!w(e)||e===n),D=e=>{let t=e?.conversations??0;return t>0?`${t.toLocaleString()} thread${t===1?``:`s`}`:`${(e?.files??0).toLocaleString()} files`},O=e=>{let t=e?.conversations??0;return`${t>0?`${t.toLocaleString()} conversation${t===1?``:`s`}`:`${(e?.files??0).toLocaleString()} files`} · ${(e?.chunks??0).toLocaleString()} indexed chunks`};return(0,R.jsxs)(`aside`,{className:`sidebar`,children:[(0,R.jsxs)(`div`,{className:`sb-brand`,children:[(0,R.jsx)(`div`,{className:`sb-logo`,"aria-hidden":`true`}),(0,R.jsxs)(`div`,{className:`sb-name`,children:[(0,R.jsx)(`b`,{children:`ThreadShelf`}),(0,R.jsxs)(`span`,{children:[`v`,`1.2.1`,` · local`]})]})]}),(0,R.jsxs)(`section`,{className:`sb-chat-panel`,"aria-label":`Conversations`,children:[(0,R.jsxs)(`div`,{className:`sb-chat-create`,children:[(0,R.jsxs)(`button`,{id:`sidebarNewChatButton`,className:`sb-new-chat`,onClick:i,children:[W.spark,(0,R.jsx)(`span`,{children:`New chat`})]}),(0,R.jsx)(`button`,{id:`sidebarPrivateChatButton`,className:`sb-private-chat`,"aria-label":`Start private conversation`,title:`Start a private chat that is cleared with this tab`,onClick:a,children:W.ghost})]}),(0,R.jsxs)(`div`,{className:`sb-chat-history`,children:[(0,R.jsxs)(`button`,{id:`sidebarChatHistoryToggle`,className:`sb-chat-history-toggle`,"aria-expanded":h,onClick:()=>{let e=!h;g(e),e&&y()},children:[(0,R.jsx)(`span`,{className:`ico`,children:W.chat}),(0,R.jsx)(`span`,{className:`label`,children:`Your chats`}),b.length>0&&(0,R.jsx)(`em`,{children:b.length}),(0,R.jsx)(`span`,{className:`sb-chat-chevron`,"aria-hidden":`true`,children:`▾`})]}),h&&(0,R.jsxs)(`div`,{className:`sb-chat-history-list`,children:[v&&(0,R.jsx)(`span`,{className:`sb-chat-history-empty`,children:`Loading chats…`}),!v&&b.length===0&&(0,R.jsx)(`span`,{className:`sb-chat-history-empty`,children:`No saved chats yet.`}),b.map(e=>(0,R.jsxs)(`button`,{className:`sb-chat-item`,"data-active":e.id===s,title:e.title,onClick:()=>o(e.id),children:[(0,R.jsx)(`strong`,{children:e.title}),(0,R.jsx)(`span`,{title:`${e.model?`${no(e.model)} · `:``}${e.turnCount} messages`,children:oo(e.updatedAt)||`just now`})]},e.id))]})]})]}),(0,R.jsxs)(`button`,{className:`sb-cmdk`,onClick:c,children:[W.search,(0,R.jsx)(`span`,{children:`Quick jump…`}),(0,R.jsx)(`kbd`,{children:`Ctrl+K`})]}),(0,R.jsx)(`div`,{className:`sb-section`,children:(0,R.jsx)(`span`,{children:`Library`})}),(0,R.jsx)(`nav`,{className:`sb-list`,style:{flex:`0 0 auto`},children:Oo.map(n=>(0,R.jsxs)(`button`,{id:n.viewKey===`indexing`?`indexingNavBtn`:void 0,className:`sb-item`,"data-active":e===n.viewKey,onClick:()=>t(n.id),children:[(0,R.jsx)(`span`,{className:`ico`,children:n.icon}),(0,R.jsx)(`span`,{className:`label`,children:n.label})]},n.id))}),(0,R.jsxs)(`div`,{className:`sb-section`,children:[(0,R.jsx)(`span`,{children:`Archive collections`}),(0,R.jsx)(`button`,{title:`New collection`,onClick:l,children:W.plus})]}),(0,R.jsxs)(`div`,{className:`sb-list sb-collections`,children:[(0,R.jsxs)(`button`,{id:`collection-all`,className:`sb-coll`,"data-active":n===`all`,onClick:()=>r(`all`),children:[(0,R.jsx)(`span`,{className:`sb-coll-dot`,style:{background:`var(--accent)`}}),(0,R.jsxs)(`span`,{className:`sb-coll-meta`,children:[(0,R.jsx)(`b`,{children:`All collections`}),(0,R.jsxs)(`span`,{children:[S,` files · `,C.toLocaleString(),` chunks`]})]})]}),E.map(e=>{let t=f[e];return(0,R.jsxs)(`div`,{className:`sb-coll-row`,children:[(0,R.jsxs)(`button`,{id:`collection-${e}`,className:`sb-coll`,"data-active":n===e,onClick:()=>r(e),children:[(0,R.jsx)(`span`,{className:`sb-coll-dot`}),(0,R.jsxs)(`span`,{className:`sb-coll-meta`,children:[(0,R.jsx)(`b`,{children:Za(e)}),(0,R.jsxs)(`span`,{title:O(t),children:[D(t),` · `,(t?.chunks??0).toLocaleString(),` chunks`]})]})]}),e!==`chunks`&&e!==`threadshelf_conversations`&&(0,R.jsx)(`button`,{id:`delete-collection-${e}`,className:`sb-coll-delete`,title:`Delete ${Za(e)}`,"aria-label":`Delete ${Za(e)}`,onClick:t=>{t.stopPropagation(),u(e)},children:W.trash})]},e)}),T.length>0&&(0,R.jsx)(`button`,{id:`toggleEmptyCollections`,className:`sb-coll-empty-toggle`,onClick:()=>m(e=>!e),children:p?`Hide empty collections`:`Show ${T.length} empty`})]}),(0,R.jsx)(`div`,{className:`sb-section sb-manage-section`,children:(0,R.jsx)(`span`,{children:`Manage`})}),(0,R.jsx)(`nav`,{className:`sb-list sb-manage-list`,children:ko.map(n=>(0,R.jsxs)(`button`,{id:n.viewKey===`indexing`?`indexingNavBtn`:void 0,className:`sb-item`,"data-active":e===n.viewKey,onClick:()=>t(n.id),children:[(0,R.jsx)(`span`,{className:`ico`,children:n.icon}),(0,R.jsx)(`span`,{className:`label`,children:n.label})]},n.id))}),(0,R.jsxs)(`div`,{className:`sb-footer`,children:[(0,R.jsx)(Do,{}),(0,R.jsxs)(`div`,{className:`sb-footer-row`,children:[(0,R.jsxs)(`span`,{className:`sb-status`,title:`Local backend · paraphrase-multilingual embeddings · LanceDB storage. Model runtime and eject live in the chat model menu.`,children:[`local · :`,window.location.port||`80`]}),(0,R.jsx)(xo,{variant:`icon`})]})]})]})}function jo({open:e,onClose:t,setView:n,onNewChat:r,setActiveColl:i,collections:a,stats:o,onNewColl:s,onRefresh:c}){let[l,u]=(0,L.useState)(``),[d,f]=(0,L.useState)(0),p=(0,L.useRef)(null);if((0,L.useEffect)(()=>{if(e){let e=window.setTimeout(()=>{u(``),f(0),p.current?.focus()},30);return()=>window.clearTimeout(e)}},[e]),!e)return null;let m=[{label:`Go to`,items:[{id:`go-search`,label:`Search archive`,icon:W.search,action:()=>n(`/search`)},{id:`go-chat`,label:`Chat history`,icon:W.chat,action:()=>n(`/chat`)},{id:`go-insights`,label:`Insights`,icon:W.chart,action:()=>n(`/insights`)},{id:`go-indexing`,label:`Indexing`,icon:W.download,action:()=>n(`/indexing`)},{id:`go-mcp`,label:`MCP`,icon:W.plug,action:()=>n(`/mcp`)},{id:`go-settings`,label:`Settings`,icon:W.settings,action:()=>n(`/settings`)}]},{label:`Collections`,items:[{id:`coll-all`,label:`All collections`,icon:W.scope,action:()=>i(`all`)},...a.filter(e=>e!==`all`).map(e=>({id:`coll-${e}`,label:Za(e),icon:W.database,meta:`${o[e]?.files??0} files`,action:()=>i(e)}))]},{label:`Actions`,items:[{id:`a-chat`,label:`New chat`,icon:W.spark,action:r},{id:`a-new`,label:`New collection…`,icon:W.plus,action:s},{id:`a-index`,label:`Index a folder`,icon:W.folder,action:()=>n(`/indexing`)},{id:`a-refresh`,label:`Refresh stats`,icon:W.refresh,action:c}]}].map(e=>({...e,items:e.items.filter(e=>!l||e.label.toLowerCase().includes(l.toLowerCase()))})).filter(e=>e.items.length>0),h=m.flatMap(e=>e.items),g=Math.min(d,h.length-1),_=e=>{e.key===`ArrowDown`?(e.preventDefault(),f(e=>(e+1)%Math.max(1,h.length))):e.key===`ArrowUp`?(e.preventDefault(),f(e=>(e-1+h.length)%Math.max(1,h.length))):e.key===`Enter`?(e.preventDefault(),h[g]?.action(),t()):e.key===`Escape`&&t()},v=0;return(0,R.jsx)(`div`,{className:`scrim`,onClick:t,children:(0,R.jsxs)(`div`,{className:`cmdk`,onClick:e=>e.stopPropagation(),children:[(0,R.jsxs)(`div`,{className:`cmdk-input`,children:[W.searchLg,(0,R.jsx)(`input`,{ref:p,value:l,onChange:e=>{u(e.target.value),f(0)},onKeyDown:_,placeholder:`Search commands, collections, or actions…`}),(0,R.jsx)(`kbd`,{children:`ESC`})]}),(0,R.jsxs)(`div`,{className:`cmdk-list`,children:[m.map(e=>(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`cmdk-group-h`,children:e.label}),e.items.map(e=>{let n=v++;return(0,R.jsxs)(`button`,{className:`cmdk-item`,"data-active":n===g,onMouseEnter:()=>f(n),onClick:()=>{e.action(),t()},children:[(0,R.jsx)(`span`,{className:`ico`,children:e.icon}),(0,R.jsx)(`span`,{children:e.label}),e.meta&&(0,R.jsx)(`span`,{className:`meta`,children:e.meta})]},e.id)})]},e.label)),h.length===0&&(0,R.jsx)(`div`,{style:{padding:24,textAlign:`center`,color:`var(--text-3)`,fontSize:12},children:`No matches`})]})]})})}function Mo({open:e,onClose:t,onCreated:n}){let[r,i]=(0,L.useState)(``),a=Ya(),o=(0,L.useCallback)(async()=>{if(r)try{let e=await a.mutateAsync(r);i(``),t(),n(e.collection??r),q.success(`Created collection "${e.collection??r}".`)}catch(e){q.error(e instanceof Error?e.message:`Unknown error`)}},[r,t,n,a]);return e?(0,R.jsx)(`div`,{className:`scrim`,onClick:t,children:(0,R.jsxs)(`div`,{className:`modal-card`,onClick:e=>e.stopPropagation(),children:[(0,R.jsxs)(`div`,{className:`modal-head`,children:[(0,R.jsx)(`h3`,{children:`New collection`}),(0,R.jsx)(`p`,{children:`Collections are local LanceDB tables. Use lowercase, alphanumeric, hyphens, underscores.`})]}),(0,R.jsxs)(`div`,{className:`modal-body`,children:[(0,R.jsx)(`label`,{children:`Name`}),(0,R.jsx)(`input`,{autoFocus:!0,value:r,onChange:e=>i(e.target.value.replace(/[^a-z0-9_-]/g,``).toLowerCase()),onKeyDown:e=>e.key===`Enter`&&r&&void o(),placeholder:`my-archive`})]}),(0,R.jsxs)(`div`,{className:`modal-foot`,children:[(0,R.jsx)(`button`,{className:`btn ghost`,onClick:t,children:`Cancel`}),(0,R.jsx)(`button`,{className:`btn primary`,onClick:()=>void o(),disabled:!r,children:`Create`})]})]})}):null}var No={info:W.info,success:W.check,error:W.warn};function Po(){let e=wo(e=>e.toasts),t=wo(e=>e.dismissToast);return e.length===0?null:(0,R.jsx)(`div`,{className:`toaster`,role:`status`,"aria-live":`polite`,children:e.map(e=>(0,R.jsxs)(`button`,{className:`toast`,"data-type":e.type,onClick:()=>t(e.id),title:`Dismiss`,children:[(0,R.jsx)(`span`,{className:`toast-ico`,children:No[e.type]}),(0,R.jsx)(`span`,{className:`toast-text`,children:e.text})]},e.id))})}function Fo(){let e=wo(e=>e.confirmState),t=wo(e=>e.resolveConfirm);if((0,L.useEffect)(()=>{if(!e)return;let n=e=>{e.key===`Escape`&&(e.preventDefault(),e.stopPropagation(),t(!1))};return window.addEventListener(`keydown`,n,!0),()=>window.removeEventListener(`keydown`,n,!0)},[e,t]),!e)return null;let{title:n,message:r,confirmLabel:i,cancelLabel:a,danger:o}=e;return(0,R.jsx)(`div`,{className:`scrim`,onClick:()=>t(!1),children:(0,R.jsxs)(`div`,{className:`modal-card`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-modal":`true`,children:[(0,R.jsxs)(`div`,{className:`modal-head`,children:[(0,R.jsx)(`h3`,{children:n}),r&&(0,R.jsx)(`p`,{children:r})]}),(0,R.jsxs)(`div`,{className:`modal-foot`,children:[(0,R.jsx)(`button`,{className:`btn ghost`,onClick:()=>t(!1),children:a??`Cancel`}),(0,R.jsx)(`button`,{className:`btn ${o?`danger`:`primary`}`,onClick:()=>t(!0),autoFocus:!0,children:i??`Confirm`})]})]})})}function Io(){let e=Qr(),t=Ke(),n=fa(),r=n.some(e=>e.pathname===`/thread`),i=B(e=>e.theme),a=B(e=>e.activeColl),o=B(e=>e.setActiveColl),s=B(e=>e.sidebarOpen),c=B(e=>e.setSidebarOpen),l=B(e=>e.cmdkOpen),u=B(e=>e.setCmdkOpen),d=B(e=>e.newCollOpen),f=B(e=>e.setNewCollOpen),{data:p}=za(),m=p?.collections??[`all`,`chunks`],h=p?.stats??{},g=qa(),_=(0,L.useCallback)(()=>c(!1),[c]),v=(0,L.useCallback)(async()=>{await Promise.all([t.invalidateQueries({queryKey:[`collections`]}),t.invalidateQueries({queryKey:[`files`]}),t.invalidateQueries({queryKey:[`search`]}),t.invalidateQueries({queryKey:[`thread`]})]),q.success(`Local index data refreshed.`)},[t]);(0,L.useEffect)(()=>{document.documentElement.dataset.theme=i},[i]);let y=(0,L.useCallback)(async t=>{if(t!==`chunks`&&t!==`threadshelf_conversations`&&await To({title:`Delete collection "${Za(t)}"?`,message:`The index and copies previously uploaded through ThreadShelf are deleted. Files in the original folder you selected remain untouched.`,confirmLabel:`Delete`,danger:!0}))try{await g.mutateAsync(t),a===t&&(o(`all`),e.navigate({to:`/search/$collection`,params:{collection:`all`}})),q.success(`Deleted collection "${Za(t)}".`)}catch(e){q.error(e instanceof Error?e.message:`Unknown error`)}},[a,o,g,e]),b=(0,L.useCallback)(t=>{t===`/search`?e.navigate({to:`/search/$collection`,params:{collection:a}}):t===`/chat`?e.navigate({to:`/chat`,search:{}}):e.navigate({to:t}),_()},[e,_,a]),x=(0,L.useCallback)(()=>{e.navigate({to:`/chat`,search:{draft:Date.now().toString(36)}}),_()},[e,_]),S=(0,L.useCallback)(()=>{e.navigate({to:`/chat`,search:{private:Date.now().toString(36)}}),_()},[e,_]),C=(0,L.useCallback)(t=>{e.navigate({to:`/chat`,search:{thread:t}}),_()},[e,_]),w=(0,L.useCallback)(t=>{o(t),e.navigate({to:`/search/$collection`,params:{collection:t}}),_()},[o,e,_]);(0,L.useEffect)(()=>{let t=t=>{let n=t.target.tagName.toLowerCase(),i=n===`input`||n===`textarea`;if((t.metaKey||t.ctrlKey)&&t.key.toLowerCase()===`k`){t.preventDefault(),u(!l);return}if(t.key===`Escape`){l?u(!1):d?f(!1):r?e.history.back():s&&_();return}!i&&t.key===`/`&&(t.preventDefault(),document.querySelector(`.search-card input`)?.focus())};return window.addEventListener(`keydown`,t),()=>window.removeEventListener(`keydown`,t)},[l,d,r,u,f,e,s,_]);let T=n[n.length-1]?.pathname??`/search`,E=r||T.startsWith(`/search`)?`search`:T.split(`/`)[1]||`search`,D=n.find(e=>e.pathname===`/chat`)?.search,O=typeof D?.thread==`string`?D.thread:``;return(0,R.jsxs)(`div`,{className:`app`,"data-reading":r,"data-sidebar-open":s,children:[(0,R.jsx)(Ao,{view:E,setView:b,activeColl:a,setActiveColl:w,onNewChat:x,onNewPrivateChat:S,onOpenChat:C,activeChatId:O,onCmdK:()=>{u(!0),_()},onNewColl:()=>{f(!0),_()},onDeleteCollection:y,collections:m,stats:h}),(0,R.jsx)(`button`,{className:`sidebar-scrim`,onClick:_,"aria-label":`Close sidebar`,tabIndex:s?0:-1}),(0,R.jsx)(`div`,{className:`main`,children:(0,R.jsx)(ca,{})}),(0,R.jsx)(jo,{open:l,onClose:()=>u(!1),setView:b,onNewChat:x,setActiveColl:w,collections:m,stats:h,onNewColl:()=>{u(!1),f(!0)},onRefresh:()=>void v()}),d&&(0,R.jsx)(Mo,{open:!0,onClose:()=>f(!1),onCreated:e=>{w(e)}}),(0,R.jsx)(Fo,{}),(0,R.jsx)(Po,{})]})}var Lo={"google-ai-studio":{label:`Google AI Studio`,short:`AI Studio`,color:`var(--p-google)`},google:{label:`Google AI Studio`,short:`AI Studio`,color:`var(--p-google)`},openrouter:{label:`OpenRouter`,short:`OpenRouter`,color:`var(--p-openrouter)`},openai:{label:`ChatGPT`,short:`ChatGPT`,color:`var(--p-openai)`},anthropic:{label:`Claude`,short:`Claude`,color:`var(--p-claude)`},claude:{label:`Claude`,short:`Claude`,color:`var(--p-claude)`},"lm-studio":{label:`LM Studio`,short:`LM Studio`,color:`var(--p-lmstudio)`},grok:{label:`Grok`,short:`Grok`,color:`var(--p-grok)`},threadshelf:{label:`ThreadShelf`,short:`ThreadShelf`,color:`oklch(0.74 0.16 165)`}},Ro={label:`Unknown`,short:`—`,color:`var(--border-2)`},zo=e=>e?Lo[e]??Ro:Ro,Bo=[`paper chromatography household experiment`,`fact-checking workflow with citations`,`sauna rules and temperature`,`openrouter export json schema`,`ablation study sample size`,`polish translation tone register`];function Vo({onPick:e}){return(0,R.jsxs)(`div`,{className:`empty`,children:[(0,R.jsx)(`h3`,{children:`Ask your archive in plain language.`}),(0,R.jsx)(`p`,{children:`ThreadShelf runs locally — your queries embed on this machine and search a local LanceDB. Try a topic, a draft you half-remember, or the shape of an answer you're looking for.`}),(0,R.jsx)(`div`,{className:`examples`,children:Bo.map(t=>(0,R.jsxs)(`button`,{className:`example-chip`,onClick:()=>e(t),children:[W.spark,(0,R.jsx)(`span`,{children:t})]},t))})]})}function Ho(e,t){let n=G(t);if(!n)return e;try{return K(e,t).map((e,t)=>n.test(e)?(0,R.jsx)(`mark`,{children:e},t):e)}catch{return e}}function Uo({result:e,query:t,onClick:n,selected:r,onMoreLikeThis:i}){let{metadata:a}=e,o=a.role??`ai`,s={user:`user`,thinking:`reasoning`,ai:`response`}[o]??o,c=zo(a.provider),l=$a(a.model),u=ao(a.createdAt),d=e.distance==null?``:(1-e.distance).toFixed(3),f=e.distance==null?0:Math.round((1-e.distance)*100),p=(0,L.useMemo)(()=>Ho(e.document,t),[e.document,t]),m=a.title?.trim()||Qa(a.sourceFile);return(0,R.jsxs)(`button`,{className:`result`,"data-selected":r,"aria-selected":r,onClick:n,children:[(0,R.jsxs)(`div`,{className:`result-head`,children:[(0,R.jsx)(`span`,{className:`r-role`,"data-role":o,children:s}),(0,R.jsxs)(`span`,{className:`r-provider`,children:[(0,R.jsx)(`span`,{className:`pdot`,style:{background:c.color}}),(0,R.jsx)(`span`,{children:c.short})]}),a.createdInThreadShelf&&(0,R.jsx)(`span`,{className:`threadshelf-turn-badge`,children:`ThreadShelf`}),e.distance!=null&&(0,R.jsx)(`div`,{className:`r-meta-right`,children:(0,R.jsxs)(`span`,{className:`r-score`,children:[(0,R.jsx)(`span`,{className:`r-score-bar`,children:(0,R.jsx)(`i`,{style:{width:`${f}%`}})}),(0,R.jsx)(`span`,{children:d})]})})]}),(0,R.jsx)(`div`,{className:`r-title`,title:m,children:m}),(0,R.jsx)(`div`,{className:`r-snippet`,children:p}),(0,R.jsxs)(`div`,{className:`r-foot`,children:[(0,R.jsxs)(`span`,{className:`r-source`,title:a.sourceFile,children:[W.folder,(0,R.jsx)(`span`,{className:`r-source-coll`,children:Za(a.collection??``)}),(0,R.jsx)(`span`,{className:`slash`,children:`/`}),(0,R.jsx)(`span`,{className:`r-source-file`,children:Qa(a.sourceFile)})]}),(0,R.jsx)(`span`,{className:`dot`}),l&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`span`,{className:`mono`,children:l}),(0,R.jsx)(`span`,{className:`dot`})]}),u&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`span`,{children:u}),(0,R.jsx)(`span`,{className:`dot`})]}),a.turnIndex!=null&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsxs)(`span`,{children:[`turn `,(0,R.jsxs)(`b`,{className:`mono`,children:[`#`,a.turnIndex]})]}),(0,R.jsx)(`span`,{className:`dot`})]}),i&&(0,R.jsx)(`span`,{className:`more-like-this`,role:`button`,tabIndex:0,title:`Search for similar passages`,onClick:e=>{e.stopPropagation(),i()},onKeyDown:e=>{(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),e.stopPropagation(),i())},children:`more like this`}),(0,R.jsxs)(`span`,{className:`open-thread`,children:[`open thread `,W.arrowRight]})]})]})}var Wo={search:`Archive`,insights:`Insights`,indexing:`Add data`,mcp:`MCP`,settings:`Settings`,chat:`Chat`};function Go({view:e,activeColl:t,onMenu:n,actions:r}){return(0,R.jsxs)(`div`,{className:`topbar`,children:[(0,R.jsx)(`button`,{className:`icon-btn mobile-menu-btn`,onClick:n,"aria-label":`Open sidebar`,children:W.menu}),(0,R.jsxs)(`div`,{className:`crumbs`,children:[(0,R.jsx)(`span`,{children:Wo[e]}),e===`search`&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`span`,{className:`sep`,children:`/`}),(0,R.jsx)(`b`,{children:Za(t)})]})]}),(0,R.jsx)(`div`,{className:`topbar-spacer`}),r&&(0,R.jsx)(`div`,{className:`topbar-actions`,children:r})]})}var Ko=100,qo=e=>{switch(e){case`recent`:return(e,t)=>(t.lastTurnAt??``).localeCompare(e.lastTurnAt??``);case`longest`:return(e,t)=>(t.turnCount??0)-(e.turnCount??0);case`title`:return(e,t)=>(e.title||e.sourceFile).localeCompare(t.title||t.sourceFile,void 0,{sensitivity:`base`})}},Jo=[{id:`user`,label:`User`,key:`user`},{id:`reasoning`,label:`Reasoning`,key:`thinking`},{id:`response`,label:`Response`,key:`ai`}];function Yo(){return(0,R.jsx)(`div`,{className:`result-list`,style:{marginTop:16},children:[0,1,2].map(e=>(0,R.jsx)(`div`,{className:`shimmer-card`},e))})}function Xo(){let e=Ni(),{collection:t}=ji({from:`/search/$collection`}),{q:n,model:r,from:i,to:a,mode:o}=Mi({from:`/search/$collection`}),s=t?decodeURIComponent(t):`all`,c=B(e=>e.setActiveColl);(0,L.useEffect)(()=>{c(s)},[s,c]);let l=B(e=>e.roles),u=B(e=>e.toggleRole),d=B(e=>e.modelFilter),f=B(e=>e.setModelFilter),p=B(e=>e.setSidebarOpen),m=B(e=>e.savedSearches),h=B(e=>e.addSavedSearch),g=B(e=>e.removeSavedSearch),_=B(e=>e.pinnedConversations),v=B(e=>e.togglePinned),[y,b]=(0,L.useState)(n??``),[x,S]=(0,L.useState)(n??``),[C,w]=(0,L.useState)(i??``),[T,E]=(0,L.useState)(a??``),[D,O]=(0,L.useState)(o===`keyword`?`keyword`:`semantic`),[ee,te]=(0,L.useState)(15),[k,ne]=(0,L.useState)(-1),[re,ie]=(0,L.useState)(``),[A,j]=(0,L.useState)(`recent`),[M,ae]=(0,L.useState)(Ko),[oe,se]=(0,L.useState)(`all`),N=(0,L.useRef)(n??``),P=(0,L.useRef)(null),F=(0,L.useRef)(null),{data:ce}=Ra(),le=ce??!0,ue=(0,L.useMemo)(()=>{let e=[];return l.user&&e.push(`user`),l.thinking&&e.push(`thinking`),l.ai&&e.push(`ai`),e.length>0&&e.length<3?e.join(`,`):void 0},[l]),{data:de,isFetching:fe}=Ua((0,L.useMemo)(()=>({q:x.trim(),collection:s,n:ee,roles:ue,keywordBoost:D===`semantic`&&x.trim().length<=40,model:(r??d).trim()||void 0,from:C.trim()||void 0,to:T.trim()||void 0,mode:D,origin:oe===`all`?void 0:oe}),[x,s,ee,ue,r,d,C,T,D,oe])),{data:pe,isLoading:me}=Va(s,!x.trim()&&le),he=(0,L.useMemo)(()=>{let e=pe?.files??[],t=re.trim().toLowerCase();return[...(t?e.filter(e=>[e.title,e.sourceFile,e.conversationKey,e.collection].some(e=>(e??``).toLowerCase().includes(t))):e).filter(e=>oe===`threadshelf`?e.createdInThreadShelf===!0||e.hasThreadShelfTurns===!0:oe!==`archive`||e.hasThreadShelfTurns!==!0)].sort(qo(A))},[pe?.files,re,A,oe]),I=(0,L.useMemo)(()=>he.slice(0,M),[he,M]);(0,L.useEffect)(()=>{let e=window.setTimeout(()=>ae(Ko),0);return()=>window.clearTimeout(e)},[s,re,A,oe]),(0,L.useEffect)(()=>{P.current?.focus()},[]),(0,L.useEffect)(()=>{let e=n??``;if(e!==N.current){let t=window.setTimeout(()=>{N.current=e,b(e),S(e),w(i??``),E(a??``),O(o===`keyword`?`keyword`:`semantic`)},0);return()=>window.clearTimeout(t)}},[n,i,a,o]),(0,L.useEffect)(()=>{let e=window.setTimeout(()=>{w(i??``),E(a??``)},0);return()=>window.clearTimeout(e)},[i,a]),(0,L.useEffect)(()=>{let e=window.setTimeout(()=>te(15),0);return()=>window.clearTimeout(e)},[x,s,ue,r,d,C,T,D,oe]);let ge=(0,L.useCallback)(t=>{let n=y.trim(),r=t??D;N.current=n,S(n),e({to:`/search/$collection`,params:{collection:s},search:n?{q:n,model:d.trim()||void 0,from:C.trim()||void 0,to:T.trim()||void 0,mode:r===`keyword`?`keyword`:void 0}:{},replace:!0})},[y,d,C,T,e,s,D]),_e=(0,L.useCallback)(()=>{N.current=``,b(``),S(``),P.current?.focus(),e({to:`/search/$collection`,params:{collection:s},search:{},replace:!0})},[e,s]),ve=(0,L.useCallback)(e=>{O(e),ge(e)},[ge]),ye=(0,L.useCallback)(t=>{e({to:`/thread`,search:{sourceFile:t.metadata.sourceFile,collection:t.metadata.collection??s,conversationKey:t.metadata.conversationKey,q:x.trim()||void 0,title:t.metadata.title,matchIdx:t.metadata.turnIndex,provider:t.metadata.provider,model:t.metadata.model}})},[s,x,e]),be=(0,L.useCallback)(t=>{let n=lo(t.document);n&&(O(`semantic`),N.current=n,b(n),S(n),e({to:`/search/$collection`,params:{collection:s},search:{q:n,model:d.trim()||void 0,from:C.trim()||void 0,to:T.trim()||void 0}}))},[s,d,C,T,e]),xe=(0,L.useCallback)(t=>{e({to:`/thread`,search:{sourceFile:t.sourceFile,collection:t.collection,conversationKey:t.conversationKey,title:t.title}})},[e]),Se=x.trim().length>0,Ce=(0,L.useMemo)(()=>({q:x.trim(),collection:s,mode:D,model:(r??d).trim()||void 0,from:C.trim()||void 0,to:T.trim()||void 0}),[x,s,D,r,d,C,T]),we=(0,L.useMemo)(()=>{let e=ka(Ce);return m.find(t=>ka(t)===e)},[m,Ce]),Te=(0,L.useCallback)(()=>{we?g(we.id):h(Ce)},[we,g,h,Ce]),Ee=(0,L.useCallback)(t=>{O(t.mode),N.current=t.q,b(t.q),S(t.q),e({to:`/search/$collection`,params:{collection:t.collection},search:{q:t.q,model:t.model,from:t.from,to:t.to,mode:t.mode===`keyword`?`keyword`:void 0}})},[e]),De=(0,L.useMemo)(()=>s===`all`?_:_.filter(e=>e.collection===s),[_,s]),Oe=(0,L.useMemo)(()=>new Set(_.map(e=>Aa(e))),[_]),ke=e=>({collection:e.collection,sourceFile:e.sourceFile,conversationKey:e.conversationKey,title:e.title,provider:e.provider}),Ae=(0,L.useMemo)(()=>de?.results??[],[de?.results]),je=Se&&!fe&&Ae.length>=ee&&ee<50,Me=s===`all`?`Conversations`:`${Za(s)} conversations`,Ne=Se?Ae.length:I.length,Pe=(0,L.useCallback)(e=>{if(Se){let t=Ae[e];t&&ye(t)}else{let t=I[e];t&&xe(t)}},[Se,Ae,I,ye,xe]);return(0,L.useEffect)(()=>{let e=window.setTimeout(()=>ne(-1),0);return()=>window.clearTimeout(e)},[x,s,Se]),(0,L.useEffect)(()=>{let e=e=>{let t=e.target,n=t.tagName?.toLowerCase(),r=t===P.current;if((n===`input`||n===`textarea`)&&!r||Ne===0)return;let i=e.key===`ArrowDown`||e.key===`j`&&!r,a=e.key===`ArrowUp`||e.key===`k`&&!r;i?(e.preventDefault(),r&&P.current?.blur(),ne(e=>Math.min(Ne-1,e+1))):a?(e.preventDefault(),ne(e=>e<=0?0:e-1)):e.key===`Enter`&&!r&&k>=0&&(e.preventDefault(),Pe(k))};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[Ne,k,Pe]),(0,L.useEffect)(()=>{k<0||F.current?.querySelector(`[data-selected="true"]`)?.scrollIntoView({block:`nearest`})},[k]),(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(Go,{view:`search`,activeColl:s,onMenu:()=>p(!0)}),(0,R.jsx)(`div`,{className:`main-scroll`,children:(0,R.jsxs)(`div`,{className:`view`,children:[!le&&(0,R.jsxs)(`div`,{className:`banner err`,children:[(0,R.jsx)(`span`,{className:`ico`,children:W.warn}),(0,R.jsxs)(`div`,{className:`grow`,children:[(0,R.jsx)(`b`,{style:{fontWeight:500},children:`Backend unreachable.`}),` `,(0,R.jsxs)(`span`,{style:{color:`var(--text-2)`},children:[`Run `,(0,R.jsx)(`code`,{children:`npm start`}),` in the project root.`]})]})]}),(0,R.jsxs)(`div`,{className:`search-card`,children:[(0,R.jsx)(`span`,{className:`search-ico`,children:W.searchLg}),(0,R.jsx)(`input`,{id:`searchInput`,ref:P,value:y,onChange:e=>b(e.target.value),onKeyDown:e=>{e.key===`Enter`?ge():e.key===`Escape`&&y&&(e.preventDefault(),e.stopPropagation(),_e())},placeholder:D===`keyword`?`Exact match: identifiers, error strings, code…`:`Search by meaning across your archive…`}),y&&(0,R.jsx)(`button`,{id:`clearSearch`,type:`button`,className:`search-clear`,"aria-label":`Clear search`,title:`Clear search (Esc)`,onClick:_e,children:W.close})]}),(0,R.jsxs)(`div`,{className:`search-toolbar`,children:[(0,R.jsxs)(`div`,{className:`mode-toggle`,role:`group`,"aria-label":`Search mode`,children:[(0,R.jsx)(`button`,{type:`button`,className:`mode-btn`,"data-on":D===`semantic`,title:`Rank by meaning (local embeddings)`,onClick:()=>ve(`semantic`),children:`Semantic`}),(0,R.jsx)(`button`,{type:`button`,className:`mode-btn`,"data-on":D===`keyword`,title:`Exact substring match (case-insensitive)`,onClick:()=>ve(`keyword`),children:`Exact`})]}),(0,R.jsx)(`div`,{className:`role-chips`,children:Jo.map(e=>(0,R.jsxs)(`button`,{className:`role-chip`,"data-role":e.id,"data-on":l[e.key],onClick:()=>u(e.key),children:[(0,R.jsx)(`span`,{className:`dot`}),e.label]},e.id))}),(0,R.jsxs)(`label`,{className:`origin-filter`,children:[(0,R.jsx)(`span`,{children:`origin`}),(0,R.jsxs)(`select`,{"aria-label":`Filter by conversation origin`,value:oe,onChange:e=>se(e.target.value),children:[(0,R.jsx)(`option`,{value:`all`,children:`All`}),(0,R.jsx)(`option`,{value:`threadshelf`,children:`ThreadShelf`}),(0,R.jsx)(`option`,{value:`archive`,children:`Clean archive`})]})]}),(0,R.jsxs)(`label`,{className:`model-filter`,children:[(0,R.jsx)(`span`,{children:`model`}),(0,R.jsx)(`input`,{value:d,onChange:e=>f(e.target.value),onKeyDown:e=>e.key===`Enter`&&ge(),placeholder:`gpt-5, claude, gemini...`})]}),(0,R.jsxs)(`label`,{className:`date-filter`,children:[(0,R.jsx)(`span`,{children:`from`}),(0,R.jsx)(`input`,{type:`date`,value:C,onChange:e=>w(e.target.value),onKeyDown:e=>e.key===`Enter`&&ge()})]}),(0,R.jsxs)(`label`,{className:`date-filter`,children:[(0,R.jsx)(`span`,{children:`to`}),(0,R.jsx)(`input`,{type:`date`,value:T,onChange:e=>E(e.target.value),onKeyDown:e=>e.key===`Enter`&&ge()})]}),(0,R.jsx)(`span`,{className:`toolbar-spacer`}),(0,R.jsxs)(`span`,{className:`toolbar-hint`,children:[(0,R.jsx)(`kbd`,{children:`/`}),` focus · `,(0,R.jsx)(`kbd`,{children:`↑↓`}),` navigate · `,(0,R.jsx)(`kbd`,{children:`↵`}),` open · `,(0,R.jsx)(`kbd`,{children:`Ctrl+K`}),` `,`commands`]})]}),!Se&&(0,R.jsxs)(R.Fragment,{children:[s===`all`&&(0,R.jsx)(Vo,{onPick:t=>{N.current=t,b(t),S(t),e({to:`/search/$collection`,params:{collection:s},search:{q:t},replace:!0})}}),m.length>0&&(0,R.jsxs)(`div`,{className:`saved-searches`,children:[(0,R.jsxs)(`span`,{className:`ss-label`,children:[W.star,` Saved`]}),m.map(e=>(0,R.jsxs)(`span`,{className:`ss-chip`,children:[(0,R.jsxs)(`button`,{type:`button`,className:`ss-run`,title:`Run: ${e.q}`,onClick:()=>Ee(e),children:[(0,R.jsx)(`span`,{className:`ss-q`,children:e.q}),e.collection!==`all`&&(0,R.jsx)(`span`,{className:`ss-tag`,children:Za(e.collection)}),e.mode===`keyword`&&(0,R.jsx)(`span`,{className:`ss-tag`,children:`exact`})]}),(0,R.jsx)(`button`,{type:`button`,className:`ss-del`,"aria-label":`Delete saved search "${e.q}"`,onClick:()=>g(e.id),children:`×`})]},e.id))]}),De.length>0&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`div`,{className:`results-meta-bar`,children:(0,R.jsxs)(`span`,{className:`h`,children:[`Pinned `,(0,R.jsx)(`b`,{children:De.length})]})}),(0,R.jsx)(`div`,{className:`result-list`,children:De.map(e=>{let t=e.provider?zo(e.provider):null,n=Qa(e.sourceFile);return(0,R.jsxs)(`button`,{className:`result`,onClick:()=>xe(e),children:[(0,R.jsxs)(`div`,{className:`result-head`,children:[(0,R.jsx)(`span`,{className:`r-role`,"data-role":`user`,children:`pinned`}),(0,R.jsxs)(`span`,{className:`r-provider`,children:[(0,R.jsx)(`span`,{className:`pdot`,style:{background:t?.color??`var(--accent)`}}),(0,R.jsx)(`span`,{children:t?.short??Za(e.collection)})]}),(0,R.jsx)(`span`,{className:`pin-toggle`,role:`button`,tabIndex:0,"data-on":`true`,title:`Unpin`,onClick:t=>{t.stopPropagation(),v(e)},onKeyDown:t=>{(t.key===`Enter`||t.key===` `)&&(t.preventDefault(),t.stopPropagation(),v(e))},children:W.pinFilled})]}),(0,R.jsx)(`div`,{className:`r-title`,title:e.title||n,children:e.title||n}),(0,R.jsxs)(`div`,{className:`r-foot`,children:[(0,R.jsxs)(`span`,{className:`r-source`,title:e.sourceFile,children:[W.folder,(0,R.jsx)(`span`,{className:`r-source-coll`,children:Za(e.collection)}),(0,R.jsx)(`span`,{className:`slash`,children:`/`}),(0,R.jsx)(`span`,{className:`r-source-file`,children:n})]}),(0,R.jsxs)(`span`,{className:`open-thread`,children:[`open thread `,W.arrowRight]})]})]},Aa(e))})})]}),(0,R.jsxs)(`div`,{className:`results-meta-bar`,children:[(0,R.jsxs)(`span`,{className:`h`,children:[Me,` `,(0,R.jsx)(`b`,{children:he.length})]}),(0,R.jsxs)(`label`,{className:`conv-sort`,children:[(0,R.jsx)(`span`,{children:`sort`}),(0,R.jsxs)(`select`,{value:A,onChange:e=>j(e.target.value),"aria-label":`Sort conversations`,children:[(0,R.jsx)(`option`,{value:`recent`,children:`Recent`}),(0,R.jsx)(`option`,{value:`longest`,children:`Longest`}),(0,R.jsx)(`option`,{value:`title`,children:`Title`})]})]}),(0,R.jsx)(`input`,{className:`conv-filter`,value:re,onChange:e=>ie(e.target.value),placeholder:`Filter by title or file…`,"aria-label":`Filter conversations`})]}),me?(0,R.jsx)(Yo,{}):he.length>0?(0,R.jsxs)(`div`,{className:`result-list`,ref:F,children:[I.map((e,t)=>{let n=Qa(e.sourceFile),r=e.title||n,i=e.provider?zo(e.provider):null,a=ao(e.lastTurnAt),o=ke(e),s=Oe.has(Aa(o));return(0,R.jsxs)(`button`,{className:`result`,"data-selected":t===k,"aria-selected":t===k,onClick:()=>xe(e),children:[(0,R.jsxs)(`div`,{className:`result-head`,children:[(0,R.jsx)(`span`,{className:`r-role`,"data-role":`ai`,children:`thread`}),e.hasThreadShelfTurns&&(0,R.jsx)(`span`,{className:`threadshelf-turn-badge`,children:e.createdInThreadShelf?`Created in ThreadShelf`:`Continued in ThreadShelf`}),(0,R.jsxs)(`span`,{className:`r-provider`,children:[(0,R.jsx)(`span`,{className:`pdot`,style:{background:i?.color??`var(--accent)`}}),(0,R.jsx)(`span`,{children:i?.short??Za(e.collection)})]}),(0,R.jsx)(`span`,{className:`pin-toggle`,role:`button`,tabIndex:0,"data-on":s,title:s?`Unpin`:`Pin conversation`,onClick:e=>{e.stopPropagation(),v(o)},onKeyDown:e=>{(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),e.stopPropagation(),v(o))},children:s?W.pinFilled:W.pin})]}),(0,R.jsx)(`div`,{className:`r-title`,title:r,children:r}),(0,R.jsxs)(`div`,{className:`r-foot`,children:[(0,R.jsxs)(`span`,{className:`r-source`,title:e.sourceFile,children:[W.folder,(0,R.jsx)(`span`,{className:`r-source-coll`,children:Za(e.collection)}),(0,R.jsx)(`span`,{className:`slash`,children:`/`}),(0,R.jsx)(`span`,{className:`r-source-file`,children:n})]}),e.turnCount!=null&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`span`,{className:`dot`}),(0,R.jsxs)(`span`,{children:[e.turnCount,` turns`]})]}),a&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`span`,{className:`dot`}),(0,R.jsx)(`span`,{children:a})]}),(0,R.jsxs)(`span`,{className:`open-thread`,children:[`open thread `,W.arrowRight]})]})]},`${e.collection}:${e.sourceFile}:${t}`)}),he.length>M&&(0,R.jsx)(`div`,{className:`load-more-row`,children:(0,R.jsxs)(`button`,{type:`button`,className:`load-more-button`,onClick:()=>ae(e=>e+Ko),children:[`Show more (`,he.length-M,` left)`]})})]}):re.trim()?(0,R.jsxs)(`div`,{className:`empty`,children:[(0,R.jsx)(`h3`,{children:`No conversations match the filter.`}),(0,R.jsx)(`p`,{children:`Try a different phrase or clear the filter box.`})]}):s===`all`?null:(0,R.jsxs)(`div`,{className:`empty`,children:[(0,R.jsx)(`h3`,{children:`No conversations indexed.`}),(0,R.jsx)(`p`,{children:`Index a folder into this collection or switch to another collection.`})]})]}),Se&&fe&&(0,R.jsx)(Yo,{}),Se&&!fe&&Ae.length===0&&(0,R.jsxs)(`div`,{className:`empty`,children:[(0,R.jsx)(`h3`,{children:`No results found.`}),(0,R.jsx)(`p`,{children:`Try another query, broaden your role filters, or index more files.`})]}),Se&&!fe&&Ae.length>0&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsxs)(`div`,{className:`results-meta-bar`,children:[(0,R.jsxs)(`span`,{className:`h`,children:[`Results `,(0,R.jsx)(`b`,{children:Ae.length}),(0,R.jsxs)(`span`,{style:{marginLeft:14,color:`var(--text-3)`},children:[`in `,Za(s)]})]}),(0,R.jsxs)(`button`,{type:`button`,className:`save-search`,"data-on":!!we,title:we?`Remove from saved searches`:`Save this search`,onClick:Te,children:[we?W.starFilled:W.star,(0,R.jsx)(`span`,{children:we?`Saved`:`Save search`})]})]}),(0,R.jsx)(`div`,{className:`result-list`,ref:F,children:Ae.map((e,t)=>(0,R.jsx)(Uo,{result:e,query:x,selected:t===k,onClick:()=>ye(e),onMoreLikeThis:()=>be(e)},t))}),je&&(0,R.jsx)(`div`,{className:`load-more-row`,children:(0,R.jsx)(`button`,{type:`button`,className:`load-more-button`,onClick:()=>te(e=>Math.min(e+15,50)),children:`Load more`})})]})]})})]})}var Zo=/^(\s*)([-*+]|\d+[.)])\s+(.*)$/,Qo=/^\s*\d+[.)]\s+/,$o=e=>{let t=e.trim();return/^(?:https?:\/\/|mailto:|#|\/)/i.test(t)?t:null},es=e=>{let t=[],n=``,r=()=>{n&&=(t.push({type:`text`,value:n}),``)},i=0;for(;i<e.length;){let a=e[i];if(a==="`"){let n=e.indexOf("`",i+1);if(n>i){r(),t.push({type:`code`,value:e.slice(i+1,n)}),i=n+1;continue}}if(a===`[`){let n=e.indexOf(`]`,i+1);if(n>i&&e[n+1]===`(`){let a=e.indexOf(`)`,n+2);if(a>n){let o=$o(e.slice(n+2,a));if(o){r(),t.push({type:`link`,href:o,children:es(e.slice(i+1,n))}),i=a+1;continue}}}}if(a===`*`&&e[i+1]===`*`||a===`_`&&e[i+1]===`_`){let n=e.slice(i,i+2),a=e.indexOf(n,i+2);if(a>i+1){r(),t.push({type:`strong`,children:es(e.slice(i+2,a))}),i=a+2;continue}}if(a===`*`){let n=e.indexOf(`*`,i+1);if(n>i+1){r(),t.push({type:`em`,children:es(e.slice(i+1,n))}),i=n+1;continue}}n+=a,i+=1}return r(),t},ts=e=>{let t=e.replace(/\r\n?/g,`
|
|
17
|
+
`);return(0,R.jsxs)(`div`,{className:`global-runtime`,"data-state":t?.state||`unknown`,title:t?.detail,children:[(0,R.jsx)(`span`,{className:`runtime-dot`,"aria-hidden":`true`}),(0,R.jsxs)(`span`,{className:`global-runtime-copy`,children:[(0,R.jsxs)(`b`,{children:[(0,R.jsx)(`span`,{children:t?.state===`starting`?`llama.cpp · loading`:`llama.cpp`}),(0,R.jsx)(`em`,{children:d}),(0,R.jsx)(`span`,{className:`runtime-install-help`,tabIndex:0,role:`img`,"aria-label":`llama.cpp CPU and GPU install commands`,title:f,children:`?`})]}),(0,R.jsx)(`span`,{children:t?.model?Eo(t.model):t?`no model loaded`:`status unavailable`}),e&&t?.detail&&(0,R.jsx)(`small`,{children:t.detail}),e&&h&&(0,R.jsx)(`small`,{className:`runtime-profile`,title:g||void 0,children:h})]}),l&&(0,R.jsx)(`button`,{type:`button`,disabled:a,onClick:()=>void c(),children:a?`…`:`Eject`})]})}var Oo=[{id:`/search`,viewKey:`search`,label:`Search archive`,icon:W.search},{id:`/insights`,viewKey:`insights`,label:`Insights`,icon:W.chart}],ko=[{id:`/indexing`,viewKey:`indexing`,label:`Add data`,icon:W.download},{id:`/mcp`,viewKey:`mcp`,label:`MCP`,icon:W.plug},{id:`/settings`,viewKey:`settings`,label:`Settings`,icon:W.settings}];function Ao({view:e,setView:t,activeColl:n,setActiveColl:r,onNewChat:i,onNewPrivateChat:a,onOpenChat:o,activeChatId:s,onCmdK:c,onNewColl:l,onDeleteCollection:u,collections:d,stats:f}){let[p,m]=(0,L.useState)(!1),[h,g]=(0,L.useState)(e===`chat`),{data:_,isLoading:v,refetch:y}=Ha(),b=_?.threads??[],x=d.filter(e=>e!==`all`),S=x.reduce((e,t)=>e+(f[t]?.files??0),0),C=x.reduce((e,t)=>e+(f[t]?.chunks??0),0),w=e=>{let t=f[e];return(t?.chunks??0)===0&&(t?.files??0)===0&&(t?.conversations??0)===0},T=x.filter(e=>w(e)&&e!==n),E=x.filter(e=>p||!w(e)||e===n),D=e=>{let t=e?.conversations??0;return t>0?`${t.toLocaleString()} thread${t===1?``:`s`}`:`${(e?.files??0).toLocaleString()} files`},O=e=>{let t=e?.conversations??0;return`${t>0?`${t.toLocaleString()} conversation${t===1?``:`s`}`:`${(e?.files??0).toLocaleString()} files`} · ${(e?.chunks??0).toLocaleString()} indexed chunks`};return(0,R.jsxs)(`aside`,{className:`sidebar`,children:[(0,R.jsxs)(`div`,{className:`sb-brand`,children:[(0,R.jsx)(`div`,{className:`sb-logo`,"aria-hidden":`true`}),(0,R.jsxs)(`div`,{className:`sb-name`,children:[(0,R.jsx)(`b`,{children:`ThreadShelf`}),(0,R.jsxs)(`span`,{children:[`v`,`1.2.2`,` · local`]})]})]}),(0,R.jsxs)(`section`,{className:`sb-chat-panel`,"aria-label":`Conversations`,children:[(0,R.jsxs)(`div`,{className:`sb-chat-create`,children:[(0,R.jsxs)(`button`,{id:`sidebarNewChatButton`,className:`sb-new-chat`,onClick:i,children:[W.spark,(0,R.jsx)(`span`,{children:`New chat`})]}),(0,R.jsx)(`button`,{id:`sidebarPrivateChatButton`,className:`sb-private-chat`,"aria-label":`Start private conversation`,title:`Start a private chat that is cleared with this tab`,onClick:a,children:W.ghost})]}),(0,R.jsxs)(`div`,{className:`sb-chat-history`,children:[(0,R.jsxs)(`button`,{id:`sidebarChatHistoryToggle`,className:`sb-chat-history-toggle`,"aria-expanded":h,onClick:()=>{let e=!h;g(e),e&&y()},children:[(0,R.jsx)(`span`,{className:`ico`,children:W.chat}),(0,R.jsx)(`span`,{className:`label`,children:`Your chats`}),b.length>0&&(0,R.jsx)(`em`,{children:b.length}),(0,R.jsx)(`span`,{className:`sb-chat-chevron`,"aria-hidden":`true`,children:`▾`})]}),h&&(0,R.jsxs)(`div`,{className:`sb-chat-history-list`,children:[v&&(0,R.jsx)(`span`,{className:`sb-chat-history-empty`,children:`Loading chats…`}),!v&&b.length===0&&(0,R.jsx)(`span`,{className:`sb-chat-history-empty`,children:`No saved chats yet.`}),b.map(e=>(0,R.jsxs)(`button`,{className:`sb-chat-item`,"data-active":e.id===s,title:e.title,onClick:()=>o(e.id),children:[(0,R.jsx)(`strong`,{children:e.title}),(0,R.jsx)(`span`,{title:`${e.model?`${no(e.model)} · `:``}${e.turnCount} messages`,children:oo(e.updatedAt)||`just now`})]},e.id))]})]})]}),(0,R.jsxs)(`button`,{className:`sb-cmdk`,onClick:c,children:[W.search,(0,R.jsx)(`span`,{children:`Quick jump…`}),(0,R.jsx)(`kbd`,{children:`Ctrl+K`})]}),(0,R.jsx)(`div`,{className:`sb-section`,children:(0,R.jsx)(`span`,{children:`Library`})}),(0,R.jsx)(`nav`,{className:`sb-list`,style:{flex:`0 0 auto`},children:Oo.map(n=>(0,R.jsxs)(`button`,{id:n.viewKey===`indexing`?`indexingNavBtn`:void 0,className:`sb-item`,"data-active":e===n.viewKey,onClick:()=>t(n.id),children:[(0,R.jsx)(`span`,{className:`ico`,children:n.icon}),(0,R.jsx)(`span`,{className:`label`,children:n.label})]},n.id))}),(0,R.jsxs)(`div`,{className:`sb-section`,children:[(0,R.jsx)(`span`,{children:`Archive collections`}),(0,R.jsx)(`button`,{title:`New collection`,onClick:l,children:W.plus})]}),(0,R.jsxs)(`div`,{className:`sb-list sb-collections`,children:[(0,R.jsxs)(`button`,{id:`collection-all`,className:`sb-coll`,"data-active":n===`all`,onClick:()=>r(`all`),children:[(0,R.jsx)(`span`,{className:`sb-coll-dot`,style:{background:`var(--accent)`}}),(0,R.jsxs)(`span`,{className:`sb-coll-meta`,children:[(0,R.jsx)(`b`,{children:`All collections`}),(0,R.jsxs)(`span`,{children:[S,` files · `,C.toLocaleString(),` chunks`]})]})]}),E.map(e=>{let t=f[e];return(0,R.jsxs)(`div`,{className:`sb-coll-row`,children:[(0,R.jsxs)(`button`,{id:`collection-${e}`,className:`sb-coll`,"data-active":n===e,onClick:()=>r(e),children:[(0,R.jsx)(`span`,{className:`sb-coll-dot`}),(0,R.jsxs)(`span`,{className:`sb-coll-meta`,children:[(0,R.jsx)(`b`,{children:Za(e)}),(0,R.jsxs)(`span`,{title:O(t),children:[D(t),` · `,(t?.chunks??0).toLocaleString(),` chunks`]})]})]}),e!==`chunks`&&e!==`threadshelf_conversations`&&(0,R.jsx)(`button`,{id:`delete-collection-${e}`,className:`sb-coll-delete`,title:`Delete ${Za(e)}`,"aria-label":`Delete ${Za(e)}`,onClick:t=>{t.stopPropagation(),u(e)},children:W.trash})]},e)}),T.length>0&&(0,R.jsx)(`button`,{id:`toggleEmptyCollections`,className:`sb-coll-empty-toggle`,onClick:()=>m(e=>!e),children:p?`Hide empty collections`:`Show ${T.length} empty`})]}),(0,R.jsx)(`div`,{className:`sb-section sb-manage-section`,children:(0,R.jsx)(`span`,{children:`Manage`})}),(0,R.jsx)(`nav`,{className:`sb-list sb-manage-list`,children:ko.map(n=>(0,R.jsxs)(`button`,{id:n.viewKey===`indexing`?`indexingNavBtn`:void 0,className:`sb-item`,"data-active":e===n.viewKey,onClick:()=>t(n.id),children:[(0,R.jsx)(`span`,{className:`ico`,children:n.icon}),(0,R.jsx)(`span`,{className:`label`,children:n.label})]},n.id))}),(0,R.jsxs)(`div`,{className:`sb-footer`,children:[(0,R.jsx)(Do,{}),(0,R.jsxs)(`div`,{className:`sb-footer-row`,children:[(0,R.jsxs)(`span`,{className:`sb-status`,title:`Local backend · paraphrase-multilingual embeddings · LanceDB storage. Model runtime and eject live in the chat model menu.`,children:[`local · :`,window.location.port||`80`]}),(0,R.jsx)(xo,{variant:`icon`})]})]})]})}function jo({open:e,onClose:t,setView:n,onNewChat:r,setActiveColl:i,collections:a,stats:o,onNewColl:s,onRefresh:c}){let[l,u]=(0,L.useState)(``),[d,f]=(0,L.useState)(0),p=(0,L.useRef)(null);if((0,L.useEffect)(()=>{if(e){let e=window.setTimeout(()=>{u(``),f(0),p.current?.focus()},30);return()=>window.clearTimeout(e)}},[e]),!e)return null;let m=[{label:`Go to`,items:[{id:`go-search`,label:`Search archive`,icon:W.search,action:()=>n(`/search`)},{id:`go-chat`,label:`Chat history`,icon:W.chat,action:()=>n(`/chat`)},{id:`go-insights`,label:`Insights`,icon:W.chart,action:()=>n(`/insights`)},{id:`go-indexing`,label:`Indexing`,icon:W.download,action:()=>n(`/indexing`)},{id:`go-mcp`,label:`MCP`,icon:W.plug,action:()=>n(`/mcp`)},{id:`go-settings`,label:`Settings`,icon:W.settings,action:()=>n(`/settings`)}]},{label:`Collections`,items:[{id:`coll-all`,label:`All collections`,icon:W.scope,action:()=>i(`all`)},...a.filter(e=>e!==`all`).map(e=>({id:`coll-${e}`,label:Za(e),icon:W.database,meta:`${o[e]?.files??0} files`,action:()=>i(e)}))]},{label:`Actions`,items:[{id:`a-chat`,label:`New chat`,icon:W.spark,action:r},{id:`a-new`,label:`New collection…`,icon:W.plus,action:s},{id:`a-index`,label:`Index a folder`,icon:W.folder,action:()=>n(`/indexing`)},{id:`a-refresh`,label:`Refresh stats`,icon:W.refresh,action:c}]}].map(e=>({...e,items:e.items.filter(e=>!l||e.label.toLowerCase().includes(l.toLowerCase()))})).filter(e=>e.items.length>0),h=m.flatMap(e=>e.items),g=Math.min(d,h.length-1),_=e=>{e.key===`ArrowDown`?(e.preventDefault(),f(e=>(e+1)%Math.max(1,h.length))):e.key===`ArrowUp`?(e.preventDefault(),f(e=>(e-1+h.length)%Math.max(1,h.length))):e.key===`Enter`?(e.preventDefault(),h[g]?.action(),t()):e.key===`Escape`&&t()},v=0;return(0,R.jsx)(`div`,{className:`scrim`,onClick:t,children:(0,R.jsxs)(`div`,{className:`cmdk`,onClick:e=>e.stopPropagation(),children:[(0,R.jsxs)(`div`,{className:`cmdk-input`,children:[W.searchLg,(0,R.jsx)(`input`,{ref:p,value:l,onChange:e=>{u(e.target.value),f(0)},onKeyDown:_,placeholder:`Search commands, collections, or actions…`}),(0,R.jsx)(`kbd`,{children:`ESC`})]}),(0,R.jsxs)(`div`,{className:`cmdk-list`,children:[m.map(e=>(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`cmdk-group-h`,children:e.label}),e.items.map(e=>{let n=v++;return(0,R.jsxs)(`button`,{className:`cmdk-item`,"data-active":n===g,onMouseEnter:()=>f(n),onClick:()=>{e.action(),t()},children:[(0,R.jsx)(`span`,{className:`ico`,children:e.icon}),(0,R.jsx)(`span`,{children:e.label}),e.meta&&(0,R.jsx)(`span`,{className:`meta`,children:e.meta})]},e.id)})]},e.label)),h.length===0&&(0,R.jsx)(`div`,{style:{padding:24,textAlign:`center`,color:`var(--text-3)`,fontSize:12},children:`No matches`})]})]})})}function Mo({open:e,onClose:t,onCreated:n}){let[r,i]=(0,L.useState)(``),a=Ya(),o=(0,L.useCallback)(async()=>{if(r)try{let e=await a.mutateAsync(r);i(``),t(),n(e.collection??r),q.success(`Created collection "${e.collection??r}".`)}catch(e){q.error(e instanceof Error?e.message:`Unknown error`)}},[r,t,n,a]);return e?(0,R.jsx)(`div`,{className:`scrim`,onClick:t,children:(0,R.jsxs)(`div`,{className:`modal-card`,onClick:e=>e.stopPropagation(),children:[(0,R.jsxs)(`div`,{className:`modal-head`,children:[(0,R.jsx)(`h3`,{children:`New collection`}),(0,R.jsx)(`p`,{children:`Collections are local LanceDB tables. Use lowercase, alphanumeric, hyphens, underscores.`})]}),(0,R.jsxs)(`div`,{className:`modal-body`,children:[(0,R.jsx)(`label`,{children:`Name`}),(0,R.jsx)(`input`,{autoFocus:!0,value:r,onChange:e=>i(e.target.value.replace(/[^a-z0-9_-]/g,``).toLowerCase()),onKeyDown:e=>e.key===`Enter`&&r&&void o(),placeholder:`my-archive`})]}),(0,R.jsxs)(`div`,{className:`modal-foot`,children:[(0,R.jsx)(`button`,{className:`btn ghost`,onClick:t,children:`Cancel`}),(0,R.jsx)(`button`,{className:`btn primary`,onClick:()=>void o(),disabled:!r,children:`Create`})]})]})}):null}var No={info:W.info,success:W.check,error:W.warn};function Po(){let e=wo(e=>e.toasts),t=wo(e=>e.dismissToast);return e.length===0?null:(0,R.jsx)(`div`,{className:`toaster`,role:`status`,"aria-live":`polite`,children:e.map(e=>(0,R.jsxs)(`button`,{className:`toast`,"data-type":e.type,onClick:()=>t(e.id),title:`Dismiss`,children:[(0,R.jsx)(`span`,{className:`toast-ico`,children:No[e.type]}),(0,R.jsx)(`span`,{className:`toast-text`,children:e.text})]},e.id))})}function Fo(){let e=wo(e=>e.confirmState),t=wo(e=>e.resolveConfirm);if((0,L.useEffect)(()=>{if(!e)return;let n=e=>{e.key===`Escape`&&(e.preventDefault(),e.stopPropagation(),t(!1))};return window.addEventListener(`keydown`,n,!0),()=>window.removeEventListener(`keydown`,n,!0)},[e,t]),!e)return null;let{title:n,message:r,confirmLabel:i,cancelLabel:a,danger:o}=e;return(0,R.jsx)(`div`,{className:`scrim`,onClick:()=>t(!1),children:(0,R.jsxs)(`div`,{className:`modal-card`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-modal":`true`,children:[(0,R.jsxs)(`div`,{className:`modal-head`,children:[(0,R.jsx)(`h3`,{children:n}),r&&(0,R.jsx)(`p`,{children:r})]}),(0,R.jsxs)(`div`,{className:`modal-foot`,children:[(0,R.jsx)(`button`,{className:`btn ghost`,onClick:()=>t(!1),children:a??`Cancel`}),(0,R.jsx)(`button`,{className:`btn ${o?`danger`:`primary`}`,onClick:()=>t(!0),autoFocus:!0,children:i??`Confirm`})]})]})})}function Io(){let e=Qr(),t=Ke(),n=fa(),r=n.some(e=>e.pathname===`/thread`),i=B(e=>e.theme),a=B(e=>e.activeColl),o=B(e=>e.setActiveColl),s=B(e=>e.sidebarOpen),c=B(e=>e.setSidebarOpen),l=B(e=>e.cmdkOpen),u=B(e=>e.setCmdkOpen),d=B(e=>e.newCollOpen),f=B(e=>e.setNewCollOpen),{data:p}=za(),m=p?.collections??[`all`,`chunks`],h=p?.stats??{},g=qa(),_=(0,L.useCallback)(()=>c(!1),[c]),v=(0,L.useCallback)(async()=>{await Promise.all([t.invalidateQueries({queryKey:[`collections`]}),t.invalidateQueries({queryKey:[`files`]}),t.invalidateQueries({queryKey:[`search`]}),t.invalidateQueries({queryKey:[`thread`]})]),q.success(`Local index data refreshed.`)},[t]);(0,L.useEffect)(()=>{document.documentElement.dataset.theme=i},[i]);let y=(0,L.useCallback)(async t=>{if(t!==`chunks`&&t!==`threadshelf_conversations`&&await To({title:`Delete collection "${Za(t)}"?`,message:`The index and copies previously uploaded through ThreadShelf are deleted. Files in the original folder you selected remain untouched.`,confirmLabel:`Delete`,danger:!0}))try{await g.mutateAsync(t),a===t&&(o(`all`),e.navigate({to:`/search/$collection`,params:{collection:`all`}})),q.success(`Deleted collection "${Za(t)}".`)}catch(e){q.error(e instanceof Error?e.message:`Unknown error`)}},[a,o,g,e]),b=(0,L.useCallback)(t=>{t===`/search`?e.navigate({to:`/search/$collection`,params:{collection:a}}):t===`/chat`?e.navigate({to:`/chat`,search:{}}):e.navigate({to:t}),_()},[e,_,a]),x=(0,L.useCallback)(()=>{e.navigate({to:`/chat`,search:{draft:Date.now().toString(36)}}),_()},[e,_]),S=(0,L.useCallback)(()=>{e.navigate({to:`/chat`,search:{private:Date.now().toString(36)}}),_()},[e,_]),C=(0,L.useCallback)(t=>{e.navigate({to:`/chat`,search:{thread:t}}),_()},[e,_]),w=(0,L.useCallback)(t=>{o(t),e.navigate({to:`/search/$collection`,params:{collection:t}}),_()},[o,e,_]);(0,L.useEffect)(()=>{let t=t=>{let n=t.target.tagName.toLowerCase(),i=n===`input`||n===`textarea`;if((t.metaKey||t.ctrlKey)&&t.key.toLowerCase()===`k`){t.preventDefault(),u(!l);return}if(t.key===`Escape`){l?u(!1):d?f(!1):r?e.history.back():s&&_();return}!i&&t.key===`/`&&(t.preventDefault(),document.querySelector(`.search-card input`)?.focus())};return window.addEventListener(`keydown`,t),()=>window.removeEventListener(`keydown`,t)},[l,d,r,u,f,e,s,_]);let T=n[n.length-1]?.pathname??`/search`,E=r||T.startsWith(`/search`)?`search`:T.split(`/`)[1]||`search`,D=n.find(e=>e.pathname===`/chat`)?.search,O=typeof D?.thread==`string`?D.thread:``;return(0,R.jsxs)(`div`,{className:`app`,"data-reading":r,"data-sidebar-open":s,children:[(0,R.jsx)(Ao,{view:E,setView:b,activeColl:a,setActiveColl:w,onNewChat:x,onNewPrivateChat:S,onOpenChat:C,activeChatId:O,onCmdK:()=>{u(!0),_()},onNewColl:()=>{f(!0),_()},onDeleteCollection:y,collections:m,stats:h}),(0,R.jsx)(`button`,{className:`sidebar-scrim`,onClick:_,"aria-label":`Close sidebar`,tabIndex:s?0:-1}),(0,R.jsx)(`div`,{className:`main`,children:(0,R.jsx)(ca,{})}),(0,R.jsx)(jo,{open:l,onClose:()=>u(!1),setView:b,onNewChat:x,setActiveColl:w,collections:m,stats:h,onNewColl:()=>{u(!1),f(!0)},onRefresh:()=>void v()}),d&&(0,R.jsx)(Mo,{open:!0,onClose:()=>f(!1),onCreated:e=>{w(e)}}),(0,R.jsx)(Fo,{}),(0,R.jsx)(Po,{})]})}var Lo={"google-ai-studio":{label:`Google AI Studio`,short:`AI Studio`,color:`var(--p-google)`},google:{label:`Google AI Studio`,short:`AI Studio`,color:`var(--p-google)`},openrouter:{label:`OpenRouter`,short:`OpenRouter`,color:`var(--p-openrouter)`},openai:{label:`ChatGPT`,short:`ChatGPT`,color:`var(--p-openai)`},anthropic:{label:`Claude`,short:`Claude`,color:`var(--p-claude)`},claude:{label:`Claude`,short:`Claude`,color:`var(--p-claude)`},"lm-studio":{label:`LM Studio`,short:`LM Studio`,color:`var(--p-lmstudio)`},grok:{label:`Grok`,short:`Grok`,color:`var(--p-grok)`},threadshelf:{label:`ThreadShelf`,short:`ThreadShelf`,color:`oklch(0.74 0.16 165)`}},Ro={label:`Unknown`,short:`—`,color:`var(--border-2)`},zo=e=>e?Lo[e]??Ro:Ro,Bo=[`paper chromatography household experiment`,`fact-checking workflow with citations`,`sauna rules and temperature`,`openrouter export json schema`,`ablation study sample size`,`polish translation tone register`];function Vo({onPick:e}){return(0,R.jsxs)(`div`,{className:`empty`,children:[(0,R.jsx)(`h3`,{children:`Ask your archive in plain language.`}),(0,R.jsx)(`p`,{children:`ThreadShelf runs locally — your queries embed on this machine and search a local LanceDB. Try a topic, a draft you half-remember, or the shape of an answer you're looking for.`}),(0,R.jsx)(`div`,{className:`examples`,children:Bo.map(t=>(0,R.jsxs)(`button`,{className:`example-chip`,onClick:()=>e(t),children:[W.spark,(0,R.jsx)(`span`,{children:t})]},t))})]})}function Ho(e,t){let n=G(t);if(!n)return e;try{return K(e,t).map((e,t)=>n.test(e)?(0,R.jsx)(`mark`,{children:e},t):e)}catch{return e}}function Uo({result:e,query:t,onClick:n,selected:r,onMoreLikeThis:i}){let{metadata:a}=e,o=a.role??`ai`,s={user:`user`,thinking:`reasoning`,ai:`response`}[o]??o,c=zo(a.provider),l=$a(a.model),u=ao(a.createdAt),d=e.distance==null?``:(1-e.distance).toFixed(3),f=e.distance==null?0:Math.round((1-e.distance)*100),p=(0,L.useMemo)(()=>Ho(e.document,t),[e.document,t]),m=a.title?.trim()||Qa(a.sourceFile);return(0,R.jsxs)(`button`,{className:`result`,"data-selected":r,"aria-selected":r,onClick:n,children:[(0,R.jsxs)(`div`,{className:`result-head`,children:[(0,R.jsx)(`span`,{className:`r-role`,"data-role":o,children:s}),(0,R.jsxs)(`span`,{className:`r-provider`,children:[(0,R.jsx)(`span`,{className:`pdot`,style:{background:c.color}}),(0,R.jsx)(`span`,{children:c.short})]}),a.createdInThreadShelf&&(0,R.jsx)(`span`,{className:`threadshelf-turn-badge`,children:`ThreadShelf`}),e.distance!=null&&(0,R.jsx)(`div`,{className:`r-meta-right`,children:(0,R.jsxs)(`span`,{className:`r-score`,children:[(0,R.jsx)(`span`,{className:`r-score-bar`,children:(0,R.jsx)(`i`,{style:{width:`${f}%`}})}),(0,R.jsx)(`span`,{children:d})]})})]}),(0,R.jsx)(`div`,{className:`r-title`,title:m,children:m}),(0,R.jsx)(`div`,{className:`r-snippet`,children:p}),(0,R.jsxs)(`div`,{className:`r-foot`,children:[(0,R.jsxs)(`span`,{className:`r-source`,title:a.sourceFile,children:[W.folder,(0,R.jsx)(`span`,{className:`r-source-coll`,children:Za(a.collection??``)}),(0,R.jsx)(`span`,{className:`slash`,children:`/`}),(0,R.jsx)(`span`,{className:`r-source-file`,children:Qa(a.sourceFile)})]}),(0,R.jsx)(`span`,{className:`dot`}),l&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`span`,{className:`mono`,children:l}),(0,R.jsx)(`span`,{className:`dot`})]}),u&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`span`,{children:u}),(0,R.jsx)(`span`,{className:`dot`})]}),a.turnIndex!=null&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsxs)(`span`,{children:[`turn `,(0,R.jsxs)(`b`,{className:`mono`,children:[`#`,a.turnIndex]})]}),(0,R.jsx)(`span`,{className:`dot`})]}),i&&(0,R.jsx)(`span`,{className:`more-like-this`,role:`button`,tabIndex:0,title:`Search for similar passages`,onClick:e=>{e.stopPropagation(),i()},onKeyDown:e=>{(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),e.stopPropagation(),i())},children:`more like this`}),(0,R.jsxs)(`span`,{className:`open-thread`,children:[`open thread `,W.arrowRight]})]})]})}var Wo={search:`Archive`,insights:`Insights`,indexing:`Add data`,mcp:`MCP`,settings:`Settings`,chat:`Chat`};function Go({view:e,activeColl:t,onMenu:n,actions:r}){return(0,R.jsxs)(`div`,{className:`topbar`,children:[(0,R.jsx)(`button`,{className:`icon-btn mobile-menu-btn`,onClick:n,"aria-label":`Open sidebar`,children:W.menu}),(0,R.jsxs)(`div`,{className:`crumbs`,children:[(0,R.jsx)(`span`,{children:Wo[e]}),e===`search`&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`span`,{className:`sep`,children:`/`}),(0,R.jsx)(`b`,{children:Za(t)})]})]}),(0,R.jsx)(`div`,{className:`topbar-spacer`}),r&&(0,R.jsx)(`div`,{className:`topbar-actions`,children:r})]})}var Ko=100,qo=e=>{switch(e){case`recent`:return(e,t)=>(t.lastTurnAt??``).localeCompare(e.lastTurnAt??``);case`longest`:return(e,t)=>(t.turnCount??0)-(e.turnCount??0);case`title`:return(e,t)=>(e.title||e.sourceFile).localeCompare(t.title||t.sourceFile,void 0,{sensitivity:`base`})}},Jo=[{id:`user`,label:`User`,key:`user`},{id:`reasoning`,label:`Reasoning`,key:`thinking`},{id:`response`,label:`Response`,key:`ai`}];function Yo(){return(0,R.jsx)(`div`,{className:`result-list`,style:{marginTop:16},children:[0,1,2].map(e=>(0,R.jsx)(`div`,{className:`shimmer-card`},e))})}function Xo(){let e=Ni(),{collection:t}=ji({from:`/search/$collection`}),{q:n,model:r,from:i,to:a,mode:o}=Mi({from:`/search/$collection`}),s=t?decodeURIComponent(t):`all`,c=B(e=>e.setActiveColl);(0,L.useEffect)(()=>{c(s)},[s,c]);let l=B(e=>e.roles),u=B(e=>e.toggleRole),d=B(e=>e.modelFilter),f=B(e=>e.setModelFilter),p=B(e=>e.setSidebarOpen),m=B(e=>e.savedSearches),h=B(e=>e.addSavedSearch),g=B(e=>e.removeSavedSearch),_=B(e=>e.pinnedConversations),v=B(e=>e.togglePinned),[y,b]=(0,L.useState)(n??``),[x,S]=(0,L.useState)(n??``),[C,w]=(0,L.useState)(i??``),[T,E]=(0,L.useState)(a??``),[D,O]=(0,L.useState)(o===`keyword`?`keyword`:`semantic`),[ee,te]=(0,L.useState)(15),[k,ne]=(0,L.useState)(-1),[re,ie]=(0,L.useState)(``),[A,j]=(0,L.useState)(`recent`),[M,ae]=(0,L.useState)(Ko),[oe,se]=(0,L.useState)(`all`),N=(0,L.useRef)(n??``),P=(0,L.useRef)(null),F=(0,L.useRef)(null),{data:ce}=Ra(),le=ce??!0,ue=(0,L.useMemo)(()=>{let e=[];return l.user&&e.push(`user`),l.thinking&&e.push(`thinking`),l.ai&&e.push(`ai`),e.length>0&&e.length<3?e.join(`,`):void 0},[l]),{data:de,isFetching:fe}=Ua((0,L.useMemo)(()=>({q:x.trim(),collection:s,n:ee,roles:ue,keywordBoost:D===`semantic`&&x.trim().length<=40,model:(r??d).trim()||void 0,from:C.trim()||void 0,to:T.trim()||void 0,mode:D,origin:oe===`all`?void 0:oe}),[x,s,ee,ue,r,d,C,T,D,oe])),{data:pe,isLoading:me}=Va(s,!x.trim()&&le),he=(0,L.useMemo)(()=>{let e=pe?.files??[],t=re.trim().toLowerCase();return[...(t?e.filter(e=>[e.title,e.sourceFile,e.conversationKey,e.collection].some(e=>(e??``).toLowerCase().includes(t))):e).filter(e=>oe===`threadshelf`?e.createdInThreadShelf===!0||e.hasThreadShelfTurns===!0:oe!==`archive`||e.hasThreadShelfTurns!==!0)].sort(qo(A))},[pe?.files,re,A,oe]),I=(0,L.useMemo)(()=>he.slice(0,M),[he,M]);(0,L.useEffect)(()=>{let e=window.setTimeout(()=>ae(Ko),0);return()=>window.clearTimeout(e)},[s,re,A,oe]),(0,L.useEffect)(()=>{P.current?.focus()},[]),(0,L.useEffect)(()=>{let e=n??``;if(e!==N.current){let t=window.setTimeout(()=>{N.current=e,b(e),S(e),w(i??``),E(a??``),O(o===`keyword`?`keyword`:`semantic`)},0);return()=>window.clearTimeout(t)}},[n,i,a,o]),(0,L.useEffect)(()=>{let e=window.setTimeout(()=>{w(i??``),E(a??``)},0);return()=>window.clearTimeout(e)},[i,a]),(0,L.useEffect)(()=>{let e=window.setTimeout(()=>te(15),0);return()=>window.clearTimeout(e)},[x,s,ue,r,d,C,T,D,oe]);let ge=(0,L.useCallback)(t=>{let n=y.trim(),r=t??D;N.current=n,S(n),e({to:`/search/$collection`,params:{collection:s},search:n?{q:n,model:d.trim()||void 0,from:C.trim()||void 0,to:T.trim()||void 0,mode:r===`keyword`?`keyword`:void 0}:{},replace:!0})},[y,d,C,T,e,s,D]),_e=(0,L.useCallback)(()=>{N.current=``,b(``),S(``),P.current?.focus(),e({to:`/search/$collection`,params:{collection:s},search:{},replace:!0})},[e,s]),ve=(0,L.useCallback)(e=>{O(e),ge(e)},[ge]),ye=(0,L.useCallback)(t=>{e({to:`/thread`,search:{sourceFile:t.metadata.sourceFile,collection:t.metadata.collection??s,conversationKey:t.metadata.conversationKey,q:x.trim()||void 0,title:t.metadata.title,matchIdx:t.metadata.turnIndex,provider:t.metadata.provider,model:t.metadata.model}})},[s,x,e]),be=(0,L.useCallback)(t=>{let n=lo(t.document);n&&(O(`semantic`),N.current=n,b(n),S(n),e({to:`/search/$collection`,params:{collection:s},search:{q:n,model:d.trim()||void 0,from:C.trim()||void 0,to:T.trim()||void 0}}))},[s,d,C,T,e]),xe=(0,L.useCallback)(t=>{e({to:`/thread`,search:{sourceFile:t.sourceFile,collection:t.collection,conversationKey:t.conversationKey,title:t.title}})},[e]),Se=x.trim().length>0,Ce=(0,L.useMemo)(()=>({q:x.trim(),collection:s,mode:D,model:(r??d).trim()||void 0,from:C.trim()||void 0,to:T.trim()||void 0}),[x,s,D,r,d,C,T]),we=(0,L.useMemo)(()=>{let e=ka(Ce);return m.find(t=>ka(t)===e)},[m,Ce]),Te=(0,L.useCallback)(()=>{we?g(we.id):h(Ce)},[we,g,h,Ce]),Ee=(0,L.useCallback)(t=>{O(t.mode),N.current=t.q,b(t.q),S(t.q),e({to:`/search/$collection`,params:{collection:t.collection},search:{q:t.q,model:t.model,from:t.from,to:t.to,mode:t.mode===`keyword`?`keyword`:void 0}})},[e]),De=(0,L.useMemo)(()=>s===`all`?_:_.filter(e=>e.collection===s),[_,s]),Oe=(0,L.useMemo)(()=>new Set(_.map(e=>Aa(e))),[_]),ke=e=>({collection:e.collection,sourceFile:e.sourceFile,conversationKey:e.conversationKey,title:e.title,provider:e.provider}),Ae=(0,L.useMemo)(()=>de?.results??[],[de?.results]),je=Se&&!fe&&Ae.length>=ee&&ee<50,Me=s===`all`?`Conversations`:`${Za(s)} conversations`,Ne=Se?Ae.length:I.length,Pe=(0,L.useCallback)(e=>{if(Se){let t=Ae[e];t&&ye(t)}else{let t=I[e];t&&xe(t)}},[Se,Ae,I,ye,xe]);return(0,L.useEffect)(()=>{let e=window.setTimeout(()=>ne(-1),0);return()=>window.clearTimeout(e)},[x,s,Se]),(0,L.useEffect)(()=>{let e=e=>{let t=e.target,n=t.tagName?.toLowerCase(),r=t===P.current;if((n===`input`||n===`textarea`)&&!r||Ne===0)return;let i=e.key===`ArrowDown`||e.key===`j`&&!r,a=e.key===`ArrowUp`||e.key===`k`&&!r;i?(e.preventDefault(),r&&P.current?.blur(),ne(e=>Math.min(Ne-1,e+1))):a?(e.preventDefault(),ne(e=>e<=0?0:e-1)):e.key===`Enter`&&!r&&k>=0&&(e.preventDefault(),Pe(k))};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[Ne,k,Pe]),(0,L.useEffect)(()=>{k<0||F.current?.querySelector(`[data-selected="true"]`)?.scrollIntoView({block:`nearest`})},[k]),(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(Go,{view:`search`,activeColl:s,onMenu:()=>p(!0)}),(0,R.jsx)(`div`,{className:`main-scroll`,children:(0,R.jsxs)(`div`,{className:`view`,children:[!le&&(0,R.jsxs)(`div`,{className:`banner err`,children:[(0,R.jsx)(`span`,{className:`ico`,children:W.warn}),(0,R.jsxs)(`div`,{className:`grow`,children:[(0,R.jsx)(`b`,{style:{fontWeight:500},children:`Backend unreachable.`}),` `,(0,R.jsxs)(`span`,{style:{color:`var(--text-2)`},children:[`Run `,(0,R.jsx)(`code`,{children:`npm start`}),` in the project root.`]})]})]}),(0,R.jsxs)(`div`,{className:`search-card`,children:[(0,R.jsx)(`span`,{className:`search-ico`,children:W.searchLg}),(0,R.jsx)(`input`,{id:`searchInput`,ref:P,value:y,onChange:e=>b(e.target.value),onKeyDown:e=>{e.key===`Enter`?ge():e.key===`Escape`&&y&&(e.preventDefault(),e.stopPropagation(),_e())},placeholder:D===`keyword`?`Exact match: identifiers, error strings, code…`:`Search by meaning across your archive…`}),y&&(0,R.jsx)(`button`,{id:`clearSearch`,type:`button`,className:`search-clear`,"aria-label":`Clear search`,title:`Clear search (Esc)`,onClick:_e,children:W.close})]}),(0,R.jsxs)(`div`,{className:`search-toolbar`,children:[(0,R.jsxs)(`div`,{className:`mode-toggle`,role:`group`,"aria-label":`Search mode`,children:[(0,R.jsx)(`button`,{type:`button`,className:`mode-btn`,"data-on":D===`semantic`,title:`Rank by meaning (local embeddings)`,onClick:()=>ve(`semantic`),children:`Semantic`}),(0,R.jsx)(`button`,{type:`button`,className:`mode-btn`,"data-on":D===`keyword`,title:`Exact substring match (case-insensitive)`,onClick:()=>ve(`keyword`),children:`Exact`})]}),(0,R.jsx)(`div`,{className:`role-chips`,children:Jo.map(e=>(0,R.jsxs)(`button`,{className:`role-chip`,"data-role":e.id,"data-on":l[e.key],onClick:()=>u(e.key),children:[(0,R.jsx)(`span`,{className:`dot`}),e.label]},e.id))}),(0,R.jsxs)(`label`,{className:`origin-filter`,children:[(0,R.jsx)(`span`,{children:`origin`}),(0,R.jsxs)(`select`,{"aria-label":`Filter by conversation origin`,value:oe,onChange:e=>se(e.target.value),children:[(0,R.jsx)(`option`,{value:`all`,children:`All`}),(0,R.jsx)(`option`,{value:`threadshelf`,children:`ThreadShelf`}),(0,R.jsx)(`option`,{value:`archive`,children:`Clean archive`})]})]}),(0,R.jsxs)(`label`,{className:`model-filter`,children:[(0,R.jsx)(`span`,{children:`model`}),(0,R.jsx)(`input`,{value:d,onChange:e=>f(e.target.value),onKeyDown:e=>e.key===`Enter`&&ge(),placeholder:`gpt-5, claude, gemini...`})]}),(0,R.jsxs)(`label`,{className:`date-filter`,children:[(0,R.jsx)(`span`,{children:`from`}),(0,R.jsx)(`input`,{type:`date`,value:C,onChange:e=>w(e.target.value),onKeyDown:e=>e.key===`Enter`&&ge()})]}),(0,R.jsxs)(`label`,{className:`date-filter`,children:[(0,R.jsx)(`span`,{children:`to`}),(0,R.jsx)(`input`,{type:`date`,value:T,onChange:e=>E(e.target.value),onKeyDown:e=>e.key===`Enter`&&ge()})]}),(0,R.jsx)(`span`,{className:`toolbar-spacer`}),(0,R.jsxs)(`span`,{className:`toolbar-hint`,children:[(0,R.jsx)(`kbd`,{children:`/`}),` focus · `,(0,R.jsx)(`kbd`,{children:`↑↓`}),` navigate · `,(0,R.jsx)(`kbd`,{children:`↵`}),` open · `,(0,R.jsx)(`kbd`,{children:`Ctrl+K`}),` `,`commands`]})]}),!Se&&(0,R.jsxs)(R.Fragment,{children:[s===`all`&&(0,R.jsx)(Vo,{onPick:t=>{N.current=t,b(t),S(t),e({to:`/search/$collection`,params:{collection:s},search:{q:t},replace:!0})}}),m.length>0&&(0,R.jsxs)(`div`,{className:`saved-searches`,children:[(0,R.jsxs)(`span`,{className:`ss-label`,children:[W.star,` Saved`]}),m.map(e=>(0,R.jsxs)(`span`,{className:`ss-chip`,children:[(0,R.jsxs)(`button`,{type:`button`,className:`ss-run`,title:`Run: ${e.q}`,onClick:()=>Ee(e),children:[(0,R.jsx)(`span`,{className:`ss-q`,children:e.q}),e.collection!==`all`&&(0,R.jsx)(`span`,{className:`ss-tag`,children:Za(e.collection)}),e.mode===`keyword`&&(0,R.jsx)(`span`,{className:`ss-tag`,children:`exact`})]}),(0,R.jsx)(`button`,{type:`button`,className:`ss-del`,"aria-label":`Delete saved search "${e.q}"`,onClick:()=>g(e.id),children:`×`})]},e.id))]}),De.length>0&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`div`,{className:`results-meta-bar`,children:(0,R.jsxs)(`span`,{className:`h`,children:[`Pinned `,(0,R.jsx)(`b`,{children:De.length})]})}),(0,R.jsx)(`div`,{className:`result-list`,children:De.map(e=>{let t=e.provider?zo(e.provider):null,n=Qa(e.sourceFile);return(0,R.jsxs)(`button`,{className:`result`,onClick:()=>xe(e),children:[(0,R.jsxs)(`div`,{className:`result-head`,children:[(0,R.jsx)(`span`,{className:`r-role`,"data-role":`user`,children:`pinned`}),(0,R.jsxs)(`span`,{className:`r-provider`,children:[(0,R.jsx)(`span`,{className:`pdot`,style:{background:t?.color??`var(--accent)`}}),(0,R.jsx)(`span`,{children:t?.short??Za(e.collection)})]}),(0,R.jsx)(`span`,{className:`pin-toggle`,role:`button`,tabIndex:0,"data-on":`true`,title:`Unpin`,onClick:t=>{t.stopPropagation(),v(e)},onKeyDown:t=>{(t.key===`Enter`||t.key===` `)&&(t.preventDefault(),t.stopPropagation(),v(e))},children:W.pinFilled})]}),(0,R.jsx)(`div`,{className:`r-title`,title:e.title||n,children:e.title||n}),(0,R.jsxs)(`div`,{className:`r-foot`,children:[(0,R.jsxs)(`span`,{className:`r-source`,title:e.sourceFile,children:[W.folder,(0,R.jsx)(`span`,{className:`r-source-coll`,children:Za(e.collection)}),(0,R.jsx)(`span`,{className:`slash`,children:`/`}),(0,R.jsx)(`span`,{className:`r-source-file`,children:n})]}),(0,R.jsxs)(`span`,{className:`open-thread`,children:[`open thread `,W.arrowRight]})]})]},Aa(e))})})]}),(0,R.jsxs)(`div`,{className:`results-meta-bar`,children:[(0,R.jsxs)(`span`,{className:`h`,children:[Me,` `,(0,R.jsx)(`b`,{children:he.length})]}),(0,R.jsxs)(`label`,{className:`conv-sort`,children:[(0,R.jsx)(`span`,{children:`sort`}),(0,R.jsxs)(`select`,{value:A,onChange:e=>j(e.target.value),"aria-label":`Sort conversations`,children:[(0,R.jsx)(`option`,{value:`recent`,children:`Recent`}),(0,R.jsx)(`option`,{value:`longest`,children:`Longest`}),(0,R.jsx)(`option`,{value:`title`,children:`Title`})]})]}),(0,R.jsx)(`input`,{className:`conv-filter`,value:re,onChange:e=>ie(e.target.value),placeholder:`Filter by title or file…`,"aria-label":`Filter conversations`})]}),me?(0,R.jsx)(Yo,{}):he.length>0?(0,R.jsxs)(`div`,{className:`result-list`,ref:F,children:[I.map((e,t)=>{let n=Qa(e.sourceFile),r=e.title||n,i=e.provider?zo(e.provider):null,a=ao(e.lastTurnAt),o=ke(e),s=Oe.has(Aa(o));return(0,R.jsxs)(`button`,{className:`result`,"data-selected":t===k,"aria-selected":t===k,onClick:()=>xe(e),children:[(0,R.jsxs)(`div`,{className:`result-head`,children:[(0,R.jsx)(`span`,{className:`r-role`,"data-role":`ai`,children:`thread`}),e.hasThreadShelfTurns&&(0,R.jsx)(`span`,{className:`threadshelf-turn-badge`,children:e.createdInThreadShelf?`Created in ThreadShelf`:`Continued in ThreadShelf`}),(0,R.jsxs)(`span`,{className:`r-provider`,children:[(0,R.jsx)(`span`,{className:`pdot`,style:{background:i?.color??`var(--accent)`}}),(0,R.jsx)(`span`,{children:i?.short??Za(e.collection)})]}),(0,R.jsx)(`span`,{className:`pin-toggle`,role:`button`,tabIndex:0,"data-on":s,title:s?`Unpin`:`Pin conversation`,onClick:e=>{e.stopPropagation(),v(o)},onKeyDown:e=>{(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),e.stopPropagation(),v(o))},children:s?W.pinFilled:W.pin})]}),(0,R.jsx)(`div`,{className:`r-title`,title:r,children:r}),(0,R.jsxs)(`div`,{className:`r-foot`,children:[(0,R.jsxs)(`span`,{className:`r-source`,title:e.sourceFile,children:[W.folder,(0,R.jsx)(`span`,{className:`r-source-coll`,children:Za(e.collection)}),(0,R.jsx)(`span`,{className:`slash`,children:`/`}),(0,R.jsx)(`span`,{className:`r-source-file`,children:n})]}),e.turnCount!=null&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`span`,{className:`dot`}),(0,R.jsxs)(`span`,{children:[e.turnCount,` turns`]})]}),a&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`span`,{className:`dot`}),(0,R.jsx)(`span`,{children:a})]}),(0,R.jsxs)(`span`,{className:`open-thread`,children:[`open thread `,W.arrowRight]})]})]},`${e.collection}:${e.sourceFile}:${t}`)}),he.length>M&&(0,R.jsx)(`div`,{className:`load-more-row`,children:(0,R.jsxs)(`button`,{type:`button`,className:`load-more-button`,onClick:()=>ae(e=>e+Ko),children:[`Show more (`,he.length-M,` left)`]})})]}):re.trim()?(0,R.jsxs)(`div`,{className:`empty`,children:[(0,R.jsx)(`h3`,{children:`No conversations match the filter.`}),(0,R.jsx)(`p`,{children:`Try a different phrase or clear the filter box.`})]}):s===`all`?null:(0,R.jsxs)(`div`,{className:`empty`,children:[(0,R.jsx)(`h3`,{children:`No conversations indexed.`}),(0,R.jsx)(`p`,{children:`Index a folder into this collection or switch to another collection.`})]})]}),Se&&fe&&(0,R.jsx)(Yo,{}),Se&&!fe&&Ae.length===0&&(0,R.jsxs)(`div`,{className:`empty`,children:[(0,R.jsx)(`h3`,{children:`No results found.`}),(0,R.jsx)(`p`,{children:`Try another query, broaden your role filters, or index more files.`})]}),Se&&!fe&&Ae.length>0&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsxs)(`div`,{className:`results-meta-bar`,children:[(0,R.jsxs)(`span`,{className:`h`,children:[`Results `,(0,R.jsx)(`b`,{children:Ae.length}),(0,R.jsxs)(`span`,{style:{marginLeft:14,color:`var(--text-3)`},children:[`in `,Za(s)]})]}),(0,R.jsxs)(`button`,{type:`button`,className:`save-search`,"data-on":!!we,title:we?`Remove from saved searches`:`Save this search`,onClick:Te,children:[we?W.starFilled:W.star,(0,R.jsx)(`span`,{children:we?`Saved`:`Save search`})]})]}),(0,R.jsx)(`div`,{className:`result-list`,ref:F,children:Ae.map((e,t)=>(0,R.jsx)(Uo,{result:e,query:x,selected:t===k,onClick:()=>ye(e),onMoreLikeThis:()=>be(e)},t))}),je&&(0,R.jsx)(`div`,{className:`load-more-row`,children:(0,R.jsx)(`button`,{type:`button`,className:`load-more-button`,onClick:()=>te(e=>Math.min(e+15,50)),children:`Load more`})})]})]})})]})}var Zo=/^(\s*)([-*+]|\d+[.)])\s+(.*)$/,Qo=/^\s*\d+[.)]\s+/,$o=e=>{let t=e.trim();return/^(?:https?:\/\/|mailto:|#|\/)/i.test(t)?t:null},es=e=>{let t=[],n=``,r=()=>{n&&=(t.push({type:`text`,value:n}),``)},i=0;for(;i<e.length;){let a=e[i];if(a==="`"){let n=e.indexOf("`",i+1);if(n>i){r(),t.push({type:`code`,value:e.slice(i+1,n)}),i=n+1;continue}}if(a===`[`){let n=e.indexOf(`]`,i+1);if(n>i&&e[n+1]===`(`){let a=e.indexOf(`)`,n+2);if(a>n){let o=$o(e.slice(n+2,a));if(o){r(),t.push({type:`link`,href:o,children:es(e.slice(i+1,n))}),i=a+1;continue}}}}if(a===`*`&&e[i+1]===`*`||a===`_`&&e[i+1]===`_`){let n=e.slice(i,i+2),a=e.indexOf(n,i+2);if(a>i+1){r(),t.push({type:`strong`,children:es(e.slice(i+2,a))}),i=a+2;continue}}if(a===`*`){let n=e.indexOf(`*`,i+1);if(n>i+1){r(),t.push({type:`em`,children:es(e.slice(i+1,n))}),i=n+1;continue}}n+=a,i+=1}return r(),t},ts=e=>{let t=e.replace(/\r\n?/g,`
|
|
18
18
|
`).split(`
|
|
19
19
|
`),n=[],r=0;for(;r<t.length;){let e=t[r];if(!e.trim()){r+=1;continue}let i=/^```(\w+)?\s*$/.exec(e);if(i){let e=[];for(r+=1;r<t.length&&!/^```\s*$/.test(t[r]);)e.push(t[r]),r+=1;r+=1,n.push({type:`code`,value:e.join(`
|
|
20
20
|
`),lang:i[1]});continue}let a=/^(#{1,6})\s+(.*)$/.exec(e);if(a){n.push({type:`heading`,level:a[1].length,children:es(a[2].trim())}),r+=1;continue}if(/^>\s?/.test(e)){let e=[];for(;r<t.length&&/^>\s?/.test(t[r]);)e.push(t[r].replace(/^>\s?/,``)),r+=1;n.push({type:`quote`,children:es(e.join(`
|
package/public/index.html
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
name="description"
|
|
10
10
|
content="Local-first semantic search and backup tool for AI chat exports (Google AI Studio, OpenRouter, LM Studio, ChatGPT, Claude)."
|
|
11
11
|
/>
|
|
12
|
-
<script type="module" crossorigin src="/assets/index-
|
|
12
|
+
<script type="module" crossorigin src="/assets/index-TIPW3iTR.js"></script>
|
|
13
13
|
<link rel="stylesheet" crossorigin href="/assets/index-Dv09K2vS.css">
|
|
14
14
|
</head>
|
|
15
15
|
<body>
|