ai-mind-map 1.6.0 → 1.6.2

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 (36) hide show
  1. package/dist/change-tracker/change-log.js +123 -123
  2. package/dist/cli.js +83 -83
  3. package/dist/cli.js.map +1 -1
  4. package/dist/context/compressor.js +3 -3
  5. package/dist/context/compressor.js.map +1 -1
  6. package/dist/context/progressive-disclosure.js +4 -4
  7. package/dist/context/progressive-disclosure.js.map +1 -1
  8. package/dist/index.d.ts +0 -11
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +1 -1371
  11. package/dist/index.js.map +1 -1
  12. package/dist/install.js +114 -114
  13. package/dist/install.js.map +1 -1
  14. package/dist/knowledge-graph/changelog.js +62 -62
  15. package/dist/knowledge-graph/dead-code.js +31 -31
  16. package/dist/knowledge-graph/graph.js +201 -201
  17. package/dist/knowledge-graph/indexer.d.ts +20 -0
  18. package/dist/knowledge-graph/indexer.d.ts.map +1 -1
  19. package/dist/knowledge-graph/indexer.js +55 -4
  20. package/dist/knowledge-graph/indexer.js.map +1 -1
  21. package/dist/knowledge-graph/semantic-search.js +50 -50
  22. package/dist/memory/decision-log.js +61 -61
  23. package/dist/memory/persistent-memory.js +70 -70
  24. package/dist/memory/session-memory.js +54 -54
  25. package/dist/tools/context-tools.js +2 -2
  26. package/dist/tools/context-tools.js.map +1 -1
  27. package/dist/tools/debug-tools.js +9 -9
  28. package/dist/tools/debug-tools.js.map +1 -1
  29. package/dist/tools/evolving-tools.js +3 -3
  30. package/dist/tools/evolving-tools.js.map +1 -1
  31. package/dist/tools/flow-tools.js +29 -29
  32. package/dist/tools/flow-tools.js.map +1 -1
  33. package/dist/tools/session-tools.js +2 -2
  34. package/dist/tools/session-tools.js.map +1 -1
  35. package/dist/tools/snapshot-tools.js +24 -24
  36. package/package.json +1 -1
@@ -46,109 +46,109 @@ export class ChangeLog {
46
46
  }
47
47
  // ----------------------------------------------------------- schema ---
48
48
  initSchema() {
49
- this.db.exec(`
50
- -- Sessions table
51
- CREATE TABLE IF NOT EXISTS change_sessions (
52
- session_id TEXT PRIMARY KEY,
53
- started_at INTEGER NOT NULL,
54
- ended_at INTEGER,
55
- total_changes INTEGER NOT NULL DEFAULT 0,
56
- files_modified TEXT NOT NULL DEFAULT '[]',
57
- summary TEXT NOT NULL DEFAULT ''
58
- );
59
-
60
- -- Change records table
61
- CREATE TABLE IF NOT EXISTS change_records (
62
- id INTEGER PRIMARY KEY AUTOINCREMENT,
63
- file_path TEXT NOT NULL,
64
- change_type TEXT NOT NULL,
65
- old_path TEXT,
66
- summary TEXT NOT NULL DEFAULT '',
67
- symbols_affected TEXT NOT NULL DEFAULT '[]',
68
- lines_added INTEGER NOT NULL DEFAULT 0,
69
- lines_removed INTEGER NOT NULL DEFAULT 0,
70
- timestamp INTEGER NOT NULL,
71
- session_id TEXT NOT NULL,
72
- FOREIGN KEY (session_id) REFERENCES change_sessions(session_id)
73
- ON DELETE CASCADE
74
- );
75
-
76
- -- Indexes for common query patterns
77
- CREATE INDEX IF NOT EXISTS idx_change_records_session
78
- ON change_records(session_id);
79
- CREATE INDEX IF NOT EXISTS idx_change_records_file
80
- ON change_records(file_path);
81
- CREATE INDEX IF NOT EXISTS idx_change_records_timestamp
82
- ON change_records(timestamp);
83
- CREATE INDEX IF NOT EXISTS idx_change_records_change_type
84
- ON change_records(change_type);
85
-
86
- -- FTS5 virtual table for full-text search across summaries and symbols
87
- CREATE VIRTUAL TABLE IF NOT EXISTS change_records_fts USING fts5(
88
- file_path,
89
- summary,
90
- symbols_affected,
91
- content = 'change_records',
92
- content_rowid = 'id',
93
- tokenize = 'porter unicode61'
94
- );
95
-
96
- -- Triggers to keep FTS index in sync
97
- CREATE TRIGGER IF NOT EXISTS trg_change_records_ai
98
- AFTER INSERT ON change_records BEGIN
99
- INSERT INTO change_records_fts(rowid, file_path, summary, symbols_affected)
100
- VALUES (new.id, new.file_path, new.summary, new.symbols_affected);
101
- END;
102
-
103
- CREATE TRIGGER IF NOT EXISTS trg_change_records_ad
104
- AFTER DELETE ON change_records BEGIN
105
- INSERT INTO change_records_fts(change_records_fts, rowid, file_path, summary, symbols_affected)
106
- VALUES ('delete', old.id, old.file_path, old.summary, old.symbols_affected);
107
- END;
108
-
109
- CREATE TRIGGER IF NOT EXISTS trg_change_records_au
110
- AFTER UPDATE ON change_records BEGIN
111
- INSERT INTO change_records_fts(change_records_fts, rowid, file_path, summary, symbols_affected)
112
- VALUES ('delete', old.id, old.file_path, old.summary, old.symbols_affected);
113
- INSERT INTO change_records_fts(rowid, file_path, summary, symbols_affected)
114
- VALUES (new.id, new.file_path, new.summary, new.symbols_affected);
115
- END;
49
+ this.db.exec(`
50
+ -- Sessions table
51
+ CREATE TABLE IF NOT EXISTS change_sessions (
52
+ session_id TEXT PRIMARY KEY,
53
+ started_at INTEGER NOT NULL,
54
+ ended_at INTEGER,
55
+ total_changes INTEGER NOT NULL DEFAULT 0,
56
+ files_modified TEXT NOT NULL DEFAULT '[]',
57
+ summary TEXT NOT NULL DEFAULT ''
58
+ );
59
+
60
+ -- Change records table
61
+ CREATE TABLE IF NOT EXISTS change_records (
62
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
63
+ file_path TEXT NOT NULL,
64
+ change_type TEXT NOT NULL,
65
+ old_path TEXT,
66
+ summary TEXT NOT NULL DEFAULT '',
67
+ symbols_affected TEXT NOT NULL DEFAULT '[]',
68
+ lines_added INTEGER NOT NULL DEFAULT 0,
69
+ lines_removed INTEGER NOT NULL DEFAULT 0,
70
+ timestamp INTEGER NOT NULL,
71
+ session_id TEXT NOT NULL,
72
+ FOREIGN KEY (session_id) REFERENCES change_sessions(session_id)
73
+ ON DELETE CASCADE
74
+ );
75
+
76
+ -- Indexes for common query patterns
77
+ CREATE INDEX IF NOT EXISTS idx_change_records_session
78
+ ON change_records(session_id);
79
+ CREATE INDEX IF NOT EXISTS idx_change_records_file
80
+ ON change_records(file_path);
81
+ CREATE INDEX IF NOT EXISTS idx_change_records_timestamp
82
+ ON change_records(timestamp);
83
+ CREATE INDEX IF NOT EXISTS idx_change_records_change_type
84
+ ON change_records(change_type);
85
+
86
+ -- FTS5 virtual table for full-text search across summaries and symbols
87
+ CREATE VIRTUAL TABLE IF NOT EXISTS change_records_fts USING fts5(
88
+ file_path,
89
+ summary,
90
+ symbols_affected,
91
+ content = 'change_records',
92
+ content_rowid = 'id',
93
+ tokenize = 'porter unicode61'
94
+ );
95
+
96
+ -- Triggers to keep FTS index in sync
97
+ CREATE TRIGGER IF NOT EXISTS trg_change_records_ai
98
+ AFTER INSERT ON change_records BEGIN
99
+ INSERT INTO change_records_fts(rowid, file_path, summary, symbols_affected)
100
+ VALUES (new.id, new.file_path, new.summary, new.symbols_affected);
101
+ END;
102
+
103
+ CREATE TRIGGER IF NOT EXISTS trg_change_records_ad
104
+ AFTER DELETE ON change_records BEGIN
105
+ INSERT INTO change_records_fts(change_records_fts, rowid, file_path, summary, symbols_affected)
106
+ VALUES ('delete', old.id, old.file_path, old.summary, old.symbols_affected);
107
+ END;
108
+
109
+ CREATE TRIGGER IF NOT EXISTS trg_change_records_au
110
+ AFTER UPDATE ON change_records BEGIN
111
+ INSERT INTO change_records_fts(change_records_fts, rowid, file_path, summary, symbols_affected)
112
+ VALUES ('delete', old.id, old.file_path, old.summary, old.symbols_affected);
113
+ INSERT INTO change_records_fts(rowid, file_path, summary, symbols_affected)
114
+ VALUES (new.id, new.file_path, new.summary, new.symbols_affected);
115
+ END;
116
116
  `);
117
117
  }
118
118
  prepareStatements() {
119
- this.stmtInsertChange = this.db.prepare(`
120
- INSERT INTO change_records
121
- (file_path, change_type, old_path, summary, symbols_affected,
122
- lines_added, lines_removed, timestamp, session_id)
123
- VALUES
124
- (@filePath, @changeType, @oldPath, @summary, @symbolsAffected,
125
- @linesAdded, @linesRemoved, @timestamp, @sessionId)
119
+ this.stmtInsertChange = this.db.prepare(`
120
+ INSERT INTO change_records
121
+ (file_path, change_type, old_path, summary, symbols_affected,
122
+ lines_added, lines_removed, timestamp, session_id)
123
+ VALUES
124
+ (@filePath, @changeType, @oldPath, @summary, @symbolsAffected,
125
+ @linesAdded, @linesRemoved, @timestamp, @sessionId)
126
126
  `);
127
- this.stmtInsertSession = this.db.prepare(`
128
- INSERT INTO change_sessions (session_id, started_at)
129
- VALUES (@sessionId, @startedAt)
127
+ this.stmtInsertSession = this.db.prepare(`
128
+ INSERT INTO change_sessions (session_id, started_at)
129
+ VALUES (@sessionId, @startedAt)
130
130
  `);
131
- this.stmtEndSession = this.db.prepare(`
132
- UPDATE change_sessions
133
- SET ended_at = @endedAt,
134
- total_changes = (
135
- SELECT COUNT(*) FROM change_records WHERE session_id = @sessionId
136
- ),
137
- files_modified = (
138
- SELECT json_group_array(DISTINCT file_path)
139
- FROM change_records WHERE session_id = @sessionId
140
- ),
141
- summary = @summary
142
- WHERE session_id = @sessionId
131
+ this.stmtEndSession = this.db.prepare(`
132
+ UPDATE change_sessions
133
+ SET ended_at = @endedAt,
134
+ total_changes = (
135
+ SELECT COUNT(*) FROM change_records WHERE session_id = @sessionId
136
+ ),
137
+ files_modified = (
138
+ SELECT json_group_array(DISTINCT file_path)
139
+ FROM change_records WHERE session_id = @sessionId
140
+ ),
141
+ summary = @summary
142
+ WHERE session_id = @sessionId
143
143
  `);
144
- this.stmtGetSession = this.db.prepare(`
145
- SELECT * FROM change_sessions WHERE session_id = ?
144
+ this.stmtGetSession = this.db.prepare(`
145
+ SELECT * FROM change_sessions WHERE session_id = ?
146
146
  `);
147
- this.stmtDeleteOldChanges = this.db.prepare(`
148
- DELETE FROM change_records WHERE timestamp < ?
147
+ this.stmtDeleteOldChanges = this.db.prepare(`
148
+ DELETE FROM change_records WHERE timestamp < ?
149
149
  `);
150
- this.stmtDeleteOldSessions = this.db.prepare(`
151
- DELETE FROM change_sessions WHERE ended_at IS NOT NULL AND ended_at < ?
150
+ this.stmtDeleteOldSessions = this.db.prepare(`
151
+ DELETE FROM change_sessions WHERE ended_at IS NOT NULL AND ended_at < ?
152
152
  `);
153
153
  }
154
154
  // ----------------------------------------------------- sessions ------
@@ -271,11 +271,11 @@ export class ChangeLog {
271
271
  const where = clauses.length > 0 ? `WHERE ${clauses.join(' AND ')}` : '';
272
272
  const limit = options.limit ?? 100;
273
273
  const offset = options.offset ?? 0;
274
- const sql = `
275
- SELECT * FROM change_records
276
- ${where}
277
- ORDER BY timestamp DESC
278
- LIMIT @limit OFFSET @offset
274
+ const sql = `
275
+ SELECT * FROM change_records
276
+ ${where}
277
+ ORDER BY timestamp DESC
278
+ LIMIT @limit OFFSET @offset
279
279
  `;
280
280
  const rows = this.db.prepare(sql).all({ ...params, limit, offset });
281
281
  return rows.map(rowToFileChange);
@@ -307,15 +307,15 @@ export class ChangeLog {
307
307
  if (!sanitised)
308
308
  return [];
309
309
  try {
310
- const sql = `
311
- SELECT
312
- cr.*,
313
- bm25(change_records_fts, 1.0, 2.0, 1.5) AS rank
314
- FROM change_records_fts fts
315
- JOIN change_records cr ON cr.id = fts.rowid
316
- WHERE change_records_fts MATCH @query
317
- ORDER BY rank
318
- LIMIT @limit
310
+ const sql = `
311
+ SELECT
312
+ cr.*,
313
+ bm25(change_records_fts, 1.0, 2.0, 1.5) AS rank
314
+ FROM change_records_fts fts
315
+ JOIN change_records cr ON cr.id = fts.rowid
316
+ WHERE change_records_fts MATCH @query
317
+ ORDER BY rank
318
+ LIMIT @limit
319
319
  `;
320
320
  const rows = this.db.prepare(sql).all({ query: sanitised, limit: maxResults });
321
321
  return rows.map((r) => ({
@@ -408,26 +408,26 @@ export class ChangeLog {
408
408
  const totalSessions = this.db.prepare('SELECT COUNT(*) AS cnt FROM change_sessions').get().cnt;
409
409
  const activeSessions = this.db.prepare('SELECT COUNT(*) AS cnt FROM change_sessions WHERE ended_at IS NULL').get().cnt;
410
410
  const mostChangedFiles = this.db
411
- .prepare(`SELECT file_path AS filePath, COUNT(*) AS changeCount
412
- FROM change_records
413
- GROUP BY file_path
414
- ORDER BY changeCount DESC
411
+ .prepare(`SELECT file_path AS filePath, COUNT(*) AS changeCount
412
+ FROM change_records
413
+ GROUP BY file_path
414
+ ORDER BY changeCount DESC
415
415
  LIMIT ?`)
416
416
  .all(topN);
417
417
  const mostActiveSessions = this.db
418
- .prepare(`SELECT cs.session_id AS sessionId,
419
- COUNT(cr.id) AS changeCount,
420
- cs.started_at AS startedAt
421
- FROM change_sessions cs
422
- LEFT JOIN change_records cr ON cr.session_id = cs.session_id
423
- GROUP BY cs.session_id
424
- ORDER BY changeCount DESC
418
+ .prepare(`SELECT cs.session_id AS sessionId,
419
+ COUNT(cr.id) AS changeCount,
420
+ cs.started_at AS startedAt
421
+ FROM change_sessions cs
422
+ LEFT JOIN change_records cr ON cr.session_id = cs.session_id
423
+ GROUP BY cs.session_id
424
+ ORDER BY changeCount DESC
425
425
  LIMIT ?`)
426
426
  .all(topN);
427
427
  const lineStats = this.db
428
- .prepare(`SELECT
429
- COALESCE(SUM(lines_added), 0) AS linesAdded,
430
- COALESCE(SUM(lines_removed), 0) AS linesRemoved
428
+ .prepare(`SELECT
429
+ COALESCE(SUM(lines_added), 0) AS linesAdded,
430
+ COALESCE(SUM(lines_removed), 0) AS linesRemoved
431
431
  FROM change_records`)
432
432
  .get();
433
433
  return {
package/dist/cli.js CHANGED
@@ -50,10 +50,10 @@ const c = {
50
50
  gray: supportsColor ? '\x1b[90m' : '',
51
51
  };
52
52
  function success(msg) {
53
- console.log(`${c.green}✔${c.reset} ${msg}`);
53
+ console.log(`${c.green}${c.reset} ${msg}`);
54
54
  }
55
55
  function error(msg) {
56
- console.log(`${c.red}✖${c.reset} ${msg}`);
56
+ console.log(`${c.red}${c.reset} ${msg}`);
57
57
  }
58
58
  function info(msg) {
59
59
  console.log(`${c.blue}ℹ${c.reset} ${msg}`);
@@ -193,7 +193,7 @@ async function cmdServe() {
193
193
  /** ai-mind-map index <project-path> — Index a project */
194
194
  async function cmdIndex(args) {
195
195
  const projectPath = args.positional[0] || process.cwd();
196
- heading('🗂️ Indexing Project');
196
+ heading(' Indexing Project');
197
197
  info(`Project: ${path.resolve(projectPath)}`);
198
198
  divider();
199
199
  const config = await resolveConfig(projectPath);
@@ -221,7 +221,7 @@ async function cmdIndex(args) {
221
221
  // Clear the progress line
222
222
  process.stdout.write('\r' + ' '.repeat(60) + '\r');
223
223
  const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
224
- heading('📊 Index Results');
224
+ heading(' Index Results');
225
225
  divider();
226
226
  console.log(` ${pad('Files scanned:', 20)} ${c.bold}${formatNum(stats.filesScanned)}${c.reset}`);
227
227
  console.log(` ${pad('Files parsed:', 20)} ${c.bold}${formatNum(stats.filesParsed)}${c.reset}`);
@@ -260,7 +260,7 @@ async function cmdSearch(args) {
260
260
  results = results.filter((n) => n.type === typeFilter);
261
261
  }
262
262
  results = results.slice(0, limit);
263
- heading(`🔍 Search Results for "${query}"`);
263
+ heading(` Search Results for "${query}"`);
264
264
  if (typeFilter)
265
265
  info(`Type filter: ${typeFilter}`);
266
266
  divider();
@@ -321,7 +321,7 @@ async function cmdTrace(args) {
321
321
  info('Try running "ai-mind-map index" first, or search with "ai-mind-map search".');
322
322
  return;
323
323
  }
324
- heading(`🔗 Trace: ${symbolName}`);
324
+ heading(` Trace: ${symbolName}`);
325
325
  info(`Direction: ${direction} | Depth: ${depth}`);
326
326
  divider();
327
327
  for (const node of nodes) {
@@ -362,7 +362,7 @@ async function cmdTrace(args) {
362
362
  // Blast radius
363
363
  const blast = graph.blastRadius(node.id, depth);
364
364
  if (blast.length > 0) {
365
- console.log(`\n ${c.red}💥 Blast Radius${c.reset} (${blast.length} affected nodes):`);
365
+ console.log(`\n ${c.red} Blast Radius${c.reset} (${blast.length} affected nodes):`);
366
366
  for (const affected of blast.slice(0, 10)) {
367
367
  console.log(` ${c.yellow}⚡${c.reset} ${affected.qualifiedName} ` +
368
368
  `${c.dim}(${affected.type})${c.reset}`);
@@ -385,7 +385,7 @@ async function cmdStructure(args) {
385
385
  const graph = openGraph(config);
386
386
  try {
387
387
  const overview = graph.getProjectOverview();
388
- heading('🏗️ Project Structure');
388
+ heading(' Project Structure');
389
389
  info(`Project: ${config.projectRoot}`);
390
390
  divider();
391
391
  if (overview.size === 0) {
@@ -420,7 +420,7 @@ async function cmdStructure(args) {
420
420
  async function cmdStatus(args) {
421
421
  const projectPath = args.positional[0];
422
422
  const config = await resolveConfig(projectPath);
423
- heading('📈 AI Mind Map Status');
423
+ heading(' AI Mind Map Status');
424
424
  info(`Project: ${config.projectRoot}`);
425
425
  info(`Database: ${config.dbPath}`);
426
426
  divider();
@@ -509,7 +509,7 @@ async function cmdRecall(args) {
509
509
  try {
510
510
  const memory = new PersistentMemory(db, config.memory);
511
511
  const results = memory.queryMemories({ text: query, limit });
512
- heading(`🧠 Memory Recall: "${query}"`);
512
+ heading(` Memory Recall: "${query}"`);
513
513
  divider();
514
514
  if (results.length === 0) {
515
515
  warn('No memories found matching your query.');
@@ -582,7 +582,7 @@ async function cmdRemember(args) {
582
582
  tags,
583
583
  source: 'user',
584
584
  });
585
- heading('💾 Memory Stored');
585
+ heading(' Memory Stored');
586
586
  divider();
587
587
  console.log(` ${pad('ID:', 14)} ${c.bold}#${created.id}${c.reset}`);
588
588
  console.log(` ${pad('Category:', 14)} ${getCategoryColor(created.category)}${created.category}${c.reset}`);
@@ -611,7 +611,7 @@ async function cmdDecisions(args) {
611
611
  status: statusFilter,
612
612
  limit: 50,
613
613
  });
614
- heading('📋 Decision Log');
614
+ heading(' Decision Log');
615
615
  if (statusFilter)
616
616
  info(`Filter: status = ${statusFilter}`);
617
617
  divider();
@@ -646,7 +646,7 @@ async function cmdChanges(args) {
646
646
  const sinceRaw = typeof args.flags['since'] === 'string' ? args.flags['since'] : undefined;
647
647
  const limit = typeof args.flags['limit'] === 'string' ? parseInt(args.flags['limit'], 10) : 30;
648
648
  const config = await resolveConfig();
649
- heading('📝 Change History');
649
+ heading(' Change History');
650
650
  divider();
651
651
  if (!existsSync(config.dbPath)) {
652
652
  warn('Database not found. Run "ai-mind-map index" first.');
@@ -707,7 +707,7 @@ async function cmdConfig(args) {
707
707
  const subCommand = args.positional[0] || 'list';
708
708
  if (subCommand === 'list') {
709
709
  const config = await resolveConfig();
710
- heading('⚙️ Configuration');
710
+ heading(' Configuration');
711
711
  divider();
712
712
  printConfigRecursive(config, '');
713
713
  divider();
@@ -767,7 +767,7 @@ function getNestedValue(obj, path) {
767
767
  }
768
768
  /** ai-mind-map sync — Sync local memories/decisions/rules with team-shared file */
769
769
  async function cmdSync(args) {
770
- heading('🔄 Team Shared Context Synchronization');
770
+ heading(' Team Shared Context Synchronization');
771
771
  divider();
772
772
  const config = await loadConfig({
773
773
  projectRoot: args.flags['project-root'],
@@ -814,7 +814,7 @@ async function cmdSync(args) {
814
814
  }
815
815
  /** ai-mind-map update — Check for updates */
816
816
  async function cmdUpdate() {
817
- heading('🔄 AI Mind Map — Update');
817
+ heading(' AI Mind Map — Update');
818
818
  divider();
819
819
  const currentVersion = getVersion();
820
820
  info(`Current version: ${c.bold}v${currentVersion}${c.reset}`);
@@ -837,7 +837,7 @@ async function cmdUpdate() {
837
837
  // 2. Compare versions
838
838
  if (currentVersion === latestVersion) {
839
839
  console.log('');
840
- console.log(` ${c.green}✔${c.reset} You are already on the latest version!`);
840
+ console.log(` ${c.green}${c.reset} You are already on the latest version!`);
841
841
  console.log('');
842
842
  divider();
843
843
  return;
@@ -861,7 +861,7 @@ async function cmdUpdate() {
861
861
  const isNpx = process.argv[1]?.includes('_npx') || process.argv[1]?.includes('npm-cache');
862
862
  if (isNpx) {
863
863
  // npx always uses latest on next run
864
- console.log(` ${c.green}✔${c.reset} You're using npx — next run will automatically use v${latestVersion}`);
864
+ console.log(` ${c.green}${c.reset} You're using npx — next run will automatically use v${latestVersion}`);
865
865
  info('To force a cache refresh now:');
866
866
  console.log(`\n ${c.bold}npx -y ai-mind-map@latest install${c.reset}\n`);
867
867
  }
@@ -875,7 +875,7 @@ async function cmdUpdate() {
875
875
  console.log(` ${c.dim}$ ${updateCmd}${c.reset}`);
876
876
  execSync(updateCmd, { stdio: 'inherit', timeout: 60_000 });
877
877
  console.log('');
878
- console.log(` ${c.green}✔${c.reset} Updated to v${latestVersion}!`);
878
+ console.log(` ${c.green}${c.reset} Updated to v${latestVersion}!`);
879
879
  }
880
880
  catch (err) {
881
881
  warn('Auto-update failed. Update manually:');
@@ -903,75 +903,75 @@ async function cmdUpdate() {
903
903
  }
904
904
  console.log('');
905
905
  divider();
906
- console.log(` ${c.green}✔${c.reset} ${c.bold}Update complete!${c.reset} Restart your AI agent to use the new version.`);
906
+ console.log(` ${c.green}${c.reset} ${c.bold}Update complete!${c.reset} Restart your AI agent to use the new version.`);
907
907
  console.log('');
908
908
  }
909
909
  /** ai-mind-map --help — Show help text */
910
910
  function showHelp() {
911
911
  const version = getVersion();
912
- console.log(`
913
- ${c.bold}${c.cyan}AI Mind Map${c.reset} ${c.dim}v${version}${c.reset}
914
- ${c.dim}MCP server that reduces AI coding agent token usage by 80-99%.${c.reset}
915
-
916
- ${c.bold}USAGE${c.reset}
917
- ${c.cyan}ai-mind-map${c.reset} <command> [options]
918
-
919
- ${c.bold}COMMANDS${c.reset}
920
- ${c.cyan}serve${c.reset} Start MCP server (default)
921
- ${c.cyan}index${c.reset} <project-path> Index a project's codebase
922
- ${c.cyan}search${c.reset} <query> Search the knowledge graph
923
- ${c.dim}--type <type> Filter: func, class, method, etc.${c.reset}
924
- ${c.dim}--limit <N> Max results (default: 20)${c.reset}
925
- ${c.cyan}trace${c.reset} <symbol-name> Trace symbol dependencies
926
- ${c.dim}--direction <dir> both, callers, or callees (default: both)${c.reset}
927
- ${c.dim}--depth <N> Traversal depth (default: 3)${c.reset}
928
- ${c.cyan}structure${c.reset} [<project-path>] Show project structure overview
929
- ${c.cyan}status${c.reset} [<project-path>] Show index and memory stats
930
- ${c.cyan}recall${c.reset} <query> Search stored memories
931
- ${c.cyan}remember${c.reset} <content> Store a new memory
932
- ${c.dim}--category <cat> Category (default: convention)${c.reset}
933
- ${c.dim}--tags <tag1,tag2> Comma-separated tags${c.reset}
934
- ${c.cyan}decisions${c.reset} List architectural decisions
935
- ${c.dim}--status <status> Filter: active, superseded, reversed${c.reset}
936
- ${c.cyan}changes${c.reset} Show change history
937
- ${c.dim}--since <last_session|epoch> Filter changes since timestamp${c.reset}
938
- ${c.dim}--limit <N> Max results (default: 30)${c.reset}
939
- ${c.cyan}sync${c.reset} Sync memories, decisions, and rules with shared file
940
-
941
- ${c.bold}AGENT MANAGEMENT${c.reset}
942
- ${c.cyan}install${c.reset} Auto-detect and configure AI agents
943
- ${c.cyan}uninstall${c.reset} Remove agent configurations
944
- ${c.cyan}update${c.reset} Check for updates + auto-update
945
- ${c.cyan}doctor${c.reset} Run diagnostics check
946
- ${c.cyan}doctor --fix${c.reset} Auto-repair broken configurations
947
-
948
- ${c.bold}CONFIGURATION${c.reset}
949
- ${c.cyan}config list${c.reset} Show current configuration
950
- ${c.cyan}config set${c.reset} <key> <value> Set a config value
951
- ${c.cyan}config reset${c.reset} <key> Reset a key to default
952
-
953
- ${c.bold}OTHER${c.reset}
954
- ${c.dim}--help, -h${c.reset} Show this help message
955
- ${c.dim}--version, -v${c.reset} Show version
956
-
957
- ${c.bold}EXAMPLES${c.reset}
958
- ${c.dim}# Index current directory${c.reset}
959
- ${c.cyan}ai-mind-map index .${c.reset}
960
-
961
- ${c.dim}# Search for a function${c.reset}
962
- ${c.cyan}ai-mind-map search "handleAuth" --type function${c.reset}
963
-
964
- ${c.dim}# Trace who calls a function${c.reset}
965
- ${c.cyan}ai-mind-map trace parseConfig --direction callers${c.reset}
966
-
967
- ${c.dim}# Store a convention${c.reset}
968
- ${c.cyan}ai-mind-map remember "Always use snake_case for DB columns" --category convention${c.reset}
969
-
970
- ${c.dim}# Install MCP config for all detected agents${c.reset}
971
- ${c.cyan}ai-mind-map install${c.reset}
972
-
973
- ${c.dim}# Run diagnostics${c.reset}
974
- ${c.cyan}ai-mind-map doctor${c.reset}
912
+ console.log(`
913
+ ${c.bold}${c.cyan}AI Mind Map${c.reset} ${c.dim}v${version}${c.reset}
914
+ ${c.dim}MCP server that reduces AI coding agent token usage by 80-99%.${c.reset}
915
+
916
+ ${c.bold}USAGE${c.reset}
917
+ ${c.cyan}ai-mind-map${c.reset} <command> [options]
918
+
919
+ ${c.bold}COMMANDS${c.reset}
920
+ ${c.cyan}serve${c.reset} Start MCP server (default)
921
+ ${c.cyan}index${c.reset} <project-path> Index a project's codebase
922
+ ${c.cyan}search${c.reset} <query> Search the knowledge graph
923
+ ${c.dim}--type <type> Filter: func, class, method, etc.${c.reset}
924
+ ${c.dim}--limit <N> Max results (default: 20)${c.reset}
925
+ ${c.cyan}trace${c.reset} <symbol-name> Trace symbol dependencies
926
+ ${c.dim}--direction <dir> both, callers, or callees (default: both)${c.reset}
927
+ ${c.dim}--depth <N> Traversal depth (default: 3)${c.reset}
928
+ ${c.cyan}structure${c.reset} [<project-path>] Show project structure overview
929
+ ${c.cyan}status${c.reset} [<project-path>] Show index and memory stats
930
+ ${c.cyan}recall${c.reset} <query> Search stored memories
931
+ ${c.cyan}remember${c.reset} <content> Store a new memory
932
+ ${c.dim}--category <cat> Category (default: convention)${c.reset}
933
+ ${c.dim}--tags <tag1,tag2> Comma-separated tags${c.reset}
934
+ ${c.cyan}decisions${c.reset} List architectural decisions
935
+ ${c.dim}--status <status> Filter: active, superseded, reversed${c.reset}
936
+ ${c.cyan}changes${c.reset} Show change history
937
+ ${c.dim}--since <last_session|epoch> Filter changes since timestamp${c.reset}
938
+ ${c.dim}--limit <N> Max results (default: 30)${c.reset}
939
+ ${c.cyan}sync${c.reset} Sync memories, decisions, and rules with shared file
940
+
941
+ ${c.bold}AGENT MANAGEMENT${c.reset}
942
+ ${c.cyan}install${c.reset} Auto-detect and configure AI agents
943
+ ${c.cyan}uninstall${c.reset} Remove agent configurations
944
+ ${c.cyan}update${c.reset} Check for updates + auto-update
945
+ ${c.cyan}doctor${c.reset} Run diagnostics check
946
+ ${c.cyan}doctor --fix${c.reset} Auto-repair broken configurations
947
+
948
+ ${c.bold}CONFIGURATION${c.reset}
949
+ ${c.cyan}config list${c.reset} Show current configuration
950
+ ${c.cyan}config set${c.reset} <key> <value> Set a config value
951
+ ${c.cyan}config reset${c.reset} <key> Reset a key to default
952
+
953
+ ${c.bold}OTHER${c.reset}
954
+ ${c.dim}--help, -h${c.reset} Show this help message
955
+ ${c.dim}--version, -v${c.reset} Show version
956
+
957
+ ${c.bold}EXAMPLES${c.reset}
958
+ ${c.dim}# Index current directory${c.reset}
959
+ ${c.cyan}ai-mind-map index .${c.reset}
960
+
961
+ ${c.dim}# Search for a function${c.reset}
962
+ ${c.cyan}ai-mind-map search "handleAuth" --type function${c.reset}
963
+
964
+ ${c.dim}# Trace who calls a function${c.reset}
965
+ ${c.cyan}ai-mind-map trace parseConfig --direction callers${c.reset}
966
+
967
+ ${c.dim}# Store a convention${c.reset}
968
+ ${c.cyan}ai-mind-map remember "Always use snake_case for DB columns" --category convention${c.reset}
969
+
970
+ ${c.dim}# Install MCP config for all detected agents${c.reset}
971
+ ${c.cyan}ai-mind-map install${c.reset}
972
+
973
+ ${c.dim}# Run diagnostics${c.reset}
974
+ ${c.cyan}ai-mind-map doctor${c.reset}
975
975
  `);
976
976
  }
977
977
  // ============================================================