Files
Codex LocalandClaude Opus 4.6 cee246a6a9 Refonte globale P0→P9 : sécurité, V2 monorepo TypeScript, tests, tooling
- P0: Correctifs sécurité critiques (injection bash, path traversal, SSRF, rate limiting)
- P1: Audit logging, session pruning, WS validation, CSRF protection
- P2: Ollama SDK migration, admin API deduplication, attachment hardening
- P3: Node Engine store complet (graphs, runs, models, deployments)
- P4: Admin UI Node Engine (éditeur visuel, runs, queue viewer)
- P5: Persona pipeline (sources, feedback, Pharmacius, editorial)
- P6: V2 packages TypeScript (core, auth, chat-domain, persona-domain, node-engine, storage, tui)
- P7: V2 apps (api + worker + web React), ops TUI, migration/rollback scripts
- P8: Training adapters (TRL/Unsloth), sandboxing (subprocess/container), Turborepo, CI
- P9: Tests (102 backend node:test + 33 React Vitest/RTL), code quality review

135 tests, 0 failures. 8 packages + 3 apps V2. 42 modules V1 validés.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
2026-03-16 06:15:04 +01:00

127 lines
3.8 KiB
JavaScript

const fs = require("fs");
const path = require("path");
const vm = require("vm");
const { execFileSync } = require("child_process");
const ROOT_DIR = path.resolve(__dirname, "..");
function toRelative(file) {
return path.relative(ROOT_DIR, file).split(path.sep).join("/");
}
function listFiles(relativeDir, matcher, { recursive = false } = {}) {
const absoluteDir = path.join(ROOT_DIR, relativeDir);
if (!fs.existsSync(absoluteDir)) return [];
const found = [];
for (const entry of fs.readdirSync(absoluteDir, { withFileTypes: true })) {
const absoluteEntry = path.join(absoluteDir, entry.name);
if (entry.isDirectory()) {
if (recursive) {
found.push(...listFiles(path.join(relativeDir, entry.name), matcher, { recursive: true }));
}
continue;
}
if (matcher(absoluteEntry, entry.name)) {
found.push(toRelative(absoluteEntry));
}
}
return found;
}
function listRootFiles(matcher) {
return fs.readdirSync(ROOT_DIR, { withFileTypes: true })
.filter((entry) => entry.isFile() && matcher(entry.name))
.map((entry) => entry.name);
}
function uniqueSorted(files) {
return [...new Set(files)].sort((a, b) => a.localeCompare(b));
}
const NODE_CHECK_FILES = uniqueSorted([
...listRootFiles((name) => name.endsWith(".js")),
...listFiles("scripts", (_file, name) => name.endsWith(".js")),
...listFiles("public", (_file, name) => name.endsWith(".js")),
"public/admin/personas.js",
]);
const HTML_FILES = uniqueSorted(listFiles("public", (_file, name) => name.endsWith(".html"), { recursive: true }));
const JSON_FILES = uniqueSorted([
"package.json",
...listFiles("apps", (_file, name) => name === "package.json", { recursive: true }),
...listFiles("packages", (_file, name) => name === "package.json", { recursive: true }),
...listFiles("ops", (_file, name) => name.endsWith(".json"), { recursive: true }),
]);
const MODULE_JS_FILES = uniqueSorted([
...listFiles("public/admin", (_file, name) => name.endsWith(".js") && name !== "personas.js"),
...listFiles("public/admin/modules", (_file, name) => name.endsWith(".js")),
]);
function runNodeCheck(file) {
const absoluteFile = path.join(ROOT_DIR, file);
execFileSync(process.execPath, ["--check", absoluteFile], {
cwd: ROOT_DIR,
stdio: "pipe",
});
}
function compileInlineScripts(file) {
const absoluteFile = path.join(ROOT_DIR, file);
const html = fs.readFileSync(absoluteFile, "utf8");
const matches = [...html.matchAll(/<script>([\s\S]*?)<\/script>/g)];
const externalScripts = [...html.matchAll(/<script[^>]+src=["']([^"']+)["'][^>]*><\/script>/g)];
if (!matches.length) {
if (externalScripts.length) return;
throw new Error(`Aucun script inline ou externe trouvé dans ${file}`);
}
matches.forEach((match, index) => {
new vm.Script(match[1], {
filename: `${file}#script${index + 1}`,
});
});
}
async function compileModule(file) {
const absoluteFile = path.join(ROOT_DIR, file);
const source = fs.readFileSync(absoluteFile, "utf8");
execFileSync(process.execPath, ["--input-type=module", "--check"], {
cwd: ROOT_DIR,
input: source,
stdio: "pipe",
});
}
function parseJsonFile(file) {
const absoluteFile = path.join(ROOT_DIR, file);
JSON.parse(fs.readFileSync(absoluteFile, "utf8"));
}
async function main() {
NODE_CHECK_FILES.forEach(runNodeCheck);
HTML_FILES.forEach(compileInlineScripts);
JSON_FILES.forEach(parseJsonFile);
for (const file of MODULE_JS_FILES) {
await compileModule(file);
}
console.log(JSON.stringify({
ok: true,
nodeChecked: NODE_CHECK_FILES.length,
htmlCompiled: HTML_FILES.length,
jsonParsed: JSON_FILES.length,
moduleCompiled: MODULE_JS_FILES.length,
}));
}
main().catch((error) => {
console.error(`[check] ${error.message}`);
process.exit(1);
});