@axiomatic-labs/claudeflow 2.13.67 → 2.13.69

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 (2) hide show
  1. package/lib/panel.js +73 -6
  2. package/package.json +1 -1
package/lib/panel.js CHANGED
@@ -1031,6 +1031,13 @@ function row(k, v, badge) {
1031
1031
  return \`<div class="card-row"><span class="k">\${escapeHtml(k)}</span><span class="v">\${b}\${escapeHtml(v)}</span></div>\`;
1032
1032
  }
1033
1033
 
1034
+ // Same as row() but the value is rendered as raw HTML (caller is responsible
1035
+ // for escaping). Use for values that already contain HTML markup (e.g. <code>).
1036
+ function rowHtml(k, vHtml, badge) {
1037
+ const b = badge ? \`<span class="badge \${badge.kind}">\${escapeHtml(badge.text)}</span>\` : '';
1038
+ return \`<div class="card-row"><span class="k">\${escapeHtml(k)}</span><span class="v">\${b}\${vHtml}</span></div>\`;
1039
+ }
1040
+
1034
1041
  function escapeHtml(s) {
1035
1042
  return String(s == null ? '' : s)
1036
1043
  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
@@ -1461,10 +1468,10 @@ function renderObserver() {
1461
1468
  // Browser section
1462
1469
  const browserBlock = o.browser && o.browser.last_snapshot_at
1463
1470
  ? \`<div class="card" style="padding:10px 14px;font-size:13px;">
1464
- \${row('Latest URL', o.browser.latest_url ? '<code>' + escapeHtml(o.browser.latest_url) + '</code>' : '<span class="muted">none</span>')}
1465
- \${row('Latest route', o.browser.latest_route ? '<code>' + escapeHtml(o.browser.latest_route) + '</code>' : '<span class="muted">none</span>')}
1466
- \${row('Snapshots received', String(o.browser.snapshots_received))}
1467
- \${row('Last snapshot', formatRelativeTime(o.browser.last_snapshot_at))}
1471
+ \${rowHtml('Latest URL', o.browser.latest_url ? '<code>' + escapeHtml(o.browser.latest_url) + '</code>' : '<span class="muted">none</span>')}
1472
+ \${rowHtml('Latest route', o.browser.latest_route ? '<code>' + escapeHtml(o.browser.latest_route) + '</code>' : '<span class="muted">none</span>')}
1473
+ \${rowHtml('Snapshots received', String(o.browser.snapshots_received))}
1474
+ \${rowHtml('Last snapshot', escapeHtml(formatRelativeTime(o.browser.last_snapshot_at)))}
1468
1475
  </div>\`
1469
1476
  : '<p class="muted">No browser snapshots received yet. (The observer collects when the agent navigates with mcp__claude-in-chrome__*.)</p>';
1470
1477
 
@@ -1518,6 +1525,33 @@ function renderObserver() {
1518
1525
  showResolvedPill +
1519
1526
  '</div>';
1520
1527
 
1528
+ // Match file:line patterns in stack traces (most common formats):
1529
+ // http://localhost:3001/src/foo.tsx:51:22
1530
+ // /Users/abs/path.ts:42
1531
+ // at SomeFn (path:line:col)
1532
+ function extractFileLineHints(text) {
1533
+ if (typeof text !== 'string') return [];
1534
+ const hints = new Set();
1535
+ // localhost source URLs (Vite/CRA dev server)
1536
+ const localRe = /https?:\\/\\/localhost(?::\\d+)?\\/([^\\s:]+?\\.(?:tsx?|jsx?|vue|svelte)):(\\d+)(?::(\\d+))?/g;
1537
+ let m;
1538
+ while ((m = localRe.exec(text)) !== null) {
1539
+ hints.add(\`\${m[1]}:\${m[2]}\${m[3] ? ':' + m[3] : ''}\`);
1540
+ if (hints.size >= 6) break;
1541
+ }
1542
+ // Bare absolute paths
1543
+ const absRe = /\\b(\\/[A-Za-z0-9_./-]+?\\.(?:tsx?|jsx?|vue|svelte)):(\\d+)(?::(\\d+))?/g;
1544
+ while ((m = absRe.exec(text)) !== null) {
1545
+ hints.add(\`\${m[1]}:\${m[2]}\${m[3] ? ':' + m[3] : ''}\`);
1546
+ if (hints.size >= 6) break;
1547
+ }
1548
+ return [...hints];
1549
+ }
1550
+
1551
+ // Server-side detail (recent_log + exit info) lookup per surface label.
1552
+ const serverByLabel = {};
1553
+ o.servers.forEach((srv) => { serverByLabel[srv.label] = srv; });
1554
+
1521
1555
  // Incidents feed
1522
1556
  const incidentsBlock = filteredIncidents.length === 0
1523
1557
  ? '<p class="muted">No incidents in this filter.</p>'
@@ -1530,6 +1564,36 @@ function renderObserver() {
1530
1564
  const surfaceLabel = inc.source === 'server' && inc.metadata && inc.metadata.label
1531
1565
  ? inc.metadata.label
1532
1566
  : inc.surface || inc.source;
1567
+ const fullMsg = inc.message || '';
1568
+ const fileLineHints = extractFileLineHints(fullMsg);
1569
+ // Show first 240 chars by default, collapsible to full message.
1570
+ const PREVIEW_CHARS = 240;
1571
+ const isLong = fullMsg.length > PREVIEW_CHARS;
1572
+ const previewMsg = isLong ? fullMsg.slice(0, PREVIEW_CHARS) + '…' : fullMsg;
1573
+ const fullBlock = isLong
1574
+ ? '<details style="margin-top:4px;"><summary style="cursor:pointer;color:var(--muted);font-size:11px;">Show full message + stack (' + fullMsg.length + ' chars)</summary><pre style="font-size:11px;white-space:pre-wrap;background:var(--panel-2);padding:8px;border-radius:4px;margin:4px 0 0 0;overflow:auto;max-height:400px;">' + escapeHtml(fullMsg) + '</pre></details>'
1575
+ : '';
1576
+ const fileLinesHtml = fileLineHints.length > 0
1577
+ ? '<div class="muted" style="font-size:11px;margin-top:4px;">📄 ' + fileLineHints.map((f) => '<code>' + escapeHtml(f) + '</code>').join(' • ') + '</div>'
1578
+ : '';
1579
+ const urlLine = inc.metadata && inc.metadata.url
1580
+ ? '<div class="muted" style="font-size:11px;margin-top:4px;">🌐 <code>' + escapeHtml(inc.metadata.url) + '</code>' + (inc.metadata.route && inc.metadata.route !== inc.metadata.url ? ' (' + escapeHtml(inc.metadata.route) + ')' : '') + '</div>'
1581
+ : '';
1582
+ // For server incidents, attach recent_log + exit info from the matching server record.
1583
+ let serverDetail = '';
1584
+ if (inc.source === 'server') {
1585
+ const srv = serverByLabel[surfaceLabel];
1586
+ if (srv) {
1587
+ const exitInfo = srv.last_exit_code !== null && srv.last_exit_code !== undefined
1588
+ ? \`<div class="muted" style="font-size:11px;margin-top:4px;">🛑 last exit: code \${srv.last_exit_code}\${srv.last_exit_signal ? ' / signal ' + srv.last_exit_signal : ''} at \${escapeHtml(formatRelativeTime(srv.last_exit_at))}</div>\`
1589
+ : '';
1590
+ const logLines = Array.isArray(srv.recent_log) ? srv.recent_log : [];
1591
+ const logBlock = logLines.length > 0
1592
+ ? '<details style="margin-top:4px;"><summary style="cursor:pointer;color:var(--muted);font-size:11px;">📋 recent_log (' + logLines.length + ' lines from daemon-supervised stdout/stderr)</summary><pre style="font-size:11px;white-space:pre-wrap;background:var(--panel-2);padding:8px;border-radius:4px;margin:4px 0 0 0;overflow:auto;max-height:300px;">' + logLines.slice(-50).map((l) => escapeHtml(typeof l === 'string' ? l : (l.line || JSON.stringify(l)))).join('\\n') + '</pre></details>'
1593
+ : '<div class="muted" style="font-size:11px;margin-top:4px;">📋 No recent_log captured (server is observed_external — daemon only port-probes it, doesn\\'t pipe stdout/stderr). Run the server under the daemon supervisor to capture log lines, or check the dev server\\'s own terminal output.</div>';
1594
+ serverDetail = exitInfo + logBlock;
1595
+ }
1596
+ }
1533
1597
  return \`<div class="incident-row" style="padding:10px 14px;border-top:1px solid var(--border);">
1534
1598
  <div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:4px;">
1535
1599
  <span class="badge \${sevClass}">\${escapeHtml(inc.severity || 'info')}</span>
@@ -1540,8 +1604,11 @@ function renderObserver() {
1540
1604
  \${resolvedBadge}
1541
1605
  <span class="muted" style="margin-left:auto;font-size:11px;">\${escapeHtml(formatRelativeTime(inc.last_seen_at))}</span>
1542
1606
  </div>
1543
- <div style="font-size:12px;white-space:pre-wrap;">\${escapeHtml((inc.message || '').slice(0, 600))}\${(inc.message || '').length > 600 ? '…' : ''}</div>
1544
- \${inc.metadata && inc.metadata.url ? '<div class="muted" style="font-size:11px;margin-top:4px;">at <code>' + escapeHtml(inc.metadata.url) + '</code></div>' : ''}
1607
+ <div style="font-size:12px;white-space:pre-wrap;">\${escapeHtml(previewMsg)}</div>
1608
+ \${fullBlock}
1609
+ \${fileLinesHtml}
1610
+ \${urlLine}
1611
+ \${serverDetail}
1545
1612
  </div>\`;
1546
1613
  }).join('') +
1547
1614
  '</div>';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axiomatic-labs/claudeflow",
3
- "version": "2.13.67",
3
+ "version": "2.13.69",
4
4
  "description": "Claudeflow — AI-powered development toolkit for Claude Code. Skills, agents, hooks, and quality gates that ship production apps.",
5
5
  "bin": {
6
6
  "claudeflow": "./bin/cli.js"