tickmarkr 1.80.0 → 1.83.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.
Files changed (50) hide show
  1. package/README.md +4 -4
  2. package/dist/brand.d.ts +4 -1
  3. package/dist/brand.js +46 -7
  4. package/dist/cli/commands/approve.js +53 -8
  5. package/dist/cli/commands/plan.js +17 -2
  6. package/dist/cli/commands/report.js +15 -6
  7. package/dist/cli/commands/ui.d.ts +1 -1
  8. package/dist/cli/commands/ui.js +47 -4
  9. package/dist/cli/index.d.ts +1 -1
  10. package/dist/cli/index.js +1 -1
  11. package/dist/compile/collateral.d.ts +19 -0
  12. package/dist/compile/collateral.js +90 -0
  13. package/dist/compile/index.js +18 -4
  14. package/dist/drivers/herdr.d.ts +1 -0
  15. package/dist/drivers/herdr.js +19 -0
  16. package/dist/drivers/types.d.ts +1 -0
  17. package/dist/gates/acceptance.js +50 -8
  18. package/dist/gates/llm.js +34 -19
  19. package/dist/gates/review.d.ts +9 -1
  20. package/dist/gates/review.js +173 -7
  21. package/dist/gates/run-gates.d.ts +1 -0
  22. package/dist/gates/run-gates.js +18 -1
  23. package/dist/report/bundle.d.ts +6 -1
  24. package/dist/report/bundle.js +13 -3
  25. package/dist/run/daemon.d.ts +5 -0
  26. package/dist/run/daemon.js +188 -27
  27. package/dist/run/journal.d.ts +5 -0
  28. package/dist/run/journal.js +71 -1
  29. package/dist/tui/cockpit/capture.d.ts +107 -1
  30. package/dist/tui/cockpit/capture.js +287 -10
  31. package/dist/tui/cockpit/components.d.ts +15 -86
  32. package/dist/tui/cockpit/components.js +49 -55
  33. package/dist/tui/cockpit/derive.d.ts +73 -1
  34. package/dist/tui/cockpit/derive.js +211 -15
  35. package/dist/tui/cockpit/keys.d.ts +244 -0
  36. package/dist/tui/cockpit/keys.js +634 -0
  37. package/dist/tui/cockpit/layout.d.ts +162 -0
  38. package/dist/tui/cockpit/layout.js +229 -0
  39. package/dist/tui/cockpit/live.d.ts +80 -0
  40. package/dist/tui/cockpit/live.js +311 -0
  41. package/dist/tui/cockpit/run-cockpit.d.ts +65 -2
  42. package/dist/tui/cockpit/run-cockpit.js +705 -128
  43. package/dist/tui/cockpit/setup-cockpit.d.ts +149 -1
  44. package/dist/tui/cockpit/setup-cockpit.js +432 -56
  45. package/dist/tui/cockpit/views.d.ts +72 -0
  46. package/dist/tui/cockpit/views.js +56 -0
  47. package/dist/tui/cockpit/width.d.ts +105 -0
  48. package/dist/tui/cockpit/width.js +276 -0
  49. package/fixtures/speckit-sample/tasks.md +2 -2
  50. package/package.json +3 -1
@@ -0,0 +1,244 @@
1
+ import { type RunViewId } from "./views.js";
2
+ /**
3
+ * THE key contract for the run cockpit. This registry is the single source of
4
+ * truth for both halves of a key: what the keybar advertises and what the key
5
+ * does. The keybar's entries are derived from these bindings (`keybarEntries`),
6
+ * so a key with no registered handler cannot be drawn — an advertised key that
7
+ * does nothing is not expressible.
8
+ */
9
+ /** The subset of an ink key event the run bindings discriminate on. */
10
+ export type RunKeyEvent = {
11
+ readonly input: string;
12
+ readonly key: {
13
+ readonly upArrow?: boolean;
14
+ readonly downArrow?: boolean;
15
+ readonly leftArrow?: boolean;
16
+ readonly rightArrow?: boolean;
17
+ readonly return?: boolean;
18
+ readonly tab?: boolean;
19
+ readonly escape?: boolean;
20
+ readonly backspace?: boolean;
21
+ readonly delete?: boolean;
22
+ readonly ctrl?: boolean;
23
+ };
24
+ };
25
+ /**
26
+ * The observable interaction state of the run surface. RunCockpitFrame renders
27
+ * every field of it — selection pointer, panel focus, opened event, follow
28
+ * indicator, filter prompt, help overlay — so the initial state below renders
29
+ * byte-identical to a frame that carries no interaction state at all, and every
30
+ * transition away from it is a change an operator can see.
31
+ */
32
+ /** The two top-level tabs: watch reads the engagement, setup writes to it. */
33
+ export type RunTabId = "watch" | "setup";
34
+ export type RunInteractionState = {
35
+ /** Which of the two tabs the surface draws — switched by Tab, never by a view. */
36
+ readonly tab: RunTabId;
37
+ /** The row in the active view the pointer marks; the overview has no rows. */
38
+ readonly selection: string | null;
39
+ /** The focused region, index into RUN_PANEL_FOCUS_ORDER — set by diving and backing out. */
40
+ readonly panel: number;
41
+ /** The selected rail row, independent from the view currently open. */
42
+ readonly railSelection: number;
43
+ /** The view drawn in the main region. */
44
+ readonly activeView: RunViewId;
45
+ /** The active view row opened by ⏎, or null while drawing the view itself. */
46
+ readonly opened: string | null;
47
+ /** Follow mode — toggled by f; drawn as a status-strip indicator while on. */
48
+ readonly follow: boolean;
49
+ /** The / prompt is open and taking filter text. */
50
+ readonly filterPrompt: boolean;
51
+ /** The text the journal is narrowed to — empty shows every row. */
52
+ readonly filterQuery: string;
53
+ /** Help overlay — toggled by ?. */
54
+ readonly help: boolean;
55
+ /** Quit requested by q. */
56
+ readonly quit: boolean;
57
+ };
58
+ export declare function initialRunInteractionState(): RunInteractionState;
59
+ /**
60
+ * The panels the run surface's focus moves between, in their painted order;
61
+ * index 0 is the content panel, and the sidebar is the level every view backs
62
+ * out to. A width that hides the sidebar resolves every index onto the panel
63
+ * that remains (`runPanelFocusOrder`).
64
+ */
65
+ export declare const RUN_PANEL_FOCUS_ORDER: readonly ["CONTENT", "VIEWS"];
66
+ /**
67
+ * The state the live surface opens in: the watch tab, the sidebar focused, so
68
+ * the very first arrow key moves the view selection rather than a row. This is
69
+ * a second constructor rather than a change to the one above: the committed
70
+ * captures depict a surface with no interaction state at all, and only an
71
+ * operator-accepted capture may re-freeze them.
72
+ */
73
+ export declare function openingRunInteractionState(tab?: RunTabId): RunInteractionState;
74
+ /**
75
+ * The whole surface: the tab being drawn and the tab waiting behind it. Each
76
+ * half keeps its own selection, so Tab and Tab again returns an operator to
77
+ * exactly the row and view they left.
78
+ */
79
+ export type RunSurfaceState = {
80
+ readonly interaction: RunInteractionState;
81
+ readonly stashed: RunInteractionState;
82
+ };
83
+ export declare function openingRunSurfaceState(): RunSurfaceState;
84
+ /**
85
+ * The rows of a view a key may actually stand on. The journal is a tail, not a
86
+ * list: it is never selected, opened or filtered, in either tab. Stated once
87
+ * here so the dispatcher and the advertisement cannot disagree about it.
88
+ */
89
+ export declare function selectableRunViewRowIds(viewId: RunViewId, rowIds: readonly string[]): readonly string[];
90
+ /** The one width predicate shared by rendering, focus and key projection. */
91
+ export declare const RUN_SIDE_RAIL_COLUMN_FLOOR = 80;
92
+ export declare function runSideRailVisible(columns: number): boolean;
93
+ export declare function runPanelFocusOrder(columns: number): readonly (typeof RUN_PANEL_FOCUS_ORDER)[number][];
94
+ export type RunKeyProjectionContext = {
95
+ readonly interaction: RunInteractionState;
96
+ readonly columns: number;
97
+ /** Stable identities in the active view's filtered logical collection. */
98
+ readonly rowIds?: readonly string[];
99
+ };
100
+ export type RunKeyApplyContext = {
101
+ readonly rowIds: readonly string[];
102
+ /**
103
+ * The terminal width the dispatch was made at, so a handler resolves focus
104
+ * against the same effective width the advertisement did. Handlers invoked
105
+ * without a dispatch — tests driving a binding directly — assume the width
106
+ * that offers every key.
107
+ */
108
+ readonly columns?: number;
109
+ };
110
+ export declare function runFocusedPanel({ interaction, columns, }: RunKeyProjectionContext): (typeof RUN_PANEL_FOCUS_ORDER)[number];
111
+ export type RunKeyBinding = {
112
+ /** The glyph the keybar draws, e.g. "↑↓". */
113
+ readonly key: string;
114
+ /** The promise the keybar draws next to the glyph, e.g. "Move". */
115
+ readonly label: string;
116
+ /** Whether a key event activates this binding. */
117
+ readonly matches: (event: RunKeyEvent) => boolean;
118
+ /** The state transition the label promises. */
119
+ readonly apply: (state: RunInteractionState, event: RunKeyEvent, context?: RunKeyApplyContext) => RunInteractionState;
120
+ /** Which projected contexts can actually observe this binding's transition. */
121
+ readonly available?: (context: RunKeyProjectionContext) => boolean;
122
+ /** Prompt bindings replace, rather than supplement, the normal roster. */
123
+ readonly scope?: "normal" | "filter-prompt";
124
+ /**
125
+ * How a binding that carries on/off state reports it — the brand's reserved
126
+ * toggle glyphs, never bracket toggles. Present exactly on the bindings
127
+ * whose state is on/off.
128
+ */
129
+ readonly report?: (state: RunInteractionState) => string;
130
+ /**
131
+ * The word naming where a switch key takes the operator from the current
132
+ * state — Tab promises the tab it will draw. Present exactly on bindings
133
+ * whose honest label depends on which side of the switch the surface is on.
134
+ */
135
+ readonly destination?: (state: RunInteractionState) => string;
136
+ };
137
+ /** A toggle's on/off report: the brand's reserved glyphs, never brackets. */
138
+ export declare function toggleReport(label: string, on: boolean): string;
139
+ /**
140
+ * Every key the run surface advertises, in keybar order. Each entry carries
141
+ * its handler, so advertisement and behaviour cannot drift apart.
142
+ */
143
+ export declare const RUN_KEY_BINDINGS: readonly RunKeyBinding[];
144
+ /**
145
+ * Number jumps name a view, and a digit means that one view on the whole
146
+ * surface — one key, one meaning, everywhere. Pressed on the setup tab, which
147
+ * holds sections rather than views, a digit switches to the tab that holds
148
+ * the views and lands on the one it numbers; setup waits behind with its own
149
+ * state intact for the round trip.
150
+ */
151
+ export declare const RUN_VIEW_KEY_BINDING: RunKeyBinding;
152
+ /** The filter prompt's own advertised and executable input roster. */
153
+ export declare const RUN_FILTER_PROMPT_BINDINGS: readonly RunKeyBinding[];
154
+ /** Every input binding the live run cockpit dispatches or the prompt owns. */
155
+ export declare const RUN_INPUT_BINDINGS: readonly RunKeyBinding[];
156
+ /** The panels the setup surface cycles through, in their painted order. */
157
+ export declare const SETUP_PANEL_FOCUS_ORDER: readonly ["SETUP", "HARNESSES", "KEYS"];
158
+ /**
159
+ * The observable state owned by setup's bindings. Its initial value is the
160
+ * already-pinned setup frame: step two, the harness body focused, nothing
161
+ * selected, no modal action open. Every handler moves away from that state in
162
+ * a way SetupCockpitFrame paints.
163
+ */
164
+ export type SetupInteractionState = {
165
+ readonly selection: number;
166
+ readonly panel: number;
167
+ readonly step: number;
168
+ readonly selected: readonly number[];
169
+ readonly all: boolean;
170
+ readonly probeRevision: number;
171
+ readonly savePrompt: boolean;
172
+ readonly saved: boolean;
173
+ readonly help: boolean;
174
+ readonly quit: boolean;
175
+ };
176
+ export declare function initialSetupInteractionState(): SetupInteractionState;
177
+ export type SetupKeyBinding = {
178
+ readonly key: string;
179
+ readonly label: string;
180
+ readonly matches: (event: RunKeyEvent) => boolean;
181
+ readonly apply: (state: SetupInteractionState, event: RunKeyEvent) => SetupInteractionState;
182
+ readonly report?: (state: SetupInteractionState) => string;
183
+ };
184
+ /**
185
+ * Every setup advertisement and handler, in the exact order the surface has
186
+ * always drawn. The global six are registered here with setup semantics; the
187
+ * six setup-only bindings follow them on the same surface registry.
188
+ */
189
+ export declare const SETUP_KEY_BINDINGS: readonly SetupKeyBinding[];
190
+ /** One surface-aware registry serves both cockpit renderers and dispatchers. */
191
+ export declare const SURFACE_KEY_BINDINGS: {
192
+ readonly run: readonly RunKeyBinding[];
193
+ readonly setup: readonly SetupKeyBinding[];
194
+ };
195
+ /** Save confirmation owns input until it is accepted or dismissed. */
196
+ export declare function applySetupPromptInput(event: RunKeyEvent, state: SetupInteractionState): SetupInteractionState | undefined;
197
+ /** What an advertisement looks like once the handler is stripped away. */
198
+ export type KeybarEntry = {
199
+ readonly key: string;
200
+ readonly label: string;
201
+ };
202
+ export type RunKeyProjection = (context: RunKeyProjectionContext) => readonly KeybarEntry[];
203
+ /** The lossless text vocabulary shared by frame and plain advertisements. */
204
+ export declare function formatKeybarEntries(entries: readonly KeybarEntry[]): string;
205
+ /**
206
+ * THE one context projection over the one run registry. Consumers receive its
207
+ * return value whole; none may filter, append or independently map bindings.
208
+ */
209
+ export declare function projectRunKeyEntries(context: RunKeyProjectionContext, bindings?: readonly RunKeyBinding[]): readonly KeybarEntry[];
210
+ /**
211
+ * The keybar's entries, derived from a binding registry. This is the only way
212
+ * a keybar list is produced: remove a handler and its entry disappears.
213
+ */
214
+ export declare function keybarEntries(bindings: readonly {
215
+ readonly key: string;
216
+ readonly label: string;
217
+ }[]): readonly KeybarEntry[];
218
+ /** The binding a key event activates, or undefined when no handler owns it. */
219
+ export declare function resolveRunKeyBinding(bindings: readonly RunKeyBinding[], event: RunKeyEvent): RunKeyBinding | undefined;
220
+ /**
221
+ * Re-establish the row invariant after a derivation or filter changes. The
222
+ * identities themselves are authoritative: an in-range position is never a
223
+ * substitute for the row that used to occupy it.
224
+ */
225
+ export declare function reconcileRunInteraction(state: RunInteractionState, rowIds: readonly string[]): RunInteractionState;
226
+ /**
227
+ * Send a key event to the registry: the matching binding's handler produces
228
+ * the next interaction state. An event no handler owns changes nothing — and
229
+ * while the / prompt is open the prompt's own scope is the only roster that
230
+ * owns anything, so a character grows the query rather than quitting the
231
+ * surface. One dispatcher decides that, so no caller can own the prompt twice.
232
+ */
233
+ export declare function dispatchRunKey(event: RunKeyEvent, state: RunInteractionState, bindings?: readonly RunKeyBinding[], rowIds?: readonly string[], columns?: number): RunInteractionState | undefined;
234
+ /**
235
+ * Send a key event to the whole surface. The registry owns every transition,
236
+ * including the tab flip; the surface only decides what a flipped tab means —
237
+ * the tab that was waiting comes forward carrying the state it was left in, and
238
+ * the tab that was drawn is what waits now.
239
+ */
240
+ export declare function dispatchRunSurfaceKey(event: RunKeyEvent, surface: RunSurfaceState, bindings?: readonly RunKeyBinding[], rowIds?: readonly string[], columns?: number): RunSurfaceState | undefined;
241
+ /** The setup binding a key event activates, or undefined when none owns it. */
242
+ export declare function resolveSetupKeyBinding(bindings: readonly SetupKeyBinding[], event: RunKeyEvent): SetupKeyBinding | undefined;
243
+ /** Send a key event through the setup half of the shared surface registry. */
244
+ export declare function dispatchSetupKey(event: RunKeyEvent, state: SetupInteractionState, bindings?: readonly SetupKeyBinding[]): SetupInteractionState | undefined;