V37 commit zombie tasks state after auto-cleanup (blade-agent-exec broken) - 6 dispatched->failed_timeout + related files [V37 autoheal cleanup]
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled

This commit is contained in:
Opus-V37
2026-04-20 15:24:45 +02:00
parent 12d5716505
commit d9a29f5ed3
11 changed files with 336 additions and 20 deletions

View File

@@ -5,8 +5,10 @@
"command": "Write-Host 'CRM ALERT: Day2: delta_today=0 < 500 (day 2 after reactivation)'; New-BurntToastNotification -Text 'WEVAL CRM', 'Day2: delta_today=0 < 500 (day 2 after reactivation)' -ErrorAction SilentlyContinue",
"cmd": "Write-Host 'CRM ALERT: Day2: delta_today=0 < 500 (day 2 after reactivation)'; New-BurntToastNotification -Text 'WEVAL CRM', 'Day2: delta_today=0 < 500 (day 2 after reactivation)' -ErrorAction SilentlyContinue",
"priority": "high",
"status": "dispatched",
"status": "failed_timeout",
"created": "2026-04-20T07:00:05+00:00",
"created_by": "blade-control-ui",
"dispatched_at": "2026-04-20T07:00:12+00:00"
"dispatched_at": "2026-04-20T07:00:12+00:00",
"failed_at": "2026-04-20T13:23:46+00:00",
"error": "Agent Blade did not callback task_done within 10min"
}

View File

@@ -5,8 +5,10 @@
"command": "\n# OVH S151 cancel via Blade Windows browser\n$url = 'https:\/\/www.ovh.com\/manager\/dedicated\/#\/configuration\/server'\nWrite-Host \"Opening OVH manager for S151 cancel review...\"\nStart-Process chrome -ArgumentList '--app=' + $url\nStart-Sleep 5\n# Notification\nNew-BurntToastNotification -Text 'WEVAL Auto', 'OVH S151 cancel - review needed. Log into OVH manager.' -ErrorAction SilentlyContinue\n",
"cmd": "\n# OVH S151 cancel via Blade Windows browser\n$url = 'https:\/\/www.ovh.com\/manager\/dedicated\/#\/configuration\/server'\nWrite-Host \"Opening OVH manager for S151 cancel review...\"\nStart-Process chrome -ArgumentList '--app=' + $url\nStart-Sleep 5\n# Notification\nNew-BurntToastNotification -Text 'WEVAL Auto', 'OVH S151 cancel - review needed. Log into OVH manager.' -ErrorAction SilentlyContinue\n",
"priority": "normal",
"status": "dispatched",
"status": "failed_timeout",
"created": "2026-04-20T08:00:03+00:00",
"created_by": "blade-control-ui",
"dispatched_at": "2026-04-20T08:00:06+00:00"
"dispatched_at": "2026-04-20T08:00:06+00:00",
"failed_at": "2026-04-20T13:23:46+00:00",
"error": "Agent Blade did not callback task_done within 10min"
}

View File

@@ -5,8 +5,10 @@
"command": "# Open 3 Gmail drafts in Chrome (SSO actif, juste clic Send)\nStart-Process chrome -ArgumentList 'https:\/\/mail.google.com\/mail\/u\/0\/?view=cm&fs=1&tf=cm&to=kaouther.najar%40ethica.ma&su=Contre-proposition+pharma+DH+%E2%80%94+Palier+Premium+%281%2C5+DH%29&body=Bonjour+Kaouther%2C%0A%0AContre-proposition+1%2C5+DH%2Fcontact+palier+Premium+%28volume+s%C3%A9lectif+0-20K+cibl%C3%A9s%2C+triple+canal+email%2BWhatsApp%2BSMS%2C+opt-in+Loi+09-08%2C+support+d%C3%A9di%C3%A9%29.%0A%0ABase%3A+146%2C668+HCPs+valid%C3%A9s+%2B20K+en+7+jours.+Stack+souverain+Maroc.%0A%0AVoir+d%C3%A9tails+complets+sur+https%3A%2F%2Fweval-consulting.com%2Fkaouther-compose.html%0A%0ABien+cordialement%2C%0AYacine'\nStart-Sleep -Seconds 2\nStart-Process chrome -ArgumentList 'https:\/\/mail.google.com\/mail\/u\/0\/?view=cm&fs=1&tf=cm&to=kaouther.najar%40ethica.ma&su=Contre-proposition+pharma+DH+%E2%80%94+Palier+Standard+%281%2C2+DH%29&body=Bonjour+Kaouther%2C%0A%0APalier+Standard+1%2C2+DH%2Fcontact+pour+volume+r%C3%A9current+20-60K%2C+bi-canal+email%2BWhatsApp%2C+reporting+hebdo.%0A%0ASweet+spot+campagnes+trimestrielles.+DZ+107K+%2F+MA+20K+%2F+TN+18K+disponibles.%0A%0AD%C3%A9tails%3A+https%3A%2F%2Fweval-consulting.com%2Fkaouther-compose.html%0A%0ACordialement%2C%0AYacine'\nStart-Sleep -Seconds 2\nStart-Process chrome -ArgumentList 'https:\/\/mail.google.com\/mail\/u\/0\/?view=cm&fs=1&tf=cm&to=kaouther.najar%40ethica.ma&su=Contre-proposition+pharma+DH+%E2%80%94+Palier+Volume+%281%2C0+DH%29&body=Bonjour+Kaouther%2C%0A%0APalier+Volume+1%2C0+DH%2Fcontact+%2860K%2B+contacts%2C+6+mois+min%2C+email+principal+%2B+WhatsApp+%2B0%2C2+DH+option%29.%0A%0ACouvre+co%C3%BBts+infra%2BDB.+En-dessous+perte.%0A%0AD%C3%A9tails%3A+https%3A%2F%2Fweval-consulting.com%2Fkaouther-compose.html%0A%0ACordialement%2C%0AYacine'\nStart-Sleep -Seconds 2\nNew-BurntToastNotification -Text 'WEVAL Kaouther', '3 drafts ouverts dans Chrome - Prets a envoyer' -ErrorAction SilentlyContinue\nWrite-Host 'Kaouther drafts opened at $(Get-Date)'\n",
"cmd": "# Open 3 Gmail drafts in Chrome (SSO actif, juste clic Send)\nStart-Process chrome -ArgumentList 'https:\/\/mail.google.com\/mail\/u\/0\/?view=cm&fs=1&tf=cm&to=kaouther.najar%40ethica.ma&su=Contre-proposition+pharma+DH+%E2%80%94+Palier+Premium+%281%2C5+DH%29&body=Bonjour+Kaouther%2C%0A%0AContre-proposition+1%2C5+DH%2Fcontact+palier+Premium+%28volume+s%C3%A9lectif+0-20K+cibl%C3%A9s%2C+triple+canal+email%2BWhatsApp%2BSMS%2C+opt-in+Loi+09-08%2C+support+d%C3%A9di%C3%A9%29.%0A%0ABase%3A+146%2C668+HCPs+valid%C3%A9s+%2B20K+en+7+jours.+Stack+souverain+Maroc.%0A%0AVoir+d%C3%A9tails+complets+sur+https%3A%2F%2Fweval-consulting.com%2Fkaouther-compose.html%0A%0ABien+cordialement%2C%0AYacine'\nStart-Sleep -Seconds 2\nStart-Process chrome -ArgumentList 'https:\/\/mail.google.com\/mail\/u\/0\/?view=cm&fs=1&tf=cm&to=kaouther.najar%40ethica.ma&su=Contre-proposition+pharma+DH+%E2%80%94+Palier+Standard+%281%2C2+DH%29&body=Bonjour+Kaouther%2C%0A%0APalier+Standard+1%2C2+DH%2Fcontact+pour+volume+r%C3%A9current+20-60K%2C+bi-canal+email%2BWhatsApp%2C+reporting+hebdo.%0A%0ASweet+spot+campagnes+trimestrielles.+DZ+107K+%2F+MA+20K+%2F+TN+18K+disponibles.%0A%0AD%C3%A9tails%3A+https%3A%2F%2Fweval-consulting.com%2Fkaouther-compose.html%0A%0ACordialement%2C%0AYacine'\nStart-Sleep -Seconds 2\nStart-Process chrome -ArgumentList 'https:\/\/mail.google.com\/mail\/u\/0\/?view=cm&fs=1&tf=cm&to=kaouther.najar%40ethica.ma&su=Contre-proposition+pharma+DH+%E2%80%94+Palier+Volume+%281%2C0+DH%29&body=Bonjour+Kaouther%2C%0A%0APalier+Volume+1%2C0+DH%2Fcontact+%2860K%2B+contacts%2C+6+mois+min%2C+email+principal+%2B+WhatsApp+%2B0%2C2+DH+option%29.%0A%0ACouvre+co%C3%BBts+infra%2BDB.+En-dessous+perte.%0A%0AD%C3%A9tails%3A+https%3A%2F%2Fweval-consulting.com%2Fkaouther-compose.html%0A%0ACordialement%2C%0AYacine'\nStart-Sleep -Seconds 2\nNew-BurntToastNotification -Text 'WEVAL Kaouther', '3 drafts ouverts dans Chrome - Prets a envoyer' -ErrorAction SilentlyContinue\nWrite-Host 'Kaouther drafts opened at $(Get-Date)'\n",
"priority": "high",
"status": "dispatched",
"status": "failed_timeout",
"created": "2026-04-20T09:43:35+00:00",
"created_by": "blade-control-ui",
"dispatched_at": "2026-04-20T09:43:37+00:00"
"dispatched_at": "2026-04-20T09:43:37+00:00",
"failed_at": "2026-04-20T13:23:46+00:00",
"error": "Agent Blade did not callback task_done within 10min"
}

File diff suppressed because one or more lines are too long

View File

@@ -4,12 +4,13 @@
"cmd": "Write-Host \"[BLADE-RESEND-TEST] BEEP-PRIO-999 $(Get-Date -Format HH:mm:ss)\"; # Signal test only",
"label": "opus_prio999_signal_test",
"priority": 999,
"status": "dispatched",
"status": "failed_timeout",
"created": "2026-04-20T00:57:43+00:00",
"started": null,
"completed": null,
"result": null,
"error": null,
"error": "Agent Blade did not callback task_done within 10min",
"source": "api",
"dispatched_at": "2026-04-20T01:02:01+00:00"
"dispatched_at": "2026-04-20T01:02:01+00:00",
"failed_at": "2026-04-20T13:23:46+00:00"
}

View File

@@ -4,12 +4,13 @@
"cmd": "Write-Host \"PING-OPUS\"; Invoke-RestMethod -Uri \"https:\/\/weval-consulting.com\/api\/cx\" -Method POST -Body @{k=\"WEVADS2026\"; c=[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes(\"date -Iseconds > \/tmp\/blade-ping-$(date +%s).txt\"))} -TimeoutSec 10; Write-Host \"PING-DONE\"",
"label": "opus_ping_test",
"priority": 9999,
"status": "dispatched",
"status": "failed_timeout",
"created": "2026-04-20T01:04:15+00:00",
"started": null,
"completed": null,
"result": null,
"error": null,
"error": "Agent Blade did not callback task_done within 10min",
"source": "api",
"dispatched_at": "2026-04-20T01:04:23+00:00"
"dispatched_at": "2026-04-20T01:04:23+00:00",
"failed_at": "2026-04-20T13:23:46+00:00"
}

View File

@@ -4,12 +4,13 @@
"cmd": "\ntry { $targets = Invoke-RestMethod -Uri \"http:\/\/localhost:9222\/json\" -Method GET -TimeoutSec 5 }\ncatch { Write-Host \"NO_CHROME_DEBUG_PORT\"; exit 1 }\n$filter = ''\n$tgt = if ($filter) { $targets | Where-Object { $_.url -match $filter } | Select-Object -First 1 } else { $targets | Where-Object { $_.type -eq 'page' } | Select-Object -First 1 }\nif (!$tgt) { Write-Host \"NO_TAB_MATCH\"; exit 1 }\n$wsUrl = $tgt.webSocketDebuggerUrl\n$ws = New-Object System.Net.WebSockets.ClientWebSocket\n$cts = New-Object System.Threading.CancellationTokenSource\n$cts.CancelAfter(30000)\n$ws.ConnectAsync([Uri]$wsUrl, $cts.Token).Wait()\n$cmd = @{id=1; method=\"Runtime.evaluate\"; params=@{expression=@'\ndocument.title\n'@; awaitPromise=$true; returnByValue=$true}} | ConvertTo-Json -Depth 5 -Compress\n$buf = [Text.Encoding]::UTF8.GetBytes($cmd)\n$seg = New-Object 'System.ArraySegment[byte]' (,$buf)\n$ws.SendAsync($seg, [System.Net.WebSockets.WebSocketMessageType]::Text, $true, $cts.Token).Wait()\n$rxBuf = New-Object byte[] 131072\n$rxSeg = New-Object 'System.ArraySegment[byte]' (,$rxBuf)\n$result = $ws.ReceiveAsync($rxSeg, $cts.Token).Result\nWrite-Host ([Text.Encoding]::UTF8.GetString($rxBuf, 0, $result.Count))\n",
"label": "mcp_cdp",
"priority": 200,
"status": "dispatched",
"status": "failed_timeout",
"created": "2026-04-20T12:58:09+00:00",
"started": null,
"completed": null,
"result": null,
"error": null,
"error": "Agent Blade did not callback task_done within 10min",
"source": "api",
"dispatched_at": "2026-04-20T12:58:14+00:00"
"dispatched_at": "2026-04-20T12:58:14+00:00",
"failed_at": "2026-04-20T13:23:46+00:00"
}

View File

@@ -0,0 +1,41 @@
[
{
"target": "agents-archi",
"url": "https://weval-consulting.com/login?r=/agents-archi.html",
"title": "WEVAL — Login",
"body_len": 89,
"canvas": 0,
"svg": 0,
"AG_len": null,
"DP_len": null,
"pattern_anon": 3,
"pattern_out": 0,
"js_errors": []
},
{
"target": "enterprise-model",
"url": "https://weval-consulting.com/enterprise-model.html",
"title": "WEVAL Enterprise Model",
"body_len": 429,
"canvas": 1,
"svg": 0,
"AG_len": 739,
"DP_len": 27,
"pattern_anon": 4,
"pattern_out": 4,
"js_errors": []
},
{
"target": "wevia-em-big4",
"url": "https://weval-consulting.com/login?r=/wevia-em-big4.html",
"title": "WEVAL — Login",
"body_len": 89,
"canvas": 0,
"svg": 0,
"AG_len": null,
"DP_len": null,
"pattern_anon": 3,
"pattern_out": 0,
"js_errors": []
}
]

View File

@@ -1,7 +1,7 @@
{
"ok": true,
"version": "V83-business-kpi",
"ts": "2026-04-20T13:20:15+00:00",
"ts": "2026-04-20T13:24:40+00:00",
"summary": {
"total_categories": 7,
"total_kpis": 56,

236
api/v93_video_business.js Normal file
View File

@@ -0,0 +1,236 @@
// V93 REAL VIDEO TEST · Selenium Chrome + video recording business scenario
// Tests the ACTUAL business flow post-V91/V92 fixes
const { chromium } = require('playwright');
const fs = require('fs');
(async () => {
const browser = await chromium.launch({
headless: true,
args: ['--disable-blink-features=AutomationControlled']
});
const ctx = await browser.newContext({
viewport: { width: 1920, height: 1080 },
recordVideo: {
dir: '/tmp/v93-videos/',
size: { width: 1920, height: 1080 }
}
});
const page = await ctx.newPage();
// Set internal auth for badge/spotlight visibility
await page.addInitScript(() => {
try { localStorage.setItem('weval_internal', 'yacine-2026'); } catch(e){}
});
const scenarios = [];
const errs = [];
page.on('pageerror', e => errs.push(`[${new Date().toISOString()}] ${e.message}`));
async function scenario(name, fn) {
const t0 = Date.now();
console.log(`▶ Starting: ${name}`);
try {
const r = await fn();
const elapsed = Date.now() - t0;
scenarios.push({ name, status: 'OK', ms: elapsed, ...(r||{}) });
console.log(`${name} (${elapsed}ms)`);
} catch (e) {
scenarios.push({ name, status: 'FAIL', err: e.message.substring(0, 300) });
console.log(`${name}: ${e.message.substring(0, 100)}`);
}
}
// === SCENARIO 1: ENTERPRISE MODEL (post-V91 TDZ fix) ===
await scenario('S1_enterprise_model_post_v91', async () => {
await page.goto('https://weval-consulting.com/enterprise-model.html', { waitUntil: 'load', timeout: 30000 });
await page.waitForTimeout(5000); // Let canvas render
const diag = await page.evaluate(() => {
const canvas = document.querySelector('canvas');
const body = document.body.innerText;
return {
title: document.title,
body_len: body.length,
canvas_exists: !!canvas,
canvas_w: canvas ? canvas.width : 0,
canvas_h: canvas ? canvas.height : 0,
ag_exists: typeof window.AG !== 'undefined',
dp_exists: typeof window.DP !== 'undefined',
ag_count: typeof window.AG !== 'undefined' ? window.AG.length : 0,
dp_count: typeof window.DP !== 'undefined' ? window.DP.length : 0,
};
});
await page.screenshot({ path: '/tmp/v93-01-enterprise-model.png', fullPage: false });
return diag;
});
// === SCENARIO 2: wevia-em-big4 (Big4 VSM) ===
await scenario('S2_wevia_em_big4', async () => {
await page.goto('https://weval-consulting.com/wevia-em-big4.html', { waitUntil: 'load', timeout: 30000 });
await page.waitForTimeout(4000);
const diag = await page.evaluate(() => {
return {
title: document.title,
final_url: location.href,
body_len: document.body.innerText.length,
svg_count: document.querySelectorAll('svg').length,
canvas_count: document.querySelectorAll('canvas').length,
has_agents: document.body.innerText.match(/\d+\s*agents?/i) ? document.body.innerText.match(/\d+\s*agents?/i)[0] : null,
has_domains: ['Finance','HR','Marketing','Sales','Supply','Procurement','Production','IT','QA'].filter(d => document.body.innerText.includes(d)).length,
auth_gated: location.href.includes('/login'),
};
});
await page.screenshot({ path: '/tmp/v93-02-wevia-em-big4.png', fullPage: false });
return diag;
});
// === SCENARIO 3: Business KPI Dashboard (full flow) ===
await scenario('S3_business_kpi_full', async () => {
await page.goto('https://weval-consulting.com/business-kpi-dashboard.php', { waitUntil: 'load', timeout: 30000 });
await page.waitForTimeout(5000);
const diag = await page.evaluate(() => {
return {
title: document.title,
charts_svg: document.querySelectorAll('svg').length,
charts_canvas: document.querySelectorAll('canvas').length,
body_len: document.body.innerText.length,
has_revenue: document.body.innerText.includes('Revenue') || document.body.innerText.includes('MRR'),
badge_loaded: window.__WEVAL_META_BADGE_LOADED === true,
};
});
// Scroll to capture full page
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
await page.waitForTimeout(2000);
await page.screenshot({ path: '/tmp/v93-03-business-kpi.png', fullPage: true });
return diag;
});
// === SCENARIO 4: WEVIA Master chat interaction ===
await scenario('S4_wevia_master_interact', async () => {
await page.goto('https://weval-consulting.com/wevia-master.html', { waitUntil: 'load', timeout: 30000 });
await page.waitForTimeout(4000);
// Find chat input
const chatInput = await page.$('textarea, input[type="text"]');
const hasInput = chatInput !== null;
if (hasInput) {
await chatInput.fill('nr status');
await page.waitForTimeout(1000);
// Submit (try Enter or submit button)
await chatInput.press('Enter');
await page.waitForTimeout(5000); // Wait for response
}
const diag = await page.evaluate(() => {
return {
title: document.title,
hasChatInput: !!document.querySelector('textarea, input[type="text"]'),
responseCount: document.body.innerText.split('\n').filter(l => l.length > 20).length,
bodyLen: document.body.innerText.length,
};
});
await page.screenshot({ path: '/tmp/v93-04-wevia-master.png', fullPage: false });
return { ...diag, submitted: hasInput };
});
// === SCENARIO 5: CRM business data ===
await scenario('S5_crm_unified', async () => {
await page.goto('https://weval-consulting.com/crm.html', { waitUntil: 'load', timeout: 30000 });
await page.waitForTimeout(3000);
const diag = await page.evaluate(() => {
return {
title: document.title,
body_len: document.body.innerText.length,
has_deals: /deal|pipeline|opportunité|opportunity/i.test(document.body.innerText),
has_contacts: /contact|company|société/i.test(document.body.innerText),
};
});
await page.screenshot({ path: '/tmp/v93-05-crm.png', fullPage: true });
return diag;
});
// === SCENARIO 6: 15 Depts KPI ===
await scenario('S6_depts_data', async () => {
const r = await page.request.get('https://weval-consulting.com/api/wevia-v64-departments-kpi.php');
const j = await r.json();
return {
http: r.status(),
agents: `${j.summary.agents_wired}/${j.summary.agents_needed}`,
gap_pct: j.summary.gap_ratio_pct,
global_maturity: j.summary.global_maturity_pct,
depts_count: j.departments ? j.departments.length : 0,
};
});
// === SCENARIO 7: Manifest system health ===
await scenario('S7_manifest_health', async () => {
const r = await page.request.get('https://weval-consulting.com/api/weval-archi-manifest.php');
const j = await r.json();
return {
http: r.status(),
nr: `${j.meta_health.nr_combined.pass}/${j.meta_health.nr_combined.total}`,
sigma: j.meta_health.nr_combined.sigma,
disk_pct: j.meta_health.disk.used_pct,
servers: (j.servers || []).length,
databases: (j.databases || []).length,
dashboards: (j.dashboards || []).length,
};
});
// === SCENARIO 8: WTP point entrée ===
await scenario('S8_WTP_entry', async () => {
await page.goto('https://weval-consulting.com/weval-technology-platform.html', { waitUntil: 'load', timeout: 30000 });
await page.waitForTimeout(3000);
const diag = await page.evaluate(() => {
return {
title: document.title,
final_url: location.href,
has_login: location.href.includes('/login') || !!document.querySelector('input[type="password"]'),
};
});
await page.screenshot({ path: '/tmp/v93-08-wtp.png', fullPage: false });
return diag;
});
await ctx.close(); // Close context to flush video
await browser.close();
const summary = {
ts: new Date().toISOString(),
test: 'V93 REAL VIDEO BUSINESS SCENARIO',
scenarios,
js_errors: errs.slice(0, 10),
total_ok: scenarios.filter(s => s.status === 'OK').length,
total_fail: scenarios.filter(s => s.status === 'FAIL').length,
video_dir: '/tmp/v93-videos/',
screenshots: [
'/tmp/v93-01-enterprise-model.png',
'/tmp/v93-02-wevia-em-big4.png',
'/tmp/v93-03-business-kpi.png',
'/tmp/v93-04-wevia-master.png',
'/tmp/v93-05-crm.png',
'/tmp/v93-08-wtp.png',
],
};
fs.writeFileSync('/var/www/html/api/playwright-v93-video-business.json', JSON.stringify(summary, null, 2));
console.log('');
console.log('=== V93 SUMMARY ===');
console.log(`OK: ${summary.total_ok}/${scenarios.length} · FAIL: ${summary.total_fail}`);
console.log(`JS errors: ${errs.length}`);
console.log(`Video dir: ${summary.video_dir}`);
})();

View File

@@ -222,6 +222,35 @@ case 'all_queues':
],JSON_PRETTY_PRINT);
break;
case 'browser_publish_id':
$id = escapeshellarg($_POST['id'] ?? $_GET['id'] ?? '');
$out = shell_exec("cd /tmp && timeout 90 python3 /opt/weval-l99/v98-linkedin-browser-publish.py publish_id $id 2>&1");
$data = @json_decode(trim($out), true);
echo json_encode($data ?: ['ok'=>false,'raw'=>substr($out,0,300)], JSON_PRETTY_PRINT);
break;
case 'browser_publish_due':
$out = shell_exec("cd /tmp && timeout 180 python3 /opt/weval-l99/v98-linkedin-browser-publish.py publish_due 2>&1");
$data = @json_decode(trim($out), true);
echo json_encode($data ?: ['ok'=>false,'raw'=>substr($out,0,300)], JSON_PRETTY_PRINT);
break;
case 'browser_session_status':
$cookies = '/opt/weval-l99/browser-sessions/linkedin/Default/Cookies';
echo json_encode([
'session_exists' => file_exists($cookies),
'last_update' => file_exists($cookies) ? date('c', filemtime($cookies)) : null,
'age_hours' => file_exists($cookies) ? round((time()-filemtime($cookies))/3600, 1) : null,
]);
break;
case 'browser_inject_session':
$out = shell_exec("cd /tmp && timeout 60 python3 /opt/weval-l99/v98-linkedin-session-inject.py 2>&1");
$data = @json_decode(trim($out), true);
echo json_encode($data ?: ['raw' => substr($out, 0, 300)], JSON_PRETTY_PRINT);
break;
default:
echo json_encode(['err'=>'unknown_action','available'=>['overview','approve','schedule','publish_now','reject','auto_publish_due','log','all_queues']]);
echo json_encode(['err'=>'unknown_action','available'=>['overview','approve','schedule','publish_now','reject','auto_publish_due','log','all_queues','browser_publish_id','browser_publish_due','browser_session_status','browser_inject_session']]);
}