@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,255 +1,255 @@
1
1
  import { BRAIN_HUB_BRAND_ICONS } from './brain-hub-brand-icons.js';
2
- export const BRAIN_HUB_AGENT_DOCK = 'const brainBrandMarks = ' + JSON.stringify(BRAIN_HUB_BRAND_ICONS) + ';\n' + String.raw `
3
- const observedPulses=new Map();
4
- let dockTool=null,dockSession=null,dockPinned=false;
5
- let dockPresenceTimer=0,dockPresenceReceived=0;
6
- const dockVisible=scope=>scope==='overview'||scope==='sessions';
7
- const rosterTool=label=>typeof label==='string'&&label&&label!=='user'&&label!=='portal';
8
- const toolKey=value=>JSON.stringify([value.projectId,value.tool,value.kind,value.identity]);
9
- const toolOrder=['codex','claude-code','deepseek-harness','opencode'];
10
- const presenceClock=()=>Date.parse(state.presence?.checkedAt)+(performance.now()-dockPresenceReceived);
11
- function currentDockConnections(){
12
- if(!state.presence?.enabled||state.errors?.presence||state.connection!=='reachable')return [];
13
- const now=presenceClock();
14
- return arr(state.presence.connections).filter(item=>Date.parse(item.expiresAt)>now);
15
- }
16
- function noteAgentActivity(events){
17
- if(document.hidden||reduced.matches||state.motionPaused||state.replayId||!dockVisible(state.view))return;
18
- const now=Date.now();
19
- for(const event of events)if(rosterTool(event.agent)&&event.projectId&&event.sessionId){
20
- const age=now-Date.parse(event.timestamp);
21
- if(age>=0&&age<6500)observedPulses.set(event.id,{until:now+1300});
22
- }
23
- for(const [id,pulse] of observedPulses)if(pulse.until<now)observedPulses.delete(id);
24
- }
25
- function rosterState(){
26
- const groups=new Map();
27
- const scope=state.project;
28
- const accepts=(projectId,tool)=>projectId&&(!scope||scope===projectId)&&rosterTool(tool);
29
- function group(projectId,tool,kind,identity){
30
- const key=toolKey({projectId,tool,kind,identity});
31
- let record=groups.get(key);
32
- if(!record){record={key,projectId,tool,kind,identity,session:null,event:null,receipt:null};groups.set(key,record);}
33
- return record;
34
- }
35
- const connections=new Map(),hostChats=new Map();
36
- const connectionKey=(projectId,connectionId)=>JSON.stringify([projectId,connectionId]);
37
- for(const session of arr(state.sessions?.sessions)){
38
- const projectId=state.sessions.projectId,tool=session.native?.tool??session.actor?.tool;
39
- const hostId=session.hostSessionId,connection=session.actor?.kind==='agent'&&session.actor?.id?.startsWith(tool+':mcp-')
40
- ?session.actor.id.slice(tool.length+1):null;
41
- if(!accepts(projectId,tool))continue;
42
- const record=group(projectId,tool,'project-session',session.id);
43
- record.session=session;record.connection=connection;
44
- if(hostId){
45
- const key=JSON.stringify([projectId,tool,hostId]);
46
- const list=hostChats.get(key)??[];
47
- list.push(record);hostChats.set(key,list);
48
- }
49
- if(connection){
50
- const key=connectionKey(projectId,connection);
51
- connections.set(key,connections.has(key)&&connections.get(key)!==tool?null:tool);
52
- }
53
- }
54
- for(const connection of currentDockConnections()){
55
- const projectId=state.presence.projectId;
56
- if(!accepts(projectId,connection.tool))continue;
57
- connections.set(connectionKey(projectId,connection.id),connection.tool);
58
- group(projectId,connection.tool,'connection',connection.id).presence=connection;
59
- }
60
- for(const event of state.events){
61
- if(!event.sessionId||!accepts(event.projectId,event.agent))continue;
62
- const measured=event.source==='measured'&&event.transport==='mcp';
63
- const tool=measured&&event.agent==='mcp-client'?connections.get(connectionKey(event.projectId,event.sessionId))??event.agent:event.agent;
64
- const record=group(event.projectId,tool,measured?'connection':'report',event.sessionId);
65
- if(!record.event||event.sequence>record.event.sequence)record.event=event;
66
- }
67
- const models=new Set();
68
- for(const receipt of arr(state.usage?.receipts)){
69
- if(!receipt.sessionId||!accepts(receipt.projectId,receipt.agent))continue;
70
- const matches=hostChats.get(JSON.stringify([receipt.projectId,receipt.agent,receipt.sessionId]))??[];
71
- const record=matches.length===1?matches[0]:group(receipt.projectId,receipt.agent,'conversation',receipt.sessionId);
72
- if(matches.length>1)record.sharedReceipt=true;
73
- if(!record.receipt||receipt.recordedAt>=record.receipt.recordedAt)record.receipt=receipt;
74
- const model=receipt.responseModel??receipt.requestModel;
75
- if(model)models.add(JSON.stringify([receipt.provider??null,model]));
76
- }
77
- const tools=new Map();
78
- for(const record of groups.values()){
79
- const latest=[record.event?.timestamp,record.receipt?.recordedAt,record.session?.lastReportedAt,record.presence?.lastSeenAt].filter(Boolean).sort().at(-1);
80
- record.latest=latest;
81
- if(!tools.has(record.tool))tools.set(record.tool,[]);
82
- tools.get(record.tool).push(record);
83
- }
84
- for(const rows of tools.values())rows.sort((a,b)=>String(b.latest??'').localeCompare(String(a.latest??'')));
85
- const order=tool=>toolOrder.includes(tool)?toolOrder.indexOf(tool):toolOrder.length;
86
- const sorted=[...tools].sort((a,b)=>order(a[0])-order(b[0])||a[0].localeCompare(b[0]));
87
- return {tools:sorted,groups,models:models.size};
88
- }
89
- function toolMark(tool){
90
- const icon=Object.hasOwn(brainBrandMarks,tool)?brainBrandMarks[tool]:'<span>'+esc(hostName(tool).slice(0,2).toUpperCase())+'</span>';
91
- return '<span class="tool-mark" aria-hidden="true">'+icon+'</span>';
92
- }
93
- function toolEnabled(tool){
94
- if(!local||!state.policy||state.errors.policy)return null;
95
- return arr(state.policy.policy.tools).find(item=>item.tool===tool.toLowerCase().trim())?.enabled!==false;
96
- }
97
- function dockAction(record){
98
- const {event,receipt,session}=record;
99
- if(record.kind==='connection'&&event)return [eventLabel(event),evidence(event)];
100
- if(event&&event.timestamp===record.latest)return [eventLabel(event),evidence(event)];
101
- if(receipt&&receipt.recordedAt===record.latest)return ['Model usage receipt','Host-reported'];
102
- if(session)return [session.native||session.sourceId?'Conversation snapshot':session.reportedStatus==='completed'?'Reported completed':
103
- session.reportedStatus==='waiting'?'Reported waiting':'Reported working','Recorded session'];
104
- return record.presence?['No recorded action','Transport heartbeat'] : ['Unavailable','No evidence'];
105
- }
106
- function toolDockInspector(record,records){
107
- const {event,receipt,session}=record;
108
- const [actionLabel,provenance]=dockAction(record);
109
- const actualTitle=session?.native?session.native.titleExact??'Unavailable':session?.title??'Not reported';
110
- const role=arr(state.policy?.chats).find(chat=>chat.id===session?.id)?.role??'Unassigned';
111
- const workspace=arr(state.overview?.projects).find(project=>project.id===record.projectId)?.name??record.projectId;
112
- const counter=value=>Number.isFinite(value)?fmt(value):'Not reported';
113
- const availability=toolEnabled(record.tool);
114
- const labelFor=item=>item.session?(item.session.native?item.session.native.titleExact??'Untitled native snapshot':item.session.title):
115
- (item.kind==='connection'?'MCP connection ':item.kind==='report'?'Host report ':item.sharedReceipt?'Shared chat usage ':'Usage receipt ')+item.identity;
116
- const chooser=records.length>1?list(records.map(item=>{
117
- const model=item.receipt?.responseModel??item.receipt?.requestModel;
118
- return '<li><button class="tool-dock-record" type="button" data-dock-record="'+esc(item.key)+'" aria-pressed="'+(item.key===record.key)+'"><strong>'+
119
- esc(labelFor(item))+'</strong>'+(model?'<small class="muted">'+esc(model)+'</small>':'')+'</button></li>';
120
- }).join(''),'aria-label="Chats and connection evidence"','tool-dock-record-list'):'';
121
- const idLabel=record.kind==='connection'?'MCP connection ID':record.kind==='report'?'Reported session ID':record.kind==='project-session'?'Project session ID':'Host chat ID';
122
- return '<section class="tool-dock-details" id="tool-dock-details" aria-label="'+esc(hostName(record.tool))+' activity details">'+
123
- '<div class="row"><h3>'+esc(hostName(record.tool))+'</h3><div class="actions">'+
124
- (session?btn('Open session','data-dock-open="'+esc(session.id)+'"','quiet'):'')+
125
- btn('Close details','data-dock-close','quiet')+'</div></div>'+chooser+
126
- '<div class="tool-evidence-grid"><dl class="facts">'+fact('Workspace',workspace)+fact('Conversation',actualTitle)+
127
- fact(idLabel,record.identity)+(session?.hostSessionId?fact('Host chat ID',session.hostSessionId):'')+
128
- (record.connection?fact('Reporting MCP connection',record.connection):'')+
129
- fact('Coordination role',role)+fact('Participation',availability===null?'Unavailable':availability?'Enabled':'Disabled')+'</dl>'+
130
- '<dl class="facts">'+fact('Latest recorded action',actionLabel)+fact('Evidence',provenance)+fact('Last seen',isoTime(record.latest))+
131
- (record.presence?fact('MCP heartbeat',isoTime(record.presence.lastSeenAt)): '')+
132
- fact('Latest tool duration',Number.isFinite(event?.durationMs)?fmt(event.durationMs)+' ms · '+evidence(event):'Not recorded')+'</dl>'+
133
- '<dl class="facts">'+fact('Model',receipt?.responseModel??receipt?.requestModel??'Not reported')+fact('Provider',receipt?.provider??'Not reported')+
134
- fact('Host-reported effort',receipt?.reasoningEffort??'Not reported')+fact('Reported input tokens',counter(receipt?.inputTokens))+
135
- fact('Reported output tokens',counter(receipt?.outputTokens))+(receipt?fact('Usage receipt time',isoTime(receipt.recordedAt)):'')+
136
- (record.sharedReceipt?fact('Attribution','Shared chat receipt · individual session unavailable'):'')+'</dl></div></section>';
137
- }
138
- function pickDockRecord(){
139
- if(!dockTool)return;
140
- const records=rosterState().tools.find(([tool])=>tool===dockTool)?.[1]??[];
141
- dockSession=(records.find(item=>item.session)??records[0])?.key??null;
142
- }
143
- function agentDockMarkup(){
144
- const {tools,groups,models}=rosterState();
145
- const visible=tools.slice(0,12);
146
- if(dockTool&&!visible.some(([tool])=>tool===dockTool)){dockTool=null;dockSession=null;dockPinned=false;}
147
- const controls=visible.map(([tool,records])=>{
148
- const availability=toolEnabled(tool);
149
- const latestEvent=records.map(item=>item.event).filter(Boolean).sort((a,b)=>b.sequence-a.sequence)[0];
150
- const chats=new Set(records.filter(item=>item.session).map(item=>JSON.stringify([item.projectId,item.session.hostSessionId??item.identity]))).size;
151
- const workers=records.filter(item=>item.session&&arr(state.policy?.chats).some(chat=>chat.id===item.session.id&&chat.role==='worker')).length;
152
- const reporting=records.filter(item=>item.presence).length;
153
- const description=availability===false?'Participation off':chats?chats+' chat'+(chats===1?'':'s')+(workers?' · '+workers+' worker'+(workers===1?'':'s'):''):
154
- reporting?reporting+' reporting':latestEvent?'Observed '+time(latestEvent.timestamp):'Reported usage';
155
- return '<li><button class="tool-dock-button" type="button" data-dock-tool="'+esc(tool)+'" aria-label="Inspect '+esc(hostName(tool))+'" aria-expanded="'+(tool===dockTool)+'" aria-controls="tool-dock-details">'+
156
- toolMark(tool)+'<span class="tool-dock-text"><strong>'+esc(hostName(tool))+'</strong><small>'+esc(description)+
157
- '</small></span><span class="tool-dock-indicator" data-observed="'+esc(latestEvent?.id)+'" title="'+esc(reporting?reporting+' reporting MCP connections':'No current transport heartbeat')+'" aria-hidden="true"></span></button></li>';
158
- }).join('');
159
- const selection=tools.find(([tool])=>tool===dockTool)?.[1]??[];
160
- const row=selection.find(item=>item.key===dockSession)??selection.find(item=>item.session)??selection[0];
161
- const conversations=new Set([...groups.values()].filter(item=>item.session).map(item=>JSON.stringify([item.projectId,item.tool,item.session.hostSessionId??item.identity]))).size;
162
- const agents=[...groups.values()].filter(item=>item.session?.actor?.kind==='agent').length;
163
- const connections=[...groups.values()].filter(item=>item.kind==='connection').length;
164
- const presence=state.errors.presence||local&&state.connection==='offline'?'Reporting MCP connections unavailable':
165
- state.presence?.enabled===false?'MCP presence recording off':state.presence?fmt(currentDockConnections().length)+' reporting MCP connections':
166
- local?'MCP presence loading':fmt(connections)+' observed MCP connections';
167
- const sourceState=!state.live&&state.features?.features?.liveActivity===false?'Journal display off':
168
- state.errors.telemetry||state.connection==='offline'?'Previously loaded activity':'Recorded activity';
169
- return '<div class="tool-dock-head"><h2>Tool activity</h2><p class="small muted">'+
170
- fmt(tools.length)+' tools <span aria-hidden="true">·</span> '+fmt(agents)+' agent sessions <span aria-hidden="true">·</span> '+fmt(conversations)+' registered chats <span aria-hidden="true">·</span> '+esc(presence)+' <span aria-hidden="true">·</span> '+fmt(models)+' reported models'+
171
- (tools.length>visible.length?' · '+visible.length+' shown':'')+'</p></div>'+
172
- (controls?list(controls,'aria-label="Tools with project evidence"','tool-dock-list'):'<p class="tool-dock-empty small muted">Tool records appear after a measured exchange or explicit host report.</p>')+
173
- (row?toolDockInspector(row,selection):'<div id="tool-dock-details" hidden></div>')+'<p class="tool-dock-caption small muted">'+esc(sourceState)+
174
- ' · Retained evidence'+(state.presence?.enabled&&!state.errors.presence?' · MCP heartbeat window '+Math.round(state.presence.expiresAfterMs/1000)+'s':'')+
175
- (state.errors.sessions?' · Sessions unavailable':'')+(state.errors.usage?' · Usage unavailable':'')+(state.errors.policy?' · Controls unavailable':'')+'</p>';
176
- }
177
- function installDockPresence(value){
178
- state.presence=value;dockPresenceReceived=performance.now();
179
- }
180
- function scheduleDockExpiry(){
181
- clearTimeout(dockPresenceTimer);
182
- if(document.hidden||!dockVisible(state.view)||!state.presence?.enabled||state.errors.presence)return;
183
- const now=presenceClock();
184
- const dates=arr(state.presence.connections).map(item=>Date.parse(item.expiresAt)).filter(time=>Number.isFinite(time));
185
- if(!dates.length||!Number.isFinite(now))return;
186
- dockPresenceTimer=setTimeout(()=>{updateAgentDock();queueLive(['presence']);},Math.max(150,Math.min(...dates)-now+100));
187
- }
188
- function agentDock(){return '<section class="panel tool-dock" id="tool-dock" aria-label="Tool activity">'+agentDockMarkup()+'</section>';}
189
- function updateAgentDock(){
190
- const dock=$('tool-dock');
191
- if(!dock)return;
192
- const focus=document.activeElement;
193
- const key=dock.contains(focus)?focus?.dataset.dockTool:null;
194
- const recordKey=dock.contains(focus)?focus?.dataset.dockRecord:null;
195
- const focused=dock.contains(focus);
196
- const id=focused?focus?.id:null;
197
- const markup=agentDockMarkup();
198
- if(dock.dataset.markup!==markup){
199
- dock.innerHTML=markup;dock.dataset.markup=markup;
200
- if(key)focusDockTool(key);
201
- else if(recordKey)[...dock.querySelectorAll('[data-dock-record]')].find(button=>button.dataset.dockRecord===recordKey)?.focus({preventScroll:true});
202
- else if(id)$(id)?.focus({preventScroll:true});
203
- else if(focused)focusDockTool(dockTool);
204
- }
205
- const now=Date.now();
206
- if(document.hidden||reduced.matches||state.motionPaused||state.replayId||state.connection!=='reachable'||!state.live){
207
- observedPulses.clear();
208
- for(const mark of dock.querySelectorAll('.tool-activity-pulse'))mark.classList.remove('tool-activity-pulse');
209
- return;
210
- }
211
- for(const button of dock.querySelectorAll('[data-dock-tool]')){
212
- const dot=button.querySelector('.tool-dock-indicator');
213
- const id=dot.dataset.observed,pulse=observedPulses.get(id);
214
- if(pulse&&pulse.until>now){
215
- if(dot.dataset.event===id)continue;
216
- dot.dataset.event=id;
217
- dot.classList.remove('tool-activity-pulse');
218
- void dot.offsetWidth;
219
- dot.classList.add('tool-activity-pulse');
220
- }
221
- }
222
- }
223
- let dockFocusRestore=false;
224
- function focusDockTool(tool){
225
- dockFocusRestore=true;
226
- [...$('tool-dock')?.querySelectorAll('[data-dock-tool]')??[]].find(button=>button.dataset.dockTool===tool)?.focus({preventScroll:true});
227
- dockFocusRestore=false;
228
- }
229
- function previewDockTool(target){
230
- const tool=target.closest?.('[data-dock-tool]')?.dataset.dockTool;
231
- if(!tool||dockPinned||dockFocusRestore||tool===dockTool)return;
232
- dockTool=tool;pickDockRecord();updateAgentDock();
233
- }
234
- function handleAgentDock(button){
235
- const data=button.dataset;
236
- if(data.dockTool){
237
- if(dockPinned&&dockTool===data.dockTool){dockTool=null;dockSession=null;dockPinned=false;updateAgentDock();focusDockTool(data.dockTool);return true;}
238
- dockPinned=true;dockTool=data.dockTool;dockSession=null;
239
- pickDockRecord();
240
- updateAgentDock();focusDockTool(data.dockTool);return true;
241
- }
242
- if(Object.hasOwn(data,'dockClose')){
243
- const prior=dockTool;dockTool=null;dockSession=null;dockPinned=false;updateAgentDock();focusDockTool(prior);return true;
244
- }
245
- if(data.dockRecord){dockSession=data.dockRecord;dockPinned=true;updateAgentDock();return true;}
246
- if(data.dockOpen){
247
- openView('sessions');
248
- void mutation(async()=>{state.sessionBefore=null;state.sessionCheckpoint=null;state.session=await api('sessions/'+encodeURIComponent(data.dockOpen));},button,'Session opened.')
249
- .then(()=>$('conversation-continuity')?.focus({preventScroll:true}));
250
- return true;
251
- }
252
- return false;
253
- }
2
+ export const BRAIN_HUB_AGENT_DOCK = 'const brainBrandMarks = ' + JSON.stringify(BRAIN_HUB_BRAND_ICONS) + ';\n' + String.raw `
3
+ const observedPulses=new Map();
4
+ let dockTool=null,dockSession=null,dockPinned=false;
5
+ let dockPresenceTimer=0,dockPresenceReceived=0;
6
+ const dockVisible=scope=>scope==='overview'||scope==='sessions';
7
+ const rosterTool=label=>typeof label==='string'&&label&&label!=='user'&&label!=='portal';
8
+ const toolKey=value=>JSON.stringify([value.projectId,value.tool,value.kind,value.identity]);
9
+ const toolOrder=['codex','claude-code','deepseek-harness','opencode'];
10
+ const presenceClock=()=>Date.parse(state.presence?.checkedAt)+(performance.now()-dockPresenceReceived);
11
+ function currentDockConnections(){
12
+ if(!state.presence?.enabled||state.errors?.presence||state.connection!=='reachable')return [];
13
+ const now=presenceClock();
14
+ return arr(state.presence.connections).filter(item=>Date.parse(item.expiresAt)>now);
15
+ }
16
+ function noteAgentActivity(events){
17
+ if(document.hidden||reduced.matches||state.motionPaused||state.replayId||!dockVisible(state.view))return;
18
+ const now=Date.now();
19
+ for(const event of events)if(rosterTool(event.agent)&&event.projectId&&event.sessionId){
20
+ const age=now-Date.parse(event.timestamp);
21
+ if(age>=0&&age<6500)observedPulses.set(event.id,{until:now+1300});
22
+ }
23
+ for(const [id,pulse] of observedPulses)if(pulse.until<now)observedPulses.delete(id);
24
+ }
25
+ function rosterState(){
26
+ const groups=new Map();
27
+ const scope=state.project;
28
+ const accepts=(projectId,tool)=>projectId&&(!scope||scope===projectId)&&rosterTool(tool);
29
+ function group(projectId,tool,kind,identity){
30
+ const key=toolKey({projectId,tool,kind,identity});
31
+ let record=groups.get(key);
32
+ if(!record){record={key,projectId,tool,kind,identity,session:null,event:null,receipt:null};groups.set(key,record);}
33
+ return record;
34
+ }
35
+ const connections=new Map(),hostChats=new Map();
36
+ const connectionKey=(projectId,connectionId)=>JSON.stringify([projectId,connectionId]);
37
+ for(const session of arr(state.sessions?.sessions)){
38
+ const projectId=state.sessions.projectId,tool=session.native?.tool??session.actor?.tool;
39
+ const hostId=session.hostSessionId,connection=session.actor?.kind==='agent'&&session.actor?.id?.startsWith(tool+':mcp-')
40
+ ?session.actor.id.slice(tool.length+1):null;
41
+ if(!accepts(projectId,tool))continue;
42
+ const record=group(projectId,tool,'project-session',session.id);
43
+ record.session=session;record.connection=connection;
44
+ if(hostId){
45
+ const key=JSON.stringify([projectId,tool,hostId]);
46
+ const list=hostChats.get(key)??[];
47
+ list.push(record);hostChats.set(key,list);
48
+ }
49
+ if(connection){
50
+ const key=connectionKey(projectId,connection);
51
+ connections.set(key,connections.has(key)&&connections.get(key)!==tool?null:tool);
52
+ }
53
+ }
54
+ for(const connection of currentDockConnections()){
55
+ const projectId=state.presence.projectId;
56
+ if(!accepts(projectId,connection.tool))continue;
57
+ connections.set(connectionKey(projectId,connection.id),connection.tool);
58
+ group(projectId,connection.tool,'connection',connection.id).presence=connection;
59
+ }
60
+ for(const event of state.events){
61
+ if(!event.sessionId||!accepts(event.projectId,event.agent))continue;
62
+ const measured=event.source==='measured'&&event.transport==='mcp';
63
+ const tool=measured&&event.agent==='mcp-client'?connections.get(connectionKey(event.projectId,event.sessionId))??event.agent:event.agent;
64
+ const record=group(event.projectId,tool,measured?'connection':'report',event.sessionId);
65
+ if(!record.event||event.sequence>record.event.sequence)record.event=event;
66
+ }
67
+ const models=new Set();
68
+ for(const receipt of arr(state.usage?.receipts)){
69
+ if(!receipt.sessionId||!accepts(receipt.projectId,receipt.agent))continue;
70
+ const matches=hostChats.get(JSON.stringify([receipt.projectId,receipt.agent,receipt.sessionId]))??[];
71
+ const record=matches.length===1?matches[0]:group(receipt.projectId,receipt.agent,'conversation',receipt.sessionId);
72
+ if(matches.length>1)record.sharedReceipt=true;
73
+ if(!record.receipt||receipt.recordedAt>=record.receipt.recordedAt)record.receipt=receipt;
74
+ const model=receipt.responseModel??receipt.requestModel;
75
+ if(model)models.add(JSON.stringify([receipt.provider??null,model]));
76
+ }
77
+ const tools=new Map();
78
+ for(const record of groups.values()){
79
+ const latest=[record.event?.timestamp,record.receipt?.recordedAt,record.session?.lastReportedAt,record.presence?.lastSeenAt].filter(Boolean).sort().at(-1);
80
+ record.latest=latest;
81
+ if(!tools.has(record.tool))tools.set(record.tool,[]);
82
+ tools.get(record.tool).push(record);
83
+ }
84
+ for(const rows of tools.values())rows.sort((a,b)=>String(b.latest??'').localeCompare(String(a.latest??'')));
85
+ const order=tool=>toolOrder.includes(tool)?toolOrder.indexOf(tool):toolOrder.length;
86
+ const sorted=[...tools].sort((a,b)=>order(a[0])-order(b[0])||a[0].localeCompare(b[0]));
87
+ return {tools:sorted,groups,models:models.size};
88
+ }
89
+ function toolMark(tool){
90
+ const icon=Object.hasOwn(brainBrandMarks,tool)?brainBrandMarks[tool]:'<span>'+esc(hostName(tool).slice(0,2).toUpperCase())+'</span>';
91
+ return '<span class="tool-mark" aria-hidden="true">'+icon+'</span>';
92
+ }
93
+ function toolEnabled(tool){
94
+ if(!local||!state.policy||state.errors.policy)return null;
95
+ return arr(state.policy.policy.tools).find(item=>item.tool===tool.toLowerCase().trim())?.enabled!==false;
96
+ }
97
+ function dockAction(record){
98
+ const {event,receipt,session}=record;
99
+ if(record.kind==='connection'&&event)return [eventLabel(event),evidence(event)];
100
+ if(event&&event.timestamp===record.latest)return [eventLabel(event),evidence(event)];
101
+ if(receipt&&receipt.recordedAt===record.latest)return ['Model usage receipt','Host-reported'];
102
+ if(session)return [session.native||session.sourceId?'Conversation snapshot':session.reportedStatus==='completed'?'Reported completed':
103
+ session.reportedStatus==='waiting'?'Reported waiting':'Reported working','Recorded session'];
104
+ return record.presence?['No recorded action','Transport heartbeat'] : ['Unavailable','No evidence'];
105
+ }
106
+ function toolDockInspector(record,records){
107
+ const {event,receipt,session}=record;
108
+ const [actionLabel,provenance]=dockAction(record);
109
+ const actualTitle=session?.native?session.native.titleExact??'Unavailable':session?.title??'Not reported';
110
+ const role=arr(state.policy?.chats).find(chat=>chat.id===session?.id)?.role??'Unassigned';
111
+ const workspace=arr(state.overview?.projects).find(project=>project.id===record.projectId)?.name??record.projectId;
112
+ const counter=value=>Number.isFinite(value)?fmt(value):'Not reported';
113
+ const availability=toolEnabled(record.tool);
114
+ const labelFor=item=>item.session?(item.session.native?item.session.native.titleExact??'Untitled native snapshot':item.session.title):
115
+ (item.kind==='connection'?'MCP connection ':item.kind==='report'?'Host report ':item.sharedReceipt?'Shared chat usage ':'Usage receipt ')+item.identity;
116
+ const chooser=records.length>1?list(records.map(item=>{
117
+ const model=item.receipt?.responseModel??item.receipt?.requestModel;
118
+ return '<li><button class="tool-dock-record" type="button" data-dock-record="'+esc(item.key)+'" aria-pressed="'+(item.key===record.key)+'"><strong>'+
119
+ esc(labelFor(item))+'</strong>'+(model?'<small class="muted">'+esc(model)+'</small>':'')+'</button></li>';
120
+ }).join(''),'aria-label="Chats and connection evidence"','tool-dock-record-list'):'';
121
+ const idLabel=record.kind==='connection'?'MCP connection ID':record.kind==='report'?'Reported session ID':record.kind==='project-session'?'Project session ID':'Host chat ID';
122
+ return '<section class="tool-dock-details" id="tool-dock-details" aria-label="'+esc(hostName(record.tool))+' activity details">'+
123
+ '<div class="row"><h3>'+esc(hostName(record.tool))+'</h3><div class="actions">'+
124
+ (session?btn('Open session','data-dock-open="'+esc(session.id)+'"','quiet'):'')+
125
+ btn('Close details','data-dock-close','quiet')+'</div></div>'+chooser+
126
+ '<div class="tool-evidence-grid"><dl class="facts">'+fact('Workspace',workspace)+fact('Conversation',actualTitle)+
127
+ fact(idLabel,record.identity)+(session?.hostSessionId?fact('Host chat ID',session.hostSessionId):'')+
128
+ (record.connection?fact('Reporting MCP connection',record.connection):'')+
129
+ fact('Coordination role',role)+fact('Participation',availability===null?'Unavailable':availability?'Enabled':'Disabled')+'</dl>'+
130
+ '<dl class="facts">'+fact('Latest recorded action',actionLabel)+fact('Evidence',provenance)+fact('Last seen',isoTime(record.latest))+
131
+ (record.presence?fact('MCP heartbeat',isoTime(record.presence.lastSeenAt)): '')+
132
+ fact('Latest tool duration',Number.isFinite(event?.durationMs)?fmt(event.durationMs)+' ms · '+evidence(event):'Not recorded')+'</dl>'+
133
+ '<dl class="facts">'+fact('Model',receipt?.responseModel??receipt?.requestModel??'Not reported')+fact('Provider',receipt?.provider??'Not reported')+
134
+ fact('Host-reported effort',receipt?.reasoningEffort??'Not reported')+fact('Reported input tokens',counter(receipt?.inputTokens))+
135
+ fact('Reported output tokens',counter(receipt?.outputTokens))+(receipt?fact('Usage receipt time',isoTime(receipt.recordedAt)):'')+
136
+ (record.sharedReceipt?fact('Attribution','Shared chat receipt · individual session unavailable'):'')+'</dl></div></section>';
137
+ }
138
+ function pickDockRecord(){
139
+ if(!dockTool)return;
140
+ const records=rosterState().tools.find(([tool])=>tool===dockTool)?.[1]??[];
141
+ dockSession=(records.find(item=>item.session)??records[0])?.key??null;
142
+ }
143
+ function agentDockMarkup(){
144
+ const {tools,groups,models}=rosterState();
145
+ const visible=tools.slice(0,12);
146
+ if(dockTool&&!visible.some(([tool])=>tool===dockTool)){dockTool=null;dockSession=null;dockPinned=false;}
147
+ const controls=visible.map(([tool,records])=>{
148
+ const availability=toolEnabled(tool);
149
+ const latestEvent=records.map(item=>item.event).filter(Boolean).sort((a,b)=>b.sequence-a.sequence)[0];
150
+ const chats=new Set(records.filter(item=>item.session).map(item=>JSON.stringify([item.projectId,item.session.hostSessionId??item.identity]))).size;
151
+ const workers=records.filter(item=>item.session&&arr(state.policy?.chats).some(chat=>chat.id===item.session.id&&chat.role==='worker')).length;
152
+ const reporting=records.filter(item=>item.presence).length;
153
+ const description=availability===false?'Participation off':chats?chats+' chat'+(chats===1?'':'s')+(workers?' · '+workers+' worker'+(workers===1?'':'s'):''):
154
+ reporting?reporting+' reporting':latestEvent?'Observed '+time(latestEvent.timestamp):'Reported usage';
155
+ return '<li><button class="tool-dock-button" type="button" data-dock-tool="'+esc(tool)+'" aria-label="Inspect '+esc(hostName(tool))+'" aria-expanded="'+(tool===dockTool)+'" aria-controls="tool-dock-details">'+
156
+ toolMark(tool)+'<span class="tool-dock-text"><strong>'+esc(hostName(tool))+'</strong><small>'+esc(description)+
157
+ '</small></span><span class="tool-dock-indicator" data-observed="'+esc(latestEvent?.id)+'" title="'+esc(reporting?reporting+' reporting MCP connections':'No current transport heartbeat')+'" aria-hidden="true"></span></button></li>';
158
+ }).join('');
159
+ const selection=tools.find(([tool])=>tool===dockTool)?.[1]??[];
160
+ const row=selection.find(item=>item.key===dockSession)??selection.find(item=>item.session)??selection[0];
161
+ const conversations=new Set([...groups.values()].filter(item=>item.session).map(item=>JSON.stringify([item.projectId,item.tool,item.session.hostSessionId??item.identity]))).size;
162
+ const agents=[...groups.values()].filter(item=>item.session?.actor?.kind==='agent').length;
163
+ const connections=[...groups.values()].filter(item=>item.kind==='connection').length;
164
+ const presence=state.errors.presence||local&&state.connection==='offline'?'Reporting MCP connections unavailable':
165
+ state.presence?.enabled===false?'MCP presence recording off':state.presence?fmt(currentDockConnections().length)+' reporting MCP connections':
166
+ local?'MCP presence loading':fmt(connections)+' observed MCP connections';
167
+ const sourceState=!state.live&&state.features?.features?.liveActivity===false?'Journal display off':
168
+ state.errors.telemetry||state.connection==='offline'?'Previously loaded activity':'Recorded activity';
169
+ return '<div class="tool-dock-head"><h2>Tool activity</h2><p class="small muted">'+
170
+ fmt(tools.length)+' tools <span aria-hidden="true">·</span> '+fmt(agents)+' agent sessions <span aria-hidden="true">·</span> '+fmt(conversations)+' registered chats <span aria-hidden="true">·</span> '+esc(presence)+' <span aria-hidden="true">·</span> '+fmt(models)+' reported models'+
171
+ (tools.length>visible.length?' · '+visible.length+' shown':'')+'</p></div>'+
172
+ (controls?list(controls,'aria-label="Tools with project evidence"','tool-dock-list'):'<p class="tool-dock-empty small muted">Tool records appear after a measured exchange or explicit host report.</p>')+
173
+ (row?toolDockInspector(row,selection):'<div id="tool-dock-details" hidden></div>')+'<p class="tool-dock-caption small muted">'+esc(sourceState)+
174
+ ' · Retained evidence'+(state.presence?.enabled&&!state.errors.presence?' · MCP heartbeat window '+Math.round(state.presence.expiresAfterMs/1000)+'s':'')+
175
+ (state.errors.sessions?' · Sessions unavailable':'')+(state.errors.usage?' · Usage unavailable':'')+(state.errors.policy?' · Controls unavailable':'')+'</p>';
176
+ }
177
+ function installDockPresence(value){
178
+ state.presence=value;dockPresenceReceived=performance.now();
179
+ }
180
+ function scheduleDockExpiry(){
181
+ clearTimeout(dockPresenceTimer);
182
+ if(document.hidden||!dockVisible(state.view)||!state.presence?.enabled||state.errors.presence)return;
183
+ const now=presenceClock();
184
+ const dates=arr(state.presence.connections).map(item=>Date.parse(item.expiresAt)).filter(time=>Number.isFinite(time));
185
+ if(!dates.length||!Number.isFinite(now))return;
186
+ dockPresenceTimer=setTimeout(()=>{updateAgentDock();queueLive(['presence']);},Math.max(150,Math.min(...dates)-now+100));
187
+ }
188
+ function agentDock(){return '<section class="panel tool-dock" id="tool-dock" aria-label="Tool activity">'+agentDockMarkup()+'</section>';}
189
+ function updateAgentDock(){
190
+ const dock=$('tool-dock');
191
+ if(!dock)return;
192
+ const focus=document.activeElement;
193
+ const key=dock.contains(focus)?focus?.dataset.dockTool:null;
194
+ const recordKey=dock.contains(focus)?focus?.dataset.dockRecord:null;
195
+ const focused=dock.contains(focus);
196
+ const id=focused?focus?.id:null;
197
+ const markup=agentDockMarkup();
198
+ if(dock.dataset.markup!==markup){
199
+ dock.innerHTML=markup;dock.dataset.markup=markup;
200
+ if(key)focusDockTool(key);
201
+ else if(recordKey)[...dock.querySelectorAll('[data-dock-record]')].find(button=>button.dataset.dockRecord===recordKey)?.focus({preventScroll:true});
202
+ else if(id)$(id)?.focus({preventScroll:true});
203
+ else if(focused)focusDockTool(dockTool);
204
+ }
205
+ const now=Date.now();
206
+ if(document.hidden||reduced.matches||state.motionPaused||state.replayId||state.connection!=='reachable'||!state.live){
207
+ observedPulses.clear();
208
+ for(const mark of dock.querySelectorAll('.tool-activity-pulse'))mark.classList.remove('tool-activity-pulse');
209
+ return;
210
+ }
211
+ for(const button of dock.querySelectorAll('[data-dock-tool]')){
212
+ const dot=button.querySelector('.tool-dock-indicator');
213
+ const id=dot.dataset.observed,pulse=observedPulses.get(id);
214
+ if(pulse&&pulse.until>now){
215
+ if(dot.dataset.event===id)continue;
216
+ dot.dataset.event=id;
217
+ dot.classList.remove('tool-activity-pulse');
218
+ void dot.offsetWidth;
219
+ dot.classList.add('tool-activity-pulse');
220
+ }
221
+ }
222
+ }
223
+ let dockFocusRestore=false;
224
+ function focusDockTool(tool){
225
+ dockFocusRestore=true;
226
+ [...$('tool-dock')?.querySelectorAll('[data-dock-tool]')??[]].find(button=>button.dataset.dockTool===tool)?.focus({preventScroll:true});
227
+ dockFocusRestore=false;
228
+ }
229
+ function previewDockTool(target){
230
+ const tool=target.closest?.('[data-dock-tool]')?.dataset.dockTool;
231
+ if(!tool||dockPinned||dockFocusRestore||tool===dockTool)return;
232
+ dockTool=tool;pickDockRecord();updateAgentDock();
233
+ }
234
+ function handleAgentDock(button){
235
+ const data=button.dataset;
236
+ if(data.dockTool){
237
+ if(dockPinned&&dockTool===data.dockTool){dockTool=null;dockSession=null;dockPinned=false;updateAgentDock();focusDockTool(data.dockTool);return true;}
238
+ dockPinned=true;dockTool=data.dockTool;dockSession=null;
239
+ pickDockRecord();
240
+ updateAgentDock();focusDockTool(data.dockTool);return true;
241
+ }
242
+ if(Object.hasOwn(data,'dockClose')){
243
+ const prior=dockTool;dockTool=null;dockSession=null;dockPinned=false;updateAgentDock();focusDockTool(prior);return true;
244
+ }
245
+ if(data.dockRecord){dockSession=data.dockRecord;dockPinned=true;updateAgentDock();return true;}
246
+ if(data.dockOpen){
247
+ openView('sessions');
248
+ void mutation(async()=>{state.sessionBefore=null;state.sessionCheckpoint=null;state.session=await api('sessions/'+encodeURIComponent(data.dockOpen));},button,'Session opened.')
249
+ .then(()=>$('conversation-continuity')?.focus({preventScroll:true}));
250
+ return true;
251
+ }
252
+ return false;
253
+ }
254
254
  `;
255
255
  //# sourceMappingURL=brain-hub-agent-dock.js.map