@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/action.ts
DELETED
|
@@ -1,329 +0,0 @@
|
|
|
1
|
-
// [LAW:types-are-the-program] The author-facing SHAPE of a decoupled, named
|
|
2
|
-
// ACTION — the config-file schema for `DslConfig.actions`. Pure data (no engine,
|
|
3
|
-
// no rich-js): the strongest theorem about what a user can declare. The loader
|
|
4
|
-
// narrows `unknown` to these; the runtime (render/action.ts) and the validator
|
|
5
|
-
// derivation (daemon/verbs/state-validators.ts) consume them.
|
|
6
|
-
//
|
|
7
|
-
// [LAW:locality-or-seam] An action is the SEAM between the clickable
|
|
8
|
-
// REPRESENTATION (a template region, `{{ action "name" … }}`) and the BEHAVIOR
|
|
9
|
-
// (what the click does). They are joined by NAME: re-glyph a button without
|
|
10
|
-
// touching behavior; re-target an action without touching the template. This is
|
|
11
|
-
// the successor to the widget surface — a widget couples representation and
|
|
12
|
-
// behavior in one declaration; an action splits them so one template expresses
|
|
13
|
-
// anything (text, state-driven display, clickable regions) and the action table
|
|
14
|
-
// is the single, statically-enumerable set of effects those regions can fire.
|
|
15
|
-
//
|
|
16
|
-
// [LAW:one-source-of-truth] Because a `set` action carries its key and value
|
|
17
|
-
// SOURCE as literal data (a literal `to`, an option domain, or numeric bounds),
|
|
18
|
-
// the writable-key gate DERIVES from the action table (deriveActionValidators).
|
|
19
|
-
// A template references a NAME; it cannot smuggle an un-gated write. The rendered
|
|
20
|
-
// click and the gate share ONE source — the action declaration.
|
|
21
|
-
//
|
|
22
|
-
// [LAW:one-source-of-truth] The option-domain + effect-verb vocabulary lives
|
|
23
|
-
// HERE — action.ts is the surviving home now that the widget surface is gone.
|
|
24
|
-
// These are the shapes a picker draws options from and the set/copy/open/int
|
|
25
|
-
// discriminator the loader and the validator-derivation match on.
|
|
26
|
-
|
|
27
|
-
// [LAW:one-source-of-truth] The domain a picker draws options from. Resolved
|
|
28
|
-
// through option-domain.ts's registry — themes/styles are registry-backed
|
|
29
|
-
// static lists, "looks" is the one PER-CONFIG domain (the merged `looks`
|
|
30
|
-
// block's names, threaded as data rather than consulted from a module
|
|
31
|
-
// constant), and an inline array is its own domain, needing no registration
|
|
32
|
-
// at all. Re-exported here so ActionDecl stays self-contained to read.
|
|
33
|
-
import type { OptionDomain } from "./option-domain.js";
|
|
34
|
-
export type { OptionDomain } from "./option-domain.js";
|
|
35
|
-
|
|
36
|
-
// [LAW:types-are-the-program] The top-level discriminator of an ActionDecl — the
|
|
37
|
-
// click effect is keyed by which of these is present. The loader proves
|
|
38
|
-
// exactly-one-of; the renderer and validator-derivation match with no fallthrough.
|
|
39
|
-
//
|
|
40
|
-
// [LAW:one-source-of-truth] `persist` is `set`'s PERSISTENT twin
|
|
41
|
-
// (candybar-config-engine-71o.2): `set` mutates per-session SessionState,
|
|
42
|
-
// `persist` mutates the config's `globals` DEFAULT through the daemon-owned
|
|
43
|
-
// overrides layer (never the hand-authored config file). `reset` clears one
|
|
44
|
-
// persisted override — the gated undo `persist` needs, since a machine-owned
|
|
45
|
-
// write with no way back would be a one-way ratchet.
|
|
46
|
-
//
|
|
47
|
-
// [LAW:one-source-of-truth] `undo`/`redo` (brandon-layout-edit-2gc.2) are
|
|
48
|
-
// `reset`'s FINE-GRAINED siblings: `reset` clears one named key outright
|
|
49
|
-
// (the coarse "forget this override" case); `undo`/`redo` step ONE GLOBAL
|
|
50
|
-
// history of every `persist`/`reset` write ever made to the overrides layer
|
|
51
|
-
// — every key, not just structural layout edits — back and forth. Neither
|
|
52
|
-
// carries a key: the history is a single stack over the whole overrides
|
|
53
|
-
// file (config-overrides-store.ts owns it), so the action is a bare marker,
|
|
54
|
-
// like `int: true` is for a set-int cursor.
|
|
55
|
-
export const ACTION_KEYS = [
|
|
56
|
-
"set",
|
|
57
|
-
"persist",
|
|
58
|
-
"copy",
|
|
59
|
-
"open",
|
|
60
|
-
"reset",
|
|
61
|
-
"undo",
|
|
62
|
-
"redo",
|
|
63
|
-
] as const;
|
|
64
|
-
export type ActionKey = (typeof ACTION_KEYS)[number];
|
|
65
|
-
|
|
66
|
-
// [LAW:types-are-the-program] An ActionDecl is the click effect a named action
|
|
67
|
-
// binds to. The top-level discriminator is which of `set`/`copy`/`open` is
|
|
68
|
-
// present (the CacheDecl/widget-Action pattern); a `set` is sub-discriminated by
|
|
69
|
-
// its value SOURCE — `to` (literal), `from` (option-bound), or `min/max/by`
|
|
70
|
-
// (bounded step). The loader proves exactly-one-of at each level; the renderer
|
|
71
|
-
// and the validator-derivation match on the present key with no fallthrough.
|
|
72
|
-
//
|
|
73
|
-
// set + to — write a literal value -> allow-list {to}
|
|
74
|
-
// set + from — write the option the template binds at render
|
|
75
|
-
// (a picker ranges the domain — a registered name like
|
|
76
|
-
// "themes", or an inline literal array) -> allow-list
|
|
77
|
-
// {options}
|
|
78
|
-
// set + min/max/by — write wrap(current ± by) clamped to [min,max]
|
|
79
|
-
// (a stepper affordance) -> range [min,max]
|
|
80
|
-
// set + int — write any integer the render binds (a paged cursor:
|
|
81
|
-
// -1 closed / 0..N pages, clamp owned by the renderer)
|
|
82
|
-
// -> int gate (unbounded). The missing primitive a
|
|
83
|
-
// width-paginated picker needs — its page key accepts any
|
|
84
|
-
// integer, which no bounded/literal arm can express.
|
|
85
|
-
// set + cycle — write the SUCCESSOR of the current value in the
|
|
86
|
-
// member list, wrapping; a current value outside the
|
|
87
|
-
// domain counts as the first member (so the second
|
|
88
|
-
// member is the "first click" target — order members
|
|
89
|
-
// default-state-first). The bounded stepper's sibling:
|
|
90
|
-
// a stepper steps a range, a cycle steps an enumerated
|
|
91
|
-
// domain (toggles, N-state cyclers, accordion paths)
|
|
92
|
-
// -> allow-list {members}
|
|
93
|
-
// copy — copy templated text to the clipboard -> no gate
|
|
94
|
-
// open — open a templated target in the editor -> no gate
|
|
95
|
-
// undo — step the config-overrides layer's GLOBAL history one
|
|
96
|
-
// entry back (any persist/reset write, not just a
|
|
97
|
-
// layout op) -> no gate, no key: there is nothing a
|
|
98
|
-
// template could smuggle, since the value restored is
|
|
99
|
-
// whatever the daemon's own history recorded, never
|
|
100
|
-
// wire input
|
|
101
|
-
// redo — the inverse of undo: re-apply the most recently
|
|
102
|
-
// undone entry -> no gate, no key
|
|
103
|
-
// removeSegment — (persist only) remove the named segment from the
|
|
104
|
-
// preset-root the `persist` key addresses
|
|
105
|
-
// (`presets.<name>.rootOps`) -> allow-list {one op
|
|
106
|
-
// token — see src/config/layout-ops.ts}
|
|
107
|
-
// insertSegment +
|
|
108
|
-
// anchor + relation — (persist only) insert a named segment before/after
|
|
109
|
-
// an existing one, same key shape -> allow-list {one
|
|
110
|
-
// op token}
|
|
111
|
-
// insertSegmentFrom +
|
|
112
|
-
// anchor + relation — (persist only) insertSegment's domain-sourced
|
|
113
|
-
// sibling (brandon-layout-edit-2gc.3): the segment
|
|
114
|
-
// name is picked from an option domain at render
|
|
115
|
-
// (a `{{ menu }}`'s bound option) rather than fixed
|
|
116
|
-
// at author time -> allow-list {one op token per
|
|
117
|
-
// domain member}
|
|
118
|
-
//
|
|
119
|
-
// [LAW:one-source-of-truth] `set` writes SessionState and `persist` writes
|
|
120
|
-
// the config-overrides layer, so only those two derive a validator (through
|
|
121
|
-
// the SAME shared registry algebra — see validator-registry.ts). copy/open/
|
|
122
|
-
// reset write nothing SPEC-shaped (reset's target is gated by key membership,
|
|
123
|
-
// not a value domain) — they derive nothing. The vocabulary grows by arms (a
|
|
124
|
-
// future `run`/`open-url`), not by validator plumbing.
|
|
125
|
-
//
|
|
126
|
-
// [LAW:one-type-per-behavior] `persist` mirrors `set`'s four value-source
|
|
127
|
-
// arms verbatim (to/from/min-max-by/cycle) MINUS `int`: an unbounded page
|
|
128
|
-
// cursor is a UI-only paging concept (a picker's own navigation state) with
|
|
129
|
-
// no meaning as a persisted config default.
|
|
130
|
-
//
|
|
131
|
-
// [LAW:locality-or-seam] `removeSegment`/`insertSegment` are `persist`-ONLY
|
|
132
|
-
// (brandon-layout-edit-2gc.1) — a structural edit is always a durable,
|
|
133
|
-
// machine-owned write by design (the ticket's own instruction: reuse 71o's
|
|
134
|
-
// writer, land in the SAME overrides layer), so there is no SessionState
|
|
135
|
-
// twin. Every operation is fully literal at config-author time — the
|
|
136
|
-
// segment names and relation are DATA the loader proves at load, not a
|
|
137
|
-
// runtime picker — so each declared action has exactly one legal request,
|
|
138
|
-
// gated the same one-member-allow-list way a literal `to` already is.
|
|
139
|
-
export type ActionDecl =
|
|
140
|
-
| { readonly set: string; readonly to: string }
|
|
141
|
-
| { readonly set: string; readonly from: OptionDomain }
|
|
142
|
-
| {
|
|
143
|
-
readonly set: string;
|
|
144
|
-
readonly min: number;
|
|
145
|
-
readonly max: number;
|
|
146
|
-
readonly by: number;
|
|
147
|
-
}
|
|
148
|
-
| { readonly set: string; readonly int: true }
|
|
149
|
-
| { readonly set: string; readonly cycle: readonly string[] }
|
|
150
|
-
| { readonly persist: string; readonly to: string }
|
|
151
|
-
| { readonly persist: string; readonly from: OptionDomain }
|
|
152
|
-
| {
|
|
153
|
-
readonly persist: string;
|
|
154
|
-
readonly min: number;
|
|
155
|
-
readonly max: number;
|
|
156
|
-
readonly by: number;
|
|
157
|
-
}
|
|
158
|
-
| { readonly persist: string; readonly cycle: readonly string[] }
|
|
159
|
-
| { readonly persist: string; readonly removeSegment: string }
|
|
160
|
-
| {
|
|
161
|
-
readonly persist: string;
|
|
162
|
-
readonly insertSegment: string;
|
|
163
|
-
readonly anchor: string;
|
|
164
|
-
readonly relation: "before" | "after";
|
|
165
|
-
}
|
|
166
|
-
// [LAW:one-source-of-truth] brandon-layout-edit-2gc.3's DOMAIN-SOURCED
|
|
167
|
-
// sibling of `insertSegment`: the same tree op, but the segment name comes
|
|
168
|
-
// from the template's bound option (a picker/menu cell) instead of being
|
|
169
|
-
// fixed at config-author time — exactly the `to`-vs-`from` split `set`/
|
|
170
|
-
// `persist` already draw, one arm over. `anchor`/`relation` stay literal
|
|
171
|
-
// (the POSITION is still author-time data; only WHICH segment lands there
|
|
172
|
-
// is picked at render). This is what makes a `{{ menu "insertHere" }}`
|
|
173
|
-
// legal over a structural edit: `requireOptionKind` (render/picker.ts)
|
|
174
|
-
// admits it alongside set-option/persist-option, and the click writes
|
|
175
|
-
// `encodeLayoutOp({ op: "insert", segment: <picked>, anchor, relation })` —
|
|
176
|
-
// the SAME wire shape a literal `insertSegment` action emits, so undo/redo
|
|
177
|
-
// and the daemon's apply-layout-op handler need no changes at all.
|
|
178
|
-
| {
|
|
179
|
-
readonly persist: string;
|
|
180
|
-
readonly insertSegmentFrom: OptionDomain;
|
|
181
|
-
readonly anchor: string;
|
|
182
|
-
readonly relation: "before" | "after";
|
|
183
|
-
}
|
|
184
|
-
| { readonly copy: string }
|
|
185
|
-
| { readonly open: string }
|
|
186
|
-
| { readonly reset: string }
|
|
187
|
-
| { readonly undo: true }
|
|
188
|
-
| { readonly redo: true }
|
|
189
|
-
| DualActionDecl;
|
|
190
|
-
|
|
191
|
-
// [LAW:one-source-of-truth] The key whose PRESENCE makes an action
|
|
192
|
-
// dual-destination, and whose VALUE names the SessionState key that chooses
|
|
193
|
-
// the destination at click time. Spelled once: the loader dispatches on it,
|
|
194
|
-
// the compiler reads it, and the settings menu's synthesis writes it.
|
|
195
|
-
export const PERSIST_WHEN = "persistWhen";
|
|
196
|
-
|
|
197
|
-
// [LAW:types-are-the-program] ONE setting, ONE control, TWO stores
|
|
198
|
-
// (candybar-settings-ui-aok.3). Before this arm, a setting with both a
|
|
199
|
-
// session and a durable half cost the author two declarations and the reader
|
|
200
|
-
// two controls — `{{ menu "applyTheme" }}` beside `📌{{ menu
|
|
201
|
-
// "applyThemeForever" }}` — a second representation of one setting that had
|
|
202
|
-
// to be reconciled at every glance.
|
|
203
|
-
//
|
|
204
|
-
// A dual decl carries BOTH destination keys (`set` = the SessionState key,
|
|
205
|
-
// `persist` = the config-overrides key — they differ where history made them
|
|
206
|
-
// differ, e.g. session "theme" over globals field "palette") and ONE value
|
|
207
|
-
// source shared by both. `persistWhen` names the session key whose boolean
|
|
208
|
-
// value SELECTS the destination; the value written is identical either way,
|
|
209
|
-
// so the destination is the only thing that varies, and it varies as DATA
|
|
210
|
-
// [LAW:dataflow-not-control-flow].
|
|
211
|
-
//
|
|
212
|
-
// [LAW:single-enforcer] This adds NO gate surface. `actionDestinations`
|
|
213
|
-
// below explodes one dual decl into exactly the two single-destination decls
|
|
214
|
-
// it is equivalent to, and both validator derivations (state-validators.ts,
|
|
215
|
-
// config-validators.ts) fold over that explosion — so the writable (key,
|
|
216
|
-
// spec) pairs stay statically enumerable from the declarations, derived by
|
|
217
|
-
// the same code that has always derived them.
|
|
218
|
-
//
|
|
219
|
-
// The `int` / `removeSegment` / `insertSegment*` sources are deliberately
|
|
220
|
-
// absent: `int` is a UI-only page cursor with no durable meaning, and the
|
|
221
|
-
// structural edits are persist-only by design (see the arms above), so
|
|
222
|
-
// neither has two destinations to choose between.
|
|
223
|
-
export type DualActionDecl =
|
|
224
|
-
| {
|
|
225
|
-
readonly set: string;
|
|
226
|
-
readonly persist: string;
|
|
227
|
-
readonly persistWhen: string;
|
|
228
|
-
readonly to: string;
|
|
229
|
-
}
|
|
230
|
-
| {
|
|
231
|
-
readonly set: string;
|
|
232
|
-
readonly persist: string;
|
|
233
|
-
readonly persistWhen: string;
|
|
234
|
-
readonly from: OptionDomain;
|
|
235
|
-
}
|
|
236
|
-
| {
|
|
237
|
-
readonly set: string;
|
|
238
|
-
readonly persist: string;
|
|
239
|
-
readonly persistWhen: string;
|
|
240
|
-
readonly cycle: readonly string[];
|
|
241
|
-
}
|
|
242
|
-
| {
|
|
243
|
-
readonly set: string;
|
|
244
|
-
readonly persist: string;
|
|
245
|
-
readonly persistWhen: string;
|
|
246
|
-
readonly min: number;
|
|
247
|
-
readonly max: number;
|
|
248
|
-
readonly by: number;
|
|
249
|
-
};
|
|
250
|
-
|
|
251
|
-
// [LAW:parse-dont-validate] The one discriminator for the dual arm, and the
|
|
252
|
-
// reason every `"set" in a` consumer stays correct: a dual decl carries both
|
|
253
|
-
// `set` and `persist`, so a consumer that must treat the two destinations
|
|
254
|
-
// separately asks THIS first (or folds through actionDestinations below), and
|
|
255
|
-
// a consumer that only asks "does this bind a session write" (actionBindsSet)
|
|
256
|
-
// keeps its existing answer with no change at all.
|
|
257
|
-
export function actionIsDual(a: ActionDecl): a is DualActionDecl {
|
|
258
|
-
return PERSIST_WHEN in a;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// [LAW:one-source-of-truth] THE explosion of an action into the
|
|
262
|
-
// single-destination declarations it writes through — `[a]` for every
|
|
263
|
-
// ordinary action, `[session, durable]` for a dual. Every consumer that
|
|
264
|
-
// reasons about DESTINATIONS (both validator derivations) flatMaps through
|
|
265
|
-
// this instead of learning the dual shape, so the gate a dual derives is by
|
|
266
|
-
// construction the union of the gates its two halves would have derived
|
|
267
|
-
// separately — there is no second derivation to keep in agreement.
|
|
268
|
-
export function actionDestinations(a: ActionDecl): readonly ActionDecl[] {
|
|
269
|
-
if (!actionIsDual(a)) return [a];
|
|
270
|
-
// [LAW:types-are-the-program] Written out per value source rather than
|
|
271
|
-
// spread-and-cast: the two halves are then ordinary, fully-typed `set` and
|
|
272
|
-
// `persist` members — the exact declarations an author would have written —
|
|
273
|
-
// and adding a value source to DualActionDecl fails to compile here until
|
|
274
|
-
// its explosion is stated.
|
|
275
|
-
if ("to" in a) {
|
|
276
|
-
return [
|
|
277
|
-
{ set: a.set, to: a.to },
|
|
278
|
-
{ persist: a.persist, to: a.to },
|
|
279
|
-
];
|
|
280
|
-
}
|
|
281
|
-
if ("from" in a) {
|
|
282
|
-
return [
|
|
283
|
-
{ set: a.set, from: a.from },
|
|
284
|
-
{ persist: a.persist, from: a.from },
|
|
285
|
-
];
|
|
286
|
-
}
|
|
287
|
-
if ("cycle" in a) {
|
|
288
|
-
return [
|
|
289
|
-
{ set: a.set, cycle: a.cycle },
|
|
290
|
-
{ persist: a.persist, cycle: a.cycle },
|
|
291
|
-
];
|
|
292
|
-
}
|
|
293
|
-
return [
|
|
294
|
-
{ set: a.set, min: a.min, max: a.max, by: a.by },
|
|
295
|
-
{ persist: a.persist, min: a.min, max: a.max, by: a.by },
|
|
296
|
-
];
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// [LAW:dataflow-not-control-flow] Does this action write a SessionState key? A
|
|
300
|
-
// `set` action composes a set-state click URL whose first segment is session.id;
|
|
301
|
-
// copy/open/persist/reset embed none. One predicate the loader's session.id
|
|
302
|
-
// requirement folds over — no per-arm branching at the callsite.
|
|
303
|
-
export function actionBindsSet(a: ActionDecl): boolean {
|
|
304
|
-
return "set" in a;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// [LAW:dataflow-not-control-flow] Does this action write the config-overrides
|
|
308
|
-
// layer? Mirrors actionBindsSet for the `persist` arm.
|
|
309
|
-
export function actionBindsPersist(a: ActionDecl): boolean {
|
|
310
|
-
return "persist" in a;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// [LAW:dataflow-not-control-flow] Does this action clear a config-overrides
|
|
314
|
-
// key? `reset` carries session.id on the wire too (for click-error surfacing,
|
|
315
|
-
// same as set/persist), so it joins the same requirement.
|
|
316
|
-
export function actionBindsReset(a: ActionDecl): boolean {
|
|
317
|
-
return "reset" in a;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// [LAW:dataflow-not-control-flow] Does this action step the config-overrides
|
|
321
|
-
// history? `undo`/`redo` carry session.id on the wire too — same reason as
|
|
322
|
-
// `reset`: an empty stack is a loud, session-scoped click.error, not a
|
|
323
|
-
// silent no-op (the ticket's own done-gate).
|
|
324
|
-
export function actionBindsUndo(a: ActionDecl): boolean {
|
|
325
|
-
return "undo" in a;
|
|
326
|
-
}
|
|
327
|
-
export function actionBindsRedo(a: ActionDecl): boolean {
|
|
328
|
-
return "redo" in a;
|
|
329
|
-
}
|
package/src/config/cli.ts
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
// [LAW:single-enforcer] Config-tooling CLI entry point for `schema`. It carries
|
|
2
|
-
// no schema LOGIC — it serves the build-generated artifact (derived from the
|
|
3
|
-
// loader's declarations), so it is a binding, not a reimplementation
|
|
4
|
-
// [LAW:one-source-of-truth]. Config *validation* lives in `cc-candybar check`
|
|
5
|
-
// (src/check.ts) — the full-pipeline verdict command; the old `lint` is its
|
|
6
|
-
// alias.
|
|
7
|
-
|
|
8
|
-
import fs from "node:fs";
|
|
9
|
-
import path from "node:path";
|
|
10
|
-
import process from "node:process";
|
|
11
|
-
|
|
12
|
-
const EXIT_VALID = 0;
|
|
13
|
-
const EXIT_USAGE = 2;
|
|
14
|
-
|
|
15
|
-
// Read the build-generated JSON Schema for the config file shape (RawDslConfig),
|
|
16
|
-
// or null when the artifact is absent. Pure read — `runSchema` owns the side
|
|
17
|
-
// effects, so the locate-and-read path is testable.
|
|
18
|
-
export function loadSchemaText(): string | null {
|
|
19
|
-
const schemaPath = locateSchema();
|
|
20
|
-
return schemaPath === null ? null : fs.readFileSync(schemaPath, "utf-8");
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// `cc-candybar schema` — print the schema so an editor can annotate a config with
|
|
24
|
-
// `"$schema": "<this output, saved somewhere>"` (or the stable published URL) for
|
|
25
|
-
// autocomplete + structural validation. Emitted from the loader schemas at build
|
|
26
|
-
// time (scripts/gen-schema.ts → emitConfigSchema); served verbatim here (the
|
|
27
|
-
// emitter runs at build, not ship time).
|
|
28
|
-
export function runSchema(): void {
|
|
29
|
-
// [LAW:no-silent-failure] A schema that exists but cannot be read (EACCES, a
|
|
30
|
-
// deletion racing the existsSync in locateSchema) is a distinct failure from
|
|
31
|
-
// schema-not-found — report it as what it is, not a misleading top-level
|
|
32
|
-
// render error.
|
|
33
|
-
let text: string | null;
|
|
34
|
-
try {
|
|
35
|
-
text = loadSchemaText();
|
|
36
|
-
} catch (e) {
|
|
37
|
-
process.stderr.write(
|
|
38
|
-
`schema: cannot read bundled schema: ${e instanceof Error ? e.message : String(e)}\n`,
|
|
39
|
-
);
|
|
40
|
-
process.exit(EXIT_USAGE);
|
|
41
|
-
}
|
|
42
|
-
if (text === null) {
|
|
43
|
-
process.stderr.write(
|
|
44
|
-
"schema: bundled schema not found (expected schema/cc-candybar.schema.json). " +
|
|
45
|
-
"Run `pnpm gen:schema` from a source checkout.\n",
|
|
46
|
-
);
|
|
47
|
-
process.exit(EXIT_USAGE);
|
|
48
|
-
}
|
|
49
|
-
process.stdout.write(text);
|
|
50
|
-
process.exit(EXIT_VALID);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// [LAW:locality-or-seam] The schema sits at `<package-root>/schema/...`. Anchor
|
|
54
|
-
// on the running CLI entry (argv[1] — `dist/index.mjs` in prod, since every
|
|
55
|
-
// subcommand execs the Node fallback) and walk up to the nearest ancestor that
|
|
56
|
-
// holds the artifact, so the prod and dev layouts aren't special-cased. argv[1]
|
|
57
|
-
// (not import.meta) keeps this resolvable identically under the ESM bundle and
|
|
58
|
-
// any module setting.
|
|
59
|
-
function locateSchema(): string | null {
|
|
60
|
-
const rel = path.join("schema", "cc-candybar.schema.json");
|
|
61
|
-
const anchor = process.argv[1];
|
|
62
|
-
if (anchor === undefined) return null;
|
|
63
|
-
let dir = path.dirname(path.resolve(anchor));
|
|
64
|
-
for (;;) {
|
|
65
|
-
const candidate = path.join(dir, rel);
|
|
66
|
-
if (fs.existsSync(candidate)) return candidate;
|
|
67
|
-
const parent = path.dirname(dir);
|
|
68
|
-
if (parent === dir) return null;
|
|
69
|
-
dir = parent;
|
|
70
|
-
}
|
|
71
|
-
}
|