Files
SLACK_COORD_RELATORIO/tools/build-workflow.js
T
GustavoandClaude Sonnet 5 a99a25cb1a feat(v2): complete n8n workflow template (36 nodes) covering full V2 pipeline + shadow branch
- 14 new Code node drivers implementing the pipeline stages: normalize
  candidates, build context SQL, merge context + hash, decide AI need,
  prepare AI prompt, validate AI response, AI-disabled fallback, reuse
  cached classification, compute score, select top 10, prepare memory/
  envio records, build message/digest, compare legacy x V2, debug panel.
- Consolidated the two context queries (followups/tasks) into a single
  UNION ALL query tagged by tipo, and added a "Merge - Unir Shadow"
  synchronization node before comparing legacy x V2: n8n does not
  guarantee relative execution order between sibling branches that only
  share an early common ancestor, so cross-branch data was only safe to
  read by name once a real Merge node forced both to complete first.
- Reordered score calculation before the memory upsert (score is needed
  in the persisted row) and turned both Data Table writes into
  side-effect branches that fan out from the main path instead of
  gating it, so the Data Table node's own output shape never needs to
  carry the full pipeline state forward.
- Fixed a duplicate-identifier bug in the build script: score.js's
  require('./cooldown') survived inlining and collided with
  cooldown.js's own computeCooldown function in the same Code node
  scope. build-workflow.js now strips inter-module requires when
  inlining, and a new test syntax-checks every generated jsCode string
  plus asserts no leftover require() calls.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-24 15:31:44 -03:00

64 lines
2.6 KiB
JavaScript

const fs = require('node:fs');
const path = require('node:path');
const ROOT = path.join(__dirname, '..');
function readLogicSource(fileName) {
const raw = fs.readFileSync(path.join(ROOT, 'logic', fileName), 'utf8');
return raw
// Remove a linha final "module.exports = {...}" -- as funcoes ficam soltas no escopo do node.
.replace(/module\.exports\s*=\s*\{[\s\S]*?\};?\s*$/m, '')
// Remove requires de outros modulos de logic/*.js -- quando inlined, a funcao requerida
// ja esta no mesmo escopo (senao vira identificador duplicado: function X + const {X} = require(...)).
.replace(/^const\s*\{[^}]*\}\s*=\s*require\(['"]\.\/[a-zA-Z0-9_-]+['"]\);?\s*$/gm, '')
.trim();
}
function inlinedLogic(fileNames) {
return fileNames.map(readLogicSource).join('\n\n');
}
function sqlAsJsTemplateLiteral(sqlRelativePath) {
const sql = fs.readFileSync(path.join(ROOT, sqlRelativePath), 'utf8');
const escaped = sql.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$\{/g, '\\${');
return `\`${escaped}\``;
}
function buildDriverCode(driverRelativePath) {
const driverPath = path.join(ROOT, 'n8n', 'nodes', driverRelativePath);
let driver = fs.readFileSync(driverPath, 'utf8');
const requiresMatch = driver.match(/^\/\/ @requires (.+)$/m);
const requiredLogicFiles = requiresMatch ? requiresMatch[1].trim().split(/\s+/) : [];
driver = driver.replace(/^\/\/ @requires .+\n/m, '');
driver = driver.replace('/* __SQL_CANDIDATOS_V2__ */', sqlAsJsTemplateLiteral('sql/candidatos_v2_glpi.sql'));
driver = driver.replace('/* __SQL_LEGADO_V1_VERBATIM__ */', sqlAsJsTemplateLiteral('sql/top_10_chamados_abertos_glpi.sql'));
driver = driver.replace('/* __SQL_CONTEXTO__ */', sqlAsJsTemplateLiteral('sql/contexto_glpi.sql'));
const logicBlock = requiredLogicFiles.length ? `${inlinedLogic(requiredLogicFiles)}\n\n` : '';
return `${logicBlock}${driver.trim()}`;
}
function buildWorkflow() {
const templatePath = path.join(ROOT, 'n8n', 'workflow.template.json');
const template = JSON.parse(fs.readFileSync(templatePath, 'utf8'));
for (const node of template.nodes) {
if (node.type === 'n8n-nodes-base.code' && typeof node.parameters.jsCode === 'string') {
const marker = node.parameters.jsCode.match(/^__BUILD__:(.+)$/);
if (marker) {
node.parameters.jsCode = buildDriverCode(marker[1].trim());
}
}
}
return template;
}
if (require.main === module) {
process.stdout.write(JSON.stringify(buildWorkflow(), null, 2));
}
module.exports = { buildWorkflow, inlinedLogic, readLogicSource, sqlAsJsTemplateLiteral, buildDriverCode };