viberadar 0.3.61 → 0.3.62

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.
@@ -809,6 +809,12 @@
809
809
  border-radius: 4px;
810
810
  }
811
811
  .agent-toolbar-btn:hover { color: var(--text); border-color: var(--blue); }
812
+ .agent-toolbar-btn:disabled {
813
+ opacity: 0.45;
814
+ cursor: not-allowed;
815
+ border-color: var(--border);
816
+ color: var(--dim);
817
+ }
812
818
  .agent-toolbar-meta { font-size: 11px; color: var(--dim); margin-left: auto; }
813
819
  .agent-queue-panel {
814
820
  display: none;
@@ -1123,13 +1129,13 @@
1123
1129
  <label><input id="agentSearchErrorsOnly" type="checkbox" /> only errors</label>
1124
1130
  <label><input id="agentSearchCurrentRunOnly" type="checkbox" /> current run</label>
1125
1131
  <label><input id="agentSearchRegex" type="checkbox" /> regex</label>
1126
- <button class="agent-toolbar-btn" onclick="jumpTerminalMatch(-1)">↑ match</button>
1127
- <button class="agent-toolbar-btn" onclick="jumpTerminalMatch(1)">↓ match</button>
1128
- <button class="agent-toolbar-btn" onclick="jumpCommand(-1)">↑ command</button>
1129
- <button class="agent-toolbar-btn" onclick="jumpCommand(1)">↓ command</button>
1130
- <button class="agent-toolbar-btn" onclick="jumpError(-1)">↑ error</button>
1131
- <button class="agent-toolbar-btn" onclick="jumpError(1)">↓ error</button>
1132
- <button class="agent-toolbar-btn" onclick="exportActiveRun()">Export run</button>
1132
+ <button class="agent-toolbar-btn" id="btnMatchPrev" onclick="jumpTerminalMatch(-1)">↑ match</button>
1133
+ <button class="agent-toolbar-btn" id="btnMatchNext" onclick="jumpTerminalMatch(1)">↓ match</button>
1134
+ <button class="agent-toolbar-btn" id="btnCmdPrev" onclick="jumpCommand(-1)">↑ command</button>
1135
+ <button class="agent-toolbar-btn" id="btnCmdNext" onclick="jumpCommand(1)">↓ command</button>
1136
+ <button class="agent-toolbar-btn" id="btnErrPrev" onclick="jumpError(-1)">↑ error</button>
1137
+ <button class="agent-toolbar-btn" id="btnErrNext" onclick="jumpError(1)">↓ error</button>
1138
+ <button class="agent-toolbar-btn" id="btnExportRun" onclick="exportActiveRun()">Export run</button>
1133
1139
  <span class="agent-toolbar-meta" id="agentSearchMeta">0 matches</span>
1134
1140
  </div>
1135
1141
  <div class="agent-queue-panel" id="agentQueuePanel"></div>
@@ -1443,10 +1449,11 @@ function switchSession(id) {
1443
1449
  : '';
1444
1450
  document.getElementById('agentPanelTitle').textContent = s.title;
1445
1451
  document.getElementById('agentPanelStatus').textContent = statusText;
1446
- }
1447
- renderTabs();
1448
- renderActiveSession();
1449
- }
1452
+ }
1453
+ renderTabs();
1454
+ renderActiveSession();
1455
+ syncSummaryForActiveSession();
1456
+ }
1450
1457
 
1451
1458
  function closeSession(id) {
1452
1459
  const idx = consoleSessions.findIndex(s => s.id === id);
@@ -1462,10 +1469,11 @@ function closeSession(id) {
1462
1469
  ? consoleSessions[Math.min(idx, consoleSessions.length - 1)].id
1463
1470
  : null;
1464
1471
  }
1465
- renderTabs();
1466
- renderActiveSession();
1467
- saveSessions();
1468
- }
1472
+ renderTabs();
1473
+ renderActiveSession();
1474
+ syncSummaryForActiveSession();
1475
+ saveSessions();
1476
+ }
1469
1477
 
1470
1478
  function appendToSession(id, lineOrNode, isError = false, isDim = false) {
1471
1479
  const s = consoleSessions.find(s => s.id === id);
@@ -1553,13 +1561,16 @@ function getActiveRunForExport() {
1553
1561
  const fromState = (agentRunsState || []).find((r) => r.runId === runId);
1554
1562
  if (fromState) return fromState;
1555
1563
  }
1556
- return lastRunSummary || null;
1564
+ return null;
1557
1565
  }
1558
1566
 
1559
1567
  function exportActiveRun() {
1560
1568
  const run = getActiveRunForExport();
1561
1569
  const session = consoleSessions.find((s) => s.id === activeSessionId);
1562
- if (!run && !session) return;
1570
+ if (!run && !session) {
1571
+ flashToolbarHint('Нечего экспортировать');
1572
+ return;
1573
+ }
1563
1574
  const mode = window.prompt('Формат экспорта: md или json', 'md');
1564
1575
  const format = (mode || 'md').trim().toLowerCase() === 'json' ? 'json' : 'md';
1565
1576
  const ts = new Date().toISOString().replace(/[:.]/g, '-');
@@ -1618,6 +1629,7 @@ function renderActiveSession() {
1618
1629
  const s = consoleSessions.find(s => s.id === activeSessionId);
1619
1630
  if (!s) {
1620
1631
  document.getElementById('agentSearchMeta').textContent = '0 matches';
1632
+ updateToolbarButtonsState();
1621
1633
  return;
1622
1634
  }
1623
1635
  const normalizedQuery = (terminalSearchQuery || '').trim();
@@ -1660,6 +1672,37 @@ function renderActiveSession() {
1660
1672
  term.scrollTop = term.scrollHeight;
1661
1673
  document.getElementById('agentSearchMeta').textContent =
1662
1674
  `${terminalMatchRefs.length} matches • ${terminalCommandRefs.length} commands • ${terminalErrorRefs.length} errors`;
1675
+ updateToolbarButtonsState();
1676
+ }
1677
+
1678
+ function updateToolbarButtonsState() {
1679
+ const setState = (id, enabled) => {
1680
+ const el = document.getElementById(id);
1681
+ if (!el) return;
1682
+ el.disabled = !enabled;
1683
+ };
1684
+ setState('btnMatchPrev', terminalMatchRefs.length > 0);
1685
+ setState('btnMatchNext', terminalMatchRefs.length > 0);
1686
+ setState('btnCmdPrev', terminalCommandRefs.length > 0);
1687
+ setState('btnCmdNext', terminalCommandRefs.length > 0);
1688
+ setState('btnErrPrev', terminalErrorRefs.length > 0);
1689
+ setState('btnErrNext', terminalErrorRefs.length > 0);
1690
+ const hasExport = !!getActiveRunForExport() || !!consoleSessions.find((s) => s.id === activeSessionId);
1691
+ setState('btnExportRun', hasExport);
1692
+ }
1693
+
1694
+ function flashToolbarHint(text) {
1695
+ const meta = document.getElementById('agentSearchMeta');
1696
+ if (!meta) return;
1697
+ const previous = meta.textContent;
1698
+ meta.textContent = text;
1699
+ meta.style.color = 'var(--yellow)';
1700
+ setTimeout(() => {
1701
+ meta.style.color = '';
1702
+ if (meta.textContent === text) {
1703
+ meta.textContent = previous || '0 matches';
1704
+ }
1705
+ }, 1400);
1663
1706
  }
1664
1707
 
1665
1708
  function extractLineText(line) {
@@ -1674,7 +1717,11 @@ function extractLineText(line) {
1674
1717
  }
1675
1718
 
1676
1719
  function jumpByRefs(refs, dir, cursorName) {
1677
- if (!refs.length) return;
1720
+ if (!refs.length) {
1721
+ const label = cursorName === 'match' ? 'совпадений' : cursorName === 'command' ? 'команд' : 'ошибок';
1722
+ flashToolbarHint(`Нет ${label} для навигации`);
1723
+ return;
1724
+ }
1678
1725
  if (cursorName === 'match') {
1679
1726
  terminalMatchCursor = (terminalMatchCursor + dir + refs.length) % refs.length;
1680
1727
  refs[terminalMatchCursor].scrollIntoView({ block: 'center', behavior: 'smooth' });
@@ -1807,6 +1854,17 @@ function renderRunSummaryMatrix(summary = lastRunSummary) {
1807
1854
  `;
1808
1855
  }
1809
1856
 
1857
+ function findSummaryForRun(runId) {
1858
+ if (!runId) return null;
1859
+ return (agentRunsState || []).find((r) => r.runId === runId && Array.isArray(r.fileOutcomes) && r.fileOutcomes.length > 0) || null;
1860
+ }
1861
+
1862
+ function syncSummaryForActiveSession() {
1863
+ const runId = sessionRunMap.get(activeSessionId) || currentRunId;
1864
+ const summary = findSummaryForRun(runId) || null;
1865
+ renderRunSummaryMatrix(summary);
1866
+ }
1867
+
1810
1868
  async function cancelQueueItem(runId) {
1811
1869
  await fetch(`/api/queue/${encodeURIComponent(runId)}/cancel`, { method: 'POST' });
1812
1870
  await loadAgentState();
@@ -1857,8 +1915,8 @@ function applyAgentStateSnapshot(state) {
1857
1915
  const latestSummary = [...agentRunsState].reverse().find((r) => Array.isArray(r.fileOutcomes) && r.fileOutcomes.length > 0);
1858
1916
  if (latestSummary) {
1859
1917
  lastRunSummary = latestSummary;
1860
- renderRunSummaryMatrix(latestSummary);
1861
1918
  }
1919
+ syncSummaryForActiveSession();
1862
1920
  }
1863
1921
 
1864
1922
  async function loadAgentState() {
@@ -1911,6 +1969,7 @@ function updateSessionFromRun(run) {
1911
1969
  if (currentRunId === run.runId) currentRunId = null;
1912
1970
  setAgentRunning(false);
1913
1971
  }
1972
+ syncSummaryForActiveSession();
1914
1973
  }
1915
1974
 
1916
1975
  function refreshPathActivityFromState() {
@@ -3652,8 +3711,8 @@ function connectSSE() {
3652
3711
  updateSessionFromRun(run);
3653
3712
  if (Array.isArray(run.fileOutcomes) && run.fileOutcomes.length > 0) {
3654
3713
  lastRunSummary = run;
3655
- renderRunSummaryMatrix(run);
3656
3714
  }
3715
+ syncSummaryForActiveSession();
3657
3716
  refreshPathActivityFromState();
3658
3717
  renderContent();
3659
3718
  });
@@ -3763,8 +3822,8 @@ function connectSSE() {
3763
3822
  `;
3764
3823
  if (fileOutcomes.length > 0) {
3765
3824
  lastRunSummary = { runId, fileOutcomes, validationStats };
3766
- renderRunSummaryMatrix(lastRunSummary);
3767
3825
  }
3826
+ syncSummaryForActiveSession();
3768
3827
  const targetId = runId ? (runSessionMap.get(runId) || runningSessionId || activeSessionId) : (runningSessionId || activeSessionId);
3769
3828
  if (targetId) {
3770
3829
  appendToSession(targetId, box);
@@ -3895,6 +3954,7 @@ init().then(async () => {
3895
3954
  await loadAgentState();
3896
3955
  connectSSE();
3897
3956
  applyTerminalFiltersFromUi();
3957
+ updateToolbarButtonsState();
3898
3958
  // Sync content padding with terminal panel open state automatically
3899
3959
  new MutationObserver(() => {
3900
3960
  const isOpen = document.getElementById('agentPanel').classList.contains('open');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viberadar",
3
- "version": "0.3.61",
3
+ "version": "0.3.62",
4
4
  "description": "Live module map with test coverage for vibecoding projects",
5
5
  "main": "./dist/cli.js",
6
6
  "bin": {