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 +142 -0
- package/config/jev-config.example.json +61 -0
- package/extensions/index.ts +692 -0
- package/package.json +39 -0
- package/skills/jev-review/SKILL.md +25 -0
- package/src/adapters/openrouter.ts +289 -0
- package/src/adapters/typesafe.ts +244 -0
- package/src/ask.ts +189 -0
- package/src/automatic/gate.ts +45 -0
- package/src/automatic/guardian.ts +320 -0
- package/src/automatic/overlay.ts +247 -0
- package/src/automatic/recovery.ts +32 -0
- package/src/automatic/serialize.ts +278 -0
- package/src/cache.ts +56 -0
- package/src/commands.ts +408 -0
- package/src/config.ts +385 -0
- package/src/exfil.ts +180 -0
- package/src/factory.ts +140 -0
- package/src/markdown.ts +26 -0
- package/src/metrics.ts +69 -0
- package/src/output-judge.ts +176 -0
- package/src/policy.ts +32 -0
- package/src/reviewer.ts +350 -0
- package/src/tools-policy.ts +128 -0
- package/src/tools.ts +43 -0
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
|
+
}
|