#!/usr/bin/env node // Génère workflows/evcs-advisor-shadow-v1.json (squelette : nodes, connexions, // credentials, positions). Le CODE des nodes est ensuite injecté depuis // src/advisor/ par tools/n8n-build.mjs (source de vérité R2). // Rejouable : écrase le fichier local (pas le serveur). import fs from 'fs'; const HA_CRED = { id: 'uv3sknYYigxBkaVN', name: 'Bearer Auth account 2' }; const OPENROUTER_CRED = { id: 'eOM9xofDHT0KMoeY', name: 'OpenRouter Advisor' }; const SPARK_URL = 'http://10.10.10.8:8000'; const CLOUD_MODEL = 'anthropic/claude-haiku-4.5'; const HA_URL = 'http://10.10.10.17:8123'; const nodes = [ { name: 'Schedule Trigger', type: 'n8n-nodes-base.scheduleTrigger', typeVersion: 1.2, position: [0, 0], parameters: { rule: { interval: [{ field: 'minutes', minutesInterval: 15 }] } }, }, { name: 'HA Snapshot Advisor', type: 'n8n-nodes-base.httpRequest', typeVersion: 4.2, position: [200, 0], parameters: { method: 'POST', url: `${HA_URL}/api/template`, authentication: 'genericCredentialType', genericAuthType: 'httpBearerAuth', sendHeaders: true, headerParameters: { parameters: [ { name: 'Content-Type', value: 'application/json' }, { name: 'Accept', value: 'text/plain' }, ], }, sendBody: true, bodyParameters: { parameters: [{ name: 'template', value: '(injecté depuis src/advisor)' }] }, options: { timeout: 15000 }, }, credentials: { httpBearerAuth: HA_CRED }, }, { name: 'BUILD_PROMPT', type: 'n8n-nodes-base.code', typeVersion: 2, position: [400, 0], parameters: { jsCode: '// injecté depuis src/advisor/BUILD_PROMPT.js' }, }, { name: 'IF_ENABLED', type: 'n8n-nodes-base.if', typeVersion: 2.2, position: [600, 0], parameters: { conditions: { options: { caseSensitive: true, leftValue: '', typeValidation: 'loose', version: 2 }, combinator: 'and', conditions: [ { leftValue: '={{ $json.enabled }}', rightValue: '', operator: { type: 'boolean', operation: 'true', singleValue: true }, }, ], }, }, }, { name: 'LLM_LOCAL_MODELS', type: 'n8n-nodes-base.httpRequest', typeVersion: 4.2, position: [800, -100], parameters: { method: 'GET', url: `${SPARK_URL}/v1/models`, options: { timeout: 5000 }, }, onError: 'continueRegularOutput', alwaysOutputData: true, }, { name: 'LLM_LOCAL', type: 'n8n-nodes-base.httpRequest', typeVersion: 4.2, position: [1000, -100], parameters: { method: 'POST', url: `${SPARK_URL}/v1/chat/completions`, sendHeaders: true, headerParameters: { parameters: [{ name: 'Content-Type', value: 'application/json' }] }, sendBody: true, specifyBody: 'json', jsonBody: "={{ JSON.stringify({ model: $('LLM_LOCAL_MODELS').first().json.data[0].id, messages: $('BUILD_PROMPT').first().json.messages, temperature: 0.1, max_tokens: 6000 }) }}", options: { timeout: 120000 }, }, onError: 'continueRegularOutput', alwaysOutputData: true, }, { name: 'IF_LOCAL_OK', type: 'n8n-nodes-base.if', typeVersion: 2.2, position: [1200, -100], parameters: { conditions: { options: { caseSensitive: true, leftValue: '', typeValidation: 'loose', version: 2 }, combinator: 'and', conditions: [ { leftValue: "={{ $json.choices !== undefined && $json.choices.length > 0 }}", rightValue: '', operator: { type: 'boolean', operation: 'true', singleValue: true }, }, ], }, }, }, { name: 'LLM_CLOUD', type: 'n8n-nodes-base.httpRequest', typeVersion: 4.2, position: [1400, 40], parameters: { method: 'POST', url: 'https://openrouter.ai/api/v1/chat/completions', authentication: 'genericCredentialType', genericAuthType: 'httpHeaderAuth', sendHeaders: true, headerParameters: { parameters: [{ name: 'Content-Type', value: 'application/json' }] }, sendBody: true, specifyBody: 'json', jsonBody: `={{ JSON.stringify({ model: '${CLOUD_MODEL}', messages: $('BUILD_PROMPT').first().json.messages, temperature: 0.1, max_tokens: 1000 }) }}`, options: { timeout: 60000 }, }, credentials: { httpHeaderAuth: OPENROUTER_CRED }, onError: 'continueRegularOutput', alwaysOutputData: true, }, { name: 'VALIDATE_PARSE', type: 'n8n-nodes-base.code', typeVersion: 2, position: [1600, -30], parameters: { jsCode: '// injecté depuis src/advisor/VALIDATE_PARSE.js' }, }, { name: 'BUILD_HA_CALLS', type: 'n8n-nodes-base.code', typeVersion: 2, position: [1800, -30], parameters: { jsCode: '// injecté depuis src/advisor/BUILD_HA_CALLS.js' }, }, { name: 'Execute HA Service Advisor', type: 'n8n-nodes-base.httpRequest', typeVersion: 4.2, position: [2000, -30], parameters: { method: 'POST', url: "={{ 'http://10.10.10.17:8123/api/services/' + $json.domain + '/' + $json.service }}", authentication: 'genericCredentialType', genericAuthType: 'httpBearerAuth', sendHeaders: true, headerParameters: { parameters: [ { name: 'Content-Type', value: 'application/json' }, { name: 'accept', value: 'application/json' }, ], }, sendBody: true, specifyBody: 'json', jsonBody: '={{ $json.data }}', options: { timeout: 15000 }, }, credentials: { httpBearerAuth: HA_CRED }, onError: 'continueRegularOutput', }, ]; const connections = { 'Schedule Trigger': { main: [[{ node: 'HA Snapshot Advisor', type: 'main', index: 0 }]] }, 'HA Snapshot Advisor': { main: [[{ node: 'BUILD_PROMPT', type: 'main', index: 0 }]] }, BUILD_PROMPT: { main: [[{ node: 'IF_ENABLED', type: 'main', index: 0 }]] }, IF_ENABLED: { main: [[{ node: 'LLM_LOCAL_MODELS', type: 'main', index: 0 }], []] }, LLM_LOCAL_MODELS: { main: [[{ node: 'LLM_LOCAL', type: 'main', index: 0 }]] }, LLM_LOCAL: { main: [[{ node: 'IF_LOCAL_OK', type: 'main', index: 0 }]] }, IF_LOCAL_OK: { main: [ [{ node: 'VALIDATE_PARSE', type: 'main', index: 0 }], [{ node: 'LLM_CLOUD', type: 'main', index: 0 }], ], }, LLM_CLOUD: { main: [[{ node: 'VALIDATE_PARSE', type: 'main', index: 0 }]] }, VALIDATE_PARSE: { main: [[{ node: 'BUILD_HA_CALLS', type: 'main', index: 0 }]] }, BUILD_HA_CALLS: { main: [[{ node: 'Execute HA Service Advisor', type: 'main', index: 0 }]] }, }; const workflow = { name: 'EVCS Advisor Shadow V1', nodes, connections, settings: { executionOrder: 'v1', callerPolicy: 'workflowsFromSameOwner' }, staticData: null, }; fs.writeFileSync('workflows/evcs-advisor-shadow-v1.json', JSON.stringify(workflow, null, 2) + '\n'); console.log(`Squelette écrit: workflows/evcs-advisor-shadow-v1.json (${nodes.length} nodes)`); console.log('→ lancer: node tools/n8n-build.mjs workflows/evcs-advisor-shadow-v1.json');