pi-jev-guard 0.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/README.md ADDED
@@ -0,0 +1,142 @@
1
+ # pi-jev-guard
2
+
3
+ Verifica le risposte con [TypeSafe Jev](https://docs.typesafe.ai) dentro [pi](https://pi.dev): un solo motore di validazione, due interfacce.
4
+
5
+ - **A richiesta** (default): tool `jev_validate`, comando `/jev check`, skill `jev-review`. Zero verifiche implicite, zero costi se non lo usi.
6
+ - **Domande tipate**: tool `jev_ask` per giudizi calibrati definiti dal modello (noul/choice/score) invece di prosa.
7
+ - **Automatica**: gemello guarded `<modello>__jev` dentro lo stesso provider, che trattiene la risposta, la verifica con Jev e pubblica solo l'output approvato (con rigenerazione privata su `block`). Stessa auth del provider: nessun login extra, funziona anche con Codex/OAuth.
8
+ - **Giudice output** (solo `automatic`, fail-open): dopo ogni `bash` cerca secret nel testo e classifica i fallimenti, allegando un consiglio al risultato.
9
+
10
+ ## Installazione
11
+
12
+ ```bash
13
+ cd pi-jev-guard
14
+ npm install
15
+ mkdir -p ~/.pi/agent
16
+ cp config/jev-config.example.json ~/.pi/agent/jev-config.json
17
+ pi install "$PWD"
18
+ ```
19
+
20
+ Chiavi (a seconda del backend Jev scelto):
21
+
22
+ ```bash
23
+ export OPENROUTER_API_KEY="sk-or-v1-..." # backend openrouter (default)
24
+ export TYPESAFE_API_KEY="..." # backend typesafe diretto
25
+ ```
26
+
27
+ ## Uso normale (invariato)
28
+
29
+ Con l'estensione installata non cambia nulla finché non la usi: i modelli normali restano selezionabili e nessuna verifica parte da sola (`mode: on-demand`).
30
+
31
+ ```text
32
+ /jev check ./src/example.ts # verifica singola di un file
33
+ /jev status # stato completo
34
+ /jev help # tutti i sottocomandi
35
+ ```
36
+
37
+ In chat, l'LLM può chiamare `jev_validate` per controlli mirati.
38
+
39
+ ## Uso protetto
40
+
41
+ ```text
42
+ /jev upstream deepseek deepseek-flash # crea deepseek/deepseek-flash__jev
43
+ /jev mode automatic # seleziona il twin + attiva enforcement
44
+ ```
45
+
46
+ Nessun login extra: il twin vive nello stesso provider e riusa la credenziale già configurata (env, stored, OAuth/SSO come Codex business plan). I modelli originali restano intatti e selezionabili.
47
+
48
+ Torna normale con `/model` (modello normale) + `/jev mode on-demand`.
49
+ In `automatic`, selezionare un modello non protetto lo fa ritornare
50
+ subito al twin (enforcement a livello selezione).
51
+ `/jev upstream` senza argomenti ripristina l'ultimo salvato, `/jev off` rimuove il twin
52
+ (e torna a on-demand, provider originale ripristinato). In `automatic` il twin
53
+ si ripristina da solo al riavvio.
54
+
55
+ Se filtri i modelli con `enabledModels`, tieni la voce del twin (es.
56
+ `deepseek/deepseek-flash__jev`) o resta nascosto.
57
+ L'installazione punta alla cartella: dopo un aggiornamento del codice basta `/reload`.
58
+
59
+ Headless/CI: `JEV_AUTO_UPSTREAM=provider/model` crea il guarded all'avvio
60
+ (con `pi --print` solo `deepseek/deepseek-flash`).
61
+
62
+ ## Come decide
63
+
64
+ Jev risponde a domande `noul` (probabilità 0–1 di "sì, c'è la falla"):
65
+
66
+ | Regola | Gate automatic | On-demand |
67
+ |---|---|---|
68
+ | `sql_injection` | ✓ | ✓ |
69
+ | `unsafe_destructive_action` | ✓ | ✓ |
70
+ | `requirement_conflict` | — (requisiti chat troppo vaghi) | ✓ (requisiti espliciti) |
71
+
72
+ Soglie preliminari calibrate live (`docs/calibration-2026-09-19.md`):
73
+ `p ≤ 0.20` pass · `p ≥ 0.90` block · in mezzo review (trattenuto) ·
74
+ errori/timeout → unavailable (trattenuto). Mai approvazione su input troncato:
75
+ un pass parziale diventa review dichiarata. I candidati lunghi sono verificati
76
+ a chunk (copertura completa); i requisiti oltre 16k trattengono con nota.
77
+
78
+ In `automatic` è attiva anche una **tool policy deterministica** (costo zero):
79
+ blocca comandi distruttivi (`rm -rf /`, fork bomb, `mkfs`, `dd` su device…)
80
+ e scritture su path sensibili (`.env`, `.ssh/`, `*.pem`, `node_modules/`).
81
+ In `on-demand` non blocca nulla. Sempre in `automatic`, i comandi con tool
82
+ di rete (`curl`, `scp`, `ssh`…) passano un check semantico Jev
83
+ (destructive/exfiltration/beyond_scope/impact): su flag chiede conferma
84
+ in TUI, in headless solo avviso (fail-open).
85
+
86
+ Sempre in `automatic`, il **giudice output** esamina i risultati `bash`
87
+ (1 chiamata Jev per output nuovo, con cache 120s): se trova un secret
88
+ avvisa e dice di riferirsi al valore per nome; se è un errore, allega il
89
+ consiglio per la classe (`transient` → riprova, `code_bug` → fixa il codice…).
90
+ Non blocca mai; `/jev output` mostra l'ultimo verdetto.
91
+
92
+ ## Configurazione
93
+
94
+ `~/.pi/agent/jev-config.json` (o `$JEV_CONFIG`). Env: `JEV_MODE`, `JEV_BACKEND`
95
+ (`openrouter`|`typesafe`|`auto`), `JEV_MODEL`, `JEV_AUTO_UPSTREAM`.
96
+ Vedi `config/jev-config.example.json` per tutti i campi.
97
+
98
+ Chiave Jev (ordine: env vince sul file): `OPENROUTER_API_KEY` o
99
+ `TYPESAFE_API_KEY`, altrimenti `jev.apiKeyFile` (es.
100
+ `"~/.pi/agent/jev-api-key.txt"`, `~/` espanso, solo prima riga, permessi
101
+ `600` consigliati). `/jev status` mostra la sorgente (`env:VAR`,
102
+ `file:<path>`, o il motivo se assente) — mai il valore.
103
+
104
+ Per salvare la chiave stando dentro pi (senza passarla come argomento,
105
+ che resterebbe in history e transcript):
106
+
107
+ ```text
108
+ /jev save-key # chiede la chiave via dialogo, la scrive a 600, ricarica
109
+ ```
110
+
111
+ Nota: il dialogo TUI potrebbe fare echo nel terminale; per massima
112
+ paranoia usa la shell: `umask 077 && cat > ~/.pi/agent/jev-api-key.txt`.
113
+
114
+ I verdetti identici sono riusati per 120s (`reviewCache`, mai gli
115
+ `unavailable`): retry e batch paralleli costano una sola chiamata.
116
+ Gli input oltre i limiti sono marcati `…[N chars elided]` nel testo inviato
117
+ a Jev, mai troncati in silenzio.
118
+
119
+ Retry solo su transienti (`jev.retryTransients`, default 1 retry): 429/5xx
120
+ ed errori di connessione ritentano con backoff, timeout e auth mai — un
121
+ rate-limit non diventa più subito hold. `/jev last` mostra l'ultimo
122
+ verdetto del gate (esito, tentativi, controllo con p, backend, tempo).
123
+
124
+ ## Sviluppo
125
+
126
+ ```bash
127
+ npm run typecheck
128
+ npm run test:unit # mock, nessun costo
129
+ npm run test:integration
130
+ RUN_JEV_LIVE=1 npm run bench:jev # corpus live (costa poco)
131
+ echo '{"requirements":"...","candidate":"..."}' | npm run jev-check
132
+ ```
133
+
134
+ ## Limiti onesti
135
+
136
+ - `pass` = "supera i controlli configurati", non "corretto". Compilazione e test restano necessari.
137
+ - Il gate copre solo il twin `__jev` selezionato; in `automatic` la
138
+ selezione di altri modelli viene rifiutata con revert al twin.
139
+ (`/jev off` ripristina il provider originale intatto.)
140
+ - Soglie calibrate su 20 casi (`docs/calibration-2026-09-19.md`): buone per
141
+ iniziare, da rivalutare con corpus più ampio.
142
+ - Jev è un giudice probabilistico, non un verificatore formale.
@@ -0,0 +1,61 @@
1
+ {
2
+ "version": 1,
3
+ "mode": "on-demand",
4
+ "jev": {
5
+ "backend": "openrouter",
6
+ "modelTypesafe": "jev-1.13.0",
7
+ "modelOpenRouter": "typesafe/jev-1.13",
8
+ "timeoutMs": 4000,
9
+ "timeoutMsTypesafe": 1500,
10
+ "timeoutMsOpenRouter": 4000,
11
+ "retryTransients": { "enabled": true, "maxRetries": 1 },
12
+ "apiKeyFile": "~/.pi/agent/jev-api-key.txt"
13
+ },
14
+ "policy": {
15
+ "revision": "2026-09-19-live1",
16
+ "passMaxFlawProbability": 0.2,
17
+ "blockMinFlawProbability": 0.9,
18
+ "onUncertain": "hold",
19
+ "onUnavailable": "hold"
20
+ },
21
+ "automatic": {
22
+ "transport": "provider-gate",
23
+ "maxRegenerations": 2,
24
+ "requireGuardedModel": true,
25
+ "upstreamProvider": "deepseek",
26
+ "upstreamModel": "deepseek-flash"
27
+ },
28
+ "limits": {
29
+ "maxPayloadBytes": 120000,
30
+ "maxBufferedBytes": 1048576,
31
+ "maxCodeBlocks": 24,
32
+ "maxRequirementsChars": 16000,
33
+ "maxCandidateChars": 100000
34
+ },
35
+ "privacy": {
36
+ "logContent": false
37
+ },
38
+ "reviewCache": {
39
+ "enabled": true,
40
+ "cacheSeconds": 120
41
+ },
42
+ "toolsPolicy": {
43
+ "enabled": true
44
+ },
45
+ "outputJudge": {
46
+ "enabled": true,
47
+ "tools": ["bash"],
48
+ "outputChars": 2000,
49
+ "leakThreshold": 0.9,
50
+ "minConfidence": 0.6,
51
+ "cacheSeconds": 120
52
+ },
53
+ "exfilCheck": {
54
+ "enabled": true,
55
+ "tools": ["bash", "powershell"],
56
+ "blockOn": { "destructive": 0.9, "exfiltration": 0.7, "beyondScope": 0.85, "impact": 2.5 },
57
+ "minConfidence": 0.5,
58
+ "cacheSeconds": 120,
59
+ "blockWithoutUI": false
60
+ }
61
+ }