agents-relay 1.0.148 → 1.0.150
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 +5 -2
- package/dist/scheduler.js +3 -1
- package/package.json +1 -1
package/dist/dashboard-html.js
CHANGED
|
@@ -72,7 +72,9 @@ export const dashboardHtml = `<!doctype html>
|
|
|
72
72
|
ul.tree { display:grid; gap:.25rem; min-width:0; max-width:100%; }
|
|
73
73
|
ul.tree li { min-width:0; max-width:100%; }
|
|
74
74
|
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-
|
|
75
|
+
.task-line { display:flex; align-items:center; gap:.2rem; min-width:0; }
|
|
76
|
+
.task-fold { flex:0 0 auto; width:1.35rem; padding:.32rem 0; border:0; background:transparent; color:var(--muted); font:inherit; cursor:pointer; }
|
|
77
|
+
.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
78
|
.task-row[aria-current="true"] { background:var(--accent2); }
|
|
77
79
|
.task-row .badge { flex:0 0 auto; }
|
|
78
80
|
.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; }
|
|
@@ -285,6 +287,7 @@ let quickMode=sessionStorage.getItem('agents-relay:quick-filter')||'jobs';
|
|
|
285
287
|
let selectedRuntimeStatus=sessionStorage.getItem('agents-relay:runtime-status-filter')||'';
|
|
286
288
|
let searchQuery=sessionStorage.getItem('agents-relay:job-search')||'';
|
|
287
289
|
let eventTaskId=selectedTaskId;
|
|
290
|
+
const collapsedTasks=new Set();
|
|
288
291
|
const displayedEventIds=new Set();
|
|
289
292
|
|
|
290
293
|
function value(input){return input===null||input===undefined||input===''?'—':String(input);}
|
|
@@ -333,7 +336,7 @@ function syncFilters(){
|
|
|
333
336
|
}
|
|
334
337
|
function repoName(repository){if(typeof repository!=='string'||!repository)return 'unknown-repo';const parts=repository.split('/').filter(Boolean);return parts.at(-1)||repository;}
|
|
335
338
|
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)));
|
|
339
|
+
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
340
|
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
341
|
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
342
|
const TASK_STATES=['DRAFT','QUEUED','RUNNING','BLOCKED','SUCCEEDED','FAILED','CANCELLED'];
|
package/dist/scheduler.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { implementationTasks } from './runtime-status.js';
|
|
1
2
|
import { decideJobLifecycle, decideTaskLifecycle } from './workflow/lifecycle.js';
|
|
2
3
|
import { reconcileTaskDependencies } from './workflow/task-reconcile.js';
|
|
3
4
|
export { dependencyReady, detectCycles } from './workflow/task-reconcile.js';
|
|
@@ -8,7 +9,8 @@ export function completionGateSatisfied(job) {
|
|
|
8
9
|
if (job.executionMode !== 'autonomous')
|
|
9
10
|
return true;
|
|
10
11
|
const planners = job.tasks.filter(task => task.kind === 'planner');
|
|
11
|
-
return planners.some(task => task.state === 'SUCCEEDED' && task.plannerResult?.objective_status === 'satisfied')
|
|
12
|
+
return planners.some(task => task.state === 'SUCCEEDED' && task.plannerResult?.objective_status === 'satisfied')
|
|
13
|
+
&& implementationTasks(job).every(task => task.state === 'SUCCEEDED');
|
|
12
14
|
}
|
|
13
15
|
export function schedule(job) {
|
|
14
16
|
reconcileTaskDependencies(job);
|