amalfa 1.0.22 → 1.0.23

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/src/cli.ts CHANGED
@@ -29,6 +29,8 @@ Commands:
29
29
  setup-mcp Generate MCP configuration JSON
30
30
  daemon <action> Manage file watcher (start|stop|status|restart)
31
31
  vector <action> Manage vector daemon (start|stop|status|restart)
32
+ sonar <action> Manage Sonar AI agent (start|stop|status|restart)
33
+ scripts list List available scripts and their descriptions
32
34
  servers [--dot] Show status of all AMALFA services (--dot for graph)
33
35
 
34
36
  Options:
@@ -42,6 +44,7 @@ Examples:
42
44
  amalfa serve # Start MCP server for Claude Desktop
43
45
  amalfa stats # Show knowledge graph statistics
44
46
  amalfa doctor # Verify installation
47
+ amalfa sonar start # Start Sonar AI agent for enhanced search
45
48
 
46
49
  Documentation: https://github.com/pjsvis/amalfa
47
50
  `);
@@ -53,7 +56,7 @@ function showVersion() {
53
56
 
54
57
  async function getDbPath(): Promise<string> {
55
58
  if (DB_PATH) return DB_PATH;
56
-
59
+
57
60
  // Load from config
58
61
  const { loadConfig } = await import("./config/defaults");
59
62
  const config = await loadConfig();
@@ -108,28 +111,68 @@ async function cmdStats() {
108
111
  // Import database wrapper
109
112
  const dbPath = await getDbPath();
110
113
  const { ResonanceDB } = await import("./resonance/db");
114
+ const { loadConfig } = await import("./config/defaults");
115
+
111
116
  const db = new ResonanceDB(dbPath);
117
+ const config = await loadConfig();
118
+ const sources = config.sources || ["./docs"];
112
119
 
113
120
  try {
114
121
  const stats = db.getStats();
115
- const fileSize = statSync(dbPath).size;
116
- const fileSizeMB = (fileSize / 1024 / 1024).toFixed(2);
122
+ const dbStats = statSync(dbPath);
123
+ const fileSizeMB = (dbStats.size / 1024 / 1024).toFixed(2);
124
+
125
+ // Check for stale files
126
+ let newerFiles = 0;
127
+ let newestFileDate = new Date(0);
128
+
129
+ const { readdirSync, statSync: statSyncFs } = await import("node:fs");
130
+
131
+ function scan(dir: string) {
132
+ if (!existsSync(dir)) return;
133
+ const entries = readdirSync(dir, { withFileTypes: true });
134
+ for (const entry of entries) {
135
+ const fullPath = join(dir, entry.name);
136
+ if (entry.name.startsWith(".")) continue;
137
+
138
+ if (entry.isDirectory()) {
139
+ scan(fullPath);
140
+ } else if (entry.name.endsWith(".md")) {
141
+ const mtime = statSyncFs(fullPath).mtime;
142
+ if (mtime > dbStats.mtime) {
143
+ newerFiles++;
144
+ }
145
+ if (mtime > newestFileDate) {
146
+ newestFileDate = mtime;
147
+ }
148
+ }
149
+ }
150
+ }
117
151
 
118
- console.log(`
152
+ for (const source of sources) {
153
+ scan(join(process.cwd(), source));
154
+ }
155
+
156
+ const isStale = newerFiles > 0;
157
+ const statusIcon = isStale ? "⚠️ STALE" : "✅ FRESH";
158
+
159
+ console.log(`
119
160
  📊 AMALFA Database Statistics
120
161
 
121
162
  Database: ${dbPath}
122
- Size: ${fileSizeMB} MB
163
+ Status: ${statusIcon}
164
+ Size: ${fileSizeMB} MB
123
165
 
124
- Nodes: ${stats.nodes.toLocaleString()}
125
- Edges: ${stats.edges.toLocaleString()}
166
+ Nodes: ${stats.nodes.toLocaleString()}
167
+ Edges: ${stats.edges.toLocaleString()}
126
168
  Embeddings: ${stats.vectors.toLocaleString()} (384-dim)
127
169
 
128
- Source: ./docs (markdown files)
129
- Last modified: ${new Date(statSync(dbPath).mtime).toISOString()}
170
+ Sources: ${sources.join(", ")}
171
+ DB Modified: ${new Date(dbStats.mtime).toISOString()}
172
+ Latest File: ${newestFileDate.toISOString()}
173
+ Stale Files: ${newerFiles}
130
174
 
131
- 🔍 To search: Use with Claude Desktop or other MCP client
132
- 📝 To update: Run 'amalfa daemon start' to watch for file changes
175
+ ${isStale ? "⚠️ ACTION REQUIRED: Run 'amalfa init' or start 'amalfa daemon' to update!" : "🔍 System is up to date."}
133
176
  `);
134
177
  } catch (error) {
135
178
  console.error("❌ Failed to read database statistics:", error);
@@ -165,7 +208,9 @@ async function cmdInit() {
165
208
  console.log(` Total files: ${report.totalFiles}`);
166
209
  console.log(` Valid files: ${report.validFiles}`);
167
210
  console.log(` Skipped files: ${report.skippedFiles}`);
168
- console.log(` Total size: ${(report.totalSizeBytes / 1024 / 1024).toFixed(2)} MB`);
211
+ console.log(
212
+ ` Total size: ${(report.totalSizeBytes / 1024 / 1024).toFixed(2)} MB`,
213
+ );
169
214
  console.log(` Estimated nodes: ${report.estimatedNodes}\n`);
170
215
 
171
216
  if (report.hasErrors) {
@@ -174,7 +219,9 @@ async function cmdInit() {
174
219
  for (const issue of report.issues.filter((i) => i.severity === "error")) {
175
220
  console.error(` - ${issue.path}: ${issue.details}`);
176
221
  }
177
- console.error("\nSee .amalfa/logs/pre-flight.log for details and recommendations");
222
+ console.error(
223
+ "\nSee .amalfa/logs/pre-flight.log for details and recommendations",
224
+ );
178
225
  console.error("\nFix these issues and try again.");
179
226
  process.exit(1);
180
227
  }
@@ -185,14 +232,14 @@ async function cmdInit() {
185
232
  for (const issue of report.issues.filter((i) => i.severity === "warning")) {
186
233
  console.warn(` - ${issue.path}: ${issue.details}`);
187
234
  }
188
- console.warn("\nSee .amalfa/logs/pre-flight.log for recommendations");
235
+ console.warn("\nSee .amalfa/logs/pre-flight.log for recommendations");
189
236
  console.warn("\nTo proceed anyway, use: amalfa init --force");
190
237
  process.exit(1);
191
238
  }
192
239
 
193
240
  if (report.validFiles === 0) {
194
241
  console.error("\n❌ No valid markdown files found");
195
- console.error("See .amalfa/logs/pre-flight.log for details");
242
+ console.error("See .amalfa/logs/pre-flight.log for details");
196
243
  process.exit(1);
197
244
  }
198
245
 
@@ -231,7 +278,7 @@ async function cmdInit() {
231
278
  const tracker = new StatsTracker();
232
279
  const fileSize = statSync(dbPath).size;
233
280
  const dbSizeMB = fileSize / 1024 / 1024;
234
-
281
+
235
282
  await tracker.recordSnapshot({
236
283
  timestamp: new Date().toISOString(),
237
284
  nodes: result.stats.nodes,
@@ -272,16 +319,168 @@ async function cmdDaemon() {
272
319
  process.exit(1);
273
320
  }
274
321
 
275
- // Run daemon with the specified action
276
- const daemonPath = join(import.meta.dir, "daemon/index.ts");
277
- const proc = spawn("bun", ["run", daemonPath, action], {
278
- stdio: "inherit",
279
- cwd: process.cwd(),
280
- });
322
+ const { DaemonManager } = await import("./utils/DaemonManager");
323
+ const manager = new DaemonManager();
281
324
 
282
- proc.on("exit", (code) => {
283
- process.exit(code ?? 0);
284
- });
325
+ if (action === "status") {
326
+ const status = await manager.checkFileWatcher();
327
+ if (status.running) {
328
+ console.log(`✅ File Watcher: Running (PID: ${status.pid})`);
329
+ } else {
330
+ console.log("❌ File Watcher: Stopped");
331
+ }
332
+ return;
333
+ }
334
+
335
+ if (action === "start") {
336
+ console.log("🚀 Starting File Watcher...");
337
+ try {
338
+ await manager.startFileWatcher();
339
+ console.log("✅ File Watcher started");
340
+ } catch (e) {
341
+ console.error("❌ Failed to start File Watcher:", e);
342
+ process.exit(1);
343
+ }
344
+ return;
345
+ }
346
+
347
+ if (action === "stop") {
348
+ console.log("🛑 Stopping File Watcher...");
349
+ try {
350
+ await manager.stopFileWatcher();
351
+ console.log("✅ File Watcher stopped");
352
+ } catch (e) {
353
+ console.error("❌ Failed to stop File Watcher:", e);
354
+ process.exit(1);
355
+ }
356
+ return;
357
+ }
358
+
359
+ if (action === "restart") {
360
+ console.log("🔄 Restarting File Watcher...");
361
+ try {
362
+ await manager.stopFileWatcher();
363
+ await manager.startFileWatcher();
364
+ console.log("✅ File Watcher restarted");
365
+ } catch (e) {
366
+ console.error("❌ Failed to restart File Watcher:", e);
367
+ process.exit(1);
368
+ }
369
+ return;
370
+ }
371
+ }
372
+
373
+ async function cmdSonar() {
374
+ const action = args[1] || "status";
375
+ const validActions = ["start", "stop", "status", "restart", "chat"];
376
+
377
+ if (!validActions.includes(action)) {
378
+ console.error(`❌ Invalid action: ${action}`);
379
+ console.error("\nUsage: amalfa sonar <start|stop|status|restart|chat>");
380
+ process.exit(1);
381
+ }
382
+
383
+ const { DaemonManager } = await import("./utils/DaemonManager");
384
+ const { discoverOllamaCapabilities } = await import(
385
+ "./utils/ollama-discovery"
386
+ );
387
+ const manager = new DaemonManager();
388
+
389
+ if (action === "status") {
390
+ console.log("🔍 Checking status...");
391
+
392
+ // Check Ollama
393
+ try {
394
+ const ollama = await discoverOllamaCapabilities();
395
+ if (ollama.available) {
396
+ console.log(
397
+ `✅ Ollama: Running (Model: ${ollama.model}, Size: ${ollama.size})`,
398
+ );
399
+ } else {
400
+ console.log("❌ Ollama: Not detected");
401
+ }
402
+ } catch {
403
+ console.log("❌ Ollama: Check failed");
404
+ }
405
+
406
+ // Check Daemon
407
+ const status = await manager.checkSonarAgent();
408
+
409
+ if (status.running) {
410
+ console.log(
411
+ `✅ Sonar Agent: Running (PID: ${status.pid}, Port: ${status.port})`,
412
+ );
413
+
414
+ // Check health endpoint
415
+ try {
416
+ const res = await fetch(`http://localhost:${status.port}/health`);
417
+ const health = await res.json();
418
+ console.log(` Health: ${JSON.stringify(health)}`);
419
+ } catch {
420
+ console.log(" Health: ⚠️ Unresponsive");
421
+ }
422
+ } else {
423
+ console.log("❌ Sonar Agent: Stopped");
424
+ }
425
+ return;
426
+ }
427
+
428
+ if (action === "start") {
429
+ console.log("🚀 Starting Sonar Agent...");
430
+ try {
431
+ await manager.startSonarAgent();
432
+ console.log("✅ Sonar Agent started");
433
+ } catch (e) {
434
+ console.error("❌ Failed to start Sonar Agent:", e);
435
+ process.exit(1);
436
+ }
437
+ return;
438
+ }
439
+
440
+ if (action === "stop") {
441
+ console.log("🛑 Stopping Sonar Agent...");
442
+ try {
443
+ await manager.stopSonarAgent();
444
+ console.log("✅ Sonar Agent stopped");
445
+ } catch (e) {
446
+ console.error("❌ Failed to stop Sonar Agent:", e);
447
+ process.exit(1);
448
+ }
449
+ return;
450
+ }
451
+
452
+ if (action === "chat") {
453
+ const { chatLoop } = await import("./cli/sonar-chat");
454
+ await chatLoop();
455
+ return;
456
+ }
457
+
458
+ if (action === "restart") {
459
+ console.log("🔄 Restarting Sonar Agent...");
460
+ try {
461
+ await manager.stopSonarAgent();
462
+ await manager.startSonarAgent();
463
+ console.log("✅ Sonar Agent restarted");
464
+ } catch (e) {
465
+ console.error("❌ Failed to restart Sonar Agent:", e);
466
+ process.exit(1);
467
+ }
468
+ return;
469
+ }
470
+ }
471
+
472
+ async function cmdScripts() {
473
+ const action = args[1] || "list";
474
+
475
+ if (action === "list") {
476
+ // Dynamic import to avoid loading everything at startup
477
+ await import("./cli/list-scripts");
478
+ return;
479
+ }
480
+
481
+ console.error(`❌ Invalid action: ${action}`);
482
+ console.error("Usage: amalfa scripts list");
483
+ process.exit(1);
285
484
  }
286
485
 
287
486
  async function cmdVector() {
@@ -295,7 +494,10 @@ async function cmdVector() {
295
494
  }
296
495
 
297
496
  // Run vector daemon with the specified action
298
- const vectorPath = join(import.meta.dir, "resonance/services/vector-daemon.ts");
497
+ const vectorPath = join(
498
+ import.meta.dir,
499
+ "resonance/services/vector-daemon.ts",
500
+ );
299
501
  const proc = spawn("bun", ["run", vectorPath, action], {
300
502
  stdio: "inherit",
301
503
  cwd: process.cwd(),
@@ -308,22 +510,22 @@ async function cmdVector() {
308
510
 
309
511
  async function cmdSetupMcp() {
310
512
  const { resolve } = await import("node:path");
311
-
513
+
312
514
  const cwd = resolve(process.cwd());
313
515
  const mcpScript = resolve(cwd, "src/mcp/index.ts");
314
-
516
+
315
517
  // Minimal PATH for MCP - only include essential directories
316
- const bunPath = process.execPath.replace(/\/bun$/, ''); // Directory containing bun
518
+ const bunPath = process.execPath.replace(/\/bun$/, ""); // Directory containing bun
317
519
  const minimalPath = [
318
520
  bunPath,
319
- '/usr/local/bin',
320
- '/usr/bin',
321
- '/bin',
322
- '/usr/sbin',
323
- '/sbin',
324
- '/opt/homebrew/bin', // Apple Silicon Homebrew
325
- ].join(':');
326
-
521
+ "/usr/local/bin",
522
+ "/usr/bin",
523
+ "/bin",
524
+ "/usr/sbin",
525
+ "/sbin",
526
+ "/opt/homebrew/bin", // Apple Silicon Homebrew
527
+ ].join(":");
528
+
327
529
  const config = {
328
530
  mcpServers: {
329
531
  amalfa: {
@@ -335,19 +537,21 @@ async function cmdSetupMcp() {
335
537
  },
336
538
  },
337
539
  };
338
-
540
+
339
541
  console.log("\n✅ AMALFA MCP Configuration");
340
542
  console.log("=".repeat(60));
341
543
  console.log(`📂 Installation: ${cwd}`);
342
544
  console.log("=".repeat(60));
343
545
  console.log("\n📋 Copy this JSON to your MCP client config:");
344
- console.log(" Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json");
546
+ console.log(
547
+ " Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json",
548
+ );
345
549
  console.log(" Warp Preview: MCP settings\n");
346
550
  console.log("=".repeat(60));
347
551
  console.log();
348
-
552
+
349
553
  console.log(JSON.stringify(config, null, 2));
350
-
554
+
351
555
  console.log();
352
556
  console.log("=".repeat(60));
353
557
  console.log("💡 Tip: If you move this folder, run 'amalfa setup-mcp' again");
@@ -358,11 +562,36 @@ async function cmdSetupMcp() {
358
562
  async function cmdServers() {
359
563
  const showDot = args.includes("--dot");
360
564
  const { AMALFA_DIRS } = await import("./config/defaults");
361
-
565
+
362
566
  const SERVICES = [
363
- { name: "MCP Server", pidFile: join(AMALFA_DIRS.runtime, "mcp.pid"), port: "stdio", id: "mcp", cmd: "amalfa serve" },
364
- { name: "Vector Daemon", pidFile: join(AMALFA_DIRS.runtime, "vector-daemon.pid"), port: "3010", id: "vector", cmd: "amalfa vector start" },
365
- { name: "File Watcher", pidFile: join(AMALFA_DIRS.runtime, "daemon.pid"), port: "-", id: "watcher", cmd: "amalfa daemon start" },
567
+ {
568
+ name: "MCP Server",
569
+ pidFile: join(AMALFA_DIRS.runtime, "mcp.pid"),
570
+ port: "stdio",
571
+ id: "mcp",
572
+ cmd: "amalfa serve",
573
+ },
574
+ {
575
+ name: "Vector Daemon",
576
+ pidFile: join(AMALFA_DIRS.runtime, "vector-daemon.pid"),
577
+ port: "3010",
578
+ id: "vector",
579
+ cmd: "amalfa vector start",
580
+ },
581
+ {
582
+ name: "File Watcher",
583
+ pidFile: join(AMALFA_DIRS.runtime, "daemon.pid"),
584
+ port: "-",
585
+ id: "watcher",
586
+ cmd: "amalfa daemon start",
587
+ },
588
+ {
589
+ name: "Sonar Agent",
590
+ pidFile: join(AMALFA_DIRS.runtime, "sonar.pid"),
591
+ port: "3012",
592
+ id: "sonar",
593
+ cmd: "amalfa sonar start",
594
+ },
366
595
  ];
367
596
 
368
597
  async function isRunning(pid: number): Promise<boolean> {
@@ -373,22 +602,22 @@ async function cmdServers() {
373
602
  return false;
374
603
  }
375
604
  }
376
-
605
+
377
606
  if (showDot) {
378
607
  // Generate DOT diagram
379
608
  const statuses = new Map<string, { status: string; pid: string }>();
380
-
609
+
381
610
  for (const svc of SERVICES) {
382
611
  let status = "stopped";
383
612
  let pidStr = "-";
384
-
613
+
385
614
  if (existsSync(svc.pidFile)) {
386
615
  try {
387
616
  const { readFileSync } = await import("node:fs");
388
617
  const text = readFileSync(svc.pidFile, "utf-8");
389
618
  const pid = Number.parseInt(text.trim(), 10);
390
-
391
- if (!Number.isNaN(pid) && await isRunning(pid)) {
619
+
620
+ if (!Number.isNaN(pid) && (await isRunning(pid))) {
392
621
  status = "running";
393
622
  pidStr = pid.toString();
394
623
  } else {
@@ -399,32 +628,39 @@ async function cmdServers() {
399
628
  // Ignore
400
629
  }
401
630
  }
402
-
631
+
403
632
  statuses.set(svc.id, { status, pid: pidStr });
404
633
  }
405
-
634
+
406
635
  console.log("digraph AMALFA {");
407
636
  console.log(" rankdir=LR;");
408
637
  console.log(" node [shape=box, style=filled];");
409
638
  console.log("");
410
639
  console.log(" // Nodes");
411
-
640
+
412
641
  for (const svc of SERVICES) {
413
642
  const st = statuses.get(svc.id);
414
- const color = st?.status === "running" ? "lightgreen" : st?.status === "stale" ? "orange" : "lightgray";
643
+ const color =
644
+ st?.status === "running"
645
+ ? "lightgreen"
646
+ : st?.status === "stale"
647
+ ? "orange"
648
+ : "lightgray";
415
649
  const label = `${svc.name}\\nPort: ${svc.port}\\nPID: ${st?.pid || "-"}`;
416
650
  console.log(` ${svc.id} [label="${label}", fillcolor=${color}];`);
417
651
  }
418
-
652
+
419
653
  console.log("");
420
654
  console.log(" // Database");
421
- console.log(" db [label=\"SQLite\\n.amalfa/resonance.db\", shape=cylinder, fillcolor=lightyellow];");
655
+ console.log(
656
+ ' db [label="SQLite\\n.amalfa/resonance.db", shape=cylinder, fillcolor=lightyellow];',
657
+ );
422
658
  console.log("");
423
659
  console.log(" // Connections");
424
- console.log(" mcp -> db [label=\"read/write\"];");
425
- console.log(" vector -> db [label=\"embeddings\"];");
426
- console.log(" watcher -> db [label=\"updates\"];");
427
- console.log(" mcp -> vector [label=\"query\", style=dashed];");
660
+ console.log(' mcp -> db [label="read/write"];');
661
+ console.log(' vector -> db [label="embeddings"];');
662
+ console.log(' watcher -> db [label="updates"];');
663
+ console.log(' mcp -> vector [label="query", style=dashed];');
428
664
  console.log("}");
429
665
  console.log("");
430
666
  console.log("# Save to file: amalfa servers --dot > amalfa.dot");
@@ -436,10 +672,10 @@ async function cmdServers() {
436
672
  console.log("─".repeat(95));
437
673
  console.log(
438
674
  "SERVICE".padEnd(18) +
439
- "COMMAND".padEnd(25) +
440
- "PORT".padEnd(12) +
441
- "STATUS".padEnd(15) +
442
- "PID".padEnd(10)
675
+ "COMMAND".padEnd(25) +
676
+ "PORT".padEnd(12) +
677
+ "STATUS".padEnd(15) +
678
+ "PID".padEnd(10),
443
679
  );
444
680
  console.log("─".repeat(95));
445
681
 
@@ -453,7 +689,7 @@ async function cmdServers() {
453
689
  const text = readFileSync(svc.pidFile, "utf-8");
454
690
  const pid = Number.parseInt(text.trim(), 10);
455
691
 
456
- if (!Number.isNaN(pid) && await isRunning(pid)) {
692
+ if (!Number.isNaN(pid) && (await isRunning(pid))) {
457
693
  status = "🟢 RUNNING";
458
694
  pidStr = pid.toString();
459
695
  } else {
@@ -467,15 +703,17 @@ async function cmdServers() {
467
703
 
468
704
  console.log(
469
705
  svc.name.padEnd(18) +
470
- svc.cmd.padEnd(25) +
471
- svc.port.padEnd(12) +
472
- status.padEnd(15) +
473
- pidStr.padEnd(10)
706
+ svc.cmd.padEnd(25) +
707
+ svc.port.padEnd(12) +
708
+ status.padEnd(15) +
709
+ pidStr.padEnd(10),
474
710
  );
475
711
  }
476
712
 
477
713
  console.log("─".repeat(95));
478
- console.log("\n💡 Commands: amalfa serve | amalfa vector start | amalfa daemon start\n");
714
+ console.log(
715
+ "\n💡 Commands: amalfa serve | amalfa vector start | amalfa daemon start\n",
716
+ );
479
717
  }
480
718
 
481
719
  async function cmdValidate() {
@@ -635,7 +873,9 @@ async function cmdDoctor() {
635
873
  console.log(" amalfa serve # Start MCP server");
636
874
  console.log(" amalfa stats # View database statistics");
637
875
  } else {
638
- console.log(`❌ Found ${issues} issue(s). Please resolve them and try again.`);
876
+ console.log(
877
+ `❌ Found ${issues} issue(s). Please resolve them and try again.`,
878
+ );
639
879
  process.exit(1);
640
880
  }
641
881
  }
@@ -651,33 +891,47 @@ async function main() {
651
891
  await cmdStats();
652
892
  break;
653
893
 
654
- case "doctor":
655
- await cmdDoctor();
656
- break;
894
+ case "doctor":
895
+ await cmdDoctor();
896
+ break;
657
897
 
658
- case "validate":
659
- await cmdValidate();
660
- break;
898
+ case "validate":
899
+ await cmdValidate();
900
+ break;
661
901
 
662
- case "init":
663
- await cmdInit();
664
- break;
902
+ case "init":
903
+ await cmdInit();
904
+ break;
665
905
 
666
- case "daemon":
667
- await cmdDaemon();
668
- break;
906
+ case "daemon":
907
+ await cmdDaemon();
908
+ break;
669
909
 
670
- case "vector":
671
- await cmdVector();
672
- break;
910
+ case "vector":
911
+ await cmdVector();
912
+ break;
673
913
 
674
- case "setup-mcp":
675
- await cmdSetupMcp();
676
- break;
914
+ case "setup-mcp":
915
+ await cmdSetupMcp();
916
+ break;
677
917
 
678
- case "servers":
679
- await cmdServers();
680
- break;
918
+ case "servers":
919
+ await cmdServers();
920
+ break;
921
+
922
+ case "sonar":
923
+ await cmdSonar();
924
+ break;
925
+
926
+ case "scripts":
927
+ await cmdScripts();
928
+ break;
929
+
930
+ case "enhance": {
931
+ const { cmdEnhance } = await import("./cli/enhance-commands");
932
+ await cmdEnhance(args);
933
+ break;
934
+ }
681
935
 
682
936
  case "version":
683
937
  case "--version":