viberadar 0.3.2 → 0.3.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.
@@ -569,6 +569,37 @@ function renderFeatureCards(c) {
569
569
  card.onclick = () => openFeaturePanel(f.key);
570
570
  grid.appendChild(card);
571
571
  });
572
+
573
+ // ── Unmapped card ──────────────────────────────────────────────────────────
574
+ if (!q) {
575
+ const unmappedSrc = D.modules.filter(m =>
576
+ m.type !== 'test' && (!m.featureKeys || m.featureKeys.length === 0)
577
+ );
578
+ if (unmappedSrc.length > 0) {
579
+ const isActive = activePanelKey === '__unmapped__';
580
+ const card = document.createElement('div');
581
+ card.className = 'feature-card' + (isActive ? ' active' : '');
582
+ card.style.borderStyle = 'dashed';
583
+ card.style.opacity = '0.75';
584
+ card.innerHTML = `
585
+ <div class="feature-accent" style="background:var(--yellow)"></div>
586
+ <div class="feature-body">
587
+ <div class="feature-title">
588
+ <span style="color:var(--yellow)">⚠ Unmapped</span>
589
+ <span class="feature-file-count">${unmappedSrc.length} ${pluralFiles(unmappedSrc.length)}</span>
590
+ </div>
591
+ <div class="feature-desc">Файлы вне карты фич — не входят ни в одну фичу</div>
592
+ <div class="feature-progress-wrap">
593
+ <div class="feature-progress-bar">
594
+ <div class="feature-progress-fill" style="width:100%;background:var(--border)"></div>
595
+ </div>
596
+ <span class="feature-progress-label" style="color:var(--dim)">нет привязки</span>
597
+ </div>
598
+ </div>`;
599
+ card.onclick = () => openUnmappedPanel(unmappedSrc);
600
+ grid.appendChild(card);
601
+ }
602
+ }
572
603
  }
573
604
 
574
605
  function renderModuleGrid(c) {
@@ -726,6 +757,71 @@ function openModulePanel(m) {
726
757
  document.getElementById('panel').classList.add('open');
727
758
  }
728
759
 
760
+ function openUnmappedPanel(files) {
761
+ activePanelKey = '__unmapped__';
762
+ renderContent();
763
+
764
+ // Group by top-level directory
765
+ const byDir = {};
766
+ files.forEach(m => {
767
+ const parts = m.relativePath.replace(/\\/g, '/').split('/');
768
+ const dir = parts.length > 1 ? parts[0] : '(root)';
769
+ if (!byDir[dir]) byDir[dir] = [];
770
+ byDir[dir].push(m);
771
+ });
772
+ const dirs = Object.keys(byDir).sort();
773
+
774
+ // Build plain-text list for copying to AI agent
775
+ const plainList = files
776
+ .map(m => '- ' + m.relativePath.replace(/\\/g, '/'))
777
+ .join('\n');
778
+
779
+ const promptText =
780
+ `В проекте ${files.length} файлов без привязки к фичам (unmapped).\n` +
781
+ `Изучи список ниже и обнови viberadar.config.json:\n` +
782
+ `добавь эти файлы в существующие фичи или создай новые.\n\n` +
783
+ plainList;
784
+
785
+ document.getElementById('panelContent').innerHTML = `
786
+ <div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">
787
+ <span style="font-size:16px">⚠</span>
788
+ <div class="panel-title" style="color:var(--yellow)">Unmapped файлы</div>
789
+ </div>
790
+ <div class="panel-subtitle">
791
+ Не входят ни в одну фичу.<br>
792
+ Запусти <code style="color:var(--blue)">npx viberadar init</code> — агент предложит куда добавить.
793
+ </div>
794
+
795
+ <button id="copyUnmapped" style="
796
+ width:100%; padding:8px 12px; margin-bottom:16px;
797
+ background:var(--bg); border:1px solid var(--border);
798
+ border-radius:6px; color:var(--blue); font-size:12px;
799
+ cursor:pointer; text-align:left;
800
+ ">📋 Скопировать список для AI-агента</button>
801
+
802
+ ${dirs.map(dir => `
803
+ <div class="panel-section">
804
+ <div class="panel-section-label">${dir}/ (${byDir[dir].length})</div>
805
+ <div class="file-list">
806
+ ${byDir[dir].map(m => fileItem(m)).join('')}
807
+ </div>
808
+ </div>
809
+ `).join('')}`;
810
+
811
+ document.getElementById('copyUnmapped').onclick = function() {
812
+ navigator.clipboard.writeText(promptText).then(() => {
813
+ this.textContent = '✅ Скопировано! Вставь в AI-агента';
814
+ this.style.color = 'var(--green)';
815
+ setTimeout(() => {
816
+ this.textContent = '📋 Скопировать список для AI-агента';
817
+ this.style.color = 'var(--blue)';
818
+ }, 3000);
819
+ });
820
+ };
821
+
822
+ document.getElementById('panel').classList.add('open');
823
+ }
824
+
729
825
  function closePanel() {
730
826
  activePanelKey = null;
731
827
  document.getElementById('panel').classList.remove('open');
@@ -778,7 +874,12 @@ async function refreshData() {
778
874
  // Re-open panel if it was open
779
875
  const panelOpen = document.getElementById('panel').classList.contains('open');
780
876
  if (panelOpen && activePanelKey) {
781
- if (view === 'features' && D.features) {
877
+ if (activePanelKey === '__unmapped__') {
878
+ const unmapped = D.modules.filter(m =>
879
+ m.type !== 'test' && (!m.featureKeys || m.featureKeys.length === 0)
880
+ );
881
+ openUnmappedPanel(unmapped);
882
+ } else if (view === 'features' && D.features) {
782
883
  openFeaturePanel(activePanelKey);
783
884
  } else {
784
885
  const m = D.modules.find(m => m.id === activePanelKey);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viberadar",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Live module map with test coverage for vibecoding projects",
5
5
  "main": "./dist/cli.js",
6
6
  "bin": {