@triedotdev/mcp 1.0.59 → 1.0.60

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 (41) hide show
  1. package/README.md +17 -13
  2. package/dist/{agent-smith-O7RG7WQ3.js → agent-smith-4IJZHSNQ.js} +3 -2
  3. package/dist/{agent-smith-runner-EW4C4PTF.js → agent-smith-runner-4PE3GOUX.js} +5 -3
  4. package/dist/{agent-smith-runner-EW4C4PTF.js.map → agent-smith-runner-4PE3GOUX.js.map} +1 -1
  5. package/dist/{chunk-HUQQSQOD.js → chunk-3XWSM2DU.js} +73 -44
  6. package/dist/chunk-3XWSM2DU.js.map +1 -0
  7. package/dist/{chunk-KLKY34RE.js → chunk-4EHBRED6.js} +139 -12
  8. package/dist/chunk-4EHBRED6.js.map +1 -0
  9. package/dist/{chunk-6ODT4U4O.js → chunk-C7LXN754.js} +539 -194
  10. package/dist/chunk-C7LXN754.js.map +1 -0
  11. package/dist/{chunk-AVOMCNBD.js → chunk-DV3JQTLQ.js} +23 -86
  12. package/dist/chunk-DV3JQTLQ.js.map +1 -0
  13. package/dist/{chunk-3CS6Z2SL.js → chunk-MVUCBUBR.js} +7 -2
  14. package/dist/chunk-MVUCBUBR.js.map +1 -0
  15. package/dist/{chunk-3B2JBLSP.js → chunk-NM7ZVUHO.js} +682 -37
  16. package/dist/chunk-NM7ZVUHO.js.map +1 -0
  17. package/dist/chunk-RAZUNSBI.js +171 -0
  18. package/dist/chunk-RAZUNSBI.js.map +1 -0
  19. package/dist/{chunk-MR755QGT.js → chunk-ULOW5HSH.js} +7 -2
  20. package/dist/chunk-ULOW5HSH.js.map +1 -0
  21. package/dist/cli/main.js +6 -5
  22. package/dist/cli/main.js.map +1 -1
  23. package/dist/cli/yolo-daemon.js +10 -9
  24. package/dist/cli/yolo-daemon.js.map +1 -1
  25. package/dist/index.js +30 -18
  26. package/dist/index.js.map +1 -1
  27. package/dist/{vibe-code-signatures-4CBHUSI7.js → vibe-code-signatures-TGMQXYGO.js} +3 -2
  28. package/dist/{vulnerability-signatures-J3CUQ7VR.js → vulnerability-signatures-GOVD4Q24.js} +3 -2
  29. package/dist/workers/agent-worker.js +4 -3
  30. package/dist/workers/agent-worker.js.map +1 -1
  31. package/package.json +1 -1
  32. package/dist/chunk-3B2JBLSP.js.map +0 -1
  33. package/dist/chunk-3CS6Z2SL.js.map +0 -1
  34. package/dist/chunk-6ODT4U4O.js.map +0 -1
  35. package/dist/chunk-AVOMCNBD.js.map +0 -1
  36. package/dist/chunk-HUQQSQOD.js.map +0 -1
  37. package/dist/chunk-KLKY34RE.js.map +0 -1
  38. package/dist/chunk-MR755QGT.js.map +0 -1
  39. /package/dist/{agent-smith-O7RG7WQ3.js.map → agent-smith-4IJZHSNQ.js.map} +0 -0
  40. /package/dist/{vibe-code-signatures-4CBHUSI7.js.map → vibe-code-signatures-TGMQXYGO.js.map} +0 -0
  41. /package/dist/{vulnerability-signatures-J3CUQ7VR.js.map → vulnerability-signatures-GOVD4Q24.js.map} +0 -0
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  Executor,
3
- Triager
4
- } from "./chunk-KLKY34RE.js";
3
+ Triager,
4
+ getChangedFilesSinceTimestamp,
5
+ isGitRepo
6
+ } from "./chunk-4EHBRED6.js";
5
7
  import {
6
8
  getSkillRegistry,
7
9
  updateContextAfterScan
8
- } from "./chunk-HUQQSQOD.js";
10
+ } from "./chunk-3XWSM2DU.js";
9
11
  import {
10
- ProgressReporter,
11
- isInteractiveMode,
12
- setInteractiveMode
13
- } from "./chunk-6ODT4U4O.js";
12
+ getOutputManager
13
+ } from "./chunk-C7LXN754.js";
14
14
  import {
15
15
  getWorkingDirectory
16
16
  } from "./chunk-ASGSTVVF.js";
@@ -18,10 +18,15 @@ import {
18
18
  getVulnerabilityStats,
19
19
  getVulnerabilityTrie,
20
20
  scanForVulnerabilities
21
- } from "./chunk-MR755QGT.js";
21
+ } from "./chunk-ULOW5HSH.js";
22
22
  import {
23
23
  Trie
24
24
  } from "./chunk-6NLHFIYA.js";
25
+ import {
26
+ ProgressReporter,
27
+ isInteractiveMode,
28
+ setInteractiveMode
29
+ } from "./chunk-RAZUNSBI.js";
25
30
  import {
26
31
  __require
27
32
  } from "./chunk-DGUM43GV.js";
@@ -76,7 +81,9 @@ var ContextAnalyzer = class {
76
81
  for (const file of files) {
77
82
  try {
78
83
  if (!existsSync(file)) {
79
- console.error(`File not found: ${file}`);
84
+ if (!isInteractiveMode()) {
85
+ console.error(`File not found: ${file}`);
86
+ }
80
87
  continue;
81
88
  }
82
89
  if (this.isSignatureFile(file)) {
@@ -119,7 +126,9 @@ var ContextAnalyzer = class {
119
126
  const fileComplexity = await this.analyzeCodeContent(content, file, context);
120
127
  totalComplexity += fileComplexity;
121
128
  } catch (error) {
122
- console.error(`Error analyzing file ${file}:`, error);
129
+ if (!isInteractiveMode()) {
130
+ console.error(`Error analyzing file ${file}:`, error);
131
+ }
123
132
  }
124
133
  }
125
134
  context.linesChanged = totalLines;
@@ -2327,17 +2336,21 @@ function getSymbolIndex() {
2327
2336
 
2328
2337
  // src/trie/incremental-scanner.ts
2329
2338
  import { createHash } from "crypto";
2330
- import { readFile as readFile5, writeFile, mkdir } from "fs/promises";
2339
+ import { readFile as readFile5, writeFile, mkdir, stat } from "fs/promises";
2331
2340
  import { existsSync as existsSync2 } from "fs";
2332
2341
  import { join as join2 } from "path";
2333
- var CACHE_VERSION = "1.0.0";
2342
+ var SCAN_CONCURRENCY = 10;
2343
+ var CACHE_VERSION = "1.1.0";
2334
2344
  var CACHE_FILE = ".trie-cache.json";
2335
2345
  var IncrementalScanner = class {
2336
2346
  cache;
2337
2347
  symbolIndex;
2338
2348
  cacheDir;
2349
+ projectRoot;
2339
2350
  dirty = false;
2351
+ isGitRepoCache = null;
2340
2352
  constructor(projectRoot) {
2353
+ this.projectRoot = projectRoot;
2341
2354
  this.cacheDir = join2(projectRoot, ".trie");
2342
2355
  this.symbolIndex = getSymbolIndex();
2343
2356
  this.cache = {
@@ -2359,14 +2372,20 @@ var IncrementalScanner = class {
2359
2372
  const data = await readFile5(cachePath, "utf-8");
2360
2373
  const parsed = JSON.parse(data);
2361
2374
  if (parsed.version !== CACHE_VERSION) {
2362
- console.error(" \u26A0\uFE0F Cache version mismatch, rebuilding...");
2375
+ if (!isInteractiveMode()) {
2376
+ console.error(" \u26A0\uFE0F Cache version mismatch, rebuilding...");
2377
+ }
2363
2378
  return false;
2364
2379
  }
2365
2380
  this.cache = parsed;
2366
- console.error(` \u2705 Loaded cache with ${Object.keys(this.cache.files).length} files`);
2381
+ if (!isInteractiveMode()) {
2382
+ console.error(` \u2705 Loaded cache with ${Object.keys(this.cache.files).length} files`);
2383
+ }
2367
2384
  return true;
2368
2385
  } catch (error) {
2369
- console.error(" \u26A0\uFE0F Failed to load cache, rebuilding...");
2386
+ if (!isInteractiveMode()) {
2387
+ console.error(" \u26A0\uFE0F Failed to load cache, rebuilding...");
2388
+ }
2370
2389
  return false;
2371
2390
  }
2372
2391
  }
@@ -2382,7 +2401,9 @@ var IncrementalScanner = class {
2382
2401
  await writeFile(cachePath, JSON.stringify(this.cache, null, 2));
2383
2402
  this.dirty = false;
2384
2403
  } catch (error) {
2385
- console.error(" \u26A0\uFE0F Failed to save cache");
2404
+ if (!isInteractiveMode()) {
2405
+ console.error(" \u26A0\uFE0F Failed to save cache");
2406
+ }
2386
2407
  }
2387
2408
  }
2388
2409
  /**
@@ -2392,6 +2413,57 @@ var IncrementalScanner = class {
2392
2413
  computeHash(content) {
2393
2414
  return createHash("sha256").update(content).digest("hex").slice(0, 16);
2394
2415
  }
2416
+ /**
2417
+ * Fast pre-check using file stats (mtime + size)
2418
+ * Returns true if file might have changed (needs hash check)
2419
+ * Returns false if file definitely hasn't changed (skip hash)
2420
+ * O(1) - just a stat call, no file read
2421
+ */
2422
+ async fastPreCheck(filePath) {
2423
+ const cached = this.cache.files[filePath];
2424
+ if (!cached || cached.mtime === void 0 || cached.size === void 0) {
2425
+ try {
2426
+ const stats = await stat(filePath);
2427
+ return { changed: true, stats: { mtime: stats.mtimeMs, size: stats.size } };
2428
+ } catch {
2429
+ return { changed: true };
2430
+ }
2431
+ }
2432
+ try {
2433
+ const stats = await stat(filePath);
2434
+ const currentMtime = stats.mtimeMs;
2435
+ const currentSize = stats.size;
2436
+ if (currentMtime === cached.mtime && currentSize === cached.size) {
2437
+ return { changed: false, stats: { mtime: currentMtime, size: currentSize } };
2438
+ }
2439
+ return { changed: true, stats: { mtime: currentMtime, size: currentSize } };
2440
+ } catch {
2441
+ return { changed: true };
2442
+ }
2443
+ }
2444
+ /**
2445
+ * Check if this project is a git repo (cached)
2446
+ */
2447
+ async checkIsGitRepo() {
2448
+ if (this.isGitRepoCache !== null) return this.isGitRepoCache;
2449
+ this.isGitRepoCache = await isGitRepo(this.projectRoot);
2450
+ return this.isGitRepoCache;
2451
+ }
2452
+ /**
2453
+ * Get files changed since last scan using git (fast path)
2454
+ * Returns null if not a git repo or git detection fails
2455
+ */
2456
+ async getGitChangedFiles() {
2457
+ if (!await this.checkIsGitRepo()) return null;
2458
+ const lastScanTime = this.cache.lastFullScanTime;
2459
+ if (!lastScanTime) return null;
2460
+ try {
2461
+ const changedFiles = await getChangedFilesSinceTimestamp(this.projectRoot, lastScanTime);
2462
+ return changedFiles ? new Set(changedFiles) : null;
2463
+ } catch {
2464
+ return null;
2465
+ }
2466
+ }
2395
2467
  /**
2396
2468
  * Check if a file has changed since last scan
2397
2469
  * O(1) for cache lookup + O(n) for hash if needed
@@ -2412,17 +2484,39 @@ var IncrementalScanner = class {
2412
2484
  /**
2413
2485
  * Scan a single file incrementally
2414
2486
  * Returns cached results if file unchanged
2487
+ *
2488
+ * Optimization layers:
2489
+ * 1. Fast pre-check (mtime + size) - O(1), avoids file read
2490
+ * 2. Hash comparison - O(n), only if pre-check fails
2415
2491
  */
2416
2492
  async scanFile(filePath, forceRescan = false) {
2493
+ const cached = this.cache.files[filePath];
2494
+ if (!forceRescan && cached) {
2495
+ const preCheck = await this.fastPreCheck(filePath);
2496
+ if (!preCheck.changed) {
2497
+ return {
2498
+ vulnerabilities: cached.vulnerabilities,
2499
+ fromCache: true,
2500
+ symbolCount: cached.symbolCount
2501
+ };
2502
+ }
2503
+ }
2417
2504
  let content;
2505
+ let fileStats;
2418
2506
  try {
2507
+ const stats = await stat(filePath);
2508
+ fileStats = { mtime: stats.mtimeMs, size: stats.size };
2419
2509
  content = await readFile5(filePath, "utf-8");
2420
2510
  } catch {
2421
2511
  return { vulnerabilities: [], fromCache: false, symbolCount: 0 };
2422
2512
  }
2423
2513
  const hash = this.computeHash(content);
2424
- const cached = this.cache.files[filePath];
2425
2514
  if (!forceRescan && cached && cached.hash === hash) {
2515
+ if (fileStats) {
2516
+ cached.mtime = fileStats.mtime;
2517
+ cached.size = fileStats.size;
2518
+ this.dirty = true;
2519
+ }
2426
2520
  return {
2427
2521
  vulnerabilities: cached.vulnerabilities,
2428
2522
  fromCache: true,
@@ -2438,7 +2532,9 @@ var IncrementalScanner = class {
2438
2532
  lastScanned: Date.now(),
2439
2533
  lineCount: content.split("\n").length,
2440
2534
  vulnerabilities,
2441
- symbolCount: symbols.length
2535
+ symbolCount: symbols.length,
2536
+ mtime: fileStats?.mtime,
2537
+ size: fileStats?.size
2442
2538
  };
2443
2539
  this.dirty = true;
2444
2540
  return {
@@ -2449,6 +2545,11 @@ var IncrementalScanner = class {
2449
2545
  }
2450
2546
  /**
2451
2547
  * Scan multiple files with incremental caching
2548
+ *
2549
+ * Optimizations:
2550
+ * 1. Git-based change detection (when available) - only scan changed files
2551
+ * 2. Parallel file scanning with concurrency limit
2552
+ * 3. Fast pre-check (mtime + size) per file
2452
2553
  */
2453
2554
  async scanFiles(filePaths, forceRescan = false, onFileProgress) {
2454
2555
  const startTime = Date.now();
@@ -2462,9 +2563,20 @@ var IncrementalScanner = class {
2462
2563
  for (const [path, state] of Object.entries(this.cache.files)) {
2463
2564
  previousVulnerabilities.set(path, state.vulnerabilities);
2464
2565
  }
2465
- for (const filePath of filePaths) {
2466
- const result = await this.scanFile(filePath, forceRescan);
2467
- onFileProgress?.(filePath, result.fromCache);
2566
+ let gitChangedFiles = null;
2567
+ if (!forceRescan) {
2568
+ gitChangedFiles = await this.getGitChangedFiles();
2569
+ if (gitChangedFiles && !isInteractiveMode()) {
2570
+ console.error(` \u26A1 Git detected ${gitChangedFiles.size} changed files`);
2571
+ }
2572
+ }
2573
+ const scanResults = await this.parallelScan(
2574
+ filePaths,
2575
+ forceRescan,
2576
+ gitChangedFiles,
2577
+ onFileProgress
2578
+ );
2579
+ for (const { filePath, result } of scanResults) {
2468
2580
  allVulnerabilities.push(...result.vulnerabilities);
2469
2581
  if (result.fromCache) {
2470
2582
  filesSkipped++;
@@ -2493,6 +2605,8 @@ var IncrementalScanner = class {
2493
2605
  }
2494
2606
  }
2495
2607
  }
2608
+ this.cache.lastFullScanTime = Date.now();
2609
+ this.dirty = true;
2496
2610
  const scanTimeMs = Date.now() - startTime;
2497
2611
  const totalFiles = filesScanned + filesSkipped;
2498
2612
  const cacheHitRate = totalFiles > 0 ? filesSkipped / totalFiles * 100 : 0;
@@ -2507,6 +2621,38 @@ var IncrementalScanner = class {
2507
2621
  cacheHitRate
2508
2622
  };
2509
2623
  }
2624
+ /**
2625
+ * Parallel file scanning with concurrency limit
2626
+ * Processes SCAN_CONCURRENCY files at a time
2627
+ */
2628
+ async parallelScan(filePaths, forceRescan, gitChangedFiles, onFileProgress) {
2629
+ const results = [];
2630
+ for (let i = 0; i < filePaths.length; i += SCAN_CONCURRENCY) {
2631
+ const batch = filePaths.slice(i, i + SCAN_CONCURRENCY);
2632
+ const batchPromises = batch.map(async (filePath) => {
2633
+ if (gitChangedFiles && !gitChangedFiles.has(filePath)) {
2634
+ const cached = this.cache.files[filePath];
2635
+ if (cached) {
2636
+ onFileProgress?.(filePath, true);
2637
+ return {
2638
+ filePath,
2639
+ result: {
2640
+ vulnerabilities: cached.vulnerabilities,
2641
+ fromCache: true,
2642
+ symbolCount: cached.symbolCount
2643
+ }
2644
+ };
2645
+ }
2646
+ }
2647
+ const result = await this.scanFile(filePath, forceRescan);
2648
+ onFileProgress?.(filePath, result.fromCache);
2649
+ return { filePath, result };
2650
+ });
2651
+ const batchResults = await Promise.all(batchPromises);
2652
+ results.push(...batchResults);
2653
+ }
2654
+ return results;
2655
+ }
2510
2656
  /**
2511
2657
  * Remove a file from the cache
2512
2658
  */
@@ -2645,6 +2791,7 @@ ${"\u2501".repeat(60)}
2645
2791
  }
2646
2792
 
2647
2793
  // src/utils/streaming.ts
2794
+ var shouldSuppressConsole = () => isInteractiveMode();
2648
2795
  var StreamingManager = class {
2649
2796
  listeners = /* @__PURE__ */ new Set();
2650
2797
  progress = {
@@ -2675,7 +2822,9 @@ var StreamingManager = class {
2675
2822
  try {
2676
2823
  listener(update);
2677
2824
  } catch (error) {
2678
- console.warn("Stream listener error:", error);
2825
+ if (!shouldSuppressConsole()) {
2826
+ console.warn("Stream listener error:", error);
2827
+ }
2679
2828
  }
2680
2829
  });
2681
2830
  }
@@ -2806,6 +2955,51 @@ var StreamingManager = class {
2806
2955
  reportMemory(action, details) {
2807
2956
  this.emit("memory", { action, details });
2808
2957
  }
2958
+ // ============================================
2959
+ // Rich Content Events (for TUI panes)
2960
+ // ============================================
2961
+ /**
2962
+ * Report a code snippet for display
2963
+ */
2964
+ reportSnippet(snippet) {
2965
+ this.emit("snippet", snippet);
2966
+ }
2967
+ /**
2968
+ * Report cost estimate from Moneybags
2969
+ */
2970
+ reportCost(cost) {
2971
+ this.emit("cost_report", cost);
2972
+ }
2973
+ /**
2974
+ * Report production readiness score
2975
+ */
2976
+ reportReadiness(readiness) {
2977
+ this.emit("readiness_report", readiness);
2978
+ }
2979
+ /**
2980
+ * Report semantic analysis results
2981
+ */
2982
+ reportSemantic(semantic) {
2983
+ this.emit("semantic_report", semantic);
2984
+ }
2985
+ /**
2986
+ * Report attack surface analysis
2987
+ */
2988
+ reportAttackSurface(attack) {
2989
+ this.emit("attack_surface", attack);
2990
+ }
2991
+ /**
2992
+ * Report skill banner (ASCII art + quote)
2993
+ */
2994
+ reportBanner(banner) {
2995
+ this.emit("skill_banner", banner);
2996
+ }
2997
+ /**
2998
+ * Report raw log entry
2999
+ */
3000
+ reportRawLog(level, message) {
3001
+ this.emit("raw_log", { level, message, time: (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false }) });
3002
+ }
2809
3003
  };
2810
3004
  function formatConsoleUpdate(update) {
2811
3005
  if (isInteractiveMode()) {
@@ -3185,7 +3379,9 @@ var colors = {
3185
3379
  alert: (s) => pc.bold(pc.red(s)),
3186
3380
  // Interactive
3187
3381
  selected: (s) => pc.bold(pc.magenta(s)),
3188
- highlight: (s) => pc.bold(pc.white(s))
3382
+ highlight: (s) => pc.bold(pc.white(s)),
3383
+ // Additional
3384
+ yellow: (s) => pc.yellow(s)
3189
3385
  };
3190
3386
  var stripAnsi = (s) => s.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "");
3191
3387
  var visibleLength = (s) => {
@@ -3271,7 +3467,27 @@ var InteractiveDashboard = class {
3271
3467
  directories: 0,
3272
3468
  recentChanges: []
3273
3469
  },
3274
- agents: {}
3470
+ agents: {},
3471
+ // Rich content state
3472
+ codeSnippets: /* @__PURE__ */ new Map(),
3473
+ costReport: null,
3474
+ readiness: null,
3475
+ semanticAnalysis: null,
3476
+ attackSurface: null,
3477
+ skillBanners: [],
3478
+ rawLog: [],
3479
+ rawLogPage: 0,
3480
+ scrollPositions: {
3481
+ overview: 0,
3482
+ issues: 0,
3483
+ agents: 0,
3484
+ files: 0,
3485
+ details: 0,
3486
+ costs: 0,
3487
+ readiness: 0,
3488
+ analysis: 0,
3489
+ rawlog: 0
3490
+ }
3275
3491
  };
3276
3492
  }
3277
3493
  /**
@@ -3283,8 +3499,64 @@ var InteractiveDashboard = class {
3283
3499
  this.addActivity("Guardian started");
3284
3500
  this.setupKeyboardHandlers();
3285
3501
  this.startUpdateLoop();
3502
+ this.registerOutputManagerCallbacks();
3286
3503
  this.render();
3287
3504
  }
3505
+ /**
3506
+ * Register callbacks with OutputManager for rich content
3507
+ */
3508
+ registerOutputManagerCallbacks() {
3509
+ const outputManager = getOutputManager();
3510
+ outputManager.setMode("tui");
3511
+ outputManager.registerTUICallbacks({
3512
+ onBanner: (banner) => {
3513
+ this.state.skillBanners.unshift(banner);
3514
+ if (this.state.skillBanners.length > 5) {
3515
+ this.state.skillBanners.pop();
3516
+ }
3517
+ this.addActivity(`[BANNER] ${banner.skill}${banner.quote ? ": " + banner.quote.slice(0, 40) + "..." : ""}`);
3518
+ this.render();
3519
+ },
3520
+ onSnippet: (snippet) => {
3521
+ this.state.codeSnippets.set(this.state.selectedIssue, snippet);
3522
+ this.render();
3523
+ },
3524
+ onCost: (cost) => {
3525
+ this.state.costReport = cost;
3526
+ this.addActivity(`[COST] Fix: $${cost.fixNowCost} | Prod: $${cost.productionCost}`);
3527
+ this.render();
3528
+ },
3529
+ onReadiness: (readiness) => {
3530
+ this.state.readiness = readiness;
3531
+ this.addActivity(`[READY] Score: ${readiness.score}/100 - ${readiness.status.toUpperCase()}`);
3532
+ this.render();
3533
+ },
3534
+ onSemantic: (semantic) => {
3535
+ this.state.semanticAnalysis = semantic;
3536
+ this.addActivity(`[SEMANTIC] DataFlow: ${semantic.dataFlowIssues} | Race: ${semantic.raceConditions} | Auth: ${semantic.authIssues}`);
3537
+ this.render();
3538
+ },
3539
+ onAttack: (attack) => {
3540
+ this.state.attackSurface = attack;
3541
+ this.addActivity(`[ATTACK] ${attack.totalEndpoints} endpoints (${attack.unprotected} unprotected)`);
3542
+ this.render();
3543
+ },
3544
+ onActivity: (message) => {
3545
+ this.addActivity(message);
3546
+ this.render();
3547
+ },
3548
+ onLog: (level, message) => {
3549
+ const time = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false, hour: "2-digit", minute: "2-digit", second: "2-digit" });
3550
+ this.state.rawLog.unshift({ time, level, message });
3551
+ if (this.state.rawLog.length > 500) {
3552
+ this.state.rawLog.pop();
3553
+ }
3554
+ if (this.state.view === "rawlog") {
3555
+ this.render();
3556
+ }
3557
+ }
3558
+ });
3559
+ }
3288
3560
  /**
3289
3561
  * Stop the dashboard
3290
3562
  */
@@ -3294,6 +3566,9 @@ var InteractiveDashboard = class {
3294
3566
  clearInterval(this.updateInterval);
3295
3567
  }
3296
3568
  this.rl.close();
3569
+ const outputManager = getOutputManager();
3570
+ outputManager.clearTUICallbacks();
3571
+ outputManager.setMode("console");
3297
3572
  process.stdout.write("\x1B[2J\x1B[H\x1B[?25h");
3298
3573
  }
3299
3574
  /**
@@ -3404,6 +3679,53 @@ var InteractiveDashboard = class {
3404
3679
  this.addActivity(`[~] Learning: ${update.data.details || "analyzing patterns"}`);
3405
3680
  }
3406
3681
  break;
3682
+ // === Rich Content Events ===
3683
+ case "snippet":
3684
+ this.state.codeSnippets.set(this.state.selectedIssue, update.data);
3685
+ break;
3686
+ case "cost_report":
3687
+ this.state.costReport = update.data;
3688
+ this.addActivity(`[COST] Fix now: $${update.data.fixNowCost} | Production: $${update.data.productionCost}`);
3689
+ break;
3690
+ case "readiness_report":
3691
+ this.state.readiness = update.data;
3692
+ this.addActivity(`[READINESS] ${update.data.score}/100 - ${update.data.status}`);
3693
+ break;
3694
+ case "semantic_report":
3695
+ this.state.semanticAnalysis = update.data;
3696
+ {
3697
+ const sem = update.data;
3698
+ const total = sem.dataFlowIssues + sem.raceConditions + sem.authIssues;
3699
+ if (total > 0) {
3700
+ this.addActivity(`[SEMANTIC] ${total} issues (${sem.dataFlowIssues} dataflow, ${sem.raceConditions} race, ${sem.authIssues} auth)`);
3701
+ }
3702
+ }
3703
+ break;
3704
+ case "attack_surface":
3705
+ this.state.attackSurface = update.data;
3706
+ {
3707
+ const atk = update.data;
3708
+ this.addActivity(`[ATTACK] ${atk.totalEndpoints} endpoints, ${atk.unprotected} unprotected, risk ${atk.riskScore}/100`);
3709
+ }
3710
+ break;
3711
+ case "skill_banner":
3712
+ const banner = update.data;
3713
+ this.state.skillBanners.unshift(banner);
3714
+ if (this.state.skillBanners.length > 5) {
3715
+ this.state.skillBanners.pop();
3716
+ }
3717
+ this.addActivity(`[SKILL] ${banner.skill}${banner.quote ? ': "' + banner.quote.slice(0, 30) + '..."' : ""}`);
3718
+ break;
3719
+ case "raw_log":
3720
+ this.state.rawLog.unshift({
3721
+ time: update.data.time || new Date(update.timestamp).toLocaleTimeString("en-US", { hour12: false }),
3722
+ level: update.data.level,
3723
+ message: update.data.message
3724
+ });
3725
+ if (this.state.rawLog.length > 500) {
3726
+ this.state.rawLog.pop();
3727
+ }
3728
+ break;
3407
3729
  }
3408
3730
  if (this.isActive) {
3409
3731
  this.render();
@@ -3477,6 +3799,30 @@ var InteractiveDashboard = class {
3477
3799
  case "?":
3478
3800
  this.showHelp();
3479
3801
  break;
3802
+ // === NEW VIEW SHORTCUTS ===
3803
+ case "d":
3804
+ if (this.state.scanComplete && this.state.issues.length > 0) {
3805
+ this.goToView("details");
3806
+ }
3807
+ break;
3808
+ case "m":
3809
+ if (this.state.costReport) {
3810
+ this.goToView("costs");
3811
+ }
3812
+ break;
3813
+ case "r":
3814
+ if (this.state.readiness) {
3815
+ this.goToView("readiness");
3816
+ }
3817
+ break;
3818
+ case "a":
3819
+ if (this.state.semanticAnalysis || this.state.attackSurface) {
3820
+ this.goToView("analysis");
3821
+ }
3822
+ break;
3823
+ case "l":
3824
+ this.goToView("rawlog");
3825
+ break;
3480
3826
  }
3481
3827
  this.render();
3482
3828
  });
@@ -3629,6 +3975,22 @@ var InteractiveDashboard = class {
3629
3975
  case "files":
3630
3976
  this.renderFilesView(width);
3631
3977
  break;
3978
+ // === NEW VIEWS ===
3979
+ case "details":
3980
+ this.renderDetailsView(width, height);
3981
+ break;
3982
+ case "costs":
3983
+ this.renderCostsView(width, height);
3984
+ break;
3985
+ case "readiness":
3986
+ this.renderReadinessView(width, height);
3987
+ break;
3988
+ case "analysis":
3989
+ this.renderAnalysisView(width, height);
3990
+ break;
3991
+ case "rawlog":
3992
+ this.renderRawLogView(width, height);
3993
+ break;
3632
3994
  }
3633
3995
  }
3634
3996
  this.renderFooter(width);
@@ -3966,6 +4328,240 @@ var InteractiveDashboard = class {
3966
4328
  this.renderLine("", width);
3967
4329
  }
3968
4330
  }
4331
+ // ============================================
4332
+ // NEW VIEWS
4333
+ // ============================================
4334
+ /**
4335
+ * Render details view - selected issue with code snippet
4336
+ */
4337
+ renderDetailsView(width, _height) {
4338
+ const sectionBorder = colors.border(box.leftT + this.line(width - 2) + box.rightT);
4339
+ const filteredIssues = this.getFilteredIssues();
4340
+ const issue = filteredIssues[this.state.selectedIssue];
4341
+ if (!issue) {
4342
+ this.renderLine(" " + colors.dim("No issue selected. Press [b] to go back."), width);
4343
+ return;
4344
+ }
4345
+ const severityColor = issue.severity === "critical" ? colors.critical : issue.severity === "serious" ? colors.serious : issue.severity === "moderate" ? colors.moderate : colors.low;
4346
+ this.renderLine(" " + colors.header("ISSUE DETAILS") + " " + severityColor(`[${issue.severity.toUpperCase()}]`), width);
4347
+ this.bufferLine(sectionBorder);
4348
+ this.renderLine(" " + colors.dim("File:") + " " + issue.file, width);
4349
+ this.renderLine(" " + colors.dim("Line:") + " " + (issue.line || "?") + " " + colors.dim("Scout:") + " " + (issue.agent || "unknown"), width);
4350
+ this.renderLine("", width);
4351
+ this.renderLine(" " + colors.header("Issue"), width);
4352
+ const issueLines = this.wrapText(issue.issue, width - 8);
4353
+ for (const line of issueLines.slice(0, 4)) {
4354
+ this.renderLine(" " + severityColor(line), width);
4355
+ }
4356
+ this.renderLine("", width);
4357
+ this.bufferLine(sectionBorder);
4358
+ this.renderLine(" " + colors.header("CODE SNIPPET"), width);
4359
+ const snippet = this.state.codeSnippets.get(this.state.selectedIssue);
4360
+ if (snippet) {
4361
+ this.renderLine(" " + colors.dim(this.line(width - 6)), width);
4362
+ const maxLines = Math.min(snippet.lines.length, 10);
4363
+ for (let i = 0; i < maxLines; i++) {
4364
+ const lineNum = snippet.startLine + i;
4365
+ const isHighlight = lineNum === snippet.highlightLine;
4366
+ const prefix = isHighlight ? colors.critical("\u2192") : " ";
4367
+ const lineNumStr = colors.dim(lineNum.toString().padStart(4));
4368
+ const lineContent = isHighlight ? colors.yellow(snippet.lines[i] || "") : snippet.lines[i] || "";
4369
+ this.renderLine(" " + prefix + " " + lineNumStr + " " + colors.dim("\u2502") + " " + lineContent, width);
4370
+ }
4371
+ if (snippet.lines.length > 10) {
4372
+ this.renderLine(" " + colors.dim(` ... ${snippet.lines.length - 10} more lines`), width);
4373
+ }
4374
+ } else {
4375
+ this.renderLine(" " + colors.dim("No code snippet available. Snippet is loaded when issue is selected."), width);
4376
+ }
4377
+ this.renderLine("", width);
4378
+ this.bufferLine(sectionBorder);
4379
+ this.renderLine(" " + colors.success("SUGGESTED FIX"), width);
4380
+ const fixLines = this.wrapText(issue.fix, width - 8);
4381
+ for (const line of fixLines.slice(0, 4)) {
4382
+ this.renderLine(" " + colors.success(line), width);
4383
+ }
4384
+ if (issue.cwe || issue.owasp || issue.effort) {
4385
+ this.renderLine("", width);
4386
+ this.bufferLine(sectionBorder);
4387
+ this.renderLine(" " + colors.header("METADATA"), width);
4388
+ if (issue.cwe) this.renderLine(" " + colors.dim("CWE:") + " " + issue.cwe, width);
4389
+ if (issue.owasp) this.renderLine(" " + colors.dim("OWASP:") + " " + issue.owasp, width);
4390
+ if (issue.effort) this.renderLine(" " + colors.dim("Effort:") + " " + issue.effort, width);
4391
+ }
4392
+ }
4393
+ /**
4394
+ * Render costs view - Moneybags cost breakdown
4395
+ */
4396
+ renderCostsView(width, _height) {
4397
+ const sectionBorder = colors.border(box.leftT + this.line(width - 2) + box.rightT);
4398
+ this.renderLine(" " + colors.header("\u{1F4B0} COST ANALYSIS") + " " + colors.dim("(Moneybags)"), width);
4399
+ this.bufferLine(sectionBorder);
4400
+ const cost = this.state.costReport;
4401
+ if (!cost) {
4402
+ this.renderLine(" " + colors.dim("No cost data available. Run a full scan to get cost estimates."), width);
4403
+ this.renderLine("", width);
4404
+ return;
4405
+ }
4406
+ const fmt = (n) => n >= 1e6 ? `$${(n / 1e6).toFixed(2)}M` : n >= 1e3 ? `$${(n / 1e3).toFixed(1)}k` : `$${n}`;
4407
+ this.renderLine("", width);
4408
+ this.renderLine(" " + colors.header("SUMMARY"), width);
4409
+ this.renderLine(" " + colors.dim(this.line(width - 6)), width);
4410
+ const fixNowLabel = colors.success("Fix Now Cost:");
4411
+ const prodLabel = colors.critical("Production Cost:");
4412
+ const savingsLabel = colors.running("Potential Savings:");
4413
+ this.renderLine(" " + fixNowLabel + " " + colors.success(fmt(cost.fixNowCost)), width);
4414
+ this.renderLine(" " + prodLabel + " " + colors.critical(fmt(cost.productionCost)), width);
4415
+ this.renderLine(" " + savingsLabel + " " + colors.running(fmt(cost.savings)), width);
4416
+ this.renderLine("", width);
4417
+ const roi = cost.fixNowCost > 0 ? Math.round(cost.savings / cost.fixNowCost * 100) : 0;
4418
+ this.renderLine(" " + colors.dim("ROI:") + " " + colors.highlight(`${roi}%`) + " " + colors.dim("return on fixing these issues now"), width);
4419
+ this.renderLine("", width);
4420
+ if (cost.perIssue && cost.perIssue.length > 0) {
4421
+ this.bufferLine(sectionBorder);
4422
+ this.renderLine(" " + colors.header("PER-ISSUE BREAKDOWN"), width);
4423
+ this.renderLine(" " + colors.dim(this.line(width - 6)), width);
4424
+ const maxRows = Math.min(cost.perIssue.length, 8);
4425
+ for (let i = 0; i < maxRows; i++) {
4426
+ const item = cost.perIssue[i];
4427
+ if (!item) continue;
4428
+ const issueName = item.issue.slice(0, 40) + (item.issue.length > 40 ? "..." : "");
4429
+ this.renderLine(" " + colors.dim("\u2022") + " " + issueName.padEnd(45) + " " + colors.serious(fmt(item.cost)), width);
4430
+ }
4431
+ if (cost.perIssue.length > 8) {
4432
+ this.renderLine(" " + colors.dim(`... and ${cost.perIssue.length - 8} more`), width);
4433
+ }
4434
+ }
4435
+ this.renderLine("", width);
4436
+ }
4437
+ /**
4438
+ * Render readiness view - Production readiness checklist
4439
+ */
4440
+ renderReadinessView(width, _height) {
4441
+ const sectionBorder = colors.border(box.leftT + this.line(width - 2) + box.rightT);
4442
+ this.renderLine(" " + colors.header("\u{1F4CA} PRODUCTION READINESS"), width);
4443
+ this.bufferLine(sectionBorder);
4444
+ const readiness = this.state.readiness;
4445
+ if (!readiness) {
4446
+ this.renderLine(" " + colors.dim("No readiness data. Run production-ready agent for assessment."), width);
4447
+ return;
4448
+ }
4449
+ const statusColor = readiness.status === "ready" ? colors.success : readiness.status === "caution" ? colors.running : colors.critical;
4450
+ const statusIcon = readiness.status === "ready" ? "\u2713" : readiness.status === "caution" ? "~" : "\u2717";
4451
+ this.renderLine("", width);
4452
+ this.renderLine(" " + colors.header("STATUS"), width);
4453
+ this.renderLine(" " + colors.dim(this.line(width - 6)), width);
4454
+ this.renderLine(" " + statusColor(`[${statusIcon}] ${readiness.status.toUpperCase()}`), width);
4455
+ this.renderLine("", width);
4456
+ const scoreWidth = 40;
4457
+ const scoreFilled = Math.round(readiness.score / 100 * scoreWidth);
4458
+ const scoreEmpty = scoreWidth - scoreFilled;
4459
+ const scoreBar = statusColor("\u2588".repeat(scoreFilled)) + colors.dim("\u2591".repeat(scoreEmpty));
4460
+ this.renderLine(" " + colors.dim("Score:") + " " + scoreBar + " " + statusColor(`${readiness.score}/100`), width);
4461
+ this.renderLine("", width);
4462
+ this.bufferLine(sectionBorder);
4463
+ this.renderLine(" " + colors.header("REQUIREMENTS"), width);
4464
+ this.renderLine(" " + colors.dim(this.line(width - 6)), width);
4465
+ this.renderLine(" " + colors.dim("Met:") + " " + colors.highlight(`${readiness.requirementsMet}/${readiness.total}`), width);
4466
+ this.renderLine("", width);
4467
+ if (readiness.requirements && readiness.requirements.length > 0) {
4468
+ for (const req of readiness.requirements.slice(0, 10)) {
4469
+ const icon = req.met ? colors.success("\u2713") : colors.critical("\u2717");
4470
+ const text = req.met ? colors.dim(req.name) : req.name;
4471
+ this.renderLine(" " + icon + " " + text, width);
4472
+ }
4473
+ }
4474
+ this.renderLine("", width);
4475
+ }
4476
+ /**
4477
+ * Render analysis view - Semantic + Attack Surface
4478
+ */
4479
+ renderAnalysisView(width, _height) {
4480
+ const sectionBorder = colors.border(box.leftT + this.line(width - 2) + box.rightT);
4481
+ this.renderLine(" " + colors.header("\u{1F50D} ANALYSIS REPORT"), width);
4482
+ this.bufferLine(sectionBorder);
4483
+ const semantic = this.state.semanticAnalysis;
4484
+ if (semantic) {
4485
+ this.renderLine(" " + colors.header("SEMANTIC ANALYSIS"), width);
4486
+ this.renderLine(" " + colors.dim(this.line(width - 6)), width);
4487
+ if (semantic.dataFlowIssues > 0) {
4488
+ this.renderLine(" " + colors.critical("[!]") + " " + colors.critical(`${semantic.dataFlowIssues} Data Flow Vulnerabilities`), width);
4489
+ this.renderLine(" " + colors.dim("Untrusted input reaching dangerous sinks"), width);
4490
+ }
4491
+ if (semantic.raceConditions > 0) {
4492
+ this.renderLine(" " + colors.running("[~]") + " " + colors.running(`${semantic.raceConditions} Race Conditions`), width);
4493
+ this.renderLine(" " + colors.dim("TOCTOU, double-spend risks"), width);
4494
+ }
4495
+ if (semantic.authIssues > 0) {
4496
+ this.renderLine(" " + colors.critical("[!]") + " " + colors.critical(`${semantic.authIssues} Authentication Issues`), width);
4497
+ this.renderLine(" " + colors.dim("Missing or bypassable auth"), width);
4498
+ }
4499
+ const total = semantic.dataFlowIssues + semantic.raceConditions + semantic.authIssues;
4500
+ if (total === 0) {
4501
+ this.renderLine(" " + colors.success("\u2713 No semantic issues detected"), width);
4502
+ }
4503
+ this.renderLine("", width);
4504
+ }
4505
+ const attack = this.state.attackSurface;
4506
+ if (attack) {
4507
+ this.bufferLine(sectionBorder);
4508
+ this.renderLine(" " + colors.header("ATTACK SURFACE"), width);
4509
+ this.renderLine(" " + colors.dim(this.line(width - 6)), width);
4510
+ this.renderLine(" " + colors.dim("Endpoints:") + " " + colors.highlight(attack.totalEndpoints.toString()), width);
4511
+ if (attack.unprotected > 0) {
4512
+ this.renderLine(" " + colors.critical("Unprotected:") + " " + colors.critical(attack.unprotected.toString()), width);
4513
+ } else {
4514
+ this.renderLine(" " + colors.success("Unprotected:") + " " + colors.success("0"), width);
4515
+ }
4516
+ const riskWidth = 30;
4517
+ const riskFilled = Math.round(attack.riskScore / 100 * riskWidth);
4518
+ const riskEmpty = riskWidth - riskFilled;
4519
+ const riskColor = attack.riskScore > 70 ? colors.critical : attack.riskScore > 40 ? colors.running : colors.success;
4520
+ const riskBar = riskColor("\u2588".repeat(riskFilled)) + colors.dim("\u2591".repeat(riskEmpty));
4521
+ this.renderLine(" " + colors.dim("Risk Score:") + " " + riskBar + " " + riskColor(`${attack.riskScore}/100`), width);
4522
+ this.renderLine("", width);
4523
+ if (attack.endpoints && attack.endpoints.length > 0) {
4524
+ this.renderLine(" " + colors.dim("Top Endpoints:"), width);
4525
+ for (const ep of attack.endpoints.slice(0, 5)) {
4526
+ const authIcon = ep.auth ? colors.success("\u{1F512}") : colors.critical("\u{1F513}");
4527
+ const method = colors.dim(ep.method.padEnd(6));
4528
+ const path = ep.sensitive ? colors.serious(ep.path) : ep.path;
4529
+ this.renderLine(" " + authIcon + " " + method + " " + path, width);
4530
+ }
4531
+ }
4532
+ }
4533
+ if (!semantic && !attack) {
4534
+ this.renderLine(" " + colors.dim("No analysis data available. Run a full scan for semantic analysis."), width);
4535
+ }
4536
+ this.renderLine("", width);
4537
+ }
4538
+ /**
4539
+ * Render raw log view - All console output
4540
+ */
4541
+ renderRawLogView(width, height) {
4542
+ const sectionBorder = colors.border(box.leftT + this.line(width - 2) + box.rightT);
4543
+ const pageSize = Math.max(10, height - 15);
4544
+ const totalPages = Math.max(1, Math.ceil(this.state.rawLog.length / pageSize));
4545
+ this.renderLine(" " + colors.header("\u{1F4CB} RAW LOG") + " " + colors.dim(`Page ${this.state.rawLogPage + 1}/${totalPages}`) + " " + colors.highlight(`${this.state.rawLog.length}`) + colors.dim(" entries"), width);
4546
+ this.bufferLine(sectionBorder);
4547
+ if (this.state.rawLog.length === 0) {
4548
+ this.renderLine(" " + colors.dim("No log entries yet."), width);
4549
+ this.renderLine("", width);
4550
+ return;
4551
+ }
4552
+ const startIdx = this.state.rawLogPage * pageSize;
4553
+ const logs = this.state.rawLog.slice(startIdx, startIdx + pageSize);
4554
+ for (const entry of logs) {
4555
+ const levelColor = entry.level === "error" ? colors.critical : entry.level === "warn" ? colors.running : entry.level === "info" ? colors.success : colors.dim;
4556
+ const levelStr = levelColor(`[${entry.level.toUpperCase().padEnd(5)}]`);
4557
+ const timeStr = colors.dim(entry.time);
4558
+ const message = entry.message.slice(0, width - 25);
4559
+ this.renderLine(" " + timeStr + " " + levelStr + " " + message, width);
4560
+ }
4561
+ for (let i = logs.length; i < pageSize; i++) {
4562
+ this.renderLine("", width);
4563
+ }
4564
+ }
3969
4565
  /**
3970
4566
  * Render footer with controls
3971
4567
  */
@@ -3974,25 +4570,44 @@ var InteractiveDashboard = class {
3974
4570
  this.bufferLine(bottomBorder);
3975
4571
  const key = (k) => colors.border("[") + colors.highlight(k) + colors.border("]");
3976
4572
  const hint = (k, desc) => key(k) + colors.dim(` ${desc}`);
4573
+ const paneHints = [];
4574
+ if (this.state.issues.length > 0) paneHints.push(hint("d", "Details"));
4575
+ if (this.state.costReport) paneHints.push(hint("m", "Cost"));
4576
+ if (this.state.readiness) paneHints.push(hint("r", "Ready"));
4577
+ if (this.state.semanticAnalysis || this.state.attackSurface) paneHints.push(hint("a", "Analysis"));
4578
+ paneHints.push(hint("l", "Log"));
4579
+ const paneStr = paneHints.length > 0 ? " " + paneHints.join(" ") : "";
3977
4580
  if (!this.state.scanComplete) {
3978
- this.bufferLine(" " + hint("q", "Quit") + " " + hint("?", "Help"));
4581
+ this.bufferLine(" " + hint("l", "Log") + " " + hint("q", "Quit") + " " + hint("?", "Help"));
4582
+ } else if (this.state.view === "details" || this.state.view === "costs" || this.state.view === "readiness" || this.state.view === "analysis" || this.state.view === "rawlog") {
4583
+ this.bufferLine(" " + hint("b", "Back") + " " + hint("n/p", "Pages") + " " + hint("Tab", "Main") + " " + hint("?", "Help") + " " + hint("q", "Quit"));
3979
4584
  } else if (this.state.view === "agents") {
3980
- this.bufferLine(" " + hint("j/k", "Select") + " " + hint("Enter", "View issues") + " " + hint("n/p", "Pages") + " " + hint("Tab", "Views") + " " + hint("?", "Help") + " " + hint("q", "Quit"));
3981
- } else if (this.state.view === "issues" && this.state.previousView === "agents") {
3982
- this.bufferLine(" " + hint("b", "Back") + " " + hint("j/k", "Nav") + " " + hint("Enter", "Details") + " " + hint("1-4", "Severity") + " " + hint("f", "Search") + " " + hint("?", "Help") + " " + hint("q", "Quit"));
4585
+ this.bufferLine(" " + hint("j/k", "Select") + " " + hint("Enter", "View") + " " + hint("n/p", "Pages") + " " + hint("Tab", "Views") + paneStr + " " + hint("?", "Help") + " " + hint("q", "Quit"));
3983
4586
  } else if (this.state.view === "issues") {
3984
- this.bufferLine(" " + hint("j/k", "Nav") + " " + hint("Enter", "Details") + " " + hint("1-4", "Severity") + " " + hint("f", "Search") + " " + hint("s", "Scout") + " " + hint("c", "Clear") + " " + hint("Tab", "Views") + " " + hint("?", "Help") + " " + hint("q", "Quit"));
4587
+ this.bufferLine(" " + hint("j/k", "Nav") + " " + hint("Enter", "Details") + " " + hint("1-4", "Sev") + " " + hint("f", "Find") + " " + hint("Tab", "Views") + paneStr + " " + hint("?", "Help") + " " + hint("q", "Quit"));
3985
4588
  } else {
3986
- this.bufferLine(" " + hint("Tab", "Views") + " " + hint("n/p", "Pages") + " " + hint("?", "Help") + " " + hint("q", "Quit"));
4589
+ this.bufferLine(" " + hint("Tab", "Views") + " " + hint("n/p", "Pages") + paneStr + " " + hint("?", "Help") + " " + hint("q", "Quit"));
3987
4590
  }
3988
4591
  }
3989
4592
  // Helper methods
3990
4593
  switchView() {
3991
4594
  if (!this.state.scanComplete) return;
3992
- const views = ["overview", "issues", "agents", "files"];
3993
- const currentIndex = views.indexOf(this.state.view);
3994
- const nextIndex = (currentIndex + 1) % views.length;
3995
- this.state.view = views[nextIndex] ?? "overview";
4595
+ const mainViews = ["overview", "issues", "agents", "files"];
4596
+ const currentIndex = mainViews.indexOf(this.state.view);
4597
+ if (currentIndex >= 0) {
4598
+ const nextIndex = (currentIndex + 1) % mainViews.length;
4599
+ this.state.view = mainViews[nextIndex] ?? "overview";
4600
+ } else {
4601
+ this.state.view = "overview";
4602
+ }
4603
+ }
4604
+ /**
4605
+ * Navigate to a specific view
4606
+ */
4607
+ goToView(view) {
4608
+ if (!this.state.scanComplete && view !== "rawlog") return;
4609
+ this.state.previousView = this.state.view;
4610
+ this.state.view = view;
3996
4611
  }
3997
4612
  navigateUp() {
3998
4613
  if (this.state.view === "issues") {
@@ -4233,11 +4848,18 @@ var InteractiveDashboard = class {
4233
4848
  pLine(" " + colors.brand("TRIE GUARDIAN") + " " + colors.dim("-") + " " + colors.header("HELP"));
4234
4849
  console.log(colors.border(box.leftT + this.line(w - 2) + box.rightT));
4235
4850
  pLine(" " + colors.header("Navigation"));
4236
- keyLine("Tab", "Switch view (overview/issues/scouts/files)");
4851
+ keyLine("Tab", "Cycle main views (overview/issues/scouts/files)");
4237
4852
  keyLine("j/k", "Navigate up/down in lists");
4238
4853
  keyLine("n/p", "Next/previous page");
4239
4854
  keyLine("Enter", "View details / drill into scout");
4240
- keyLine("b", "Go back (after drilling into scout)");
4855
+ keyLine("b", "Go back to previous view");
4856
+ pLine("");
4857
+ pLine(" " + colors.header("Panes"));
4858
+ keyLine("d", "Issue Details with code snippet");
4859
+ keyLine("m", "Cost Analysis (Moneybags)");
4860
+ keyLine("r", "Production Readiness score");
4861
+ keyLine("a", "Analysis (Semantic + Attack Surface)");
4862
+ keyLine("l", "Raw Log viewer");
4241
4863
  pLine("");
4242
4864
  pLine(" " + colors.header("Filters"));
4243
4865
  keyLine("1-4", "Filter by severity (1=critical, 4=low)");
@@ -5585,6 +6207,13 @@ var TrieScanTool = class {
5585
6207
  const dashboard = interactiveEnabled ? args?.dashboard instanceof InteractiveDashboard ? args.dashboard : new InteractiveDashboard() : void 0;
5586
6208
  if (interactiveEnabled) {
5587
6209
  setInteractiveMode(true);
6210
+ getOutputManager().setMode("tui");
6211
+ } else {
6212
+ const isMCPContext = !process.stdout.isTTY;
6213
+ getOutputManager().setMode(isMCPContext ? "mcp" : "console");
6214
+ }
6215
+ if (streamingManager) {
6216
+ getOutputManager().setStreamingManager(streamingManager);
5588
6217
  }
5589
6218
  if (dashboard && streamingManager) {
5590
6219
  if (!(args?.dashboard instanceof InteractiveDashboard)) {
@@ -6243,6 +6872,22 @@ ${issue.fix}
6243
6872
 
6244
6873
  `;
6245
6874
  }
6875
+ const outputManager = getOutputManager();
6876
+ if (outputManager.getMode() === "mcp") {
6877
+ const accumulatedMarkdown = outputManager.getMarkdown();
6878
+ if (accumulatedMarkdown.trim()) {
6879
+ output2 += `---
6880
+
6881
+ `;
6882
+ output2 += `## Additional Analysis
6883
+
6884
+ `;
6885
+ output2 += accumulatedMarkdown;
6886
+ output2 += `
6887
+ `;
6888
+ }
6889
+ outputManager.clearBuffers();
6890
+ }
6246
6891
  output2 += `---
6247
6892
  `;
6248
6893
  output2 += `*Powered by Trie Agent \u2014 showing you what matters.*
@@ -6332,4 +6977,4 @@ export {
6332
6977
  InteractiveDashboard,
6333
6978
  TrieScanTool
6334
6979
  };
6335
- //# sourceMappingURL=chunk-3B2JBLSP.js.map
6980
+ //# sourceMappingURL=chunk-NM7ZVUHO.js.map