monomind 2.0.3 → 2.1.3

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 (113) hide show
  1. package/README.md +74 -92
  2. package/package.json +11 -7
  3. package/packages/@monomind/cli/.claude/helpers/control-start.cjs +13 -20
  4. package/packages/@monomind/cli/.claude/helpers/event-logger.cjs +109 -6
  5. package/packages/@monomind/cli/.claude/helpers/graphify-freshen.cjs +19 -17
  6. package/packages/@monomind/cli/.claude/helpers/handlers/agent-start-handler.cjs +60 -28
  7. package/packages/@monomind/cli/.claude/helpers/handlers/capture-handler.cjs +99 -28
  8. package/packages/@monomind/cli/.claude/helpers/handlers/edit-handler.cjs +27 -9
  9. package/packages/@monomind/cli/.claude/helpers/handlers/gates-handler.cjs +18 -9
  10. package/packages/@monomind/cli/.claude/helpers/handlers/loops-status-handler.cjs +1 -1
  11. package/packages/@monomind/cli/.claude/helpers/handlers/route-handler.cjs +33 -4
  12. package/packages/@monomind/cli/.claude/helpers/handlers/session-handler.cjs +75 -45
  13. package/packages/@monomind/cli/.claude/helpers/handlers/session-restore-handler.cjs +0 -12
  14. package/packages/@monomind/cli/.claude/helpers/handlers/task-handler.cjs +53 -22
  15. package/packages/@monomind/cli/.claude/helpers/hook-handler.cjs +75 -4
  16. package/packages/@monomind/cli/.claude/helpers/intelligence.cjs +94 -15
  17. package/packages/@monomind/cli/.claude/helpers/session.cjs +6 -1
  18. package/packages/@monomind/cli/.claude/helpers/statusline.cjs +10 -10
  19. package/packages/@monomind/cli/.claude/helpers/token-tracker.cjs +3 -3
  20. package/packages/@monomind/cli/.claude/helpers/utils/agent-registrations.cjs +41 -0
  21. package/packages/@monomind/cli/.claude/helpers/utils/fs-helpers.cjs +183 -0
  22. package/packages/@monomind/cli/.claude/helpers/utils/micro-agents.cjs +10 -6
  23. package/packages/@monomind/cli/.claude/helpers/utils/monograph.cjs +73 -2
  24. package/packages/@monomind/cli/.claude/helpers/utils/telemetry.cjs +35 -19
  25. package/packages/@monomind/cli/README.md +74 -92
  26. package/packages/@monomind/cli/bin/cli.js +10 -1
  27. package/packages/@monomind/cli/dist/src/browser/workflow/store.d.ts +2 -2
  28. package/packages/@monomind/cli/dist/src/commands/agent-ops.js +9 -15
  29. package/packages/@monomind/cli/dist/src/commands/browse.d.ts +1 -1
  30. package/packages/@monomind/cli/dist/src/commands/cleanup.js +20 -4
  31. package/packages/@monomind/cli/dist/src/commands/completions.js +66 -261
  32. package/packages/@monomind/cli/dist/src/commands/doctor-env-checks.js +5 -0
  33. package/packages/@monomind/cli/dist/src/commands/doctor.js +7 -2
  34. package/packages/@monomind/cli/dist/src/commands/hooks-workers.js +7 -0
  35. package/packages/@monomind/cli/dist/src/commands/index.js +3 -0
  36. package/packages/@monomind/cli/dist/src/commands/mcp.js +11 -6
  37. package/packages/@monomind/cli/dist/src/commands/memory-admin.js +12 -6
  38. package/packages/@monomind/cli/dist/src/commands/memory-transfer.js +6 -13
  39. package/packages/@monomind/cli/dist/src/commands/monograph.js +3 -3
  40. package/packages/@monomind/cli/dist/src/commands/org.d.ts +3 -1
  41. package/packages/@monomind/cli/dist/src/commands/org.js +321 -127
  42. package/packages/@monomind/cli/dist/src/commands/platforms.d.ts +1 -1
  43. package/packages/@monomind/cli/dist/src/commands/start.js +142 -37
  44. package/packages/@monomind/cli/dist/src/commands/tokens.js +21 -3
  45. package/packages/@monomind/cli/dist/src/config-adapter.js +37 -17
  46. package/packages/@monomind/cli/dist/src/index.js +64 -28
  47. package/packages/@monomind/cli/dist/src/init/claudemd-generator.js +44 -11
  48. package/packages/@monomind/cli/dist/src/init/executor.js +93 -55
  49. package/packages/@monomind/cli/dist/src/mcp-client.d.ts +8 -3
  50. package/packages/@monomind/cli/dist/src/mcp-client.js +37 -3
  51. package/packages/@monomind/cli/dist/src/mcp-server.js +8 -2
  52. package/packages/@monomind/cli/dist/src/mcp-tools/agent-tools.d.ts +20 -0
  53. package/packages/@monomind/cli/dist/src/mcp-tools/agent-tools.js +10 -5
  54. package/packages/@monomind/cli/dist/src/mcp-tools/auto-install.d.ts +8 -8
  55. package/packages/@monomind/cli/dist/src/mcp-tools/coherence/types.d.ts +31 -31
  56. package/packages/@monomind/cli/dist/src/mcp-tools/github-tools.js +30 -8
  57. package/packages/@monomind/cli/dist/src/mcp-tools/graphify-tools.js +11 -2
  58. package/packages/@monomind/cli/dist/src/mcp-tools/hive-mind-tools.js +56 -35
  59. package/packages/@monomind/cli/dist/src/mcp-tools/knowledge-tools.js +9 -1
  60. package/packages/@monomind/cli/dist/src/mcp-tools/monograph-compat.js +56 -14
  61. package/packages/@monomind/cli/dist/src/mcp-tools/monograph-tools.js +88 -41
  62. package/packages/@monomind/cli/dist/src/mcp-tools/quality/coverage-analysis/prioritize-gaps.d.ts +36 -36
  63. package/packages/@monomind/cli/dist/src/mcp-tools/quality/security-compliance/detect-secrets.d.ts +4 -4
  64. package/packages/@monomind/cli/dist/src/mcp-tools/swarm-tools.js +6 -4
  65. package/packages/@monomind/cli/dist/src/mcp-tools/system-tools.js +4 -4
  66. package/packages/@monomind/cli/dist/src/mcp-tools/types.d.ts +20 -0
  67. package/packages/@monomind/cli/dist/src/mcp-tools/types.js +36 -1
  68. package/packages/@monomind/cli/dist/src/memory/ewc-consolidation.d.ts +12 -0
  69. package/packages/@monomind/cli/dist/src/memory/hnsw-operations.d.ts +13 -1
  70. package/packages/@monomind/cli/dist/src/memory/hnsw-operations.js +66 -14
  71. package/packages/@monomind/cli/dist/src/memory/intelligence.js +99 -3
  72. package/packages/@monomind/cli/dist/src/memory/memory-bridge.d.ts +7 -0
  73. package/packages/@monomind/cli/dist/src/memory/memory-bridge.js +20 -0
  74. package/packages/@monomind/cli/dist/src/memory/sona-optimizer.d.ts +12 -0
  75. package/packages/@monomind/cli/dist/src/orgrt/broker.d.ts +26 -0
  76. package/packages/@monomind/cli/dist/src/orgrt/broker.js +73 -0
  77. package/packages/@monomind/cli/dist/src/orgrt/bus.d.ts +5 -1
  78. package/packages/@monomind/cli/dist/src/orgrt/bus.js +5 -1
  79. package/packages/@monomind/cli/dist/src/orgrt/daemon.d.ts +46 -0
  80. package/packages/@monomind/cli/dist/src/orgrt/daemon.js +201 -18
  81. package/packages/@monomind/cli/dist/src/orgrt/forwarder.d.ts +10 -5
  82. package/packages/@monomind/cli/dist/src/orgrt/forwarder.js +138 -8
  83. package/packages/@monomind/cli/dist/src/orgrt/inbox.d.ts +11 -0
  84. package/packages/@monomind/cli/dist/src/orgrt/inbox.js +56 -0
  85. package/packages/@monomind/cli/dist/src/orgrt/policy.d.ts +5 -1
  86. package/packages/@monomind/cli/dist/src/orgrt/policy.js +58 -5
  87. package/packages/@monomind/cli/dist/src/orgrt/provider.js +1 -0
  88. package/packages/@monomind/cli/dist/src/orgrt/scheduler.d.ts +13 -0
  89. package/packages/@monomind/cli/dist/src/orgrt/scheduler.js +48 -0
  90. package/packages/@monomind/cli/dist/src/orgrt/server.d.ts +9 -0
  91. package/packages/@monomind/cli/dist/src/orgrt/server.js +39 -0
  92. package/packages/@monomind/cli/dist/src/orgrt/session.d.ts +10 -1
  93. package/packages/@monomind/cli/dist/src/orgrt/session.js +24 -1
  94. package/packages/@monomind/cli/dist/src/orgrt/test-loop.d.ts +12 -0
  95. package/packages/@monomind/cli/dist/src/orgrt/test-loop.js +108 -0
  96. package/packages/@monomind/cli/dist/src/orgrt/types.d.ts +52 -52
  97. package/packages/@monomind/cli/dist/src/output.d.ts +29 -29
  98. package/packages/@monomind/cli/dist/src/output.js +22 -7
  99. package/packages/@monomind/cli/dist/src/parser.d.ts +32 -0
  100. package/packages/@monomind/cli/dist/src/parser.js +130 -5
  101. package/packages/@monomind/cli/dist/src/routing/embed-worker.js +13 -1
  102. package/packages/@monomind/cli/dist/src/routing/route-layer-factory.js +31 -0
  103. package/packages/@monomind/cli/dist/src/services/config-file-manager.d.ts +21 -0
  104. package/packages/@monomind/cli/dist/src/services/config-file-manager.js +60 -7
  105. package/packages/@monomind/cli/dist/src/services/crash-reporter.js +2 -1
  106. package/packages/@monomind/cli/dist/src/types.d.ts +2 -2
  107. package/packages/@monomind/cli/dist/src/ui/dashboard.html +243 -49
  108. package/packages/@monomind/cli/dist/src/ui/orgs-files.js +192 -0
  109. package/packages/@monomind/cli/dist/src/ui/orgs.html +79 -11
  110. package/packages/@monomind/cli/dist/src/ui/server.mjs +346 -139
  111. package/packages/@monomind/cli/dist/src/utils/input-guards.d.ts +9 -0
  112. package/packages/@monomind/cli/dist/src/utils/input-guards.js +39 -5
  113. package/packages/@monomind/cli/package.json +15 -15
@@ -428,6 +428,18 @@ html, body { height: 100%; background: var(--bg); color: var(--text-hi); font-fa
428
428
  /* SVG org chart */
429
429
  .org-chart-wrap { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; margin-bottom: 12px; }
430
430
  .org-chart-svg { width: 100%; display: block; }
431
+ .v2-bubble-inner {
432
+ background: oklch(18% 0.01 55 / 0.95);
433
+ border: 1px solid oklch(72% 0.18 75 / 0.4);
434
+ border-radius: 8px;
435
+ padding: 4px 8px;
436
+ font: 500 9.5px 'Inter', system-ui, sans-serif;
437
+ color: oklch(88% 0.01 75);
438
+ text-align: center;
439
+ white-space: nowrap;
440
+ overflow: hidden;
441
+ text-overflow: ellipsis;
442
+ }
431
443
  .org-chart-legend { display: flex; gap: 14px; flex-wrap: wrap; padding: 0 2px; }
432
444
  .ocl-item { display: flex; align-items: center; gap: 5px; font-size: 10px; color: var(--text-lo); }
433
445
 
@@ -2468,7 +2480,7 @@ function switchView(v, { updateHash = true } = {}) {
2468
2480
  const titles = { now:'Now', projects:'Projects', sessions:'Sessions', loops:'Loops', tokens:'Tokens', memory:'Memory', orgs:'Orgs', monograph:'Monograph', monoagent:'MonoAgent', global:'Global Feed', 'global-loops':'Global Loops', 'global-tokens':'Global Tokens', chat:'Global Agent Chat' };
2469
2481
  document.getElementById('view-title').textContent = titles[v] || v;
2470
2482
  const PROJECT = DIR ? shortPath(DIR) : 'monomind';
2471
- const VIEW_LABELS = { now: 'Now', sessions: 'Sessions', projects: 'Projects', loops: 'Loops', tokens: 'Tokens', memory: 'Memory', orgs: 'Orgs', monograph: 'Monograph', global: 'Global Feed', 'global-loops': 'Global Loops', 'global-tokens': 'Global Tokens' };
2483
+ const VIEW_LABELS = { now: 'Now', sessions: 'Sessions', projects: 'Projects', loops: 'Loops', tokens: 'Tokens', memory: 'Memory', orgs: 'Orgs', monograph: 'Monograph', monoagent: 'MonoAgent', global: 'Global Feed', 'global-loops': 'Global Loops', 'global-tokens': 'Global Tokens', chat: 'Global Agent Chat' };
2472
2484
  document.title = `monomind · ${PROJECT} · ${VIEW_LABELS[v] || v}`;
2473
2485
  if (updateHash) _pushHash();
2474
2486
  // Projects always re-fetches so onclick paths in cards stay current
@@ -4448,9 +4460,9 @@ function appendChatViewEvent(ev, animate) {
4448
4460
  const atBottom = !animate || (feed.scrollHeight - feed.scrollTop - feed.clientHeight < 80);
4449
4461
  const ts = ev.ts ? new Date(ev.ts).toLocaleTimeString([],{hour:'2-digit',minute:'2-digit',second:'2-digit'}) : '';
4450
4462
  if (ev.type === 'run:start') {
4451
- el = mkCVSys('▶ Run started' + (ev.goal ? ': ' + esc(ev.goal.slice(0,80)) : '') + (ev.bossRole ? ' · boss: ' + esc(ev.bossRole) : ''), ts);
4463
+ el = mkCVSys('▶ Run started' + (ev.goal ? ': ' + (ev.goal.slice(0,80)) : '') + (ev.bossRole ? ' · boss: ' + (ev.bossRole) : ''), ts);
4452
4464
  } else if (ev.type === 'run:cycle:complete') {
4453
- el = mkCVSys('◎ Cycle complete' + (ev.pending != null ? ' · ' + esc(String(ev.pending)) + ' tasks pending' : ''), ts);
4465
+ el = mkCVSys('◎ Cycle complete' + (ev.pending != null ? ' · ' + (String(ev.pending)) + ' tasks pending' : ''), ts);
4454
4466
  } else if (ev.type === 'intercom') {
4455
4467
  el = mkCVIntercom(ev.from, ev.to, ev.msg || '', ts);
4456
4468
  } else if (ev.type === 'org:comms') {
@@ -4459,15 +4471,15 @@ function appendChatViewEvent(ev, animate) {
4459
4471
  if (ev.to && ev.to !== 'all') el = mkCVIntercom(_cvCommsFrom, ev.to, ev.msg || '', ts);
4460
4472
  else el = mkCVAgent(_cvCommsFrom, ev.msg || '', ts, 'org:comms');
4461
4473
  } else if (ev.type === 'org:agent:online') {
4462
- el = mkCVSys('[' + esc(ev.org || '') + '] ' + esc(ev.role || ev.title || '?') + ' online' + (ev.title && ev.role && ev.title !== ev.role ? ' (' + esc(ev.title) + ')' : ''), ts);
4474
+ el = mkCVSys('[' + (ev.org || '') + '] ' + (ev.role || ev.title || '?') + ' online' + (ev.title && ev.role && ev.title !== ev.role ? ' (' + (ev.title) + ')' : ''), ts);
4463
4475
  } else if (ev.type === 'org:checkpoint') {
4464
- el = mkCVSys('[checkpoint] ' + esc(ev.summary || ev.progress || ev.msg || ''), ts);
4476
+ el = mkCVSys('[checkpoint] ' + (ev.summary || ev.progress || ev.msg || ''), ts);
4465
4477
  } else if (ev.type === 'org:start') {
4466
- el = mkCVSys('[org:start] ' + esc(ev.org || ''), ts);
4478
+ el = mkCVSys('[org:start] ' + (ev.org || ''), ts);
4467
4479
  } else if (ev.type === 'run:complete') {
4468
- el = mkCVSys('■ Run complete' + (ev.status ? ' [' + esc(ev.status) + ']' : ''), ts);
4480
+ el = mkCVSys('■ Run complete' + (ev.status ? ' [' + (ev.status) + ']' : ''), ts);
4469
4481
  } else if (ev.type === 'org:complete') {
4470
- el = mkCVSys('■ Org complete' + (ev.org ? ' — ' + esc(ev.org) : ''), ts);
4482
+ el = mkCVSys('■ Org complete' + (ev.org ? ' — ' + (ev.org) : ''), ts);
4471
4483
  } else if (ev.type === 'agent:result') {
4472
4484
  el = mkCVResult(ev.agent || ev.from || '?', ev.result || ev.msg || ev.message || ev.summary || '', ts);
4473
4485
  } else if (ev.type === 'agent:spawn') {
@@ -4487,36 +4499,36 @@ function appendChatViewEvent(ev, animate) {
4487
4499
  const _auAgent = ev.role || ev.agentType || '?';
4488
4500
  const _auCost = ev.cost_usd != null ? '$' + Number(ev.cost_usd).toFixed(4) : '';
4489
4501
  const _auTok = (ev.tokens_in || ev.tokens_out) ? ((ev.tokens_in||0)).toLocaleString() + '↑ ' + ((ev.tokens_out||0)).toLocaleString() + '↓' : '';
4490
- el = mkCVSys('◈ ' + esc(_auAgent) + (_auTok ? ' · ' + _auTok : '') + (_auCost ? ' · ' + _auCost : ''), ts);
4502
+ el = mkCVSys('◈ ' + (_auAgent) + (_auTok ? ' · ' + _auTok : '') + (_auCost ? ' · ' + _auCost : ''), ts);
4491
4503
  } else if (ev.type === 'agent:message') {
4492
4504
  el = mkCVAgent(ev.agent || ev.name || ev.role || '?', ev.msg || ev.message || ev.content || '', ts, ev.type);
4493
4505
  } else if (ev.type === 'session:start') {
4494
- el = mkCVSys('Session started' + (ev.prompt ? ': ' + esc(ev.prompt.slice(0,80)) : ''), ts);
4506
+ el = mkCVSys('Session started' + (ev.prompt ? ': ' + (ev.prompt.slice(0,80)) : ''), ts);
4495
4507
  } else if (ev.type === 'session:complete') {
4496
- el = mkCVSys('Session complete' + (ev.status ? ' — ' + esc(ev.status) : ''), ts);
4508
+ el = mkCVSys('Session complete' + (ev.status ? ' — ' + (ev.status) : ''), ts);
4497
4509
  } else if (ev.type === 'domain:dispatch') {
4498
- el = mkCVSys('→ ' + esc(ev.domain || '') + (ev.cmd ? ': ' + esc(ev.cmd.slice(0,80)) : ''), ts);
4510
+ el = mkCVSys('→ ' + (ev.domain || '') + (ev.cmd ? ': ' + (ev.cmd.slice(0,80)) : ''), ts);
4499
4511
  } else if (ev.type === 'domain:complete') {
4500
- el = mkCVSys('✓ ' + esc(ev.domain || '') + (ev.status ? ' [' + esc(ev.status) + ']' : ''), ts);
4512
+ el = mkCVSys('✓ ' + (ev.domain || '') + (ev.status ? ' [' + (ev.status) + ']' : ''), ts);
4501
4513
  } else if (ev.type === 'loop:start') {
4502
- el = mkCVSys('◎ Loop: ' + esc(ev.command || '') + (ev.repeat ? ' ×' + esc(String(ev.repeat)) : ''), ts);
4514
+ el = mkCVSys('◎ Loop: ' + (ev.command || '') + (ev.repeat ? ' ×' + (String(ev.repeat)) : ''), ts);
4503
4515
  if (currentView === 'loops') renderLoops();
4504
4516
  } else if (ev.type === 'loop:complete') {
4505
- el = mkCVSys('■ Loop done: ' + esc(ev.command || '') + (ev.ranReps ? ' (' + esc(String(ev.ranReps)) + ' runs)' : ''), ts);
4517
+ el = mkCVSys('■ Loop done: ' + (ev.command || '') + (ev.ranReps ? ' (' + (String(ev.ranReps)) + ' runs)' : ''), ts);
4506
4518
  if (currentView === 'loops') renderLoops();
4507
4519
  } else if (ev.type === 'loop:tick') {
4508
4520
  const _tickLbl = ev.rep != null
4509
- ? 'rep ' + esc(String(ev.rep)) + ' done' + (ev.wait != null ? ' → next in ' + esc(String(ev.wait)) + 's' : '')
4510
- : esc(ev.command || ev.loopId || ev.id || '');
4521
+ ? 'rep ' + (String(ev.rep)) + ' done' + (ev.wait != null ? ' → next in ' + (String(ev.wait)) + 's' : '')
4522
+ : (ev.command || ev.loopId || ev.id || '');
4511
4523
  el = mkCVSys('◷ ' + _tickLbl, ts);
4512
4524
  el.dataset.evType = 'loop:tick';
4513
4525
  if (feed.lastElementChild?.dataset?.evType === 'loop:tick') feed.lastElementChild.remove();
4514
4526
  if (currentView === 'loops') renderLoops();
4515
4527
  } else if (ev.type === 'loop:hil' || ev.type === 'loop:hil:waiting') {
4516
- el = mkCVSys('⚠ Loop HIL: ' + esc(ev.command || ev.loopId || ev.id || ''), ts);
4528
+ el = mkCVSys('⚠ Loop HIL: ' + (ev.command || ev.loopId || ev.id || ''), ts);
4517
4529
  if (currentView === 'loops') renderLoops();
4518
4530
  } else if (ev.type === 'loop:hil:resolved') {
4519
- el = mkCVSys('✓ Loop HIL resolved: ' + esc(ev.loopId || ev.command || ''), ts);
4531
+ el = mkCVSys('✓ Loop HIL resolved: ' + (ev.loopId || ev.command || ''), ts);
4520
4532
  if (currentView === 'loops') renderLoops();
4521
4533
  } else if (ev.type === 'file:write') {
4522
4534
  el = mkCVFileCard(ev.name || ev.path || '?', ev.path || '', ev.size || 0, ts);
@@ -4527,12 +4539,12 @@ function appendChatViewEvent(ev, animate) {
4527
4539
  } else if (ev.type === 'agent:browse') {
4528
4540
  el = mkCVTool('BROWSE', ev.payload || ev.url || '', '', 'oklch(65% 0.15 190)', ts);
4529
4541
  } else if (ev.type === 'org:agent:offline') {
4530
- el = mkCVSys('◌ ' + esc(ev.title || ev.role || '?') + ' offline' + (ev.org ? ' [' + esc(ev.org) + ']' : ''), ts);
4542
+ el = mkCVSys('◌ ' + (ev.title || ev.role || '?') + ' offline' + (ev.org ? ' [' + (ev.org) + ']' : ''), ts);
4531
4543
  } else if (ev.type === 'org:error') {
4532
- el = mkCVSys('⚠ Error: ' + esc(ev.msg || ev.error || ev.message || ''), ts);
4544
+ el = mkCVSys('⚠ Error: ' + (ev.msg || ev.error || ev.message || ''), ts);
4533
4545
  el.classList.add('cv-err');
4534
4546
  } else {
4535
- el = mkCVSys(esc(ev.type || 'event'), ts);
4547
+ el = mkCVSys((ev.type || 'event'), ts);
4536
4548
  }
4537
4549
  if (animate) el.classList.add('cv-new');
4538
4550
  feed.appendChild(el);
@@ -4671,10 +4683,10 @@ function mkCVTool(tag, cmd, output, color, ts) {
4671
4683
  return d;
4672
4684
  }
4673
4685
 
4674
- function mkCVSys(html, ts) {
4686
+ function mkCVSys(text, ts) {
4675
4687
  const d = document.createElement('div');
4676
4688
  d.className = 'cv-msg cv-sys';
4677
- d.innerHTML = `<div class="cv-bub"><span class="cv-etype">SYS</span><span class="cv-text">${html}</span><span class="cv-ts">${ts}</span></div>`;
4689
+ d.innerHTML = `<div class="cv-bub"><span class="cv-etype">SYS</span><span class="cv-text">${esc(text)}</span><span class="cv-ts">${ts}</span></div>`;
4678
4690
  return d;
4679
4691
  }
4680
4692
 
@@ -5786,6 +5798,7 @@ let _v2SelOrg = null;
5786
5798
  let _v2OrgData = null;
5787
5799
  let _v2OrgTab = 'chart';
5788
5800
  const _v2OrgEventLog = {};
5801
+ let _v2ChartLayout = { pos: {}, edgeIdByPair: new Map() };
5789
5802
 
5790
5803
  async function renderOrgs() {
5791
5804
  try {
@@ -6204,6 +6217,9 @@ function v2RenderOrgChart() {
6204
6217
  <image href="${avatarSrc}" x="${-avR}" y="${-R + 2}" width="${avR * 2}" height="${avR * 2}" clip-path="url(#${nodeClipIds[i]})" preserveAspectRatio="xMidYMid meet" onerror="this.setAttribute('href','data/avatars/coder.svg')"/>
6205
6218
  <text text-anchor="middle" y="${nameY}" font-size="9" font-weight="${leader?'600':'500'}" font-family="'Inter',system-ui,sans-serif" fill="${color}">${esc(nameText)}</text>
6206
6219
  ${subTypeText ? `<text text-anchor="middle" y="${+nameY + 11}" font-size="7.5" font-family="'Inter',system-ui,sans-serif" fill="oklch(48% 0.005 75)">${esc(subTypeText)}</text>` : ''}
6220
+ <foreignObject class="v2-activity-bubble" data-bubble-for="${esc(role.id)}" x="-70" y="${-R - 46}" width="140" height="34" style="overflow:visible;pointer-events:none;visibility:hidden;opacity:0">
6221
+ <div class="v2-bubble-inner" xmlns="http://www.w3.org/1999/xhtml"></div>
6222
+ </foreignObject>
6207
6223
  </g>`;
6208
6224
  });
6209
6225
 
@@ -6230,6 +6246,7 @@ function v2RenderOrgChart() {
6230
6246
  <g id="v2oc-edges">${edgesHTML}</g>
6231
6247
  <g id="v2oc-nodes">${nodesHTML}</g>
6232
6248
  <g id="v2oc-particles" opacity="${isRunning ? 1 : 0}">${particlesHTML}</g>
6249
+ <g id="v2oc-letters"></g>
6233
6250
  </svg>
6234
6251
  </div>
6235
6252
  <div class="org-chart-legend" style="margin-top:10px">
@@ -6262,8 +6279,158 @@ function v2RenderOrgChart() {
6262
6279
  el.style.opacity = '0';
6263
6280
  });
6264
6281
  }
6282
+
6283
+ const edgeIdByPair = new Map();
6284
+ comms.forEach((edge, ei) => {
6285
+ if (edge.from === edge.to) return;
6286
+ edgeIdByPair.set(edge.from + '->' + edge.to, 'v2ep' + ei);
6287
+ });
6288
+ _v2ChartLayout = { pos, edgeIdByPair };
6289
+ v2OrgActivityReset();
6290
+ }
6291
+
6292
+ function _v2RoleName(id, roles) {
6293
+ const r = (roles || []).find(x => x.id === id);
6294
+ return r ? (r.name || r.title || r.id) : id;
6295
+ }
6296
+
6297
+ function v2DeriveActivityText(ev, roles) {
6298
+ if (!ev || !ev.from) return null;
6299
+ const type = ev.type || '';
6300
+ if (type === 'org:tool') return ev.tool ? ('running ' + ev.tool) : 'active';
6301
+ if (type === 'org:checkpoint') {
6302
+ const p = ev.progress || '';
6303
+ return p ? (p.length > 40 ? p.slice(0, 39) + '...' : p) : 'active';
6304
+ }
6305
+ if (type === 'org:comms') {
6306
+ if (!ev.to || ev.to === 'all') return 'broadcasting';
6307
+ return 'messaging ' + _v2RoleName(ev.to, roles);
6308
+ }
6309
+ if (type === 'org:artifact') {
6310
+ const label = ev.artifact && ev.artifact.label;
6311
+ return label ? ('writing ' + label) : 'active';
6312
+ }
6313
+ return 'active';
6314
+ }
6315
+
6316
+ function v2DeriveLetterTarget(ev, roles) {
6317
+ if (!ev || !ev.from) return null;
6318
+ const type = ev.type || '';
6319
+ if (type === 'org:comms') {
6320
+ if (!ev.to || ev.to === 'all') return null;
6321
+ return { from: ev.from, to: ev.to };
6322
+ }
6323
+ if (type === 'org:checkpoint' || type === 'org:artifact') {
6324
+ const leader = (roles || []).find(_v2OrgIsLeader);
6325
+ if (!leader || leader.id === ev.from) return null;
6326
+ return { from: ev.from, to: leader.id };
6327
+ }
6328
+ return null;
6329
+ }
6330
+
6331
+ let _v2LetterBurst = { lastTs: 0, count: 0 };
6332
+
6333
+ function v2SpawnLetter(fromId, toId) {
6334
+ const layout = _v2ChartLayout;
6335
+ const fp = layout.pos[fromId], tp = layout.pos[toId];
6336
+ if (!fp || !tp) return;
6337
+ const group = document.getElementById('v2oc-letters');
6338
+ if (!group) return;
6339
+
6340
+ const now = Date.now();
6341
+ if (now - _v2LetterBurst.lastTs < 150) _v2LetterBurst.count++;
6342
+ else _v2LetterBurst.count = 0;
6343
+ _v2LetterBurst.lastTs = now;
6344
+ const delay = (_v2LetterBurst.count * 0.08).toFixed(2);
6345
+
6346
+ const svgNS = 'http://www.w3.org/2000/svg';
6347
+ let pathId = layout.edgeIdByPair.get(fromId + '->' + toId);
6348
+ let synthesizedPath = null;
6349
+ if (!pathId) {
6350
+ pathId = 'v2lp' + Math.random().toString(36).slice(2, 9);
6351
+ synthesizedPath = document.createElementNS(svgNS, 'path');
6352
+ synthesizedPath.setAttribute('id', pathId);
6353
+ synthesizedPath.setAttribute('d', 'M' + fp.x + ',' + fp.y + ' L' + tp.x + ',' + tp.y);
6354
+ synthesizedPath.setAttribute('fill', 'none');
6355
+ synthesizedPath.setAttribute('stroke', 'none');
6356
+ document.getElementById('v2oc-edges').appendChild(synthesizedPath);
6357
+ }
6358
+
6359
+ const letter = document.createElementNS(svgNS, 'g');
6360
+ const circ = document.createElementNS(svgNS, 'circle');
6361
+ circ.setAttribute('r', '6');
6362
+ circ.setAttribute('fill', 'oklch(85% 0.16 85)');
6363
+ circ.setAttribute('stroke', 'oklch(30% 0.02 55)');
6364
+ circ.setAttribute('stroke-width', '1');
6365
+ letter.appendChild(circ);
6366
+ const flap = document.createElementNS(svgNS, 'path');
6367
+ flap.setAttribute('d', 'M-3.5,-2 L0,1 L3.5,-2');
6368
+ flap.setAttribute('stroke', 'oklch(30% 0.02 55)');
6369
+ flap.setAttribute('stroke-width', '1');
6370
+ flap.setAttribute('fill', 'none');
6371
+ letter.appendChild(flap);
6372
+
6373
+ const anim = document.createElementNS(svgNS, 'animateMotion');
6374
+ anim.setAttribute('dur', '0.8s');
6375
+ anim.setAttribute('begin', delay + 's');
6376
+ anim.setAttribute('fill', 'freeze');
6377
+ const mpath = document.createElementNS(svgNS, 'mpath');
6378
+ mpath.setAttributeNS('http://www.w3.org/1999/xlink', 'href', '#' + pathId);
6379
+ anim.appendChild(mpath);
6380
+ letter.appendChild(anim);
6381
+ group.appendChild(letter);
6382
+
6383
+ if (typeof gsap !== 'undefined') {
6384
+ gsap.fromTo(letter, { scale: 0, autoAlpha: 0 }, { scale: 1, autoAlpha: 1, duration: 0.15, delay: Number(delay), ease: 'back.out(1.7)' });
6385
+ }
6386
+
6387
+ const totalMs = (Number(delay) + 0.8) * 1000;
6388
+ setTimeout(function() {
6389
+ function cleanup() {
6390
+ letter.remove();
6391
+ if (synthesizedPath) synthesizedPath.remove();
6392
+ }
6393
+ if (typeof gsap !== 'undefined') {
6394
+ gsap.to(letter, { autoAlpha: 0, duration: 0.15, onComplete: cleanup });
6395
+ } else cleanup();
6396
+ }, totalMs);
6397
+ }
6398
+
6399
+ let _v2BubbleTimers = new Map();
6400
+
6401
+ function v2OrgActivityReset() {
6402
+ _v2BubbleTimers.forEach(t => clearTimeout(t));
6403
+ _v2BubbleTimers = new Map();
6265
6404
  }
6266
6405
 
6406
+ function v2ShowActivityBubble(roleId, text) {
6407
+ const fo = document.querySelector('.v2-activity-bubble[data-bubble-for="' + CSS.escape(roleId) + '"]');
6408
+ if (!fo) return;
6409
+ const inner = fo.querySelector('.v2-bubble-inner');
6410
+ inner.textContent = text;
6411
+ if (typeof gsap !== 'undefined') {
6412
+ gsap.killTweensOf(fo);
6413
+ fo.style.visibility = 'visible';
6414
+ gsap.fromTo(fo, { scale: 0.8, autoAlpha: 0 }, {
6415
+ scale: 1, autoAlpha: 1, duration: 0.3, ease: 'back.out(1.7)',
6416
+ transformOrigin: '50% 100%',
6417
+ });
6418
+ } else {
6419
+ fo.style.visibility = 'visible';
6420
+ fo.style.opacity = '1';
6421
+ }
6422
+ const existing = _v2BubbleTimers.get(roleId);
6423
+ if (existing) clearTimeout(existing);
6424
+ _v2BubbleTimers.set(roleId, setTimeout(function() {
6425
+ if (typeof gsap !== 'undefined') {
6426
+ gsap.to(fo, { autoAlpha: 0, duration: 0.4, ease: 'power2.in', onComplete: function() { fo.style.visibility = 'hidden'; } });
6427
+ } else {
6428
+ fo.style.opacity = '0';
6429
+ fo.style.visibility = 'hidden';
6430
+ }
6431
+ _v2BubbleTimers.delete(roleId);
6432
+ }, 5000));
6433
+ }
6267
6434
 
6268
6435
  // ── in-place running dot updater (avoids full re-render + GSAP flicker on SSE events) ──
6269
6436
  function v2UpdateChartRunningDots() {
@@ -7940,17 +8107,28 @@ window.odtChatSelectAgent = function(name) {
7940
8107
  });
7941
8108
  const feed = document.getElementById('odt-chat-feed');
7942
8109
  const emptyEl = document.getElementById('odt-chat-empty');
7943
- const sess = _odtChatSessions.find(s => s.id === _odtChatCurrentId);
7944
8110
  feed.querySelectorAll('.cv-msg').forEach(e => e.remove());
7945
- if (!sess) { if (emptyEl) emptyEl.style.display = 'block'; return; }
7946
- const visible = (sess.events || []).filter(ev => _odtChatAgentMatches(ev));
8111
+ const id = _odtChatCurrentId;
8112
+ let events = null;
8113
+ let sess = null;
8114
+ if (id && id.startsWith('rgrp:') && _odtRunGroups[id]) {
8115
+ events = _odtGetMergedRunGroupEvents(_odtRunGroups[id]);
8116
+ } else if (id && id.startsWith('grp:') && _odtSessionGroups[id]) {
8117
+ events = _odtGetMergedGroupEvents(_odtSessionGroups[id]);
8118
+ } else {
8119
+ sess = _odtChatSessions.find(s => s.id === id);
8120
+ events = sess ? (sess.events || []) : null;
8121
+ }
8122
+ if (events === null) { if (emptyEl) { emptyEl.style.display = 'block'; emptyEl.textContent = 'Select a session to see agent communications.'; } return; }
8123
+ const visible = events.filter(ev => _odtChatAgentMatches(ev));
7947
8124
  if (!visible.length) {
7948
8125
  if (emptyEl) { emptyEl.style.display = 'block'; emptyEl.textContent = name === 'all' ? 'No events.' : `${name} was online in this run but sent no messages.`; }
7949
8126
  } else {
7950
8127
  if (emptyEl) emptyEl.style.display = 'none';
7951
8128
  visible.forEach(ev => _odtAppendEvent(ev, false));
8129
+ if (!feed.querySelector('.cv-msg') && emptyEl) { emptyEl.style.display = 'block'; emptyEl.textContent = 'No displayable events.'; }
7952
8130
  }
7953
- if (!sess._isOrgRun) {
8131
+ if (sess && !sess._isOrgRun) {
7954
8132
  const _linkedRunId = 'run-' + (sess.id || '').replace(/^mm-/, '');
7955
8133
  const _linkedRun = _odtChatSessions.find(s => s._isOrgRun && s.id === _linkedRunId);
7956
8134
  if (_linkedRun) {
@@ -7976,17 +8154,25 @@ window.odtChatSelectAgent = function(name) {
7976
8154
  // Chat tab render mode (Summary/Detailed/Raw) — persists to localStorage
7977
8155
  let _odtChatMode = localStorage.getItem('odt-chat-mode') || 'detailed';
7978
8156
 
7979
- function setOdtChatMode(mode) {
7980
- _odtChatMode = mode;
7981
- localStorage.setItem('odt-chat-mode', mode);
8157
+ function _odtApplyChatModeUI(mode) {
7982
8158
  document.querySelectorAll('.odt-mode-btn').forEach(b => b.classList.remove('active'));
7983
8159
  const btn = document.getElementById('odt-mode-' + mode);
7984
8160
  if (btn) btn.classList.add('active');
7985
8161
  }
7986
8162
 
8163
+ function setOdtChatMode(mode) {
8164
+ _odtChatMode = mode;
8165
+ localStorage.setItem('odt-chat-mode', mode);
8166
+ _odtApplyChatModeUI(mode);
8167
+ // Re-render the current selection so the mode change is reflected immediately —
8168
+ // previously this only affected events appended after the switch.
8169
+ if (_odtChatCurrentId) window.odtChatSelectAgent(_odtChatCurrentAgent);
8170
+ }
8171
+
7987
8172
  function initOdtChatMode() {
7988
8173
  const saved = localStorage.getItem('odt-chat-mode') || 'detailed';
7989
- setOdtChatMode(saved);
8174
+ _odtChatMode = saved;
8175
+ _odtApplyChatModeUI(saved);
7990
8176
  }
7991
8177
 
7992
8178
  function _odtAppendEvent(ev, animate) {
@@ -8014,18 +8200,18 @@ function _odtAppendEvent(ev, animate) {
8014
8200
  const ts = ev.ts ? new Date(ev.ts).toLocaleTimeString([],{hour:'2-digit',minute:'2-digit',second:'2-digit'}) : '';
8015
8201
  let el;
8016
8202
  if (ev.type === 'run:start') {
8017
- el = mkCVSys('▶ Run started' + (ev.goal ? ': ' + esc(ev.goal.slice(0,80)) : '') + (ev.bossRole ? ' · boss: ' + esc(ev.bossRole) : ''), ts);
8203
+ el = mkCVSys('▶ Run started' + (ev.goal ? ': ' + (ev.goal.slice(0,80)) : '') + (ev.bossRole ? ' · boss: ' + (ev.bossRole) : ''), ts);
8018
8204
  } else if (ev.type === 'run:cycle:complete') {
8019
- el = mkCVSys('◎ Cycle complete' + (ev.pending != null ? ' · ' + esc(String(ev.pending)) + ' tasks pending' : ''), ts);
8205
+ el = mkCVSys('◎ Cycle complete' + (ev.pending != null ? ' · ' + (String(ev.pending)) + ' tasks pending' : ''), ts);
8020
8206
  } else if (ev.type === 'run:complete') {
8021
- el = mkCVSys('■ Run complete' + (ev.status ? ' [' + esc(ev.status) + ']' : ''), ts);
8207
+ el = mkCVSys('■ Run complete' + (ev.status ? ' [' + (ev.status) + ']' : ''), ts);
8022
8208
  } else if (ev.type === 'org:comms') {
8023
8209
  // Some older runs use ev.role instead of ev.from — normalise before rendering
8024
8210
  const _commsFrom = ev.from || ev.role || 'boss';
8025
8211
  if (ev.to && ev.to !== 'all') el = mkCVIntercom(_commsFrom, ev.to, ev.msg || '', ts);
8026
8212
  else el = mkCVAgent(_commsFrom, ev.msg || '', ts, 'org:comms');
8027
8213
  } else if (ev.type === 'org:agent:online') {
8028
- el = mkCVSys('◉ ' + esc(ev.title || ev.role || '?') + ' online', ts);
8214
+ el = mkCVSys('◉ ' + (ev.title || ev.role || '?') + ' online', ts);
8029
8215
  } else if (ev.type === 'org:checkpoint') {
8030
8216
  el = mkCVAgent('boss', ev.summary || ev.progress || ev.msg || '', ts, 'org:checkpoint');
8031
8217
  } else if (ev.type === 'org:start' || ev.type === 'org:complete') {
@@ -8041,32 +8227,32 @@ function _odtAppendEvent(ev, animate) {
8041
8227
  } else if (ev.type === 'agent:message') {
8042
8228
  el = mkCVAgent(ev.agent || ev.name || ev.role || '?', ev.msg || ev.message || ev.content || '', ts, ev.type);
8043
8229
  } else if (ev.type === 'session:start') {
8044
- el = mkCVSys('▶ ' + esc((ev.prompt || '').replace(/^running org:\s*/i,'').slice(0,80) || 'Session started'), ts);
8230
+ el = mkCVSys('▶ ' + ((ev.prompt || '').replace(/^running org:\s*/i,'').slice(0,80) || 'Session started'), ts);
8045
8231
  } else if (ev.type === 'session:complete') {
8046
- el = mkCVSys('■ Complete' + (ev.status ? ' — ' + esc(ev.status) : ''), ts);
8232
+ el = mkCVSys('■ Complete' + (ev.status ? ' — ' + (ev.status) : ''), ts);
8047
8233
  } else if (ev.type === 'domain:dispatch') {
8048
- el = mkCVSys('→ ' + esc(ev.domain || '') + (ev.cmd ? ': ' + esc(ev.cmd.slice(0,80)) : ''), ts);
8234
+ el = mkCVSys('→ ' + (ev.domain || '') + (ev.cmd ? ': ' + (ev.cmd.slice(0,80)) : ''), ts);
8049
8235
  } else if (ev.type === 'domain:complete') {
8050
- el = mkCVSys('✓ ' + esc(ev.domain || '') + (ev.status ? ' [' + esc(ev.status) + ']' : ''), ts);
8236
+ el = mkCVSys('✓ ' + (ev.domain || '') + (ev.status ? ' [' + (ev.status) + ']' : ''), ts);
8051
8237
  } else if (ev.type === 'loop:start') {
8052
- el = mkCVSys('Loop: ' + esc(ev.command || ''), ts);
8238
+ el = mkCVSys('Loop: ' + (ev.command || ''), ts);
8053
8239
  } else if (ev.type === 'loop:complete') {
8054
- el = mkCVSys('Loop done: ' + esc(ev.command || '') + (ev.ranReps ? ' (' + ev.ranReps + ' runs)' : ''), ts);
8240
+ el = mkCVSys('Loop done: ' + (ev.command || '') + (ev.ranReps ? ' (' + ev.ranReps + ' runs)' : ''), ts);
8055
8241
  } else if (ev.type === 'loop:tick') {
8056
8242
  const _trep = ev.rep ?? ev.fromRep;
8057
8243
  const _tnext = ev.nextRep ?? ev.toRep;
8058
8244
  const tickLabel = _trep != null
8059
- ? 'rep ' + esc(String(_trep)) + ' done' + (_tnext != null ? ' → rep ' + esc(String(_tnext)) + (ev.wait != null ? ' in ' + esc(String(ev.wait)) + 's' : '') : '')
8060
- : esc(ev.command || ev.loopId || '');
8245
+ ? 'rep ' + (String(_trep)) + ' done' + (_tnext != null ? ' → rep ' + (String(_tnext)) + (ev.wait != null ? ' in ' + (String(ev.wait)) + 's' : '') : '')
8246
+ : (ev.command || ev.loopId || '');
8061
8247
  el = mkCVSys('◷ ' + tickLabel, ts);
8062
8248
  el.dataset.evType = 'loop:tick';
8063
8249
  // Collapse: replace the previous loop:tick if it's the last element — prevents the
8064
8250
  // feed from flooding with one entry per rep in long-running loops (e.g. --repeat 9999).
8065
8251
  if (feed.lastElementChild?.dataset?.evType === 'loop:tick') feed.lastElementChild.remove();
8066
8252
  } else if (ev.type === 'loop:hil' || ev.type === 'loop:hil:waiting') {
8067
- el = mkCVSys('⚠ Loop HIL: ' + esc(ev.command || ev.loopId || ''), ts);
8253
+ el = mkCVSys('⚠ Loop HIL: ' + (ev.command || ev.loopId || ''), ts);
8068
8254
  } else if (ev.type === 'loop:hil:resolved') {
8069
- el = mkCVSys('✓ Loop HIL resolved: ' + esc(ev.loopId || ''), ts);
8255
+ el = mkCVSys('✓ Loop HIL resolved: ' + (ev.loopId || ''), ts);
8070
8256
  } else if (ev.type === 'agent:edit' || ev.type === 'agent:write') {
8071
8257
  el = mkCVTool('EDIT', ev.payload || ev.file || ev.path || '', '', 'oklch(65% 0.20 270)', ts);
8072
8258
  } else if (ev.type === 'agent:bash') {
@@ -8074,15 +8260,15 @@ function _odtAppendEvent(ev, animate) {
8074
8260
  } else if (ev.type === 'agent:browse') {
8075
8261
  el = mkCVTool('BROWSE', ev.payload || ev.url || '', '', 'oklch(65% 0.15 190)', ts);
8076
8262
  } else if (ev.type === 'org:error') {
8077
- el = mkCVSys('⚠ Error: ' + esc(ev.msg || ev.error || ev.message || ''), ts);
8263
+ el = mkCVSys('⚠ Error: ' + (ev.msg || ev.error || ev.message || ''), ts);
8078
8264
  el.classList.add('cv-err');
8079
8265
  } else if (ev.type === 'org:agent:offline') {
8080
- el = mkCVSys('◌ ' + esc(ev.title || ev.role || '?') + ' offline', ts);
8266
+ el = mkCVSys('◌ ' + (ev.title || ev.role || '?') + ' offline', ts);
8081
8267
  } else if (ev.type === 'user:message') {
8082
8268
  el = mkCVAgent('you', ev.text || ev.msg || ev.message || '', ts, 'user:message');
8083
8269
  el.classList.add('cv-user-msg');
8084
8270
  } else {
8085
- el = mkCVSys(esc(ev.type || 'event'), ts);
8271
+ el = mkCVSys((ev.type || 'event'), ts);
8086
8272
  }
8087
8273
  if (animate) el.classList.add('cv-new');
8088
8274
  feed.appendChild(el);
@@ -8146,6 +8332,14 @@ function _odtHandleLiveEvent(ev) {
8146
8332
  const _arr = [..._odtChatSeenKeys];
8147
8333
  _odtChatSeenKeys = new Set(_arr.slice(1000));
8148
8334
  }
8335
+ // Wire activity bubble for org chart visualization
8336
+ if (ev && ev.org === _v2SelOrg) {
8337
+ const roles = Array.isArray(_v2OrgData && _v2OrgData.roles) ? _v2OrgData.roles : [];
8338
+ const text = v2DeriveActivityText(ev, roles);
8339
+ if (text && ev.from) v2ShowActivityBubble(ev.from, text);
8340
+ const letterTarget = v2DeriveLetterTarget(ev, roles);
8341
+ if (letterTarget) v2SpawnLetter(letterTarget.from, letterTarget.to);
8342
+ }
8149
8343
  // Route org run events (have runId + org) to the active run session
8150
8344
  if (ev?.org && ev?.runId && ev.org === _v2SelOrg) {
8151
8345
  let runSess = _odtChatSessions.find(s => s.id === ev.runId);