diff --git a/public_html/admin/index.php b/public_html/admin/index.php
index ac084b9..cd728aa 100644
--- a/public_html/admin/index.php
+++ b/public_html/admin/index.php
@@ -2172,10 +2172,82 @@ function wToast(msg,err=false) {
setTimeout(()=>{t.style.opacity='0';},3000);
}
async function workerAction(type,id,action) {
+ if (type === 'agent' && action === 'update') {
+ await agentUpdateFlow(id);
+ return;
+ }
const res=await api('worker_action',{worker_type:type,worker_id:id,action});
if(res&&res.ok){wToast(res.msg||'Done');setTimeout(loadWorkers,2500);}
else wToast((res&&res.error)||'Action failed',true);
}
+
+async function agentUpdateFlow(agentId) {
+ // Find the current version for this agent from the table
+ const row = [...document.querySelectorAll('#workers-agents tr')]
+ .find(r => r.innerHTML.includes(agentId));
+ const curVerEl = row ? row.querySelector('td:nth-child(5) span') : null;
+ const curVer = curVerEl ? curVerEl.textContent.replace(/[^0-9.]/g,'').trim() : '?';
+
+ // Show modal with live status
+ openModal(`⬆ UPDATE AGENT — ${agentId}`,
+ `
+
Dispatching update command...
+
`, null, null);
+ document.getElementById('modalSave').style.display = 'none';
+
+ const log = (msg, col) => {
+ const el = document.getElementById('upd-status');
+ if (el) el.innerHTML += `${msg}
`;
+ };
+
+ // Dispatch command
+ const res = await api('worker_action', {worker_type:'agent', worker_id:agentId, action:'update'});
+ if (!res || !res.ok) {
+ log('✗ Failed to dispatch: ' + (res?.error||'unknown'), 'var(--red)');
+ document.getElementById('modalSave').style.display = '';
+ document.getElementById('modalSave').textContent = 'CLOSE';
+ document.getElementById('modalSave').onclick = closeModal;
+ return;
+ }
+ log('✓ Command dispatched — waiting for agent to pick up...', 'var(--cyan)');
+
+ // Poll agent_commands for the result (max 90s)
+ const cmdRes = await api('worker_action', {worker_type:'agent', worker_id:agentId, action:'update_status'}).catch(()=>null);
+ // Actually poll via workers_list for version change
+ const deadline = Date.now() + 90000;
+ let done = false;
+ while (Date.now() < deadline) {
+ await new Promise(r => setTimeout(r, 4000));
+ const wData = await api('workers_list').catch(()=>null);
+ if (!wData || !wData.agents) break;
+ const ag = wData.agents.find(a => a.agent_id === agentId);
+ if (!ag) break;
+ const newVer = ag.version || null;
+ const latest = (wData.latest_versions||{})[ag.agent_type] || null;
+ if (latest && newVer === latest) {
+ log(`✓ Agent confirmed v${newVer} — up to date!`, 'var(--green)');
+ // Update the version cell in the table live
+ if (curVerEl) {
+ curVerEl.textContent = `v${newVer} ✓`;
+ curVerEl.style.color = 'var(--green)';
+ const tdVer = curVerEl.closest('td');
+ if (tdVer) tdVer.innerHTML = `v${newVer} ✓`;
+ }
+ done = true;
+ break;
+ } else if (newVer && newVer !== curVer) {
+ log(`↻ Version changed: ${curVer} → ${newVer} (checking if latest...)`, 'var(--yellow)');
+ } else {
+ log('· Waiting...', 'var(--text-dim)');
+ }
+ }
+ if (!done) {
+ log('⚠ Timed out — agent may update in background (self-update runs periodically)', 'var(--yellow)');
+ }
+ document.getElementById('modalSave').style.display = '';
+ document.getElementById('modalSave').textContent = 'CLOSE';
+ document.getElementById('modalSave').onclick = () => { closeModal(); loadWorkers(); };
+}
async function loadWorkers() {
const d=await api('workers_list');
if(!d||d.error) return;