pi-jev-guard 0.1.5 → 0.1.6
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 +3 -0
- package/extensions/index.ts +12 -9
- package/package.json +7 -1
- package/src/store-models.ts +47 -0
package/README.md
CHANGED
|
@@ -45,6 +45,9 @@ In chat, l'LLM può chiamare `jev_validate` per controlli mirati.
|
|
|
45
45
|
|
|
46
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
47
|
|
|
48
|
+
In `automatic` il twin viene registrato già all'avvio (prima del ripristino del
|
|
49
|
+
modello di sessione), così la sessione può riaprire direttamente su `__jev`.
|
|
50
|
+
|
|
48
51
|
Torna normale con `/model` (modello normale) + `/jev mode on-demand`.
|
|
49
52
|
In `automatic`, selezionare un modello non protetto lo fa ritornare
|
|
50
53
|
subito al twin (enforcement a livello selezione).
|
package/extensions/index.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { ExtensionAPI, ExtensionContext, ModelRegistry } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import type { Model, Provider } from "@earendil-works/pi-ai";
|
|
3
3
|
import type { Api } from "@earendil-works/pi-ai";
|
|
4
|
-
import { builtinProviders } from "@earendil-works/pi-ai/providers/all";
|
|
5
|
-
import { registerJevCommand, type UpstreamResult } from "../src/commands.ts";
|
|
4
|
+
import { builtinProviders } from "@earendil-works/pi-ai/providers/all";import { registerJevCommand, type UpstreamResult } from "../src/commands.ts";
|
|
6
5
|
import { registerJevAskTool } from "../src/ask.ts";
|
|
7
6
|
import {
|
|
8
7
|
configSnapshot,
|
|
@@ -22,8 +21,8 @@ import {
|
|
|
22
21
|
twinIdFor,
|
|
23
22
|
} from "../src/automatic/overlay.ts";
|
|
24
23
|
import type { GateVerdictReport } from "../src/automatic/guardian.ts";
|
|
25
|
-
import {
|
|
26
|
-
import { elideWithMarker } from "../src/reviewer.ts";
|
|
24
|
+
import { readStoreModels } from "../src/store-models.ts";
|
|
25
|
+
import { DEFAULT_GATE_RULES, elideWithMarker } from "../src/reviewer.ts";
|
|
27
26
|
import {
|
|
28
27
|
TOOL_POLICY_REVISION,
|
|
29
28
|
checkFilePath,
|
|
@@ -331,12 +330,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
331
330
|
// provider non lo è e fallirebbe a load (solo installazioni npm).
|
|
332
331
|
const base = builtinProviders().find((p) => p.id === seedTarget?.provider);
|
|
333
332
|
if (!base) throw new Error(`provider ${seedTarget.provider} not in builtins`);
|
|
334
|
-
// Il catalogo builtin può non avere il modello salvato
|
|
335
|
-
//
|
|
336
|
-
|
|
337
|
-
|
|
333
|
+
// Il catalogo builtin può non avere il modello salvato: provider
|
|
334
|
+
// dinamici (es. openai-codex) tengono la lista nel models-store,
|
|
335
|
+
// altri (deepseek-flash su versioni vecchie) in una definizione statica.
|
|
336
|
+
const storeModels = readStoreModels(seedTarget.provider);
|
|
337
|
+
const extra = [
|
|
338
|
+
...(seedTarget.provider === "deepseek" && seedTarget.model === "deepseek-flash"
|
|
338
339
|
? [STATIC_DEEPSEEK_FLASH]
|
|
339
|
-
: []
|
|
340
|
+
: []),
|
|
341
|
+
...storeModels,
|
|
342
|
+
];
|
|
340
343
|
const seedUpstream: Provider = {
|
|
341
344
|
...base,
|
|
342
345
|
getModels: () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-jev-guard",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Jev validation guard for pi: on-demand tool + automatic provider gate. Dual backend: TypeSafe direct + OpenRouter.",
|
|
6
6
|
"keywords": [
|
|
@@ -46,5 +46,11 @@
|
|
|
46
46
|
"typebox": "1.3.34",
|
|
47
47
|
"typescript": "5.9.3",
|
|
48
48
|
"vitest": "5.0.1"
|
|
49
|
+
},
|
|
50
|
+
"allowScripts": {
|
|
51
|
+
"@google/genai@1.52.0": true,
|
|
52
|
+
"@openrouter/sdk@1.3.1": true,
|
|
53
|
+
"protobufjs@7.6.6": true,
|
|
54
|
+
"esbuild@0.28.2": true
|
|
49
55
|
}
|
|
50
56
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lettura read-only dei modelli dinamici dal models-store di pi.
|
|
3
|
+
*
|
|
4
|
+
* Alcuni provider (es. openai-codex) non hanno modelli nel catalogo statico:
|
|
5
|
+
* la lista arriva da `<agentDir>/models-store.json` e viene popolata al
|
|
6
|
+
* refresh con le credenziali. Senza questo, il seed all'avvio non troverebbe
|
|
7
|
+
* il modello e il twin non esisterebbe al momento del ripristino sessione.
|
|
8
|
+
*
|
|
9
|
+
* Solo lettura, best-effort: file assente/corrotto → nessun modello.
|
|
10
|
+
*/
|
|
11
|
+
import { readFileSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
14
|
+
import type { Api, Model } from "@earendil-works/pi-ai";
|
|
15
|
+
|
|
16
|
+
export function modelsStorePath(agentDir?: string): string {
|
|
17
|
+
return join(agentDir ?? getAgentDir(), "models-store.json");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function isUsableModel(value: unknown, providerId: string): value is Model<Api> {
|
|
21
|
+
if (typeof value !== "object" || value === null) return false;
|
|
22
|
+
const m = value as Record<string, unknown>;
|
|
23
|
+
return (
|
|
24
|
+
typeof m.id === "string" &&
|
|
25
|
+
m.id.length > 0 &&
|
|
26
|
+
typeof m.api === "string" &&
|
|
27
|
+
m.api.length > 0 &&
|
|
28
|
+
(m.provider === undefined || m.provider === providerId)
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Modelli salvati nello store per un provider, normalizzati sull'id richiesto. */
|
|
33
|
+
export function readStoreModels(providerId: string, agentDir?: string): Model<Api>[] {
|
|
34
|
+
try {
|
|
35
|
+
const raw = JSON.parse(readFileSync(modelsStorePath(agentDir), "utf8")) as Record<
|
|
36
|
+
string,
|
|
37
|
+
{ models?: unknown }
|
|
38
|
+
>;
|
|
39
|
+
const entry = raw?.[providerId];
|
|
40
|
+
const models = Array.isArray(entry?.models) ? entry.models : [];
|
|
41
|
+
return models
|
|
42
|
+
.filter((m) => isUsableModel(m, providerId))
|
|
43
|
+
.map((m) => ({ ...(m as Model<Api>), provider: providerId }));
|
|
44
|
+
} catch {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
}
|