nexus-prime 7.9.21 → 7.9.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/adapters/ide-compat.d.ts +3 -3
- package/dist/agents/adapters/ide-compat.js +51 -1
- package/dist/agents/adapters/mcp/definitions.js +4 -1
- package/dist/agents/adapters/mcp/dispatch.js +66 -4
- package/dist/agents/adapters/mcp/handlers/memory.js +44 -5
- package/dist/agents/adapters/mcp/handlers/orchestration.js +91 -0
- package/dist/agents/adapters/mcp/runHandler.js +3 -0
- package/dist/agents/adapters/mcp/util/detect-caller.js +21 -0
- package/dist/agents/adapters/mcp.js +1 -1
- package/dist/agents/adapters.d.ts +10 -1
- package/dist/agents/adapters.js +21 -0
- package/dist/agents/core/types.d.ts +1 -1
- package/dist/cli/hook.d.ts +4 -6
- package/dist/cli/hook.js +6 -8
- package/dist/cli/install-wizard.js +5 -1
- package/dist/cli.js +181 -15
- package/dist/core/types.d.ts +1 -1
- package/dist/dashboard/app/styles/board.css +85 -1
- package/dist/dashboard/app/styles/runtime.css +148 -0
- package/dist/dashboard/app/styles/workforce.css +28 -0
- package/dist/dashboard/app/views/board.js +56 -0
- package/dist/dashboard/app/views/memory.js +71 -10
- package/dist/dashboard/app/views/runtime.js +138 -4
- package/dist/dashboard/app/views/workforce.js +11 -4
- package/dist/dashboard/routes/events.js +3 -0
- package/dist/dashboard/selectors/operate-selector.js +5 -0
- package/dist/dashboard/selectors/runs-selector.js +5 -0
- package/dist/dashboard/server.js +6 -0
- package/dist/dashboard/types.d.ts +4 -0
- package/dist/engines/client-bootstrap.d.ts +5 -1
- package/dist/engines/client-bootstrap.js +105 -10
- package/dist/engines/client-registry.js +51 -0
- package/dist/engines/event-bus.d.ts +20 -2
- package/dist/engines/feature-registry.js +1 -0
- package/dist/engines/instruction-gateway.d.ts +9 -0
- package/dist/engines/instruction-gateway.js +113 -4
- package/dist/engines/memory/types.d.ts +28 -0
- package/dist/engines/memory-bridge.d.ts +1 -1
- package/dist/engines/memory-bridge.js +1 -1
- package/dist/engines/memory.d.ts +5 -0
- package/dist/engines/memory.js +144 -12
- package/dist/engines/orchestrator/decision-spine.d.ts +26 -0
- package/dist/engines/orchestrator/decision-spine.js +145 -6
- package/dist/engines/orchestrator/funnel.js +8 -1
- package/dist/engines/orchestrator/scoring.d.ts +1 -1
- package/dist/engines/orchestrator/scoring.js +24 -2
- package/dist/engines/orchestrator.d.ts +3 -0
- package/dist/engines/orchestrator.js +73 -13
- package/dist/engines/peer-connectors.d.ts +1 -1
- package/dist/engines/peer-connectors.js +9 -2
- package/dist/engines/runtime-registry.d.ts +9 -0
- package/dist/index.js +9 -0
- package/dist/install/state-locator.d.ts +1 -1
- package/dist/install/state-locator.js +3 -0
- package/dist/synapse/bootstrap.js +3 -0
- package/dist/synapse/mandate/pipeline.js +52 -5
- package/dist/synapse/sorties/runner.js +32 -0
- package/dist/synapse/types.d.ts +27 -0
- package/package.json +1 -1
|
@@ -133,6 +133,9 @@ const _CLIENT_LABEL = {
|
|
|
133
133
|
continue: 'Continue',
|
|
134
134
|
cline: 'Cline',
|
|
135
135
|
openclaw: 'OpenClaw',
|
|
136
|
+
hermes: 'Hermes',
|
|
137
|
+
nanoclaw: 'NanoClaw',
|
|
138
|
+
picoclaw: 'PicoClaw',
|
|
136
139
|
mcp: 'MCP',
|
|
137
140
|
};
|
|
138
141
|
function _clientStateColor(state) {
|
|
@@ -683,6 +686,9 @@ function _buildDecisionSpineHtml(spine) {
|
|
|
683
686
|
const decisionLog = Array.isArray(artifacts.decisionLog) ? artifacts.decisionLog : [];
|
|
684
687
|
const selected = spine?.summary?.selected || plan.selected || {};
|
|
685
688
|
const model = spine?.summary?.modelRoute || plan.modelRoute || brief.modelPolicy || {};
|
|
689
|
+
const budgets = spine?.summary?.budgets || plan.budgets || {};
|
|
690
|
+
const executionPolicy = spine?.summary?.executionPolicy || plan.executionPolicy || {};
|
|
691
|
+
const agentFlow = spine?.summary?.agentFlow || executionPolicy.agentFlow || {};
|
|
686
692
|
const latestDecision = spine?.summary?.latestDecision || decisionLog[decisionLog.length - 1] || null;
|
|
687
693
|
const prompt = brief.rewrittenPrompt || brief.rawPrompt || '';
|
|
688
694
|
return `<div class="dsec decision-spine">
|
|
@@ -699,6 +705,11 @@ function _buildDecisionSpineHtml(spine) {
|
|
|
699
705
|
<div class="decision-spine-v">${esc(model.workerTier || '—')}</div>
|
|
700
706
|
<div class="decision-spine-sub">${esc(model.reviewerTier ? 'review ' + model.reviewerTier : model.reason || '—')}</div>
|
|
701
707
|
</div>
|
|
708
|
+
<div class="decision-spine-card">
|
|
709
|
+
<div class="decision-spine-k">Budget</div>
|
|
710
|
+
<div class="decision-spine-v">${fmtNum(budgets.totalTokens || 0)} t</div>
|
|
711
|
+
<div class="decision-spine-sub">${fmtNum(budgets.codeBlocks || budgets.codeBlockPolicy?.reservedTokens || 0)} t code blocks</div>
|
|
712
|
+
</div>
|
|
702
713
|
<div class="decision-spine-card">
|
|
703
714
|
<div class="decision-spine-k">Context</div>
|
|
704
715
|
<div class="decision-spine-v">${fmtNum(contextLog.length)} events</div>
|
|
@@ -707,12 +718,53 @@ function _buildDecisionSpineHtml(spine) {
|
|
|
707
718
|
</div>
|
|
708
719
|
<div class="decision-spine-block"><span>Files</span>${miniListHtml(selected.files || plan.candidates?.files || [])}</div>
|
|
709
720
|
<div class="decision-spine-block"><span>Skills</span>${miniListHtml(selected.skills || plan.candidates?.skills || [])}</div>
|
|
721
|
+
<div class="decision-spine-block"><span>Workflows</span>${miniListHtml(selected.workflows || plan.candidates?.workflows || [])}</div>
|
|
710
722
|
<div class="decision-spine-block"><span>Crew</span>${miniListHtml([...(selected.crews || []), ...(selected.specialists || [])], 6)}</div>
|
|
723
|
+
<div class="decision-spine-block"><span>Workers</span>${miniListHtml(selected.workers || executionPolicy.subagents?.map(agent => `${agent.role}:${agent.modelTier}`) || [], 8)}</div>
|
|
724
|
+
${_buildDecisionSpineBudgetHtml(budgets)}
|
|
725
|
+
${_buildAgentFlowHtml(agentFlow)}
|
|
711
726
|
${latestDecision ? `<div class="decision-spine-latest">${esc(latestDecision.verb || 'decision')} · ${esc(latestDecision.decision || '')}</div>` : ''}
|
|
712
727
|
${_buildDecisionSpineLogBrowser(contextLog, decisionLog)}
|
|
713
728
|
</div>`;
|
|
714
729
|
}
|
|
715
730
|
|
|
731
|
+
function _buildDecisionSpineBudgetHtml(budgets) {
|
|
732
|
+
if (!budgets || typeof budgets !== 'object' || !Object.keys(budgets).length) return '';
|
|
733
|
+
const rows = [
|
|
734
|
+
['Prompt', budgets.prompt],
|
|
735
|
+
['Memory', budgets.memory],
|
|
736
|
+
['Repo', budgets.repo],
|
|
737
|
+
['Skills', budgets.skills],
|
|
738
|
+
['Reasoning', budgets.reasoning],
|
|
739
|
+
['Code blocks', budgets.codeBlocks || budgets.codeBlockPolicy?.reservedTokens],
|
|
740
|
+
['Verification', budgets.verification],
|
|
741
|
+
['Reserve', budgets.reserve],
|
|
742
|
+
].filter(([, value]) => Number(value) > 0);
|
|
743
|
+
const templates = budgets.codeBlockPolicy?.templates || [];
|
|
744
|
+
return `<div class="decision-spine-budget-grid" aria-label="Token budget breakdown">
|
|
745
|
+
${rows.map(([label, value]) => `<div><span>${esc(label)}</span><strong>${fmtNum(value)}t</strong></div>`).join('')}
|
|
746
|
+
${templates.length ? `<div class="decision-spine-budget-wide"><span>Code block templates</span>${miniListHtml(templates, 6)}</div>` : ''}
|
|
747
|
+
</div>`;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
function _buildAgentFlowHtml(agentFlow) {
|
|
751
|
+
const stages = Array.isArray(agentFlow?.stages) ? agentFlow.stages : [];
|
|
752
|
+
if (!stages.length) return '';
|
|
753
|
+
const gates = Array.isArray(agentFlow.deterministicGates) ? agentFlow.deterministicGates : [];
|
|
754
|
+
return `<div class="decision-spine-agentflow" aria-label="AgentFlow pipeline">
|
|
755
|
+
<div class="decision-spine-browser-title">AgentFlow pipeline</div>
|
|
756
|
+
<div class="decision-spine-agentflow-rail">
|
|
757
|
+
${stages.map(stage => `<div class="decision-spine-agentflow-stage">
|
|
758
|
+
<span>${esc(stage.stage)}</span>
|
|
759
|
+
<strong>${esc(stage.ownerRole || 'worker')}</strong>
|
|
760
|
+
<small>${esc(stage.modelTier || '')}</small>
|
|
761
|
+
</div>`).join('')}
|
|
762
|
+
</div>
|
|
763
|
+
<div class="decision-spine-log-ref">${esc(agentFlow.dispatchPolicy || '')}</div>
|
|
764
|
+
${gates.length ? `<div class="decision-spine-block"><span>Gates</span>${miniListHtml(gates, 8)}</div>` : ''}
|
|
765
|
+
</div>`;
|
|
766
|
+
}
|
|
767
|
+
|
|
716
768
|
function _buildDecisionSpineLogBrowser(contextLog, decisionLog) {
|
|
717
769
|
const contextRows = contextLog.slice(0, 6).map(entry => `
|
|
718
770
|
<div class="decision-spine-log-row">
|
|
@@ -751,11 +803,15 @@ function _buildDecisionSpineMiniHtml(spine) {
|
|
|
751
803
|
const plan = artifacts.selectionPlan || {};
|
|
752
804
|
const selected = spine?.summary?.selected || plan.selected || {};
|
|
753
805
|
const model = spine?.summary?.modelRoute || plan.modelRoute || brief.modelPolicy || {};
|
|
806
|
+
const budgets = spine?.summary?.budgets || plan.budgets || {};
|
|
807
|
+
const agentFlow = spine?.summary?.agentFlow || plan.executionPolicy?.agentFlow || {};
|
|
754
808
|
return `<div class="decision-spine-mini">
|
|
755
809
|
<div class="decision-spine-mini-head">Decision Spine · run ${esc((spine.runId || '').slice(-8))}</div>
|
|
756
810
|
<div class="decision-spine-mini-row">
|
|
757
811
|
<span>intent ${esc(brief.intent || plan.intent || spine?.summary?.intent || '—')}</span>
|
|
758
812
|
<span>model ${esc(model.workerTier || '—')}</span>
|
|
813
|
+
<span>budget ${fmtNum(budgets.totalTokens || 0)}t</span>
|
|
814
|
+
<span>flow ${fmtNum(agentFlow.stages?.length || 0)}</span>
|
|
759
815
|
<span>ctx ${fmtNum(spine?.summary?.contextEvents || artifacts.contextLog?.length || 0)}</span>
|
|
760
816
|
<span>decisions ${fmtNum(spine?.summary?.decisions || artifacts.decisionLog?.length || 0)}</span>
|
|
761
817
|
</div>
|
|
@@ -34,6 +34,42 @@ function memText(m) {
|
|
|
34
34
|
return m.title || m.excerpt || m.content || m.summary || m.id || '';
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
function pct(value) {
|
|
38
|
+
const n = Number(value);
|
|
39
|
+
return Number.isFinite(n) ? `${Math.round(n * 100)}%` : '—';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function decayProfile(m) {
|
|
43
|
+
const rawScore = Number(m.decay?.score ?? m.entropyScore ?? m.entropy ?? 0);
|
|
44
|
+
const score = Number.isFinite(rawScore) ? Math.max(0, Math.min(1, rawScore)) : 0;
|
|
45
|
+
const state = m.decay?.state || (score >= 0.75 ? 'retiring' : score >= 0.5 ? 'stale' : score >= 0.25 ? 'fading' : 'fresh');
|
|
46
|
+
return {
|
|
47
|
+
...m.decay,
|
|
48
|
+
score,
|
|
49
|
+
state,
|
|
50
|
+
nextAction: m.decay?.nextAction || (state === 'fresh' ? 'keep' : state === 'fading' ? 'reinforce' : state === 'stale' ? 'review' : 'archive'),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function reinforcementProfile(m) {
|
|
55
|
+
const rawScore = Number(m.reinforcement?.score ?? m.trustScore ?? m.trust ?? 0);
|
|
56
|
+
const score = Number.isFinite(rawScore) ? Math.max(0, Math.min(1, rawScore)) : 0;
|
|
57
|
+
return { ...m.reinforcement, score };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function decayStroke(state) {
|
|
61
|
+
if (state === 'retiring') return '#ff5f57';
|
|
62
|
+
if (state === 'stale') return '#ffd14d';
|
|
63
|
+
if (state === 'fading') return '#00d4ff';
|
|
64
|
+
return '#00ff88';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function lifecycleLabel(m) {
|
|
68
|
+
const decay = decayProfile(m);
|
|
69
|
+
const reinforcement = reinforcementProfile(m);
|
|
70
|
+
return `${decay.state} · ${decay.nextAction} · reinforced ${pct(reinforcement.score)}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
37
73
|
function selectedMemories() {
|
|
38
74
|
const selected = new Set(S.selectedMemoryIds || []);
|
|
39
75
|
return S.memories.filter(m => selected.has(m.id));
|
|
@@ -282,7 +318,9 @@ function buildGraph() {
|
|
|
282
318
|
S.gNodes = sortedMemories.map(m=>({
|
|
283
319
|
id:m.id, label:m.title||(m.content||'').substring(0,50)||m.id,
|
|
284
320
|
priority:m.priority||0.5, tier:m.tier||'semantic', nodeType:'memory',
|
|
285
|
-
createdAt:m.createdAt||m.timestamp||Date.now(), tags:m.tags||[],
|
|
321
|
+
createdAt:m.createdAt||m.timestamp||Date.now(), tags:m.tags||[],
|
|
322
|
+
decayState:decayProfile(m).state, decayScore:decayProfile(m).score,
|
|
323
|
+
reinforcementScore:reinforcementProfile(m).score, data:m,
|
|
286
324
|
}));
|
|
287
325
|
|
|
288
326
|
const links = [];
|
|
@@ -383,11 +421,11 @@ function renderGraph() {
|
|
|
383
421
|
const isPromoted=d=>(d.tier==='hippocampus'||d.tier==='cortex'||d.tier==='episodic'||d.tier==='semantic');
|
|
384
422
|
const nodeEl=d3s.append('g').selectAll('circle').data(memNodes).enter().append('circle')
|
|
385
423
|
.attr('r',d=>4+d.priority*9).attr('fill',nc).attr('fill-opacity',0.85)
|
|
386
|
-
.attr('stroke',d=>
|
|
424
|
+
.attr('stroke',d=>decayStroke(d.decayState)).attr('stroke-width',d=>isPromoted(d)||d.decayState==='stale'||d.decayState==='retiring'?1.8:1)
|
|
387
425
|
.style('cursor','pointer')
|
|
388
|
-
.classed('node-pulse', d=>isPromoted(d))
|
|
426
|
+
.classed('node-pulse', d=>isPromoted(d) || d.reinforcementScore >= 0.7)
|
|
389
427
|
.on('click',(_,d)=>_openMemDrawer(d))
|
|
390
|
-
.on('mouseover',function(ev,d){ _memHover(d, nodeEl, fileEl, linkEl); _showTip(ev
|
|
428
|
+
.on('mouseover',function(ev,d){ _memHover(d, nodeEl, fileEl, linkEl); _showTip(ev,`${d.label} · ${lifecycleLabel(d.data||d)}`); })
|
|
391
429
|
.on('mouseout', function(){ _memHoverOut(nodeEl, fileEl, linkEl); _hideTip(); });
|
|
392
430
|
const drag=d3.drag()
|
|
393
431
|
.on('start',(ev,d)=>{ if(!ev.active) sim.alphaTarget(0.3).restart(); d.fx=d.x; d.fy=d.y; })
|
|
@@ -469,14 +507,17 @@ export function renderMemList() {
|
|
|
469
507
|
const tier=m.tier||'semantic';
|
|
470
508
|
const pri=m.priority!=null?`p:${Math.round(m.priority*100)}%`:'';
|
|
471
509
|
const state=m.state && m.state !== 'active' ? ` · ${m.state}` : '';
|
|
472
|
-
const decay=m
|
|
510
|
+
const decay=decayProfile(m);
|
|
511
|
+
const reinforcement=reinforcementProfile(m);
|
|
512
|
+
const decayStyle=decay.state==='stale'||decay.state==='retiring'?'opacity:0.72':'';
|
|
513
|
+
const createdAt=m.createdAt||m.timestamp;
|
|
473
514
|
const selected = (S.selectedMemoryIds || []).includes(m.id);
|
|
474
|
-
return `<div class="mem-item ${selected ? 'selected' : ''}" style="${
|
|
515
|
+
return `<div class="mem-item ${selected ? 'selected' : ''}" style="${decayStyle}" data-memid="${esc(m.id)}">
|
|
475
516
|
<button class="mem-select-btn ${selected ? 'active' : ''}" data-mem-toggle="${esc(m.id)}" aria-pressed="${selected ? 'true' : 'false'}">${selected ? 'Selected' : 'Select'}</button>
|
|
476
517
|
<div class="tier-dot t-${esc(tier)}"></div>
|
|
477
518
|
<div style="flex:1;min-width:0">
|
|
478
519
|
<div class="mem-title">${esc(memText(m).substring(0,90))}</div>
|
|
479
|
-
<div class="mem-meta">${esc(tier)}${esc(state)}${pri?' · '+pri:''}${
|
|
520
|
+
<div class="mem-meta">${esc(tier)}${esc(state)}${pri?' · '+pri:''}${createdAt?' · '+timeAgo(createdAt):''} · ${esc(decay.state)}:${esc(decay.nextAction)} · r:${esc(pct(reinforcement.score))}</div>
|
|
480
521
|
</div>
|
|
481
522
|
</div>`;
|
|
482
523
|
}).join('');
|
|
@@ -501,25 +542,45 @@ function _browseMemories() {
|
|
|
501
542
|
${items.map(m => `<div class="trust-event-row" data-drawer-mem="${esc(m.id)}">
|
|
502
543
|
<div class="trust-event-main">
|
|
503
544
|
<span class="chip chip-muted">${esc(m.tier || 'semantic')}</span>
|
|
545
|
+
<span class="chip chip-muted">${esc(lifecycleLabel(m))}</span>
|
|
504
546
|
<span class="trust-event-type">${esc(memText(m).slice(0, 120))}</span>
|
|
505
547
|
</div>
|
|
506
|
-
<div class="trust-event-meta">${esc(m.state || 'active')}${m.createdAt ? ' · '+esc(timeAgo(m.createdAt)) : ''}</div>
|
|
548
|
+
<div class="trust-event-meta">${esc(m.state || 'active')}${(m.createdAt||m.timestamp) ? ' · '+esc(timeAgo(m.createdAt||m.timestamp)) : ''}</div>
|
|
507
549
|
</div>`).join('')}
|
|
508
550
|
</div>` : '<div class="empty-sub">No memories available for the selected runtime.</div>',
|
|
509
551
|
});
|
|
552
|
+
document.querySelectorAll('[data-drawer-mem]').forEach(row => {
|
|
553
|
+
row.addEventListener('click', () => {
|
|
554
|
+
const memory = S.memories.find(item => item.id === row.dataset.drawerMem);
|
|
555
|
+
if (memory) _openMemDrawer({ id: memory.id, label: memText(memory), data: memory });
|
|
556
|
+
});
|
|
557
|
+
});
|
|
510
558
|
}
|
|
511
559
|
|
|
512
560
|
function _openMemDrawer(node) {
|
|
513
561
|
const m=node.data||node;
|
|
514
562
|
const tags=(m.tags||[]).map(t=>`<span class="chip">${esc(t)}</span>`).join(' ');
|
|
515
563
|
const drows=rows=>rows.map(([k,v])=>`<div class="drow"><span class="drow-k">${esc(k)}</span><span class="drow-v">${esc(String(v??'—'))}</span></div>`).join('');
|
|
564
|
+
const decay=decayProfile(m);
|
|
565
|
+
const reinforcement=reinforcementProfile(m);
|
|
566
|
+
const createdAt=m.createdAt||m.timestamp;
|
|
567
|
+
const decayReasons=(decay.reasons||[]).slice(0,4).map(reason=>`<span class="chip chip-muted">${esc(reason)}</span>`).join(' ');
|
|
568
|
+
const reinforcementReasons=(reinforcement.reasons||[]).slice(0,4).map(reason=>`<span class="chip chip-muted">${esc(reason)}</span>`).join(' ');
|
|
516
569
|
openDrawer({ title: node.label||'Memory', body:
|
|
517
570
|
`<div class="dsec"><div class="dsec-title">Memory</div>${drows([
|
|
518
571
|
['ID',m.id],['Tier',m.tier||'semantic'],
|
|
519
572
|
['Priority',m.priority!=null?Math.round(m.priority*100)+'%':'—'],
|
|
520
|
-
['Created',
|
|
521
|
-
['Entropy',m.entropy!=null?m.entropy.toFixed(3):'—']
|
|
573
|
+
['Created',createdAt?new Date(createdAt).toLocaleString():'—'],
|
|
574
|
+
['Entropy',m.entropyScore!=null?m.entropyScore.toFixed(3):(m.entropy!=null?m.entropy.toFixed(3):'—')]
|
|
522
575
|
])}</div>
|
|
576
|
+
<div class="dsec"><div class="dsec-title">Lifecycle</div>${drows([
|
|
577
|
+
['Decay',`${decay.state} (${pct(decay.score)})`],
|
|
578
|
+
['Next action',decay.nextAction],
|
|
579
|
+
['Half-life',decay.halfLifeDays!=null?`${Math.round(decay.halfLifeDays)}d`:'—'],
|
|
580
|
+
['Reinforcement',pct(reinforcement.score)],
|
|
581
|
+
['Feedback',reinforcement.feedbackCount ?? 0],
|
|
582
|
+
['Recalls',reinforcement.accessCount ?? m.accessCount ?? 0]
|
|
583
|
+
])}${decayReasons?`<div class="dtags">${decayReasons}</div>`:''}${reinforcementReasons?`<div class="dtags">${reinforcementReasons}</div>`:''}</div>
|
|
523
584
|
${tags?`<div class="dsec"><div class="dsec-title">Tags</div><div class="dtags">${tags}</div></div>`:''}
|
|
524
585
|
<div class="dsec"><div class="dsec-title">Content</div><div class="dcontent">${esc(m.content||m.excerpt||m.title||'(no content)')}</div></div>
|
|
525
586
|
<div class="dsec"><div class="dsec-title">Code block</div><pre class="memory-code-block"><code>${esc(memoryBlock(m))}</code></pre></div>` });
|
|
@@ -30,6 +30,10 @@ let _settledToolTimes = new Map();
|
|
|
30
30
|
let _pulseTimer = null;
|
|
31
31
|
// toast queue
|
|
32
32
|
let _toastTimer = null;
|
|
33
|
+
let _tokenFlyoutOpen = false;
|
|
34
|
+
let _tokenFlyoutLoading = false;
|
|
35
|
+
let _tokenFlyoutError = '';
|
|
36
|
+
let _tokenTelemetry = null;
|
|
33
37
|
|
|
34
38
|
/* ── Category metadata ──────────────────────────────────────────────────────── */
|
|
35
39
|
const CATEGORY_META = {
|
|
@@ -65,6 +69,27 @@ function humanMs(ms) {
|
|
|
65
69
|
return `${(ms / 1000).toFixed(1)}s`;
|
|
66
70
|
}
|
|
67
71
|
|
|
72
|
+
function fmtTokens(n) {
|
|
73
|
+
const v = Number(n ?? 0);
|
|
74
|
+
if (!Number.isFinite(v) || v <= 0) return '0';
|
|
75
|
+
if (v >= 1_000_000) return `${(v / 1_000_000).toFixed(1)}M`;
|
|
76
|
+
if (v >= 10_000) return `${Math.round(v / 1000)}k`;
|
|
77
|
+
if (v >= 1000) return `${(v / 1000).toFixed(1)}k`;
|
|
78
|
+
return Math.round(v).toLocaleString();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function fmtPct(n) {
|
|
82
|
+
const v = Number(n ?? 0);
|
|
83
|
+
if (!Number.isFinite(v)) return '0%';
|
|
84
|
+
return `${Math.round(v)}%`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function fmtTime(ts) {
|
|
88
|
+
const n = Number(ts ?? 0);
|
|
89
|
+
if (!Number.isFinite(n) || n <= 0) return 'recent';
|
|
90
|
+
return new Date(n).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
91
|
+
}
|
|
92
|
+
|
|
68
93
|
function toolNameFromPayload(payload) {
|
|
69
94
|
return String(payload.toolName ?? payload.tool ?? payload.name ?? '').trim();
|
|
70
95
|
}
|
|
@@ -159,10 +184,10 @@ function mount() {
|
|
|
159
184
|
<div class="rt-kpi-val" id="rt-toolcalls">0</div>
|
|
160
185
|
<div class="rt-kpi-lbl">Tool Calls</div>
|
|
161
186
|
</div>
|
|
162
|
-
<
|
|
187
|
+
<button class="rt-kpi rt-kpi-action" id="rt-kpi-saved" type="button" aria-expanded="false" aria-controls="rt-token-flyout" title="Open token telemetry">
|
|
163
188
|
<div class="rt-kpi-val" id="rt-tokens-saved">0</div>
|
|
164
189
|
<div class="rt-kpi-lbl">Tokens Saved</div>
|
|
165
|
-
</
|
|
190
|
+
</button>
|
|
166
191
|
<div class="rt-kpi">
|
|
167
192
|
<div class="rt-kpi-val" id="rt-active-count">0</div>
|
|
168
193
|
<div class="rt-kpi-lbl">Active Now</div>
|
|
@@ -170,6 +195,7 @@ function mount() {
|
|
|
170
195
|
</div>
|
|
171
196
|
|
|
172
197
|
<div class="rt-mcp-strip" id="rt-mcp-strip"></div>
|
|
198
|
+
<div class="rt-token-flyout-slot" id="rt-token-flyout-slot"></div>
|
|
173
199
|
|
|
174
200
|
<div class="rt-filter-bar">
|
|
175
201
|
<button class="rt-filter-btn active" data-filter="all">All</button>
|
|
@@ -212,6 +238,14 @@ function mount() {
|
|
|
212
238
|
renderAll();
|
|
213
239
|
});
|
|
214
240
|
|
|
241
|
+
$('rt-kpi-saved')?.addEventListener('click', () => {
|
|
242
|
+
_tokenFlyoutOpen = !_tokenFlyoutOpen;
|
|
243
|
+
renderTokenFlyout();
|
|
244
|
+
if (_tokenFlyoutOpen && !_tokenTelemetry && !_tokenFlyoutLoading) {
|
|
245
|
+
void loadTokenTelemetry();
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
|
|
215
249
|
_mounted = true;
|
|
216
250
|
renderAll();
|
|
217
251
|
}
|
|
@@ -220,6 +254,7 @@ function mount() {
|
|
|
220
254
|
function renderAll() {
|
|
221
255
|
expireStaleActiveTools();
|
|
222
256
|
renderKPIs();
|
|
257
|
+
renderTokenFlyout();
|
|
223
258
|
renderMcpStrip();
|
|
224
259
|
renderFeed();
|
|
225
260
|
}
|
|
@@ -233,6 +268,96 @@ function renderKPIs() {
|
|
|
233
268
|
? (_totalTokensSaved >= 1000 ? `${(_totalTokensSaved / 1000).toFixed(1)}k` : String(_totalTokensSaved))
|
|
234
269
|
: '0';
|
|
235
270
|
if (activeEl) activeEl.textContent = String(_activeTools.size);
|
|
271
|
+
const tokenBtn = $('rt-kpi-saved');
|
|
272
|
+
if (tokenBtn) tokenBtn.setAttribute('aria-expanded', _tokenFlyoutOpen ? 'true' : 'false');
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async function loadTokenTelemetry() {
|
|
276
|
+
_tokenFlyoutLoading = true;
|
|
277
|
+
_tokenFlyoutError = '';
|
|
278
|
+
renderTokenFlyout();
|
|
279
|
+
try {
|
|
280
|
+
const [summary, lifetimeRaw, bySource, timeline] = await Promise.all([
|
|
281
|
+
api('/api/tokens/summary', 0),
|
|
282
|
+
api('/api/tokens/lifetime', 0),
|
|
283
|
+
api('/api/tokens/by-source', 0),
|
|
284
|
+
api('/api/tokens/timeline?limit=8', 0),
|
|
285
|
+
]);
|
|
286
|
+
_tokenTelemetry = {
|
|
287
|
+
summary: summary ?? {},
|
|
288
|
+
lifetime: lifetimeRaw?.data ?? lifetimeRaw ?? {},
|
|
289
|
+
bySource: bySource ?? {},
|
|
290
|
+
timeline: Array.isArray(timeline) ? timeline : [],
|
|
291
|
+
};
|
|
292
|
+
} catch (err) {
|
|
293
|
+
_tokenFlyoutError = err?.message || String(err);
|
|
294
|
+
} finally {
|
|
295
|
+
_tokenFlyoutLoading = false;
|
|
296
|
+
renderTokenFlyout();
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function renderTokenFlyout() {
|
|
301
|
+
const slot = $('rt-token-flyout-slot');
|
|
302
|
+
if (!slot) return;
|
|
303
|
+
const btn = $('rt-kpi-saved');
|
|
304
|
+
if (btn) btn.setAttribute('aria-expanded', _tokenFlyoutOpen ? 'true' : 'false');
|
|
305
|
+
if (!_tokenFlyoutOpen) {
|
|
306
|
+
slot.innerHTML = '';
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (_tokenFlyoutLoading && !_tokenTelemetry) {
|
|
311
|
+
slot.innerHTML = `<div class="rt-token-flyout" id="rt-token-flyout">
|
|
312
|
+
<div class="rt-token-head"><div><div class="rt-token-title">Token telemetry</div><div class="rt-token-sub">Loading current runtime ledger...</div></div><button class="rt-token-close" id="rt-token-close" type="button">Close</button></div>
|
|
313
|
+
</div>`;
|
|
314
|
+
} else if (_tokenFlyoutError) {
|
|
315
|
+
slot.innerHTML = `<div class="rt-token-flyout" id="rt-token-flyout">
|
|
316
|
+
<div class="rt-token-head"><div><div class="rt-token-title">Token telemetry</div><div class="rt-token-sub rt-token-error">${esc(_tokenFlyoutError)}</div></div><button class="rt-token-close" id="rt-token-close" type="button">Close</button></div>
|
|
317
|
+
</div>`;
|
|
318
|
+
} else {
|
|
319
|
+
const data = _tokenTelemetry ?? {};
|
|
320
|
+
const summary = data.summary ?? {};
|
|
321
|
+
const lifetime = data.lifetime ?? {};
|
|
322
|
+
const bySource = data.bySource ?? {};
|
|
323
|
+
const timeline = Array.isArray(data.timeline) ? data.timeline : [];
|
|
324
|
+
const sourceRows = Object.entries(bySource).slice(0, 5).map(([source, value]) => {
|
|
325
|
+
const item = typeof value === 'object' && value ? value : { savedTokens: Number(value ?? 0) };
|
|
326
|
+
const saved = item.savedTokens ?? item.tokensSaved ?? item.saved ?? 0;
|
|
327
|
+
const gross = item.grossInputTokens ?? item.tokensOptimized ?? item.gross ?? 0;
|
|
328
|
+
return `<div class="rt-token-row"><span>${esc(source)}</span><strong>${fmtTokens(saved)}</strong><span>${fmtTokens(gross)} gross</span></div>`;
|
|
329
|
+
}).join('') || '<div class="rt-token-muted">No source ledger yet.</div>';
|
|
330
|
+
const timelineRows = timeline.slice(0, 6).map((item) => {
|
|
331
|
+
const saved = item.savedTokens ?? item.tokensSaved ?? item.saved ?? 0;
|
|
332
|
+
const run = item.runId ?? item.sessionId ?? item.source ?? 'runtime';
|
|
333
|
+
return `<div class="rt-token-row"><span>${esc(String(run).slice(0, 18))}</span><strong>${fmtTokens(saved)}</strong><span>${fmtTime(item.timestamp ?? item.ts ?? item.time)}</span></div>`;
|
|
334
|
+
}).join('') || '<div class="rt-token-muted">No recent token events yet.</div>';
|
|
335
|
+
slot.innerHTML = `<div class="rt-token-flyout" id="rt-token-flyout">
|
|
336
|
+
<div class="rt-token-head">
|
|
337
|
+
<div>
|
|
338
|
+
<div class="rt-token-title">Token telemetry</div>
|
|
339
|
+
<div class="rt-token-sub">Runtime ledger, lifetime savings, and live SSE savings for this tab.</div>
|
|
340
|
+
</div>
|
|
341
|
+
<button class="rt-token-close" id="rt-token-close" type="button">Close</button>
|
|
342
|
+
</div>
|
|
343
|
+
<div class="rt-token-grid">
|
|
344
|
+
<div class="rt-token-stat"><span>Recent saved</span><strong>${fmtTokens(summary.savedTokens ?? summary.saved)}</strong></div>
|
|
345
|
+
<div class="rt-token-stat"><span>Recent compression</span><strong>${fmtPct(summary.compressionPct)}</strong></div>
|
|
346
|
+
<div class="rt-token-stat"><span>Lifetime saved</span><strong>${fmtTokens(lifetime.savedTokens ?? lifetime.totalSaved)}</strong></div>
|
|
347
|
+
<div class="rt-token-stat"><span>Live tab saved</span><strong>${fmtTokens(_totalTokensSaved)}</strong></div>
|
|
348
|
+
</div>
|
|
349
|
+
<div class="rt-token-columns">
|
|
350
|
+
<div><div class="rt-token-section-title">By source</div>${sourceRows}</div>
|
|
351
|
+
<div><div class="rt-token-section-title">Recent runs</div>${timelineRows}</div>
|
|
352
|
+
</div>
|
|
353
|
+
</div>`;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
$('rt-token-close')?.addEventListener('click', () => {
|
|
357
|
+
_tokenFlyoutOpen = false;
|
|
358
|
+
renderTokenFlyout();
|
|
359
|
+
renderKPIs();
|
|
360
|
+
});
|
|
236
361
|
}
|
|
237
362
|
|
|
238
363
|
function renderMcpStrip() {
|
|
@@ -421,11 +546,20 @@ export function ingestEvent(evt) {
|
|
|
421
546
|
break;
|
|
422
547
|
case 'memory.store':
|
|
423
548
|
label = 'memory · store';
|
|
424
|
-
detail =
|
|
549
|
+
detail = [
|
|
550
|
+
payload.id ? `id ${String(payload.id).slice(0, 12)}` : null,
|
|
551
|
+
payload.tier ? `tier ${payload.tier}` : null,
|
|
552
|
+
payload.priority != null ? `priority ${Number(payload.priority).toFixed(2)}` : null,
|
|
553
|
+
Array.isArray(payload.tags) && payload.tags.length ? `tags ${payload.tags.slice(0, 3).join(', ')}` : null,
|
|
554
|
+
].filter(Boolean).join(' · ') || String(payload.key ?? payload.content ?? '').slice(0, 80);
|
|
425
555
|
break;
|
|
426
556
|
case 'memory.recall':
|
|
427
557
|
label = 'memory · recall';
|
|
428
|
-
detail =
|
|
558
|
+
detail = [
|
|
559
|
+
`${Number(payload.count ?? 0)} recalled`,
|
|
560
|
+
payload.crossClient ? 'cross-client' : null,
|
|
561
|
+
String(payload.query ?? '').slice(0, 60),
|
|
562
|
+
].filter(Boolean).join(' · ');
|
|
429
563
|
break;
|
|
430
564
|
case 'tokens.optimized': {
|
|
431
565
|
const src = payload.source ? ` · ${payload.source}` : '';
|
|
@@ -45,6 +45,7 @@ export function handleDispatchEvent(evt) {
|
|
|
45
45
|
const type = evt.type ?? '';
|
|
46
46
|
|
|
47
47
|
if (type === 'dispatch.started') {
|
|
48
|
+
if (oid) _dispatches.delete(`__warmup__:${oid}`);
|
|
48
49
|
run.status = 'spawning';
|
|
49
50
|
run.invoker = p.invokerId ?? '';
|
|
50
51
|
} else if (type === 'dispatch.event') {
|
|
@@ -117,18 +118,20 @@ function _buildDispatchStrip(run) {
|
|
|
117
118
|
}).join('<span class="ds-sep">→</span>');
|
|
118
119
|
|
|
119
120
|
const isFinal = ['complete','failed','cancelled'].includes(run.status);
|
|
121
|
+
const isPendingAdapter = run.pendingAdapter === true;
|
|
120
122
|
|
|
121
123
|
return `<div class="dispatch-strip" data-run-id="${esc(run.runId)}">
|
|
122
124
|
<div class="ds-stages">${stageHtml}</div>
|
|
123
125
|
${run.messages.length ? `<div class="ds-stdout">${esc(run.messages[run.messages.length - 1])}</div>` : ''}
|
|
124
126
|
<div class="ds-meta">
|
|
127
|
+
${run.invoker ? `<span>${esc(run.invoker)}</span>` : ''}
|
|
125
128
|
${run.tokens ? `<span>${run.tokens.toLocaleString()} tokens</span>` : ''}
|
|
126
129
|
${run.costUsd ? `<span>$${run.costUsd.toFixed(4)}</span>` : ''}
|
|
127
130
|
${run.filesChanged.length ? `<span>${run.filesChanged.length} file(s)</span>` : ''}
|
|
128
131
|
</div>
|
|
129
132
|
${run.summary ? `<div class="ds-summary">${esc(String(run.summary).slice(0, 160))}</div>` : ''}
|
|
130
133
|
${run.error ? `<div class="ds-error">${esc(run.error)}</div>` : ''}
|
|
131
|
-
${!isFinal ? `<button class="btn btn-sm ds-stop-btn" data-stop-run="${esc(run.runId)}">Stop</button>` : ''}
|
|
134
|
+
${!isFinal && !isPendingAdapter ? `<button class="btn btn-sm ds-stop-btn" data-stop-run="${esc(run.runId)}">Stop</button>` : ''}
|
|
132
135
|
</div>`;
|
|
133
136
|
}
|
|
134
137
|
|
|
@@ -560,14 +563,18 @@ function _showHireSheet(specialistId, name) {
|
|
|
560
563
|
stripDiv.setAttribute('data-dispatch-strip', '');
|
|
561
564
|
drawerBody.appendChild(stripDiv);
|
|
562
565
|
}
|
|
563
|
-
const
|
|
564
|
-
|
|
566
|
+
const warmupKey = `__warmup__:${operativeId}`;
|
|
567
|
+
const warmupRun = { runId: warmupKey, operativeId, status: 'queued', tokens: 0, costUsd: 0, messages: ['Adapter pending; waiting for dispatch.started…'], filesChanged: [], pendingAdapter: true };
|
|
568
|
+
_dispatches.set(warmupKey, warmupRun);
|
|
565
569
|
stripDiv.innerHTML = _buildDispatchStrip(warmupRun);
|
|
566
570
|
}
|
|
567
571
|
const fd = real.data?.firstDispatch;
|
|
568
|
-
_dispatches.delete('__warmup__');
|
|
569
572
|
if (fd?.runId) {
|
|
573
|
+
_dispatches.delete(`__warmup__:${operativeId}`);
|
|
570
574
|
_dispatches.set(fd.runId, { runId: fd.runId, operativeId, status: 'queued', tokens: 0, costUsd: 0, messages: [], filesChanged: [] });
|
|
575
|
+
} else if (fd?.queued) {
|
|
576
|
+
const pending = _dispatches.get(`__warmup__:${operativeId}`);
|
|
577
|
+
if (pending) pending.messages = ['First sortie queued; adapter start will stream here.'];
|
|
571
578
|
}
|
|
572
579
|
_refreshDrawerForOp(operativeId);
|
|
573
580
|
}
|
|
@@ -174,6 +174,9 @@ export const handleEventRoutes = async (ctx, req, res, url) => {
|
|
|
174
174
|
intent: requestBrief?.intent ?? selectionPlan?.intent ?? run.intent ?? null,
|
|
175
175
|
risk: requestBrief?.risk ?? null,
|
|
176
176
|
modelRoute: selectionPlan?.modelRoute ?? requestBrief?.modelPolicy ?? null,
|
|
177
|
+
budgets: selectionPlan?.budgets ?? null,
|
|
178
|
+
executionPolicy: selectionPlan?.executionPolicy ?? null,
|
|
179
|
+
agentFlow: selectionPlan?.executionPolicy?.agentFlow ?? null,
|
|
177
180
|
selected: selectionPlan?.selected ?? null,
|
|
178
181
|
contextEvents: Array.isArray(contextLog) ? contextLog.length : 0,
|
|
179
182
|
decisions: Array.isArray(decisionLog) ? decisionLog.length : 0,
|
|
@@ -8,6 +8,11 @@ export async function buildOperateSurface(ctx, url) {
|
|
|
8
8
|
runs: serializeRuns(state.runtime?.listRuns?.(12) ?? []),
|
|
9
9
|
usage: state.usage,
|
|
10
10
|
tokenOptimization: state.tokenOptimization,
|
|
11
|
+
sourceAwareTokenBudget: state.snapshot?.sourceAwareTokenBudget ?? state.runtime?.getUsageSnapshot?.()?.sourceAwareTokenBudget ?? {},
|
|
12
|
+
agentFlow: state.snapshot?.instructionPacket?.selectionPlan?.executionPolicy?.agentFlow
|
|
13
|
+
?? state.snapshot?.executionLedger?.agentFlow
|
|
14
|
+
?? state.runtime?.getUsageSnapshot?.()?.selectionPlan?.executionPolicy?.agentFlow
|
|
15
|
+
?? {},
|
|
11
16
|
gateSummary: state.gateSummary,
|
|
12
17
|
memoryContainers: state.memoryContainers,
|
|
13
18
|
interpretationIssues: state.interpretationIssues,
|
|
@@ -11,6 +11,11 @@ export async function buildRunsSurface(ctx, url) {
|
|
|
11
11
|
gateTimeline: serializeGateTimeline(state.latestRun),
|
|
12
12
|
parallelism: serializeParallelism(state.snapshot, state.runtime),
|
|
13
13
|
tokenOptimization: state.tokenOptimization,
|
|
14
|
+
sourceAwareTokenBudget: state.snapshot?.sourceAwareTokenBudget ?? state.runtime?.getUsageSnapshot?.()?.sourceAwareTokenBudget ?? {},
|
|
15
|
+
agentFlow: state.snapshot?.instructionPacket?.selectionPlan?.executionPolicy?.agentFlow
|
|
16
|
+
?? state.snapshot?.executionLedger?.agentFlow
|
|
17
|
+
?? state.runtime?.getUsageSnapshot?.()?.selectionPlan?.executionPolicy?.agentFlow
|
|
18
|
+
?? {},
|
|
14
19
|
orchestrationSession: state.snapshot?.orchestration ?? state.orchestrator?.getSessionState?.() ?? {},
|
|
15
20
|
orchestrationLedger: state.snapshot?.executionLedger ?? state.runtime?.getExecutionLedger?.() ?? {},
|
|
16
21
|
workerPlan: state.snapshot?.workerPlan ?? state.runtime?.getUsageSnapshot?.()?.workerPlan ?? {},
|
package/dist/dashboard/server.js
CHANGED
|
@@ -992,6 +992,12 @@ export class DashboardServer {
|
|
|
992
992
|
selectedFiles: Array.isArray(budget?.selectedFiles) ? budget.selectedFiles : [],
|
|
993
993
|
reason: budget?.reason || 'Token optimization has not reported a source-aware budget yet.',
|
|
994
994
|
dominantSource: budget?.dominantSource || null,
|
|
995
|
+
bySource: budget?.bySource ?? {},
|
|
996
|
+
byStage: budget?.byStage ?? {},
|
|
997
|
+
totalBudget: Number(budget?.totalBudget ?? 0),
|
|
998
|
+
codeBlocks: budget?.codeBlocks ?? null,
|
|
999
|
+
qualityGates: Array.isArray(budget?.qualityGates) ? budget.qualityGates : [],
|
|
1000
|
+
recommendations: Array.isArray(budget?.recommendations) ? budget.recommendations : [],
|
|
995
1001
|
dropped: Array.isArray(budget?.dropped) ? budget.dropped : [],
|
|
996
1002
|
};
|
|
997
1003
|
}
|
|
@@ -175,6 +175,8 @@ export interface OperateSurfaceDTO {
|
|
|
175
175
|
runs: unknown[];
|
|
176
176
|
usage: unknown;
|
|
177
177
|
tokenOptimization: unknown;
|
|
178
|
+
sourceAwareTokenBudget: unknown;
|
|
179
|
+
agentFlow: unknown;
|
|
178
180
|
gateSummary: unknown;
|
|
179
181
|
memoryContainers: unknown;
|
|
180
182
|
interpretationIssues: unknown[];
|
|
@@ -220,6 +222,8 @@ export interface RunsSurfaceDTO {
|
|
|
220
222
|
gateTimeline: unknown[];
|
|
221
223
|
parallelism: unknown;
|
|
222
224
|
tokenOptimization: unknown;
|
|
225
|
+
sourceAwareTokenBudget: unknown;
|
|
226
|
+
agentFlow: unknown;
|
|
223
227
|
orchestrationSession: unknown;
|
|
224
228
|
orchestrationLedger: unknown;
|
|
225
229
|
workerPlan: unknown;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type SetupClientId = 'cursor' | 'claude' | 'claude-code' | 'claude-desktop' | 'opencode' | 'windsurf' | 'antigravity' | 'openclaw' | 'codex' | 'aider' | 'continue' | 'cline';
|
|
1
|
+
export type SetupClientId = 'cursor' | 'claude' | 'claude-code' | 'claude-desktop' | 'opencode' | 'windsurf' | 'antigravity' | 'openclaw' | 'hermes' | 'nanoclaw' | 'picoclaw' | 'codex' | 'aider' | 'continue' | 'cline';
|
|
2
2
|
export type SetupInstructionMode = 'replace' | 'codex-managed-agents';
|
|
3
3
|
export type SetupInstructionScope = 'home' | 'workspace';
|
|
4
4
|
export type SetupState = 'missing' | 'drifted' | 'installed';
|
|
@@ -23,6 +23,8 @@ export interface BootstrapManifestClientStatus {
|
|
|
23
23
|
instructionFiles: string[];
|
|
24
24
|
homeReady: boolean;
|
|
25
25
|
workspaceReady: boolean;
|
|
26
|
+
memoryHookReady: boolean;
|
|
27
|
+
memoryHookSummary: string;
|
|
26
28
|
summary: string;
|
|
27
29
|
updatedAt: number;
|
|
28
30
|
}
|
|
@@ -62,6 +64,8 @@ export declare function statusForDefinition(definition: SetupDefinition): {
|
|
|
62
64
|
summary: string;
|
|
63
65
|
homeReady: boolean;
|
|
64
66
|
workspaceReady: boolean;
|
|
67
|
+
memoryHookReady: boolean;
|
|
68
|
+
memoryHookSummary: string;
|
|
65
69
|
};
|
|
66
70
|
export declare function supportedSetupClients(): SetupClientId[];
|
|
67
71
|
export declare function readBootstrapManifest(stateRoot?: string, workspaceRoot?: string): BootstrapManifestStatus | undefined;
|