@alucard_24/pi-codeindex 0.0.0-stage → 1.1.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 ADDED
@@ -0,0 +1,32 @@
1
+ # Changelog
2
+
3
+ ## 1.1.0
4
+
5
+ ### Novità
6
+
7
+ - Modello di embedding in un servizio locale condiviso tra processi pi e CLI:
8
+ una sola pipeline per endpoint, avvio automatico, inferenze serializzate e
9
+ coda limitata. Nessun fallback in-process in caso di errore del servizio.
10
+ - Rilascio del modello dopo inattività (default 5 minuti), configurabile con
11
+ `serviceIdleMs` / `CODEINDEX_SERVICE_IDLE_MS`.
12
+ - `/codeindex service status` e `/codeindex service stop`, disponibili anche
13
+ dalla CLI. Autenticazione locale, verifica del profilo dopo riconnessione e
14
+ rifiuto dei conflitti di configurazione senza creare un secondo modello.
15
+ - Indicizzazione e sincronizzazione anche nelle cartelle senza repository Git.
16
+ Home e radice del disco richiedono consenso esplicito in ogni sessione.
17
+ - Diagnostica, configurazione e documentazione aggiornate; test di concorrenza,
18
+ crash, shutdown e prove opt-in con modello reale.
19
+
20
+ ### Aggiornamento
21
+
22
+ Chiudere e riaprire i vecchi processi pi dopo l'aggiornamento: le copie del
23
+ modello caricate dal vecchio runtime in-process non vengono liberate dal
24
+ nuovo servizio. Per cambiare il profilo di un servizio già attivo usare
25
+ `/codeindex service stop` quando inattivo, oppure attendere il timeout idle.
26
+ I probe espliciti di doctor restano isolati e possono caricare un modello
27
+ aggiuntivo. Endpoint diversi permettono deliberatamente istanze separate.
28
+
29
+ Il servizio è stato verificato su Linux x64 con CPU, CUDA, WebGPU automatico
30
+ e WebGPU/Vulkan; DirectML/Windows e CoreML/macOS restano da verificare sulle
31
+ rispettive piattaforme. Le misure storiche Fase 5–7 non sono nuovi benchmark
32
+ del servizio condiviso.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alucard24
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,443 @@
1
- # Temporary Holding Version
1
+ # pi-codeindex
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Indice semantico locale del codice per l'agente pi: embedding con
4
+ **EmbeddingGemma 2** (ONNX, servizio locale condiviso) e ricerca ibrida
5
+ (coseno + lessico) che restituisce `path:righe` + simbolo + anteprima.
6
+ Una sola copia del modello fra processi pi/CLI sullo stesso endpoint;
7
+ nessun servizio remoto o database. Indice: due file in
8
+ `~/.cache/pi-codeindex/<sha1(repo)>/`.
9
+
10
+ ## Requisiti
11
+
12
+ - Node 22+ (testato su 26.5.1).
13
+ - CPU sempre disponibile come profilo base nelle build native supportate.
14
+ - GPU opzionale: CUDA su Linux x64, WebGPU dove incluso nel binding,
15
+ DirectML su Windows, CoreML su macOS. Non tutte le combinazioni modello,
16
+ driver e hardware sono verificate: vedi la matrice sotto.
17
+
18
+ ## Installazione
19
+
20
+ ### Da npm, solo su richiesta
21
+
22
+ ```bash
23
+ pi -e npm:@alucard_24/pi-codeindex@1.0.0
24
+ ```
25
+
26
+ Carica il pacchetto per questa invocazione, senza aggiungerlo alle impostazioni
27
+ globali di pi. Dalla sessione puoi usare `/codeindex configure` e
28
+ `/codeindex doctor`. I pesi vengono scaricati solo al primo utilizzo del modello;
29
+ CUDA e Vulkan richiedono i setup opzionali descritti sotto.
30
+
31
+ Il pacchetto npm include codice, setup, schema, README, licenza e query di
32
+ esempio. Il repository GitHub resta privato; piano di lavoro, report completi,
33
+ harness sperimentale e test non sono inclusi nel tarball npm.
34
+
35
+ ### Dal sorgente (sviluppo)
36
+
37
+ ```bash
38
+ npm install
39
+ npm run setup-gpu # solo GPU NVIDIA: scarica il provider CUDA e lo configura
40
+ ```
41
+
42
+ `setup-gpu.sh` è **solo Linux x64** e richiede CUDA 13 + `patchelf`.
43
+ Va rieseguito se un aggiornamento/reinstallazione sostituisce il provider.
44
+ DirectML, CoreML e WebGPU usano i provider inclusi nel binding nativo;
45
+ non richiedono questo script CUDA.
46
+
47
+ Il pacchetto espone anche il binario `pi-codeindex`: gli esempi
48
+ `node src/cli.js ...` possono essere eseguiti come `pi-codeindex ...`
49
+ quando il binario è sul PATH. `pi-codeindex setup-gpu` avvia il setup CUDA.
50
+ Nessun postinstall scarica i pesi e nessuna configurazione globale di pi viene
51
+ modificata dal pacchetto.
52
+
53
+ ## Embedding e backend
54
+
55
+ Il modello **EmbeddingGemma 2** gira in un servizio locale condiviso avviato
56
+ automaticamente al primo utilizzo, anche dall'indicizzazione automatica.
57
+ I client pi/CLI non caricano una pipeline propria. I soli pesi testo vengono
58
+ scaricati e riutilizzati fra repository; dopo il primo download è possibile
59
+ lavorare offline. Il codice da embeddare viaggia solo sul loopback locale,
60
+ non viene inviato al server dei pesi o a un'API di embedding remota.
61
+
62
+ | `device` | Default `dtype: auto` | Stato |
63
+ |---|---|---|
64
+ | `cpu` | `q8` | inferenza reale verificata su Linux x64 |
65
+ | `cuda` | `fp16` | inferenza reale verificata su NVIDIA/Linux x64; setup opzionale |
66
+ | `webgpu` | `fp16` | inferenza reale verificata su questa macchina Linux; supporto hardware/driver variabile |
67
+ | `dml` | `fp16` | DirectML/Windows: integrazione e policy testate, hardware non verificato |
68
+ | `coreml` | `fp16` | CoreML/macOS: integrazione e policy testate, hardware non verificato |
69
+
70
+ **Vulkan è selezionabile come backend nativo di WebGPU**, non come provider
71
+ ONNX autonomo: usa `device: "webgpu"` + `webgpuBackend: "vulkan"` dopo il setup
72
+ opzionale sotto. `device: "vulkan"` resta un errore esplicativo. Con
73
+ `webgpuBackend: "auto"` decide Dawn: non si garantisce Vulkan e non lo si
74
+ presenta come forzato. Stato e metadati distinguono `webgpu→vulkan/fp16` da
75
+ `webgpu→auto/fp16`.
76
+ Un provider presente nel binding non garantisce compatibilità, velocità,
77
+ utilizzo della GPU dedicata o copertura totale del grafo: ORT può eseguire
78
+ alcuni operatori su CPU. Gli smoke test non sostituiscono un benchmark di
79
+ retrieval/performance per piattaforma. `q4` è disponibile ma il drift non è
80
+ validato sull'eval.
81
+
82
+ **Auto:** Linux prova CUDA → WebGPU → CPU; Windows DirectML → WebGPU → CPU;
83
+ macOS CoreML → WebGPU → CPU. I provider assenti vengono saltati; una prova del
84
+ modello reale deve riuscire prima che il profilo venga fissato. Tentativi e
85
+ fallback sono visibili nei log e nello stato/avvisi dell'estensione.
86
+ Un device forzato fallisce per default; `fallback: "cpu"` autorizza il ripiego.
87
+ Il fallback avviene solo all'inizializzazione, mai durante l'embedding di un
88
+ indice già iniziato. La prima riconciliazione di un processo inizializza il
89
+ modello anche se l'indice era caldo; i vecchi tempi di re-index sotto indicati
90
+ precedono questo cambiamento.
91
+
92
+ ### WebGPU con Vulkan forzato (opzionale, Linux x64)
93
+
94
+ ```bash
95
+ npm run setup-vulkan
96
+ CODEINDEX_OFFLINE=true node src/cli.js doctor --probe --device webgpu --webgpu-backend vulkan
97
+ CODEINDEX_DEVICE=webgpu CODEINDEX_WEBGPU_BACKEND=vulkan pi -e ./src/extension.js
98
+ ```
99
+
100
+ Il setup richiede **compilatore C++17, header Node/N-API, `tar`, `patchelf` e
101
+ rete** per scaricare i piccoli sorgenti del binding. Non compila ORT/Dawn e
102
+ non richiede CUDA o il Vulkan SDK: riusa il runtime precompilato con WebGPU;
103
+ per eseguire serve il driver Vulkan. Header fuori dai percorsi standard:
104
+ `npm run setup-vulkan -- --node-headers /percorso/include/node`.
105
+
106
+ Il binding Node standard 1.30.0 non espone il selettore Dawn. Il setup
107
+ compila un binding opzionale da un commit ORT fissato e con hash dei sorgenti
108
+ verificati. Binding e copia del runtime (con SONAME distinto) restano in
109
+ `~/.cache/pi-codeindex/native/`: **nessuna modifica a `node_modules`**, nessun
110
+ provider standard sostituito. Il backend aggiunto ha nome unico e priorità
111
+ negativa: viene usato solo da una sessione che lo richiede esplicitamente.
112
+ Prima del caricamento si verificano gli hash; un controllo negativo obbligatorio
113
+ rifiuta i binding che ignorano il selettore. Manca il setup, il runtime è
114
+ cambiato o non esiste un adapter Vulkan? Errore, non WebGPU automatico nascosto.
115
+ Il fallback CPU resta solo quello già autorizzato da `fallback: "cpu"`.
116
+
117
+ Il setup è idempotente; dopo un cambio di runtime può essere necessario
118
+ rieseguirlo. `pi-codeindex setup-vulkan` è equivalente. Riavvia pi dopo setup
119
+ o cambi di profilo. Il backend WebGPU entra nell'identità dell'indice: cambiare
120
+ `auto` ↔ `vulkan` richiede re-index. Con `device: "auto"` il selettore riguarda
121
+ solo l'eventuale tentativo WebGPU: CUDA può ancora essere scelto prima.
122
+
123
+ Windows richiederebbe anche una build ORT/Dawn con Vulkan abilitato: **non
124
+ implementata/verificata** da questo setup. AMD e Intel richiedono prove sulle
125
+ rispettive GPU. Nessuna promessa di vantaggio prestazionale rispetto a CUDA.
126
+ Le prove con il modello completo richiedono VRAM libera; il processo `doctor`
127
+ riporta l'errore e non termina applicazioni GPU altrui per liberarla.
128
+
129
+ Test opzionali reali, dopo setup e download dei pesi fp16:
130
+ `CODEINDEX_TEST_VULKAN=1 node --test test/vulkan-integration.test.js`.
131
+ La suite normale non richiede GPU né compila addon. Verificati su questa
132
+ macchina Linux x64 / RTX 5070 Ti: EmbeddingGemma fp16, indice incrementale,
133
+ ricerca su fixture e coesistenza con i provider standard. Queste prove non
134
+ sostituiscono un benchmark di qualità o prestazioni su altri hardware.
135
+
136
+ ## Servizio condiviso e memoria
137
+
138
+ Il primo client sceglie il profilo secondo la configurazione; gli altri
139
+ riutilizzano la stessa pipeline se quel profilo è consentito. Un profilo
140
+ incompatibile, una cache pesi diversa o valori diversi di `cpuThreads` o
141
+ `serviceIdleMs` danno errore: **nessun secondo modello e nessun fallback
142
+ in-process**. Un device forzato può riutilizzare un servizio CPU solo con
143
+ `fallback: cpu`, con avviso esplicito. Le richieste sono serializzate, con
144
+ massimo 16 richieste attive/in coda; ogni batch contiene al massimo 128 testi
145
+ e 2 MiB di testo. La saturazione della coda produce un errore, non un altro
146
+ worker. Un crash interrompe la richiesta corrente; un uso successivo può
147
+ riavviare il servizio, verificando il profilo già fissato dal client.
148
+
149
+ Dopo **5 minuti senza operazioni sul modello** il processo termina e l'OS
150
+ libera RAM/VRAM native. `status` non rinnova il timer. Chiudere/disabilitare
151
+ una singola sessione non arresta un modello che può servire altri processi.
152
+ Per liberarlo subito, quando non ci sono inferenze in corso:
153
+
154
+ ```text
155
+ /codeindex service status
156
+ /codeindex service status --json
157
+ /codeindex service stop
158
+ ```
159
+
160
+ Gli stessi comandi funzionano come `node src/cli.js service status|stop`.
161
+ Stop viene rifiutato se ci sono richieste attive/in coda; non interrompe altri
162
+ client. Il servizio si riavvierà al prossimo utilizzo del modello. Nessun
163
+ avvio al login, servizio di sistema o modifica alle impostazioni globali di pi.
164
+
165
+ Il listener è solo `127.0.0.1`, con porta deterministica per la directory
166
+ utente e autenticazione tramite token in `~/.cache/pi-codeindex/service/`
167
+ (directory 0700, record 0600 su POSIX). Il binding esclusivo della porta
168
+ impedisce due avvii simultanei. Una porta occupata da un altro programma dà
169
+ un errore: `servicePort` consente una scelta esplicita. Usa gli stessi
170
+ `serviceDir`/`servicePort` in tutti i client: cambiarli crea endpoint distinti
171
+ e permette deliberatamente più modelli. Non condividere il token o la directory.
172
+
173
+ Restano per-processo le cache degli indici, dei vettori e dei grafi: il servizio
174
+ elimina le copie del **modello**, non tutta la memoria di pi. Dopo l'aggiornamento
175
+ **chiudi e riapri i vecchi processi pi**: i modelli già caricati dal vecchio
176
+ codice in-process non possono essere liberati dal nuovo servizio.
177
+
178
+ Verifica reale opt-in, con pesi già in cache (offline), due processi client,
179
+ indice/ricerca e uscita idle:
180
+
181
+ ```bash
182
+ CODEINDEX_TEST_SERVICE=1 CODEINDEX_DEVICE=cuda node --test test/service-integration.test.js
183
+ # Oppure cpu/q8, oppure WebGPU con CODEINDEX_WEBGPU_BACKEND=vulkan dopo setup-vulkan.
184
+ ```
185
+
186
+ Questi test non sono un nuovo benchmark Fase 5–7. La piattaforma iniziale di
187
+ verifica del servizio è Linux x64; Windows/DirectML e macOS/CoreML richiedono
188
+ verifica sulle rispettive macchine.
189
+
190
+ ## Configurazione
191
+
192
+ Dentro pi:
193
+
194
+ ```text
195
+ /codeindex configure menu interattivo + conferma salvataggio
196
+ /codeindex config valori effettivi, provenienza e percorso
197
+ /codeindex config set device webgpu
198
+ /codeindex config set dtype fp16
199
+ /codeindex config set webgpuBackend vulkan solo WebGPU, setup-vulkan richiesto
200
+ /codeindex config set fallback cpu
201
+ /codeindex config unset device ripristina la scelta automatica
202
+ /codeindex service status processo condiviso, profilo e memoria
203
+ /codeindex service stop rilascia il modello quando inattivo
204
+ /codeindex doctor inventario, senza inferenza/download
205
+ /codeindex doctor --probe --device webgpu prova reale isolata (può scaricare i pesi)
206
+ ```
207
+
208
+ La configurazione è **della macchina**, non della sessione pi:
209
+ `$XDG_CONFIG_HOME/pi-codeindex/config.json` oppure
210
+ `~/.config/pi-codeindex/config.json` (`%APPDATA%/pi-codeindex/config.json`
211
+ su Windows). `CODEINDEX_CONFIG=/percorso/config.json` sceglie un file diverso,
212
+ anche per un singolo progetto; nessun file del repository viene letto
213
+ implicitamente. Non vengono modificate le impostazioni di pi.
214
+ Precedenza: **default < file < ambiente**. Il menu salva solo i campi cambiati,
215
+ non gli override d'ambiente. JSON malformato/chiavi sconosciute producono errori,
216
+ non default silenziosi. Schema per editor: [config.schema.json](config.schema.json).
217
+
218
+ ```json
219
+ {
220
+ "device": "auto",
221
+ "dtype": "auto",
222
+ "fallback": "error",
223
+ "offline": false,
224
+ "cpuThreads": 0
225
+ }
226
+ ```
227
+
228
+ | Campo | Valori | Override ambiente |
229
+ |---|---|---|
230
+ | `device` | `auto`, `cpu`, `cuda`, `webgpu`, `dml`, `coreml` | `CODEINDEX_DEVICE` |
231
+ | `dtype` | `auto`, `q8`, `q4`, `fp16` | `CODEINDEX_DTYPE` |
232
+ | `webgpuBackend` | `auto` (default), `vulkan` forzato; riguarda solo WebGPU | `CODEINDEX_WEBGPU_BACKEND` |
233
+ | `fallback` | `error` (default), `cpu`; riguarda device forzati | `CODEINDEX_FALLBACK` |
234
+ | `offline` | booleano; niente download, errore se mancano pesi | `CODEINDEX_OFFLINE=true\|false\|1\|0` |
235
+ | `cacheDir` | cache pesi, default `~/.cache/pi-codeindex/text-model` | `CODEINDEX_MODEL_CACHE` |
236
+ | `cpuThreads` | 0 = default ORT, oppure 1–256; non limita la GPU | `CODEINDEX_CPU_THREADS` |
237
+ | `serviceIdleMs` | default 300000 (5 min), da 1000 a 86400000 ms | `CODEINDEX_SERVICE_IDLE_MS` |
238
+ | `serviceDir` | directory privata condivisa, default `~/.cache/pi-codeindex/service` | `CODEINDEX_SERVICE_DIR` |
239
+ | `servicePort` | 0 = deterministica, oppure 1024–65535; solo loopback | `CODEINDEX_SERVICE_PORT` |
240
+
241
+ **Riavvia pi con un nuovo processo** dopo una modifica: non si cambia pipeline
242
+ nel mezzo di un run. Se il servizio ha già un profilo/configurazione diversi,
243
+ usa anche `service stop` quando inattivo, oppure attendi l'uscita idle.
244
+ Prima di aggiornare a un protocollo incompatibile, arresta il vecchio servizio.
245
+ Il menu non riavvia né reindicizza da solo. Device, dtype
246
+ e backend WebGPU effettivi sono salvati nell'indice; se diversi, la ricerca rifiuta di mescolare
247
+ i vettori e chiede un re-index. Gli indici precedenti senza `device` vengono
248
+ ricostruiti alla prossima indicizzazione.
249
+
250
+ Da shell, senza avviare pi:
251
+
252
+ ```bash
253
+ node src/cli.js config show
254
+ node src/cli.js config set device cpu
255
+ node src/cli.js config set cpuThreads 4
256
+ node src/cli.js doctor --probe --device cpu --json
257
+ node src/cli.js doctor --probe --all # prove sequenziali dei provider presenti
258
+ node src/cli.js doctor --probe --device webgpu --webgpu-backend vulkan
259
+ CODEINDEX_DEVICE=cuda CODEINDEX_DTYPE=fp16 pi -e ./src/extension.js
260
+ ```
261
+
262
+ `doctor` senza `--probe` non carica/scarica il modello. Le prove reali girano
263
+ in subprocessi isolati con timeout di 120 s per backend; `--all` può scaricare
264
+ più varianti. Ogni provider forzato viene provato senza fallback, per non
265
+ attribuire alla GPU un successo ottenuto in CPU. Usa `offline: true` per provarle solo dalla cache. Un crash nativo
266
+ di una prova non abbatte pi. I probe restano esplicitamente isolati e **possono
267
+ caricare una copia aggiuntiva del modello** mentre il servizio è attivo: arresta
268
+ prima il servizio se vuoi evitare questo picco. Anche la pipeline ordinaria è
269
+ ora isolata, nel worker condiviso. Smoke del menu e dei comandi via RPC, senza
270
+ chiamate LLM e con cache modello temporanea/offline: `CODEINDEX_TEST_RPC=1 node --test test/config-rpc.test.js` (richiede
271
+ `pi` sul PATH; usa un file config temporaneo, non modifica quello utente).
272
+
273
+ ## Comandi
274
+
275
+ ```bash
276
+ node src/cli.js index [--root DIR] [--max-files 5000] [--max-bytes 200] [--force]
277
+ node src/cli.js status [--root DIR]
278
+ node src/cli.js search "query" [--k 8] [--path-prefix src/] [--stale] [--bundle] [--json]
279
+ node src/cli.js eval [--file eval/queries.jsonl] [--json]
280
+ node src/cli.js embed-test
281
+ ```
282
+
283
+ - `index` è incrementale: confronta l'hash di ogni file e riusa i vettori dei
284
+ chunk invariati. Salvataggio atomico; una cache di ripresa evita di
285
+ ricalcolare tutto se il run viene interrotto.
286
+ - `search` legge il codice dal disco solo per i risultati finali e non esce
287
+ mai dal repo.
288
+ - `eval` misura recall@3/@8 e latenza sulle query della fixture.
289
+
290
+ ## Uso dentro pi
291
+
292
+ ```bash
293
+ # pacchetto npm: solo questa invocazione, nessuna configurazione globale
294
+ pi -e npm:@alucard_24/pi-codeindex@1.0.0
295
+
296
+ # in sviluppo, dalla directory del progetto
297
+ pi -e ./src/extension.js
298
+ ```
299
+
300
+ Cosa aggiunge:
301
+
302
+ - **`search_code`** — ricerca semantica (`query`, `k` 1–30, `path_prefix`,
303
+ `context`) che restituisce `path:start-end`, simbolo e anteprima. Non
304
+ sostituisce `grep`.
305
+ - i risultati il cui file è cambiato dopo l'indicizzazione sono marcati
306
+ `STALE` (hash su disco, non fiducia nel watcher);
307
+ - `context: "bundle"` aggiunge import, importatori e fino a 5 chiamanti
308
+ **euristici** dei primi 3 risultati: un round-trip invece di una catena
309
+ `grep`+`read`.
310
+ - **outline su `read`** — se leggi un file > 300 righe con ≥ 5 simboli indicizzati
311
+ e senza `offset`/`limit` mirati, ricevi un blocco `[outline from code index]`
312
+ con i simboli e i loro range (max 40, ~3,5% di caratteri in più).
313
+ - **riga di stato** nel footer (`codeindex: 5.2k chunk`, `codeindex: 1.2k/4.8k`
314
+ durante l'indicizzazione).
315
+ - **`/codeindex status|reindex [--force]|enable|disable|config|configure|doctor`**. `disable` spegne
316
+ tutto: tool, outline, riga di stato, riga nel system prompt, watcher e
317
+ indicizzazione in corso. Lo stato è persistito nel branch della sessione;
318
+ una sessione nuova riparte attiva.
319
+ - **indicizzazione automatica** all'avvio della sessione, in background,
320
+ single-flight, interrompibile, con cap 5.000 file / 200 MB.
321
+ - **sincronizzazione**: watcher ricorsivo con debounce 800 ms, invalidazione
322
+ diretta da `write`/`edit` e controllo dopo `bash`: sweep `git status` nei
323
+ repository, riconciliazione incrementale nelle cartelle senza Git. Una
324
+ riconciliazione riusa i vettori dei file intatti (misurato nei repository:
325
+ 1 chunk re-embedded su 3 dopo una modifica, 920 ms fino all'indice aggiornato).
326
+
327
+ Se il modello non è scaricabile o il reindex fallisce, `search_code` risponde
328
+ con lo stato reale e la sessione continua.
329
+
330
+ ### Cartelle senza Git
331
+
332
+ Git è opzionale. Nei repository la radice resta quella restituita da Git,
333
+ anche avviando pi da una sottocartella. Altrimenti viene usata **esattamente
334
+ la directory da cui avvii pi**: non viene creato `.git`, non servono commit
335
+ né un remote. `/codeindex status` mostra radice e modalità.
336
+
337
+ In modalità cartella la scansione esclude le directory nascoste e le consuete
338
+ directory di dipendenze/output (`node_modules`, `dist`, `build`, `out`,
339
+ `vendor`, `target`, `coverage`, `venv`, `__pycache__`); non segue i symlink.
340
+ Restano i limiti di estensione, dimensione, 5.000 file e 200 MB. Le esclusioni
341
+ sono quelle fisse della scansione locale: **senza Git i file `.gitignore`
342
+ non vengono interpretati**. Nei repository continua a valere `git ls-files`
343
+ con le esclusioni Git.
344
+
345
+ Il watcher gestisce anche rename/cancellazioni di directory; dopo `bash`
346
+ viene accodata una riconciliazione senza ricalcolare i vettori invariati.
347
+ Se il watcher non è disponibile, la riconciliazione viene accodata anche
348
+ all'inizio di un nuovo prompt. `/codeindex reindex` resta disponibile per
349
+ aggiornare manualmente l'indice; `--force` ricalcola tutti i vettori.
350
+
351
+ Per evitare scansioni involontarie dell'intera macchina, nella **home** e
352
+ nella **radice del disco**, se non sono repository Git, l'indice parte spento.
353
+ Avvia pi dalla cartella del progetto oppure abilitalo esplicitamente con
354
+ `/codeindex enable`; nelle due cartelle protette il consenso va ripetuto a
355
+ ogni avvio della sessione. Nessuna nuova configurazione globale è necessaria.
356
+
357
+ ## Cosa indicizza
358
+
359
+ JS/TS/TSX/JSX, Python, Go, Rust, C, C++, C#, PowerBuilder (.srw/.sru/…),
360
+ Markdown. Chunk declaration-aware, con fusione dei chunk piccoli (Markdown fino
361
+ a 80 righe; codice solo micro-chunk ≤6 righe). Esclusi: binari, file >1 MB,
362
+ minified, lockfile, `.pbl`/`.pbt`/`.pbw`.
363
+
364
+ ## Numeri misurati (runtime originale in-process, RTX 5070 Ti, fp16)
365
+
366
+ Queste misure precedono il servizio condiviso e non ne misurano memoria,
367
+ latenza IPC o prestazioni con client concorrenti.
368
+
369
+ | Repo | File | Chunk | Primo indice | Re-index |
370
+ |---|---|---|---|---|
371
+ | `pi.dev-ext` | 373 | 5.230 | 44 s | 169 ms |
372
+ | `Strata` | 2.872 | 29.974 | ~2–5 min | 737 ms |
373
+
374
+ Su CPU q8 (`pi.dev-ext`): 18m28s il primo indice, 143 ms il secondo.
375
+ Ricerca a indice caldo: p50 32 ms. Recall@3 sulla fixture: 5/8.
376
+
377
+ Dentro pi: cache in-process dell'indice (stat dei due file come chiave), quindi
378
+ 11,5 ms a caldo su `pi.dev-ext` e **40 ms su `Strata`** (30k chunk), contro ~1,2 s
379
+ di caricamento modello alla prima query di un processo nuovo.
380
+ Outline su un file da 3.713 righe: **+3,5% caratteri** sulla read.
381
+
382
+ ## Misura (giro completo)
383
+
384
+ I file e i comandi di questa sezione si riferiscono al checkout di sviluppo:
385
+ piano, report completi e harness non vengono distribuiti nel pacchetto npm.
386
+ Il riepilogo e i limiti delle misure sono riportati qui senza estenderne lo scope.
387
+
388
+ `RESULTS.md` riporta l'esperimento A (pi nudo) vs C (pi + indice) su 10 task per
389
+ repo × 3 ripetizioni: mediana dei delta **−25,4% token su `Strata`** e **−9,7% su
390
+ `pi.dev-ext`**, ma costo totale **−12,3%** e **−12,9%**: sotto la soglia del 15%
391
+ del gate primario. Il verdetto è nel file: **gate non superato**, progetto fermo
392
+ per la regola scritta in `PLAN.md`. Il braccio B (OpenLore) non è stato eseguito:
393
+ nessun claim comparativo.
394
+
395
+ La Fase 6 ha ripetuto la misura con un budget di **80 tool call** per sessione
396
+ (`RESULTS-FASE6.md`): costo **−23,2%** su `Strata` e **−19,2%** su `pi.dev-ext`,
397
+ ma successo **27/30 vs 28/30** su `Strata`. Tutti i fallimenti sono run tagliati
398
+ dal cap; il criterio pre-registrato `C ≥ A` non è soddisfatto per una run, quindi
399
+ quel gate resta non superato.
400
+
401
+ La Fase 7 (`RESULTS-FASE7.md`, 80 coppie appaiate per repo, ipotesi più debole
402
+ pre-registrata prima dei run) supera il gate che chiede **solo di non spendere
403
+ più**: costo appaiato **−22,1%** su `Strata` (CI unilaterale [−29,3%, −14,1%]) e
404
+ −21,5% su `pi.dev-ext`, successo **74/80 vs 74/80** e 79/80 vs 80/80. La soglia
405
+ del **15%** resta non misurata: quello che è dimostrato è "in sessione con budget
406
+ di 80 tool call il costo non aumenta e il successo non peggiora oltre 10pp".
407
+
408
+ ```bash
409
+ node scripts/experiment.mjs --repo ~/AI-Projects/Strata --repeat 8 \
410
+ --max-tool-calls 80 --out /tmp/exp5-strata
411
+ node scripts/analyze-experiment.mjs --runs /tmp/exp5-strata --runs /tmp/exp5-pidev
412
+ ```
413
+
414
+ ## Limiti noti
415
+
416
+ - Il chunker è euristico (regex per famiglia): nessun parser AST, nessun
417
+ call graph. Gli errori di confine sono possibili e non etichettati.
418
+ - I chiamanti del bundle sono euristici (scansione dell'identificatore, non un
419
+ call graph): su un campione di 61 casi la precisione misurata è 92%. Il livello
420
+ import è più stretto: solo specifiche che risolvono a un unico file, 29/30 edge
421
+ senza ambiguità su `Strata`.
422
+ - I documenti di piano Markdown competono con il codice nella ricerca: il cap
423
+ di 2 risultati per file e il peso maggiore di path/simbolo mitigano, non
424
+ eliminano il problema.
425
+ - Query in italiano su codice con identificatori inglesi funzionano meno bene
426
+ delle query in inglese.
427
+ - Device e `dtype` fanno parte dell'identità dei vettori: cambiarli richiede
428
+ un re-index. Lo storage v2 lega manifest e vettori con SHA-256: anche un
429
+ salvataggio concorrente/incompleto non viene scambiato per un indice valido.
430
+ Gli indici vecchi senza digest richiedono ricostruzione. La directory è
431
+ unica per repo: processi con profili diversi possono sostituirla o renderla
432
+ temporaneamente indisponibile, mai riutilizzare vettori incompatibili.
433
+ - DirectML e CoreML richiedono ancora smoke test su Windows/macOS; WebGPU è
434
+ verificato solo sulla macchina Linux disponibile, non su tutte le GPU.
435
+ - I pesi sono ancora scaricati dalla revisione `main` del modello; il cache non
436
+ viene aggiornato automaticamente. Prima di un rilascio riproducibile occorre
437
+ fissare uno snapshot dei pesi e verificarne l'integrità.
438
+
439
+ ## Licenza
440
+
441
+ Il codice di pi-codeindex è distribuito sotto licenza [MIT](LICENSE).
442
+ Dipendenze, sorgenti upstream scaricati dal setup e pesi del modello mantengono
443
+ le rispettive licenze; non sono inclusi nel tarball del pacchetto.
@@ -0,0 +1,19 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "title": "pi-codeindex — configurazione embedding locali",
4
+ "type": "object",
5
+ "additionalProperties": false,
6
+ "properties": {
7
+ "$schema": { "type": "string" },
8
+ "device": { "enum": ["auto", "cpu", "cuda", "webgpu", "dml", "coreml"], "default": "auto", "description": "Per Vulkan forzato usa webgpu con webgpuBackend: vulkan. auto prova i provider presenti per piattaforma, poi CPU." },
9
+ "dtype": { "enum": ["auto", "q8", "q4", "fp16"], "default": "auto", "description": "auto: q8 su CPU, fp16 sugli altri provider. Cambiarlo richiede reindex." },
10
+ "webgpuBackend": { "enum": ["auto", "vulkan"], "default": "auto", "description": "Backend Dawn quando il provider effettivo è webgpu. vulkan forza Vulkan e richiede setup-vulkan (inizialmente Linux x64). Non influenza CPU/CUDA/DirectML/CoreML." },
11
+ "fallback": { "enum": ["error", "cpu"], "default": "error", "description": "Fallback consentito per un device forzato; auto include sempre CPU." },
12
+ "offline": { "type": "boolean", "default": false },
13
+ "cacheDir": { "type": "string", "minLength": 1, "pattern": "\\S", "description": "Cache dei pesi. Supporta ~/; i percorsi relativi sono risolti dal cwd." },
14
+ "cpuThreads": { "type": "integer", "minimum": 0, "maximum": 256, "default": 0, "description": "0 usa il default di ONNX Runtime; non limita la GPU." },
15
+ "serviceDir": { "type": "string", "minLength": 1, "pattern": "\\S", "description": "Directory privata del servizio condiviso. Default ~/.cache/pi-codeindex/service; non cambiarla fra sessioni se vuoi condividere il modello." },
16
+ "servicePort": { "type": "integer", "anyOf": [{ "const": 0 }, { "minimum": 1024, "maximum": 65535 }], "default": 0, "description": "0 sceglie una porta loopback deterministica dalla directory del servizio. Cambiarla crea un endpoint distinto." },
17
+ "serviceIdleMs": { "type": "integer", "minimum": 1000, "maximum": 86400000, "default": 300000, "description": "Inattività prima di terminare il processo e liberare il modello (default 5 minuti). Status non rinnova il timer." }
18
+ }
19
+ }
@@ -0,0 +1,8 @@
1
+ {"query":"dove viene stimato il numero di token BPE di un messaggio","expects":["bpe-token-estimator"],"why":"estimatore token BPE dedicato"}
2
+ {"query":"come viene applicata una modifica ancorata a un file","expects":["anchored-edit"],"why":"motore delle modifiche ancorate"}
3
+ {"query":"ricerca nella history canonica delle sessioni","expects":["history-service","history-source-reader","context-history-tool"],"why":"lettura e ricerca della history"}
4
+ {"query":"coordinamento della compaction tra più sessioni","expects":["compaction-coordinator"],"why":"coordinatore della compaction"}
5
+ {"query":"lock per evitare rebase concorrenti di una sessione","expects":["rebase-lock"],"why":"lock di rebase"}
6
+ {"query":"quali artefatti vengono conservati e per quanto tempo","expects":["ARTIFACTS.md","artifacts"],"why":"documentazione sugli artefatti"}
7
+ {"query":"marker di omissione per non riesportare dati già visti","expects":["egress"],"why":"gestione egress e marker di omissione"}
8
+ {"query":"indicizzazione incrementale delle sessioni salvate","expects":["session-indexer"],"why":"indice incrementale delle sessioni"}
package/package.json CHANGED
@@ -1,6 +1,36 @@
1
1
  {
2
2
  "name": "@alucard_24/pi-codeindex",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.1.0",
4
+ "description": "Indice semantico locale del codice per pi (EmbeddingGemma 2, ONNX)",
5
+ "license": "MIT",
6
+ "author": "Alucard24",
7
+ "repository": { "type": "git", "url": "git+https://github.com/Alucard24/pi-codeindex.git" },
8
+ "homepage": "https://www.npmjs.com/package/@alucard_24/pi-codeindex",
9
+ "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org/" },
10
+ "main": "./src/extension.js",
11
+ "bin": { "pi-codeindex": "src/cli.js" },
12
+ "files": ["src", "scripts/setup-gpu.sh", "scripts/setup-vulkan.mjs", "scripts/vulkan-sources.json", "eval/queries.jsonl", "config.schema.json", "README.md", "CHANGELOG.md", "LICENSE"],
13
+ "engines": { "node": ">=22" },
14
+ "scripts": {
15
+ "test": "node --test 'test/*.test.js'",
16
+ "embed-test": "node src/cli.js embed-test",
17
+ "setup-gpu": "bash scripts/setup-gpu.sh",
18
+ "setup-vulkan": "node scripts/setup-vulkan.mjs",
19
+ "doctor": "node src/cli.js doctor"
20
+ },
21
+ "keywords": ["pi-package", "embeddings", "code-search"],
22
+ "type": "module",
23
+ "pi": {
24
+ "extensions": [
25
+ "./src/extension.js"
26
+ ]
27
+ },
28
+ "dependencies": {
29
+ "@huggingface/transformers": "4.3.2",
30
+ "onnxruntime-node": "1.30.0"
31
+ },
32
+ "peerDependencies": {
33
+ "@earendil-works/pi-ai": "*",
34
+ "@earendil-works/pi-coding-agent": "*"
35
+ }
6
36
  }
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env bash
2
+ # Abilita il provider CUDA di onnxruntime-node (Linux x64, GPU NVIDIA).
3
+ #
4
+ # 1. scarica i binari del provider CUDA se mancano (script ufficiale ORT);
5
+ # 2. trova le librerie CUDA 13 richieste dal provider 1.30 (libcublasLt.so.13,
6
+ # libcudart.so.13, libcurand.so.10, ...);
7
+ # 3. scrive un RUNPATH nel .so del provider: così la GPU funziona senza
8
+ # esportare LD_LIBRARY_PATH (necessario perché l'estensione pi gira
9
+ # dentro un processo già avviato).
10
+ #
11
+ # Idempotente. Da rieseguire dopo `npm install` (node_modules viene ricreato).
12
+ set -euo pipefail
13
+
14
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
15
+ if ! node -e 'process.exit(process.platform === "linux" && process.arch === "x64" ? 0 : 1)'; then
16
+ echo "[gpu] setup CUDA disponibile solo su Linux x64; usa doctor per i backend della tua piattaforma." >&2
17
+ exit 1
18
+ fi
19
+ # Funziona anche con dipendenze npm hoisted, non solo con node_modules locale.
20
+ ORT="$(node --input-type=module - "$ROOT/package.json" <<'JS'
21
+ import { createRequire } from 'node:module';
22
+ import path from 'node:path';
23
+ console.log(path.dirname(createRequire(process.argv[2]).resolve('onnxruntime-node/package.json')));
24
+ JS
25
+ )"
26
+ PROVIDER="$(find "$ORT/bin" -path '*/linux/x64/libonnxruntime_providers_cuda.so' | head -1 || true)"
27
+ BIN_DIR="$(dirname "${PROVIDER:-$ORT/bin/napi-v6/linux/x64/x}")"
28
+
29
+ if [[ ! -f "$PROVIDER" ]]; then
30
+ echo "[gpu] provider CUDA assente: lo scarico (≈270 MB)…"
31
+ node "$ORT/script/install.js" --onnxruntime-node-install=cuda12
32
+ PROVIDER="$BIN_DIR/libonnxruntime_providers_cuda.so"
33
+ fi
34
+
35
+ find_cuda_lib() {
36
+ local d
37
+ for d in \
38
+ "${CUDA13_LIB:-}" \
39
+ "$HOME"/.local/cuda-13*/targets/*/lib \
40
+ /usr/local/cuda-13*/targets/*/lib \
41
+ /usr/local/cuda/lib64 \
42
+ "$HOME"/.local/venv-cu13/lib/python*/site-packages/nvidia/cu13/lib \
43
+ /opt/cuda/lib64; do
44
+ [[ -n "$d" && -e "$d/libcublasLt.so.13" ]] && { echo "$d"; return 0; }
45
+ done
46
+ return 1
47
+ }
48
+
49
+ CUDA_LIB="$(find_cuda_lib || true)"
50
+ if [[ -z "$CUDA_LIB" ]]; then
51
+ echo "[gpu] ERRORE: non trovo libcublasLt.so.13 (serve il runtime CUDA 13)." >&2
52
+ echo " Installa CUDA 13 o imposta CUDA13_LIB=/percorso/lib." >&2
53
+ exit 1
54
+ fi
55
+
56
+ command -v patchelf >/dev/null || { echo "[gpu] ERRORE: patchelf non installato." >&2; exit 1; }
57
+
58
+ echo "[gpu] CUDA libs: $CUDA_LIB"
59
+ patchelf --set-rpath "$CUDA_LIB" "$PROVIDER"
60
+ if LD_LIBRARY_PATH= ldd "$PROVIDER" | grep -q "not found"; then
61
+ echo "[gpu] ERRORE: dipendenze non risolte:" >&2
62
+ LD_LIBRARY_PATH= ldd "$PROVIDER" | grep "not found" >&2
63
+ exit 1
64
+ fi
65
+ echo "[gpu] ok: provider CUDA pronto (nessun LD_LIBRARY_PATH richiesto)"