@kopikocappu/mycelium 0.2.3 → 0.2.4

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/dist/cli.js +271 -29
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -16030,8 +16030,52 @@ var EMBEDDED_VIEWER = `<!DOCTYPE html>
16030
16030
  flex-direction: column;
16031
16031
  z-index: 10;
16032
16032
  overflow: hidden;
16033
+ position: relative;
16033
16034
  }
16034
16035
 
16036
+ .sidebar-tab {
16037
+ flex: 1;
16038
+ padding: 8px 4px;
16039
+ background: none;
16040
+ border: none;
16041
+ border-bottom: 2px solid transparent;
16042
+ color: var(--text-dim);
16043
+ cursor: pointer;
16044
+ font-family: inherit;
16045
+ font-size: 11px;
16046
+ letter-spacing: 0.05em;
16047
+ transition: color 0.15s, border-color 0.15s;
16048
+ }
16049
+ .sidebar-tab:hover { color: var(--text); }
16050
+ .sidebar-tab.active { color: var(--text); border-bottom-color: var(--accent); }
16051
+
16052
+ .tab-content { display: flex; flex-direction: column; flex: 1; overflow: hidden; }
16053
+
16054
+ /* \u2500\u2500 History items \u2500\u2500 */
16055
+ .history-item {
16056
+ padding: 10px 12px;
16057
+ border-bottom: 1px solid var(--border);
16058
+ font-size: 11px;
16059
+ }
16060
+ .history-item:hover { background: rgba(255,255,255,0.02); }
16061
+ .history-file { color: var(--text); margin-bottom: 3px; font-family: 'SF Mono', monospace; }
16062
+ .history-meta { color: var(--text-dim); display: flex; gap: 8px; flex-wrap: wrap; }
16063
+ .history-task { color: var(--accent2); }
16064
+ .history-agent { color: var(--accent3); }
16065
+
16066
+ /* \u2500\u2500 Ignore list items \u2500\u2500 */
16067
+ .ignore-item {
16068
+ display: flex; align-items: center; justify-content: space-between;
16069
+ padding: 4px 0; gap: 8px;
16070
+ }
16071
+ .ignore-item:hover { background: rgba(255,255,255,0.03); }
16072
+ .ignore-pattern { font-size: 11px; color: var(--text); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: 'SF Mono', monospace; }
16073
+ .ignore-pattern.removed { color: var(--text-dim); text-decoration: line-through; }
16074
+ .ignore-pattern.custom { color: #6B8AFF; }
16075
+ .ignore-btn { background: none; border: 1px solid var(--border); color: var(--text-dim); cursor: pointer; font-family: inherit; font-size: 10px; padding: 2px 7px; flex-shrink: 0; }
16076
+ .ignore-btn:hover { color: var(--text); }
16077
+ .ignore-btn.danger:hover { color: #F28B82; border-color: #F28B82; }
16078
+
16035
16079
  #sidebar-header {
16036
16080
  padding: 16px;
16037
16081
  border-bottom: 1px solid var(--border);
@@ -16608,12 +16652,12 @@ var EMBEDDED_VIEWER = `<!DOCTYPE html>
16608
16652
 
16609
16653
  .link {
16610
16654
  fill: none;
16611
- stroke: rgba(255,255,255,0.4);
16612
- stroke-opacity: 0.7;
16655
+ stroke: #4a8fff;
16656
+ stroke-opacity: 0.6;
16613
16657
  }
16614
16658
 
16615
- .link.imports-edge { stroke: rgba(255,255,255,0.35); stroke-width: 1; }
16616
- .link.calls-edge { stroke: rgba(255,255,255,0.18); stroke-width: 1; stroke-dasharray: 4,4; }
16659
+ .link.imports-edge { stroke: #4a8fff; stroke-width: 1.5; stroke-opacity: 0.6; }
16660
+ .link.calls-edge { stroke: #f7916a; stroke-width: 1.5; stroke-dasharray: 5,4; stroke-opacity: 0.5; }
16617
16661
  .link.contains-edge { stroke: #333344; stroke-width: 0.5; stroke-dasharray: 3,3; }
16618
16662
 
16619
16663
  .link.highlighted { stroke-opacity: 1 !important; stroke-width: 3 !important; }
@@ -16639,41 +16683,136 @@ var EMBEDDED_VIEWER = `<!DOCTYPE html>
16639
16683
 
16640
16684
  <!-- Sidebar -->
16641
16685
  <div id="sidebar">
16642
- <div id="sidebar-header">
16686
+ <div id="sidebar-header" style="display:flex;align-items:center;justify-content:space-between;padding:0 12px;">
16643
16687
  <div class="logo">mycelium<span>.dev</span></div>
16688
+ <button id="settings-btn" title="Manage ignore list" style="background:none;border:1px solid var(--border);color:var(--text-dim);cursor:pointer;font-size:13px;padding:3px 8px;font-family:inherit;border-radius:3px;" onmouseenter="this.style.color='var(--text)'" onmouseleave="this.style.color='var(--text-dim)'">\u2699</button>
16644
16689
  </div>
16645
- <div id="search-wrap">
16646
- <span class="search-icon">\u2315</span>
16647
- <input id="search" type="text" placeholder="Search files, functions, tags\u2026" autocomplete="off">
16690
+
16691
+ <!-- Tab bar -->
16692
+ <div style="display:flex;border-bottom:1px solid var(--border);flex-shrink:0;">
16693
+ <button class="sidebar-tab active" id="tab-graph" onclick="switchTab('graph')">Graph</button>
16694
+ <button class="sidebar-tab" id="tab-history" onclick="switchTab('history')">History</button>
16695
+ <button class="sidebar-tab" id="tab-help" onclick="switchTab('help')">? Help</button>
16648
16696
  </div>
16649
- <div id="controls">
16650
- <div class="control-row">
16651
- <span>Edges:</span>
16652
- <button class="toggle-btn active" id="toggle-imports" data-tip="Show/hide import edges&#10;Blue lines \u2014 file A imports file B&#10;Shows dependency direction">Imports</button>
16653
- <button class="toggle-btn active" id="toggle-calls" data-tip="Show/hide call edges&#10;Dashed lines \u2014 function A calls function B&#10;Requires codebase-memory-mcp">Calls</button>
16654
- <button class="toggle-btn" id="toggle-fns">Functions</button>
16697
+
16698
+ <!-- GRAPH TAB -->
16699
+ <div id="tab-content-graph" class="tab-content">
16700
+ <div id="search-wrap">
16701
+ <span class="search-icon">\u2315</span>
16702
+ <input id="search" type="text" placeholder="Search files, functions, tags\u2026" autocomplete="off">
16655
16703
  </div>
16656
- <div class="control-row">
16657
- <span>Zoom level:</span>
16658
- <div class="zoom-level-btns">
16659
- <button class="toggle-btn active" id="zoom-files" data-tip="File view (default)&#10;One dot per file&#10;Best for understanding structure">Files</button>
16660
- <button class="toggle-btn" id="zoom-symbols" data-tip="Symbol view&#10;Shows functions and classes&#10;Symbols orbit their parent file">Symbols</button>
16704
+ <div id="controls">
16705
+ <div class="control-row">
16706
+ <span>Edges:</span>
16707
+ <button class="toggle-btn active" id="toggle-imports" data-tip="Show/hide import edges&#10;Blue solid lines&#10;File A imports from File B">Imports</button>
16708
+ <button class="toggle-btn active" id="toggle-calls" data-tip="Show/hide call edges&#10;Orange dashed lines&#10;Function A calls Function B&#10;(needs codebase-memory-mcp)">Calls</button>
16709
+ <button class="toggle-btn" id="toggle-functions" data-tip="Show function nodes&#10;Symbols within each file&#10;Circles attached to parent file">Functions</button>
16710
+ </div>
16711
+ <div class="control-row">
16712
+ <span>Zoom level:</span>
16713
+ <div class="zoom-level-btns">
16714
+ <button class="toggle-btn active" id="zoom-files" data-tip="Files only (default)&#10;One dot = one file&#10;Best for codebase structure">Files</button>
16715
+ <button class="toggle-btn" id="zoom-symbols" data-tip="Show symbols&#10;Functions and classes appear&#10;orbiting their parent file">Symbols</button>
16716
+ </div>
16717
+ </div>
16718
+ <div class="control-row">
16719
+ <button class="toggle-btn" id="toggle-clusters" data-tip="Directory grouping&#10;Dashed outlines show&#10;which folder each node is in">Directory clusters</button>
16720
+ </div>
16721
+ </div>
16722
+ <div id="node-info">
16723
+ <div class="node-info-empty" style="line-height:1.8">Click any dot to see<br>what it imports, exports,<br>and connects to</div>
16724
+ </div>
16725
+ <div id="legend">
16726
+ <div id="dir-legend"></div>
16727
+ <div class="legend-item">
16728
+ <div class="legend-line" style="background:#4a8fff;height:2px;"></div>
16729
+ <span style="font-size:10px;">Import (blue)</span>
16730
+ </div>
16731
+ <div class="legend-item" style="margin-top:4px;">
16732
+ <div style="width:24px;height:2px;background:repeating-linear-gradient(90deg,#f7916a 0,#f7916a 4px,transparent 4px,transparent 8px);flex-shrink:0;"></div>
16733
+ <span style="font-size:10px;">Call (orange dashed)</span>
16661
16734
  </div>
16662
16735
  </div>
16663
- <div class="control-row">
16664
- <button class="toggle-btn" id="toggle-clusters" data-tip="Show/hide directory boundaries&#10;Dashed outlines group files&#10;by their folder">Directory clusters</button>
16736
+ </div>
16737
+
16738
+ <!-- HISTORY TAB -->
16739
+ <div id="tab-content-history" class="tab-content" style="display:none;overflow-y:auto;flex:1;">
16740
+ <div style="padding:12px;border-bottom:1px solid var(--border);">
16741
+ <div style="font-size:10px;letter-spacing:0.1em;text-transform:uppercase;color:var(--text-dim);margin-bottom:4px;">Active task</div>
16742
+ <div id="history-task" style="font-size:13px;color:var(--text);">Loading\u2026</div>
16743
+ </div>
16744
+ <div id="history-list" style="padding:8px 0;"></div>
16745
+ <div style="padding:12px;border-top:1px solid var(--border);">
16746
+ <button onclick="loadHistory()" style="background:none;border:1px solid var(--border);color:var(--text-dim);cursor:pointer;font-family:inherit;font-size:11px;padding:5px 10px;width:100%;">\u21BB Refresh</button>
16665
16747
  </div>
16666
16748
  </div>
16667
- <div id="node-info">
16668
- <div class="node-info-empty" style="line-height:1.8">Click any dot to see<br>what it imports, exports,<br>and connects to</div>
16749
+
16750
+ <!-- HELP TAB -->
16751
+ <div id="tab-content-help" class="tab-content" style="display:none;overflow-y:auto;flex:1;padding:14px;font-size:12px;line-height:1.7;">
16752
+ <div style="font-family:inherit;font-weight:700;font-size:13px;margin-bottom:12px;color:var(--text);">What Mycelium does</div>
16753
+
16754
+ <div style="color:var(--text-dim);margin-bottom:16px;">One command gives AI agents persistent, queryable memory of your entire codebase. Agents call /preflight before touching any file \u2014 instead of reading 40 files, they read 4.</div>
16755
+
16756
+ <div style="font-size:10px;letter-spacing:0.1em;text-transform:uppercase;color:var(--text-dim);margin-bottom:8px;">Graph viewer</div>
16757
+ <div style="margin-bottom:14px;">
16758
+ <div style="margin-bottom:5px;"><span style="color:#4a8fff;">\u25CF</span> <strong>Blue solid lines</strong> \u2014 import edges. File A imports from File B.</div>
16759
+ <div style="margin-bottom:5px;"><span style="color:#f7916a;">\u25CF</span> <strong>Orange dashed lines</strong> \u2014 call edges. Function A calls Function B. Requires codebase-memory-mcp.</div>
16760
+ <div style="margin-bottom:5px;"><span style="color:#ffffff;opacity:0.5;">\u25CF</span> <strong>Node size</strong> \u2014 scales with file size (line count).</div>
16761
+ <div style="margin-bottom:5px;"><span style="color:#ffffff;opacity:0.5;">\u25CF</span> <strong>Node color</strong> \u2014 one color per directory.</div>
16762
+ <div style="margin-bottom:5px;"><strong>Click a node</strong> \u2014 see AI description, imports, callers.</div>
16763
+ <div style="margin-bottom:5px;"><strong>Scroll</strong> \u2014 zoom. <strong>Drag</strong> \u2014 pan. <strong>\u22A1</strong> \u2014 fit to screen.</div>
16764
+ </div>
16765
+
16766
+ <div style="font-size:10px;letter-spacing:0.1em;text-transform:uppercase;color:var(--text-dim);margin-bottom:8px;">Agent API endpoints</div>
16767
+ <div style="margin-bottom:14px;">
16768
+ <div style="margin-bottom:6px;"><code style="color:#6af7c4;">/preflight?task=</code><br><span style="color:var(--text-dim);">Natural language task \u2192 exact files to read. Saves 7k+ tokens per agent task.</span></div>
16769
+ <div style="margin-bottom:6px;"><code style="color:#6af7c4;">/search?q=</code><br><span style="color:var(--text-dim);">Semantic search across all file descriptions and tags.</span></div>
16770
+ <div style="margin-bottom:6px;"><code style="color:#6af7c4;">/dependencies?file=</code><br><span style="color:var(--text-dim);">What a file imports and what imports it.</span></div>
16771
+ <div style="margin-bottom:6px;"><code style="color:#6af7c4;">/xref?file=&fn=</code><br><span style="color:var(--text-dim);">Every caller and callee of a function. Know the blast radius before changing anything.</span></div>
16772
+ <div style="margin-bottom:6px;"><code style="color:#6af7c4;">/history</code><br><span style="color:var(--text-dim);">Every file save by task and agent identity.</span></div>
16773
+ <div style="margin-bottom:6px;"><code style="color:#6af7c4;">/graph</code><br><span style="color:var(--text-dim);">Full graph \u2014 all nodes and edges.</span></div>
16774
+ </div>
16775
+
16776
+ <div style="font-size:10px;letter-spacing:0.1em;text-transform:uppercase;color:var(--text-dim);margin-bottom:8px;">CLI commands</div>
16777
+ <div style="margin-bottom:14px;">
16778
+ <div style="margin-bottom:4px;"><code style="color:#6af7c4;">mycelium init</code> \u2014 scan, summarize, serve, watch</div>
16779
+ <div style="margin-bottom:4px;"><code style="color:#6af7c4;">mycelium serve</code> \u2014 start server from existing graph</div>
16780
+ <div style="margin-bottom:4px;"><code style="color:#6af7c4;">mycelium scan</code> \u2014 re-scan without starting server</div>
16781
+ <div style="margin-bottom:4px;"><code style="color:#6af7c4;">mycelium search</code> \u2014 search from terminal</div>
16782
+ <div style="margin-bottom:4px;"><code style="color:#6af7c4;">mycelium status</code> \u2014 graph stats</div>
16783
+ <div style="margin-bottom:4px;"><code style="color:#6af7c4;">mycelium key</code> \u2014 save Anthropic/OpenAI keys</div>
16784
+ <div style="margin-bottom:4px;"><code style="color:#6af7c4;">mycelium embed</code> \u2014 generate semantic embeddings</div>
16785
+ <div style="margin-bottom:4px;"><code style="color:#6af7c4;">mycelium history</code> \u2014 show change log</div>
16786
+ <div style="margin-bottom:4px;"><code style="color:#6af7c4;">mycelium task</code> \u2014 set active task for history</div>
16787
+ <div style="margin-bottom:4px;"><code style="color:#6af7c4;">mycelium ignore</code> \u2014 manage scan ignore list</div>
16788
+ </div>
16789
+
16790
+ <div style="font-size:10px;letter-spacing:0.1em;text-transform:uppercase;color:var(--text-dim);margin-bottom:8px;">CLAUDE.md</div>
16791
+ <div style="color:var(--text-dim);margin-bottom:16px;">Mycelium writes a 5-step checklist into CLAUDE.md automatically. Claude Code reads it and calls /preflight before touching any file.</div>
16792
+
16793
+ <div style="border-top:1px solid var(--border);padding-top:12px;">
16794
+ <a href="https://github.com/KopikoCappu/Mycelium" target="_blank" style="color:#6B8AFF;text-decoration:none;font-size:11px;">GitHub \u2197</a>
16795
+ &nbsp;&nbsp;
16796
+ <a href="https://www.npmjs.com/package/@kopikocappu/mycelium" target="_blank" style="color:#6B8AFF;text-decoration:none;font-size:11px;">npm \u2197</a>
16797
+ </div>
16669
16798
  </div>
16670
- <div id="legend">
16671
- <div id="dir-legend"></div>
16672
- <div class="legend-item">
16673
- <div class="legend-line" style="background:rgba(255,255,255,0.35)"></div>Import
16799
+
16800
+ <!-- SETTINGS PANEL (slides over everything) -->
16801
+ <div id="settings-panel" style="display:none;position:absolute;top:0;left:0;right:0;bottom:0;background:var(--surface);z-index:50;overflow-y:auto;padding:16px;flex-direction:column;">
16802
+ <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;padding-bottom:10px;border-bottom:1px solid var(--border);">
16803
+ <span style="font-weight:700;font-size:13px;">\u2699 Ignore List</span>
16804
+ <button id="settings-close" style="background:none;border:1px solid var(--border);color:var(--text-dim);cursor:pointer;font-size:12px;padding:3px 10px;font-family:inherit;">\u2715</button>
16674
16805
  </div>
16675
- <div class="legend-item">
16676
- <div class="legend-line" style="background:rgba(255,255,255,0.25)"></div>Call
16806
+ <div style="font-size:10px;letter-spacing:0.1em;text-transform:uppercase;color:var(--text-dim);margin-bottom:8px;">Default patterns</div>
16807
+ <div id="ignore-default-list"></div>
16808
+ <div style="font-size:10px;letter-spacing:0.1em;text-transform:uppercase;color:var(--text-dim);margin-top:14px;margin-bottom:8px;">Custom patterns</div>
16809
+ <div id="ignore-custom-list"><div style="font-size:11px;color:var(--text-dim);padding:4px 0;">None added yet</div></div>
16810
+ <div style="display:flex;gap:8px;margin-top:10px;">
16811
+ <input id="ignore-input" placeholder="e.g. android/** or **/*.test.ts" style="flex:1;background:var(--surface2);border:1px solid var(--border);color:var(--text);font-family:inherit;font-size:12px;padding:7px 10px;outline:none;" />
16812
+ <button id="ignore-add-btn" style="background:rgba(107,138,255,0.15);border:1px solid rgba(107,138,255,0.3);color:#6B8AFF;cursor:pointer;font-family:inherit;font-size:11px;padding:7px 14px;">+ Add</button>
16813
+ </div>
16814
+ <div style="font-size:10px;color:var(--text-dim);margin-top:12px;padding:8px;border:1px solid var(--border);line-height:1.6;">
16815
+ Changes apply on next scan.<br>Run <code>mycelium scan</code> or re-run <code>mycelium init</code>.
16677
16816
  </div>
16678
16817
  </div>
16679
16818
  </div>
@@ -17455,6 +17594,109 @@ function hideLoading() {
17455
17594
  initMinimap();
17456
17595
  loadGraph();
17457
17596
 
17597
+ // \u2500\u2500 Tab switching \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
17598
+ function switchTab(name) {
17599
+ ['graph','history','help'].forEach(t => {
17600
+ document.getElementById('tab-content-' + t).style.display = t === name ? 'flex' : 'none';
17601
+ const btn = document.getElementById('tab-' + t);
17602
+ if (btn) btn.classList.toggle('active', t === name);
17603
+ });
17604
+ if (name === 'history') loadHistory();
17605
+ }
17606
+
17607
+ // \u2500\u2500 History tab \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
17608
+ async function loadHistory() {
17609
+ const listEl = document.getElementById('history-list');
17610
+ const taskEl = document.getElementById('history-task');
17611
+ listEl.innerHTML = '<div style="padding:12px;font-size:11px;color:var(--text-dim)">Loading\u2026</div>';
17612
+ try {
17613
+ const res = await fetch(\`\${API_BASE}/history\`);
17614
+ const data = await res.json();
17615
+ taskEl.textContent = data.activeTask || 'General development';
17616
+ const changes = data.recentChanges || [];
17617
+ if (changes.length === 0) {
17618
+ listEl.innerHTML = '<div style="padding:12px;font-size:11px;color:var(--text-dim)">No changes yet.<br>Mycelium logs every file save during active sessions.</div>';
17619
+ return;
17620
+ }
17621
+ listEl.innerHTML = changes.slice(0, 50).map(c => {
17622
+ const time = new Date(c.timestamp || c.at || Date.now()).toLocaleTimeString([], {hour:'2-digit',minute:'2-digit'});
17623
+ const file = (c.file || c.path || '').split(/[\\/]/).pop();
17624
+ return \`<div class="history-item">
17625
+ <div class="history-file">\${file || c.file || '\u2014'}</div>
17626
+ <div class="history-meta">
17627
+ <span>\${time}</span>
17628
+ \${c.task ? '<span class="history-task">' + c.task + '</span>' : ''}
17629
+ \${c.agent ? '<span class="history-agent">' + c.agent + '</span>' : ''}
17630
+ </div>
17631
+ </div>\`;
17632
+ }).join('');
17633
+ } catch(e) {
17634
+ listEl.innerHTML = '<div style="padding:12px;font-size:11px;color:var(--text-dim)">Could not load history.<br>Is the server running?</div>';
17635
+ }
17636
+ }
17637
+
17638
+ // \u2500\u2500 Settings panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
17639
+ document.getElementById('settings-btn').addEventListener('click', () => {
17640
+ document.getElementById('settings-panel').style.display = 'flex';
17641
+ loadIgnoreConfig();
17642
+ });
17643
+ document.getElementById('settings-close').addEventListener('click', () => {
17644
+ document.getElementById('settings-panel').style.display = 'none';
17645
+ });
17646
+
17647
+ async function loadIgnoreConfig() {
17648
+ try {
17649
+ const res = await fetch(\`\${API_BASE}/config\`);
17650
+ const data = await res.json();
17651
+ renderIgnoreList(data);
17652
+ } catch(e) {
17653
+ document.getElementById('ignore-default-list').innerHTML =
17654
+ '<div style="font-size:11px;color:var(--text-dim);padding:4px 0">Server not reachable</div>';
17655
+ }
17656
+ }
17657
+
17658
+ function renderIgnoreList(data) {
17659
+ const { defaultIgnore = [], userIgnore = [], userUnignore = [] } = data;
17660
+ document.getElementById('ignore-default-list').innerHTML = defaultIgnore.map(p => {
17661
+ const removed = userUnignore.includes(p);
17662
+ return \`<div class="ignore-item">
17663
+ <span class="ignore-pattern \${removed ? 'removed' : ''}">\${p}</span>
17664
+ \${removed
17665
+ ? \`<button class="ignore-btn" onclick="ignoreAction('restore','\${p}')">restore</button>\`
17666
+ : \`<button class="ignore-btn danger" onclick="ignoreAction('remove','\${p}')">remove</button>\`}
17667
+ </div>\`;
17668
+ }).join('');
17669
+ const customEl = document.getElementById('ignore-custom-list');
17670
+ customEl.innerHTML = userIgnore.length === 0
17671
+ ? '<div style="font-size:11px;color:var(--text-dim);padding:4px 0;">None added yet</div>'
17672
+ : userIgnore.map(p => \`<div class="ignore-item">
17673
+ <span class="ignore-pattern custom">\${p}</span>
17674
+ <button class="ignore-btn danger" onclick="ignoreAction('remove','\${p}')">remove</button>
17675
+ </div>\`).join('');
17676
+ }
17677
+
17678
+ async function ignoreAction(action, pattern) {
17679
+ try {
17680
+ await fetch(\`\${API_BASE}/config\`, {
17681
+ method: 'POST',
17682
+ headers: {'Content-Type':'application/json'},
17683
+ body: JSON.stringify({action, pattern}),
17684
+ });
17685
+ await loadIgnoreConfig();
17686
+ } catch(e) { alert('Could not update config.'); }
17687
+ }
17688
+
17689
+ document.getElementById('ignore-add-btn').addEventListener('click', async () => {
17690
+ const input = document.getElementById('ignore-input');
17691
+ const pattern = input.value.trim();
17692
+ if (!pattern) return;
17693
+ await ignoreAction('add', pattern);
17694
+ input.value = '';
17695
+ });
17696
+ document.getElementById('ignore-input').addEventListener('keydown', e => {
17697
+ if (e.key === 'Enter') document.getElementById('ignore-add-btn').click();
17698
+ });
17699
+
17458
17700
  // \u2500\u2500 Settings / Ignore Panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
17459
17701
  const settingsBtn = document.getElementById('settings-btn');
17460
17702
  const settingsPanel = document.getElementById('settings-panel');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kopikocappu/mycelium",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "Codebase memory for AI coding agents. Natural language preflight, graph viewer, and agent history in one command.",
5
5
  "bin": {
6
6
  "mycelium": "dist/cli.js"