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.
Files changed (59) hide show
  1. package/dist/agents/adapters/ide-compat.d.ts +3 -3
  2. package/dist/agents/adapters/ide-compat.js +51 -1
  3. package/dist/agents/adapters/mcp/definitions.js +4 -1
  4. package/dist/agents/adapters/mcp/dispatch.js +66 -4
  5. package/dist/agents/adapters/mcp/handlers/memory.js +44 -5
  6. package/dist/agents/adapters/mcp/handlers/orchestration.js +91 -0
  7. package/dist/agents/adapters/mcp/runHandler.js +3 -0
  8. package/dist/agents/adapters/mcp/util/detect-caller.js +21 -0
  9. package/dist/agents/adapters/mcp.js +1 -1
  10. package/dist/agents/adapters.d.ts +10 -1
  11. package/dist/agents/adapters.js +21 -0
  12. package/dist/agents/core/types.d.ts +1 -1
  13. package/dist/cli/hook.d.ts +4 -6
  14. package/dist/cli/hook.js +6 -8
  15. package/dist/cli/install-wizard.js +5 -1
  16. package/dist/cli.js +181 -15
  17. package/dist/core/types.d.ts +1 -1
  18. package/dist/dashboard/app/styles/board.css +85 -1
  19. package/dist/dashboard/app/styles/runtime.css +148 -0
  20. package/dist/dashboard/app/styles/workforce.css +28 -0
  21. package/dist/dashboard/app/views/board.js +56 -0
  22. package/dist/dashboard/app/views/memory.js +71 -10
  23. package/dist/dashboard/app/views/runtime.js +138 -4
  24. package/dist/dashboard/app/views/workforce.js +11 -4
  25. package/dist/dashboard/routes/events.js +3 -0
  26. package/dist/dashboard/selectors/operate-selector.js +5 -0
  27. package/dist/dashboard/selectors/runs-selector.js +5 -0
  28. package/dist/dashboard/server.js +6 -0
  29. package/dist/dashboard/types.d.ts +4 -0
  30. package/dist/engines/client-bootstrap.d.ts +5 -1
  31. package/dist/engines/client-bootstrap.js +105 -10
  32. package/dist/engines/client-registry.js +51 -0
  33. package/dist/engines/event-bus.d.ts +20 -2
  34. package/dist/engines/feature-registry.js +1 -0
  35. package/dist/engines/instruction-gateway.d.ts +9 -0
  36. package/dist/engines/instruction-gateway.js +113 -4
  37. package/dist/engines/memory/types.d.ts +28 -0
  38. package/dist/engines/memory-bridge.d.ts +1 -1
  39. package/dist/engines/memory-bridge.js +1 -1
  40. package/dist/engines/memory.d.ts +5 -0
  41. package/dist/engines/memory.js +144 -12
  42. package/dist/engines/orchestrator/decision-spine.d.ts +26 -0
  43. package/dist/engines/orchestrator/decision-spine.js +145 -6
  44. package/dist/engines/orchestrator/funnel.js +8 -1
  45. package/dist/engines/orchestrator/scoring.d.ts +1 -1
  46. package/dist/engines/orchestrator/scoring.js +24 -2
  47. package/dist/engines/orchestrator.d.ts +3 -0
  48. package/dist/engines/orchestrator.js +73 -13
  49. package/dist/engines/peer-connectors.d.ts +1 -1
  50. package/dist/engines/peer-connectors.js +9 -2
  51. package/dist/engines/runtime-registry.d.ts +9 -0
  52. package/dist/index.js +9 -0
  53. package/dist/install/state-locator.d.ts +1 -1
  54. package/dist/install/state-locator.js +3 -0
  55. package/dist/synapse/bootstrap.js +3 -0
  56. package/dist/synapse/mandate/pipeline.js +52 -5
  57. package/dist/synapse/sorties/runner.js +32 -0
  58. package/dist/synapse/types.d.ts +27 -0
  59. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -72,6 +72,14 @@ const CLAUDE_MANAGED_START = '<!-- nexus-prime:claude-bootstrap:start -->';
72
72
  const CLAUDE_MANAGED_END = '<!-- nexus-prime:claude-bootstrap:end -->';
73
73
  const CLINE_MANAGED_START = '<!-- nexus-prime:cline-bootstrap:start -->';
74
74
  const CLINE_MANAGED_END = '<!-- nexus-prime:cline-bootstrap:end -->';
75
+ const SETUP_CLIENTS = ['codex', 'cursor', 'claude-code', 'claude-desktop', 'opencode', 'windsurf', 'antigravity', 'openclaw', 'hermes', 'nanoclaw', 'picoclaw', 'aider', 'continue', 'cline'];
76
+ const HOME_SKILL_BUNDLE_DIRS = {
77
+ antigravity: join(homedir(), '.antigravity', 'skills', 'nexus-prime'),
78
+ openclaw: join(homedir(), '.openclaw', 'skills', 'nexus-prime'),
79
+ hermes: join(homedir(), '.hermes', 'skills', 'nexus-prime'),
80
+ nanoclaw: join(homedir(), '.nanoclaw', 'skills', 'nexus-prime'),
81
+ picoclaw: join(homedir(), '.picoclaw', 'skills', 'nexus-prime'),
82
+ };
75
83
  function getWorkspaceContext() {
76
84
  return resolveWorkspaceContext();
77
85
  }
@@ -405,15 +413,10 @@ function buildInstructionFiles(clientId) {
405
413
  content: artifact.content,
406
414
  }));
407
415
  }
408
- if (clientId === 'antigravity') {
409
- return bundle.artifacts.map((artifact) => ({
410
- path: join(homedir(), '.antigravity', 'skills', 'nexus-prime', artifact.fileName),
411
- content: artifact.content,
412
- }));
413
- }
414
- if (clientId === 'openclaw') {
416
+ const homeSkillDir = HOME_SKILL_BUNDLE_DIRS[clientId];
417
+ if (homeSkillDir) {
415
418
  return bundle.artifacts.map((artifact) => ({
416
- path: join(homedir(), '.openclaw', 'skills', 'nexus-prime', artifact.fileName),
419
+ path: join(homeSkillDir, artifact.fileName),
417
420
  content: artifact.content,
418
421
  }));
419
422
  }
@@ -546,6 +549,33 @@ function getSetupDefinition(clientId) {
546
549
  instructionFiles,
547
550
  };
548
551
  }
552
+ if (clientId === 'hermes') {
553
+ return {
554
+ id: clientId,
555
+ label: 'Hermes',
556
+ workspaceRoot,
557
+ configPath: join(homedir(), '.hermes', 'mcp.json'),
558
+ instructionFiles,
559
+ };
560
+ }
561
+ if (clientId === 'nanoclaw') {
562
+ return {
563
+ id: clientId,
564
+ label: 'NanoClaw',
565
+ workspaceRoot,
566
+ configPath: join(homedir(), '.nanoclaw', 'mcp.json'),
567
+ instructionFiles,
568
+ };
569
+ }
570
+ if (clientId === 'picoclaw') {
571
+ return {
572
+ id: clientId,
573
+ label: 'PicoClaw',
574
+ workspaceRoot,
575
+ configPath: join(homedir(), '.picoclaw', 'mcp.json'),
576
+ instructionFiles,
577
+ };
578
+ }
549
579
  return {
550
580
  id: clientId,
551
581
  label: 'Cline',
@@ -555,6 +585,7 @@ function getSetupDefinition(clientId) {
555
585
  };
556
586
  }
557
587
  function installSetup(definition) {
588
+ ensureMemoryHookSeed(definition.workspaceRoot);
558
589
  if (definition.configPath) {
559
590
  if (definition.id === 'codex' && definition.configPath.endsWith('.toml')) {
560
591
  writeCodexMcpConfig(definition.configPath);
@@ -586,6 +617,43 @@ function installSetup(definition) {
586
617
  writeFileSync(file.path, file.content, 'utf8');
587
618
  }
588
619
  }
620
+ const MEMORY_HOOK_SEEDS = [
621
+ {
622
+ relativePath: '.agents/hooks/memory-stored-review.md',
623
+ content: `---
624
+ name: memory-stored-review
625
+ description: Preferred repo-local review hook for important stored memories.
626
+ trigger: memory.stored
627
+ riskClass: read
628
+ domain: memory
629
+ ---
630
+
631
+ Project-local hook seed. Customize this file when memory writes need repo-specific review rules.
632
+ `,
633
+ },
634
+ {
635
+ relativePath: '.agent/hooks/memory-stored-review.md',
636
+ content: `---
637
+ name: memory-stored-review
638
+ description: Local review hook for important stored memories.
639
+ trigger: memory.stored
640
+ riskClass: read
641
+ domain: memory
642
+ ---
643
+
644
+ Project-local hook seed. Customize this file when memory writes need repo-specific review rules.
645
+ `,
646
+ },
647
+ ];
648
+ function ensureMemoryHookSeed(workspaceRoot) {
649
+ for (const seed of MEMORY_HOOK_SEEDS) {
650
+ const target = join(workspaceRoot, seed.relativePath);
651
+ if (existsSync(target))
652
+ continue;
653
+ ensureParentDir(target);
654
+ writeFileSync(target, seed.content, 'utf8');
655
+ }
656
+ }
589
657
  function printSetupPreview(definition) {
590
658
  console.log(`--- ${definition.label.toUpperCase()} SETUP PREVIEW ---`);
591
659
  if (definition.configPath) {
@@ -671,13 +739,66 @@ function instructionState(definition) {
671
739
  return 'missing';
672
740
  return definition.instructionFiles.every((file) => existsSync(file.path)) ? 'installed' : 'missing';
673
741
  }
742
+ const MEMORY_HOOK_SETUP_CLIENTS = new Set(['codex', 'cursor', 'claude', 'claude-code', 'claude-desktop']);
743
+ function setupInstructionMentionsMemoryHook(content) {
744
+ return content.includes('nexus_store_memory') && /memory hooks?/i.test(content);
745
+ }
746
+ function setupHasInstructionMemoryHook(definition) {
747
+ return definition.instructionFiles.some((file) => {
748
+ if (!existsSync(file.path))
749
+ return false;
750
+ try {
751
+ return setupInstructionMentionsMemoryHook(readFileSync(file.path, 'utf8'));
752
+ }
753
+ catch {
754
+ return false;
755
+ }
756
+ });
757
+ }
758
+ function setupHasRepoMemoryHookSeed(workspaceRoot) {
759
+ return ['.agents/hooks/memory-stored-review.md', '.agent/hooks/memory-stored-review.md']
760
+ .some((relativePath) => existsSync(join(workspaceRoot, relativePath)));
761
+ }
762
+ function setupHasClaudeCodeMemoryHook() {
763
+ const settingsPath = join(homedir(), '.claude', 'settings.json');
764
+ if (!existsSync(settingsPath))
765
+ return false;
766
+ try {
767
+ const parsed = JSON.parse(readFileSync(settingsPath, 'utf8'));
768
+ return Boolean(parsed?.hooks?.PostToolUse?.some((entry) => (entry?.hooks?.some((hook) => hook?.command === 'nexus-prime hook memory'))));
769
+ }
770
+ catch {
771
+ return false;
772
+ }
773
+ }
774
+ function setupMemoryHookStatus(definition) {
775
+ if (!MEMORY_HOOK_SETUP_CLIENTS.has(definition.id)) {
776
+ return { memoryHookReady: false, memoryHookSummary: 'Memory hook readiness is not tracked for this client' };
777
+ }
778
+ const instructionReady = setupHasInstructionMemoryHook(definition);
779
+ const repoHookReady = setupHasRepoMemoryHookSeed(definition.workspaceRoot);
780
+ const nativeHookRequired = definition.id === 'claude' || definition.id === 'claude-code';
781
+ const nativeHookReady = nativeHookRequired ? setupHasClaudeCodeMemoryHook() : true;
782
+ const memoryHookReady = instructionReady && repoHookReady && nativeHookReady;
783
+ const missing = [
784
+ instructionReady ? null : 'client instruction wording',
785
+ repoHookReady ? null : 'repo memory.stored hook seed',
786
+ nativeHookReady ? null : 'Claude Code PostToolUse hook',
787
+ ].filter(Boolean);
788
+ return {
789
+ memoryHookReady,
790
+ memoryHookSummary: memoryHookReady ? 'Memory hooks ready' : `Memory hooks incomplete: ${missing.join(', ')}`,
791
+ };
792
+ }
674
793
  function statusForDefinition(definition) {
675
794
  const configOk = definition.configPath ? hasExpectedConfig(definition) : true;
676
795
  const instructions = instructionState(definition);
796
+ const memoryHook = setupMemoryHookStatus(definition);
677
797
  if (configOk && instructions === 'installed') {
678
798
  return {
679
799
  state: 'installed',
680
800
  summary: definition.configPath ? 'Config and client instructions are current' : 'Managed client instructions are current',
801
+ ...memoryHook,
681
802
  };
682
803
  }
683
804
  if ((definition.configPath && existsSync(definition.configPath)) || instructions !== 'missing') {
@@ -686,11 +807,13 @@ function statusForDefinition(definition) {
686
807
  summary: definition.configPath
687
808
  ? 'Setup exists but is missing the autonomous profile or current instructions'
688
809
  : 'A client instruction file exists, but the managed Nexus Prime bootstrap block is missing or outdated',
810
+ ...memoryHook,
689
811
  };
690
812
  }
691
813
  return {
692
814
  state: 'missing',
693
815
  summary: definition.configPath ? 'Setup not installed yet' : 'No managed client instruction file installed yet',
816
+ ...memoryHook,
694
817
  };
695
818
  }
696
819
  program
@@ -1044,7 +1167,7 @@ program
1044
1167
  .command('adapter')
1045
1168
  .description('Manage adapters')
1046
1169
  .addCommand(new Command('add')
1047
- .argument('<type>', 'Adapter type (openclaw, claude-code, ruflo)')
1170
+ .argument('<type>', 'Adapter type (openclaw, hermes, nanoclaw, picoclaw, claude-code, ruflo)')
1048
1171
  .action(async (type) => {
1049
1172
  if (!nexus) {
1050
1173
  await ensureNexusRunning();
@@ -1473,13 +1596,54 @@ program
1473
1596
  console.log(`✅ Nexus Prime installed for OpenClaw`);
1474
1597
  console.log(` MCP: ${definition.configPath}`);
1475
1598
  definition.instructionFiles.forEach((file) => console.log(` Instruction: ${file.path}`));
1599
+ }))
1600
+ .addCommand(new Command('hermes')
1601
+ .description('Integrate with Hermes')
1602
+ .option('--dry-run', 'Preview changes')
1603
+ .action((options) => {
1604
+ const definition = getSetupDefinition('hermes');
1605
+ if (options.dryRun) {
1606
+ printSetupPreview(definition);
1607
+ return;
1608
+ }
1609
+ installSetup(definition);
1610
+ console.log(`✅ Nexus Prime installed for Hermes`);
1611
+ console.log(` MCP: ${definition.configPath}`);
1612
+ definition.instructionFiles.forEach((file) => console.log(` Skill: ${file.path}`));
1613
+ }))
1614
+ .addCommand(new Command('nanoclaw')
1615
+ .description('Integrate with NanoClaw')
1616
+ .option('--dry-run', 'Preview changes')
1617
+ .action((options) => {
1618
+ const definition = getSetupDefinition('nanoclaw');
1619
+ if (options.dryRun) {
1620
+ printSetupPreview(definition);
1621
+ return;
1622
+ }
1623
+ installSetup(definition);
1624
+ console.log(`✅ Nexus Prime installed for NanoClaw`);
1625
+ console.log(` MCP: ${definition.configPath}`);
1626
+ definition.instructionFiles.forEach((file) => console.log(` Skill: ${file.path}`));
1627
+ }))
1628
+ .addCommand(new Command('picoclaw')
1629
+ .description('Integrate with PicoClaw')
1630
+ .option('--dry-run', 'Preview changes')
1631
+ .action((options) => {
1632
+ const definition = getSetupDefinition('picoclaw');
1633
+ if (options.dryRun) {
1634
+ printSetupPreview(definition);
1635
+ return;
1636
+ }
1637
+ installSetup(definition);
1638
+ console.log(`✅ Nexus Prime installed for PicoClaw`);
1639
+ console.log(` MCP: ${definition.configPath}`);
1640
+ definition.instructionFiles.forEach((file) => console.log(` Skill: ${file.path}`));
1476
1641
  }))
1477
1642
  .addCommand(new Command('all')
1478
1643
  .description('Install Nexus Prime for all supported clients in the current workspace')
1479
1644
  .option('--dry-run', 'Preview changes')
1480
1645
  .action((options) => {
1481
- const definitions = ['codex', 'cursor', 'claude-code', 'claude-desktop', 'opencode', 'windsurf', 'antigravity', 'openclaw', 'aider', 'continue', 'cline']
1482
- .map((clientId) => getSetupDefinition(clientId));
1646
+ const definitions = SETUP_CLIENTS.map((clientId) => getSetupDefinition(clientId));
1483
1647
  if (options.dryRun) {
1484
1648
  definitions.forEach((definition) => printSetupPreview(definition));
1485
1649
  writeClaudeCodeHooks(join(homedir(), '.claude', 'settings.json'), true);
@@ -1532,11 +1696,12 @@ program
1532
1696
  .description('Check integration status')
1533
1697
  .action(() => {
1534
1698
  console.log('📋 Integration Status:');
1535
- ['codex', 'cursor', 'claude-code', 'claude-desktop', 'opencode', 'windsurf', 'antigravity', 'openclaw', 'aider', 'continue', 'cline'].forEach((clientId) => {
1699
+ SETUP_CLIENTS.forEach((clientId) => {
1536
1700
  const definition = getSetupDefinition(clientId);
1537
1701
  const status = statusForDefinition(definition);
1538
1702
  const icon = status.state === 'installed' ? '✅' : status.state === 'drifted' ? '🟡' : '❌';
1539
- console.log(` - ${definition.label}: ${icon} ${status.summary}`);
1703
+ const hookSummary = status.memoryHookReady ? ' · memory hooks ready' : '';
1704
+ console.log(` - ${definition.label}: ${icon} ${status.summary}${hookSummary}`);
1540
1705
  });
1541
1706
  }))
1542
1707
  .addCommand(new Command('diagnose')
@@ -1545,13 +1710,14 @@ program
1545
1710
  console.log('🔍 Nexus Prime Setup Diagnostics\n');
1546
1711
  const manifest = collectBootstrapManifest({ packageRoot: PACKAGE_ROOT, workspaceRoot: getWorkspaceRoot() });
1547
1712
  const pad = (s, n) => s.padEnd(n);
1548
- console.log(`${pad('Client', 16)} ${pad('State', 12)} ${pad('Home', 8)} ${pad('Workspace', 12)} ${pad('Config Path', 10)}`);
1713
+ console.log(`${pad('Client', 16)} ${pad('State', 12)} ${pad('Home', 8)} ${pad('Workspace', 12)} ${pad('MemHook', 9)} ${pad('Config Path', 10)}`);
1549
1714
  console.log('─'.repeat(80));
1550
1715
  for (const client of manifest.clients) {
1551
1716
  const stateIcon = client.state === 'installed' ? '✅' : client.state === 'drifted' ? '🟡' : '❌';
1552
1717
  const homeIcon = client.homeReady ? '✅' : '❌';
1553
1718
  const wsIcon = client.workspaceReady ? '✅' : '❌';
1554
- console.log(`${pad(client.label, 16)} ${stateIcon} ${pad(client.state, 9)} ${homeIcon} ${pad('', 5)} ${wsIcon} ${pad('', 9)} ${client.configPath || '(none)'}`);
1719
+ const hookIcon = client.memoryHookReady ? '' : '';
1720
+ console.log(`${pad(client.label, 16)} ${stateIcon} ${pad(client.state, 9)} ${homeIcon} ${pad('', 5)} ${wsIcon} ${pad('', 9)} ${hookIcon} ${pad('', 6)} ${client.configPath || '(none)'}`);
1555
1721
  }
1556
1722
  console.log('\n📂 Path Validation:');
1557
1723
  for (const client of manifest.clients) {
@@ -151,7 +151,7 @@ export interface EvolutionConfig {
151
151
  }
152
152
  export interface Adapter {
153
153
  name: string;
154
- type: 'openclaw' | 'claude-code' | 'ruflo' | 'langchain' | 'autogen' | 'custom' | 'mcp' | 'codex' | 'opencode' | 'cursor' | 'windsurf' | 'aider' | 'continue' | 'cline';
154
+ type: 'openclaw' | 'hermes' | 'nanoclaw' | 'picoclaw' | 'claude-code' | 'ruflo' | 'langchain' | 'autogen' | 'custom' | 'mcp' | 'codex' | 'opencode' | 'cursor' | 'windsurf' | 'aider' | 'continue' | 'cline';
155
155
  connected: boolean;
156
156
  agents: string[];
157
157
  send(message: NetworkMessage): Promise<void>;
@@ -183,7 +183,7 @@
183
183
  }
184
184
  .decision-spine-grid {
185
185
  display: grid;
186
- grid-template-columns: repeat(3, minmax(0, 1fr));
186
+ grid-template-columns: repeat(4, minmax(0, 1fr));
187
187
  gap: 8px;
188
188
  margin-bottom: 10px;
189
189
  }
@@ -241,6 +241,80 @@
241
241
  gap: 4px;
242
242
  min-width: 0;
243
243
  }
244
+ .decision-spine-budget-grid {
245
+ display: grid;
246
+ grid-template-columns: repeat(4, minmax(0, 1fr));
247
+ gap: 6px;
248
+ margin: 8px 0 10px;
249
+ }
250
+ .decision-spine-budget-grid > div {
251
+ min-width: 0;
252
+ padding: 7px 8px;
253
+ border: 1px solid var(--border);
254
+ border-radius: var(--radius);
255
+ background: var(--bg-panel);
256
+ }
257
+ .decision-spine-budget-grid span {
258
+ display: block;
259
+ color: var(--text-dim);
260
+ font-family: var(--font-mono);
261
+ font-size: 0.66rem;
262
+ text-transform: uppercase;
263
+ letter-spacing: 0.05em;
264
+ }
265
+ .decision-spine-budget-grid strong {
266
+ display: block;
267
+ margin-top: 3px;
268
+ color: var(--accent);
269
+ font-family: var(--font-mono);
270
+ font-size: 0.82rem;
271
+ }
272
+ .decision-spine-budget-wide {
273
+ grid-column: 1 / -1;
274
+ }
275
+ .decision-spine-agentflow {
276
+ margin-top: 8px;
277
+ padding-top: 10px;
278
+ border-top: 1px solid var(--border);
279
+ }
280
+ .decision-spine-agentflow-rail {
281
+ display: grid;
282
+ grid-template-columns: repeat(6, minmax(72px, 1fr));
283
+ gap: 6px;
284
+ margin-bottom: 8px;
285
+ }
286
+ .decision-spine-agentflow-stage {
287
+ min-width: 0;
288
+ padding: 7px 8px;
289
+ border: 1px solid var(--border);
290
+ border-radius: var(--radius);
291
+ background: var(--bg-elevated);
292
+ }
293
+ .decision-spine-agentflow-stage span,
294
+ .decision-spine-agentflow-stage small {
295
+ display: block;
296
+ overflow: hidden;
297
+ text-overflow: ellipsis;
298
+ white-space: nowrap;
299
+ }
300
+ .decision-spine-agentflow-stage span {
301
+ color: var(--text-dim);
302
+ font-family: var(--font-mono);
303
+ font-size: 0.66rem;
304
+ text-transform: uppercase;
305
+ letter-spacing: 0.05em;
306
+ }
307
+ .decision-spine-agentflow-stage strong {
308
+ display: block;
309
+ margin: 3px 0;
310
+ color: var(--text-main);
311
+ font-size: 0.76rem;
312
+ }
313
+ .decision-spine-agentflow-stage small {
314
+ color: var(--accent);
315
+ font-family: var(--font-mono);
316
+ font-size: 0.68rem;
317
+ }
244
318
  .decision-spine-latest {
245
319
  margin-top: 10px;
246
320
  padding: 7px 9px;
@@ -329,6 +403,16 @@
329
403
  line-height: 1.35;
330
404
  }
331
405
 
406
+ @media (max-width: 820px) {
407
+ .decision-spine-grid,
408
+ .decision-spine-budget-grid {
409
+ grid-template-columns: repeat(2, minmax(0, 1fr));
410
+ }
411
+ .decision-spine-agentflow-rail {
412
+ grid-template-columns: repeat(2, minmax(0, 1fr));
413
+ }
414
+ }
415
+
332
416
  /* ── Tasks Tab ── */
333
417
  .task-toolbar { display: flex; align-items: center; gap: 8px; margin-bottom: 14px; flex-wrap: wrap; }
334
418
  .filter-grp { display: flex; gap: 2px; }
@@ -20,6 +20,25 @@
20
20
  border-radius: 8px;
21
21
  padding: 14px 18px;
22
22
  min-width: 0;
23
+ text-align: left;
24
+ }
25
+
26
+ .rt-kpi-action {
27
+ cursor: pointer;
28
+ color: inherit;
29
+ font: inherit;
30
+ transition: border-color 0.15s, background 0.15s, transform 0.15s;
31
+ }
32
+
33
+ .rt-kpi-action:hover,
34
+ .rt-kpi-action[aria-expanded="true"] {
35
+ border-color: var(--accent);
36
+ background: oklch(87% 0.19 152 / 7%);
37
+ }
38
+
39
+ .rt-kpi-action:focus-visible {
40
+ outline: 2px solid var(--accent);
41
+ outline-offset: 2px;
23
42
  }
24
43
 
25
44
  .rt-kpi-val {
@@ -234,6 +253,135 @@
234
253
  min-height: 0;
235
254
  }
236
255
 
256
+ /* ── Token telemetry flyout ─────────────────────────────────────────────────── */
257
+ .rt-token-flyout-slot {
258
+ position: relative;
259
+ }
260
+
261
+ .rt-token-flyout {
262
+ border: 1px solid var(--border);
263
+ border-radius: 8px;
264
+ background: var(--surface);
265
+ padding: 14px;
266
+ box-shadow: 0 18px 45px oklch(0% 0 0 / 35%);
267
+ animation: rt-ev-in 0.12s ease;
268
+ }
269
+
270
+ .rt-token-head {
271
+ display: flex;
272
+ align-items: flex-start;
273
+ justify-content: space-between;
274
+ gap: 12px;
275
+ margin-bottom: 12px;
276
+ }
277
+
278
+ .rt-token-title {
279
+ font: 700 14px ui-sans-serif, system-ui, sans-serif;
280
+ color: var(--text);
281
+ }
282
+
283
+ .rt-token-sub {
284
+ margin-top: 3px;
285
+ font-size: 12px;
286
+ color: var(--text-muted);
287
+ }
288
+
289
+ .rt-token-error { color: var(--bad, #ef4444); }
290
+
291
+ .rt-token-close {
292
+ border: 1px solid var(--border);
293
+ border-radius: 6px;
294
+ background: transparent;
295
+ color: var(--text-muted);
296
+ padding: 4px 9px;
297
+ cursor: pointer;
298
+ font-size: 12px;
299
+ }
300
+
301
+ .rt-token-close:hover {
302
+ border-color: var(--accent);
303
+ color: var(--accent);
304
+ }
305
+
306
+ .rt-token-grid {
307
+ display: grid;
308
+ grid-template-columns: repeat(4, minmax(0, 1fr));
309
+ gap: 8px;
310
+ margin-bottom: 12px;
311
+ }
312
+
313
+ .rt-token-stat {
314
+ border: 1px solid var(--border);
315
+ border-radius: 7px;
316
+ padding: 10px;
317
+ background: var(--bg-panel, transparent);
318
+ }
319
+
320
+ .rt-token-stat span,
321
+ .rt-token-row span {
322
+ color: var(--text-muted);
323
+ font-size: 11px;
324
+ }
325
+
326
+ .rt-token-stat strong {
327
+ display: block;
328
+ margin-top: 5px;
329
+ font: 700 20px/1 var(--font-mono, ui-monospace, monospace);
330
+ color: var(--accent);
331
+ }
332
+
333
+ .rt-token-columns {
334
+ display: grid;
335
+ grid-template-columns: 1fr 1fr;
336
+ gap: 12px;
337
+ }
338
+
339
+ .rt-token-section-title {
340
+ color: var(--text-muted);
341
+ font: 700 11px var(--font-mono, ui-monospace, monospace);
342
+ letter-spacing: 0.06em;
343
+ text-transform: uppercase;
344
+ margin-bottom: 6px;
345
+ }
346
+
347
+ .rt-token-row {
348
+ display: grid;
349
+ grid-template-columns: minmax(0, 1fr) auto auto;
350
+ gap: 8px;
351
+ align-items: center;
352
+ border-top: 1px solid var(--border);
353
+ padding: 6px 0;
354
+ min-width: 0;
355
+ }
356
+
357
+ .rt-token-row strong {
358
+ color: var(--text);
359
+ font: 700 12px var(--font-mono, ui-monospace, monospace);
360
+ }
361
+
362
+ .rt-token-row span:first-child {
363
+ overflow: hidden;
364
+ text-overflow: ellipsis;
365
+ white-space: nowrap;
366
+ }
367
+
368
+ .rt-token-muted {
369
+ color: var(--text-muted);
370
+ font-size: 12px;
371
+ padding: 8px 0;
372
+ }
373
+
374
+ @media (max-width: 900px) {
375
+ .runtime-kpis,
376
+ .rt-token-grid,
377
+ .rt-token-columns {
378
+ grid-template-columns: 1fr;
379
+ }
380
+ .runtime-kpis {
381
+ display: grid;
382
+ }
383
+ }
384
+
237
385
  .rt-mcp-strip-inner {
238
386
  display: flex;
239
387
  flex-wrap: wrap;
@@ -101,6 +101,34 @@
101
101
  }
102
102
  .dtags { display: flex; flex-wrap: wrap; gap: 4px; }
103
103
 
104
+ .dispatch-strip {
105
+ margin-top: 10px;
106
+ padding: 10px;
107
+ border: 1px solid var(--border);
108
+ border-radius: var(--radius);
109
+ background: var(--bg-panel);
110
+ }
111
+ .ds-stages { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; margin-bottom: 7px; }
112
+ .ds-stage {
113
+ font: 0.68rem var(--font-mono);
114
+ padding: 2px 6px;
115
+ border: 1px solid var(--border);
116
+ border-radius: 999px;
117
+ color: var(--text-dim);
118
+ }
119
+ .ds-stage.ds-done { color: var(--accent); border-color: rgba(0,255,136,0.28); }
120
+ .ds-stage.ds-active { color: var(--secondary); border-color: rgba(0,212,255,0.35); }
121
+ .ds-sep { color: var(--text-dim); font-size: 0.68rem; }
122
+ .ds-stdout, .ds-summary {
123
+ font-size: 0.74rem;
124
+ color: var(--text-muted);
125
+ line-height: 1.45;
126
+ margin-top: 5px;
127
+ }
128
+ .ds-meta { display: flex; flex-wrap: wrap; gap: 8px; color: var(--text-dim); font: 0.68rem var(--font-mono); }
129
+ .ds-error { margin-top: 6px; color: var(--warning); font-size: 0.74rem; }
130
+ .ds-stop-btn { margin-top: 8px; }
131
+
104
132
  /* ── Unified workforce kanban ── */
105
133
  .workforce-kanban { padding: 0; background: transparent; border: none !important; }
106
134
  .kanban-meta { font-size: 0.75rem; color: var(--text-dim); margin-bottom: 8px; padding: 0 4px; }