@promptctl/cc-candybar 1.42.1 → 1.43.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 +72 -71
- package/package.json +5 -6
- package/src/check.ts +0 -478
- package/src/cli-flags.ts +0 -8
- package/src/click/wire.ts +0 -158
- package/src/config/action.ts +0 -329
- package/src/config/cli.ts +0 -71
- package/src/config/default-dsl-config.ts +0 -1645
- package/src/config/disclosure.ts +0 -170
- package/src/config/dsl-loader.ts +0 -339
- package/src/config/dsl-types.ts +0 -581
- package/src/config/edit-chrome.ts +0 -559
- package/src/config/help.ts +0 -151
- package/src/config/ident.ts +0 -22
- package/src/config/layout-ops.ts +0 -177
- package/src/config/loader/actions.ts +0 -972
- package/src/config/loader/cache.ts +0 -206
- package/src/config/loader/cross-ref.ts +0 -714
- package/src/config/loader/cycles.ts +0 -148
- package/src/config/loader/diagnostics.ts +0 -99
- package/src/config/loader/discovery.ts +0 -182
- package/src/config/loader/edit-mode.ts +0 -137
- package/src/config/loader/emit-schema.ts +0 -68
- package/src/config/loader/globals.ts +0 -269
- package/src/config/loader/helpers.ts +0 -48
- package/src/config/loader/layout.ts +0 -693
- package/src/config/loader/looks.ts +0 -96
- package/src/config/loader/menu-synth.ts +0 -435
- package/src/config/loader/merge.ts +0 -115
- package/src/config/loader/persist-target.ts +0 -67
- package/src/config/loader/presets.ts +0 -119
- package/src/config/loader/refs.ts +0 -100
- package/src/config/loader/reserved-namespace.ts +0 -38
- package/src/config/loader/segments.ts +0 -120
- package/src/config/loader/validate-core.ts +0 -737
- package/src/config/loader/variables.ts +0 -260
- package/src/config/menu-keys.ts +0 -139
- package/src/config/option-domain.ts +0 -164
- package/src/config/presets.ts +0 -326
- package/src/config/settings-menu.ts +0 -775
- package/src/daemon/acquire.ts +0 -684
- package/src/daemon/cache/git.ts +0 -649
- package/src/daemon/cache/render.ts +0 -623
- package/src/daemon/cache/session-usage-store.ts +0 -720
- package/src/daemon/cache/watchers.ts +0 -249
- package/src/daemon/client-debug.ts +0 -120
- package/src/daemon/client-stats.ts +0 -130
- package/src/daemon/client-transport.ts +0 -273
- package/src/daemon/client.ts +0 -78
- package/src/daemon/config-overrides-store.ts +0 -663
- package/src/daemon/debug-types.ts +0 -91
- package/src/daemon/debug.ts +0 -264
- package/src/daemon/fork-bomb-breaker.ts +0 -351
- package/src/daemon/limits.ts +0 -211
- package/src/daemon/log.ts +0 -81
- package/src/daemon/parent-watchdog.ts +0 -87
- package/src/daemon/paths.ts +0 -211
- package/src/daemon/process-fingerprint.ts +0 -146
- package/src/daemon/protocol.ts +0 -292
- package/src/daemon/render-payload.ts +0 -1256
- package/src/daemon/server.ts +0 -1330
- package/src/daemon/session-state-file.ts +0 -108
- package/src/daemon/session-state.ts +0 -237
- package/src/daemon/socket-lease.ts +0 -209
- package/src/daemon/socket-ownership.ts +0 -209
- package/src/daemon/stats.ts +0 -235
- package/src/daemon/verbs/config-validators.ts +0 -250
- package/src/daemon/verbs/index.ts +0 -706
- package/src/daemon/verbs/state-validators.ts +0 -249
- package/src/daemon/verbs/validator-registry.ts +0 -457
- package/src/demo/dsl.ts +0 -143
- package/src/demo/mock-data.ts +0 -67
- package/src/demo/statusline.json5 +0 -94
- package/src/dsl/node-registry.ts +0 -374
- package/src/dsl/render.ts +0 -803
- package/src/help-text.ts +0 -90
- package/src/index.ts +0 -210
- package/src/install/currency.ts +0 -197
- package/src/install/index.ts +0 -557
- package/src/proc/launch.ts +0 -459
- package/src/proc/stats-handle.ts +0 -13
- package/src/render/action.ts +0 -883
- package/src/render/active-segment.ts +0 -78
- package/src/render/diagnostic-style.ts +0 -23
- package/src/render/diagnostic-text.ts +0 -77
- package/src/render/error-glyph.ts +0 -53
- package/src/render/menu.ts +0 -257
- package/src/render/outcome-plan.ts +0 -45
- package/src/render/picker.ts +0 -372
- package/src/render/segment-color.ts +0 -74
- package/src/render/split-lines.ts +0 -51
- package/src/render/strip.ts +0 -228
- package/src/segments/cache.ts +0 -131
- package/src/segments/context.ts +0 -190
- package/src/segments/git.ts +0 -1084
- package/src/segments/metrics.ts +0 -187
- package/src/segments/pricing.ts +0 -452
- package/src/segments/session.ts +0 -23
- package/src/segments/tmux.ts +0 -74
- package/src/template-engine/cells.ts +0 -90
- package/src/template-engine/colors.ts +0 -124
- package/src/template-engine/engine.ts +0 -108
- package/src/template-engine/funcs.ts +0 -232
- package/src/template-engine/index.ts +0 -11
- package/src/template-engine/layout.ts +0 -133
- package/src/template-engine/scope.ts +0 -62
- package/src/template-engine/sparkline.ts +0 -79
- package/src/themes/index.ts +0 -20
- package/src/themes/palette-resolvers.ts +0 -84
- package/src/themes/policy.ts +0 -393
- package/src/utils/cache.ts +0 -206
- package/src/utils/claude.ts +0 -683
- package/src/utils/color-support.ts +0 -118
- package/src/utils/formatters.ts +0 -99
- package/src/utils/logger.ts +0 -5
- package/src/utils/outcome.ts +0 -33
- package/src/utils/schema-validator.ts +0 -126
- package/src/utils/single-flight.ts +0 -57
- package/src/utils/terminal-width.ts +0 -51
- package/src/utils/terminal.ts +0 -11
- package/src/utils/transcript-fs.ts +0 -279
- package/src/var-system/index.ts +0 -24
- package/src/var-system/sources.ts +0 -1047
- package/src/var-system/store.ts +0 -223
- package/src/var-system/types.ts +0 -57
- package/src/version.ts +0 -17
package/src/config/dsl-types.ts
DELETED
|
@@ -1,581 +0,0 @@
|
|
|
1
|
-
// [LAW:types-are-the-program] DslConfig is the strongest theorem we can write
|
|
2
|
-
// about a validated config: every legal config is representable, every illegal
|
|
3
|
-
// one is not. The loader is the proof — its body either narrows `unknown` to
|
|
4
|
-
// `DslConfig` or throws ConfigError. Downstream consumers receive a DslConfig
|
|
5
|
-
// and are free to assume invariants (closed source-kind set, exactly-one cache
|
|
6
|
-
// key, no dangling cross-refs, no template cycles) without re-checking.
|
|
7
|
-
//
|
|
8
|
-
// [LAW:one-source-of-truth] These shapes are the JSON-shape mirror of the
|
|
9
|
-
// var-system's runtime types (`CachePolicy`, `ShellOptions`, etc. in
|
|
10
|
-
// src/var-system/sources.ts). The loader is the single point that translates
|
|
11
|
-
// between the two; no other module should re-derive these shapes.
|
|
12
|
-
|
|
13
|
-
// [LAW:one-way-deps] The action schema lives in its own leaf module; DslConfig
|
|
14
|
-
// references it here. The dependency is one-way (this file → action.ts), never
|
|
15
|
-
// the reverse, so that shape can be lifted out without a cycle.
|
|
16
|
-
import type { ActionDecl } from "./action.js";
|
|
17
|
-
// [LAW:one-source-of-truth] A look IS a rich-js ThemeKey (four numeric axes:
|
|
18
|
-
// hueShift / chromaScale / lightnessScale / lightnessShift) — the config type
|
|
19
|
-
// references the vocabulary owner's type verbatim, so a rich-js axis rename is
|
|
20
|
-
// a compile error here, never silent drift. Type-only: no runtime rich-js
|
|
21
|
-
// dependency enters the config layer.
|
|
22
|
-
import type { ThemeKey } from "@promptctl/rich-js";
|
|
23
|
-
import type {
|
|
24
|
-
Charset,
|
|
25
|
-
ColorCompatibility,
|
|
26
|
-
StripStyle,
|
|
27
|
-
} from "../themes/policy.js";
|
|
28
|
-
|
|
29
|
-
// [LAW:types-are-the-program] Three stages, three names.
|
|
30
|
-
//
|
|
31
|
-
// RawDslConfig — the user-file shape. Every top-level key is optional
|
|
32
|
-
// because "user didn't write this" is a representable,
|
|
33
|
-
// distinct state from "user wrote an explicit empty."
|
|
34
|
-
// Internal to the loader module; downstream consumers
|
|
35
|
-
// never see it.
|
|
36
|
-
//
|
|
37
|
-
// DslConfig — the effective shape: the user's deltas merged on top
|
|
38
|
-
// of DEFAULT_DSL_CONFIG. Every top-level key is required.
|
|
39
|
-
// Output of `loadConfig`. Cross-refs and cycles have NOT
|
|
40
|
-
// yet been checked at this stage.
|
|
41
|
-
//
|
|
42
|
-
// ValidatedConfig — DslConfig + a phantom brand proving validateConfig()
|
|
43
|
-
// has run. The renderer accepts only this type, so the
|
|
44
|
-
// compiler structurally enforces "no unvalidated config
|
|
45
|
-
// can reach rendering." The brand is module-scoped via
|
|
46
|
-
// `unique symbol`, so the only construction site is
|
|
47
|
-
// `validateConfig` itself.
|
|
48
|
-
// [LAW:types-are-the-program] The recursive layout substrate collapses to
|
|
49
|
-
// exactly two kinds: a `segment` leaf (a ref into the named `segments` block —
|
|
50
|
-
// THE unit of rendering, a single template that IS its content) or a
|
|
51
|
-
// `container` whose `direction` is DATA that decides how its children map onto
|
|
52
|
-
// the 2D plane. Both the bar and (a later child's) menu are projections of this
|
|
53
|
-
// one tree — they differ only in `direction`, not in code path
|
|
54
|
-
// [LAW:dataflow-not-control-flow].
|
|
55
|
-
//
|
|
56
|
-
// [LAW:types-are-the-program] `Direction` carries the projection a container
|
|
57
|
-
// applies to its child blocks as DATA. `vertical` STACKS them (concat the
|
|
58
|
-
// children's line-lists); `horizontal` ZIPS them (per row, the children's cells
|
|
59
|
-
// concatenate into one strip, so the powerline joiner caps ACROSS the seam —
|
|
60
|
-
// abut is never valid). `outline` (a later child's menu) is NOT in the union
|
|
61
|
-
// yet — it joins as a new arm only when its renderer exists, so the union stays
|
|
62
|
-
// the strongest theorem that is still TRUE, with no representable-but-
|
|
63
|
-
// unrenderable direction.
|
|
64
|
-
// [LAW:one-source-of-truth] The runtime list and the type derive from one
|
|
65
|
-
// declaration; the loader validates a container's `direction` against this set,
|
|
66
|
-
// and renderDsl's projection switch is exhaustive over it (adding an arm here
|
|
67
|
-
// forces a matching render arm).
|
|
68
|
-
export const DIRECTIONS = ["vertical", "horizontal"] as const;
|
|
69
|
-
export type Direction = (typeof DIRECTIONS)[number];
|
|
70
|
-
|
|
71
|
-
// [LAW:one-type-per-behavior] THE unit of rendering: a ref into the named
|
|
72
|
-
// `segments` block. A segment IS a single template (text, state-driven display,
|
|
73
|
-
// clickable regions — whatever the template produces); there is no `inline` /
|
|
74
|
-
// `stepper` / `picker` node kind, because "make a node flexible enough for
|
|
75
|
-
// whatever" = one template expresses anything. A segment renders to ONE strip
|
|
76
|
-
// item; the powerline joiner joins items, never inside one. A horizontal run of
|
|
77
|
-
// segments is spelled `{ h: ["seg1", "seg2"] }` in the A-grammar.
|
|
78
|
-
export interface SegmentNode {
|
|
79
|
-
readonly kind: "segment";
|
|
80
|
-
// A name into the `segments` block. The segment's own template/palette/`when`
|
|
81
|
-
// live on its SegmentDecl, not here; this node is purely the tree position.
|
|
82
|
-
readonly name: string;
|
|
83
|
-
// [LAW:dataflow-not-control-flow] Absent `when` ≡ always-rendered. A node-level
|
|
84
|
-
// predicate, ANDed with the segment-decl's own `when` at render.
|
|
85
|
-
readonly when?: string;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export interface ContainerNode {
|
|
89
|
-
readonly kind: "container";
|
|
90
|
-
readonly direction: Direction;
|
|
91
|
-
readonly children: readonly LayoutNode[];
|
|
92
|
-
// A container's `when` gates the whole subtree: a hidden container emits no
|
|
93
|
-
// lines, but its descendants are still walked so per-segment hue indices stay
|
|
94
|
-
// positionally stable.
|
|
95
|
-
readonly when?: string;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export type LayoutNode = ContainerNode | SegmentNode;
|
|
99
|
-
|
|
100
|
-
// [LAW:types-are-the-program] The `group` SUGAR as collected at parse — an
|
|
101
|
-
// INPUT-only shape, never a canonical LayoutNode kind: arranging + gating are
|
|
102
|
-
// behaviors `container` already has, so "group" may only be a spelling. The
|
|
103
|
-
// loader lowers each group to container/segment nodes and SYNTHESIZES its state
|
|
104
|
-
// var + cycle action + toggle segment under the reserved `groups.` namespace
|
|
105
|
-
// (one declaration; every derived artifact single-sourced from it
|
|
106
|
-
// [LAW:one-source-of-truth]). `path` records the node's tree position so the
|
|
107
|
-
// nesting invariant (an ancestor and a descendant must not share a state key)
|
|
108
|
-
// is checkable after the walk.
|
|
109
|
-
export interface GroupSugarDecl {
|
|
110
|
-
readonly name: string;
|
|
111
|
-
readonly label: string;
|
|
112
|
-
readonly open?: boolean;
|
|
113
|
-
readonly direction?: Direction;
|
|
114
|
-
readonly key?: string;
|
|
115
|
-
readonly bg?: string;
|
|
116
|
-
readonly fg?: string;
|
|
117
|
-
readonly when?: string;
|
|
118
|
-
readonly path: string;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// [LAW:single-enforcer] THE one pre-order walk over a node tree. Every consumer
|
|
122
|
-
// that needs "which segments / which `when` predicates does this layout name"
|
|
123
|
-
// (the reachability closure, the debug dump, the cross-ref validator) iterates
|
|
124
|
-
// this — none re-recurses the tree itself.
|
|
125
|
-
export function* walkNodes(node: LayoutNode): IterableIterator<LayoutNode> {
|
|
126
|
-
yield node;
|
|
127
|
-
if (node.kind === "container") {
|
|
128
|
-
for (const child of node.children) yield* walkNodes(child);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
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
|
-
|
|
165
|
-
export interface RawDslConfig {
|
|
166
|
-
readonly globals?: Partial<Globals>;
|
|
167
|
-
readonly variables?: Readonly<Record<string, VariableDecl>>;
|
|
168
|
-
readonly segments?: Readonly<Record<string, SegmentDecl>>;
|
|
169
|
-
readonly root?: LayoutNode;
|
|
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>>;
|
|
175
|
-
// The display globals edit mode stages while it is on — see DslConfig's own
|
|
176
|
-
// `editGlobals` for the shape, the merge, and where it sits in the chain.
|
|
177
|
-
readonly editGlobals?: Partial<Globals>;
|
|
178
|
-
// Named theme-adaptation bundles ("looks"): each is a full ThemeKey (the
|
|
179
|
-
// loader normalizes absent axes to identity at parse). Applied ON TOP of the
|
|
180
|
-
// active theme at render — a transform composing with every theme, selected
|
|
181
|
-
// per session exactly like theme/style (session key `look`).
|
|
182
|
-
readonly looks?: Readonly<Record<string, ThemeKey>>;
|
|
183
|
-
// [LAW:single-enforcer] Config-level shared helper templates: name → Go-template
|
|
184
|
-
// body. Each compiles to one `{{ define "name" }}body{{ end }}` unit, and the
|
|
185
|
-
// whole set into one shared define set every template this config parses
|
|
186
|
-
// inherits — so a formatter (`{{ template "formatCost" .x }}`) is
|
|
187
|
-
// defined ONCE and callable from any segment/predicate, never re-inlined per
|
|
188
|
-
// segment. Absent ≡ no helpers; merges by-name (user overrides a helper).
|
|
189
|
-
readonly helpers?: Readonly<Record<string, string>>;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
export interface DslConfig {
|
|
193
|
-
readonly globals: Globals;
|
|
194
|
-
readonly variables: Readonly<Record<string, VariableDecl>>;
|
|
195
|
-
readonly segments: Readonly<Record<string, SegmentDecl>>;
|
|
196
|
-
// [LAW:one-source-of-truth] The SINGLE canonical layout representation authored
|
|
197
|
-
// via the A-grammar (seg/h/v node arms, group sugar). No legacy sugar reaches
|
|
198
|
-
// this field; the loader rejects `layout:` and `kind:"cells"` with migration errors.
|
|
199
|
-
readonly root: LayoutNode;
|
|
200
|
-
// [LAW:locality-or-seam] The named seam between click BEHAVIOR and the
|
|
201
|
-
// clickable REPRESENTATION. Each entry is a statically-declared effect a
|
|
202
|
-
// segment template binds a region to via `{{ action "name" … }}`. The
|
|
203
|
-
// writable-key gate derives from this table (deriveActionValidators), so a
|
|
204
|
-
// template cannot smuggle an un-gated write. Empty when no config declares
|
|
205
|
-
// actions — an absent `actions` key merges to `{}`.
|
|
206
|
-
readonly actions: Readonly<Record<string, ActionDecl>>;
|
|
207
|
-
// [LAW:one-source-of-truth] The effective look set: name → full ThemeKey.
|
|
208
|
-
// Merges by name with the bundled default (user wins per name), like
|
|
209
|
-
// segments/actions/variables — so the default's `none` (the identity look and
|
|
210
|
-
// the resolution floor of effectiveLookName) is present in EVERY merged
|
|
211
|
-
// config by construction. An action `{ set: …, from: "looks" }` ranges these
|
|
212
|
-
// names; the derived click gate and the rendered options read this one map.
|
|
213
|
-
readonly looks: Readonly<Record<string, ThemeKey>>;
|
|
214
|
-
// [LAW:one-source-of-truth] The effective preset set: name → config fragment.
|
|
215
|
-
// Merges by name with the bundled default (user wins per name) like every
|
|
216
|
-
// other section — so the default's `default` preset (the empty fragment, and
|
|
217
|
-
// the resolution floor of effectivePresetName) is present in EVERY merged
|
|
218
|
-
// config by construction, exactly as `looks` guarantees `none`. An action
|
|
219
|
-
// `{ set: …, from: "presets" }` ranges these names; the derived click gate and
|
|
220
|
-
// the rendered options read this one map.
|
|
221
|
-
readonly presets: Readonly<Record<string, PresetDecl>>;
|
|
222
|
-
// [LAW:one-source-of-truth] The display globals edit mode stages while it is
|
|
223
|
-
// on — the `globals` half of the fragment whose `root` half edit chrome
|
|
224
|
-
// already stages (src/config/edit-chrome.ts). Merges FIELD BY FIELD with the
|
|
225
|
-
// bundled default's (like `globals` itself, not wholesale like `root`), so a
|
|
226
|
-
// user retuning the separator keeps the bundled `style: "plain"`.
|
|
227
|
-
//
|
|
228
|
-
// [LAW:types-are-the-program] `Partial<Globals>`, deliberately NOT
|
|
229
|
-
// `PresetDecl`: a preset is root + globals, and edit mode needs only the
|
|
230
|
-
// globals half. Taking the wider type to use half of it would make "an edit
|
|
231
|
-
// fragment that restages the layout" representable — a second authority over
|
|
232
|
-
// a tree edit-chrome already owns. The loader additionally rejects `preset`
|
|
233
|
-
// inside it, for the same reason a preset may not select a preset.
|
|
234
|
-
//
|
|
235
|
-
// Its rung in the precedence chain is the RIGHTMOST one (see
|
|
236
|
-
// src/config/presets.ts): it outranks even a session pick, because entering
|
|
237
|
-
// edit mode is decided later than picking a style. Nothing writes it back to
|
|
238
|
-
// SessionState or the overrides layer, which is why leaving edit mode
|
|
239
|
-
// restores the previous look with no save/restore path
|
|
240
|
-
// [LAW:dataflow-not-control-flow].
|
|
241
|
-
readonly editGlobals: Partial<Globals>;
|
|
242
|
-
// [LAW:single-enforcer] The effective helper set: a name → template-body map
|
|
243
|
-
// compiled to one shared define set at registerDslConfig. Empty when no config
|
|
244
|
-
// declares helpers — an absent `helpers` key merges to `{}` (same cascade as
|
|
245
|
-
// actions). The single definition site for each formatter/transform a template
|
|
246
|
-
// calls via `{{ template "name" .arg }}`.
|
|
247
|
-
readonly helpers: Readonly<Record<string, string>>;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// [LAW:single-enforcer] The brand symbol is `unique` and module-private —
|
|
251
|
-
// nothing outside this file can construct a value carrying it. The only
|
|
252
|
-
// production-path producer is validateConfig() in dsl-loader.ts (one
|
|
253
|
-
// callsite of `config as ValidatedConfig`). Renderer signatures require
|
|
254
|
-
// ValidatedConfig; the type system therefore proves the validation step
|
|
255
|
-
// ran before any render path consumed the config.
|
|
256
|
-
declare const __validated: unique symbol;
|
|
257
|
-
export type ValidatedConfig = DslConfig & {
|
|
258
|
-
readonly [__validated]: true;
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
export interface Globals {
|
|
262
|
-
readonly default_bg?: string;
|
|
263
|
-
readonly default_fg?: string;
|
|
264
|
-
readonly default_empty_value?: string;
|
|
265
|
-
readonly default_separator?: string;
|
|
266
|
-
readonly default_truncate_marker?: string;
|
|
267
|
-
// [LAW:one-source-of-truth] A palette NAME, not a resolved Palette: DslConfig
|
|
268
|
-
// is the JSON-shape mirror, so the name is the authoritative datum and the
|
|
269
|
-
// renderer owns name→Palette resolution. The config default for the base
|
|
270
|
-
// theme; the daemon resolves the live base per render as
|
|
271
|
-
// `sessionState.theme ?? globals.palette ?? default`, and a per-segment
|
|
272
|
-
// `palette` is an explicit override that ignores the session theme.
|
|
273
|
-
readonly palette?: string;
|
|
274
|
-
|
|
275
|
-
// [LAW:one-type-per-behavior] The config default for the LOOK (a named
|
|
276
|
-
// theme-adaptation from the `looks` block) — the exact twin of `palette` one
|
|
277
|
-
// dimension over: the daemon resolves the live look per render as
|
|
278
|
-
// `sessionState.look ?? globals.look ?? "none"` (effectiveLookName), so a
|
|
279
|
-
// look click recolors the bar live and a config can set a default adaptation
|
|
280
|
-
// without an edit-per-session. Membership in the merged `looks` map is
|
|
281
|
-
// validated post-merge (cross-ref) — a user's globals.look may name a
|
|
282
|
-
// default-provided look.
|
|
283
|
-
readonly look?: string;
|
|
284
|
-
|
|
285
|
-
// [LAW:one-type-per-behavior] The config default for the PRESET (a named
|
|
286
|
-
// config fragment from the `presets` block) — the same twin-of-`palette`
|
|
287
|
-
// shape as `look` one dimension over: the daemon resolves the live preset per
|
|
288
|
-
// render as `sessionState.preset ?? globals.preset ?? "default"`
|
|
289
|
-
// (effectivePresetName), so a preset click restages the bar live and a config
|
|
290
|
-
// can pick a default arrangement without an edit-per-session. Membership in
|
|
291
|
-
// the merged `presets` map is validated post-merge (cross-ref) — a user's
|
|
292
|
-
// globals.preset may name a default-provided preset.
|
|
293
|
-
//
|
|
294
|
-
// [LAW:one-source-of-truth] A preset's own `globals` may NOT carry this field
|
|
295
|
-
// (the loader rejects it): a preset selecting a preset is a second authority
|
|
296
|
-
// over which preset is active, and a cyclic one.
|
|
297
|
-
readonly preset?: string;
|
|
298
|
-
|
|
299
|
-
// [LAW:one-type-per-behavior] The config default for the powerline cap/
|
|
300
|
-
// separator SHAPE — the exact twin of `palette` one dimension over: the
|
|
301
|
-
// daemon resolves the live strip style per render as
|
|
302
|
-
// `sessionState.style ?? globals.style ?? "powerline"` (effectiveStripStyle),
|
|
303
|
-
// so a style click reshapes the bar live and a config can set the default
|
|
304
|
-
// shape without an edit-per-session.
|
|
305
|
-
readonly style?: StripStyle;
|
|
306
|
-
|
|
307
|
-
// The legacy display.autoWrap knob: whether FlexStrip soft-wraps a root
|
|
308
|
-
// row that exceeds the usable width. Default true (current behavior);
|
|
309
|
-
// false renders each row as one unbounded line, overflow off-screen.
|
|
310
|
-
// [config-only] Unlike palette/style there is no SessionState/click half —
|
|
311
|
-
// the daemon resolves `globals.autoWrap ?? true` into renderOpts.wrap.
|
|
312
|
-
readonly autoWrap?: boolean;
|
|
313
|
-
|
|
314
|
-
// The legacy display.padding knob: spaces synthesized INSIDE each segment
|
|
315
|
-
// cell per side (intra-cell, within the bg fill — not rich-js FlexStrip's
|
|
316
|
-
// inter-item gap). Default 1 (current behavior). Templates author content;
|
|
317
|
-
// this chrome is applied structurally at the cell-formation seam.
|
|
318
|
-
// [config-only] The daemon resolves `globals.padding ?? 1` into
|
|
319
|
-
// renderOpts.padding; no SessionState/click half.
|
|
320
|
-
readonly padding?: number;
|
|
321
|
-
|
|
322
|
-
// The legacy display.charset knob: which glyph vocabulary the strip joiners
|
|
323
|
-
// render with. Default "unicode" (current behavior — rich-js's powerline
|
|
324
|
-
// caps, U+E0Bx). "ascii" swaps the caps for single-column ASCII glyphs so
|
|
325
|
-
// terminals/fonts without powerline glyphs render cleanly instead of tofu.
|
|
326
|
-
// Orthogonal to `style`: style picks the joiner shape, charset the glyphs.
|
|
327
|
-
// [config-only] The daemon resolves `globals.charset ?? "unicode"` into
|
|
328
|
-
// renderOpts.charset; no SessionState/click half.
|
|
329
|
-
readonly charset?: Charset;
|
|
330
|
-
|
|
331
|
-
// The legacy display.colorCompatibility knob: the color depth rich-js
|
|
332
|
-
// downsamples output to. Default "truecolor" (current behavior — NOT the
|
|
333
|
-
// legacy "auto" default, which would change rendering for existing users).
|
|
334
|
-
// The type excludes "auto" entirely: the daemon is detached, so env
|
|
335
|
-
// detection would read the wrong terminal — see COLOR_COMPATIBILITIES.
|
|
336
|
-
// [config-only] The daemon resolves `globals.colorCompatibility ??
|
|
337
|
-
// "truecolor"` into renderOpts.colorCompatibility; no SessionState/click half.
|
|
338
|
-
readonly colorCompatibility?: ColorCompatibility;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
// [LAW:one-type-per-behavior] One discriminated union covers every source
|
|
342
|
-
// kind. Adding a new kind = code change here + matching runtime support in
|
|
343
|
-
// var-system. There is no "extension" path that bypasses this list.
|
|
344
|
-
export type VariableDecl =
|
|
345
|
-
| LiteralVarDecl
|
|
346
|
-
| InputVarDecl
|
|
347
|
-
| EnvVarDecl
|
|
348
|
-
| FileVarDecl
|
|
349
|
-
| ShellVarDecl
|
|
350
|
-
| TemplateVarDecl
|
|
351
|
-
| TimeVarDecl
|
|
352
|
-
| GitVarDecl
|
|
353
|
-
| StateVarDecl;
|
|
354
|
-
|
|
355
|
-
export interface LiteralVarDecl {
|
|
356
|
-
readonly kind: "literal";
|
|
357
|
-
readonly value: string | number | boolean;
|
|
358
|
-
readonly default?: string;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// [LAW:types-are-the-program] `type` carries the runtime kind of the value at
|
|
362
|
-
// the resolved payload path. Number/bool are needed for the usage/cost/today
|
|
363
|
-
// family — token counts, cost amounts, percentages — whose formatters
|
|
364
|
-
// (`formatCost`, `formatTokens`, `round`, `budgetStatus`) take numeric inputs.
|
|
365
|
-
// Absent `type` defaults to "string" at the loader, preserving the historical
|
|
366
|
-
// behavior of every existing declaration. The default value's literal type
|
|
367
|
-
// must match the declared type — a number default on a string-typed input
|
|
368
|
-
// (or vice versa) is rejected at load time, not at first render.
|
|
369
|
-
export interface InputVarDecl {
|
|
370
|
-
readonly kind: "input";
|
|
371
|
-
readonly path: string;
|
|
372
|
-
readonly type?: "string" | "number" | "boolean";
|
|
373
|
-
readonly default?: string | number | boolean;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
export interface EnvVarDecl {
|
|
377
|
-
readonly kind: "env";
|
|
378
|
-
readonly name: string;
|
|
379
|
-
readonly default?: string;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
export interface FileVarDecl {
|
|
383
|
-
readonly kind: "file";
|
|
384
|
-
readonly path: string;
|
|
385
|
-
readonly readMode?: "whole" | "first-line";
|
|
386
|
-
readonly regex?: string;
|
|
387
|
-
readonly cache: CacheDecl;
|
|
388
|
-
readonly default?: string;
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
export interface ShellVarDecl {
|
|
392
|
-
readonly kind: "shell";
|
|
393
|
-
readonly command: string;
|
|
394
|
-
readonly regex?: string;
|
|
395
|
-
readonly cache: CacheDecl;
|
|
396
|
-
readonly default?: string;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
export interface TemplateVarDecl {
|
|
400
|
-
readonly kind: "template";
|
|
401
|
-
readonly template: string;
|
|
402
|
-
readonly cache?: CacheDecl;
|
|
403
|
-
readonly default?: string;
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
// [LAW:types-are-the-program] Time vars refresh on a clock — ttl is the only
|
|
407
|
-
// cache form the runtime honors (declareTime always registers a TTL timer).
|
|
408
|
-
// The loader rejects the other CacheDecl arms at load, so past that boundary
|
|
409
|
-
// a non-ttl cache on a time var is unrepresentable, not silently coerced.
|
|
410
|
-
export interface TimeVarDecl {
|
|
411
|
-
readonly kind: "time";
|
|
412
|
-
readonly layout: string;
|
|
413
|
-
readonly cache?: TtlCacheDecl;
|
|
414
|
-
readonly default?: string;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
export interface GitVarDecl {
|
|
418
|
-
readonly kind: "git";
|
|
419
|
-
readonly field: GitField;
|
|
420
|
-
readonly cache: CacheDecl;
|
|
421
|
-
readonly default?: string;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
// [LAW:one-source-of-truth] A `state` variable reads through to the daemon's
|
|
425
|
-
// SessionState (the canonical store for per-session toggles, random picks,
|
|
426
|
-
// click-mutated values). Reactivity is wired by SessionState's internal MobX
|
|
427
|
-
// atom — a click verb that writes into SessionState invalidates this
|
|
428
|
-
// variable's downstream computeds automatically. Persistence rides for free
|
|
429
|
-
// on SessionState's disk backing.
|
|
430
|
-
//
|
|
431
|
-
// The session id is resolved from the conventional `session.id` variable —
|
|
432
|
-
// that name is the canonical anchor for "which session am I in," declared
|
|
433
|
-
// once by DSL configs as an input variable carrying hook_data.session_id.
|
|
434
|
-
// [LAW:no-mode-explosion] No per-decl override knob: a single canonical
|
|
435
|
-
// session-id source keeps every state var's resolution uniform and removes
|
|
436
|
-
// an axis along which configs could drift from each other.
|
|
437
|
-
export interface StateVarDecl {
|
|
438
|
-
readonly kind: "state";
|
|
439
|
-
readonly key: string;
|
|
440
|
-
readonly default?: string;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
export type GitField =
|
|
444
|
-
| "branch"
|
|
445
|
-
| "sha"
|
|
446
|
-
| "dirty"
|
|
447
|
-
| "ahead"
|
|
448
|
-
| "behind"
|
|
449
|
-
| "stash";
|
|
450
|
-
|
|
451
|
-
// [LAW:dataflow-not-control-flow] The discriminator is "which key is present"
|
|
452
|
-
// in the user's JSON — not a `kind` field. Encoded as a 5-arm union so the
|
|
453
|
-
// type system enforces "exactly one of these." The loader validates the
|
|
454
|
-
// runtime invariant (one and only one); the type then carries it forward.
|
|
455
|
-
export type CacheDecl =
|
|
456
|
-
| TtlCacheDecl
|
|
457
|
-
| { readonly watch_file: string }
|
|
458
|
-
| { readonly depends_on: readonly string[] }
|
|
459
|
-
| { readonly key: string }
|
|
460
|
-
| { readonly never: true };
|
|
461
|
-
|
|
462
|
-
// [LAW:one-source-of-truth] The ttl arm named once, so the kinds that honor
|
|
463
|
-
// only a refresh interval (time) reference the same member the full vocabulary
|
|
464
|
-
// is composed from — narrowing is a subset, never a parallel shape.
|
|
465
|
-
export interface TtlCacheDecl {
|
|
466
|
-
readonly ttl: string;
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
export const CACHE_KEYS = [
|
|
470
|
-
"ttl",
|
|
471
|
-
"watch_file",
|
|
472
|
-
"depends_on",
|
|
473
|
-
"key",
|
|
474
|
-
"never",
|
|
475
|
-
] as const;
|
|
476
|
-
export type CacheKey = (typeof CACHE_KEYS)[number];
|
|
477
|
-
|
|
478
|
-
export const SOURCE_KINDS = [
|
|
479
|
-
"literal",
|
|
480
|
-
"input",
|
|
481
|
-
"env",
|
|
482
|
-
"file",
|
|
483
|
-
"shell",
|
|
484
|
-
"template",
|
|
485
|
-
"time",
|
|
486
|
-
"git",
|
|
487
|
-
"state",
|
|
488
|
-
] as const;
|
|
489
|
-
export type SourceKind = (typeof SOURCE_KINDS)[number];
|
|
490
|
-
|
|
491
|
-
// [LAW:one-source-of-truth] The "which kinds have a cache field" predicate
|
|
492
|
-
// lives here once. The loader's cross-ref and cycle validators narrow via
|
|
493
|
-
// this guard instead of repeating the kind list (`!== "literal" && !==
|
|
494
|
-
// "input" && ...`) at every site — adding a new no-cache kind only requires
|
|
495
|
-
// updating the union and this guard.
|
|
496
|
-
export type VariableDeclWithCache =
|
|
497
|
-
| FileVarDecl
|
|
498
|
-
| ShellVarDecl
|
|
499
|
-
| TemplateVarDecl
|
|
500
|
-
| TimeVarDecl
|
|
501
|
-
| GitVarDecl;
|
|
502
|
-
|
|
503
|
-
export function hasCacheField(v: VariableDecl): v is VariableDeclWithCache {
|
|
504
|
-
return (
|
|
505
|
-
v.kind !== "literal" &&
|
|
506
|
-
v.kind !== "input" &&
|
|
507
|
-
v.kind !== "env" &&
|
|
508
|
-
v.kind !== "state"
|
|
509
|
-
);
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
export const GIT_FIELDS: readonly GitField[] = [
|
|
513
|
-
"branch",
|
|
514
|
-
"sha",
|
|
515
|
-
"dirty",
|
|
516
|
-
"ahead",
|
|
517
|
-
"behind",
|
|
518
|
-
"stash",
|
|
519
|
-
];
|
|
520
|
-
|
|
521
|
-
// Source kinds where the user MUST declare a cache policy (no sensible default).
|
|
522
|
-
// Aligns with the proposal's cache-invalidation table.
|
|
523
|
-
export const SOURCES_REQUIRING_CACHE: readonly SourceKind[] = [
|
|
524
|
-
"file",
|
|
525
|
-
"shell",
|
|
526
|
-
"git",
|
|
527
|
-
];
|
|
528
|
-
|
|
529
|
-
export interface SegmentDecl {
|
|
530
|
-
readonly template: string;
|
|
531
|
-
readonly width?: "auto" | number;
|
|
532
|
-
readonly justify?: JustifyMode;
|
|
533
|
-
readonly truncate?: TruncateMode;
|
|
534
|
-
readonly bg?: string;
|
|
535
|
-
readonly fg?: string;
|
|
536
|
-
readonly when?: string;
|
|
537
|
-
// [LAW:one-source-of-truth] Per-segment palette override (a NAME). Overrides
|
|
538
|
-
// globals.palette for this segment only; undefined = inherit the cascade base.
|
|
539
|
-
readonly palette?: string;
|
|
540
|
-
// Per-segment vars sub-block — lives in the same global MobX store at
|
|
541
|
-
// runtime under the namespaced key `<segment>.<var>`. Templates reference a
|
|
542
|
-
// segment local ONLY via that namespaced form (`.<segment>.local`), from any
|
|
543
|
-
// segment including the owning one; the loader rejects bare refs at load
|
|
544
|
-
// with a diagnostic naming the namespaced form. [LAW:one-source-of-truth]
|
|
545
|
-
readonly vars?: Readonly<Record<string, VariableDecl>>;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
export type JustifyMode = "left" | "center" | "right";
|
|
549
|
-
export type TruncateMode = "right" | "left" | "middle";
|
|
550
|
-
|
|
551
|
-
export const JUSTIFY_MODES: readonly JustifyMode[] = [
|
|
552
|
-
"left",
|
|
553
|
-
"center",
|
|
554
|
-
"right",
|
|
555
|
-
];
|
|
556
|
-
export const TRUNCATE_MODES: readonly TruncateMode[] = [
|
|
557
|
-
"right",
|
|
558
|
-
"left",
|
|
559
|
-
"middle",
|
|
560
|
-
];
|
|
561
|
-
|
|
562
|
-
// ─── Conventional render-time variable names ─────────────────────────────────
|
|
563
|
-
//
|
|
564
|
-
// [LAW:one-source-of-truth] These are not widget types (those live in
|
|
565
|
-
// `./action.ts`); they are the conventional variable NAMES the renderer and the
|
|
566
|
-
// picker agree on. Kept here, with the other render/config conventions.
|
|
567
|
-
|
|
568
|
-
// [LAW:one-source-of-truth] The conventional variable a picker paginates against
|
|
569
|
-
// — the usable terminal width renderDsl injects each render. One name shared by
|
|
570
|
-
// the declaration (default config) and the picker's read, so they cannot drift.
|
|
571
|
-
export const TERM_COLS_VAR = "term.cols";
|
|
572
|
-
|
|
573
|
-
// [LAW:one-source-of-truth] The conventional variable per-segment hue rotation
|
|
574
|
-
// reads. hueStep is NOT a globals field (that would be a second source for a
|
|
575
|
-
// render-time value); it is a value in the store like every other render input.
|
|
576
|
-
// A config declares this variable — as a `state` var so a stepper can drive it
|
|
577
|
-
// live (session value over the declared default, the same session-over-default
|
|
578
|
-
// the theme uses), or as any kind for a fixed value. renderDsl reads it through
|
|
579
|
-
// this one name; a bounded stepper action writes the SessionState key it reads.
|
|
580
|
-
// Absent ≡ no rotation (step 0) — the degenerate case, not a special branch.
|
|
581
|
-
export const HUE_STEP_VAR = "hue.step";
|