@promptctl/cc-candybar 1.26.0 → 1.28.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 +86 -85
- package/package.json +6 -6
- package/schema/cc-candybar.schema.json +193 -4
- package/src/check.ts +49 -27
- package/src/click/wire.ts +16 -0
- package/src/config/action.ts +57 -22
- package/src/config/default-dsl-config.ts +424 -55
- package/src/config/dsl-loader.ts +14 -2
- package/src/config/dsl-types.ts +59 -0
- package/src/config/loader/actions.ts +283 -109
- package/src/config/loader/cross-ref.ts +148 -28
- package/src/config/loader/emit-schema.ts +2 -0
- package/src/config/loader/globals.ts +118 -31
- package/src/config/loader/merge.ts +58 -1
- package/src/config/loader/persist-target.ts +32 -0
- package/src/config/loader/presets.ts +107 -0
- package/src/config/option-domain.ts +164 -0
- package/src/config/presets.ts +188 -0
- package/src/daemon/cache/git.ts +1 -1
- package/src/daemon/cache/render.ts +72 -7
- package/src/daemon/config-overrides-store.ts +322 -0
- package/src/daemon/paths.ts +10 -0
- package/src/daemon/render-payload.ts +84 -19
- package/src/daemon/server.ts +68 -55
- package/src/daemon/verbs/config-validators.ts +127 -0
- package/src/daemon/verbs/index.ts +129 -2
- package/src/daemon/verbs/state-validators.ts +98 -586
- package/src/daemon/verbs/validator-registry.ts +457 -0
- package/src/demo/dsl.ts +17 -10
- package/src/dsl/node-registry.ts +54 -39
- package/src/dsl/render.ts +158 -46
- package/src/help-text.ts +3 -3
- package/src/install/index.ts +2 -2
- package/src/render/action.ts +155 -33
- package/src/render/active-segment.ts +78 -0
- package/src/render/menu.ts +16 -11
- package/src/render/picker.ts +51 -13
- package/src/render/segment-color.ts +74 -0
- package/src/segments/git.ts +389 -48
- package/src/template-engine/colors.ts +67 -45
- package/src/template-engine/engine.ts +11 -12
- package/src/themes/index.ts +1 -4
- package/src/themes/palette-resolvers.ts +22 -30
- package/src/themes/policy.ts +37 -16
package/src/config/dsl-loader.ts
CHANGED
|
@@ -50,6 +50,7 @@ import { synthesizeGroupDecls, validateRoot } from "./loader/layout.js";
|
|
|
50
50
|
import { synthesizeMenuDecls } from "./loader/menu-synth.js";
|
|
51
51
|
import { validateActions } from "./loader/actions.js";
|
|
52
52
|
import { validateLooks } from "./loader/looks.js";
|
|
53
|
+
import { validatePresets } from "./loader/presets.js";
|
|
53
54
|
import { validateHelpers } from "./loader/helpers.js";
|
|
54
55
|
import { validateCrossReferences } from "./loader/cross-ref.js";
|
|
55
56
|
import { validateNoCycles } from "./loader/cycles.js";
|
|
@@ -67,7 +68,10 @@ export {
|
|
|
67
68
|
resolveDslConfigPath,
|
|
68
69
|
detectConfigCollisions,
|
|
69
70
|
} from "./loader/discovery.js";
|
|
70
|
-
export {
|
|
71
|
+
export {
|
|
72
|
+
mergeWithDefault,
|
|
73
|
+
applySegmentPaletteOverrides,
|
|
74
|
+
} from "./loader/merge.js";
|
|
71
75
|
export {
|
|
72
76
|
extractTemplateRefs,
|
|
73
77
|
extractActionRefs,
|
|
@@ -230,7 +234,7 @@ function validateTopLevel(
|
|
|
230
234
|
|
|
231
235
|
const out: Mutable<RawDslConfig> = {};
|
|
232
236
|
if (raw.globals !== undefined)
|
|
233
|
-
out.globals = validateGlobals(ctx, raw.globals);
|
|
237
|
+
out.globals = validateGlobals(ctx, "globals", raw.globals);
|
|
234
238
|
if (raw.variables !== undefined)
|
|
235
239
|
out.variables = validateVariables(ctx, "variables", raw.variables);
|
|
236
240
|
if (raw.segments !== undefined)
|
|
@@ -252,6 +256,13 @@ function validateTopLevel(
|
|
|
252
256
|
if (raw.actions !== undefined)
|
|
253
257
|
out.actions = validateActions(ctx, raw.actions);
|
|
254
258
|
if (raw.looks !== undefined) out.looks = validateLooks(ctx, raw.looks);
|
|
259
|
+
// [LAW:one-source-of-truth] Parsed BEFORE the synthesis passes below, because
|
|
260
|
+
// a preset's `root` runs through the same validateRoot and therefore collects
|
|
261
|
+
// its group sugar into the same `ctx.groups` the top-level root does — the
|
|
262
|
+
// synthesized artifacts must see every group the config declares, wherever it
|
|
263
|
+
// was staged from.
|
|
264
|
+
if (raw.presets !== undefined)
|
|
265
|
+
out.presets = validatePresets(ctx, raw.presets);
|
|
255
266
|
if (raw.helpers !== undefined)
|
|
256
267
|
out.helpers = validateHelpers(ctx, raw.helpers);
|
|
257
268
|
// [LAW:one-source-of-truth] Group sugar synthesis runs AFTER every section
|
|
@@ -280,5 +291,6 @@ const TOP_LEVEL_KEYS = new Set([
|
|
|
280
291
|
"root",
|
|
281
292
|
"actions",
|
|
282
293
|
"looks",
|
|
294
|
+
"presets",
|
|
283
295
|
"helpers",
|
|
284
296
|
]);
|
package/src/config/dsl-types.ts
CHANGED
|
@@ -129,12 +129,49 @@ export function* walkNodes(node: LayoutNode): IterableIterator<LayoutNode> {
|
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
// [LAW:types-are-the-program] A PRESET is a named config FRAGMENT — one
|
|
133
|
+
// alternative arrangement of a bar the user can switch to — and its field set
|
|
134
|
+
// is capped at exactly `root` + `globals`. That cap is not taste; it is the
|
|
135
|
+
// daemon's own lifetime boundary made into a type.
|
|
136
|
+
//
|
|
137
|
+
// One RenderCache entry is keyed by (projectDir, cwd) and serves MANY sessions.
|
|
138
|
+
// Its SourceRegistry (timers, fs watchers, git subscriptions) and its derived
|
|
139
|
+
// click gate (registerStateValidator over deriveActionValidators) are built
|
|
140
|
+
// ONCE, in buildState. A preset, by contrast, is a per-SESSION pick. So a
|
|
141
|
+
// preset carrying `variables` would need a per-session registry, and one
|
|
142
|
+
// carrying `actions` would need a per-session wire gate — or a gate that is the
|
|
143
|
+
// union of every preset's actions anyway, at which point the preset scoped
|
|
144
|
+
// nothing and only the merge got harder [LAW:no-ambient-temporal-coupling].
|
|
145
|
+
// `root` and `globals` have no such problem: the root is WALKED per render (so
|
|
146
|
+
// every preset's tree is compiled up front and one is selected by name, exactly
|
|
147
|
+
// how every look's ThemeKey is resolved up front and one is selected by name),
|
|
148
|
+
// and globals already resolve per render into EffectiveGlobals.
|
|
149
|
+
//
|
|
150
|
+
// Read as a rule an author can hold: a preset may carry what the bar RESOLVES
|
|
151
|
+
// each render, never what the daemon REGISTERS once per process. An unbounded
|
|
152
|
+
// preset would just be a second config file with extra steps.
|
|
153
|
+
export interface PresetDecl {
|
|
154
|
+
// Absent ⇒ this preset does not restage the layout; the config's own `root`
|
|
155
|
+
// renders. A preset declares only its delta [LAW:carrying-cost] — a preset
|
|
156
|
+
// that had to restate every row to change one would be a copy, and copies go
|
|
157
|
+
// stale silently while continuing to look intentional.
|
|
158
|
+
readonly root?: LayoutNode;
|
|
159
|
+
// Absent ⇒ no display-default changes. Shallow-merged OVER the config's own
|
|
160
|
+
// globals when this preset is active, so a preset naming `padding` says
|
|
161
|
+
// nothing about `charset`.
|
|
162
|
+
readonly globals?: Globals;
|
|
163
|
+
}
|
|
164
|
+
|
|
132
165
|
export interface RawDslConfig {
|
|
133
166
|
readonly globals?: Partial<Globals>;
|
|
134
167
|
readonly variables?: Readonly<Record<string, VariableDecl>>;
|
|
135
168
|
readonly segments?: Readonly<Record<string, SegmentDecl>>;
|
|
136
169
|
readonly root?: LayoutNode;
|
|
137
170
|
readonly actions?: Readonly<Record<string, ActionDecl>>;
|
|
171
|
+
// Named config fragments ("presets"): each an alternative `root`/`globals`
|
|
172
|
+
// arrangement selected per session, the exact twin of `looks` one level up
|
|
173
|
+
// (a look adapts the THEME; a preset adapts the LAYOUT + display globals).
|
|
174
|
+
readonly presets?: Readonly<Record<string, PresetDecl>>;
|
|
138
175
|
// Named theme-adaptation bundles ("looks"): each is a full ThemeKey (the
|
|
139
176
|
// loader normalizes absent axes to identity at parse). Applied ON TOP of the
|
|
140
177
|
// active theme at render — a transform composing with every theme, selected
|
|
@@ -171,6 +208,14 @@ export interface DslConfig {
|
|
|
171
208
|
// config by construction. An action `{ set: …, from: "looks" }` ranges these
|
|
172
209
|
// names; the derived click gate and the rendered options read this one map.
|
|
173
210
|
readonly looks: Readonly<Record<string, ThemeKey>>;
|
|
211
|
+
// [LAW:one-source-of-truth] The effective preset set: name → config fragment.
|
|
212
|
+
// Merges by name with the bundled default (user wins per name) like every
|
|
213
|
+
// other section — so the default's `default` preset (the empty fragment, and
|
|
214
|
+
// the resolution floor of effectivePresetName) is present in EVERY merged
|
|
215
|
+
// config by construction, exactly as `looks` guarantees `none`. An action
|
|
216
|
+
// `{ set: …, from: "presets" }` ranges these names; the derived click gate and
|
|
217
|
+
// the rendered options read this one map.
|
|
218
|
+
readonly presets: Readonly<Record<string, PresetDecl>>;
|
|
174
219
|
// [LAW:single-enforcer] The effective helper set: a name → template-body map
|
|
175
220
|
// compiled to a defines-preamble at registerDslConfig. Empty when no config
|
|
176
221
|
// declares helpers — an absent `helpers` key merges to `{}` (same cascade as
|
|
@@ -214,6 +259,20 @@ export interface Globals {
|
|
|
214
259
|
// default-provided look.
|
|
215
260
|
readonly look?: string;
|
|
216
261
|
|
|
262
|
+
// [LAW:one-type-per-behavior] The config default for the PRESET (a named
|
|
263
|
+
// config fragment from the `presets` block) — the same twin-of-`palette`
|
|
264
|
+
// shape as `look` one dimension over: the daemon resolves the live preset per
|
|
265
|
+
// render as `sessionState.preset ?? globals.preset ?? "default"`
|
|
266
|
+
// (effectivePresetName), so a preset click restages the bar live and a config
|
|
267
|
+
// can pick a default arrangement without an edit-per-session. Membership in
|
|
268
|
+
// the merged `presets` map is validated post-merge (cross-ref) — a user's
|
|
269
|
+
// globals.preset may name a default-provided preset.
|
|
270
|
+
//
|
|
271
|
+
// [LAW:one-source-of-truth] A preset's own `globals` may NOT carry this field
|
|
272
|
+
// (the loader rejects it): a preset selecting a preset is a second authority
|
|
273
|
+
// over which preset is active, and a cyclic one.
|
|
274
|
+
readonly preset?: string;
|
|
275
|
+
|
|
217
276
|
// [LAW:one-type-per-behavior] The config default for the powerline cap/
|
|
218
277
|
// separator SHAPE — the exact twin of `palette` one dimension over: the
|
|
219
278
|
// daemon resolves the live strip style per render as
|