agents-relay 2.0.146 → 2.0.148

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.
@@ -74,10 +74,8 @@ ${dashboardStyles}
74
74
  <div class="graph-preview">
75
75
  <div id="graph-navigation" class="graph-navigation" aria-label="Graph navigation"><button type="button" id="graph-back" class="refresh-button">Back</button><button type="button" id="graph-forward" class="refresh-button">Forward</button><button type="button" id="graph-entry" class="refresh-button">Entry</button><span id="graph-breadcrumb" class="subtle"></span></div>
76
76
  <div id="graph-detail" class="graph-source" aria-live="polite" hidden></div>
77
- <div id="graph-links" class="graph-navigation" aria-label="Linked subgraphs"></div>
78
- <div class="graph-preview-head"><h3 id="graph-title">Select a graph</h3><button type="button" id="graph-maximize" class="refresh-button">Maximize graph</button><span id="graph-path" class="subtle"></span></div>
77
+ <div class="graph-preview-head"><h3 id="graph-title">Select a graph</h3><button type="button" id="graph-maximize" class="refresh-button">Maximize graph</button></div><p id="graph-description" class="subtle"></p><span id="graph-path" class="subtle"></span>
79
78
  <div id="graph-canvas" class="graph-canvas"><p class="empty">Select a graph to inspect it.</p></div>
80
- <details class="graph-source-details"><summary>Mermaid source</summary><pre id="graph-source" class="graph-source"></pre></details>
81
79
  </div>
82
80
  </div>
83
81
  </div>
@@ -150,7 +148,7 @@ const graphList=document.querySelector('#graph-list');
150
148
  const graphTitle=document.querySelector('#graph-title');
151
149
  const graphPath=document.querySelector('#graph-path');
152
150
  const graphCanvas=document.querySelector('#graph-canvas');
153
- const graphSource=document.querySelector('#graph-source');
151
+ const graphDescription=document.querySelector('#graph-description');
154
152
  const rulesText=document.querySelector('#rules-text');
155
153
  const rulesMeta=document.querySelector('#rules-meta');
156
154
  const rulesStatus=document.querySelector('#rules-status');
@@ -295,7 +293,6 @@ function githubUsageCard(effective,status){
295
293
  async function drawUsage(){try{const overview=await loadJSON('/api/usage');usageRoot.replaceChildren();usageMeta.textContent='Real account telemetry when available';const providers=Array.isArray(overview.providers)?overview.providers:[];const credits=Array.isArray(overview.credits)?overview.credits:[];const grid=element('div','usage-providers');if(overview.githubEffective||overview.githubStatus)grid.append(githubUsageCard(overview.githubEffective,overview.githubStatus));for(const provider of providers)grid.append(usageProvider(provider));for(const provider of credits)grid.append(creditProvider(provider));if(!grid.children.length){usageRoot.append(element('p','empty',text('Usage telemetry is unavailable.')));return;}usageRoot.append(grid);}catch(error){usageMeta.textContent='Unavailable';usageRoot.replaceChildren(element('p','error-state',text('Usage unavailable: '+error.message)));}}
296
294
  function selectedWorkflowGraph(){return workflowGraphs.find(graph=>graph.id===selectedGraphId)||null;}
297
295
  function graphLinks(source){const links=new Map();for(const line of source.split('\\n')){const match=/^\\s*click\\s+([A-Za-z0-9_]+)\\s+href\\s+"([a-z0-9-]+\\.mmd)"(?:\\s+"[^"\\n]*")?\\s*$/.exec(line);if(!match)continue;const id=match[2].slice(0,-4);if(workflowGraphs.some(graph=>graph.id===id))links.set(match[1],id);}return links;}
298
- function graphTargets(id){const graph=selectedWorkflowGraph();return graph?[...new Set(graphLinks(graph.source).values())]:[];}
299
296
  function graphFromHash(){if(location.hash==='#/graphs'||location.hash==='#/graphs/entry')return 'main';if(!location.hash.startsWith('#/graphs/'))return null;const id=location.hash.slice(9);return /^[a-z0-9-]+$/.test(id)?id:null;}
300
297
  const WORKFLOW_NAV_KEY='agents-relay:workflow-navigation';
301
298
  function graphHistory(){try{const value=JSON.parse(sessionStorage.getItem(WORKFLOW_NAV_KEY)||'null');if(value&&Array.isArray(value.entries)&&value.entries.every(id=>typeof id==='string'&&/^[a-z0-9-]+$/.test(id)))return value;}catch{}return {entries:[]};}
@@ -304,7 +301,7 @@ function graphHistoryIndex(){const n=history.state?.workflowIndex;return Number.
304
301
  function initializeGraphHistory(){const route=graphFromHash();if(route===null)return;let data=graphHistory();const index=graphHistoryIndex();if(index!==null&&data.entries[index]===route)return;data={entries:[route]};saveGraphHistory(data);history.replaceState({...history.state,workflowIndex:0,workflowPath:route==='main'?['main']:['main',route]},'');}
305
302
  function navigateGraph(id){if(id!=='entry'&&!workflowGraphs.some(graph=>graph.id===id))return;if(graphFromHash()===null)return;initializeGraphHistory();const data=graphHistory();const current=graphHistoryIndex()??0;const path=history.state?.workflowPath;const valid=Array.isArray(path)&&path.at(-1)===graphFromHash()&&path[0]==='main';const nextPath=id==='main'?['main']:[...(valid?path:['main']),id];data.entries=data.entries.slice(0,current+1);data.entries.push(id);saveGraphHistory(data);history.pushState({workflowIndex:current+1,workflowPath:nextPath},'','#/graphs/'+id);syncGraphRoute();}
306
303
  function syncGraphRoute(){const route=graphFromHash();if(route===null)return;initializeGraphHistory();selectedGraphId=route;renderGraphList();void renderSelectedGraph();}
307
- function renderGraphNavigation(){const graph=selectedWorkflowGraph();initializeGraphHistory();const data=graphHistory();const index=graphHistoryIndex()??0;document.querySelector('#graph-back').disabled=index<=0;document.querySelector('#graph-forward').disabled=index>=data.entries.length-1;const path=history.state?.workflowPath;const names=Array.isArray(path)&&path.at(-1)===selectedGraphId?path:[selectedGraphId==='main'?'main':'main',...(selectedGraphId==='main'?[]:[selectedGraphId])];document.querySelector('#graph-breadcrumb').textContent=names.map(id=>id==='main'?'Main (conceptual)':workflowGraphs.find(g=>g.id===id)?.name||id).join(' / ');const links=document.querySelector('#graph-links');links.replaceChildren();for(const id of graphTargets(selectedGraphId)){if(!workflowGraphs.some(g=>g.id===id))continue;const button=element('button','refresh-button',text('Open '+id));button.type='button';button.addEventListener('click',()=>navigateGraph(id));links.append(button);}}
304
+ function renderGraphNavigation(){const graph=selectedWorkflowGraph();initializeGraphHistory();const data=graphHistory();const index=graphHistoryIndex()??0;document.querySelector('#graph-back').disabled=index<=0;document.querySelector('#graph-forward').disabled=index>=data.entries.length-1;const path=history.state?.workflowPath;const names=Array.isArray(path)&&path.at(-1)===selectedGraphId?path:[selectedGraphId==='main'?'main':'main',...(selectedGraphId==='main'?[]:[selectedGraphId])];document.querySelector('#graph-breadcrumb').textContent=names.map(id=>id==='main'?'Main (conceptual)':workflowGraphs.find(g=>g.id===id)?.name||id).join(' / ');}
308
305
  function renderGraphList(){graphList.replaceChildren();if(!workflowGraphs.length){graphList.append(element('p','empty',text('No workflow graphs found.')));return;}for(const graph of workflowGraphs){const button=document.createElement('button');button.type='button';button.className='graph-button';button.setAttribute('aria-current',String(graph.id===selectedGraphId));button.append(element('strong','',text(graph.name)),element('span','',text(graph.path)));button.addEventListener('click',()=>navigateGraph(graph.id));graphList.append(button);}}
309
306
  async function graphDetail(kind,name){const panel=document.querySelector('#graph-detail');panel.hidden=false;panel.replaceChildren(element('strong','',text(kind+': '+name)),element('p','subtle',text('Loading authoritative references…')));try{const params=new URLSearchParams({graph:selectedGraphId,kind,name});const result=await loadJSON('/api/graph-symbol?'+params);panel.replaceChildren(element('strong','',text(kind+': '+name)));const sections=[['Graph',[result.graph]],['Canonical contract',result.contracts],['Implementation',result.implementation],['Tests',result.tests]];for(const [heading,refs] of sections){panel.append(element('p','detail-label',text(heading)));if(!refs?.length){panel.append(element('p','subtle',text('No exact symbol reference found.')));continue;}for(const ref of refs){const link=element('a','',text(ref.path+(ref.line>0?':'+ref.line:'')+' ['+(ref.evidence==='exact-token'?'verified graph token':'text-search suggestion')+']'));if(WORKFLOW_SOURCE_REF){link.href='https://github.com/lalalic/agents-relay/blob/'+WORKFLOW_SOURCE_REF+'/'+ref.path+(ref.line>0?'#L'+ref.line:'');link.target='_blank';link.rel='noopener noreferrer';}else{link.removeAttribute('href');link.title='Source revision unavailable';}link.target='_blank';link.rel='noopener noreferrer';panel.append(link,document.createTextNode(' '));}}panel.scrollIntoView({block:'nearest'});}catch(error){panel.append(element('p','error-state',text('Reference lookup unavailable: '+error.message)));}}
310
307
  function interactiveNode(node,callback,label){node.classList.add('drillable');node.setAttribute('tabindex','0');node.setAttribute('role','button');node.setAttribute('aria-label',label);node.addEventListener('click',callback);node.addEventListener('keydown',event=>{if(event.key==='Enter'||event.key===' '){event.preventDefault();callback();}});}
@@ -312,7 +309,7 @@ function graphNodeDefinitions(source){const result=new Map();for(const line of s
312
309
  function addNodeLabel(node,label){const ns='http://www.w3.org/2000/svg';const old=node.querySelector('g.label');if(old)old.remove();const textNode=document.createElementNS(ns,'text');textNode.setAttribute('x','0');textNode.setAttribute('y','0');textNode.setAttribute('text-anchor','middle');textNode.setAttribute('dominant-baseline','middle');textNode.setAttribute('fill','#182536');textNode.setAttribute('font-size','13');const rect=node.querySelector('rect.label-container,rect.basic,rect');const width=Math.max(65,Number(rect?.getAttribute('width')||135)-14);const maxChars=Math.max(9,Math.floor(width/7.2));const words=label.split(/\\s+/);const lines=[];let current='';for(const word of words){if(current&&(current+' '+word).length>maxChars){lines.push(current);current=word;}else current=current?current+' '+word:word;}if(current)lines.push(current);for(let i=0;i<lines.length;i++){const tspan=document.createElementNS(ns,'tspan');tspan.setAttribute('x','0');tspan.setAttribute('dy',i===0?String(-((lines.length-1)*7)):'14');tspan.textContent=lines[i];textNode.append(tspan);}node.append(textNode);}
313
310
  function sanitizeGraphSvg(markup){const parsed=new DOMParser().parseFromString(markup.replace(/^<svg\\b/,'<svg xmlns:xlink="http://www.w3.org/1999/xlink"'),'image/svg+xml');const source=parsed.documentElement;if(source.localName!=='svg'||parsed.querySelector('parsererror'))throw new Error('Invalid SVG');const ns='http://www.w3.org/2000/svg';const elements=new Set(['svg','g','path','rect','circle','ellipse','line','polyline','polygon','text','tspan','defs','marker','title','desc','clipPath']);const attributes=new Set(['id','class','viewBox','width','height','x','y','x1','y1','x2','y2','cx','cy','r','rx','ry','d','points','transform','fill','stroke','stroke-width','stroke-dasharray','stroke-linecap','stroke-linejoin','opacity','fill-opacity','stroke-opacity','font-size','font-family','font-weight','text-anchor','dominant-baseline','markerWidth','markerHeight','markerUnits','refX','refY','orient','preserveAspectRatio','clip-path','marker-start','marker-mid','marker-end','role','aria-label']);const clean=node=>{if(node.nodeType===3)return document.createTextNode(node.textContent||'');if(node.nodeType!==1||node.namespaceURI!==ns||!elements.has(node.localName))return null;const out=document.createElementNS(ns,node.localName);for(const attr of node.attributes){if(!attr.namespaceURI&&attr.name==='style'){for(const declaration of attr.value.split(';')){const split=declaration.indexOf(':');if(split<0)continue;const property=declaration.slice(0,split).trim();const cssValue=declaration.slice(split+1).trim();if((property==='stroke'||property==='fill')&&/^(?:#[0-9a-fA-F]{3,8}|rgb\\([0-9.,%\\s]+\\)|none|currentColor)$/.test(cssValue))out.setAttribute(property,cssValue);else if(property==='stroke-width'&&/^[0-9]+(?:\\.[0-9]+)?(?:px)?$/.test(cssValue))out.setAttribute(property,cssValue);}continue;}if(attr.namespaceURI||!attributes.has(attr.name))continue;if(['marker-start','marker-mid','marker-end','clip-path'].includes(attr.name)){if(!attr.value.startsWith('url(#')||!attr.value.endsWith(')')||!(/^[a-zA-Z0-9_-]+$/.test(attr.value.slice(5,-1))))continue;}else if(attr.value.toLowerCase().includes('url(')||attr.value.includes('<')||attr.value.includes('>'))continue;out.setAttribute(attr.name,attr.value);}for(const child of node.childNodes){const safe=clean(child);if(safe)out.appendChild(safe);}return out;};return clean(source);}
314
311
  function applyGraphPalette(svg){const ns='http://www.w3.org/2000/svg';for(const path of svg.querySelectorAll('path')){if(path.closest('marker')){if(!path.hasAttribute('fill'))path.setAttribute('fill','#65768a');continue;}if(!path.hasAttribute('fill'))path.setAttribute('fill','none');if(!path.hasAttribute('stroke'))path.setAttribute('stroke','#65768a');}for(const node of svg.querySelectorAll('g.node')){const error=node.classList.contains('failure')||node.classList.contains('exception');for(const shape of node.querySelectorAll('rect,polygon,circle,ellipse')){shape.setAttribute('fill',error?'#ffe4e4':'#f9fbff');shape.setAttribute('stroke',error?'#be3030':'#657f9e');shape.setAttribute('stroke-width','1.3');}for(const label of node.querySelectorAll('text'))label.setAttribute('fill',node.classList.contains('drillable')?'#2367b1':error?'#7c1818':'#182536');}for(const rect of svg.querySelectorAll('rect')){if(!rect.closest('g.node')&&!rect.hasAttribute('fill'))rect.setAttribute('fill','#ffffff');}for(const label of svg.querySelectorAll('text'))if(!label.hasAttribute('fill'))label.setAttribute('fill','#182536');}
315
- async function renderSelectedGraph(){const graph=selectedWorkflowGraph();renderGraphNavigation();document.querySelector('#graph-detail').hidden=true;if(!graph){graphTitle.textContent='Graph not found';graphPath.textContent='';graphSource.textContent='';graphCanvas.replaceChildren(element('p','error-state',text('Graph not found: '+selectedGraphId+'. Select Entry or another graph.')));return;}graphTitle.textContent=graph.name;graphPath.textContent=graph.path;graphSource.textContent=graph.source;graphCanvas.replaceChildren(element('p','subtle',text('Rendering…')));try{if(!window.mermaid)throw new Error('Mermaid renderer unavailable');if(!window.__relayMermaidReady){window.mermaid.initialize({startOnLoad:false,securityLevel:'strict',flowchart:{htmlLabels:false}});window.__relayMermaidReady=true;}const rendered=await window.mermaid.render('relay-graph-'+graph.id.replace(/[^A-Za-z0-9_-]/g,'-'),graph.source.replace(/^\\s*click\\s+[^\\n]*$/gm,''));if(graph.id!==selectedGraphId)return;const svg=sanitizeGraphSvg(rendered.svg);graphCanvas.replaceChildren(svg);if(graph.id!=='entry'){const events=[...new Set([...graph.source.matchAll(/\\|on:\\s*([A-Za-z0-9_.-]+)\\|/g)].map(m=>m[1]))];const links=document.querySelector('#graph-links');for(const event of events){const button=element('button','refresh-button',text('Event: '+event));button.addEventListener('click',()=>graphDetail('Event',event));links.append(button);}}const definitions=graphNodeDefinitions(graph.source);for(const node of svg.querySelectorAll('g.node')){const entry=Array.from(definitions.entries()).find(([key])=>node.id.includes('-flowchart-'+key+'-'));const label=entry?.[1]||'';if(label)addNodeLabel(node,label);const target=entry?.[0];const next=target?graphLinks(graph.source).get(target):null;if(next){interactiveNode(node,()=>navigateGraph(next),'Explore '+target);}else{const match=/^(state|guard|action):\\s*([A-Za-z0-9_.-]+)/.exec(label);if(match)interactiveNode(node,()=>graphDetail(match[1]==='guard'?'Guard':match[1]==='action'?'Action':'State',match[2]),'Inspect '+match[1]+' '+match[2]);}}applyGraphPalette(svg);}catch(error){graphCanvas.replaceChildren(element('p','error-state',text('Visual preview unavailable: '+error.message+'. Mermaid source remains available below.')));}}
312
+ async function renderSelectedGraph(){const graph=selectedWorkflowGraph();renderGraphNavigation();document.querySelector('#graph-detail').hidden=true;if(!graph){graphTitle.textContent='Graph not found';graphPath.textContent='';graphDescription.textContent='';graphCanvas.replaceChildren(element('p','error-state',text('Graph not found: '+selectedGraphId+'. Select Entry or another graph.')));return;}graphTitle.textContent=graph.name;graphDescription.textContent=graph.description||'';graphPath.textContent=graph.path;graphCanvas.replaceChildren(element('p','subtle',text('Rendering…')));try{if(!window.mermaid)throw new Error('Mermaid renderer unavailable');if(!window.__relayMermaidReady){window.mermaid.initialize({startOnLoad:false,securityLevel:'strict',flowchart:{htmlLabels:false}});window.__relayMermaidReady=true;}const rendered=await window.mermaid.render('relay-graph-'+graph.id.replace(/[^A-Za-z0-9_-]/g,'-'),graph.source.replace(/^\\s*click\\s+[^\\n]*$/gm,''));if(graph.id!==selectedGraphId)return;const svg=sanitizeGraphSvg(rendered.svg);graphCanvas.replaceChildren(svg);const definitions=graphNodeDefinitions(graph.source);for(const node of svg.querySelectorAll('g.node')){const entry=Array.from(definitions.entries()).find(([key])=>node.id.includes('-flowchart-'+key+'-'));const label=entry?.[1]||'';if(label)addNodeLabel(node,label);const target=entry?.[0];const next=target?graphLinks(graph.source).get(target):null;if(next){interactiveNode(node,()=>navigateGraph(next),'Explore '+target);}else{const match=/^(state|guard|action):\\s*([A-Za-z0-9_.-]+)/.exec(label);if(match)interactiveNode(node,()=>graphDetail(match[1]==='guard'?'Guard':match[1]==='action'?'Action':'State',match[2]),'Inspect '+match[1]+' '+match[2]);}}applyGraphPalette(svg);}catch(error){graphCanvas.replaceChildren(element('p','error-state',text('Visual preview unavailable: '+error.message+'.')));}}
316
313
  async function drawGraphs(){try{const graphs=await loadJSON('/api/graphs');workflowGraphs=Array.isArray(graphs)?graphs:[];const requested=graphFromHash();selectedGraphId=requested||'main';graphsMeta.textContent=(workflowGraphs.length-1)+' executable workflow graphs · main is conceptual';renderGraphList();await renderSelectedGraph();}catch(error){graphsMeta.textContent='Unavailable';workflowGraphs=[];selectedGraphId='main';renderGraphList();await renderSelectedGraph();graphPath.textContent='Executable graphs unavailable: '+error.message;}}
317
314
  function renderAudit(records){auditLog.replaceChildren();if(!Array.isArray(records)||!records.length){auditLog.append(element('p','empty',text('No schema v5 routing decisions yet.')));return;}for(const record of records){const card=element('article','audit-entry');const head=element('div','audit-entry-head');head.append(element('strong','',text(routeWorker(record)+' · '+value(record?.selected?.model?.model))),element('span','subtle',text(new Date(record.timestamp).toLocaleString())));card.append(head);const correlation=record.correlation||{};card.append(element('div','subtle',text([correlation.job_id,correlation.task_id].filter(Boolean).join(' / ')||'uncorrelated')));const probabilities=record.decision_evidence?.probabilities||{};const gates=(record.gate_results||[]).filter(item=>!item.eligible).map(item=>item.candidate_id+': '+item.rejection_reasons.join(', '));const nl=String.fromCharCode(10);const details=document.createElement('pre');details.textContent='fallback: '+String(Boolean(record.decision_evidence?.fallback))+(Object.keys(probabilities).length?nl+'probabilities: '+JSON.stringify(probabilities,null,2):'')+(gates.length?nl+'rejected: '+gates.join(nl):'');card.append(details);auditLog.append(card);}}
318
315
  async function drawAudit(){auditRefresh.disabled=true;try{renderAudit(await loadJSON('/api/decision-audit'));}catch(error){auditLog.replaceChildren(element('p','error-state',text('Audit unavailable: '+error.message)));}finally{auditRefresh.disabled=false;}}
package/dist/dashboard.js CHANGED
@@ -15,12 +15,17 @@ const SSE_HEARTBEAT_MS = 15000;
15
15
  const WORKFLOW_DIR = fileURLToPath(new URL('../workflow/', import.meta.url));
16
16
  export async function dashboardWorkflowGraphs() {
17
17
  const names = (await readdir(WORKFLOW_DIR)).filter(name => name.endsWith('.mmd')).sort();
18
- return Promise.all(names.map(async (name) => ({
19
- id: name.replace(/\.mmd$/, ''),
20
- name: name === 'main.mmd' ? 'Main / Happy Path' : name.replace(/\.mmd$/, '').split('-').map(part => part.charAt(0).toUpperCase() + part.slice(1)).join(' '),
21
- path: `workflow/${name}`,
22
- source: await readFile(join(WORKFLOW_DIR, name), 'utf8'),
23
- })));
18
+ return Promise.all(names.map(async (name) => {
19
+ const source = await readFile(join(WORKFLOW_DIR, name), 'utf8');
20
+ const metadata = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(source)?.[1] ?? '';
21
+ const field = (key) => metadata.match(new RegExp(`^${key}:\\s*(.+)$`, 'm'))?.[1]?.trim() ?? '';
22
+ return {
23
+ id: name.replace(/\.mmd$/, ''),
24
+ name: field('title') || (name === 'main.mmd' ? 'Main / Happy Path' : name.replace(/\.mmd$/, '').split('-').map(part => part.charAt(0).toUpperCase() + part.slice(1)).join(' ')),
25
+ description: field('description'),
26
+ path: `workflow/${name}`, source,
27
+ };
28
+ }));
24
29
  }
25
30
  function effectiveGitHubUsage(snapshot, runtime) {
26
31
  const candidates = [snapshot?.resources.core, snapshot?.resources.graphql, snapshot?.resources.search, runtime?.resources.core, runtime?.resources.graphql, runtime?.resources.search]
@@ -24,11 +24,30 @@ function parseLabel(raw, line) {
24
24
  }
25
25
  export function parseGraphV2(source) {
26
26
  const lines = source.split(/\r?\n/);
27
+ // Mermaid YAML frontmatter is metadata only; never execute it as graph policy.
28
+ // Preserve original source line positions for diagnostics and coverage reports.
29
+ let graphStart = 0;
30
+ if (lines[0]?.trim() === '---') {
31
+ let closing = -1;
32
+ for (let i = 1; i < lines.length; i += 1) {
33
+ if (lines[i].trim() === '---') {
34
+ closing = i;
35
+ break;
36
+ }
37
+ if (!/^(title|description):\s+[^\r\n]+$/.test(lines[i]))
38
+ fail(i + 1, 'unsupported graph frontmatter field');
39
+ }
40
+ if (closing < 0)
41
+ fail(1, 'unterminated graph frontmatter');
42
+ if (closing === 1)
43
+ fail(1, 'empty graph frontmatter');
44
+ graphStart = closing + 1;
45
+ }
27
46
  let direction = null;
28
47
  let initial = null;
29
48
  const nodes = new Map();
30
49
  const edges = [];
31
- for (let index = 0; index < lines.length; index += 1) {
50
+ for (let index = graphStart; index < lines.length; index += 1) {
32
51
  const lineNumber = index + 1;
33
52
  const line = lines[index].trim();
34
53
  if (!line)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agents-relay",
3
- "version": "2.0.146",
3
+ "version": "2.0.148",
4
4
  "description": "Durable async agent jobs coordinated through GitHub pull requests",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Authoritative Unblock
3
+ description: Validates authoritative unblock requests and safely resumes blocked workflow work.
4
+ ---
1
5
  flowchart LR
2
6
  %% relay: initial blocked
3
7
  blocked["state: blocked"]
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Blocker Resolution
3
+ description: Resolves blockers through verified recovery evidence and graph-authorized decisions.
4
+ ---
1
5
  flowchart LR
2
6
  %% relay: initial waiting
3
7
  waiting["state: waiting"]
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Escalation
3
+ description: Routes unresolved recovery to human escalation and records response outcomes.
4
+ ---
1
5
  flowchart LR
2
6
  %% relay: initial suspected
3
7
  suspected["state: suspected_human_blocker"]
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Interactive Invocation
3
+ description: Controls interactive agent invocation through guarded lifecycle transitions.
4
+ ---
1
5
  flowchart LR
2
6
  %% relay: initial awaiting_decision
3
7
  awaiting_decision["state: awaiting_decision"]
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Job Lifecycle
3
+ description: Defines canonical Job states, completion gates, and terminal transitions.
4
+ ---
1
5
  flowchart LR
2
6
  %% relay: initial draft
3
7
  draft["state: DRAFT"]
package/workflow/main.mmd CHANGED
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Main
3
+ description: Presentation-only entry map linking workflow graphs and explaining contract, graph, code, guard, action, and effect ownership.
4
+ ---
1
5
  %% dashboard: presentation-only — not registered with GraphRuntime or the executable Graph DSL.
2
6
  %% PRINCIPLES (this graph is a readable overview, not an executable policy):
3
7
  %% CONTRACT defines typed events, permissions and invariants; GRAPH defines legal transitions,
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Orchestrator Rescue
3
+ description: Determines when orchestration needs safe intervention or recovery.
4
+ ---
1
5
  flowchart LR
2
6
  %% relay: initial idle
3
7
  idle["state: idle"]
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Planner Orchestration
3
+ description: Guards autonomous planning rounds, interrupted plans, and planner recovery.
4
+ ---
1
5
  flowchart LR
2
6
  %% relay: initial idle
3
7
  idle["state: idle"]
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Planner Trigger
3
+ description: Classifies planning requests as manual, unblock, scheduled, initial, or continuation.
4
+ ---
1
5
  flowchart LR
2
6
  %% relay: initial idle
3
7
  idle["state: idle"]
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Projection Conflict
3
+ description: Detects and resolves conflicting workflow state projections against authoritative facts.
4
+ ---
1
5
  flowchart LR
2
6
  %% relay: initial classify
3
7
  classify["state: classify"]
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Review Lifecycle
3
+ description: Manages review creation, immutable verdicts, changes-required, and re-review.
4
+ ---
1
5
  flowchart LR
2
6
  %% relay: initial none
3
7
  none["state: NONE"]
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Schedule Cycle
3
+ description: Reconciles scheduled execution slots and finishes verified completed slots.
4
+ ---
1
5
  flowchart LR
2
6
  %% relay: initial idle
3
7
  idle["state: idle"]
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Scheduled Run
3
+ description: Controls scheduled-run lifecycle and guarded execution.
4
+ ---
1
5
  flowchart LR
2
6
  %% relay: initial idle
3
7
  idle["state: idle"]
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Task Lifecycle
3
+ description: Defines canonical Task transitions, dispatch guards, failure, and recovery.
4
+ ---
1
5
  flowchart LR
2
6
  %% relay: initial draft
3
7
  draft["state: DRAFT"]
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Task Related Action
3
+ description: Authorizes task-related control actions using current workflow state.
4
+ ---
1
5
  flowchart LR
2
6
  %% relay: initial evaluate
3
7
  evaluate["state: evaluate"]
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Task Resolution
3
+ description: Selects and verifies resolution paths for failed or blocked Tasks.
4
+ ---
1
5
  flowchart LR
2
6
  %% relay: initial unresolved
3
7
  unresolved["state: unresolved"]
@@ -1,3 +1,7 @@
1
+ ---
2
+ title: Troubleshooter
3
+ description: Coordinates diagnosis, recovery, escalation, and resolution of failed Tasks.
4
+ ---
1
5
  flowchart LR
2
6
  %% relay: initial idle
3
7
  idle["state: idle"]