agents-relay 1.0.149 → 1.0.151
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dashboard-html.js +10 -3
- package/dist/dashboard.js +7 -2
- package/package.json +1 -1
package/dist/dashboard-html.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';
|
|
2
2
|
const packageVersion = createRequire(import.meta.url)('../package.json').version;
|
|
3
|
+
export const dashboardVersion = packageVersion;
|
|
3
4
|
export const dashboardHtml = `<!doctype html>
|
|
4
5
|
<html lang="en" data-dashboard-contract="safe-dom,named-relay-events,snapshot-events,bounded-event-history">
|
|
5
6
|
<head>
|
|
@@ -72,7 +73,9 @@ export const dashboardHtml = `<!doctype html>
|
|
|
72
73
|
ul.tree { display:grid; gap:.25rem; min-width:0; max-width:100%; }
|
|
73
74
|
ul.tree li { min-width:0; max-width:100%; }
|
|
74
75
|
ul.tree ul { width:calc(100% - .6rem); min-width:0; max-width:calc(100% - .6rem); list-style:none; margin:.2rem 0 .1rem .6rem; padding-left:.6rem; border-left:1px solid var(--border); }
|
|
75
|
-
.task-
|
|
76
|
+
.task-line { display:flex; align-items:center; gap:.2rem; min-width:0; }
|
|
77
|
+
.task-fold { flex:0 0 auto; width:1.35rem; padding:.32rem 0; border:0; background:transparent; color:var(--muted); font:inherit; cursor:pointer; }
|
|
78
|
+
.task-row { width:100%; max-width:100%; overflow:hidden; flex:1 1 0; display:flex; align-items:center; gap:.4rem; min-width:0; padding:.32rem .38rem; border:0; border-radius:.35rem; background:transparent; color:inherit; font:inherit; text-align:left; cursor:pointer; }
|
|
76
79
|
.task-row[aria-current="true"] { background:var(--accent2); }
|
|
77
80
|
.task-row .badge { flex:0 0 auto; }
|
|
78
81
|
.task-id { min-width:0; max-width:100%; flex:1 1 0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font: .77rem ui-monospace,SFMono-Regular,Menlo,monospace; }
|
|
@@ -161,7 +164,7 @@ export const dashboardHtml = `<!doctype html>
|
|
|
161
164
|
</head>
|
|
162
165
|
<body>
|
|
163
166
|
<header>
|
|
164
|
-
<div class="brand"><h1>Agents Relay Console</h1><p class="tagline">Durable PR state is authoritative; events are observability.</p><span class="version">v${
|
|
167
|
+
<div class="brand"><h1>Agents Relay Console</h1><p class="tagline">Durable PR state is authoritative; events are observability.</p><span class="version">v${dashboardVersion}</span></div>
|
|
165
168
|
<div id="runtime-summary" class="runtime-summary" aria-label="Runtime summary"></div>
|
|
166
169
|
<div id="rate-limit-warning" class="warning-banner" role="status" hidden></div>
|
|
167
170
|
<nav role="tablist" aria-label="Console views">
|
|
@@ -238,6 +241,7 @@ export const dashboardHtml = `<!doctype html>
|
|
|
238
241
|
// function usageBar(label, window)
|
|
239
242
|
|
|
240
243
|
const MAX_EVENTS=60;
|
|
244
|
+
const DASHBOARD_VERSION=${JSON.stringify(dashboardVersion)};
|
|
241
245
|
const jobsTab=document.querySelector('#jobs-tab');
|
|
242
246
|
const usageTab=document.querySelector('#usage-tab');
|
|
243
247
|
const rulesTab=document.querySelector('#rules-tab');
|
|
@@ -285,6 +289,7 @@ let quickMode=sessionStorage.getItem('agents-relay:quick-filter')||'jobs';
|
|
|
285
289
|
let selectedRuntimeStatus=sessionStorage.getItem('agents-relay:runtime-status-filter')||'';
|
|
286
290
|
let searchQuery=sessionStorage.getItem('agents-relay:job-search')||'';
|
|
287
291
|
let eventTaskId=selectedTaskId;
|
|
292
|
+
const collapsedTasks=new Set();
|
|
288
293
|
const displayedEventIds=new Set();
|
|
289
294
|
|
|
290
295
|
function value(input){return input===null||input===undefined||input===''?'—':String(input);}
|
|
@@ -333,7 +338,7 @@ function syncFilters(){
|
|
|
333
338
|
}
|
|
334
339
|
function repoName(repository){if(typeof repository!=='string'||!repository)return 'unknown-repo';const parts=repository.split('/').filter(Boolean);return parts.at(-1)||repository;}
|
|
335
340
|
function renderJobList(){jobList.replaceChildren();const visible=filteredJobs();if(!jobs.length){jobList.append(element('li','empty',text('No durable jobs discovered.')));return;}if(!visible.length){jobList.append(element('li','empty',text('No jobs match the selected repo.')));return;}for(const job of visible){const row=element('div','job-row'+(isCompleteUnmerged(job)?' complete-unmerged':''));row.setAttribute('aria-current',String(job.id===selectedJob));row.addEventListener('click',()=>selectJob(job.id));const content=element('div','job-content');const select=document.createElement('button');select.type='button';select.className='job-button';select.setAttribute('aria-current',String(job.id===selectedJob));select.title=job.title||job.id;select.addEventListener('click',event=>{event.stopPropagation();selectJob(job.id);});select.append(element('span','job-title',text(repoName(job.repository)+'/PR#'+value(job.prNumber)+': '+value(job.title||job.id))));const states=element('span','job-status-line');states.append(element('span','badge '+value(job.state),text(value(job.state))),element('span','badge '+value(job.runtimeStatus||'IDLE'),text(value(job.runtimeStatus||'IDLE'))));if(job.executionMode==='autonomous')states.append(element('span','badge flag-autonomous',text('AUTONOMOUS')));if(job.reviewEnabled!==false&&job.githubState!=='MERGED')states.append(element('span','badge flag-review',text('REVIEW REQUIRED')));if(job.githubState==='MERGED'&&job.publication?.version)states.append(element('span','badge SUCCEEDED',text('v'+job.publication.version)));if(isCompleteUnmerged(job))states.append(element('span','badge MERGE_PENDING',text('MERGE PENDING')));const primary=element('div','job-primary');primary.append(states);const lastLine=element('div','job-last-line');lastLine.append(element('span','subtle',text(compactCounts(counts(job.tasks)))),element('span','subtle',text(relativeTime(job.updatedAt))));content.append(select,primary,lastLine);row.append(content);jobList.append(element('li','',row));}}
|
|
336
|
-
function taskNode(task,children,depth){const li=element('li');const row=document.createElement('button');row.type='button';row.className='task-row';row.setAttribute('aria-current',String(task.id===selectedTaskId));row.title=task.id;row.addEventListener('click',()=>{const deselect=selectedTaskId===task.id;selectedTaskId=deselect?null:task.id;eventTaskId=deselect?null:task.id;rememberSelection();clearEvents();renderAll();void loadEventHistory();});const id=element('span','task-id',text(task.id));id.style.paddingLeft=Math.min(depth,4)*6+'px';row.append(id,element('span','badge '+value(task.state),text(task.state)));
|
|
341
|
+
function taskNode(task,children,depth){const li=element('li');const nested=children.get(task.id)||[];const line=element('div','task-line');if(nested.length){const key=(selectedJob||'')+':'+task.id;const collapsed=collapsedTasks.has(key);const fold=document.createElement('button');fold.type='button';fold.className='task-fold';fold.setAttribute('aria-expanded',String(!collapsed));fold.setAttribute('aria-label',(collapsed?'Expand ':'Collapse ')+task.id);fold.textContent=collapsed?'▸':'▾';line.append(fold);const ul=element('ul','tree');ul.hidden=collapsed;for(const child of nested)ul.append(taskNode(child,children,depth+1));fold.addEventListener('click',()=>{const next=!ul.hidden;ul.hidden=next;fold.setAttribute('aria-expanded',String(!next));fold.setAttribute('aria-label',(next?'Expand ':'Collapse ')+task.id);fold.textContent=next?'▸':'▾';if(next)collapsedTasks.add(key);else collapsedTasks.delete(key);});li.append(line,ul);}else li.append(line);const row=document.createElement('button');row.type='button';row.className='task-row';row.setAttribute('aria-current',String(task.id===selectedTaskId));row.title=task.id;row.addEventListener('click',()=>{const deselect=selectedTaskId===task.id;selectedTaskId=deselect?null:task.id;eventTaskId=deselect?null:task.id;rememberSelection();clearEvents();renderAll();void loadEventHistory();});const id=element('span','task-id',text(task.id));id.style.paddingLeft=Math.min(depth,4)*6+'px';row.append(id,element('span','badge '+value(task.state),text(task.state)));line.append(row);return li;}
|
|
337
342
|
function buildTree(tasks){taskTree.replaceChildren();if(!Array.isArray(tasks)||!tasks.length){taskTree.append(element('li','empty',text('No tasks in durable state.')));return;}const known=new Set(tasks.map(task=>task.id));const children=new Map();const roots=[];for(const task of tasks){if(!task.parentTaskId||!known.has(task.parentTaskId))roots.push(task);else{const siblings=children.get(task.parentTaskId)||[];siblings.push(task);children.set(task.parentTaskId,siblings);}}for(const task of roots)taskTree.append(taskNode(task,children,0));}
|
|
338
343
|
function attemptBudget(task){const attempt=Number(task?.attempt)||0;const max=Number(task?.maxAttempts)||0;if(max>=3&&max%3===0){const effectiveMax=Math.max(max,Math.ceil(attempt/3)*3);return attempt+' / 3×'+(effectiveMax/3);}return attempt+' / '+max;}
|
|
339
344
|
const TASK_STATES=['DRAFT','QUEUED','RUNNING','BLOCKED','SUCCEEDED','FAILED','CANCELLED'];
|
|
@@ -349,6 +354,7 @@ function isTerminalJob(job){return ['COMPLETED','CANCELLED'].includes(job.state)
|
|
|
349
354
|
function jobGroup(job){if(isTerminalJob(job))return 3;if(job.executionMode==='autonomous')return 1;if(job.draft||job.state==='DRAFT')return 2;return 0;}
|
|
350
355
|
function compareJobs(a,b){const groupDelta=jobGroup(a)-jobGroup(b);if(groupDelta)return groupDelta;const mergePendingDelta=Number(isCompleteUnmerged(b))-Number(isCompleteUnmerged(a));return mergePendingDelta||String(b.updatedAt).localeCompare(String(a.updatedAt));}
|
|
351
356
|
async function loadJSON(url){const response=await fetch(url);if(!response.ok)throw new Error(response.status+' '+response.statusText);return response.json();}
|
|
357
|
+
async function refreshVersion(){try{const live=await loadJSON('/api/version');if(live?.version&&live.version!==DASHBOARD_VERSION)location.reload();}catch{}}
|
|
352
358
|
function renderRateLimitStatus(status){
|
|
353
359
|
if(!status?.limited){rateLimitWarning.hidden=true;rateLimitWarning.textContent='';return;}
|
|
354
360
|
const until=status.cooldownUntil?new Date(status.cooldownUntil):null;
|
|
@@ -423,6 +429,7 @@ stream.addEventListener('relay',message=>{const payload=parseMessage(message);if
|
|
|
423
429
|
if(location.hash==='#/usage')showView('usage');else if(location.hash==='#/model-router-rules')showView('rules');else if(location.hash==='#/worker-router-rules')showView('worker-rules');else showView('jobs');
|
|
424
430
|
setInterval(()=>{if(location.hash!=='#/usage'&&location.hash!=='#/model-router-rules'&&location.hash!=='#/worker-router-rules')void refresh();},300000);
|
|
425
431
|
setInterval(()=>{if(location.hash==='#/usage')void drawUsage();},30000);
|
|
432
|
+
setInterval(()=>void refreshVersion(),30000);
|
|
426
433
|
async function refreshSelected(){if(!selectedJob){await refresh();return;}selectedJobRefresh.disabled=true;selectedJobRefresh.textContent='Refreshing…';try{const updated=await loadJSON('/api/job?id='+encodeURIComponent(selectedJob));const index=jobs.findIndex(job=>job.id===selectedJob);if(index>=0)jobs[index]=updated;else jobs.push(updated);rememberSelection();renderAll();connection.textContent='';connection.setAttribute('aria-label','Live durable state connected');connection.className='status-pill ok';}catch(error){connection.textContent='';connection.setAttribute('aria-label','Durable state unavailable');connection.className='status-pill bad';}finally{selectedJobRefresh.disabled=false;selectedJobRefresh.textContent='Refresh';}}
|
|
427
434
|
</script>
|
|
428
435
|
</body>
|
package/dist/dashboard.js
CHANGED
|
@@ -53,8 +53,8 @@ async function eventHistory(jobId, taskId, limit) {
|
|
|
53
53
|
}
|
|
54
54
|
return output;
|
|
55
55
|
}
|
|
56
|
-
export { dashboardHtml } from './dashboard-html.js';
|
|
57
|
-
import { dashboardHtml } from './dashboard-html.js';
|
|
56
|
+
export { dashboardHtml, dashboardVersion } from './dashboard-html.js';
|
|
57
|
+
import { dashboardHtml, dashboardVersion } from './dashboard-html.js';
|
|
58
58
|
export function serveDashboard(store, port = 8787, bus, refreshMs = 300000, jobId, usageRegistry, overviewProvider, webhook, statusProvider, githubUsageProvider, exactJobProvider, actions) {
|
|
59
59
|
const legacyActions = typeof exactJobProvider === 'object' && exactJobProvider !== null ? exactJobProvider : undefined;
|
|
60
60
|
const legacyExactJobProvider = !exactJobProvider && githubUsageProvider ? githubUsageProvider : undefined;
|
|
@@ -154,6 +154,11 @@ export function serveDashboard(store, port = 8787, bus, refreshMs = 300000, jobI
|
|
|
154
154
|
res.end(dashboardHtml);
|
|
155
155
|
return;
|
|
156
156
|
}
|
|
157
|
+
if (req.url === '/api/version') {
|
|
158
|
+
res.writeHead(200, { 'content-type': 'application/json', 'cache-control': 'no-store' });
|
|
159
|
+
res.end(JSON.stringify({ version: dashboardVersion }));
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
157
162
|
if (req.url === '/webhooks/github' && req.method === 'POST') {
|
|
158
163
|
const chunks = [];
|
|
159
164
|
for await (const chunk of req)
|