@cortexkit/aft-opencode 0.50.2 → 0.51.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.
@@ -17,6 +17,7 @@ import {
17
17
  formatSemanticRefreshing,
18
18
  type StatusBar,
19
19
  type StatusCompression,
20
+ worktreeCacheRoleNote,
20
21
  } from "../shared/status";
21
22
  import { resolveCortexKitStorageRoot } from "../shared/storage-paths";
22
23
  import { badgeTextColor } from "./badge-contrast";
@@ -193,7 +194,7 @@ export function collapsedCompressionValue(
193
194
  return `${formatCount(savings_tokens)} / ${pct}%`;
194
195
  }
195
196
 
196
- export type HealthLightTone = "ok" | "warn" | "err";
197
+ export type HealthLightTone = "ok" | "warn" | "err" | "muted";
197
198
 
198
199
  // Degraded-mode reason → human-readable hint. Distinct strings per reason
199
200
  // because the UX direction is different: "home_root" tells the user to open a
@@ -215,26 +216,31 @@ export function degradedReasonLabel(reason: string): string {
215
216
  }
216
217
 
217
218
  export interface HealthLights {
218
- // Diagnostics: red if any errors, yellow if any warnings, else green.
219
219
  diagnostics: HealthLightTone;
220
- // Code cruft: yellow if there is any dead code, unused export, or duplicate,
221
- // green when zero. Never red — cruft is not a build failure.
222
220
  code: HealthLightTone;
223
- // TODOs: yellow if any, else green.
224
221
  todos: HealthLightTone;
225
222
  }
226
223
 
227
- // Three traffic lights for the collapsed view, replacing the cramped
228
- // `E· W· | D· U· C· | T·` string. Returns null until populated.
224
+ // Missing categories are intentionally muted: a green light requires an
225
+ // explicit zero for every category that feeds that light.
229
226
  export function collapsedHealthLights(statusBar: StatusBar | undefined): HealthLights | null {
230
227
  if (!statusBar) return null;
231
228
  const diagnostics: HealthLightTone =
232
- statusBar.errors > 0 ? "err" : statusBar.warnings > 0 ? "warn" : "ok";
233
- const code: HealthLightTone =
234
- statusBar.dead_code > 0 || statusBar.unused_exports > 0 || statusBar.duplicates > 0
235
- ? "warn"
236
- : "ok";
237
- const todos: HealthLightTone = statusBar.todos > 0 ? "warn" : "ok";
229
+ statusBar.errors !== undefined && statusBar.errors > 0
230
+ ? "err"
231
+ : statusBar.warnings !== undefined && statusBar.warnings > 0
232
+ ? "warn"
233
+ : statusBar.errors === 0 && statusBar.warnings === 0
234
+ ? "ok"
235
+ : "muted";
236
+ const codeValues = [statusBar.dead_code, statusBar.unused_exports, statusBar.duplicates];
237
+ const code: HealthLightTone = codeValues.some((value) => value !== undefined && value > 0)
238
+ ? "warn"
239
+ : codeValues.every((value) => value === 0)
240
+ ? "ok"
241
+ : "muted";
242
+ const todos: HealthLightTone =
243
+ statusBar.todos === undefined ? "muted" : statusBar.todos > 0 ? "warn" : "ok";
238
244
  return { diagnostics, code, todos };
239
245
  }
240
246
 
@@ -561,6 +567,10 @@ const SidebarContent = (props: {
561
567
  return reasons.map(degradedReasonLabel).join("; ");
562
568
  };
563
569
 
570
+ // Worktree borrow is a shared-index arrangement, not a degraded_reasons
571
+ // entry. Keep this muted and separate from the DEGRADED badge above.
572
+ const worktreeNote = () => worktreeCacheRoleNote(s()?.cache_role);
573
+
564
574
  return (
565
575
  <box
566
576
  width="100%"
@@ -627,6 +637,12 @@ const SidebarContent = (props: {
627
637
  </box>
628
638
  )}
629
639
 
640
+ {!notInitialized() && worktreeNote() && (
641
+ <box marginTop={1} width="100%">
642
+ <text fg={props.theme.textMuted}>{worktreeNote()}</text>
643
+ </box>
644
+ )}
645
+
630
646
  {/* Lazy-bridge placeholder. AFT skips spawning the `aft` binary at
631
647
  plugin init to keep memory/CPU low on OpenCode Desktop sessions
632
648
  that have many projects pinned in the sidebar. The RPC server
@@ -755,54 +771,62 @@ const SidebarContent = (props: {
755
771
  </>
756
772
  )}
757
773
 
758
- {/* Code Health — the agent status-bar glance, surfaced for users.
759
- Hidden until the Tier-2 cache is populated (status_bar undefined),
760
- so it never shows fabricated zeros. Errors/warnings are live LSP
761
- diagnostics; D/U/C/T come from the last background scan. A `~` on
762
- the section header flags the Tier-2 counts as predating the latest
763
- edit. */}
774
+ {/* Human health values are optional. A category stays absent until the
775
+ server proves it, rather than appearing as a clean zero. */}
764
776
  {prefs().sections.codeHealth && statusBar() && (
765
777
  <>
766
778
  <SectionHeader
767
779
  theme={props.theme}
768
780
  title={statusBar()!.tier2_stale ? "Code Health ~" : "Code Health"}
769
781
  />
770
- <StatRow
771
- theme={props.theme}
772
- label="Errors"
773
- value={formatCount(statusBar()!.errors)}
774
- tone={statusBar()!.errors > 0 ? "err" : "muted"}
775
- />
776
- <StatRow
777
- theme={props.theme}
778
- label="Warnings"
779
- value={formatCount(statusBar()!.warnings)}
780
- tone={statusBar()!.warnings > 0 ? "warn" : "muted"}
781
- />
782
- <StatRow
783
- theme={props.theme}
784
- label="Dead Code"
785
- value={formatCount(statusBar()!.dead_code)}
786
- tone="muted"
787
- />
788
- <StatRow
789
- theme={props.theme}
790
- label="Unused Exports"
791
- value={formatCount(statusBar()!.unused_exports)}
792
- tone="muted"
793
- />
794
- <StatRow
795
- theme={props.theme}
796
- label="Duplicates"
797
- value={formatCount(statusBar()!.duplicates)}
798
- tone="muted"
799
- />
800
- <StatRow
801
- theme={props.theme}
802
- label="TODOs"
803
- value={formatCount(statusBar()!.todos)}
804
- tone="muted"
805
- />
782
+ {statusBar()!.errors !== undefined && (
783
+ <StatRow
784
+ theme={props.theme}
785
+ label="Errors"
786
+ value={formatCount(statusBar()!.errors)}
787
+ tone={statusBar()!.errors! > 0 ? "err" : "muted"}
788
+ />
789
+ )}
790
+ {statusBar()!.warnings !== undefined && (
791
+ <StatRow
792
+ theme={props.theme}
793
+ label="Warnings"
794
+ value={formatCount(statusBar()!.warnings)}
795
+ tone={statusBar()!.warnings! > 0 ? "warn" : "muted"}
796
+ />
797
+ )}
798
+ {statusBar()!.dead_code !== undefined && (
799
+ <StatRow
800
+ theme={props.theme}
801
+ label="Dead Code"
802
+ value={formatCount(statusBar()!.dead_code)}
803
+ tone="muted"
804
+ />
805
+ )}
806
+ {statusBar()!.unused_exports !== undefined && (
807
+ <StatRow
808
+ theme={props.theme}
809
+ label="Unused Exports"
810
+ value={formatCount(statusBar()!.unused_exports)}
811
+ tone="muted"
812
+ />
813
+ )}
814
+ {statusBar()!.duplicates !== undefined && (
815
+ <StatRow
816
+ theme={props.theme}
817
+ label="Duplicates"
818
+ value={formatCount(statusBar()!.duplicates)}
819
+ tone="muted"
820
+ />
821
+ )}
822
+ {statusBar()!.todos !== undefined && (
823
+ <StatRow
824
+ theme={props.theme}
825
+ label="TODOs"
826
+ value={formatCount(statusBar()!.todos)}
827
+ tone="muted"
828
+ />
829
+ )}
806
830
  </>
807
831
  )}
808
832
 
@@ -12,7 +12,7 @@ import { createElement as _$createElement } from "opentui:runtime-module:%40open
12
12
  import { createMemo, createSignal, onCleanup } from "opentui:runtime-module:solid-js";
13
13
  import { version as packageVersion } from "../../package.json";
14
14
  import { AftRpcClient } from "../shared/rpc-client";
15
- import { coerceAftStatus, formatBytes, formatSemanticIndexStatus, formatSemanticRefreshing } from "../shared/status";
15
+ import { coerceAftStatus, formatBytes, formatCacheRoleLabel, formatSemanticIndexStatus, formatSemanticRefreshing } from "../shared/status";
16
16
  import { createDebouncedStatusRefresh, refreshAftTuiSocketScope, startAftTuiSocket, stopAftTuiSocket, subscribeStatusInvalidations } from "./notification-socket";
17
17
  import { createAftSidebarSlot, formatCompressionSidebarRows, isSnapshotForContext, resolveTuiStorageDir, shouldSuppressUninitializedDowngrade } from "./sidebar";
18
18
 
@@ -188,9 +188,9 @@ const StatusDialog = props => {
188
188
  }
189
189
  });
190
190
 
191
- // Visual cache-role badge: main is accent, worktree is warning,
192
- // not_initialized is muted. Matches the sidebar convention.
193
- const cacheRoleTone = role => role === "main" ? "accent" : role === "worktree" ? "warn" : "muted";
191
+ // Visual cache-role badge: main is accent. Worktree/read_only borrow the
192
+ // shared repo index — muted, not warning, so it is not read as a failure.
193
+ const cacheRoleTone = role => role === "main" ? "accent" : "muted";
194
194
  // Reuse the sidebar's label/value formatter so the dialog and sidebar
195
195
  // render identical text (e.g. "Session" / "-174,489 tokens, 59% reduction").
196
196
  // The earlier `formatCompressionDialogRows` returned padded strings that
@@ -288,7 +288,7 @@ const StatusDialog = props => {
288
288
  },
289
289
  label: "Cache role",
290
290
  get value() {
291
- return status().cache_role;
291
+ return formatCacheRoleLabel(status().cache_role);
292
292
  },
293
293
  get tone() {
294
294
  return cacheRoleTone(status().cache_role);
@@ -696,70 +696,88 @@ const StatusDialog = props => {
696
696
  _$setProp(_el$53, "marginTop", 1);
697
697
  _$insertNode(_el$54, _el$55);
698
698
  _$insert(_el$55, () => status().status_bar.tier2_stale ? "Code Health ~" : "Code Health");
699
- _$insert(_el$53, _$createComponent(R, {
700
- get theme() {
701
- return t();
702
- },
703
- label: "Errors",
704
- get value() {
705
- return formatCountShort(status().status_bar.errors);
706
- },
707
- get tone() {
708
- return status().status_bar.errors > 0 ? "err" : "muted";
709
- }
710
- }), null);
711
- _$insert(_el$53, _$createComponent(R, {
712
- get theme() {
713
- return t();
714
- },
715
- label: "Warnings",
716
- get value() {
717
- return formatCountShort(status().status_bar.warnings);
718
- },
719
- get tone() {
720
- return status().status_bar.warnings > 0 ? "warn" : "muted";
721
- }
722
- }), null);
723
- _$insert(_el$53, _$createComponent(R, {
724
- get theme() {
725
- return t();
726
- },
727
- label: "Dead Code",
728
- get value() {
729
- return formatCountShort(status().status_bar.dead_code);
730
- },
731
- tone: "muted"
732
- }), null);
733
- _$insert(_el$53, _$createComponent(R, {
734
- get theme() {
735
- return t();
736
- },
737
- label: "Unused Exports",
738
- get value() {
739
- return formatCountShort(status().status_bar.unused_exports);
740
- },
741
- tone: "muted"
742
- }), null);
743
- _$insert(_el$53, _$createComponent(R, {
744
- get theme() {
745
- return t();
746
- },
747
- label: "Duplicates",
748
- get value() {
749
- return formatCountShort(status().status_bar.duplicates);
750
- },
751
- tone: "muted"
752
- }), null);
753
- _$insert(_el$53, _$createComponent(R, {
754
- get theme() {
755
- return t();
756
- },
757
- label: "TODOs",
758
- get value() {
759
- return formatCountShort(status().status_bar.todos);
760
- },
761
- tone: "muted"
762
- }), null);
699
+ _$insert(_el$53, (() => {
700
+ var _c$14 = _$memo(() => status().status_bar.errors !== undefined);
701
+ return () => _c$14() ? _$createComponent(R, {
702
+ get theme() {
703
+ return t();
704
+ },
705
+ label: "Errors",
706
+ get value() {
707
+ return formatCountShort(status().status_bar.errors);
708
+ },
709
+ get tone() {
710
+ return status().status_bar.errors > 0 ? "err" : "muted";
711
+ }
712
+ }) : null;
713
+ })(), null);
714
+ _$insert(_el$53, (() => {
715
+ var _c$15 = _$memo(() => status().status_bar.warnings !== undefined);
716
+ return () => _c$15() ? _$createComponent(R, {
717
+ get theme() {
718
+ return t();
719
+ },
720
+ label: "Warnings",
721
+ get value() {
722
+ return formatCountShort(status().status_bar.warnings);
723
+ },
724
+ get tone() {
725
+ return status().status_bar.warnings > 0 ? "warn" : "muted";
726
+ }
727
+ }) : null;
728
+ })(), null);
729
+ _$insert(_el$53, (() => {
730
+ var _c$16 = _$memo(() => status().status_bar.dead_code !== undefined);
731
+ return () => _c$16() ? _$createComponent(R, {
732
+ get theme() {
733
+ return t();
734
+ },
735
+ label: "Dead Code",
736
+ get value() {
737
+ return formatCountShort(status().status_bar.dead_code);
738
+ },
739
+ tone: "muted"
740
+ }) : null;
741
+ })(), null);
742
+ _$insert(_el$53, (() => {
743
+ var _c$17 = _$memo(() => status().status_bar.unused_exports !== undefined);
744
+ return () => _c$17() ? _$createComponent(R, {
745
+ get theme() {
746
+ return t();
747
+ },
748
+ label: "Unused Exports",
749
+ get value() {
750
+ return formatCountShort(status().status_bar.unused_exports);
751
+ },
752
+ tone: "muted"
753
+ }) : null;
754
+ })(), null);
755
+ _$insert(_el$53, (() => {
756
+ var _c$18 = _$memo(() => status().status_bar.duplicates !== undefined);
757
+ return () => _c$18() ? _$createComponent(R, {
758
+ get theme() {
759
+ return t();
760
+ },
761
+ label: "Duplicates",
762
+ get value() {
763
+ return formatCountShort(status().status_bar.duplicates);
764
+ },
765
+ tone: "muted"
766
+ }) : null;
767
+ })(), null);
768
+ _$insert(_el$53, (() => {
769
+ var _c$19 = _$memo(() => status().status_bar.todos !== undefined);
770
+ return () => _c$19() ? _$createComponent(R, {
771
+ get theme() {
772
+ return t();
773
+ },
774
+ label: "TODOs",
775
+ get value() {
776
+ return formatCountShort(status().status_bar.todos);
777
+ },
778
+ tone: "muted"
779
+ }) : null;
780
+ })(), null);
763
781
  _$effect(_$p => _$setProp(_el$54, "fg", t().text, _$p));
764
782
  return _el$53;
765
783
  })() : null;