@promptctl/cc-candybar 1.8.4 → 1.10.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.
@@ -30,6 +30,15 @@ export interface SegmentLayoutOptions {
30
30
  justify: JustifyMode;
31
31
  /** Overflow strategy when content exceeds a fixed width. Ignored when "auto". */
32
32
  truncate: TruncateMode;
33
+ /**
34
+ * Spaces synthesized inside the collapsed cell on each side (the resolved
35
+ * globals.padding). [LAW:types-are-the-program] Required so every layout
36
+ * site states the value — the walk threads the one render-wide resolution;
37
+ * there is no per-site re-default. Applied BEFORE width sizing, so padding
38
+ * sits inside a fixed `width` (the legacy intra-cell semantics: the joiners
39
+ * sit between cells; padding sits inside the bg fill).
40
+ */
41
+ padding: number;
33
42
  /** Glyph inserted at the overflow cut point. Default "…". */
34
43
  truncateMarker?: string;
35
44
  /**
@@ -95,11 +104,23 @@ export function applySegmentLayout(
95
104
  cells: readonly RichText[],
96
105
  options: SegmentLayoutOptions,
97
106
  ): RichText[] {
98
- const { width, justify, truncate, truncateMarker = "…", baseStyle } = options;
107
+ const {
108
+ width,
109
+ justify,
110
+ truncate,
111
+ truncateMarker = "…",
112
+ baseStyle,
113
+ padding,
114
+ } = options;
99
115
 
100
116
  if (cells.length === 0) return [];
101
117
 
102
- const cell = collapseToCell(cells, baseStyle);
118
+ // [LAW:one-source-of-truth] The DSL path's ONE intra-cell padding
119
+ // application — the same rich-js pad primitive toCell (render/strip.ts)
120
+ // uses on the legacy shape, threading the same resolved globals.padding.
121
+ // pad() shifts spans, so OSC-8 link regions survive; the spaces inherit
122
+ // the cell's wrapping style, so the segment bg is continuous.
123
+ const cell = collapseToCell(cells, baseStyle).pad(padding);
103
124
  if (width === "auto") return [cell];
104
125
 
105
126
  if (cell.cellLength > width) {
@@ -9,11 +9,7 @@ export {
9
9
  effectiveStripStyle,
10
10
  isStripStyle,
11
11
  listResolvablePaletteNames,
12
- listAvailableThemes,
13
- pickRandomTheme,
14
12
  STRIP_STYLES,
15
- STYLE_ORDER,
16
- DISPLAY_STYLES,
17
13
  } from "./policy.js";
18
14
  export type { StripStyle } from "./policy.js";
19
15
 
@@ -47,14 +47,6 @@ export function listResolvablePaletteNames(): readonly string[] {
47
47
  return [...listThemePalettes(), ...listThemeAliases()];
48
48
  }
49
49
 
50
- // Selectable theme names for the random pool + picker: registry names plus the
51
- // "custom" sentinel. Aliases are excluded — they duplicate registry entries.
52
- export function listAvailableThemes(): string[] {
53
- const allNames = new Set<string>(listThemePalettes() as readonly string[]);
54
- allNames.add("custom");
55
- return [...allNames].sort();
56
- }
57
-
58
50
  // --- Powerline strip-style identifiers ---
59
51
 
60
52
  // [LAW:one-source-of-truth][LAW:types-are-the-program] The single canonical set
@@ -87,28 +79,3 @@ export function effectiveStripStyle(
87
79
  const chosen = sessionStyle ?? globalsStyle ?? "powerline";
88
80
  return isStripStyle(chosen) ? chosen : "powerline";
89
81
  }
90
-
91
- // --- Legacy palette-preset identifiers (per-session random feature only) ---
92
- // [LAW:no-silent-failure] NOT the picker's style domain — these were the
93
- // pre-DSL bg/fg derivation presets, surviving only as the random pool for
94
- // session-random.ts. The interactive style picker resolves over STRIP_STYLES.
95
- export const STYLE_ORDER: readonly string[] = [
96
- "surface",
97
- "muted",
98
- "button",
99
- "hue",
100
- ];
101
-
102
- export const DISPLAY_STYLES: ReadonlyArray<
103
- "minimal" | "powerline" | "capsule"
104
- > = ["minimal", "powerline", "capsule"];
105
-
106
- // --- Session-random pick ---
107
-
108
- // [LAW:one-source-of-truth] The random pool derives from the same registry the
109
- // rest of the system uses. "custom" is excluded because it requires inline
110
- // colors.custom to be defined.
111
- export function pickRandomTheme(): string {
112
- const themes = listAvailableThemes().filter((t) => t !== "custom");
113
- return themes[Math.floor(Math.random() * themes.length)]!;
114
- }
@@ -1,88 +0,0 @@
1
- // [LAW:single-enforcer] One place resolves the "random" sentinel into a
2
- // concrete value, keyed by sessionId so the random pick is *stable for the
3
- // life of that session* (pick once; clicks like set-state overwrite it).
4
- // Each setting (theme / style / endpoints) flows through the same pattern:
5
- // read sessionState → if cached return it → if config says "random" pick
6
- // + cache → otherwise return config value as-is.
7
- //
8
- // The cache is sessionState itself: that means a) the set-state click
9
- // verb continues to work (it overwrites the same key), and b) the
10
- // dataflow is uniform — no parallel "random cache" to keep in sync with
11
- // sessionState.
12
-
13
- import { pickRandomTheme, DISPLAY_STYLES, STYLE_ORDER } from "./policy.js";
14
-
15
- interface SessionStateRW {
16
- get(sessionId: string, key: string): string | null;
17
- set(sessionId: string, key: string, value: string): void;
18
- }
19
-
20
- const SENTINEL = "random";
21
-
22
- // [LAW:dataflow-not-control-flow] Same shape every call — the only branch is
23
- // "is this random?" and that's a value-driven question, not a control-flow
24
- // special case. No early returns hide the cache write from later readers.
25
- function resolve(
26
- sessionId: string,
27
- key: string,
28
- configValue: string | undefined,
29
- sessionState: SessionStateRW | undefined,
30
- pick: () => string,
31
- fallback: string,
32
- ): string {
33
- if (!sessionState) {
34
- return configValue === SENTINEL ? pick() : (configValue ?? fallback);
35
- }
36
- const cached = sessionState.get(sessionId, key);
37
- if (cached) return cached;
38
- if (configValue !== SENTINEL) return configValue ?? fallback;
39
- const chosen = pick();
40
- sessionState.set(sessionId, key, chosen);
41
- return chosen;
42
- }
43
-
44
- export function resolveSessionTheme(
45
- sessionId: string,
46
- configTheme: string | undefined,
47
- sessionState: SessionStateRW | undefined,
48
- ): string {
49
- return resolve(
50
- sessionId,
51
- "theme",
52
- configTheme,
53
- sessionState,
54
- pickRandomTheme,
55
- "dark",
56
- );
57
- }
58
-
59
- export function resolveSessionStyle(
60
- sessionId: string,
61
- configStyle: string | undefined,
62
- sessionState: SessionStateRW | undefined,
63
- ): string {
64
- return resolve(
65
- sessionId,
66
- "style",
67
- configStyle,
68
- sessionState,
69
- () => STYLE_ORDER[Math.floor(Math.random() * STYLE_ORDER.length)]!,
70
- "surface",
71
- );
72
- }
73
-
74
- export function resolveSessionDisplayStyle(
75
- sessionId: string,
76
- configDisplayStyle: string | undefined,
77
- sessionState: SessionStateRW | undefined,
78
- ): "minimal" | "powerline" | "capsule" {
79
- const value = resolve(
80
- sessionId,
81
- "displayStyle",
82
- configDisplayStyle,
83
- sessionState,
84
- () => DISPLAY_STYLES[Math.floor(Math.random() * DISPLAY_STYLES.length)]!,
85
- "minimal",
86
- );
87
- return value === "powerline" || value === "capsule" ? value : "minimal";
88
- }