@cortexkit/aft-opencode 0.63.5 → 0.65.0

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 (52) hide show
  1. package/dist/bg-notifications.d.ts.map +1 -1
  2. package/dist/config-live-reload.d.ts +4 -28
  3. package/dist/config-live-reload.d.ts.map +1 -1
  4. package/dist/config.d.ts +11 -40
  5. package/dist/config.d.ts.map +1 -1
  6. package/dist/entry/server.js +1726 -674
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +1726 -674
  9. package/dist/lsp-auto-install.d.ts.map +1 -1
  10. package/dist/shared/session-directory.d.ts +11 -4
  11. package/dist/shared/session-directory.d.ts.map +1 -1
  12. package/dist/shared/status.d.ts +2 -6
  13. package/dist/shared/status.d.ts.map +1 -1
  14. package/dist/subc-tool-schemas.d.ts +4 -3
  15. package/dist/subc-tool-schemas.d.ts.map +1 -1
  16. package/dist/tool-registration.d.ts +1 -1
  17. package/dist/tool-registration.d.ts.map +1 -1
  18. package/dist/tools/_shared.d.ts +11 -17
  19. package/dist/tools/_shared.d.ts.map +1 -1
  20. package/dist/tools/bash.d.ts.map +1 -1
  21. package/dist/tools/bash_watch.d.ts +6 -3
  22. package/dist/tools/bash_watch.d.ts.map +1 -1
  23. package/dist/tools/definitions/v2.d.ts +26 -1
  24. package/dist/tools/definitions/v2.d.ts.map +1 -1
  25. package/dist/tools/inspect.d.ts +0 -15
  26. package/dist/tools/inspect.d.ts.map +1 -1
  27. package/dist/tui/preferences.d.ts +1 -1
  28. package/dist/tui/shared-sidebar.d.ts +4 -0
  29. package/dist/tui/shared-sidebar.d.ts.map +1 -0
  30. package/dist/tui/v2-status.d.ts +3 -2
  31. package/dist/tui/v2-status.d.ts.map +1 -1
  32. package/dist/v2-session-lifecycle.d.ts.map +1 -1
  33. package/dist/workflow-hints.d.ts +1 -5
  34. package/dist/workflow-hints.d.ts.map +1 -1
  35. package/package.json +14 -12
  36. package/src/shared/session-directory.ts +90 -17
  37. package/src/shared/status.ts +6 -26
  38. package/src/tui/index.tsx +8 -28
  39. package/src/tui/preferences.ts +1 -1
  40. package/src/tui/shared-sidebar.ts +14 -0
  41. package/src/tui/sidebar-view.tsx +257 -283
  42. package/src/tui/v2-status.ts +5 -14
  43. package/src/tui-compiled/index.tsx +6 -44
  44. package/src/tui-compiled/preferences.ts +1 -1
  45. package/src/tui-compiled/shared-sidebar-host.tsx +816 -0
  46. package/src/tui-compiled/shared-sidebar-local.tsx +816 -0
  47. package/src/tui-compiled/shared-sidebar.LICENSE +21 -0
  48. package/src/tui-compiled/shared-sidebar.ts +14 -0
  49. package/src/tui-compiled/sidebar-view.tsx +185 -261
  50. package/src/tui-compiled/sidebar.tsx +1 -0
  51. package/src/tui-compiled/v2-status.ts +5 -14
  52. package/src/tui-compiled/v2.tsx +1 -0
@@ -33,6 +33,7 @@ import {
33
33
  seedCollapsedFromPrefs,
34
34
  watchTuiPreferences,
35
35
  } from "./preferences";
36
+ import { SidebarFrame, type SidebarTheme } from "./shared-sidebar";
36
37
 
37
38
  const SINGLE_BORDER = { type: "single" } as any;
38
39
 
@@ -301,7 +302,6 @@ export function degradedReasonLabel(reason: string): string {
301
302
 
302
303
  export interface HealthLights {
303
304
  diagnostics: HealthLightTone;
304
- code: HealthLightTone;
305
305
  todos: HealthLightTone;
306
306
  }
307
307
 
@@ -317,15 +317,9 @@ export function collapsedHealthLights(statusBar: StatusBar | undefined): HealthL
317
317
  : statusBar.errors === 0 && statusBar.warnings === 0
318
318
  ? "ok"
319
319
  : "muted";
320
- const codeValues = [statusBar.dead_code, statusBar.unused_exports, statusBar.duplicates];
321
- const code: HealthLightTone = codeValues.some((value) => value !== undefined && value > 0)
322
- ? "warn"
323
- : codeValues.every((value) => value === 0)
324
- ? "ok"
325
- : "muted";
326
320
  const todos: HealthLightTone =
327
321
  statusBar.todos === undefined ? "muted" : statusBar.todos > 0 ? "warn" : "ok";
328
- return { diagnostics, code, todos };
322
+ return { diagnostics, todos };
329
323
  }
330
324
 
331
325
  export interface AftSidebarPanelProps {
@@ -436,317 +430,297 @@ export const AftSidebarPanel = (props: AftSidebarPanelProps) => {
436
430
  // entry. Keep this muted and separate from the DEGRADED badge above.
437
431
  const worktreeNote = () => worktreeCacheRoleNote(s()?.cache_role);
438
432
 
439
- return (
440
- <box
441
- width="100%"
442
- flexDirection="column"
443
- border={SINGLE_BORDER}
444
- borderColor={props.palette.border}
445
- paddingTop={1}
446
- paddingBottom={1}
447
- paddingLeft={1}
448
- paddingRight={1}
449
- >
450
- {/* Header: triangle toggle + AFT badge + binary version + degraded badge.
451
- Clicking the header row collapses/expands the panel (mirrors OpenCode's
452
- native MCP sidebar section). Only interactive once initialized — the
453
- lazy-bridge placeholder has nothing to collapse. */}
454
- <box
455
- flexDirection="row"
456
- justifyContent="space-between"
457
- alignItems="center"
458
- onMouseDown={() => {
459
- if (notInitialized()) return;
460
- props.onToggleCollapsed();
461
- }}
462
- >
463
- <box flexDirection="row" alignItems="center">
464
- {/* Triangle lives inside the accent badge so the toggle reads as one
465
- unit: "▶ AFT" / "▼ AFT". Hidden pre-init (nothing to collapse). */}
466
- <box paddingLeft={1} paddingRight={1} backgroundColor={props.palette.accent}>
467
- <text fg={badgeForeground(props.palette.accent, props.palette.background)}>
468
- <b>
469
- {notInitialized() ? "" : props.collapsed ? "▶ " : "▼ "}
470
- {props.prefs.header.label}
471
- </b>
472
- </text>
473
- </box>
474
- {s()?.degraded && degradedHeaderMarker(s()?.degraded_reasons ?? []).calm && (
475
- <box marginLeft={1}>
476
- <text fg={props.palette.warning}>
477
- {degradedHeaderMarker(s()?.degraded_reasons ?? []).text}
478
- </text>
479
- </box>
480
- )}
481
- {s()?.degraded && !degradedHeaderMarker(s()?.degraded_reasons ?? []).calm && (
482
- <box
483
- paddingLeft={1}
484
- paddingRight={1}
485
- marginLeft={1}
486
- backgroundColor={props.palette.warning}
487
- >
488
- <text fg={badgeForeground(props.palette.warning, props.palette.background)}>
489
- <b>{degradedHeaderMarker(s()?.degraded_reasons ?? []).text}</b>
490
- </text>
491
- </box>
492
- )}
433
+ const headerMarkers = () => (
434
+ <>
435
+ {s()?.degraded && degradedHeaderMarker(s()?.degraded_reasons ?? []).calm && (
436
+ <box marginLeft={1}>
437
+ <text fg={props.palette.warning}>
438
+ {degradedHeaderMarker(s()?.degraded_reasons ?? []).text}
439
+ </text>
493
440
  </box>
494
- {!notInitialized() && props.prefs.header.showVersion && (
495
- <text fg={props.palette.textMuted}>v{s()?.version ?? props.pluginVersion}</text>
496
- )}
497
- </box>
441
+ )}
442
+ {s()?.degraded && !degradedHeaderMarker(s()?.degraded_reasons ?? []).calm && (
443
+ <box
444
+ paddingLeft={1}
445
+ paddingRight={1}
446
+ marginLeft={1}
447
+ backgroundColor={props.palette.warning}
448
+ >
449
+ <text fg={badgeForeground(props.palette.warning, props.palette.background)}>
450
+ <b>{degradedHeaderMarker(s()?.degraded_reasons ?? []).text}</b>
451
+ </text>
452
+ </box>
453
+ )}
454
+ </>
455
+ );
498
456
 
499
- {/* Degraded reason — explains why heavy tools (aft_search, aft_callgraph)
500
- are disabled. Surface this prominently so users know to open a real
501
- project subdirectory if they want full features. */}
457
+ const notices = () => (
458
+ <>
459
+ {/* These explanations remain visible when the metric rows are collapsed. */}
502
460
  {s()?.degraded && degradedSummary() && (
503
461
  <box marginTop={1} width="100%">
504
462
  <text fg={props.palette.warning}>⚠ {degradedSummary()}</text>
505
463
  </box>
506
464
  )}
507
-
508
465
  {!notInitialized() && worktreeNote() && (
509
466
  <box marginTop={1} width="100%">
510
467
  <text fg={props.palette.textMuted}>{worktreeNote()}</text>
511
468
  </box>
512
469
  )}
513
-
514
- {/* Lazy-bridge placeholder. AFT skips spawning the `aft` binary at
515
- plugin init to keep memory/CPU low on OpenCode Desktop sessions
516
- that have many projects pinned in the sidebar. The RPC server
517
- returns a synthetic `cache_role === "not_initialized"` snapshot
518
- until the first tool call routes through `callBridge()` and warms
519
- the bridge. Show the explanatory message instead of empty status
520
- rows so users understand why metrics are blank. */}
521
470
  {notInitialized() && (
522
471
  <box marginTop={1} width="100%">
523
472
  {s()!.config_error ? (
524
- // Config error state: no bridge will ever start in this process,
525
- // so the placeholder text would mislead; show the error instead.
526
473
  <text fg={props.palette.error}>✖ {s()!.message}</text>
527
474
  ) : (
528
475
  <text fg={props.palette.textMuted}>{s()!.message || NOT_STARTED_STATUS_TEXT}</text>
529
476
  )}
530
477
  </box>
531
478
  )}
479
+ </>
480
+ );
532
481
 
533
- {/* Collapsed view — condensed status dots + compact compression. Shown
482
+ return (
483
+ <box
484
+ width="100%"
485
+ flexDirection="column"
486
+ border={SINGLE_BORDER}
487
+ borderColor={props.palette.border}
488
+ paddingTop={1}
489
+ paddingBottom={1}
490
+ paddingLeft={1}
491
+ paddingRight={1}
492
+ >
493
+ <SidebarFrame
494
+ header={{
495
+ badge: props.prefs.header.label,
496
+ version:
497
+ !notInitialized() && props.prefs.header.showVersion
498
+ ? `v${s()?.version ?? props.pluginVersion}`
499
+ : undefined,
500
+ afterBadge: headerMarkers,
501
+ }}
502
+ accounts={[]}
503
+ theme={
504
+ {
505
+ ...props.palette,
506
+ // The shared background role is used only as the badge foreground.
507
+ background: badgeForeground(props.palette.accent, props.palette.background),
508
+ } as SidebarTheme
509
+ }
510
+ appearance={{
511
+ barWidth: 0,
512
+ barFilledChar: "",
513
+ barEmptyChar: "",
514
+ warnThreshold: 70,
515
+ errorThreshold: 90,
516
+ }}
517
+ showQuota={false}
518
+ now={0}
519
+ collapsed={props.collapsed}
520
+ collapsible={!notInitialized()}
521
+ onToggle={props.onToggleCollapsed}
522
+ collapsedSections={() => (
523
+ <>
524
+ {notices()}
525
+ {/* Collapsed view — condensed status dots + compact compression. Shown
534
526
  only when initialized AND collapsed. Three rows mirroring the section
535
527
  order of the expanded grid. */}
536
- {!notInitialized() && props.collapsed && (
537
- <box width="100%" flexDirection="column">
538
- {props.prefs.sections.searchIndex && (
539
- <CollapsedRow palette={props.palette} label="Search Index">
540
- <text fg={toneColor(props.palette, searchStatus().tone)}>●</text>
541
- </CollapsedRow>
542
- )}
543
- {props.prefs.sections.semanticIndex && (
544
- <CollapsedRow palette={props.palette} label="Semantic Index">
545
- <text fg={toneColor(props.palette, semanticStatus().tone)}>●</text>
546
- </CollapsedRow>
547
- )}
548
- {props.prefs.sections.codeHealth && collapsedHealthLights(statusBar()) && (
549
- <CollapsedRow palette={props.palette} label="Code Health">
550
- <box flexDirection="row" gap={1}>
551
- <text
552
- fg={toneColor(props.palette, collapsedHealthLights(statusBar())!.diagnostics)}
553
- >
554
- ●
555
- </text>
556
- <text fg={toneColor(props.palette, collapsedHealthLights(statusBar())!.code)}>
557
- ●
558
- </text>
559
- <text fg={toneColor(props.palette, collapsedHealthLights(statusBar())!.todos)}>
560
- ●
561
- </text>
528
+ {!notInitialized() && props.collapsed && (
529
+ <box width="100%" flexDirection="column">
530
+ {props.prefs.sections.searchIndex && (
531
+ <CollapsedRow palette={props.palette} label="Search Index">
532
+ <text fg={toneColor(props.palette, searchStatus().tone)}>●</text>
533
+ </CollapsedRow>
534
+ )}
535
+ {props.prefs.sections.semanticIndex && (
536
+ <CollapsedRow palette={props.palette} label="Semantic Index">
537
+ <text fg={toneColor(props.palette, semanticStatus().tone)}>●</text>
538
+ </CollapsedRow>
539
+ )}
540
+ {props.prefs.sections.codeHealth && collapsedHealthLights(statusBar()) && (
541
+ <CollapsedRow palette={props.palette} label="Code Health">
542
+ <box flexDirection="row" gap={1}>
543
+ <text
544
+ fg={toneColor(
545
+ props.palette,
546
+ collapsedHealthLights(statusBar())!.diagnostics,
547
+ )}
548
+ >
549
+ ●
550
+ </text>
551
+ <text
552
+ fg={toneColor(props.palette, collapsedHealthLights(statusBar())!.todos)}
553
+ >
554
+ ●
555
+ </text>
556
+ </box>
557
+ </CollapsedRow>
558
+ )}
559
+ {props.prefs.sections.compression &&
560
+ collapsedCompressionValue(s()?.compression) && (
561
+ <CollapsedRow palette={props.palette} label="Compression">
562
+ <text fg={props.palette.textMuted}>
563
+ <b>{collapsedCompressionValue(s()?.compression)}</b>
564
+ </text>
565
+ </CollapsedRow>
566
+ )}
562
567
  </box>
563
- </CollapsedRow>
564
- )}
565
- {props.prefs.sections.compression && collapsedCompressionValue(s()?.compression) && (
566
- <CollapsedRow palette={props.palette} label="Compression">
567
- <text fg={props.palette.textMuted}>
568
- <b>{collapsedCompressionValue(s()?.compression)}</b>
569
- </text>
570
- </CollapsedRow>
571
- )}
572
- </box>
573
- )}
574
-
575
- {/* Search index */}
576
- {!notInitialized() && !props.collapsed && (
577
- <>
578
- {props.prefs.sections.searchIndex && (
579
- <>
580
- <SectionHeader palette={props.palette} title="Search Index" />
581
- <StatRow
582
- palette={props.palette}
583
- label="Status"
584
- value={searchStatus().label}
585
- tone={searchStatus().tone}
586
- />
587
- {(s()?.search_index?.files ?? null) != null && (
588
- <StatRow
589
- palette={props.palette}
590
- label="Files"
591
- value={formatCount(s()!.search_index.files)}
592
- tone="muted"
593
- />
594
- )}
595
- <StatRow
596
- palette={props.palette}
597
- label="Disk"
598
- value={formatBytes(trigramBytes())}
599
- tone="muted"
600
- />
601
- </>
602
- )}
568
+ )}
569
+ </>
570
+ )}
571
+ sections={() => (
572
+ <>
573
+ {notices()}
574
+ {/* Search index */}
575
+ {!notInitialized() && !props.collapsed && (
576
+ <>
577
+ {props.prefs.sections.searchIndex && (
578
+ <>
579
+ <SectionHeader palette={props.palette} title="Search Index" />
580
+ <StatRow
581
+ palette={props.palette}
582
+ label="Status"
583
+ value={searchStatus().label}
584
+ tone={searchStatus().tone}
585
+ />
586
+ {(s()?.search_index?.files ?? null) != null && (
587
+ <StatRow
588
+ palette={props.palette}
589
+ label="Files"
590
+ value={formatCount(s()!.search_index.files)}
591
+ tone="muted"
592
+ />
593
+ )}
594
+ <StatRow
595
+ palette={props.palette}
596
+ label="Disk"
597
+ value={formatBytes(trigramBytes())}
598
+ tone="muted"
599
+ />
600
+ </>
601
+ )}
603
602
 
604
- {props.prefs.sections.semanticIndex && (
605
- <>
606
- <SectionHeader palette={props.palette} title="Semantic Index" />
607
- <StatRow
608
- palette={props.palette}
609
- label="Status"
610
- value={semanticStatus().label}
611
- tone={semanticStatus().tone}
612
- />
613
- {semanticRefreshing() && (
614
- <box width="100%">
615
- <text fg={props.palette.textMuted}>{semanticRefreshing()}</text>
616
- </box>
617
- )}
618
- {/* When loading, magic-context-style progress hint helps users see
619
- background work is making progress instead of stuck. */}
620
- {s()?.semantic_index?.status === "loading" &&
621
- s()?.semantic_index?.entries_total != null &&
622
- s()!.semantic_index.entries_total! > 0 && (
623
- <StatRow
624
- palette={props.palette}
625
- label="Progress"
626
- value={`${formatCount(s()!.semantic_index.entries_done)} / ${formatCount(
627
- s()!.semantic_index.entries_total,
628
- )}`}
629
- tone="warn"
630
- />
603
+ {props.prefs.sections.semanticIndex && (
604
+ <>
605
+ <SectionHeader palette={props.palette} title="Semantic Index" />
606
+ <StatRow
607
+ palette={props.palette}
608
+ label="Status"
609
+ value={semanticStatus().label}
610
+ tone={semanticStatus().tone}
611
+ />
612
+ {semanticRefreshing() && (
613
+ <box width="100%">
614
+ <text fg={props.palette.textMuted}>{semanticRefreshing()}</text>
615
+ </box>
616
+ )}
617
+ {/* Show loading progress so background work does not look stalled. */}
618
+ {s()?.semantic_index?.status === "loading" &&
619
+ s()?.semantic_index?.entries_total != null &&
620
+ s()!.semantic_index.entries_total! > 0 && (
621
+ <StatRow
622
+ palette={props.palette}
623
+ label="Progress"
624
+ value={`${formatCount(s()!.semantic_index.entries_done)} / ${formatCount(
625
+ s()!.semantic_index.entries_total,
626
+ )}`}
627
+ tone="warn"
628
+ />
629
+ )}
630
+ {(s()?.semantic_index?.entries ?? null) != null && (
631
+ <StatRow
632
+ palette={props.palette}
633
+ label="Entries"
634
+ value={formatCount(s()!.semantic_index.entries)}
635
+ tone="muted"
636
+ />
637
+ )}
638
+ <StatRow
639
+ palette={props.palette}
640
+ label="Disk"
641
+ value={formatBytes(semanticBytes())}
642
+ tone="muted"
643
+ />
644
+ </>
631
645
  )}
632
- {(s()?.semantic_index?.entries ?? null) != null && (
633
- <StatRow
634
- palette={props.palette}
635
- label="Entries"
636
- value={formatCount(s()!.semantic_index.entries)}
637
- tone="muted"
638
- />
639
- )}
640
- <StatRow
641
- palette={props.palette}
642
- label="Disk"
643
- value={formatBytes(semanticBytes())}
644
- tone="muted"
645
- />
646
- </>
647
- )}
648
646
 
649
- {/* Human health values are optional. A category stays absent until the
647
+ {/* Human health values are optional. A category stays absent until the
650
648
  server proves it, rather than appearing as a clean zero. */}
651
- {props.prefs.sections.codeHealth && statusBar() && (
652
- <>
653
- <SectionHeader
654
- palette={props.palette}
655
- title={statusBar()!.tier2_stale ? "Code Health ~" : "Code Health"}
656
- />
657
- {(statusBar()!.disabled_categories ?? []).map((key) => (
658
- <StatRow
659
- palette={props.palette}
660
- label={key.replaceAll("_", " ")}
661
- value="○ off"
662
- tone="muted"
663
- />
664
- ))}
665
- {statusBar()!.errors !== undefined && (
666
- <StatRow
667
- palette={props.palette}
668
- label="Errors"
669
- value={formatCount(statusBar()!.errors)}
670
- tone={statusBar()!.errors! > 0 ? "err" : "muted"}
671
- />
672
- )}
673
- {statusBar()!.warnings !== undefined && (
674
- <StatRow
675
- palette={props.palette}
676
- label="Warnings"
677
- value={formatCount(statusBar()!.warnings)}
678
- tone={statusBar()!.warnings! > 0 ? "warn" : "muted"}
679
- />
680
- )}
681
- {statusBar()!.dead_code !== undefined && (
682
- <StatRow
683
- palette={props.palette}
684
- label="Dead Code"
685
- value={formatCount(statusBar()!.dead_code)}
686
- tone="muted"
687
- />
688
- )}
689
- {statusBar()!.unused_exports !== undefined && (
690
- <StatRow
691
- palette={props.palette}
692
- label="Unused Exports"
693
- value={formatCount(statusBar()!.unused_exports)}
694
- tone="muted"
695
- />
696
- )}
697
- {statusBar()!.duplicates !== undefined && (
698
- <StatRow
699
- palette={props.palette}
700
- label="Duplicates"
701
- value={formatCount(statusBar()!.duplicates)}
702
- tone="muted"
703
- />
704
- )}
705
- {statusBar()!.todos !== undefined && (
706
- <StatRow
707
- palette={props.palette}
708
- label="TODOs"
709
- value={formatCount(statusBar()!.todos)}
710
- tone="muted"
711
- />
712
- )}
713
- </>
714
- )}
649
+ {props.prefs.sections.codeHealth && statusBar() && (
650
+ <>
651
+ <SectionHeader palette={props.palette} title="Code Health" />
652
+ {(statusBar()!.disabled_categories ?? []).map((key) => (
653
+ <StatRow
654
+ palette={props.palette}
655
+ label={key.replaceAll("_", " ")}
656
+ value="○ off"
657
+ tone="muted"
658
+ />
659
+ ))}
660
+ {statusBar()!.errors !== undefined && (
661
+ <StatRow
662
+ palette={props.palette}
663
+ label="Errors"
664
+ value={formatCount(statusBar()!.errors)}
665
+ tone={statusBar()!.errors! > 0 ? "err" : "muted"}
666
+ />
667
+ )}
668
+ {statusBar()!.warnings !== undefined && (
669
+ <StatRow
670
+ palette={props.palette}
671
+ label="Warnings"
672
+ value={formatCount(statusBar()!.warnings)}
673
+ tone={statusBar()!.warnings! > 0 ? "warn" : "muted"}
674
+ />
675
+ )}
676
+ {statusBar()!.todos !== undefined && (
677
+ <StatRow
678
+ palette={props.palette}
679
+ label="TODOs"
680
+ value={formatCount(statusBar()!.todos)}
681
+ tone="muted"
682
+ />
683
+ )}
684
+ </>
685
+ )}
715
686
 
716
- {/* Compression aggregates. Tabular layout matching Search/Semantic
687
+ {/* Compression aggregates. Tabular layout matching Search/Semantic
717
688
  Index above: each scope ("Session", "Project") renders as a
718
689
  subheader followed by two StatRows (Tokens Saved, Compression
719
690
  Ratio). Keeps numbers right-aligned in the value column instead
720
691
  of jamming them after the label on the same line. */}
721
- {props.prefs.sections.compression && compressionRows().length > 0 && (
722
- <>
723
- <SectionHeader palette={props.palette} title="Compression" />
724
- {compressionRows().map((row) =>
725
- row.kind === "scope" ? (
726
- <box width="100%">
727
- <text fg={props.palette.text}>{row.label}</text>
728
- </box>
729
- ) : (
730
- <StatRow
731
- palette={props.palette}
732
- label={row.label}
733
- value={row.value}
734
- tone="muted"
735
- />
736
- ),
737
- )}
738
- </>
739
- )}
692
+ {props.prefs.sections.compression && compressionRows().length > 0 && (
693
+ <>
694
+ <SectionHeader palette={props.palette} title="Compression" />
695
+ {compressionRows().map((row) =>
696
+ row.kind === "scope" ? (
697
+ <box width="100%">
698
+ <text fg={props.palette.text}>{row.label}</text>
699
+ </box>
700
+ ) : (
701
+ <StatRow
702
+ palette={props.palette}
703
+ label={row.label}
704
+ value={row.value}
705
+ tone="muted"
706
+ />
707
+ ),
708
+ )}
709
+ </>
710
+ )}
740
711
 
741
- {/* Surface failures clearly so users know to act (install ONNX,
712
+ {/* Surface failures clearly so users know to act (install ONNX Runtime,
742
713
  fix config, etc.) rather than silently leaving the panel "off". */}
743
- {s()?.semantic_index?.status === "failed" && s()?.semantic_index?.error && (
744
- <box marginTop={1} width="100%">
745
- <text fg={props.palette.error}>⚠ {s()!.semantic_index.error}</text>
746
- </box>
747
- )}
748
- </>
749
- )}
714
+ {s()?.semantic_index?.status === "failed" && s()?.semantic_index?.error && (
715
+ <box marginTop={1} width="100%">
716
+ <text fg={props.palette.error}>⚠ {s()!.semantic_index.error}</text>
717
+ </box>
718
+ )}
719
+ </>
720
+ )}
721
+ </>
722
+ )}
723
+ />
750
724
  </box>
751
725
  );
752
726
  };
@@ -27,8 +27,9 @@ function diagnosticsPart(bar: StatusBar): string {
27
27
  * The V2 footer segment. "AFT starting…" is only true before the bridge has
28
28
  * delivered a real snapshot. After that the footer shows every health category
29
29
  * that has a value and `?` for any that does not, because a producer that is
30
- * unavailable (for example dead-code when the callgraph store cannot be used)
31
- * can leave the complete `status_bar` missing for the whole session.
30
+ * unavailable (for example no language server) can leave the complete
31
+ * `status_bar` missing for the whole session. Dead code, unused exports and
32
+ * duplicates are not shown: they are computed only by aft_inspect.
32
33
  */
33
34
  export function formatAftStatusSegment(status: AftStatusSnapshot | null): string {
34
35
  // The config error state never produces a real snapshot; say so instead of
@@ -36,12 +37,7 @@ export function formatAftStatusSegment(status: AftStatusSnapshot | null): string
36
37
  if (status?.config_error) return "AFT config error";
37
38
  if (!status || status.cache_role === "not_initialized") return "AFT starting…";
38
39
  const bar: StatusBar = status.status_bar ?? status.status_bar_values ?? {};
39
- const stale = bar.tier2_stale ? "~" : "";
40
- return (
41
- `AFT ${diagnosticsPart(bar)} | ` +
42
- `${stale}D${count(bar.dead_code, bar.disabled_categories?.includes("dead_code"))} U${count(bar.unused_exports, bar.disabled_categories?.includes("unused_exports"))} ` +
43
- `C${count(bar.duplicates, bar.disabled_categories?.includes("duplicates"))} | T${count(bar.todos, bar.disabled_categories?.includes("todos"))}`
44
- );
40
+ return `AFT ${diagnosticsPart(bar)} | T${count(bar.todos, bar.disabled_categories?.includes("todos"))}`;
45
41
  }
46
42
 
47
43
  export type AftSidebarSummary = {
@@ -53,12 +49,7 @@ export type AftSidebarSummary = {
53
49
  };
54
50
  function healthSummary(bar: StatusBar | undefined): string {
55
51
  if (!bar) return "health pending";
56
- const stale = bar.tier2_stale ? "~" : "";
57
- return (
58
- `${diagnosticsPart(bar)} ` +
59
- `${stale}D${count(bar.dead_code, bar.disabled_categories?.includes("dead_code"))} U${count(bar.unused_exports, bar.disabled_categories?.includes("unused_exports"))} ` +
60
- `C${count(bar.duplicates, bar.disabled_categories?.includes("duplicates"))} T${count(bar.todos, bar.disabled_categories?.includes("todos"))}`
61
- );
52
+ return `${diagnosticsPart(bar)} T${count(bar.todos, bar.disabled_categories?.includes("todos"))}`;
62
53
  }
63
54
 
64
55
  /**