@kopikocappu/mycelium 0.2.2 → 0.2.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.
- package/dist/cli.js +657 -15
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -15698,7 +15698,7 @@ function getEngine() {
|
|
|
15698
15698
|
var import_child_process = require("child_process");
|
|
15699
15699
|
var import_crypto2 = __toESM(require("crypto"));
|
|
15700
15700
|
var import_path2 = __toESM(require("path"));
|
|
15701
|
-
var CbmAdapter = class {
|
|
15701
|
+
var CbmAdapter = class _CbmAdapter {
|
|
15702
15702
|
constructor() {
|
|
15703
15703
|
this.cbmBin = this.findBinary();
|
|
15704
15704
|
}
|
|
@@ -15844,6 +15844,71 @@ var CbmAdapter = class {
|
|
|
15844
15844
|
return null;
|
|
15845
15845
|
}
|
|
15846
15846
|
}
|
|
15847
|
+
static {
|
|
15848
|
+
// Directories/patterns that are never application source code
|
|
15849
|
+
// This is a blacklist approach — custom dirs are included automatically
|
|
15850
|
+
this.NEVER_SOURCE = [
|
|
15851
|
+
"node_modules",
|
|
15852
|
+
".expo",
|
|
15853
|
+
".git",
|
|
15854
|
+
"dist",
|
|
15855
|
+
"build",
|
|
15856
|
+
"out",
|
|
15857
|
+
".next",
|
|
15858
|
+
".nuxt",
|
|
15859
|
+
".output",
|
|
15860
|
+
"coverage",
|
|
15861
|
+
"android",
|
|
15862
|
+
"ios",
|
|
15863
|
+
"Pods",
|
|
15864
|
+
"assets",
|
|
15865
|
+
"public",
|
|
15866
|
+
"static",
|
|
15867
|
+
".mycelium",
|
|
15868
|
+
".graphmem",
|
|
15869
|
+
".cache",
|
|
15870
|
+
".turbo",
|
|
15871
|
+
"generated",
|
|
15872
|
+
"__generated__",
|
|
15873
|
+
"docs",
|
|
15874
|
+
"fixtures",
|
|
15875
|
+
"e2e",
|
|
15876
|
+
".vscode",
|
|
15877
|
+
".idea"
|
|
15878
|
+
];
|
|
15879
|
+
}
|
|
15880
|
+
static {
|
|
15881
|
+
this.NEVER_EXTENSIONS = [
|
|
15882
|
+
".d.ts",
|
|
15883
|
+
".min.js",
|
|
15884
|
+
".min.css",
|
|
15885
|
+
".map",
|
|
15886
|
+
".png",
|
|
15887
|
+
".jpg",
|
|
15888
|
+
".jpeg",
|
|
15889
|
+
".gif",
|
|
15890
|
+
".svg",
|
|
15891
|
+
".ico",
|
|
15892
|
+
".woff",
|
|
15893
|
+
".woff2",
|
|
15894
|
+
".ttf",
|
|
15895
|
+
".mp4",
|
|
15896
|
+
".mp3"
|
|
15897
|
+
];
|
|
15898
|
+
}
|
|
15899
|
+
isSourceFile(filePath) {
|
|
15900
|
+
const parts = filePath.split("/");
|
|
15901
|
+
for (const part of parts) {
|
|
15902
|
+
if (_CbmAdapter.NEVER_SOURCE.includes(part)) return false;
|
|
15903
|
+
}
|
|
15904
|
+
for (const ext2 of _CbmAdapter.NEVER_EXTENSIONS) {
|
|
15905
|
+
if (filePath.endsWith(ext2)) return false;
|
|
15906
|
+
}
|
|
15907
|
+
if (filePath.includes(".test.") || filePath.includes(".spec.")) return false;
|
|
15908
|
+
if (filePath.includes(".stories.")) return false;
|
|
15909
|
+
if (filePath.includes("__tests__") || filePath.includes("__mocks__")) return false;
|
|
15910
|
+
return true;
|
|
15911
|
+
}
|
|
15847
15912
|
convertNodes(cbmNodes, repoPath) {
|
|
15848
15913
|
const now = Date.now();
|
|
15849
15914
|
const nodes = [];
|
|
@@ -15851,6 +15916,11 @@ var CbmAdapter = class {
|
|
|
15851
15916
|
const label = n.label?.toLowerCase() ?? "file";
|
|
15852
15917
|
const kind = this.mapLabel(label);
|
|
15853
15918
|
const filePath = n.file ? import_path2.default.relative(repoPath, n.file).replace(/\\/g, "/") : n.name;
|
|
15919
|
+
if (kind === "file" && !this.isSourceFile(filePath)) continue;
|
|
15920
|
+
if (kind !== "file") {
|
|
15921
|
+
const parentFile = filePath.split("::")[0];
|
|
15922
|
+
if (!this.isSourceFile(parentFile)) continue;
|
|
15923
|
+
}
|
|
15854
15924
|
const id = kind === "file" ? filePath : `${filePath}::${n.qualified_name ?? n.name}`;
|
|
15855
15925
|
nodes.push({
|
|
15856
15926
|
id,
|
|
@@ -16338,6 +16408,184 @@ var EMBEDDED_VIEWER = `<!DOCTYPE html>
|
|
|
16338
16408
|
box-shadow: 0 4px 20px rgba(0,0,0,0.4);
|
|
16339
16409
|
}
|
|
16340
16410
|
|
|
16411
|
+
/* \u2500\u2500 Button tooltips \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 */
|
|
16412
|
+
[data-tip] { position: relative; }
|
|
16413
|
+
[data-tip]::after {
|
|
16414
|
+
content: attr(data-tip);
|
|
16415
|
+
position: absolute;
|
|
16416
|
+
bottom: calc(100% + 8px);
|
|
16417
|
+
left: 50%;
|
|
16418
|
+
transform: translateX(-50%);
|
|
16419
|
+
background: #1a1a1a;
|
|
16420
|
+
border: 1px solid rgba(255,255,255,0.15);
|
|
16421
|
+
color: rgba(255,255,255,0.85);
|
|
16422
|
+
font-family: var(--font-code);
|
|
16423
|
+
font-size: 11px;
|
|
16424
|
+
white-space: pre;
|
|
16425
|
+
padding: 6px 10px;
|
|
16426
|
+
line-height: 1.5;
|
|
16427
|
+
pointer-events: none;
|
|
16428
|
+
opacity: 0;
|
|
16429
|
+
transition: opacity 0.15s;
|
|
16430
|
+
z-index: 50;
|
|
16431
|
+
text-align: left;
|
|
16432
|
+
min-width: 160px;
|
|
16433
|
+
}
|
|
16434
|
+
[data-tip]:hover::after { opacity: 1; }
|
|
16435
|
+
|
|
16436
|
+
/* \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 */
|
|
16437
|
+
#settings-panel {
|
|
16438
|
+
display: none;
|
|
16439
|
+
position: absolute;
|
|
16440
|
+
top: 0; left: 0; right: 0; bottom: 0;
|
|
16441
|
+
background: var(--bg);
|
|
16442
|
+
z-index: 30;
|
|
16443
|
+
overflow-y: auto;
|
|
16444
|
+
padding: 20px;
|
|
16445
|
+
}
|
|
16446
|
+
|
|
16447
|
+
#settings-panel.open { display: block; }
|
|
16448
|
+
|
|
16449
|
+
.settings-header {
|
|
16450
|
+
display: flex;
|
|
16451
|
+
align-items: center;
|
|
16452
|
+
justify-content: space-between;
|
|
16453
|
+
margin-bottom: 20px;
|
|
16454
|
+
padding-bottom: 12px;
|
|
16455
|
+
border-bottom: 1px solid var(--border);
|
|
16456
|
+
}
|
|
16457
|
+
|
|
16458
|
+
.settings-title {
|
|
16459
|
+
font-family: var(--font-mono);
|
|
16460
|
+
font-size: 13px;
|
|
16461
|
+
font-weight: 700;
|
|
16462
|
+
color: var(--text);
|
|
16463
|
+
}
|
|
16464
|
+
|
|
16465
|
+
.settings-close {
|
|
16466
|
+
background: none;
|
|
16467
|
+
border: 1px solid var(--border);
|
|
16468
|
+
color: var(--text-dim);
|
|
16469
|
+
cursor: pointer;
|
|
16470
|
+
font-size: 14px;
|
|
16471
|
+
padding: 2px 8px;
|
|
16472
|
+
font-family: var(--font-code);
|
|
16473
|
+
}
|
|
16474
|
+
|
|
16475
|
+
.settings-close:hover { color: var(--text); background: rgba(255,255,255,0.05); }
|
|
16476
|
+
|
|
16477
|
+
.settings-section {
|
|
16478
|
+
margin-bottom: 20px;
|
|
16479
|
+
}
|
|
16480
|
+
|
|
16481
|
+
.settings-section-title {
|
|
16482
|
+
font-family: var(--font-code);
|
|
16483
|
+
font-size: 10px;
|
|
16484
|
+
letter-spacing: 0.12em;
|
|
16485
|
+
text-transform: uppercase;
|
|
16486
|
+
color: var(--text-dim);
|
|
16487
|
+
margin-bottom: 10px;
|
|
16488
|
+
}
|
|
16489
|
+
|
|
16490
|
+
.ignore-item {
|
|
16491
|
+
display: flex;
|
|
16492
|
+
align-items: center;
|
|
16493
|
+
justify-content: space-between;
|
|
16494
|
+
padding: 5px 8px;
|
|
16495
|
+
border-radius: 3px;
|
|
16496
|
+
gap: 8px;
|
|
16497
|
+
}
|
|
16498
|
+
|
|
16499
|
+
.ignore-item:hover { background: rgba(255,255,255,0.04); }
|
|
16500
|
+
|
|
16501
|
+
.ignore-pattern {
|
|
16502
|
+
font-family: var(--font-code);
|
|
16503
|
+
font-size: 11px;
|
|
16504
|
+
color: var(--text);
|
|
16505
|
+
flex: 1;
|
|
16506
|
+
overflow: hidden;
|
|
16507
|
+
text-overflow: ellipsis;
|
|
16508
|
+
white-space: nowrap;
|
|
16509
|
+
}
|
|
16510
|
+
|
|
16511
|
+
.ignore-pattern.removed { color: var(--text-dim); text-decoration: line-through; }
|
|
16512
|
+
.ignore-pattern.custom { color: #6B8AFF; }
|
|
16513
|
+
|
|
16514
|
+
.ignore-btn {
|
|
16515
|
+
background: none;
|
|
16516
|
+
border: 1px solid var(--border);
|
|
16517
|
+
color: var(--text-dim);
|
|
16518
|
+
cursor: pointer;
|
|
16519
|
+
font-family: var(--font-code);
|
|
16520
|
+
font-size: 10px;
|
|
16521
|
+
padding: 2px 7px;
|
|
16522
|
+
flex-shrink: 0;
|
|
16523
|
+
transition: all 0.12s;
|
|
16524
|
+
}
|
|
16525
|
+
|
|
16526
|
+
.ignore-btn:hover { color: var(--text); border-color: rgba(255,255,255,0.3); }
|
|
16527
|
+
.ignore-btn.danger:hover { color: #F28B82; border-color: #F28B82; }
|
|
16528
|
+
|
|
16529
|
+
.ignore-add-row {
|
|
16530
|
+
display: flex;
|
|
16531
|
+
gap: 8px;
|
|
16532
|
+
margin-top: 10px;
|
|
16533
|
+
}
|
|
16534
|
+
|
|
16535
|
+
.ignore-input {
|
|
16536
|
+
flex: 1;
|
|
16537
|
+
background: var(--surface2);
|
|
16538
|
+
border: 1px solid var(--border);
|
|
16539
|
+
color: var(--text);
|
|
16540
|
+
font-family: var(--font-code);
|
|
16541
|
+
font-size: 12px;
|
|
16542
|
+
padding: 7px 10px;
|
|
16543
|
+
outline: none;
|
|
16544
|
+
}
|
|
16545
|
+
|
|
16546
|
+
.ignore-input:focus { border-color: rgba(255,255,255,0.3); }
|
|
16547
|
+
.ignore-input::placeholder { color: var(--text-dim); }
|
|
16548
|
+
|
|
16549
|
+
.ignore-add-btn {
|
|
16550
|
+
background: rgba(107,138,255,0.15);
|
|
16551
|
+
border: 1px solid rgba(107,138,255,0.3);
|
|
16552
|
+
color: #6B8AFF;
|
|
16553
|
+
cursor: pointer;
|
|
16554
|
+
font-family: var(--font-code);
|
|
16555
|
+
font-size: 11px;
|
|
16556
|
+
padding: 7px 14px;
|
|
16557
|
+
transition: all 0.12s;
|
|
16558
|
+
}
|
|
16559
|
+
|
|
16560
|
+
.ignore-add-btn:hover { background: rgba(107,138,255,0.25); }
|
|
16561
|
+
|
|
16562
|
+
.settings-note {
|
|
16563
|
+
font-family: var(--font-code);
|
|
16564
|
+
font-size: 10px;
|
|
16565
|
+
color: var(--text-dim);
|
|
16566
|
+
margin-top: 12px;
|
|
16567
|
+
line-height: 1.6;
|
|
16568
|
+
padding: 8px;
|
|
16569
|
+
border: 1px solid var(--border);
|
|
16570
|
+
background: rgba(255,255,255,0.02);
|
|
16571
|
+
}
|
|
16572
|
+
|
|
16573
|
+
.rescan-btn {
|
|
16574
|
+
width: 100%;
|
|
16575
|
+
margin-top: 16px;
|
|
16576
|
+
padding: 10px;
|
|
16577
|
+
background: rgba(107,138,255,0.1);
|
|
16578
|
+
border: 1px solid rgba(107,138,255,0.25);
|
|
16579
|
+
color: #6B8AFF;
|
|
16580
|
+
font-family: var(--font-code);
|
|
16581
|
+
font-size: 12px;
|
|
16582
|
+
cursor: pointer;
|
|
16583
|
+
transition: all 0.12s;
|
|
16584
|
+
letter-spacing: 0.05em;
|
|
16585
|
+
}
|
|
16586
|
+
|
|
16587
|
+
.rescan-btn:hover { background: rgba(107,138,255,0.2); }
|
|
16588
|
+
|
|
16341
16589
|
#tooltip .tip-name { font-weight: 700; font-size: 13px; margin-bottom: 4px; color: var(--text); }
|
|
16342
16590
|
#tooltip .tip-desc { color: var(--text-dim); font-size: 11px; line-height: 1.6; margin-top: 4px; }
|
|
16343
16591
|
#tooltip .tip-tags { margin-top: 6px; display: flex; flex-wrap: wrap; gap: 3px; }
|
|
@@ -16401,19 +16649,19 @@ var EMBEDDED_VIEWER = `<!DOCTYPE html>
|
|
|
16401
16649
|
<div id="controls">
|
|
16402
16650
|
<div class="control-row">
|
|
16403
16651
|
<span>Edges:</span>
|
|
16404
|
-
<button class="toggle-btn active" id="toggle-imports">Imports</button>
|
|
16405
|
-
<button class="toggle-btn active" id="toggle-calls">Calls</button>
|
|
16652
|
+
<button class="toggle-btn active" id="toggle-imports" data-tip="Show/hide import edges Blue lines \u2014 file A imports file B Shows dependency direction">Imports</button>
|
|
16653
|
+
<button class="toggle-btn active" id="toggle-calls" data-tip="Show/hide call edges Dashed lines \u2014 function A calls function B Requires codebase-memory-mcp">Calls</button>
|
|
16406
16654
|
<button class="toggle-btn" id="toggle-fns">Functions</button>
|
|
16407
16655
|
</div>
|
|
16408
16656
|
<div class="control-row">
|
|
16409
16657
|
<span>Zoom level:</span>
|
|
16410
16658
|
<div class="zoom-level-btns">
|
|
16411
|
-
<button class="toggle-btn active" id="zoom-files">Files</button>
|
|
16412
|
-
<button class="toggle-btn" id="zoom-symbols">Symbols</button>
|
|
16659
|
+
<button class="toggle-btn active" id="zoom-files" data-tip="File view (default) One dot per file Best for understanding structure">Files</button>
|
|
16660
|
+
<button class="toggle-btn" id="zoom-symbols" data-tip="Symbol view Shows functions and classes Symbols orbit their parent file">Symbols</button>
|
|
16413
16661
|
</div>
|
|
16414
16662
|
</div>
|
|
16415
16663
|
<div class="control-row">
|
|
16416
|
-
<button class="toggle-btn" id="toggle-clusters">Directory clusters</button>
|
|
16664
|
+
<button class="toggle-btn" id="toggle-clusters" data-tip="Show/hide directory boundaries Dashed outlines group files by their folder">Directory clusters</button>
|
|
16417
16665
|
</div>
|
|
16418
16666
|
</div>
|
|
16419
16667
|
<div id="node-info">
|
|
@@ -16562,7 +16810,12 @@ function buildVis() {
|
|
|
16562
16810
|
// Filter nodes/links based on current view settings
|
|
16563
16811
|
visNodes = allNodes.filter(n => {
|
|
16564
16812
|
if (n.kind === 'file') return true;
|
|
16565
|
-
if (
|
|
16813
|
+
if (zoomLevel === 'symbols' && showFunctions) {
|
|
16814
|
+
if (n.kind === 'function' || n.kind === 'class' || n.kind === 'type' || n.kind === 'interface') {
|
|
16815
|
+
// Only show named, non-anonymous symbols
|
|
16816
|
+
return n.name && n.name.length > 1 && !n.name.includes('anonymous') && !n.name.startsWith('_');
|
|
16817
|
+
}
|
|
16818
|
+
}
|
|
16566
16819
|
return false;
|
|
16567
16820
|
});
|
|
16568
16821
|
|
|
@@ -16571,7 +16824,9 @@ function buildVis() {
|
|
|
16571
16824
|
if (!nodeIds.has(l.from) || !nodeIds.has(l.to)) return false;
|
|
16572
16825
|
if (l.kind === 'imports' && !showImports) return false;
|
|
16573
16826
|
if (l.kind === 'calls' && !showCalls) return false;
|
|
16574
|
-
|
|
16827
|
+
// Contains edges anchor symbols to their parent file
|
|
16828
|
+
// Critical: without these, symbols have no edges and scatter everywhere
|
|
16829
|
+
if (l.kind === 'contains') return zoomLevel === 'symbols' && showFunctions;
|
|
16575
16830
|
return true;
|
|
16576
16831
|
});
|
|
16577
16832
|
|
|
@@ -16620,7 +16875,11 @@ function buildVis() {
|
|
|
16620
16875
|
.id(d => d.id)
|
|
16621
16876
|
.distance(d => d.kind === 'contains' ? 40 : d.kind === 'calls' ? 80 : 100)
|
|
16622
16877
|
.strength(d => d.kind === 'contains' ? 0.8 : 0.3))
|
|
16623
|
-
.force('charge', d3.forceManyBody()
|
|
16878
|
+
.force('charge', d3.forceManyBody()
|
|
16879
|
+
// Symbols get very weak repulsion so they cluster near parent files via contains edges
|
|
16880
|
+
// Without this, 600+ unconnected symbols explode across the entire screen
|
|
16881
|
+
.strength(d => d.kind === 'file' ? -180 : -8)
|
|
16882
|
+
.distanceMax(300))
|
|
16624
16883
|
.force('center', d3.forceCenter(W / 2, H / 2))
|
|
16625
16884
|
.force('collision', d3.forceCollide().radius(d => nodeRadius(d) + 8))
|
|
16626
16885
|
.force('cluster', clusterForce(dirGroups, 0.08))
|
|
@@ -17016,6 +17275,12 @@ document.getElementById('toggle-clusters').addEventListener('click', function()
|
|
|
17016
17275
|
});
|
|
17017
17276
|
|
|
17018
17277
|
document.getElementById('zoom-files').addEventListener('click', function() {
|
|
17278
|
+
if (zoomLevel === 'symbols') {
|
|
17279
|
+
// Reset positions \u2014 symbols simulation spreads files far apart
|
|
17280
|
+
// Without this, files stay in their spread-out positions after toggling back
|
|
17281
|
+
allNodes.forEach(n => { n.x = undefined; n.y = undefined; n.vx = 0; n.vy = 0; });
|
|
17282
|
+
_initialFitDone = false;
|
|
17283
|
+
}
|
|
17019
17284
|
zoomLevel = 'files';
|
|
17020
17285
|
this.classList.add('active');
|
|
17021
17286
|
document.getElementById('zoom-symbols').classList.remove('active');
|
|
@@ -17190,6 +17455,99 @@ function hideLoading() {
|
|
|
17190
17455
|
initMinimap();
|
|
17191
17456
|
loadGraph();
|
|
17192
17457
|
|
|
17458
|
+
// \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
|
+
const settingsBtn = document.getElementById('settings-btn');
|
|
17460
|
+
const settingsPanel = document.getElementById('settings-panel');
|
|
17461
|
+
const settingsClose = document.getElementById('settings-close');
|
|
17462
|
+
|
|
17463
|
+
settingsBtn.addEventListener('click', () => {
|
|
17464
|
+
settingsPanel.classList.add('open');
|
|
17465
|
+
loadIgnoreConfig();
|
|
17466
|
+
});
|
|
17467
|
+
|
|
17468
|
+
settingsClose.addEventListener('click', () => {
|
|
17469
|
+
settingsPanel.classList.remove('open');
|
|
17470
|
+
});
|
|
17471
|
+
|
|
17472
|
+
// Hover effect for gear button
|
|
17473
|
+
settingsBtn.addEventListener('mouseenter', () => {
|
|
17474
|
+
settingsBtn.style.color = 'var(--text)';
|
|
17475
|
+
settingsBtn.style.borderColor = 'rgba(255,255,255,0.3)';
|
|
17476
|
+
});
|
|
17477
|
+
settingsBtn.addEventListener('mouseleave', () => {
|
|
17478
|
+
settingsBtn.style.color = 'var(--text-dim)';
|
|
17479
|
+
settingsBtn.style.borderColor = 'var(--border)';
|
|
17480
|
+
});
|
|
17481
|
+
|
|
17482
|
+
async function loadIgnoreConfig() {
|
|
17483
|
+
try {
|
|
17484
|
+
const res = await fetch(\`\${API_BASE}/config\`);
|
|
17485
|
+
const data = await res.json();
|
|
17486
|
+
renderIgnoreList(data);
|
|
17487
|
+
} catch (e) {
|
|
17488
|
+
document.getElementById('ignore-default-list').innerHTML =
|
|
17489
|
+
'<div style="font-family:var(--font-code);font-size:11px;color:var(--text-dim);padding:4px 0">Could not load config \u2014 is the server running?</div>';
|
|
17490
|
+
}
|
|
17491
|
+
}
|
|
17492
|
+
|
|
17493
|
+
function renderIgnoreList(data) {
|
|
17494
|
+
const { defaultIgnore, userIgnore, userUnignore } = data;
|
|
17495
|
+
|
|
17496
|
+
// Default patterns
|
|
17497
|
+
const defaultEl = document.getElementById('ignore-default-list');
|
|
17498
|
+
defaultEl.innerHTML = defaultIgnore.map(pattern => {
|
|
17499
|
+
const isRemoved = userUnignore.includes(pattern);
|
|
17500
|
+
return \`<div class="ignore-item">
|
|
17501
|
+
<span class="ignore-pattern \${isRemoved ? 'removed' : ''}">\${pattern}</span>
|
|
17502
|
+
\${isRemoved
|
|
17503
|
+
? \`<button class="ignore-btn" onclick="restorePattern('\${pattern}')">restore</button>\`
|
|
17504
|
+
: \`<button class="ignore-btn danger" onclick="removePattern('\${pattern}')">remove</button>\`
|
|
17505
|
+
}
|
|
17506
|
+
</div>\`;
|
|
17507
|
+
}).join('');
|
|
17508
|
+
|
|
17509
|
+
// Custom patterns
|
|
17510
|
+
const customEl = document.getElementById('ignore-custom-list');
|
|
17511
|
+
if (userIgnore.length === 0) {
|
|
17512
|
+
customEl.innerHTML = '<div style="font-family:var(--font-code);font-size:11px;color:var(--text-dim);padding:4px 0;">None added yet</div>';
|
|
17513
|
+
} else {
|
|
17514
|
+
customEl.innerHTML = userIgnore.map(pattern =>
|
|
17515
|
+
\`<div class="ignore-item">
|
|
17516
|
+
<span class="ignore-pattern custom">\${pattern}</span>
|
|
17517
|
+
<button class="ignore-btn danger" onclick="removePattern('\${pattern}')">remove</button>
|
|
17518
|
+
</div>\`
|
|
17519
|
+
).join('');
|
|
17520
|
+
}
|
|
17521
|
+
}
|
|
17522
|
+
|
|
17523
|
+
async function postIgnoreAction(action, pattern) {
|
|
17524
|
+
try {
|
|
17525
|
+
await fetch(\`\${API_BASE}/config\`, {
|
|
17526
|
+
method: 'POST',
|
|
17527
|
+
headers: { 'Content-Type': 'application/json' },
|
|
17528
|
+
body: JSON.stringify({ action, pattern }),
|
|
17529
|
+
});
|
|
17530
|
+
await loadIgnoreConfig();
|
|
17531
|
+
} catch (e) {
|
|
17532
|
+
alert('Could not update config. Is the server running?');
|
|
17533
|
+
}
|
|
17534
|
+
}
|
|
17535
|
+
|
|
17536
|
+
function removePattern(pattern) { postIgnoreAction('remove', pattern); }
|
|
17537
|
+
function restorePattern(pattern) { postIgnoreAction('restore', pattern); }
|
|
17538
|
+
|
|
17539
|
+
document.getElementById('ignore-add-btn').addEventListener('click', async () => {
|
|
17540
|
+
const input = document.getElementById('ignore-input');
|
|
17541
|
+
const pattern = input.value.trim();
|
|
17542
|
+
if (!pattern) return;
|
|
17543
|
+
await postIgnoreAction('add', pattern);
|
|
17544
|
+
input.value = '';
|
|
17545
|
+
});
|
|
17546
|
+
|
|
17547
|
+
document.getElementById('ignore-input').addEventListener('keydown', e => {
|
|
17548
|
+
if (e.key === 'Enter') document.getElementById('ignore-add-btn').click();
|
|
17549
|
+
});
|
|
17550
|
+
|
|
17193
17551
|
function updateDirLegend() {
|
|
17194
17552
|
const el = document.getElementById('dir-legend');
|
|
17195
17553
|
if (!el) return;
|
|
@@ -17220,8 +17578,62 @@ var RateLimiter = class {
|
|
|
17220
17578
|
return true;
|
|
17221
17579
|
}
|
|
17222
17580
|
};
|
|
17581
|
+
var DEFAULT_IGNORE_LIST = [
|
|
17582
|
+
"node_modules/**",
|
|
17583
|
+
"vendor/**",
|
|
17584
|
+
".pnp/**",
|
|
17585
|
+
"dist/**",
|
|
17586
|
+
"build/**",
|
|
17587
|
+
"out/**",
|
|
17588
|
+
".next/**",
|
|
17589
|
+
".nuxt/**",
|
|
17590
|
+
".output/**",
|
|
17591
|
+
"coverage/**",
|
|
17592
|
+
"android/**",
|
|
17593
|
+
"ios/**",
|
|
17594
|
+
".expo/**",
|
|
17595
|
+
"Pods/**",
|
|
17596
|
+
"assets/**",
|
|
17597
|
+
"public/**",
|
|
17598
|
+
"static/**",
|
|
17599
|
+
"**/*.png",
|
|
17600
|
+
"**/*.jpg",
|
|
17601
|
+
"**/*.jpeg",
|
|
17602
|
+
"**/*.gif",
|
|
17603
|
+
"**/*.svg",
|
|
17604
|
+
"**/*.ico",
|
|
17605
|
+
"**/*.woff",
|
|
17606
|
+
"**/*.woff2",
|
|
17607
|
+
"**/*.ttf",
|
|
17608
|
+
"**/*.mp4",
|
|
17609
|
+
"**/*.mp3",
|
|
17610
|
+
".mycelium/**",
|
|
17611
|
+
".graphmem/**",
|
|
17612
|
+
".cache/**",
|
|
17613
|
+
".turbo/**",
|
|
17614
|
+
"generated/**",
|
|
17615
|
+
"__generated__/**",
|
|
17616
|
+
"**/*.generated.ts",
|
|
17617
|
+
"**/*.generated.js",
|
|
17618
|
+
"**/*.d.ts",
|
|
17619
|
+
"**/*.min.js",
|
|
17620
|
+
"**/*.min.css",
|
|
17621
|
+
"**/*.map",
|
|
17622
|
+
"**/*.test.ts",
|
|
17623
|
+
"**/*.test.tsx",
|
|
17624
|
+
"**/*.spec.ts",
|
|
17625
|
+
"**/*.spec.tsx",
|
|
17626
|
+
"**/__tests__/**",
|
|
17627
|
+
"**/__mocks__/**",
|
|
17628
|
+
"**/*.stories.ts",
|
|
17629
|
+
"**/*.stories.tsx",
|
|
17630
|
+
"docs/**",
|
|
17631
|
+
"fixtures/**",
|
|
17632
|
+
"e2e/**"
|
|
17633
|
+
];
|
|
17223
17634
|
var McpServer = class {
|
|
17224
17635
|
constructor(store, changeLogger, config) {
|
|
17636
|
+
this.projectRoot = null;
|
|
17225
17637
|
this.rateLimiter = new RateLimiter();
|
|
17226
17638
|
this.server = null;
|
|
17227
17639
|
this.store = store;
|
|
@@ -17299,6 +17711,10 @@ var McpServer = class {
|
|
|
17299
17711
|
if (pathname === "/xref") {
|
|
17300
17712
|
return this.handleXref(url, res);
|
|
17301
17713
|
}
|
|
17714
|
+
if (pathname === "/config") {
|
|
17715
|
+
if (req.method === "GET") return this.handleConfigGet(res);
|
|
17716
|
+
if (req.method === "POST") return this.handleConfigPost(req, res);
|
|
17717
|
+
}
|
|
17302
17718
|
if (pathname === "/preflight") {
|
|
17303
17719
|
return this.handlePreflight(url, res);
|
|
17304
17720
|
}
|
|
@@ -17503,6 +17919,75 @@ var McpServer = class {
|
|
|
17503
17919
|
this.handleKeywordPreflight(task, teamName, lens, res);
|
|
17504
17920
|
}
|
|
17505
17921
|
}
|
|
17922
|
+
handleConfigGet(res) {
|
|
17923
|
+
const configPath = path4.join(this.projectRoot ?? process.cwd(), ".mycelium", "config.json");
|
|
17924
|
+
let saved = {};
|
|
17925
|
+
try {
|
|
17926
|
+
if (fs3.existsSync(configPath)) saved = JSON.parse(fs3.readFileSync(configPath, "utf-8"));
|
|
17927
|
+
} catch {
|
|
17928
|
+
}
|
|
17929
|
+
const userIgnore = saved?.parser?.userIgnore ?? [];
|
|
17930
|
+
const userUnignore = saved?.parser?.userUnignore ?? [];
|
|
17931
|
+
const defaultIgnore = DEFAULT_IGNORE_LIST;
|
|
17932
|
+
const activeIgnore = [
|
|
17933
|
+
...defaultIgnore.filter((p) => !userUnignore.includes(p)),
|
|
17934
|
+
...userIgnore
|
|
17935
|
+
];
|
|
17936
|
+
res.writeHead(200, { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" });
|
|
17937
|
+
res.end(JSON.stringify({
|
|
17938
|
+
defaultIgnore,
|
|
17939
|
+
userIgnore,
|
|
17940
|
+
userUnignore,
|
|
17941
|
+
activeIgnore,
|
|
17942
|
+
totalActive: activeIgnore.length
|
|
17943
|
+
}));
|
|
17944
|
+
}
|
|
17945
|
+
handleConfigPost(req, res) {
|
|
17946
|
+
let body = "";
|
|
17947
|
+
req.on("data", (chunk) => {
|
|
17948
|
+
body += chunk.toString();
|
|
17949
|
+
});
|
|
17950
|
+
req.on("end", () => {
|
|
17951
|
+
try {
|
|
17952
|
+
const { action, pattern } = JSON.parse(body);
|
|
17953
|
+
const configPath = path4.join(this.projectRoot ?? process.cwd(), ".mycelium", "config.json");
|
|
17954
|
+
let saved = {};
|
|
17955
|
+
try {
|
|
17956
|
+
if (fs3.existsSync(configPath)) saved = JSON.parse(fs3.readFileSync(configPath, "utf-8"));
|
|
17957
|
+
} catch {
|
|
17958
|
+
}
|
|
17959
|
+
if (!saved.parser) saved.parser = {};
|
|
17960
|
+
let userIgnore = saved.parser.userIgnore ?? [];
|
|
17961
|
+
let userUnignore = saved.parser.userUnignore ?? [];
|
|
17962
|
+
if (action === "add" && pattern) {
|
|
17963
|
+
if (!userIgnore.includes(pattern)) {
|
|
17964
|
+
userIgnore = [...userIgnore, pattern];
|
|
17965
|
+
userUnignore = userUnignore.filter((p) => p !== pattern);
|
|
17966
|
+
}
|
|
17967
|
+
} else if (action === "remove" && pattern) {
|
|
17968
|
+
const isDefault = DEFAULT_IGNORE_LIST.includes(pattern);
|
|
17969
|
+
if (isDefault) {
|
|
17970
|
+
if (!userUnignore.includes(pattern)) userUnignore = [...userUnignore, pattern];
|
|
17971
|
+
} else {
|
|
17972
|
+
userIgnore = userIgnore.filter((p) => p !== pattern);
|
|
17973
|
+
}
|
|
17974
|
+
} else if (action === "restore" && pattern) {
|
|
17975
|
+
userUnignore = userUnignore.filter((p) => p !== pattern);
|
|
17976
|
+
} else if (action === "reset") {
|
|
17977
|
+
userIgnore = [];
|
|
17978
|
+
userUnignore = [];
|
|
17979
|
+
}
|
|
17980
|
+
saved.parser.userIgnore = userIgnore;
|
|
17981
|
+
saved.parser.userUnignore = userUnignore;
|
|
17982
|
+
fs3.writeFileSync(configPath, JSON.stringify(saved, null, 2));
|
|
17983
|
+
res.writeHead(200, { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" });
|
|
17984
|
+
res.end(JSON.stringify({ ok: true, userIgnore, userUnignore }));
|
|
17985
|
+
} catch (e) {
|
|
17986
|
+
res.writeHead(400);
|
|
17987
|
+
res.end(JSON.stringify({ error: e.message }));
|
|
17988
|
+
}
|
|
17989
|
+
});
|
|
17990
|
+
}
|
|
17506
17991
|
async handleXref(url, res) {
|
|
17507
17992
|
const file = (url.searchParams.get("file") || "").slice(0, 500);
|
|
17508
17993
|
const fn = (url.searchParams.get("fn") || "").slice(0, 500);
|
|
@@ -18073,6 +18558,68 @@ ${GRAPHMEM_SECTION_END}`;
|
|
|
18073
18558
|
}
|
|
18074
18559
|
|
|
18075
18560
|
// src/graph/schema.ts
|
|
18561
|
+
var DEFAULT_IGNORE = [
|
|
18562
|
+
// Package managers & deps
|
|
18563
|
+
"node_modules/**",
|
|
18564
|
+
"vendor/**",
|
|
18565
|
+
".pnp/**",
|
|
18566
|
+
// Build output
|
|
18567
|
+
"dist/**",
|
|
18568
|
+
"build/**",
|
|
18569
|
+
"out/**",
|
|
18570
|
+
".next/**",
|
|
18571
|
+
".nuxt/**",
|
|
18572
|
+
".output/**",
|
|
18573
|
+
"coverage/**",
|
|
18574
|
+
// Native mobile (usually auto-generated)
|
|
18575
|
+
"android/**",
|
|
18576
|
+
"ios/**",
|
|
18577
|
+
".expo/**",
|
|
18578
|
+
"Pods/**",
|
|
18579
|
+
// Assets & static
|
|
18580
|
+
"assets/**",
|
|
18581
|
+
"public/**",
|
|
18582
|
+
"static/**",
|
|
18583
|
+
"**/*.png",
|
|
18584
|
+
"**/*.jpg",
|
|
18585
|
+
"**/*.jpeg",
|
|
18586
|
+
"**/*.gif",
|
|
18587
|
+
"**/*.svg",
|
|
18588
|
+
"**/*.ico",
|
|
18589
|
+
"**/*.woff",
|
|
18590
|
+
"**/*.woff2",
|
|
18591
|
+
"**/*.ttf",
|
|
18592
|
+
"**/*.mp4",
|
|
18593
|
+
"**/*.mp3",
|
|
18594
|
+
// Generated & cache
|
|
18595
|
+
".mycelium/**",
|
|
18596
|
+
".graphmem/**",
|
|
18597
|
+
".cache/**",
|
|
18598
|
+
".turbo/**",
|
|
18599
|
+
"generated/**",
|
|
18600
|
+
"__generated__/**",
|
|
18601
|
+
"**/*.generated.ts",
|
|
18602
|
+
"**/*.generated.js",
|
|
18603
|
+
// Config & declaration files
|
|
18604
|
+
"**/*.d.ts",
|
|
18605
|
+
"**/*.min.js",
|
|
18606
|
+
"**/*.min.css",
|
|
18607
|
+
"**/*.map",
|
|
18608
|
+
// Tests (optional — users may want these)
|
|
18609
|
+
"**/*.test.ts",
|
|
18610
|
+
"**/*.test.tsx",
|
|
18611
|
+
"**/*.spec.ts",
|
|
18612
|
+
"**/*.spec.tsx",
|
|
18613
|
+
"**/__tests__/**",
|
|
18614
|
+
"**/__mocks__/**",
|
|
18615
|
+
// Stories
|
|
18616
|
+
"**/*.stories.ts",
|
|
18617
|
+
"**/*.stories.tsx",
|
|
18618
|
+
// Docs & fixtures
|
|
18619
|
+
"docs/**",
|
|
18620
|
+
"fixtures/**",
|
|
18621
|
+
"e2e/**"
|
|
18622
|
+
];
|
|
18076
18623
|
var DEFAULT_CONFIG = {
|
|
18077
18624
|
teams: {
|
|
18078
18625
|
core: { name: "core", includeTags: [], includeAll: true }
|
|
@@ -18082,8 +18629,9 @@ var DEFAULT_CONFIG = {
|
|
|
18082
18629
|
batchSize: 10
|
|
18083
18630
|
},
|
|
18084
18631
|
parser: {
|
|
18085
|
-
include: [
|
|
18086
|
-
|
|
18632
|
+
include: [],
|
|
18633
|
+
// empty = auto-detect from tsconfig or directory structure
|
|
18634
|
+
exclude: DEFAULT_IGNORE
|
|
18087
18635
|
},
|
|
18088
18636
|
mcp: {
|
|
18089
18637
|
port: 47821,
|
|
@@ -18123,13 +18671,41 @@ function resolveRoot(input) {
|
|
|
18123
18671
|
}
|
|
18124
18672
|
function loadProjectConfig(root) {
|
|
18125
18673
|
const cfgPath = path8.join(root, ".mycelium", "config.json");
|
|
18674
|
+
let saved = {};
|
|
18126
18675
|
if (fs8.existsSync(cfgPath)) {
|
|
18127
18676
|
try {
|
|
18128
|
-
|
|
18677
|
+
saved = JSON.parse(fs8.readFileSync(cfgPath, "utf8"));
|
|
18129
18678
|
} catch {
|
|
18130
18679
|
}
|
|
18131
18680
|
}
|
|
18132
|
-
|
|
18681
|
+
const merged = { ...DEFAULT_CONFIG, ...saved };
|
|
18682
|
+
const userIgnore = saved.parser?.userIgnore ?? [];
|
|
18683
|
+
const userUnignore = saved.parser?.userUnignore ?? [];
|
|
18684
|
+
merged.parser = {
|
|
18685
|
+
...DEFAULT_CONFIG.parser,
|
|
18686
|
+
...saved.parser ?? {},
|
|
18687
|
+
exclude: [
|
|
18688
|
+
...DEFAULT_IGNORE.filter((p) => !userUnignore.includes(p)),
|
|
18689
|
+
...userIgnore
|
|
18690
|
+
],
|
|
18691
|
+
userIgnore,
|
|
18692
|
+
userUnignore
|
|
18693
|
+
};
|
|
18694
|
+
return merged;
|
|
18695
|
+
}
|
|
18696
|
+
function saveProjectConfig(root, update) {
|
|
18697
|
+
const cfgPath = path8.join(root, ".mycelium", "config.json");
|
|
18698
|
+
let existing = {};
|
|
18699
|
+
if (fs8.existsSync(cfgPath)) {
|
|
18700
|
+
try {
|
|
18701
|
+
existing = JSON.parse(fs8.readFileSync(cfgPath, "utf8"));
|
|
18702
|
+
} catch {
|
|
18703
|
+
}
|
|
18704
|
+
}
|
|
18705
|
+
if (!existing.parser) existing.parser = {};
|
|
18706
|
+
if (update.userIgnore !== void 0) existing.parser.userIgnore = update.userIgnore;
|
|
18707
|
+
if (update.userUnignore !== void 0) existing.parser.userUnignore = update.userUnignore;
|
|
18708
|
+
fs8.writeFileSync(cfgPath, JSON.stringify(existing, null, 2));
|
|
18133
18709
|
}
|
|
18134
18710
|
function initProjectDir(root) {
|
|
18135
18711
|
const dir = path8.join(root, ".mycelium");
|
|
@@ -18307,7 +18883,7 @@ program2.command("init [path]").description("Scan codebase, build graph, start s
|
|
|
18307
18883
|
ok(".mcp.json written");
|
|
18308
18884
|
if (opts.serve) {
|
|
18309
18885
|
const server = new McpServer(store, logger, config);
|
|
18310
|
-
server.start();
|
|
18886
|
+
server.start(root);
|
|
18311
18887
|
log("");
|
|
18312
18888
|
log(` ${C.bold}Graph view${C.reset} ${C.cyan}http://localhost:${config.mcp.port}/ui${C.reset}`);
|
|
18313
18889
|
log(` ${C.bold}MCP server${C.reset} ${C.gray}http://localhost:${config.mcp.port}${C.reset}`);
|
|
@@ -18338,7 +18914,7 @@ program2.command("serve [path]").description("Start MCP server and file watcher
|
|
|
18338
18914
|
}
|
|
18339
18915
|
ok(`Loaded graph: ${stats.fileCount} files, ${stats.edgeCount} edges`);
|
|
18340
18916
|
const server = new McpServer(store, logger, config);
|
|
18341
|
-
server.start();
|
|
18917
|
+
server.start(root);
|
|
18342
18918
|
log("");
|
|
18343
18919
|
log(` ${C.bold}Graph view${C.reset} ${C.cyan}http://localhost:${config.mcp.port}/ui${C.reset}`);
|
|
18344
18920
|
log(` ${C.bold}MCP server${C.reset} ${C.gray}http://localhost:${config.mcp.port}${C.reset}`);
|
|
@@ -18529,6 +19105,72 @@ program2.command("embed [path]").description("Generate semantic embeddings for a
|
|
|
18529
19105
|
if (pruned > 0) ok(`${pruned} stale embeddings removed`);
|
|
18530
19106
|
ok(`Semantic search now active on /search and /preflight`);
|
|
18531
19107
|
});
|
|
19108
|
+
program2.command("ignore [path]").description("View and manage the scan ignore list").option("--add <pattern>", "Add a pattern to the ignore list").option("--remove <pattern>", "Remove a pattern (default or custom) from the ignore list").option("--reset", "Reset to default ignore list").action((targetPath, opts) => {
|
|
19109
|
+
header();
|
|
19110
|
+
const root = resolveRoot(targetPath);
|
|
19111
|
+
const config = loadProjectConfig(root);
|
|
19112
|
+
const userIgnore = config.parser.userIgnore ?? [];
|
|
19113
|
+
const userUnignore = config.parser.userUnignore ?? [];
|
|
19114
|
+
if (opts.reset) {
|
|
19115
|
+
saveProjectConfig(root, { userIgnore: [], userUnignore: [] });
|
|
19116
|
+
ok("Ignore list reset to defaults");
|
|
19117
|
+
return;
|
|
19118
|
+
}
|
|
19119
|
+
if (opts.add) {
|
|
19120
|
+
const pattern = opts.add.trim();
|
|
19121
|
+
if (userIgnore.includes(pattern)) {
|
|
19122
|
+
warn(`Already ignored: ${pattern}`);
|
|
19123
|
+
return;
|
|
19124
|
+
}
|
|
19125
|
+
const newUnignore = userUnignore.filter((p) => p !== pattern);
|
|
19126
|
+
saveProjectConfig(root, { userIgnore: [...userIgnore, pattern], userUnignore: newUnignore });
|
|
19127
|
+
ok(`Added to ignore list: ${C.gray}${pattern}${C.reset}`);
|
|
19128
|
+
ok("Run mycelium scan to apply changes");
|
|
19129
|
+
return;
|
|
19130
|
+
}
|
|
19131
|
+
if (opts.remove) {
|
|
19132
|
+
const pattern = opts.remove.trim();
|
|
19133
|
+
const isDefault = DEFAULT_IGNORE.includes(pattern);
|
|
19134
|
+
const isCustom = userIgnore.includes(pattern);
|
|
19135
|
+
if (!isDefault && !isCustom) {
|
|
19136
|
+
warn(`Pattern not found in ignore list: ${pattern}`);
|
|
19137
|
+
return;
|
|
19138
|
+
}
|
|
19139
|
+
if (isDefault) {
|
|
19140
|
+
if (!userUnignore.includes(pattern)) {
|
|
19141
|
+
saveProjectConfig(root, { userIgnore, userUnignore: [...userUnignore, pattern] });
|
|
19142
|
+
}
|
|
19143
|
+
} else {
|
|
19144
|
+
saveProjectConfig(root, { userIgnore: userIgnore.filter((p) => p !== pattern), userUnignore });
|
|
19145
|
+
}
|
|
19146
|
+
ok(`Removed from ignore list: ${C.gray}${pattern}${C.reset}`);
|
|
19147
|
+
ok("Run mycelium scan to apply changes");
|
|
19148
|
+
return;
|
|
19149
|
+
}
|
|
19150
|
+
const activeIgnore = [
|
|
19151
|
+
...DEFAULT_IGNORE.filter((p) => !userUnignore.includes(p)),
|
|
19152
|
+
...userIgnore
|
|
19153
|
+
];
|
|
19154
|
+
log(`
|
|
19155
|
+
${C.bold}Default patterns${C.reset} ${C.gray}(${DEFAULT_IGNORE.length - userUnignore.length} active)${C.reset}`);
|
|
19156
|
+
for (const p of DEFAULT_IGNORE) {
|
|
19157
|
+
const removed = userUnignore.includes(p);
|
|
19158
|
+
log(` ${removed ? C.gray + "\u2717 " : " "}${p}${removed ? " (removed)" : ""}${C.reset}`);
|
|
19159
|
+
}
|
|
19160
|
+
if (userIgnore.length > 0) {
|
|
19161
|
+
log(`
|
|
19162
|
+
${C.bold}Custom patterns${C.reset} ${C.gray}(${userIgnore.length})${C.reset}`);
|
|
19163
|
+
for (const p of userIgnore) {
|
|
19164
|
+
log(` ${C.cyan}+${C.reset} ${p}`);
|
|
19165
|
+
}
|
|
19166
|
+
}
|
|
19167
|
+
log(`
|
|
19168
|
+
${C.gray}Total active: ${activeIgnore.length} patterns${C.reset}`);
|
|
19169
|
+
log(` ${C.gray}Add: mycelium ignore --add "android/**"${C.reset}`);
|
|
19170
|
+
log(` ${C.gray}Remove: mycelium ignore --remove "**/*.test.ts"${C.reset}`);
|
|
19171
|
+
log(` ${C.gray}Reset: mycelium ignore --reset${C.reset}
|
|
19172
|
+
`);
|
|
19173
|
+
});
|
|
18532
19174
|
program2.parse(process.argv);
|
|
18533
19175
|
/*! Bundled license information:
|
|
18534
19176
|
|
package/package.json
CHANGED