viberadar 0.3.43 → 0.3.45

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.
@@ -482,56 +482,49 @@
482
482
 
483
483
  /* ── Test-type cards inside feature detail ───────────────────────────────── */
484
484
  .test-type-grid {
485
- display: flex;
486
- gap: 8px;
487
- margin-bottom: 14px;
488
- flex-wrap: wrap;
489
- align-items: center;
485
+ display: grid;
486
+ grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
487
+ gap: 10px;
488
+ margin-bottom: 18px;
490
489
  }
491
490
  .test-type-card {
492
491
  display: flex;
493
- align-items: center;
494
- gap: 8px;
492
+ flex-direction: column;
495
493
  background: var(--bg-card);
496
494
  border: 1px solid var(--border);
497
- border-left: 3px solid transparent;
495
+ border-top: 3px solid transparent;
498
496
  border-radius: 8px;
499
- padding: 7px 12px;
497
+ padding: 12px 14px 10px;
500
498
  cursor: pointer;
501
499
  transition: background 0.15s, border-color 0.15s;
502
- flex-shrink: 0;
500
+ min-width: 0;
503
501
  }
504
502
  .test-type-card:hover { background: var(--bg-hover); }
505
- .test-type-card .tt-accent { display: none; } /* replaced by border-left */
506
- .test-type-card .tt-label {
507
- font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px;
508
- color: var(--muted); white-space: nowrap;
509
- }
510
- .test-type-card .tt-count {
511
- font-size: 18px; font-weight: 700; line-height: 1;
512
- }
513
- .test-type-card .tt-sub {
514
- font-size: 11px; color: var(--dim); white-space: nowrap;
515
- }
516
- .test-type-card.tt-empty { opacity: 0.65; }
517
- .test-type-card.tt-active { background: var(--bg-hover); }
503
+ .test-type-card.tt-active { background: var(--bg-hover); border-color: var(--border); }
504
+ .test-type-card.tt-empty { opacity: 0.6; }
518
505
  .test-type-card.tt-failed {
519
506
  border-color: var(--red) !important;
520
- background: rgba(248, 81, 73, 0.06);
521
- }
522
- .tt-chip-actions { display: flex; gap: 4px; margin-left: 4px; }
507
+ background: rgba(248, 81, 73, 0.05);
508
+ }
509
+ .tt-card-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
510
+ .tt-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--muted); }
511
+ .tt-failed-badge { font-size: 10px; color: var(--red); font-weight: 700; }
512
+ .tt-count { font-size: 28px; font-weight: 700; line-height: 1; margin-bottom: 2px; }
513
+ .tt-sub { font-size: 11px; color: var(--dim); }
514
+ .tt-card-actions { display: flex; flex-direction: column; gap: 5px; margin-top: 10px; }
523
515
  .tt-run-btn {
524
- display: inline-block; margin: 0;
525
- padding: 3px 9px;
516
+ width: 100%; padding: 5px 10px;
526
517
  background: transparent; border: 1px solid var(--border);
527
- border-radius: 4px; color: var(--muted); font-size: 10px;
528
- cursor: pointer; white-space: nowrap;
518
+ border-radius: 5px; color: var(--muted); font-size: 11px;
519
+ cursor: pointer; text-align: center;
529
520
  transition: background 0.1s, color 0.1s, border-color 0.1s;
530
521
  }
531
522
  .tt-run-btn:hover { background: var(--bg-hover); color: var(--text); border-color: var(--dim); }
532
523
  .tt-run-btn:disabled { opacity: 0.4; cursor: not-allowed; }
533
524
  .tt-fix-btn { border-color: var(--yellow); color: var(--yellow); font-weight: 600; }
534
525
  .tt-fix-btn:hover { background: rgba(255,200,0,0.1); color: var(--yellow); border-color: var(--yellow); }
526
+ .tt-write-btn { border-color: var(--accent); color: var(--accent); }
527
+ .tt-write-btn:hover { background: rgba(88,166,255,0.1); color: var(--accent); border-color: var(--accent); }
535
528
  .file-rows { display: flex; flex-direction: column; gap: 2px; }
536
529
  .file-row {
537
530
  display: flex;
@@ -668,6 +661,12 @@
668
661
  font-size: 14px; padding: 3px 6px; border-radius: 4px; line-height: 1;
669
662
  }
670
663
  .agent-panel-close:hover { background: var(--border); color: var(--text); }
664
+ .agent-panel-copy {
665
+ background: none; border: none; color: var(--dim); cursor: pointer;
666
+ font-size: 13px; padding: 3px 7px; border-radius: 4px; line-height: 1;
667
+ }
668
+ .agent-panel-copy:hover { background: var(--border); color: var(--text); }
669
+ .agent-panel-copy.copied { color: var(--green); }
671
670
  .agent-panel-cancel {
672
671
  background: none; border: 1px solid var(--yellow); color: var(--yellow);
673
672
  cursor: pointer; font-size: 11px; padding: 2px 8px; border-radius: 4px;
@@ -818,6 +817,7 @@
818
817
  <span class="agent-queue-badge" id="agentQueueBadge" style="display:none">📋 <span id="agentQueueCount">0</span> в очереди</span>
819
818
  <button class="agent-panel-cancel" id="agentQueueClearBtn" onclick="clearAgentQueue()" title="Очистить очередь" style="display:none">🗑 очередь</button>
820
819
  <button class="agent-panel-cancel" id="agentCancelBtn" onclick="cancelAgent()" title="Сбросить состояние агента" style="display:none">⏹ сброс</button>
820
+ <button class="agent-panel-copy" id="agentCopyBtn" onclick="copyTerminalContent()" title="Скопировать содержимое вкладки в буфер обмена">⎘</button>
821
821
  <button class="agent-panel-close" onclick="closeAgentPanel()">✕</button>
822
822
  </div>
823
823
  <div class="agent-tabs-bar" id="agentTabsBar"></div>
@@ -984,7 +984,9 @@ function renderTabs() {
984
984
  bar.innerHTML = consoleSessions.map(s => {
985
985
  const isActive = s.id === activeSessionId;
986
986
  const safe = s.title.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
987
- return `<div class="agent-tab${isActive ? ' active' : ''}" onclick="switchSession('${s.id}')">
987
+ return `<div class="agent-tab${isActive ? ' active' : ''}"
988
+ onclick="switchSession('${s.id}')"
989
+ onmousedown="if(event.button===1){event.preventDefault();event.stopPropagation();closeSession('${s.id}')}">
988
990
  <span class="tab-dot tab-dot-${s.status}"></span>
989
991
  <span class="agent-tab-title" title="${safe}">${safe}</span>
990
992
  <button class="agent-tab-close" onclick="event.stopPropagation();closeSession('${s.id}')" title="Закрыть вкладку">×</button>
@@ -994,6 +996,29 @@ function renderTabs() {
994
996
  if (active) active.scrollIntoView({ block: 'nearest', inline: 'nearest' });
995
997
  }
996
998
 
999
+ function copyTerminalContent() {
1000
+ const s = consoleSessions.find(s => s.id === activeSessionId);
1001
+ if (!s || s.lines.length === 0) return;
1002
+ // Extract plain text from each line (strip HTML for rich nodes)
1003
+ const text = s.lines.map(l => {
1004
+ if (l.text !== undefined) return l.text;
1005
+ if (l.html) {
1006
+ const tmp = document.createElement('div');
1007
+ tmp.innerHTML = l.html;
1008
+ return tmp.innerText;
1009
+ }
1010
+ return '';
1011
+ }).filter(Boolean).join('\n');
1012
+ navigator.clipboard.writeText(text).then(() => {
1013
+ const btn = document.getElementById('agentCopyBtn');
1014
+ if (!btn) return;
1015
+ const prev = btn.textContent;
1016
+ btn.textContent = '✓';
1017
+ btn.classList.add('copied');
1018
+ setTimeout(() => { btn.textContent = prev; btn.classList.remove('copied'); }, 1500);
1019
+ });
1020
+ }
1021
+
997
1022
  function renderActiveSession() {
998
1023
  const term = document.getElementById('agentTerminal');
999
1024
  if (!term) return;
@@ -1533,30 +1558,38 @@ function renderFeatureCards(c) {
1533
1558
  }
1534
1559
 
1535
1560
  function testTypeCard(type, label, icon, color, count, active, featureKey, failedCount = 0) {
1536
- const empty = count === 0 && type !== 'source';
1561
+ const empty = count === 0 && type !== 'source';
1537
1562
  const hasFailed = failedCount > 0 && type !== 'source';
1538
- const subLabel = type === 'source' ? 'файлов' : (empty ? 'нет тестов' : pluralFiles(count));
1563
+ const subLabel = type === 'source' ? 'файлов' : (empty ? 'нет тестов' : pluralFiles(count));
1539
1564
  const accentColor = hasFailed ? 'var(--red)' : color;
1540
1565
  const countColor = hasFailed ? 'var(--red)' : (active || !empty ? color : 'var(--dim)');
1541
1566
 
1567
+ const failedBadge = hasFailed
1568
+ ? `<span class="tt-failed-badge">❌ ${failedCount}</span>`
1569
+ : '';
1570
+
1542
1571
  const runBtn = !empty && type !== 'source' && featureKey
1543
- ? `<button class="tt-run-btn" onclick="event.stopPropagation();runTests('${featureKey}','${type}')">▶ запустить</button>`
1572
+ ? `<button class="tt-run-btn" onclick="event.stopPropagation();runTests('${featureKey}','${type}')">▶ запустить тесты</button>`
1544
1573
  : '';
1545
1574
  const fixAllBtn = hasFailed && D.agent && featureKey
1546
- ? `<button class="tt-run-btn tt-fix-btn" onclick="event.stopPropagation();runAgentTask('fix-tests-all','${featureKey}','${type}')">🔧 починить</button>`
1575
+ ? `<button class="tt-run-btn tt-fix-btn" onclick="event.stopPropagation();runAgentTask('fix-tests-all','${featureKey}','${type}')">🔧 починить все</button>`
1547
1576
  : '';
1548
- const failedBadge = hasFailed
1549
- ? `<span style="font-size:10px;color:var(--red);font-weight:700;white-space:nowrap">❌ ${failedCount}</span>`
1577
+ const writeBtn = type !== 'source' && D.agent && featureKey
1578
+ ? `<button class="tt-run-btn tt-write-btn" onclick="event.stopPropagation();runAgentTask('write-tests','${featureKey}')">✍ написать тесты</button>`
1579
+ : '';
1580
+ const actions = (runBtn || fixAllBtn || writeBtn)
1581
+ ? `<div class="tt-card-actions">${runBtn}${fixAllBtn}${writeBtn}</div>`
1550
1582
  : '';
1551
- const actions = (runBtn || fixAllBtn) ? `<div class="tt-chip-actions">${runBtn}${fixAllBtn}</div>` : '';
1552
1583
 
1553
1584
  return `
1554
1585
  <div class="test-type-card${empty ? ' tt-empty' : ''}${active ? ' tt-active' : ''}${hasFailed ? ' tt-failed' : ''}"
1555
- data-testtype="${type}" style="border-left-color:${accentColor}${active ? ';border-color:' + color : ''}">
1556
- <span class="tt-label">${icon} ${label}</span>
1586
+ data-testtype="${type}" style="border-top-color:${accentColor}">
1587
+ <div class="tt-card-header">
1588
+ <span class="tt-label">${icon} ${label}</span>
1589
+ ${failedBadge}
1590
+ </div>
1557
1591
  <span class="tt-count" style="color:${countColor}">${count}</span>
1558
1592
  <span class="tt-sub">${subLabel}</span>
1559
- ${failedBadge}
1560
1593
  ${actions}
1561
1594
  </div>`;
1562
1595
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viberadar",
3
- "version": "0.3.43",
3
+ "version": "0.3.45",
4
4
  "description": "Live module map with test coverage for vibecoding projects",
5
5
  "main": "./dist/cli.js",
6
6
  "bin": {