@theihtisham/agent-shadow-brain 7.22.0 → 7.22.1

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.
Files changed (66) hide show
  1. package/CHANGELOG.md +7 -1
  2. package/README.md +7 -3
  3. package/dist/brain/auto-update.js +1 -1
  4. package/dist/brain/brain-portability.js +1 -1
  5. package/dist/brain/client-integrations.js +1 -1
  6. package/dist/brain/context-efficiency.d.ts.map +1 -1
  7. package/dist/brain/mcp-presence.js +2 -2
  8. package/dist/brain/mcp-server.js +5 -5
  9. package/dist/brain/native-codex.js +1 -1
  10. package/dist/brain/orchestrator.js +1 -1
  11. package/dist/brain/project-hub-pdf-worker.js +57 -57
  12. package/dist/brain/project-hub-store.js +11 -11
  13. package/dist/cli.js +1 -1
  14. package/dist/dashboard/brain-hub-agent-dock.js +252 -252
  15. package/dist/dashboard/brain-hub-controls.js +61 -61
  16. package/dist/dashboard/brain-hub-exchanges.js +80 -80
  17. package/dist/dashboard/brain-hub-graph.js +336 -336
  18. package/dist/dashboard/brain-hub-html.js +78 -78
  19. package/dist/dashboard/brain-hub-live.js +149 -149
  20. package/dist/dashboard/brain-hub-managed-skills.js +18 -18
  21. package/dist/dashboard/brain-hub-native.js +42 -42
  22. package/dist/dashboard/live-workspace-html.js +1 -1
  23. package/dist/dashboard/project-feedback-html.js +211 -211
  24. package/dist/dashboard/project-kit-html.js +353 -353
  25. package/dist/dashboard/server.js +1 -1
  26. package/dist/dashboard/v6-dashboard-html.js +4261 -4261
  27. package/dist/dashboard/workspace-api.js +1 -1
  28. package/dist/dashboard/workspace-html.js +2534 -2534
  29. package/dist/dashboard/workspace-status.js +1 -1
  30. package/dist/project-cli.js +1 -1
  31. package/docs/BRAND_ASSETS.md +36 -36
  32. package/docs/COMPARISON.md +22 -22
  33. package/docs/COMPONENTS.md +66 -66
  34. package/docs/CONTEXT_LAB.md +79 -79
  35. package/docs/INTEGRATIONS.md +69 -69
  36. package/docs/LEARNING.md +45 -45
  37. package/docs/PROJECT_KIT.md +97 -97
  38. package/docs/SHARING.md +13 -13
  39. package/docs/SHOWCASE.md +87 -87
  40. package/docs/STATS.md +21 -21
  41. package/docs/TROUBLESHOOTING.md +42 -42
  42. package/docs/UPGRADE_PLAN_v7.0.0.md +203 -203
  43. package/docs/WORKFLOW_INTEGRATION.md +125 -125
  44. package/docs/evaluation/CONTEXT_EVALUATION_v7.1.4.json +1818 -1818
  45. package/docs/evaluation/CONTEXT_EVALUATION_v7.1.4.md +36 -36
  46. package/docs/launch/COMPONENT_MAP_v7.1.4.md +122 -122
  47. package/docs/launch/PROJECT_KIT_PLAN_v7.1.4.md +110 -110
  48. package/docs/launch/PROJECT_LEARNING_PLAN_v7.1.4.md +63 -63
  49. package/docs/launch/RELEASE_ACCEPTANCE_v7.22.0.md +48 -48
  50. package/docs/launch/RELEASE_CHECKLIST_v7.0.0.md +24 -24
  51. package/docs/launch/RELEASE_NOTES_v7.0.0.md +44 -44
  52. package/docs/launch/RELEASE_NOTES_v7.1.0.md +32 -32
  53. package/docs/launch/RELEASE_NOTES_v7.1.3.md +40 -40
  54. package/docs/launch/RELEASE_NOTES_v7.1.4.md +30 -30
  55. package/docs/launch/RELEASE_NOTES_v7.2.0.md +24 -24
  56. package/docs/launch/RELEASE_NOTES_v7.22.0.md +53 -53
  57. package/docs/launch/RELEASE_NOTES_v7.22.1.md +11 -0
  58. package/docs/launch/RESEARCH_AND_PLAN_v7.1.4.md +255 -255
  59. package/docs/launch/RESEARCH_AND_PLAN_v7.22.0.md +672 -672
  60. package/package.json +7 -3
  61. package/skills/shadow-debug/SKILL.md +16 -16
  62. package/skills/shadow-implement/SKILL.md +16 -16
  63. package/skills/shadow-release/SKILL.md +16 -16
  64. package/skills/shadow-research/SKILL.md +14 -14
  65. package/skills/shadow-review/SKILL.md +14 -14
  66. package/skills/shadow-workflow/SKILL.md +39 -39
@@ -1,63 +1,63 @@
1
- export const BRAIN_HUB_CONTROLS = String.raw `
2
- function projectControls(){
3
- if(!local)return '';
4
- if(state.errors.policy)return panel('Project sharing',error('policy','project controls'));
5
- const view=state.policy;
6
- if(!view)return panel('Project sharing',empty('Loading project controls','Reading sharing and context preferences.'));
7
- const snapshot=view.policy;
8
- const disabled=state.pending?' disabled':'';
9
- const slider=(name,label,min,max,value,suffix)=>'<label><span class="row">'+esc(label)+' <output class="mono cyan" for="policy-'+name+'" data-policy-output="'+name+'">'+fmt(value)+'</output></span>'+
10
- '<input id="policy-'+name+'" name="'+name+'" type="range" min="'+min+'" max="'+max+'" value="'+value+'" aria-label="'+esc(label)+'" aria-valuetext="'+fmt(value)+' '+suffix+'"'+disabled+'></label>';
11
- const ceilings='<form class="form" data-form="policy-context">'+slider('maxTokens','Maximum estimated context tokens',200,12000,snapshot.context.maxTokens,'estimated tokens')+
12
- slider('maxEntries','Maximum context entries',1,30,snapshot.context.maxEntries,'entries')+submit('Save context limits')+'</form>';
13
- const tools=list(arr(view.tools).map(tool=>{
14
- const on=arr(snapshot.tools).find(entry=>entry.tool===tool)?.enabled!==false;
15
- return '<li class="item"><div class="row"><strong>'+esc(hostName(tool))+'</strong>'+btn(on?'Enabled':'Disabled','role="switch" aria-checked="'+on+'" aria-label="Allow '+esc(hostName(tool))+
16
- ' to use project tools" data-policy-tool="'+esc(tool)+'" data-enabled="'+!on+'"'+disabled)+'</div></li>';
17
- }).join(''),'aria-label="Project tools"');
18
- const candidates=arr(view.chats);
19
- const selected=candidates.find(chat=>chat.id===state.policySelection)??candidates[0];
20
- const chats=selected?'<div class="stack"><label class="form">Conversation<select id="policy-chat"><option value="" disabled>Select a conversation</option>'+
21
- candidates.map(chat=>'<option value="'+esc(chat.id)+'" '+(chat.id===selected.id?'selected':'')+'>'+esc(chat.title)+' · '+esc(hostName(chat.tool))+'</option>').join('')+
22
- '</select></label><div class="row"><span>Share context from this chat</span>'+btn(selected.shareContext?'Sharing':'Private to operator',
23
- 'role="switch" aria-label="Share context from the selected chat" aria-checked="'+!!selected.shareContext+'" data-policy-chat="'+esc(selected.id)+'" data-enabled="'+!selected.shareContext+'"'+disabled)+
24
- '</div>'+(selected.inheritedBlocked?'<p class="small amber">An earlier handoff in this conversation is unavailable to agents.</p>':'')+
25
- '<form class="form" data-form="policy-role" data-id="'+esc(selected.id)+'"><label>Coordination role<select name="role">'+
26
- [['','Unassigned'],['lead','Lead'],['worker','Worker'],['observer','Observer']].map(([value,label])=>'<option value="'+value+'" '+((selected.role??'')===value?'selected':'')+'>'+label+'</option>').join('')+
27
- '</select></label>'+submit('Save role','')+'</form></div>':empty('No shared conversations yet','Open or import a conversation to set its sharing and role.');
28
- return panel('Project sharing','<div class="panel-body stack"><div class="two"><section class="stack"><h3>Context limits</h3>'+ceilings+'</section>'+
29
- '<section class="stack"><h3>Conversation access</h3>'+chats+'</section></div><details id="policy-tools"><summary>Tool participation</summary>'+tools+
30
- '<p class="small muted">Applies to client labels connected to this project’s Shadow Brain. Role assignments are coordination labels.</p></details></div>',chip('Revision '+snapshot.revision));
31
- }
32
- function installPolicy(value){
33
- if(state.policy?.policy.revision>value.policy.revision)return false;
34
- const changed=JSON.stringify(state.policy)!==JSON.stringify(value);
35
- const prior=state.context?.policy?.revision;
36
- state.policy=value;
37
- if(prior!==undefined&&prior!==value.policy.revision){
38
- state.context=null;state.comparison=null;
39
- if(state.view==='context')status('Project controls changed. Build a fresh context pack.');
40
- }
41
- return changed;
42
- }
43
- async function saveProjectPolicy(command){
44
- if(!state.policy)return;
45
- try {
46
- const result=await api('project-policy',json({...command,expectedRevision:state.policy.policy.revision}));
47
- installPolicy(result);delete state.errors.policy;
48
- }catch(failure){
49
- if(failure.status===409){
50
- try{installPolicy(await api('project-policy'));render(true);}catch{}
51
- }
52
- throw failure;
53
- }
54
- }
55
- function reflectPolicySlider(target){
56
- if(!target.id?.startsWith('policy-')||target.type!=='range')return;
57
- const output=target.parentElement.querySelector('output');
58
- const text=fmt(Number(target.value));
59
- if(output)output.textContent=text;
60
- target.setAttribute('aria-valuetext',text+(target.name==='maxTokens'?' estimated tokens':' entries'));
61
- }
1
+ export const BRAIN_HUB_CONTROLS = String.raw `
2
+ function projectControls(){
3
+ if(!local)return '';
4
+ if(state.errors.policy)return panel('Project sharing',error('policy','project controls'));
5
+ const view=state.policy;
6
+ if(!view)return panel('Project sharing',empty('Loading project controls','Reading sharing and context preferences.'));
7
+ const snapshot=view.policy;
8
+ const disabled=state.pending?' disabled':'';
9
+ const slider=(name,label,min,max,value,suffix)=>'<label><span class="row">'+esc(label)+' <output class="mono cyan" for="policy-'+name+'" data-policy-output="'+name+'">'+fmt(value)+'</output></span>'+
10
+ '<input id="policy-'+name+'" name="'+name+'" type="range" min="'+min+'" max="'+max+'" value="'+value+'" aria-label="'+esc(label)+'" aria-valuetext="'+fmt(value)+' '+suffix+'"'+disabled+'></label>';
11
+ const ceilings='<form class="form" data-form="policy-context">'+slider('maxTokens','Maximum estimated context tokens',200,12000,snapshot.context.maxTokens,'estimated tokens')+
12
+ slider('maxEntries','Maximum context entries',1,30,snapshot.context.maxEntries,'entries')+submit('Save context limits')+'</form>';
13
+ const tools=list(arr(view.tools).map(tool=>{
14
+ const on=arr(snapshot.tools).find(entry=>entry.tool===tool)?.enabled!==false;
15
+ return '<li class="item"><div class="row"><strong>'+esc(hostName(tool))+'</strong>'+btn(on?'Enabled':'Disabled','role="switch" aria-checked="'+on+'" aria-label="Allow '+esc(hostName(tool))+
16
+ ' to use project tools" data-policy-tool="'+esc(tool)+'" data-enabled="'+!on+'"'+disabled)+'</div></li>';
17
+ }).join(''),'aria-label="Project tools"');
18
+ const candidates=arr(view.chats);
19
+ const selected=candidates.find(chat=>chat.id===state.policySelection)??candidates[0];
20
+ const chats=selected?'<div class="stack"><label class="form">Conversation<select id="policy-chat"><option value="" disabled>Select a conversation</option>'+
21
+ candidates.map(chat=>'<option value="'+esc(chat.id)+'" '+(chat.id===selected.id?'selected':'')+'>'+esc(chat.title)+' · '+esc(hostName(chat.tool))+'</option>').join('')+
22
+ '</select></label><div class="row"><span>Share context from this chat</span>'+btn(selected.shareContext?'Sharing':'Private to operator',
23
+ 'role="switch" aria-label="Share context from the selected chat" aria-checked="'+!!selected.shareContext+'" data-policy-chat="'+esc(selected.id)+'" data-enabled="'+!selected.shareContext+'"'+disabled)+
24
+ '</div>'+(selected.inheritedBlocked?'<p class="small amber">An earlier handoff in this conversation is unavailable to agents.</p>':'')+
25
+ '<form class="form" data-form="policy-role" data-id="'+esc(selected.id)+'"><label>Coordination role<select name="role">'+
26
+ [['','Unassigned'],['lead','Lead'],['worker','Worker'],['observer','Observer']].map(([value,label])=>'<option value="'+value+'" '+((selected.role??'')===value?'selected':'')+'>'+label+'</option>').join('')+
27
+ '</select></label>'+submit('Save role','')+'</form></div>':empty('No shared conversations yet','Open or import a conversation to set its sharing and role.');
28
+ return panel('Project sharing','<div class="panel-body stack"><div class="two"><section class="stack"><h3>Context limits</h3>'+ceilings+'</section>'+
29
+ '<section class="stack"><h3>Conversation access</h3>'+chats+'</section></div><details id="policy-tools"><summary>Tool participation</summary>'+tools+
30
+ '<p class="small muted">Applies to client labels connected to this project’s Shadow Brain. Role assignments are coordination labels.</p></details></div>',chip('Revision '+snapshot.revision));
31
+ }
32
+ function installPolicy(value){
33
+ if(state.policy?.policy.revision>value.policy.revision)return false;
34
+ const changed=JSON.stringify(state.policy)!==JSON.stringify(value);
35
+ const prior=state.context?.policy?.revision;
36
+ state.policy=value;
37
+ if(prior!==undefined&&prior!==value.policy.revision){
38
+ state.context=null;state.comparison=null;
39
+ if(state.view==='context')status('Project controls changed. Build a fresh context pack.');
40
+ }
41
+ return changed;
42
+ }
43
+ async function saveProjectPolicy(command){
44
+ if(!state.policy)return;
45
+ try {
46
+ const result=await api('project-policy',json({...command,expectedRevision:state.policy.policy.revision}));
47
+ installPolicy(result);delete state.errors.policy;
48
+ }catch(failure){
49
+ if(failure.status===409){
50
+ try{installPolicy(await api('project-policy'));render(true);}catch{}
51
+ }
52
+ throw failure;
53
+ }
54
+ }
55
+ function reflectPolicySlider(target){
56
+ if(!target.id?.startsWith('policy-')||target.type!=='range')return;
57
+ const output=target.parentElement.querySelector('output');
58
+ const text=fmt(Number(target.value));
59
+ if(output)output.textContent=text;
60
+ target.setAttribute('aria-valuetext',text+(target.name==='maxTokens'?' estimated tokens':' entries'));
61
+ }
62
62
  `;
63
63
  //# sourceMappingURL=brain-hub-controls.js.map
@@ -1,82 +1,82 @@
1
- export const BRAIN_HUB_EXCHANGES = String.raw `
2
- function exchangeKey(event){
3
- if(event?.source!=='measured'||event.transport!=='mcp'||!['tool-start','tool-end'].includes(event.kind)||
4
- !event.projectId||!event.sessionId||!event.agent||!event.tool||!event.correlationId)return null;
5
- return JSON.stringify([event.projectId,event.sessionId,event.agent,event.tool,event.correlationId]);
6
- }
7
- function exchangeClientKey(event){return JSON.stringify([event.projectId,event.agent,event.sessionId]);}
8
- let exchangeCache={events:null,pairs:new Map(),clients:[]};
9
- function observedExchanges(){
10
- if(exchangeCache.events===state.events)return exchangeCache;
11
- const exchanges=new Map(),clients=new Map(),pairs=new Map();
12
- for(const event of state.events){
13
- const key=exchangeKey(event);
14
- if(!key)continue;
15
- const pair=exchanges.get(key)??{requests:[],results:[]};
16
- if(event.kind==='tool-start')pair.requests.push(event);
17
- else pair.results.push(event);
18
- exchanges.set(key,pair);
19
- const client=exchangeClientKey(event);
20
- clients.delete(client);
21
- clients.set(client,event);
22
- }
23
- for(const pair of exchanges.values()){
24
- const request=pair.requests[0],result=pair.results[0];
25
- if(pair.requests.length!==1||pair.results.length!==1||request.sequence>=result.sequence)continue;
26
- pairs.set(request.id,result);
27
- pairs.set(result.id,request);
28
- }
29
- exchangeCache={events:state.events,pairs,clients:[...clients.values()].reverse()};
30
- return exchangeCache;
31
- }
32
- function exchangeLabel(event){
33
- return event.kind==='tool-start'?'Request observed':event.outcome==='success'?'Result ready':
34
- event.outcome==='cancelled'?'Tool cancelled':'Tool error';
35
- }
36
- function exchangeDirection(event){
37
- return event.kind==='tool-start'?'Client → Workspace':'Workspace → Client';
38
- }
39
- function exchangeProject(event){
40
- return arr(state.overview?.projects).find(project=>project.id===event.projectId)?.name??event.projectId;
41
- }
42
- function exchangeMarkup(){
43
- const {clients}=observedExchanges();
44
- const selected=state.replayId?displayEvent():null;
45
- const events=state.replayId?(exchangeKey(selected)?[selected]:[]):clients.slice(0,3);
46
- const mode=state.replayId?'Replay':state.errors.telemetry||state.connection==='offline'?'Last loaded':'Latest';
47
- const label=state.replayId?mode:mode+(clients.length?' · '+(clients.length>3?'3 of ':'')+clients.length+' client sessions':'');
48
- const rows=events.map(event=>{
49
- const incoming=event.kind==='tool-start';
50
- const isError=!incoming&&event.outcome!=='success';
51
- const host=hostName(event.agent),project=exchangeProject(event);
52
- const client='<span>'+esc(host)+' <small class="muted mono" aria-label="Session suffix '+esc(event.sessionId.slice(-6))+'">'+esc(event.sessionId.slice(-6))+'</small></span>';
53
- const workspace='<span class="exchange-workspace">Workspace</span>',arrow='<span class="exchange-arrow" aria-hidden="true"></span><span class="sr-only"> to </span>';
54
- const route='<span class="exchange-route" title="'+esc(exchangeDirection(event)+' · '+project)+'">'+(incoming?client+arrow+workspace:workspace+arrow+client)+'</span>';
55
- return '<li><button class="exchange-row" type="button" data-event="'+esc(event.id)+'" aria-pressed="'+(state.replayId===event.id)+'" title="'+esc(project+' · '+event.sessionId)+'">'+route+
56
- '<span class="exchange-summary"><strong>'+esc(event.tool)+'</strong><span class="'+(isError?'red':incoming?'blue':'cyan')+'">'+exchangeLabel(event)+'</span></span><time class="mono muted" datetime="'+esc(event.timestamp)+'">'+esc(time(event.timestamp))+'</time></button></li>';
57
- }).join('');
58
- const message=state.replayExpired?'The selected replay record is outside the loaded history.':selected?'This event does not have a measured MCP request or result direction.':state.errors.telemetry?'The activity journal is unavailable.':
59
- state.connection==='offline'?'The workspace is offline.':!state.live?'Live activity is off.':'Awaiting a measured MCP tool exchange.';
60
- return '<div class="exchange-head"><h3>MCP exchanges</h3><span class="small muted">'+esc(label)+'</span></div>'+
61
- (rows?list(rows,'aria-label="Observed MCP client sessions"','exchange-list'):'<p class="exchange-empty small muted">'+esc(message)+'</p>');
62
- }
63
- function updateExchanges(){
64
- const container=$('graph-exchanges');
65
- if(!container)return;
66
- const markup=exchangeMarkup();
67
- if(container.dataset.markup===markup)return;
68
- const active=container.querySelector('[data-event]:focus')?.dataset.event;
69
- container.innerHTML=markup;container.dataset.markup=markup;
70
- if(active)[...container.querySelectorAll('[data-event]')].find(row=>row.dataset.event===active)?.focus({preventScroll:true});
71
- }
72
- function pairedExchangeMarkup(event){
73
- if(!exchangeKey(event))return '';
74
- const other=observedExchanges().pairs.get(event.id);
75
- const isRequest=event.kind==='tool-start';
76
- return '<dl class="facts">'+fact('Boundary',exchangeDirection(event))+fact('Observation',exchangeLabel(event))+fact('Project',exchangeProject(event))+'</dl>'+
77
- (other?'<button class="btn quiet" type="button" data-event="'+esc(other.id)+'">'+(isRequest?'Inspect paired result':'Inspect paired request')+'</button>':
78
- '<p class="small muted">'+(isRequest?'A matching result is absent from loaded records.':'A matching request is absent from loaded records.')+'</p>')+
79
- '<p class="small muted">The journal records the tool boundary. Model consumption is unobserved.</p>';
80
- }
1
+ export const BRAIN_HUB_EXCHANGES = String.raw `
2
+ function exchangeKey(event){
3
+ if(event?.source!=='measured'||event.transport!=='mcp'||!['tool-start','tool-end'].includes(event.kind)||
4
+ !event.projectId||!event.sessionId||!event.agent||!event.tool||!event.correlationId)return null;
5
+ return JSON.stringify([event.projectId,event.sessionId,event.agent,event.tool,event.correlationId]);
6
+ }
7
+ function exchangeClientKey(event){return JSON.stringify([event.projectId,event.agent,event.sessionId]);}
8
+ let exchangeCache={events:null,pairs:new Map(),clients:[]};
9
+ function observedExchanges(){
10
+ if(exchangeCache.events===state.events)return exchangeCache;
11
+ const exchanges=new Map(),clients=new Map(),pairs=new Map();
12
+ for(const event of state.events){
13
+ const key=exchangeKey(event);
14
+ if(!key)continue;
15
+ const pair=exchanges.get(key)??{requests:[],results:[]};
16
+ if(event.kind==='tool-start')pair.requests.push(event);
17
+ else pair.results.push(event);
18
+ exchanges.set(key,pair);
19
+ const client=exchangeClientKey(event);
20
+ clients.delete(client);
21
+ clients.set(client,event);
22
+ }
23
+ for(const pair of exchanges.values()){
24
+ const request=pair.requests[0],result=pair.results[0];
25
+ if(pair.requests.length!==1||pair.results.length!==1||request.sequence>=result.sequence)continue;
26
+ pairs.set(request.id,result);
27
+ pairs.set(result.id,request);
28
+ }
29
+ exchangeCache={events:state.events,pairs,clients:[...clients.values()].reverse()};
30
+ return exchangeCache;
31
+ }
32
+ function exchangeLabel(event){
33
+ return event.kind==='tool-start'?'Request observed':event.outcome==='success'?'Result ready':
34
+ event.outcome==='cancelled'?'Tool cancelled':'Tool error';
35
+ }
36
+ function exchangeDirection(event){
37
+ return event.kind==='tool-start'?'Client → Workspace':'Workspace → Client';
38
+ }
39
+ function exchangeProject(event){
40
+ return arr(state.overview?.projects).find(project=>project.id===event.projectId)?.name??event.projectId;
41
+ }
42
+ function exchangeMarkup(){
43
+ const {clients}=observedExchanges();
44
+ const selected=state.replayId?displayEvent():null;
45
+ const events=state.replayId?(exchangeKey(selected)?[selected]:[]):clients.slice(0,3);
46
+ const mode=state.replayId?'Replay':state.errors.telemetry||state.connection==='offline'?'Last loaded':'Latest';
47
+ const label=state.replayId?mode:mode+(clients.length?' · '+(clients.length>3?'3 of ':'')+clients.length+' client sessions':'');
48
+ const rows=events.map(event=>{
49
+ const incoming=event.kind==='tool-start';
50
+ const isError=!incoming&&event.outcome!=='success';
51
+ const host=hostName(event.agent),project=exchangeProject(event);
52
+ const client='<span>'+esc(host)+' <small class="muted mono" aria-label="Session suffix '+esc(event.sessionId.slice(-6))+'">'+esc(event.sessionId.slice(-6))+'</small></span>';
53
+ const workspace='<span class="exchange-workspace">Workspace</span>',arrow='<span class="exchange-arrow" aria-hidden="true"></span><span class="sr-only"> to </span>';
54
+ const route='<span class="exchange-route" title="'+esc(exchangeDirection(event)+' · '+project)+'">'+(incoming?client+arrow+workspace:workspace+arrow+client)+'</span>';
55
+ return '<li><button class="exchange-row" type="button" data-event="'+esc(event.id)+'" aria-pressed="'+(state.replayId===event.id)+'" title="'+esc(project+' · '+event.sessionId)+'">'+route+
56
+ '<span class="exchange-summary"><strong>'+esc(event.tool)+'</strong><span class="'+(isError?'red':incoming?'blue':'cyan')+'">'+exchangeLabel(event)+'</span></span><time class="mono muted" datetime="'+esc(event.timestamp)+'">'+esc(time(event.timestamp))+'</time></button></li>';
57
+ }).join('');
58
+ const message=state.replayExpired?'The selected replay record is outside the loaded history.':selected?'This event does not have a measured MCP request or result direction.':state.errors.telemetry?'The activity journal is unavailable.':
59
+ state.connection==='offline'?'The workspace is offline.':!state.live?'Live activity is off.':'Awaiting a measured MCP tool exchange.';
60
+ return '<div class="exchange-head"><h3>MCP exchanges</h3><span class="small muted">'+esc(label)+'</span></div>'+
61
+ (rows?list(rows,'aria-label="Observed MCP client sessions"','exchange-list'):'<p class="exchange-empty small muted">'+esc(message)+'</p>');
62
+ }
63
+ function updateExchanges(){
64
+ const container=$('graph-exchanges');
65
+ if(!container)return;
66
+ const markup=exchangeMarkup();
67
+ if(container.dataset.markup===markup)return;
68
+ const active=container.querySelector('[data-event]:focus')?.dataset.event;
69
+ container.innerHTML=markup;container.dataset.markup=markup;
70
+ if(active)[...container.querySelectorAll('[data-event]')].find(row=>row.dataset.event===active)?.focus({preventScroll:true});
71
+ }
72
+ function pairedExchangeMarkup(event){
73
+ if(!exchangeKey(event))return '';
74
+ const other=observedExchanges().pairs.get(event.id);
75
+ const isRequest=event.kind==='tool-start';
76
+ return '<dl class="facts">'+fact('Boundary',exchangeDirection(event))+fact('Observation',exchangeLabel(event))+fact('Project',exchangeProject(event))+'</dl>'+
77
+ (other?'<button class="btn quiet" type="button" data-event="'+esc(other.id)+'">'+(isRequest?'Inspect paired result':'Inspect paired request')+'</button>':
78
+ '<p class="small muted">'+(isRequest?'A matching result is absent from loaded records.':'A matching request is absent from loaded records.')+'</p>')+
79
+ '<p class="small muted">The journal records the tool boundary. Model consumption is unobserved.</p>';
80
+ }
81
81
  `;
82
82
  //# sourceMappingURL=brain-hub-exchanges.js.map