dsh-locator 0.7.6 → 0.8.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/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.8.0 — 2026-11-12
4
+
5
+ Search and locate: all three stores in one panel, and a Word/Notepad++-style highlight in the conversation.
6
+
7
+ * **One combined search**: the new `POST /dsh-locator/combined` route queries content (bodies and sessions), files and folders in one request, keeps the old `/search` and `/content` routes for tools and compatibility, and returns grouped results in content → files → folders order with per-group counts. Paths found by both content and name are merged into the content row and counted.
8
+ * **All scopes on by default**: the panel now has three independent checkboxes (Content, Files, Folders), all checked; unchecking one narrows the search. Empty queries and one-character queries never start the lazy content build, so opening the panel stays cheap.
9
+ * **Conversation highlight**: double-clicking (or pressing Enter on) a session hit opens the conversation and paints the matched words with a translucent amber highlight (CSS Custom Highlight API, follows scrolling, centered on arrival). The scroll lock releases as soon as the reader scrolls or presses a key; `Esc` clears the highlight. Long sessions load older pages until the message is present, and `hidden="until-found"` rows are expanded with `beforematch`.
10
+ * **Panel rebuild**: grouped listbox with sticky group headers, per-group counts and truncation hints, relevance ordering for content and the sort menu for names, scope preference persistence, content-index progress with a retry, and light/dark theme tokens instead of `prefers-color-scheme`.
11
+ * **Keyboard and accessibility**: Enter activates the selected hit, `Ctrl+Shift+C` copies the path (Everything-style), `Ctrl+Shift+O` reveals it, `Alt+1–3` toggle scopes, Home/End/PageUp/PageDown move the selection, and a minimal dialog focus trap restores focus on close. Rows expose `role=option` / `aria-selected`; the panel is a combobox + listbox with a polite live region.
12
+ * Fixed: duplicate React keys for several session hits, the unstyled snippet line, and the fake content total. Tests: 37 unit tests (combined scope gating, merge/dedupe, lazy-build guards, plus the existing content/plugin suites); `scripts/verify.mjs` now also syntax-checks `client.js` and asserts the new route and highlight markers.
13
+ * No content-index schema change: upgrading does not rebuild the database. File-body hits still reveal the file in the file manager (line-level preview in DSH is the next step); assistant messages are located by phrase because their DOM rows carry no message id.
14
+
15
+ ## 0.7.7 — 2026-11-11
16
+
17
+ Documentation release.
18
+
19
+ * README (zh/en) rewritten against the 0.7.x behaviour and measurements: stale content defaults (1 MB / 1 GB / 100 sessions, previously documented as 4 MB / 2 GB / 200), refreshed performance tables, corrected `locator_status` scope, comparison with Everything/Spotlight/grep, resource tuning, troubleshooting, version compatibility and roadmap.
20
+ * Spanish, Portuguese and Hindi READMEs brought to the same structure and section set.
21
+ * The npm package page therefore receives the current documentation; no runtime changes.
22
+
3
23
  ## 0.7.6 — 2026-11-11
4
24
 
5
25
  Remaining-risk pass: sharing a cache directory, engine re-scans, and platform coverage.
package/README-es.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  # 🔎 dsh-locator
4
4
 
5
- **Búsqueda de archivos en todo el disco, en milisegundos, para DeepSeek Harness — sin Everything.**
5
+ **Busca por nombre cuando recuerdas el nombre y por contenido cuando recuerdas la frase; después abre el archivo o vuelve a la conversación.**
6
6
 
7
- Índice propio multiplataforma (Windows USN/MFT · macOS FSEvents · Linux inotify), seis herramientas para el agente —nombres, contenido y sesiones— y un panel web ordenable.
7
+ Búsqueda de archivos en todo el disco para [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) con su **propio** índice: sin instalar Everything, sin `es.exe`, con las mismas herramientas y el mismo panel en Windows, macOS y Linux.
8
8
 
9
9
  [![npm version](https://img.shields.io/npm/v/dsh-locator)](https://www.npmjs.com/package/dsh-locator)
10
10
  [![npm downloads](https://img.shields.io/npm/dm/dsh-locator)](https://www.npmjs.com/package/dsh-locator)
@@ -12,7 +12,8 @@
12
12
  [![version](https://img.shields.io/github/v/tag/PerryLink/dsh-locator?label=version)](https://github.com/PerryLink/dsh-locator/releases)
13
13
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
14
14
  [![DSH plugin](https://img.shields.io/badge/dsh--plugin-✅-green)](https://github.com/topics/dsh-plugin)
15
- [![Node](https://img.shields.io/badge/node-%5E22.19%20%7C%7C%20%3E%3D24-brightgreen.svg)](#)
15
+ [![Awesome DSH](https://img.shields.io/badge/awesome--dsh--plugin-listed-2ea44f)](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin)
16
+ [![Node](https://img.shields.io/badge/node-%5E22.19%20%7C%7C%20%3E%3D24-brightgreen.svg)](#versión-y-compatibilidad)
16
17
  [![Gitee](https://img.shields.io/badge/Gitee-mirror-c71d23?logo=gitee)](https://gitee.com/perrylink/dsh-locator)
17
18
  [![GitCode](https://img.shields.io/badge/GitCode-mirror-1f6feb)](https://gitcode.com/PerryLink/dsh-locator)
18
19
 
@@ -24,15 +25,62 @@ dsh plugin --profile web add dsh-locator
24
25
 
25
26
  </div>
26
27
 
27
- > **Repositorio oficial:** [GitHub `PerryLink/dsh-locator`](https://github.com/PerryLink/dsh-locator). Gitee y GitCode son espejos sincronizados automáticamente; GitHub es la fuente de verdad.
28
- >
29
- > Forma parte de la [familia de plugins DSH](https://github.com/PerryLink) (Apache-2.0). Si te sirve, **una ⭐ ayuda a que la próxima persona lo encuentre**; no desbloquea nada.
28
+ > **Repositorio oficial:** [GitHub `PerryLink/dsh-locator`](https://github.com/PerryLink/dsh-locator); Gitee y GitCode son réplicas sincronizadas automáticamente y GitHub es la fuente de verdad. Forma parte de la [familia de plugins de DSH](https://github.com/PerryLink) (Apache-2.0) y está listado en [awesome-dsh-plugin](https://github.com/awesome-dsh-plugin/awesome-dsh-plugin). Una ⭐ ayuda a que más gente lo encuentre; no hay nada bloqueado detrás de ella.
29
+
30
+ ## Índice
31
+
32
+ - [De un vistazo](#de-un-vistazo)
33
+ - [En qué se diferencia de Everything / Spotlight / grep](#en-qué-se-diferencia-de-everything--spotlight--grep)
34
+ - [Instalación](#instalación)
35
+ - [Primera ejecución](#primera-ejecución)
36
+ - [Dos búsquedas](#dos-búsquedas)
37
+ - [Panel web](#panel-web)
38
+ - [Herramientas](#herramientas)
39
+ - [Lenguaje de consulta](#lenguaje-de-consulta)
40
+ - [Configuración](#configuración)
41
+ - [Rendimiento y recursos](#rendimiento-y-recursos)
42
+ - [Soporte de plataformas](#soporte-de-plataformas)
43
+ - [Solución de problemas](#solución-de-problemas)
44
+ - [Compilar desde el código fuente](#compilar-desde-el-código-fuente)
45
+ - [Diseño](#diseño)
46
+ - [Limitaciones](#limitaciones)
47
+ - [Memoria](#memoria)
48
+ - [Seguridad y privacidad](#seguridad-y-privacidad)
49
+ - [Versión y compatibilidad](#versión-y-compatibilidad)
50
+ - [Hoja de ruta](#hoja-de-ruta)
51
+ - [Licencia](#licencia)
52
+
53
+ ## De un vistazo
54
+
55
+ Buscar archivos tiene dos formas:
56
+
57
+ - **Recuerdas el nombre pero no la ubicación.** `glob`/`grep` recorren el espacio de trabajo en cada llamada: bien si conoces el directorio, molesto si solo recuerdas medio nombre.
58
+ - **Recuerdas una frase, una decisión o un fragmento, no el archivo ni la conversación.** Un índice de nombres no ayuda, y los registros de sesión de DSH también son datos de primera clase.
59
+
60
+ `dsh-locator` reúne ambos en un solo plugin:
61
+
62
+ | Capacidad | Cómo se usa |
63
+ |---|---|
64
+ | Búsqueda por nombre / ruta | `locator_search`, o el modo por defecto del panel |
65
+ | Búsqueda en el cuerpo del archivo | `locator_find`, o el modo **Buscar contenido** del panel |
66
+ | Búsqueda en sesiones de DSH | Las mismas herramientas; los resultados llevan `sessionId` / `messageId` y el panel puede volver a la conversación |
67
+ | Abrir / mostrar | Las herramientas devuelven rutas; el panel abre con doble clic, `Ctrl+O` abre y `Ctrl+Enter` inserta `@"ruta"` en el compositor |
68
+ | Consumo externo | `locator_export` escribe una réplica SQLite de solo lectura |
69
+
70
+ El índice es local: sin llamadas de red, sin telemetría, sin subidas; el plugin nunca modifica, mueve ni borra los archivos indexados.
30
71
 
31
- `dsh-locator` indexa una vez los directorios que elijas, guarda el resultado en una instantánea compacta, aplica los cambios del sistema de archivos y responde consultas de nombre/ruta en decenas de milisegundos sobre más de un millón de entradas. El agente recibe `locator_search`, `locator_status`, `locator_rebuild` y `locator_export`; las personas tienen un **panel global** en la Web GUI (`Ctrl+Shift+F` o la lupa del pie de la barra lateral).
72
+ ## En qué se diferencia de Everything / Spotlight / grep
32
73
 
33
- ## ¿Por qué otro buscador?
74
+ | | dsh-locator | Everything | Spotlight | `glob` / `grep` |
75
+ |---|---|---|---|---|
76
+ | Plataformas | Windows / macOS / Linux / WSL | Windows | macOS | Multiplataforma |
77
+ | Índice | Persistente, propio | Persistente (USN de NTFS) | Índice del sistema (metadatos/contenido) | Recorrido en cada llamada |
78
+ | Búsqueda en contenido | Archivos de texto + mensajes de sesión de DSH | Solo nombres por defecto | Sí, varía según el sistema | Sí, sin índice |
79
+ | Salto a sesión | Los resultados llevan `sessionId` / `messageId` | No | No | No |
80
+ | Herramientas para agentes | Seis herramientas, un lenguaje de consulta | Requiere CLI/servicio | Requiere scripts propios | Nativas, sin índice persistente |
81
+ | Velocidad en Windows | Cerca de Everything (USN opcional) | La más rápida y ligera | No aplica | Más lenta que un índice |
34
82
 
35
- `glob` y `grep` recorren el workspace en cada llamada: rápidos si conoces el directorio, lentos si solo recuerdas parte de un nombre. Everything es excelente en Windows, pero solo existe en Windows; envolverlo deja fuera macOS, Linux, WSL y hosts remotos. `dsh-locator` es dueño del índice, así que las mismas herramientas funcionan en cualquier sitio donde corran Node y Go.
83
+ En resumen: la **idea** de Everything (índice persistente + consultas estructuradas) está implementada de forma independiente y multiplataforma, con las sesiones de DSH añadidas encima. No es un envoltorio de Everything.
36
84
 
37
85
  ## Instalación
38
86
 
@@ -40,154 +88,335 @@ dsh plugin --profile web add dsh-locator
40
88
  # npm (recomendado)
41
89
  dsh plugin --profile web add dsh-locator
42
90
 
43
- # GitHub main
91
+ # fijar una versión
92
+ dsh plugin --profile web add dsh-locator@0.7.7
93
+
94
+ # rama principal de GitHub
44
95
  dsh plugin --profile web add github:PerryLink/dsh-locator
45
96
 
46
- # desde el código
97
+ # desde un checkout
47
98
  pnpm install
48
99
  pnpm build
49
- pnpm build:engine
100
+ pnpm build:engine # motor Go para la plataforma actual
50
101
  dsh plugin --profile web add /ruta/absoluta/dsh-locator
51
102
 
52
- # tarball
103
+ # desde un tarball (salida de npm pack; sustituye la versión real)
53
104
  npm pack
54
- dsh plugin --profile web add /ruta/absoluta/dsh-locator-0.5.0.tgz
105
+ dsh plugin --profile web add /ruta/absoluta/dsh-locator-0.7.7.tgz
106
+ ```
107
+
108
+ - El paquete incluye motores precompilados para `linux-x64`, `linux-arm64`, `win32-x64`, `win32-arm64`, `darwin-x64` y `darwin-arm64`; no hace falta Go local.
109
+ - Si tu réplica de npm va con retraso, añade `--registry=https://registry.npmjs.org` al comando.
110
+ - Tras instalar en un perfil Web **en ejecución**, **recarga la página** (`F5`): las herramientas del host pueden montarse al momento, pero el panel del navegador se carga del boot graph al abrir la página. Los perfiles headless/TUI solo tienen las herramientas.
111
+ - Actualizar: `dsh plugin --profile web add dsh-locator@latest` y luego `F5`. Un cambio de esquema del contenido reconstruye la base una vez.
112
+ - Desinstalar: `dsh plugin --profile web remove dsh-locator`; para mantener la configuración pero desactivarlo, `enabled: false`.
113
+
114
+ ## Primera ejecución
115
+
116
+ En el primer montaje el motor indexa las raíces configuradas (por defecto, tu directorio personal) y escribe la instantánea y la base de contenido en el directorio de caché de la plataforma:
117
+
118
+ | Plataforma | Directorio de estado por defecto |
119
+ |---|---|
120
+ | Windows | `%LOCALAPPDATA%\dsh-locator` |
121
+ | macOS | `~/Library/Application Support/dsh-locator` |
122
+ | Linux | `$XDG_CACHE_HOME/dsh-locator` o `~/.cache/dsh-locator` |
123
+
124
+ El primer escaneo de un directorio personal grande lee el disco; los arranques posteriores cargan la instantánea. Las peticiones se atienden **durante** ese escaneo: la búsqueda devuelve lo ya indexado con `indexing: true` y el pie del panel indica que el índice sigue construyéndose.
125
+
126
+ Por defecto se omiten `node_modules`, `.git`, `.hg`, `.svn`, `.cache`, `__pycache__`, `.venv`, `venv` y `.next` por nombre; `excludes` cambia la lista.
127
+
128
+ Prueba con:
129
+
130
+ ```text
131
+ Busca los PDF que cambié la semana pasada
132
+ ¿Dónde se habló de "contentRefreshMs"?
133
+ ¿En qué conversación se decidió este diseño?
55
134
  ```
56
135
 
57
- El paquete npm incluye motores precompilados para `linux-x64`, `linux-arm64`, `win32-x64`, `win32-arm64`, `darwin-x64` y `darwin-arm64`.
136
+ ## Dos búsquedas
58
137
 
59
- Si instalas en un perfil Web ya en ejecución, **recarga la página** (`F5`): las herramientas pueden montarse en caliente, pero el panel (`client.js`) se carga desde el boot graph al abrir la página. Los perfiles headless/TUI no montan panel.
138
+ ### Por nombre: `locator_search`
139
+
140
+ Sintaxis estilo Everything que devuelve ruta, tamaño, fecha de modificación, extensión y tipo. Adecuada para «el nombre contiene report», «PDF modificados esta semana», «vídeos de más de 50 MB».
141
+
142
+ La ordenación, la paginación y `limit`/`offset` los hace el motor del host; las consultas habituales sobre 1,51 M de entradas responden en decenas de milisegundos.
143
+
144
+ ### Por contenido: `locator_find`
145
+
146
+ Busca en el **cuerpo** de archivos de texto y mensajes de sesión de DSH y devuelve fragmentos con su origen:
147
+
148
+ - los aciertos de archivo llevan ruta y se pueden abrir o mostrar;
149
+ - los aciertos de sesión llevan `sessionId` y `messageId`, así el panel abre la conversación y resalta el mensaje;
150
+ - funcionan subcadenas en chino e inglés (tokenizador trigram, sin segmentación de palabras).
151
+
152
+ Comportamiento del índice de contenido:
153
+
154
+ - **Perezoso por defecto.** Al iniciar el plugin no se construye nada; la primera búsqueda de contenido (`locator_find` o el modo contenido del panel) arranca la construcción en segundo plano, y `contentLazy: false` recupera la construcción al arranque. La primera consulta informa `building: true` en lugar de devolver un resultado vacío sin explicación.
155
+ - **Reinicio con reutilización.** Si existe la base, se actualiza de forma incremental; la construcción completa (primero logs de sesión y luego cuerpos de archivo) solo ocurre si falta la base, el esquema es antiguo, la construcción anterior quedó a medias o la base no se puede abrir.
156
+ - **Actualización incremental** cada `contentRefreshMs` (5 minutos por defecto), releyendo solo archivos y sesiones cuya mtime cambió; `0` la desactiva.
157
+ - **Sesiones archivadas y activas.** Las archivadas se omiten salvo `contentIncludeArchived: true`; un log que se sigue escribiendo se indexa tras `contentActiveSessionDelayMs` (2 minutos) de calma, para no descomprimirlo en cada actualización. Las sesiones borradas salen del índice cuando desaparecen sus archivos.
158
+ - **Presupuesto y truncado.** Valores por defecto: 1 MB por archivo de texto, 200.000 archivos, 1 GB de cuerpos y las 100 sesiones más recientes. Al alcanzar el presupuesto se omiten los archivos que llegan después en el orden de escaneo; `locator_find` informa `content budget reached` y el estado HTTP lleva `truncated: true`. Sube `contentMaxTotalBytes` o reduce `contentExcludes`.
159
+ - **Los árboles de dependencias no se leen.** `node_modules`, `.cargo`, `.bun`, `.pnpm`, `site-packages`, `toolchain`, … se omiten por defecto con `contentExcludes`; de lo contrario el código de librerías agotaría el presupuesto antes que tus documentos. El índice de nombres sí los cubre.
160
+
161
+ La construcción ocurre dentro del proceso anfitrión de DSH, pero las lecturas y la descompresión zstd son asíncronas y ambos bucles ceden el paso cada ~8 ms: en un corpus de 28,6 MB el bloqueo más largo del bucle de eventos bajó de 968 ms a unos 20 ms, así que la carga y el cambio de sesión no se ven afectados. Las **consultas** de contenido se ejecutan en un hilo worker con conexión de solo lectura: las palabras comunes tardan unos 100 ms y las raras unos milisegundos, sin bloquear al host.
60
162
 
61
163
  ## Panel web
62
164
 
63
- ![Panel de búsqueda de dsh-locator: resultados Markdown filtrados por ruta, con recuento, tiempo y columnas ordenables](docs/assets/panel-en.png)
165
+ ![Panel de búsqueda de dsh-locator: modo contenido activado, con aciertos en el cuerpo y fragmentos](docs/assets/panel-en.png)
166
+
167
+ Pulsa `Ctrl+Shift+F` en cualquier parte de la GUI web, o haz clic en la lupa del pie de la barra lateral.
64
168
 
65
- Pulsa `Ctrl+Shift+F` en cualquier parte de la Web GUI, o haz clic en la lupa del pie de la barra lateral. El panel consulta el mismo índice mediante rutas del host del mismo origen (`/dsh-locator/search`, `/dsh-locator/content`, `/dsh-locator/status`, `/dsh-locator/reveal` y `/dsh-locator/open`), sin segundo servidor ni puerto extra.
169
+ - Una consulta vacía lista las entradas modificadas más recientemente; al escribir se usa la misma sintaxis que las herramientas tras 110 ms de debounce.
170
+ - Haz clic en la cabecera de una columna para ordenar por nombre, tamaño, fecha de modificación o ruta.
171
+ - Alterna **solo archivos** / **solo directorios** para filtrar el tipo.
172
+ - Marca **Buscar contenido** para pasar de nombres a cuerpos de archivo y mensajes de sesión; mientras se construye el índice el pie muestra el estado y el panel vuelve a consultar.
173
+ - `↑`/`↓` seleccionan, `Enter` copia la ruta, `Ctrl+O` abre, `Ctrl+Enter` inserta `@"ruta"` en el compositor y `Esc` cierra.
174
+ - Doble clic en un archivo lo muestra en Explorer/Finder/`xdg-open`; doble clic en una sesión abre la conversación en el mensaje encontrado.
175
+ - El texto del panel sigue `navigator.language` (zh/en/es/pt/hi).
66
176
 
67
- * Consulta vacía: entradas recientes por fecha; al escribir, debounce de 110 ms y la misma sintaxis que las herramientas.
68
- * Clic en una columna para ordenar por nombre, tamaño, fecha o ruta; otro clic invierte.
69
- * `Solo archivos` / `Solo carpetas` filtran por tipo; la barra inferior muestra aciertos, límite y tiempo.
70
- * Marca **Buscar contenido** para pasar de los nombres al contenido de los archivos y a los mensajes de sesión; cada acierto muestra un fragmento de una línea.
71
- * `↑`/`↓` selecciona, `Enter` copia, `Ctrl+O` abre, `Ctrl+Enter` inserta `@"ruta"` en el compositor y `Esc` cierra.
72
- * El doble clic sobre un archivo abre su ubicación en el gestor de archivos; el doble clic sobre un resultado de sesión abre esa conversación y resalta el mensaje encontrado por un momento.
73
- * La interfaz sigue `navigator.language` (zh/en/es/pt/hi).
177
+ El panel usa rutas del mismo origen — `/dsh-locator/search`, `/dsh-locator/content`, `/dsh-locator/content/rebuild`, `/dsh-locator/combined`, `/dsh-locator/status`, `/dsh-locator/reveal`, `/dsh-locator/open` — así que no necesita otro servidor ni otro puerto. Los perfiles sin servidor web no lo montan.
178
+
179
+ - **Los tres ámbitos están activos por defecto**: contenido (cuerpos + sesiones), archivos y carpetas; desmarca cualquiera para acotar. Los resultados se agrupan **contenido → archivos → carpetas** con el recuento por grupo; el contenido se ordena por relevancia y los grupos de nombres siguen el menú de orden.
180
+ - **Doble clic o `Enter` activa un resultado**: una sesión abre la conversación y pinta las palabras encontradas con un resaltado ámbar translúcido que sigue el desplazamiento, se centra al llegar y se limpia con `Esc`; archivos y carpetas se muestran en el gestor de archivos. `Ctrl+Shift+C` copia la ruta, `Ctrl+O` abre, `Ctrl+Enter` inserta `@file` y `Alt+1–3` alterna los ámbitos.
181
+ - Las consultas de contenido requieren al menos dos caracteres; las consultas vacías o de un carácter no inician la construcción del índice.
74
182
 
75
183
  ## Herramientas
76
184
 
77
- | Herramienta | Uso |
185
+ | Herramienta | Qué hace |
78
186
  |---|---|
79
- | `locator_search` | Consulta el índice con sintaxis estilo Everything. |
80
- | `locator_find` | Busca en el contenido de los archivos y en los mensajes de sesión de DSH; los aciertos traen un fragmento y, cuando vienen de una conversación, `sessionId`/`messageId`. |
81
- | `locator_status` | Raíces, entradas, watcher, modo USN y errores. |
82
- | `locator_rebuild` | Reconstruye en segundo plano; las búsquedas siguen usando el índice anterior. |
83
- | `locator_reindex` | Refresca o reconstruye el índice de contenido: incremental por defecto; `full: true` lo borra y lo vuelve a construir. |
84
- | `locator_export` | Copia de solo lectura en SQLite (`entries(path, name, dir, size, mtime_ms, ext)`). |
187
+ | `locator_search` | Consulta nombres y rutas con filtros `ext:`, `size:`, `dm:`, `path:`, ordenación y paginación. |
188
+ | `locator_find` | Busca en cuerpos de archivo y mensajes de sesión; devuelve fragmentos, `sessionId`/`messageId` y el estado del índice de contenido. |
189
+ | `locator_status` | Raíces, recuentos del índice de nombres, estado del watcher, directorio de estado y ruta del motor. (El progreso del contenido lo informan `locator_find` y el panel). |
190
+ | `locator_rebuild` | Sustituye el índice de nombres por un escaneo en segundo plano; las búsquedas usan el índice antiguo hasta que el nuevo esté listo. |
191
+ | `locator_reindex` | Actualiza o reconstruye el índice de contenido: incremental por defecto, `full: true` lo borra y reconstruye. |
192
+ | `locator_export` | Escribe una réplica SQLite de solo lectura del índice de nombres (tabla `entries`) para herramientas SQL externas. |
85
193
 
86
- ### Búsqueda por contenido
194
+ ## Lenguaje de consulta
87
195
 
88
- `locator_find` busca en el contenido de los archivos de texto y en los mensajes de sesión de DSH mediante un índice SQLite FTS5 local. Las subcadenas en chino e inglés funcionan sin necesidad de segmentar palabras.
196
+ Las palabras sueltas son subcadenas del nombre unidas con AND. Los filtros estilo Everything se combinan con ellas:
89
197
 
90
- Cada acierto devuelve un fragmento; si viene de una conversación, incluye `sessionId` y `messageId`, de modo que el panel puede abrir esa sesión y resaltar el mensaje encontrado.
198
+ | Ejemplo | Significado |
199
+ |---|---|
200
+ | `report` | el nombre contiene `report` |
201
+ | `report ext:pdf` | …y la extensión es `pdf` |
202
+ | `ext:ts,js` / `ext:!tmp` | incluir o excluir extensiones |
203
+ | `*.sln` / `?ata` | comodines `*` y `?` |
204
+ | `"annual report"` | frase con espacio |
205
+ | `!archive` | negar un término |
206
+ | `path:src` | la ruta completa contiene `src` |
207
+ | `size:>10mb` / `size:1kb..2mb` | comparaciones de tamaño |
208
+ | `dm:today` / `dm:thisweek` / `dm:2026-01-01` | fecha de modificación |
209
+ | `folder:` / `file:` | solo directorios / solo archivos |
210
+ | `case:1` / `wholeword:1` | sensible a mayúsculas / límites de palabra |
211
+
212
+ `locator_search` también acepta `sort` (`name`, `path`, `size`, `mtime`, `ext`), `desc`, `offset`, `limit`, `regex`, `caseSensitive` y `wholeWord`.
213
+
214
+ ## Configuración
215
+
216
+ Cada campo es un campo de configuración de Schemastery; sobrescribe la entrada `dsh-locator` en el patch del perfil, por ejemplo:
217
+
218
+ ```yaml
219
+ - id: dsh-locator
220
+ name: dsh-locator
221
+ config:
222
+ roots: ['/home/me/Documents', '/home/me/notes']
223
+ contentMaxTotalBytes: 2000000000
224
+ contentExcludes: ['node_modules', '.git', '.cargo', 'site-packages']
225
+ ```
91
226
 
92
- El índice de contenido es perezoso por defecto: al iniciar no se construye nada y la primera búsqueda de contenido lo arranca en segundo plano (`contentLazy: false` lo construye desde el arranque). Al reiniciar, el plugin reutiliza la base de datos existente y la actualiza de forma incremental; solo construye el índice completo (primero los registros de sesión, luego el contenido de los archivos) cuando la base no existe, tiene una versión de esquema antigua o no se puede abrir. Después, el refresco incremental se repite cada `contentRefreshMs` (5 minutos) y solo relee los archivos y las sesiones cuya `mtime` cambió; `locator_reindex` permite lanzar a mano cualquiera de los dos modos.
227
+ | Clave | Valor por defecto | Significado |
228
+ |---|---|---|
229
+ | `enabled` | `true` | Interruptor general; `false` no monta herramientas ni arranca el motor. |
230
+ | `roots` | directorio personal | Directorios a indexar; puede haber varios. |
231
+ | `excludes` | nombres de desarrollo/caché | Globs por nombre que omite el índice de nombres. |
232
+ | `watch` | `true` | Aplicar notificaciones del sistema de archivos. |
233
+ | `refreshIntervalMs` | `1800000` | Cadencia de reconstrucción cuando no hay watcher nativo (kqueue o fallo del watcher); `0` la desactiva. |
234
+ | `scanWorkers` | `0` | Concurrencia de lectura de directorios; `0` usa el número de CPU. |
235
+ | `windowsUsn` | `false` | Probar la enumeración USN/MFT de NTFS antes del recorrido (Windows, administrador; con reserva automática). |
236
+ | `memoryLimitMB` | `0` | Límite blando del heap Go del motor en MiB; `0` lo deja a `GOMEMLIMIT`/`GOGC`. |
237
+ | `contentIndex` | `true` | Construir el índice de cuerpos y mensajes de sesión; `false` deja la búsqueda por nombre con un coste de contenido casi nulo. |
238
+ | `contentLazy` | `true` | Construir el índice de contenido en la primera búsqueda en lugar de al iniciar. |
239
+ | `contentMaxFileBytes` | `1000000` | Bytes leídos de un archivo de texto. |
240
+ | `contentMaxTotalBytes` | `1000000000` | Total de bytes de cuerpos guardados; `0` = sin límite. |
241
+ | `contentMaxFiles` | `200000` | Archivos de texto indexados por construcción; `0` = sin límite. |
242
+ | `contentMaxSessions` | `100` | Logs de sesión más recientes indexados; `0` = todos. |
243
+ | `contentRefreshMs` | `300000` | Cadencia de actualización incremental del contenido; `0` la desactiva. |
244
+ | `contentIncludeArchived` | `false` | Indexar también las sesiones archivadas. |
245
+ | `contentActiveSessionDelayMs` | `120000` | Indexar un log de sesión solo tras este tiempo de calma. |
246
+ | `contentSessionDirs` | `[]` | Directorios de sesión adicionales; vacío = `$DSH_HOME/sessions`. |
247
+ | `contentExcludes` | nombres de dependencias/toolchains | Segmentos o subcadenas de ruta que omite el índice de contenido; el de nombres sí los cubre. |
248
+ | `stateDir` | `''` | Directorio de la instantánea y la base de contenido; vacío = caché de la plataforma. Usa uno distinto por proceso de DSH. |
249
+
250
+ `binaryPath`, `maxResults`, `startupTimeoutMs` y `requestTimeoutMs` también están disponibles para motores personalizados, límites de página y tiempos de espera; los valores por defecto sirven para casi todo.
251
+
252
+ ## Rendimiento y recursos
253
+
254
+ Medido en una máquina de desarrollo WSL2 (Linux, caché de página caliente) y un directorio personal real; tu equipo variará según disco, número de archivos, caché y GC.
255
+
256
+ **Índice de nombres**
257
+
258
+ | Métrica | Resultado |
259
+ |---|---|
260
+ | Escaneo en frío | ~1,51 M de entradas en 11–12 s |
261
+ | Tamaño de la instantánea | ~171 MB para 1,51 M de entradas |
262
+ | Consulta en caliente (`locator_search`) | 6–25 ms para consultas comunes; escaneos `path:` ~70 ms |
263
+ | Búsqueda durante una reconstrucción | El índice antiguo sigue sirviendo hasta que el nuevo está listo |
264
+ | Memoria pico de escaneo | Cientos de MB; el motor es un proceso hijo y respeta `memoryLimitMB` / `GOMEMLIMIT` |
93
265
 
94
- Mientras hay una construcción en marcha, las búsquedas siguen respondiendo con lo que ya está indexado, y la herramienta y el panel informan del estado del proceso.
266
+ **Índice de contenido** (directorio personal real, presupuesto de 1 GB)
95
267
 
96
- Los límites actuales son 1 MB por archivo de texto, 200 000 archivos, las 100 sesiones más recientes y 1 GB de contenido en total; todos se pueden ajustar en la configuración. Las carpetas de dependencias y toolchains (`node_modules`, `.cargo`, `.bun`, `.pnpm`, `site-packages`, `toolchain`, …) se omiten por defecto — si no, se comen el presupuesto antes que tus propios documentos — y `contentExcludes` cambia esa lista. El índice lee y descomprime de forma asíncrona y cede el bucle de eventos cada ~8 ms (28,6 MB: 968 ms → 19 ms), así que no frena la carga ni el cambio de sesión; las sesiones archivadas no se indexan salvo `contentIncludeArchived: true`, y una sesión que se está escribiendo espera `contentActiveSessionDelayMs`.
268
+ | Métrica | Resultado (0.7.x, directorio real) |
269
+ |---|---|
270
+ | Cobertura | ~95,8 k archivos de texto / 95 sesiones / 1.050 mensajes |
271
+ | Reconstrucción completa | ~3,5 min en segundo plano; el host p95 14 ms / máx 115 ms durante ella |
272
+ | Actualización incremental (sin cambios) | ~12 s (dominado por el dump de 1,51 M de entradas del motor) |
273
+ | Latencia del host en reposo | p50 2 ms / p95 3 ms / máx 6 ms |
274
+ | Tamaño de la base | ~3,1 GB (unas 3× el presupuesto de cuerpos) |
275
+ | Consulta de contenido | ~100 ms para palabras comunes, pocos ms para raras (hilo worker, el host no se bloquea) |
97
276
 
98
- ### Sintaxis de consulta
277
+ **Configuraciones más económicas**
99
278
 
100
- ```text
101
- reporte palabras AND en el nombre
102
- "dos palabras" frase literal
103
- *.go ? comodines
104
- ext:pdf,docx ext:!tmp por extensión (o negación)
105
- path:src subcadena de la ruta completa
106
- size:>10mb 1kb..2mb tamaño
107
- dm:today dm:thisweek fecha de modificación
108
- folder: file: solo carpetas / solo archivos
109
- !tmp negar
110
- case:1 wholeword:1 mayúsculas / palabra completa
279
+ - Solo búsqueda por nombre: `contentIndex: false` reduce el trabajo de contenido a cero.
280
+ - Mantener contenido usando menos disco: baja `contentMaxTotalBytes` (p. ej. 256000000) o `contentMaxFileBytes`, o sube `contentRefreshMs`.
281
+ - Cubrir más archivos: sube `contentMaxTotalBytes` / `contentMaxFiles` y comprueba que `contentExcludes` no excluye árboles de documentos reales.
282
+ - La base de contenido es una caché: borrar `stateDir` la reconstruye y nunca toca los archivos originales.
283
+
284
+ ## Soporte de plataformas
285
+
286
+ | Plataforma | Escaneo + instantánea | Actualizaciones en vivo | Notas |
287
+ |---|---|---|---|
288
+ | Linux | sí | inotify, recursivo | Los descriptores de vigilancia son por directorio; árboles enormes pueden alcanzar `fs.inotify.max_user_watches`. |
289
+ | Windows | sí | `ReadDirectoryChangesW`, recursivo | No hace falta administrador ni Everything. Enumeración USN/MFT opcional con privilegios elevados. Los cambios de WSL en `/mnt/<unidad>` pueden no generar notificaciones; reconstruye esas raíces. |
290
+ | macOS | sí | FSEvents en los binarios cgo publicados, recursivo y sin límite | kqueue es la reserva con `CGO_ENABLED=0` (hasta 4.096 directorios); los cambios de contenido dependen de la reconstrucción periódica. |
291
+
292
+ ### Windows y el diario USN
293
+
294
+ El motor incluye un decodificador USN, una ruta rápida opcional y una sonda. La ruta está **desactivada por defecto** (`windowsUsn: false`) porque el ioctl del volumen necesita permisos de administrador; se ha validado de extremo a extremo en un runner Windows de GitHub Actions (administrador, volumen NTFS real):
295
+
296
+ - 1.345.546 registros MFT leídos, 1.345.539 rutas resueltas
297
+ - 164.209 entradas bajo `C:\Windows` (122.915 archivos, 41.294 directorios)
298
+ - `scan --usn --root C:\Windows` indexó 164.216 entradas en 7,8 s; una consulta respondió en 9,6 ms
299
+ - se leyó el diario de cambios (8.233 registros en una ejecución) y un diario inactivo en `D:` cayó al recorrido con un aviso
300
+
301
+ Pruébalo tú mismo:
302
+
303
+ ```powershell
304
+ # PowerShell elevado (o: Start-Process -Verb RunAs <ruta> ...)
305
+ & ".\bin\win32-x64\indexd.exe" usn-probe --volume C: --root "C:\Windows" --limit 5 --journal 5
111
306
  ```
112
307
 
113
- ## Configuración esencial
308
+ Imprime el id/USNs del diario, enumera la MFT (registros por segundo, archivos/directorios bajo la raíz, rutas de ejemplo) y decodifica los últimos registros del diario. Sin elevación falla con `Access is denied`; el parser y la reconstrucción de rutas están cubiertos por pruebas unitarias en todas las plataformas.
114
309
 
115
- | Clave | Valor |
116
- |---|---|
117
- | `roots` | Directorios a indexar; vacío = directorio personal. |
118
- | `excludes` | Globs por nombre (`node_modules`, `.git`, …). |
119
- | `watch` | Activa las notificaciones del sistema. |
120
- | `refreshIntervalMs` | Reconstrucción periódica si no hay watcher nativo. |
121
- | `windowsUsn` | Ruta rápida USN/MFT (Windows, administrador; por defecto `false`). |
122
- | `scanWorkers` | Lectores de directorio en paralelo; 0 = CPU. |
123
- | `stateDir` | Directorio de la instantánea; vacío = caché del sistema. |
124
- | `contentIndex` | Activa la construcción del índice de contenido de archivos y mensajes de sesión (por defecto `true`). |
125
- | `contentLazy` | Construye el índice de contenido en la primera búsqueda de contenido en vez de al iniciar; `false` lo construye en segundo plano desde el arranque (por defecto `true`). |
126
- | `contentMaxFileBytes` | Máximo de bytes que se leen de cada archivo de texto (por defecto `1000000`). |
127
- | `contentMaxTotalBytes` | Total de bytes de contenido que se conservan; `0` = sin límite (por defecto `1000000000`). |
128
- | `contentMaxFiles` | Archivos de texto indexados en cada construcción; `0` = sin límite (por defecto `200000`). |
129
- | `contentMaxSessions` | Sesiones más recientes indexadas; `0` = todas (por defecto `100`). |
130
- | `contentRefreshMs` | Cadencia del refresco incremental de contenido; `0` lo desactiva (por defecto `300000`). |
131
- | `contentIncludeArchived` | Indexa también las sesiones archivadas; por defecto `false`. |
132
- | `contentActiveSessionDelayMs` | Solo indexa un registro de sesión tras estar quieto este tiempo (por defecto `120000`). |
133
- | `contentSessionDirs` | Directorios de sesión adicionales; vacío = `$DSH_HOME/sessions` (por defecto `[]`). |
134
- | `contentExcludes` | Tramos de ruta que la búsqueda por contenido omite (dependencias y toolchains); el índice de nombres no cambia. |
135
-
136
-
137
- ## Plataformas
138
-
139
- | Plataforma | Exploración | Actualizaciones |
140
- |---|---|---|
141
- | Linux | recorrido paralelo | inotify recursivo |
142
- | Windows | recorrido o USN/MFT (admin) | `ReadDirectoryChangesW`; USN reanuda tras reinicio |
143
- | macOS | recorrido | FSEvents en binarios cgo; kqueue como respaldo |
310
+ Con `windowsUsn: true` (o `indexd scan --usn`) el motor enumera la MFT en vez de recorrer directorios y construye rutas desde el mapa de padres FRN. Un escaneo USN correcto escribe `usn-state.json` (id del diario, siguiente USN, raíces) y conserva el FRN en cada registro; en el siguiente `serve --usn` el motor reproduce el diario desde ese cursor antes de responder, así los archivos creados mientras estaba parado aparecen sin un escaneo completo. Un diario envuelto, borrado o inconsistente cae al watcher portátil. Mantiene el handle del volumen y consulta el diario cada dos segundos, aplicando altas, bajas y renombrados mediante `usn.ApplyChanges` (el mismo mapa FRN, actualizado in situ). Los registros USN **no llevan tamaño ni fecha de modificación**: los resultados son correctos para nombres y rutas, `locator_status` marca ese índice con `USN`, y el daemon hace stat de la página devuelta para que las filas muestren tamaños y fechas reales; los filtros `size:`/`dm:` sobre todo el índice siguen siendo aproximados hasta que se ejecuta una pasada de metadatos. Cualquier fallo (sin elevación, volumen no soportado, demasiados registros) cae al recorrido portátil con un aviso; nunca desactiva la búsqueda.
144
311
 
145
- En Windows, `scan --usn` guarda `usn-state.json` (id del diario, siguiente USN, raíces) y `serve --usn` reproduce el diario antes de servir: un archivo creado con el daemon detenido aparece al reiniciar sin reescanear. Un diario desactualizado o desmontado cae al watcher portátil.
312
+ Everything lee la Master File Table de NTFS a través del diario USN, por eso su primer índice es casi instantáneo. `dsh-locator` mantiene el recorrido de directorios portátil como opción por defecto (sin servicio, sin UAC, cualquier sistema de archivos) y usa USN/MFT como ruta rápida opcional donde el proceso tiene `GENERIC_READ` (administrador), con reproducción del diario entre reinicios. El recorrido portátil sigue siendo la reserva.
146
313
 
147
- ## Rendimiento
314
+ ## Solución de problemas
148
315
 
149
- Contenido medido en la misma máquina (caché caliente): 20 000 archivos / 40 MB → 15,1 s y 71 MB; 200 000 archivos / 331 MB → 31,5 s y 711 MB; refresco incremental del índice completo (1,3 M entradas) 2,9 s; reiniciar reutiliza la base y tarda 4,6 s en el corpus de 200 000 archivos. La base ocupa 2–3 veces el texto indexado.
316
+ **El panel no aparece tras la instalación.**
317
+ Recarga la página (`F5`); confirma que instalaste en el perfil `web` y que el panel se carga del boot graph. Los perfiles headless/TUI nunca montan panel.
150
318
 
151
- - 1,2 M de entradas: consulta en caliente 25–35 ms; búsqueda durante el escaneo ~2 ms.
152
- - `C:\Windows` (164 216 entradas) indexado por USN en 7,8 s en un runner de CI; consulta 9,6 ms.
153
- - `locator_export` de 1,24 M de filas: 477 MB, 6,4 s.
319
+ **Un archivo recién creado no aparece.**
320
+ Puede que la notificación no haya llegado (habitual con escrituras de WSL en `/mnt/c`, recursos de red y algunos overlays de contenedores). Espera un momento o ejecuta `locator_rebuild` para esa raíz. El modo USN reproduce el diario al reiniciar.
154
321
 
155
- ## Diseño
322
+ **La búsqueda de contenido no devuelve nada.**
323
+ Mira `building` en el resultado de `locator_find`: la primera búsqueda lanza la construcción perezosa y los resultados pueden ser parciales hasta que termine (el panel vuelve a consultar solo). Comprueba también que la extensión es de texto, el archivo no supera `contentMaxFileBytes`, no está excluido por `contentExcludes` y la sesión no está archivada (las archivadas se omiten por defecto).
324
+
325
+ **La base de contenido es enorme / el disco crece rápido.**
326
+ Consulta [Rendimiento y recursos](#rendimiento-y-recursos): baja el presupuesto o pon `contentIndex: false`. Borrar `stateDir` provoca una reconstrucción.
156
327
 
157
- ![Arquitectura de dsh-locator: sistemas de archivos → escaneo/vigilancia → instantánea compacta → motor de consulta → herramientas / panel](docs/assets/architecture.svg)
328
+ **Aparece un aviso de `inotify`.**
329
+ Demasiados directorios alcanzan el límite del kernel; el índice sigue siendo usable y los cambios dependen de reconstrucciones periódicas. Sube `fs.inotify.max_user_watches` o reduce `roots`.
158
330
 
159
- * **Escaneo paralelo**: cola acotada, lotes por directorio para que el padre exista antes que los hijos.
160
- * **Memoria**: registros de 40 B, nombres en una arena compartida, tabla de rutas abierta; la ruta completa se reconstruye solo al devolver resultados.
161
- * **Consulta**: los términos se compilan una vez, se reparten por fragmentos y un heap acotado selecciona `offset+limit`.
162
- * **Persistencia**: archivo temporal + rename atómico; el snapshot es la fuente de arranque.
163
- * **Protocolo**: NDJSON por stdio; sin puerto ni superficie de red.
331
+ **El comportamiento cambió tras actualizar.**
332
+ Ejecuta `dsh plugin --profile web add dsh-locator@latest` y `F5`. Un cambio de esquema del contenido reconstruye la base una vez. Consulta [CHANGELOG](CHANGELOG.md).
164
333
 
165
- ## Compilar desde el código
334
+ ## Compilar desde el código fuente
166
335
 
167
- Requiere Node `^22.19 || >=24.9`, pnpm y Go 1.22+.
336
+ Requisitos: Node `^22.19 || >=24.9`, pnpm y Go 1.22+ para el motor.
168
337
 
169
338
  ```sh
170
339
  pnpm install
171
340
  pnpm build
172
- pnpm build:engine:all
173
- pnpm check
341
+ pnpm build:engine:all # o build:engine para la plataforma actual
342
+ pnpm check # typecheck + pruebas + verificación de empaquetado/instalación
174
343
  ```
175
344
 
176
- El motor Go vive en `engine/`; pruebas: `cd engine && go test ./...`.
345
+ El motor es un módulo Go independiente en `engine/`; sus pruebas se ejecutan con `cd engine && go test ./...`. El backend FSEvents de macOS necesita cgo y se compila en CI de macOS. Las pruebas de Node se ejecutan en Linux, Windows y macOS en CI.
177
346
 
178
- ## Límites
347
+ ## Diseño
179
348
 
180
- * La búsqueda por contenido solo lee archivos de texto (por extensión) y los registros de sesión del DSH; los PDF, documentos de Office e imágenes no se extraen. De forma predeterminada el cuerpo indexado se limita a 1 GB / 200.000 archivos, así que en un directorio personal enorme solo queda la primera parte que se alcanza.
181
- * No es un driver de sistema de archivos; cubre solo las raíces configuradas.
182
- * inotify consume un descriptor por directorio; árboles enormes pueden agotar el límite del kernel (se avisa y la instantánea sigue usable).
183
- * Escrituras WSL en `/mnt/c` pueden no generar notificaciones de Windows; reconstruye esas raíces.
184
- * macOS: FSEvents en los binarios publicados; kqueue (máx. 4.096 directorios) en compilaciones `CGO_ENABLED=0`. Los cambios de contenido dependen de la reconstrucción periódica.
349
+ ![Arquitectura de dsh-locator: sistemas de archivos → escaneo/vigilancia → instantánea compacta → motor de consultas → herramientas del agente / panel web](docs/assets/architecture.svg)
350
+
351
+ ```
352
+ DeepSeek Harness
353
+ └─ dsh-locator (plugin TypeScript)
354
+ ├─ locator_search / locator_find / locator_status / locator_rebuild /
355
+ │ locator_reindex / locator_export
356
+ ├─ client.js: overlay Ctrl+Shift+F (slot shell.overlay)
357
+ ├─ POST /dsh-locator/{search,content,status,reveal,open} (mismo origen)
358
+ ├─ almacén de contenido: SQLite FTS5 (trigram) en el proceso anfitrión,
359
+ │ consultas en un hilo worker
360
+ └─ proceso hijo: indexd serve (Go, NDJSON por stdio)
361
+ ├─ scanner: recorrido recursivo, exclusiones, progreso
362
+ ├─ index: arena de nombres + registros fijos + tabla de rutas abierta
363
+ ├─ query: parser, matcher, selección top-K, orden, paginación
364
+ ├─ watcher: inotify (Linux) / ReadDirectoryChangesW (Windows)
365
+ └─ snapshot: archivo único, mmap-friendly, renombrado atómico
366
+ ```
367
+
368
+ - **Escáner paralelo.** Los lectores de directorios drenan una cola acotada y escriben un lote por directorio (`AddBatch`), de modo que el registro padre existe antes de encolar sus hijos. La cola no bloquea: si está llena, ese subárbol se escanea en línea.
369
+ - **Disposición en memoria.** Los registros guardan un desplazamiento/longitud de nombre en una arena de bytes y un id de padre; las rutas completas solo se reconstruyen para la página de resultados y los filtros `path:`. Así se evita una cabecera de string por archivo.
370
+ - **Tabla de rutas.** Una tabla de direccionamiento abierto con ranuras `id+1` mantiene búsqueda/actualización en ~12 bytes por entrada en vez de los ~50 de un `map[string]int32`.
371
+ - **Motor de consultas.** Los términos y filtros se compilan una vez, se comparan en trozos paralelos y se reducen con un max-heap acotado: se seleccionan las `offset+limit` filas sin ordenar millones de coincidencias.
372
+ - **Índice de contenido.** SQLite FTS5 en el host con tokenizador trigram (subcadenas UTF-8, CJK); la lista de archivos viene del propio escaneo del motor y los logs de sesión se descomprimen con zstd de Node.
373
+ - **Consistencia del contenido.** Un lock de construcción por proceso serializa escritores que comparten `stateDir`, una marca de construcción completa fuerza la reconstrucción tras una interrumpida, y un handle obsoleto se detecta por dispositivo+inodo para que la reconstrucción de otro proceso no deje al host leyendo una base desvinculada.
374
+ - **Persistencia.** La instantánea se escribe en un archivo temporal y se renombra; un contador de generación permite que el daemon guarde solo cuando el índice cambió. Las lápidas se compactan cuando las bajas superan un umbral.
375
+ - **Protocolo.** Una petición/respuesta JSON por línea en stdio, con eventos `scan`, `stats`, `warning`, `error` y `rebuilt`. Sin puertos, sin superficie de autenticación, sin listeners de red.
376
+ - **Solo lectura.** El motor abre archivos solo para metadatos; nunca escribe en las rutas indexadas.
377
+
378
+ ## Limitaciones
379
+
380
+ - La búsqueda de contenido solo lee archivos de texto (por extensión) y logs de sesión de DSH; no se extrae texto de PDF, Office ni imágenes.
381
+ - El presupuesto de contenido se consume en orden de escaneo, no por importancia del archivo; los archivos posteriores no son buscables al alcanzar el límite (`truncated` es true).
382
+ - El índice cubre las raíces configuradas; no es un driver del sistema de archivos.
383
+ - Linux inotify vigila un descriptor por directorio; un directorio personal con cientos de miles de directorios puede superar el límite del kernel. El plugin avisa y la instantánea sigue utilizable; las reconstrucciones se ponen al día.
384
+ - Las escrituras de WSL en `/mnt/c` pueden no producir notificaciones de Windows (el watcher no ve el flujo del escritor 9p). Reconstruye esas raíces.
385
+ - Los recursos de red solo se escanean si son accesibles como directorios normales; no hay feed de cambios específico de SMB.
386
+ - El contenido de las sesiones viene de logs locales; los mensajes aún no volcados a disco no son buscables.
387
+ - Dos procesos de DSH compartiendo un `stateDir` deben evitarse: el lock de construcción serializa escritores, pero no puede compartir un handle de base de datos abierto.
388
+ - macOS usa FSEvents (recursivo) en los binarios publicados; una compilación con `CGO_ENABLED=0` cae a kqueue, limitado a 4.096 directorios, con cambios de contenido dependientes de la reconstrucción periódica.
389
+ - USN/MFT de Windows es opcional y solo se usa si el proceso puede leer el volumen y el diario está activo; si no, se usa el recorrido portátil.
390
+
391
+ - Los aciertos en el cuerpo de un archivo se muestran por ahora en el gestor de archivos (la vista por línea dentro de DSH es el siguiente paso); los mensajes del asistente se localizan por frase porque sus filas del DOM no llevan messageId.
392
+ - El resaltado dentro de la conversación usa la API CSS Custom Highlight; los navegadores antiguos sin ella caen a un contorno de fila.
393
+
394
+ ## Memoria
395
+
396
+ El motor es un único proceso Go y respeta las variables estándar `GOMEMLIMIT` y `GOGC` (o `memoryLimitMB` en la configuración). Un índice de 1,2–1,5 M de entradas alcanza varios cientos de MB de RSS con el GC por defecto; usa `GOMEMLIMIT=600MiB` (límite blando, el runtime cambia CPU por memoria) o `GOGC=50` cuando el host vaya justo de RAM. Ninguno cambia el formato de la instantánea. En la instalación en vivo usada para las cifras anteriores, el proceso anfitrión de DSH (incluida la caché de páginas de la base de contenido) rondaba los 700 MB de RSS con el índice construido, y la latencia del host en reposo se mantenía en p50 2 ms.
185
397
 
186
398
  ## Seguridad y privacidad
187
399
 
188
- La base de datos de contenido y el bloqueo de compilación se crean con permisos `0600`, y el directorio de estado con `0700`: otros usuarios locales no pueden leer los documentos indexados ni el texto de las sesiones.
400
+ - El índice es local: sin llamadas de red, sin telemetría, sin subidas. El plugin nunca modifica, mueve ni borra archivos indexados.
401
+ - La base de contenido y el lock de construcción se crean con `0600`, y el directorio de estado con `0700`: otros usuarios locales no pueden leer documentos indexados ni el texto de las sesiones.
402
+ - La instantánea y la base de contenido contienen nombres, rutas y cuerpos; trata el directorio de estado como datos privados. Borrarlo limpia la caché.
403
+ - Da a cada proceso de DSH concurrente un `stateDir` distinto.
404
+
405
+ ## Versión y compatibilidad
406
+
407
+ - Node `^22.19.0 || >=24.9.0`; DSH `>=0.2.1-rc.2 <0.3.0` (ver `engines` en `package.json`).
408
+ - Las versiones se publican con procedencia de GitHub Actions, así que el origen del paquete npm es verificable; Gitee / GitCode se sincronizan con un workflow de réplica.
409
+ - Registro de cambios: [CHANGELOG.md](CHANGELOG.md); dudas e informes: [Issues](https://github.com/PerryLink/dsh-locator/issues).
410
+
411
+ ## Hoja de ruta
412
+
413
+ No es un compromiso, solo la dirección actual:
189
414
 
190
- El índice es local: sin red, sin telemetría, sin subidas. La instantánea contiene nombres y rutas; trátala como datos privados. El plugin nunca modifica, mueve ni borra los archivos indexados.
415
+ 1. Verificar el runtime de escritorio Electron en una instalación real de Windows.
416
+ 2. Vistas previas y agrupación de resultados en el panel.
417
+ 3. Cobertura de runtime en Windows on ARM / Linux ARM.
418
+ 4. Arena de nombres en minúsculas y prefiltro trigram para índices muy grandes.
419
+ 5. Compactación incremental de la instantánea y diarios por raíz.
191
420
 
192
421
  ## Licencia
193
422