clawmetry 0.12.332__py3-none-any.whl → 0.12.334__py3-none-any.whl

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.
@@ -3890,7 +3890,20 @@ function renderBrainStream(events) {
3890
3890
  // (filter changes, auto-refresh) recompute from the source of truth.
3891
3891
  filtered = _collapseBodylessOutbound(filtered);
3892
3892
  if (!filtered || filtered.length === 0) {
3893
- el.innerHTML = '<div style="color:var(--text-muted);padding:20px">No activity yet</div>';
3893
+ // Runtime-aware empty state: the header switcher counts SESSIONS on record
3894
+ // (lifetime), but this feed only shows RECENT events. Selecting a runtime
3895
+ // with sessions but no recent activity used to read a bare "No activity
3896
+ // yet", which contradicts the switcher's "Goose · 3 sessions". Explain it.
3897
+ var _bf = (typeof _cmRuntimeFilter === 'function') ? _cmRuntimeFilter() : 'all';
3898
+ var _bmsg = 'No activity yet';
3899
+ if (_bf && _bf !== 'all') {
3900
+ var _blbl = (_CM_RT_LABEL && _CM_RT_LABEL[_bf]) || _bf;
3901
+ var _bn = (_cmGlobalRtCounts && _cmGlobalRtCounts[_bf]) || 0;
3902
+ _bmsg = 'No recent ' + escHtml(_blbl) + ' activity in this live feed.'
3903
+ + (_bn ? ' ' + escHtml(_blbl) + ' has ' + _bn + ' session' + (_bn === 1 ? '' : 's')
3904
+ + ' on record (older than this window) — open the Tracing tab to explore them.' : '');
3905
+ }
3906
+ el.innerHTML = '<div style="color:var(--text-muted);padding:20px;line-height:1.6;">' + _bmsg + '</div>';
3894
3907
  return;
3895
3908
  }
3896
3909
  // Issue #1203: one-line banner when Telegram outbound rows are visible so
@@ -6798,6 +6811,8 @@ function _cmPopulateGlobalRuntime(counts) {
6798
6811
  function _cmOnGlobalRuntimeChange(sel) {
6799
6812
  if (!sel) return;
6800
6813
  _cmSetRuntimeFilter(sel.value);
6814
+ // Swap the Flow + Overview diagram to the selected runtime's topology.
6815
+ try { if (typeof _applyRuntimeFlowDiagram === 'function') _applyRuntimeFlowDiagram(sel.value); } catch (e) {}
6801
6816
  // Reload the current tab so any runtime-aware view re-filters in place.
6802
6817
  if (typeof switchTab === 'function' && _cmCurrentTab) switchTab(_cmCurrentTab);
6803
6818
  }
@@ -13641,6 +13656,97 @@ function initFlow() {
13641
13656
  // the browser tab is hidden — completes Phase 2 coverage.
13642
13657
  if (window._flowStatsTimer) { try { clearInterval(window._flowStatsTimer); } catch(e){} }
13643
13658
  window._flowStatsTimer = visibilitySetInterval(updateFlowStats, updateInterval);
13659
+ // Per-adapter Flow diagram: reflect the runtime currently selected in the
13660
+ // global switcher (OpenClaw/Hermes keep the rich channel→gateway SVG;
13661
+ // coding-CLI + pico/nano get their own generated topology).
13662
+ try { _applyRuntimeFlowDiagram((typeof _cmRuntimeFilter === 'function') ? _cmRuntimeFilter() : 'all'); } catch (e) {}
13663
+ }
13664
+
13665
+ // ── Per-adapter Flow diagram (goal: distinct topology per runtime) ──────────
13666
+ // OpenClaw / Hermes keep the hand-built channel→gateway→agent→tools SVG. The
13667
+ // coding-CLI runtimes (Claude Code, Codex, Cursor, Aider, Goose, opencode,
13668
+ // Qwen) and the minimal PicoClaw/NanoClaw don't have channels or a chat
13669
+ // gateway, so showing them the OpenClaw topology was misleading. We swap
13670
+ // #flow-svg's content for a generated, runtime-correct diagram and re-mirror
13671
+ // the Overview pane. Driven by the global runtime switcher.
13672
+ var _origFlowSvgInner = null;
13673
+ var _RT_FLOW = {
13674
+ claude_code: { label:'Claude Code', src:['⌨️','Terminal'], accent:'#d97706', stroke:'#b45309', tools:[['📝','Edit/Write'],['📖','Read'],['⚡','Bash'],['🔍','Grep/Glob'],['🐝','Subagents'],['🧩','MCP']] },
13675
+ codex: { label:'Codex', src:['⌨️','Terminal'], accent:'#10a37f', stroke:'#0d8a6a', tools:[['📝','Apply patch'],['📖','Read'],['⚡','Shell'],['🔍','Search'],['🧩','MCP']] },
13676
+ cursor: { label:'Cursor', src:['🖥️','Editor'], accent:'#6366f1', stroke:'#4f46e5', tools:[['📝','Edit'],['📖','Read'],['⚡','Terminal'],['🔍','Codebase'],['🧩','MCP']] },
13677
+ aider: { label:'Aider', src:['⌨️','Terminal'], accent:'#22a559', stroke:'#1a8045', tools:[['📝','Edit'],['📖','Read'],['⚡','Shell'],['🔀','Git commit']] },
13678
+ goose: { label:'Goose', src:['⌨️','Terminal'], accent:'#0ea5e9', stroke:'#0284c7', tools:[['📝','Edit'],['⚡','Shell'],['🔍','Search'],['🧩','Extensions']] },
13679
+ opencode: { label:'opencode', src:['⌨️','Terminal'], accent:'#f59e0b', stroke:'#d97706', tools:[['📝','Edit'],['📖','Read'],['⚡','Bash'],['🔍','Grep']] },
13680
+ qwen_code: { label:'Qwen Code', src:['⌨️','Terminal'], accent:'#7c3aed', stroke:'#6d28d9', tools:[['📝','Edit'],['📖','Read'],['⚡','Shell'],['🔍','Search']] },
13681
+ picoclaw: { label:'PicoClaw', src:['👤','You'], accent:'#ec4899', stroke:'#db2777', tools:[['⚡','Exec'],['🧠','Memory'],['📋','Sessions']], minimal:true },
13682
+ nanoclaw: { label:'NanoClaw', src:['👤','You'], accent:'#14b8a6', stroke:'#0d9488', tools:[['⚡','Exec'],['🧠','Memory']], minimal:true },
13683
+ };
13684
+
13685
+ function _flowEdge(x1, y1, x2, y2, color, delay) {
13686
+ var mx = (x1 + x2) / 2;
13687
+ var d = 'M' + x1 + ' ' + y1 + ' C ' + mx + ' ' + y1 + ' ' + mx + ' ' + y2 + ' ' + x2 + ' ' + y2;
13688
+ return '<path d="' + d + '" fill="none" stroke="' + color + '" stroke-width="2" stroke-opacity="0.55" stroke-dasharray="6 6">'
13689
+ + '<animate attributeName="stroke-dashoffset" from="24" to="0" dur="1.1s" begin="' + delay + 's" repeatCount="indefinite"/></path>';
13690
+ }
13691
+
13692
+ function _buildRuntimeFlowInner(rt, model) {
13693
+ var s = _RT_FLOW[rt];
13694
+ if (!s) return null;
13695
+ var tools = s.tools, n = tools.length;
13696
+ var th = 40, gap = 14, colX = 715, colW = 160;
13697
+ var totalH = n * th + (n - 1) * gap;
13698
+ var y0 = 275 - totalH / 2;
13699
+ var agentW = 210, agentH = 96, agentCx = 460, agentCy = 275;
13700
+ var agentX = agentCx - agentW / 2, agentY = agentCy - agentH / 2;
13701
+ var srcX = 45, srcY = 247, srcW = 150, srcH = 56, srcCx = srcX + srcW / 2, srcCy = srcY + srcH / 2;
13702
+ var h = '<defs><filter id="rtShadow" x="-20%" y="-20%" width="140%" height="140%"><feDropShadow dx="0" dy="2" stdDeviation="3" flood-opacity="0.35"/></filter></defs>';
13703
+ // Edges first (under nodes): source→agent, agent→each tool.
13704
+ h += _flowEdge(srcX + srcW, srcCy, agentX, agentCy, s.accent, 0);
13705
+ for (var i = 0; i < n; i++) { var ty = y0 + i * (th + gap) + th / 2; h += _flowEdge(agentX + agentW, agentCy, colX, ty, s.accent, 0.12 + i * 0.1); }
13706
+ // Source node.
13707
+ h += '<g class="flow-node"><rect x="' + srcX + '" y="' + srcY + '" width="' + srcW + '" height="' + srcH + '" rx="12" fill="#1e293b" stroke="#334155" stroke-width="2" filter="url(#rtShadow)"/>'
13708
+ + '<text x="' + srcCx + '" y="' + (srcCy - 3) + '" style="font-size:22px;text-anchor:middle;">' + s.src[0] + '</text>'
13709
+ + '<text x="' + srcCx + '" y="' + (srcCy + 19) + '" style="font-size:12px;font-weight:700;fill:#cbd5e1;text-anchor:middle;">' + escHtml(s.src[1]) + '</text></g>';
13710
+ // Agent node (runtime).
13711
+ h += '<g class="flow-node flow-node-brain"><rect x="' + agentX + '" y="' + agentY + '" width="' + agentW + '" height="' + agentH + '" rx="14" fill="' + s.accent + '" stroke="' + s.stroke + '" stroke-width="3" filter="url(#rtShadow)"/>'
13712
+ + '<text x="' + agentCx + '" y="' + (agentY + 31) + '" style="font-size:22px;text-anchor:middle;">🧠</text>'
13713
+ + '<text x="' + agentCx + '" y="' + (agentY + 55) + '" style="font-size:17px;font-weight:800;fill:#fff;text-anchor:middle;">' + escHtml(s.label) + '</text>'
13714
+ + '<text x="' + agentCx + '" y="' + (agentY + 73) + '" style="font-size:10px;fill:rgba(255,255,255,0.85);text-anchor:middle;">' + escHtml(model || (s.minimal ? 'OpenClaw-family' : 'coding agent')) + '</text>'
13715
+ + '<circle cx="' + agentCx + '" cy="' + (agentY + agentH - 9) + '" r="4" fill="#fff"><animate attributeName="opacity" values="0.4;1;0.4" dur="1.4s" repeatCount="indefinite"/></circle></g>';
13716
+ // Tool column (right).
13717
+ for (var j = 0; j < n; j++) { var y = y0 + j * (th + gap), cy = y + th / 2;
13718
+ h += '<g class="flow-node flow-node-tool"><rect x="' + colX + '" y="' + y + '" width="' + colW + '" height="' + th + '" rx="10" fill="#0f172a" stroke="' + s.accent + '" stroke-width="1.6" filter="url(#rtShadow)"/>'
13719
+ + '<text x="' + (colX + colW / 2) + '" y="' + (cy + 1) + '" style="font-size:12px;font-weight:700;fill:#e2e8f0;text-anchor:middle;">' + tools[j][0] + ' ' + escHtml(tools[j][1]) + '</text></g>';
13720
+ }
13721
+ // Workspace sink for coding agents.
13722
+ if (!s.minimal) {
13723
+ var wy = y0 + totalH + 20;
13724
+ h += '<g class="flow-node"><rect x="' + colX + '" y="' + wy + '" width="' + colW + '" height="38" rx="10" fill="#1e293b" stroke="#334155" stroke-width="1.6"/>'
13725
+ + '<text x="' + (colX + colW / 2) + '" y="' + (wy + 23) + '" style="font-size:12px;font-weight:700;fill:#94a3b8;text-anchor:middle;">📂 Workspace</text></g>';
13726
+ }
13727
+ return h;
13728
+ }
13729
+
13730
+ function _applyRuntimeFlowDiagram(rt) {
13731
+ var svg = document.getElementById('flow-svg');
13732
+ if (!svg) return;
13733
+ if (_origFlowSvgInner === null) _origFlowSvgInner = svg.innerHTML;
13734
+ var model = '';
13735
+ try { var ml = document.getElementById('brain-model-text'); model = ml ? (ml.textContent || '') : ''; } catch (e) {}
13736
+ if (model === 'unknown') model = '';
13737
+ var inner = _buildRuntimeFlowInner(rt, model);
13738
+ if (inner) {
13739
+ svg.innerHTML = inner;
13740
+ } else if (svg.innerHTML.indexOf('rtShadow') !== -1) {
13741
+ // Currently showing a generated diagram → restore the original OpenClaw SVG.
13742
+ svg.innerHTML = _origFlowSvgInner;
13743
+ try { hideUnconfiguredChannels(document); } catch (e) {}
13744
+ }
13745
+ // Re-mirror the Overview pane from whatever #flow-svg now holds.
13746
+ try {
13747
+ var c = document.getElementById('overview-flow-container');
13748
+ if (c) { c.innerHTML = ''; if (typeof initOverviewFlow === 'function') initOverviewFlow(); }
13749
+ } catch (e) {}
13644
13750
  }
13645
13751
 
13646
13752
  // Map brain-history event types → Flow's active-tool buckets (exec/browser/
@@ -14589,14 +14695,33 @@ async function loadOverviewTasks() {
14589
14695
  else if (isRealFailure) failed.push(a);
14590
14696
  else done.push(a);
14591
14697
  });
14592
- // Filter old completed/failed (2h)
14593
- done = done.filter(function(a) { return a.runtimeMs < 2 * 60 * 60 * 1000; });
14594
- failed = failed.filter(function(a) { return a.runtimeMs < 2 * 60 * 60 * 1000; });
14698
+ // "Recently Completed/Failed" must mean RECENT — bound by how long ago the
14699
+ // task FINISHED, not its run duration. The old `runtimeMs < 2h` check used
14700
+ // duration, so a 5-minute task that finished 6 days ago still passed and
14701
+ // showed as "recent" (an idle node looked busy). Derive the end time the
14702
+ // same way _ovRenderCard's "Finished N ago" does (completionTs → updatedAt
14703
+ // → startedAt+runtime); unknown end time → not recent.
14704
+ var RECENT_DONE_MS = 60 * 60 * 1000; // 1h
14705
+ var _nowMs = Date.now();
14706
+ function _ovEndedMs(a) {
14707
+ var e = 0;
14708
+ if (a.completionTs) { var ct = Date.parse(a.completionTs); if (!isNaN(ct)) e = ct; }
14709
+ if (!e && a.updatedAt) e = a.updatedAt;
14710
+ if (!e && a.startedAt && a.runtimeMs) e = a.startedAt + a.runtimeMs;
14711
+ return e;
14712
+ }
14713
+ function _ovRecentlyFinished(a) {
14714
+ var e = _ovEndedMs(a);
14715
+ return e > 0 && (_nowMs - e) < RECENT_DONE_MS;
14716
+ }
14717
+ done = done.filter(_ovRecentlyFinished);
14718
+ failed = failed.filter(_ovRecentlyFinished);
14595
14719
 
14596
14720
  if (countBadge) countBadge.textContent = running.length > 0 ? '(' + running.length + ' running)' : '(' + (done.length + failed.length) + ' recent)';
14597
14721
 
14598
14722
  var totalShown = running.length + done.length + failed.length;
14599
14723
  if (totalShown === 0) {
14724
+ if (countBadge) countBadge.textContent = '';
14600
14725
  el.innerHTML = '<div style="text-align:center;padding:40px 20px;color:var(--text-muted);">'
14601
14726
  + '<div style="font-size:32px;margin-bottom:12px;" class="tasks-empty-icon">😴</div>'
14602
14727
  + '<div style="font-size:14px;font-weight:600;color:var(--text-tertiary);margin-bottom:4px;">No active tasks</div>'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clawmetry
3
- Version: 0.12.332
3
+ Version: 0.12.334
4
4
  Summary: ClawMetry - Real-time observability dashboard for OpenClaw AI agents
5
5
  Home-page: https://github.com/vivekchand/clawmetry
6
6
  Author: Vivek Chand
@@ -1,4 +1,4 @@
1
- dashboard.py,sha256=wwqvgbHH--zu33q7EMl8Y1QgBbNB_WWpb84A9kC_Fq8,821494
1
+ dashboard.py,sha256=89ln1GmgehxKOfg2a9M7CoaVEQUwiBZxT7zzcFyQqjg,821494
2
2
  clawmetry/__init__.py,sha256=IxhgASo8kfwL953PqW31XkE5OxNKDKOkVIdMbDTEWBI,929
3
3
  clawmetry/__main__.py,sha256=t0FzM3mA26QcQcycSwQIimmSanw1aR1E4jsHApdUi_w,268
4
4
  clawmetry/alert_evaluator.py,sha256=Ecw8mlEiovuhYotzP6h69LItpEeXmdzgq8Ikg_J6rp8,20426
@@ -54,7 +54,7 @@ clawmetry/resources/add-nemoclaw-clawmetry-preset.sh,sha256=tjV7HY8LAIya_LuUIAHL
54
54
  clawmetry/static/css/dashboard.css,sha256=zljgDilsH3QcVvMcRcxAKWdDxFJCdzuSmU2jOt3TRjg,108373
55
55
  clawmetry/static/img/logo.svg,sha256=_yazPBh2ffmVN-oBCamRBO6n05YwOiRKnNLA_irMhVE,10883
56
56
  clawmetry/static/js/alerts.js,sha256=hunFsaUQbAAZPIBnY3bwen5tUVGeuhPShvY8BvnDH20,33359
57
- clawmetry/static/js/app.js,sha256=XkJEc9T6ya2W9kc174Rdgx_uWZVRoH8r0gqLh1XrfNE,1000272
57
+ clawmetry/static/js/app.js,sha256=MYkwK5LmYR7BqDe4SlAILy4XXTb4GlBq3I79Rl2T6c8,1009589
58
58
  clawmetry/static/js/auth-bootstrap.js,sha256=HkZLqHeEW9QSUNZMUs1gk3A0u-y-Dc97_0iuFkNS3Ak,5131
59
59
  clawmetry/static/js/dives.js,sha256=LFxQhAsu9cDh4VADC1P7A3P0UznZKNXe17BRBGo_8iA,10075
60
60
  clawmetry/static/js/gw-setup.js,sha256=vJXU1fS8JuWgEl0OaFV7aVuBahYKbNbTjSoakwI03ns,8506
@@ -141,7 +141,7 @@ clawmetry/tests/integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMp
141
141
  clawmetry/tests/integration/test_fast_paths_cross_process.py,sha256=9L9p5_gzQ1rZI3GV0F_pGD2GIF1JAAhwpGq55uGfdus,15299
142
142
  clawmetry/v2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
143
143
  clawmetry/v2/routes.py,sha256=V0NGbWudBK0MIdl56m3PYwWZDrUClEZR4OZs4_rQJmc,18029
144
- clawmetry-0.12.332.dist-info/licenses/LICENSE,sha256=zdQBHvfCz4k8T_ib6mtyWYbQXGtD-g8Ih3t20sax_xE,1068
144
+ clawmetry-0.12.334.dist-info/licenses/LICENSE,sha256=zdQBHvfCz4k8T_ib6mtyWYbQXGtD-g8Ih3t20sax_xE,1068
145
145
  helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
146
146
  helpers/gateway.py,sha256=9QAqXRrdQlTypA2qAXSegz4VguwM0vK1irtdCh62OCs,8569
147
147
  helpers/hardware.py,sha256=PmYDyrhsmE9rz6KL_0ktKZNMCWtG7CjP55RVYpnREg8,3675
@@ -429,8 +429,8 @@ tests/test_v3_schema_parser.py,sha256=iHpxmvpdJWlPZKpUnvjMz1Mcwml_9q0cEAExhs1lRb
429
429
  tests/test_version_impact.py,sha256=x_Zmd7eD7wYrDdpMTF_y24dmRtXB8tYR5huSD8-IZCg,3039
430
430
  tests/test_version_impact_local_store_v3.py,sha256=bmX4M8AKMRws6HBiWoOwtvIc5MXsPj22hyWAtCQBK14,12034
431
431
  tests/test_workspace_switcher_copy.py,sha256=XUDkQ7BZIIXLfpvzzzfaRzWOyGs2E8dVOPLmAPrKErI,1708
432
- clawmetry-0.12.332.dist-info/METADATA,sha256=kDE9ZqZyI_75SmamLOe031yJhBpQJOV-4cZUmIXioiM,18547
433
- clawmetry-0.12.332.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
434
- clawmetry-0.12.332.dist-info/entry_points.txt,sha256=RdRaoQJOKNChZUlJV3qqHRTa_PXGjskOCDgUXEp6XR0,49
435
- clawmetry-0.12.332.dist-info/top_level.txt,sha256=uBMYWHIWh_Jg_0SlFoFh3SZH0zr0AJ8nmneynwHhgDA,41
436
- clawmetry-0.12.332.dist-info/RECORD,,
432
+ clawmetry-0.12.334.dist-info/METADATA,sha256=C-QkY1yn2_N36-38J8dOgbXRxXlbcncYL7Nvqwm0VzY,18547
433
+ clawmetry-0.12.334.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
434
+ clawmetry-0.12.334.dist-info/entry_points.txt,sha256=RdRaoQJOKNChZUlJV3qqHRTa_PXGjskOCDgUXEp6XR0,49
435
+ clawmetry-0.12.334.dist-info/top_level.txt,sha256=uBMYWHIWh_Jg_0SlFoFh3SZH0zr0AJ8nmneynwHhgDA,41
436
+ clawmetry-0.12.334.dist-info/RECORD,,
dashboard.py CHANGED
@@ -153,7 +153,7 @@ except ImportError:
153
153
  metrics_service_pb2 = None
154
154
  trace_service_pb2 = None
155
155
 
156
- __version__ = "0.12.332"
156
+ __version__ = "0.12.334"
157
157
 
158
158
  # Extensions (Phase 2) — load plugins at import time; safe no-op if package not installed
159
159
  try: