Agent IA planificateur EVCS en MODE OMBRE (Advisor Shadow V1)

- Workflow n8n tdfInZns7cqo8fU2 actif (15 min): snapshot HA compact -> prompt FR
  -> LLM local Spark (modèle dynamique via /v1/models) avec fallback OpenRouter
  claude-haiku-4.5 (credential chiffré, clé hors git) -> validation stricte
  (enums, bornes, rejet total si invalide) -> helpers advisor_* + divergence
  + compteurs accord/divergence + logbook.
- GARANTIE OMBRE structurelle: écritures limitées à advisor_*/logbook,
  vérifiée par tests/advisor/run.mjs (16 tests, bloquants au push).
- Kill-switch input_boolean.evcs_advisor_enabled.
- Extension R2 multi-workflows (lib-node-map WORKFLOWS[], build/extract/push
  par fichier, n8n-create.mjs, gen-advisor-workflow.mjs).
- Helpers HA via package NFS + carte dashboard EVCS Master (backup fait).
- 1re reco réelle: auto_solar_plus, cible 35%, accord avec le réel.
- Fix sécurité n8n-push: plus de fallback d'id implicite vers le workflow EVCS.
This commit is contained in:
Tallagrand Thierry
2026-08-07 22:42:06 +02:00
parent 1ae8129658
commit 63d56bf284
13 changed files with 1282 additions and 69 deletions

37
tools/n8n-create.mjs Normal file
View File

@@ -0,0 +1,37 @@
#!/usr/bin/env node
// Crée un workflow n8n depuis un fichier JSON local (POST /api/v1/workflows).
// Usage: node tools/n8n-create.mjs <fichier.json>
import fs from 'fs';
import os from 'os';
import path from 'path';
const INPUT = process.argv[2];
if (!INPUT) { console.error('Usage: node tools/n8n-create.mjs <fichier.json>'); process.exit(1); }
const local = JSON.parse(fs.readFileSync(INPUT, 'utf8'));
const cfg = JSON.parse(fs.readFileSync(path.join(os.homedir(), '.config/opencode/opencode.json'), 'utf8'));
const env = cfg.mcp['n8n-mcp'].environment;
const url = env.N8N_API_URL.replace(/\/api\/v1\/?$/, '');
const headers = { 'X-N8N-API-KEY': env.N8N_API_KEY, 'Content-Type': 'application/json' };
const body = {
name: local.name,
nodes: local.nodes,
connections: local.connections,
settings: {
executionOrder: local.settings?.executionOrder || 'v1',
callerPolicy: local.settings?.callerPolicy || 'workflowsFromSameOwner',
},
};
const res = await fetch(`${url}/api/v1/workflows`, { method: 'POST', headers, body: JSON.stringify(body) });
const text = await res.text();
if (!res.ok) {
console.error(`CRÉATION REFUSÉE: ${res.status} ${res.statusText}`);
console.error(text.slice(0, 1000));
process.exit(1);
}
const created = JSON.parse(text);
console.log(`Créé: "${created.name}" id=${created.id} (active=${created.active})`);
console.log(`→ reporter l'id dans le fichier local si besoin: ${INPUT}`);