Files
html/api/wevia-pipeline.php
2026-04-12 22:57:03 +02:00

191 lines
8.4 KiB
PHP

<?php
header("Content-Type: application/json; charset=utf-8");
$input = json_decode(file_get_contents("php://input"), true) ?: [];
$step = $input["step"] ?? $_GET["step"] ?? "full";
$task = $input["task"] ?? "";
$secrets=[];
foreach(file("/etc/weval/secrets.env",2|4) as $l){if(strpos($l,"=")!==false){list($k,$v)=explode("=",$l,2);$secrets[trim($k)]=trim($v," \t\"'");}}
function llm($prompt, $secrets) {
$ch=curl_init("https://api.cerebras.ai/v1/chat/completions");
curl_setopt_array($ch,[CURLOPT_POST=>true,CURLOPT_POSTFIELDS=>json_encode(["model"=>"qwen-3-235b-a22b-instruct-2507","messages"=>[["role"=>"system","content"=>"WEVIA DevOps Pipeline. French. Concise."],["role"=>"user","content"=>$prompt]],"max_tokens"=>500,"temperature"=>0.2]),CURLOPT_HTTPHEADER=>["Content-Type: application/json","Authorization: Bearer ".($secrets["CEREBRAS_API_KEY"]??"")],CURLOPT_RETURNTRANSFER=>true,CURLOPT_TIMEOUT=>12]);
$r=curl_exec($ch);curl_close($ch);
return json_decode($r,true)["choices"][0]["message"]["content"]??"";
}
$trace = [];
// STEP 1: ANALYZE REQUEST + WIKI + L99
if ($step === "full" || $step === "analyze") {
// Read wiki
$wikiFiles = glob("/opt/weval-l99/wiki/*.json");
$wikiCount = count($wikiFiles);
$recentWiki = [];
foreach (array_slice($wikiFiles, -5) as $wf) {
$d = json_decode(@file_get_contents($wf), true);
$recentWiki[] = $d["title"] ?? basename($wf);
}
// Read L99
$l99 = json_decode(@file_get_contents("/var/www/html/api/l99-results.json") ?: "{}", true);
// Scan servers
$ram = trim(shell_exec("free -h | grep Mem | awk '{print $3\"/\"$2}'"));
$disk = trim(shell_exec("df -h / | tail -1 | awk '{print $5}'"));
$docker = trim(shell_exec("docker ps -q 2>/dev/null | wc -l"));
$git = trim(shell_exec("cd /var/www/html && git status --short 2>/dev/null | wc -l"));
$gitBranch = trim(shell_exec("cd /var/www/html && git branch --show-current 2>/dev/null"));
// Scan architecture
$fastLines = count(file("/var/www/html/api/weval-ia-fast.php"));
$autoLines = count(file("/var/www/html/api/wevia-autonomous.php"));
$analysis = [
"task" => $task,
"wiki" => ["count" => $wikiCount, "recent" => $recentWiki],
"l99" => ["passed" => $l99["passed"] ?? "?", "total" => $l99["total"] ?? "?"],
"infra" => ["ram" => $ram, "disk" => $disk, "docker" => $docker, "dirty_files" => $git, "branch" => $gitBranch],
"codebase" => ["fast_lines" => $fastLines, "auto_lines" => $autoLines],
];
// LLM analysis
if ($task) {
$analysis["llm_analysis"] = llm("Dev request: $task\nInfra: RAM=$ram Disk=$disk Docker=$docker\nL99: {$l99['passed']}/{$l99['total']}\nFast.php: $fastLines lines\nAnalyze: what files to modify, risks, approach.", $secrets);
}
$trace[] = ["step" => "analyze", "data" => $analysis];
if ($step === "analyze") { echo json_encode($analysis, JSON_UNESCAPED_UNICODE); exit; }
}
// STEP 2: GOLD BACKUP
if ($step === "full" || $step === "backup") {
$timestamp = date("Ymd-His");
$backupDir = "/opt/wevads/vault/gold-$timestamp/";
@mkdir($backupDir, 0777, true);
shell_exec("cp /var/www/html/api/weval-ia-fast.php $backupDir 2>/dev/null");
shell_exec("cp /var/www/html/api/wevia-autonomous.php $backupDir 2>/dev/null");
shell_exec("cp /var/www/html/wevia-master.html $backupDir 2>/dev/null");
shell_exec("cd $backupDir && md5sum * > checksums.md5 2>/dev/null");
$trace[] = ["step" => "backup", "dir" => $backupDir, "files" => count(glob("$backupDir*"))];
if ($step === "backup") { echo json_encode(["backup" => $backupDir, "files" => count(glob("$backupDir*"))]); exit; }
}
// STEP 3: GIT SNAPSHOT
if ($step === "full" || $step === "snapshot") {
$gitStatus = shell_exec("cd /var/www/html && git add -A && git status --short 2>&1");
$dirty = substr_count($gitStatus, "\n");
if ($dirty > 0) {
shell_exec("cd /var/www/html && git commit -m 'PIPELINE: pre-dev snapshot' 2>&1");
}
$hash = trim(shell_exec("cd /var/www/html && git rev-parse --short HEAD 2>/dev/null"));
$trace[] = ["step" => "snapshot", "hash" => $hash, "dirty" => $dirty];
}
// STEP 4: L99 PRE-TEST
if ($step === "full" || $step === "pretest") {
$py = 'import asyncio
from playwright.async_api import async_playwright
async def t():
async with async_playwright() as p:
b=await p.chromium.launch(headless=True,args=["--no-sandbox"])
results=[]
pages={"master":"https://weval-consulting.com/wevia-master.html","cortex":"https://weval-consulting.com/wevia-cortex.html","site":"https://weval-consulting.com/"}
for name,url in pages.items():
pg=await b.new_page()
try:
await pg.goto(url,timeout=10000)
await pg.wait_for_timeout(2000)
title=await pg.title()
errors=[]
pg.on("pageerror",lambda e:errors.append(1))
await pg.wait_for_timeout(500)
await pg.screenshot(path=f"/tmp/l99-pre-{name}.png")
results.append({"page":name,"title":title,"errors":len(errors),"ok":True})
except Exception as e:
results.append({"page":name,"error":str(e)[:80],"ok":False})
await pg.close()
await b.close()
import json;print(json.dumps(results))
asyncio.run(t())';
$out = shell_exec("timeout 30 python3 -c " . escapeshellarg($py) . " 2>&1");
$preTests = json_decode($out, true) ?: [];
$prePassed = count(array_filter($preTests, function($t){return $t["ok"];}));
$trace[] = ["step" => "pretest", "passed" => $prePassed, "total" => count($preTests), "results" => $preTests];
}
// STEP 5: DEV (placeholder — actual dev done by caller)
if ($step === "full") {
$trace[] = ["step" => "dev", "status" => "ready", "note" => "Development phase — modify files now"];
}
// STEP 6: POST-TEST (L99 + NonReg)
if ($step === "full" || $step === "posttest") {
// PHP lint all modified files
$phpFiles = glob("/var/www/html/api/*.php");
$lintErrors = 0;
foreach ($phpFiles as $pf) {
$lint = shell_exec("php -l $pf 2>&1");
if (strpos($lint, "Errors") !== false) $lintErrors++;
}
// Playwright visual test
$postPy = 'import asyncio,json
from playwright.async_api import async_playwright
async def t():
async with async_playwright() as p:
b=await p.chromium.launch(headless=True,args=["--no-sandbox"])
pg=await b.new_page(viewport={"width":1400,"height":900})
await pg.goto("https://weval-consulting.com/wevia-master.html",timeout=10000)
await pg.wait_for_timeout(3000)
items=await pg.eval_on_selector_all(".sb-item","e=>e.length")
await pg.screenshot(path="/tmp/l99-post-master.png")
await b.close()
print(json.dumps({"sidebar":items,"ok":True}))
asyncio.run(t())';
$postOut = shell_exec("timeout 20 python3 -c " . escapeshellarg($postPy) . " 2>&1");
$postResult = json_decode($postOut, true) ?: ["ok" => false];
$trace[] = ["step" => "posttest", "lint_errors" => $lintErrors, "visual" => $postResult];
}
// STEP 7: COMMIT + PUSH TO ALL REPOS
if ($step === "full" || $step === "push") {
$msg = $input["commit_msg"] ?? "PIPELINE: auto-commit " . date("Y-m-d H:i");
// Local git
$gitResult = shell_exec("cd /var/www/html && git add -A && git commit -m " . escapeshellarg($msg) . " 2>&1");
// GitHub
$ghPush = shell_exec("cd /var/www/html && git push github main 2>&1 | tail -1");
// Get commit hash
$hash = trim(shell_exec("cd /var/www/html && git rev-parse --short HEAD 2>/dev/null"));
$trace[] = ["step" => "push", "hash" => $hash, "github" => strpos($ghPush, "->") !== false ? "OK" : $ghPush];
}
// STEP 8: WIKI UPDATE
if ($step === "full" || $step === "wiki") {
$wiki = [
"title" => "PIPELINE-" . date("Ymd-His"),
"date" => date("c"),
"task" => $task,
"steps" => count($trace),
"results" => array_map(function($t){return ["step"=>$t["step"],"ok"=>true];}, $trace),
];
file_put_contents("/opt/weval-l99/wiki/PIPELINE-" . date("Ymd-His") . ".json", json_encode($wiki));
$trace[] = ["step" => "wiki", "entries" => count(glob("/opt/weval-l99/wiki/*.json"))];
}
// STEP 9: FINAL STATUS
$pipeline = [
"task" => $task,
"steps" => count($trace),
"trace" => $trace,
"status" => "COMPLETE",
"timestamp" => date("c"),
];
echo json_encode($pipeline, JSON_UNESCAPED_UNICODE);