#!/usr/bin/env node /** * Tooling Прил.Н dormancy extractor — emits {id: unavailable_bool} JSON for * the missed-activation matcher (Pravila §16.4 conditional rule). * * Two signals (either is sufficient) treat a node as effectively unavailable: * 1. `dormant: true` — Tooling-marked permanent dormancy (e.g. #17 pg_partman, * native Windows-PG cannot load the extension). * 2. `boundaries` column contains the word DEFERRED — node is registered * but not active (e.g. #44 Figma MCP "DEFERRED — нет Figma-аккаунта", * #50 Jupyter MCP, #54 n8n-mcp). The output key is still named "dormant" * for consumer simplicity — semantics: "node cannot be activated right * now, exclude from missed-activation counts". * * Parses 9-attribute table rows; ignores headers/separators/templates. * * Security Guidance #40: pure parsing — no exec/execSync. */ import { readFileSync, writeFileSync } from 'fs'; const ROW_RE = /^\|\s*#(\d+)\s*\|[^|]+\|[^|]+\|[^|]+\|[^|]+\|[^|]+\|([^|]+)\|\s*(true|false)\s*\|[^|]+\|$/gm; export function extractDormancy(md) { const out = {}; for (const m of md.matchAll(ROW_RE)) { const id = `#${m[1]}`; const boundaries = m[2]; const tooledDormant = m[3] === 'true'; out[id] = tooledDormant || /\bDEFERRED\b/.test(boundaries); } return out; } if (process.argv[1] && process.argv[1].replace(/\\/g, '/').endsWith('/extract-node-dormancy.mjs')) { const src = readFileSync('docs/Tooling_v8_3.md', 'utf-8'); const dormancy = extractDormancy(src); writeFileSync('tools/.node-dormancy.json', JSON.stringify(dormancy, null, 2) + '\n'); console.log(`[extract-node-dormancy] OK — ${Object.keys(dormancy).length} nodes`); }