@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.
- package/dist/index.mjs +36 -36
- package/package.json +5 -5
- package/schema/cc-candybar.schema.json +8 -0
- package/src/config/default-dsl-config.ts +43 -31
- package/src/config/dsl-types.ts +15 -0
- package/src/config/loader/globals.ts +8 -0
- package/src/config/loader/validate-core.ts +28 -0
- package/src/daemon/server.ts +15 -0
- package/src/daemon/verbs/state-validators.ts +4 -4
- package/src/demo/dsl.ts +9 -1
- package/src/dsl/node-registry.ts +9 -0
- package/src/dsl/render.ts +9 -1
- package/src/render/action.ts +6 -0
- package/src/render/picker.ts +5 -1
- package/src/render/strip.ts +44 -15
- package/src/template-engine/layout.ts +23 -2
- package/src/themes/index.ts +0 -4
- package/src/themes/policy.ts +0 -33
- package/src/themes/session-random.ts +0 -88
|
@@ -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 {
|
|
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
|
-
|
|
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) {
|
package/src/themes/index.ts
CHANGED
package/src/themes/policy.ts
CHANGED
|
@@ -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
|
-
}
|