tickmarkr 1.81.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 (49) 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.js +13 -1
  8. package/dist/cli/index.d.ts +1 -1
  9. package/dist/cli/index.js +1 -1
  10. package/dist/compile/collateral.d.ts +19 -0
  11. package/dist/compile/collateral.js +90 -0
  12. package/dist/compile/index.js +18 -4
  13. package/dist/drivers/herdr.d.ts +1 -0
  14. package/dist/drivers/herdr.js +19 -0
  15. package/dist/drivers/types.d.ts +1 -0
  16. package/dist/gates/acceptance.js +50 -8
  17. package/dist/gates/llm.js +34 -19
  18. package/dist/gates/review.d.ts +9 -1
  19. package/dist/gates/review.js +173 -7
  20. package/dist/gates/run-gates.d.ts +1 -0
  21. package/dist/gates/run-gates.js +18 -1
  22. package/dist/report/bundle.d.ts +6 -1
  23. package/dist/report/bundle.js +13 -3
  24. package/dist/run/daemon.d.ts +5 -0
  25. package/dist/run/daemon.js +188 -27
  26. package/dist/run/journal.d.ts +5 -0
  27. package/dist/run/journal.js +71 -1
  28. package/dist/tui/cockpit/capture.d.ts +107 -1
  29. package/dist/tui/cockpit/capture.js +287 -10
  30. package/dist/tui/cockpit/components.d.ts +12 -46
  31. package/dist/tui/cockpit/components.js +48 -48
  32. package/dist/tui/cockpit/derive.d.ts +73 -1
  33. package/dist/tui/cockpit/derive.js +211 -15
  34. package/dist/tui/cockpit/keys.d.ts +114 -19
  35. package/dist/tui/cockpit/keys.js +413 -44
  36. package/dist/tui/cockpit/layout.d.ts +162 -0
  37. package/dist/tui/cockpit/layout.js +229 -0
  38. package/dist/tui/cockpit/live.d.ts +52 -3
  39. package/dist/tui/cockpit/live.js +216 -40
  40. package/dist/tui/cockpit/run-cockpit.d.ts +64 -8
  41. package/dist/tui/cockpit/run-cockpit.js +686 -163
  42. package/dist/tui/cockpit/setup-cockpit.d.ts +146 -1
  43. package/dist/tui/cockpit/setup-cockpit.js +337 -5
  44. package/dist/tui/cockpit/views.d.ts +72 -0
  45. package/dist/tui/cockpit/views.js +56 -0
  46. package/dist/tui/cockpit/width.d.ts +105 -0
  47. package/dist/tui/cockpit/width.js +276 -0
  48. package/fixtures/speckit-sample/tasks.md +2 -2
  49. package/package.json +3 -1
@@ -1,3 +1,4 @@
1
+ import { type RunViewId } from "./views.js";
1
2
  /**
2
3
  * THE key contract for the run cockpit. This registry is the single source of
3
4
  * truth for both halves of a key: what the keybar advertises and what the key
@@ -12,6 +13,7 @@ export type RunKeyEvent = {
12
13
  readonly upArrow?: boolean;
13
14
  readonly downArrow?: boolean;
14
15
  readonly leftArrow?: boolean;
16
+ readonly rightArrow?: boolean;
15
17
  readonly return?: boolean;
16
18
  readonly tab?: boolean;
17
19
  readonly escape?: boolean;
@@ -27,13 +29,21 @@ export type RunKeyEvent = {
27
29
  * byte-identical to a frame that carries no interaction state at all, and every
28
30
  * transition away from it is a change an operator can see.
29
31
  */
32
+ /** The two top-level tabs: watch reads the engagement, setup writes to it. */
33
+ export type RunTabId = "watch" | "setup";
30
34
  export type RunInteractionState = {
31
- /** The journal row the pointer marks — moved by ↑↓, -1 while nothing is selected. */
32
- readonly selection: number;
33
- /** The focused panel, index into RUN_PANEL_FOCUS_ORDER — cycled by Tab. */
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. */
34
40
  readonly panel: number;
35
- /** The selection opened by ⏎, or null once ← returns from it. */
36
- readonly opened: number | null;
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;
37
47
  /** Follow mode — toggled by f; drawn as a status-strip indicator while on. */
38
48
  readonly follow: boolean;
39
49
  /** The / prompt is open and taking filter text. */
@@ -47,10 +57,57 @@ export type RunInteractionState = {
47
57
  };
48
58
  export declare function initialRunInteractionState(): RunInteractionState;
49
59
  /**
50
- * The panels Tab cycles focus through, in cycle order; index 0 is the focus
51
- * the surface opens with, so the initial frame is the one the anchors pin.
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.
52
88
  */
53
- export declare const RUN_PANEL_FOCUS_ORDER: readonly ["RUN", "VIEWS", "KEYS"];
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];
54
111
  export type RunKeyBinding = {
55
112
  /** The glyph the keybar draws, e.g. "↑↓". */
56
113
  readonly key: string;
@@ -59,13 +116,23 @@ export type RunKeyBinding = {
59
116
  /** Whether a key event activates this binding. */
60
117
  readonly matches: (event: RunKeyEvent) => boolean;
61
118
  /** The state transition the label promises. */
62
- readonly apply: (state: RunInteractionState, event: RunKeyEvent) => RunInteractionState;
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";
63
124
  /**
64
125
  * How a binding that carries on/off state reports it — the brand's reserved
65
126
  * toggle glyphs, never bracket toggles. Present exactly on the bindings
66
127
  * whose state is on/off.
67
128
  */
68
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;
69
136
  };
70
137
  /** A toggle's on/off report: the brand's reserved glyphs, never brackets. */
71
138
  export declare function toggleReport(label: string, on: boolean): string;
@@ -74,6 +141,18 @@ export declare function toggleReport(label: string, on: boolean): string;
74
141
  * its handler, so advertisement and behaviour cannot drift apart.
75
142
  */
76
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[];
77
156
  /** The panels the setup surface cycles through, in their painted order. */
78
157
  export declare const SETUP_PANEL_FOCUS_ORDER: readonly ["SETUP", "HARNESSES", "KEYS"];
79
158
  /**
@@ -115,19 +194,19 @@ export declare const SURFACE_KEY_BINDINGS: {
115
194
  };
116
195
  /** Save confirmation owns input until it is accepted or dismissed. */
117
196
  export declare function applySetupPromptInput(event: RunKeyEvent, state: SetupInteractionState): SetupInteractionState | undefined;
118
- /**
119
- * The transitions of the open / prompt. The prompt is not an advertised key,
120
- * so it has no binding — but its transitions live here beside the registry
121
- * because they rewrite the same interaction state: characters grow the query,
122
- * backspace shrinks it, ⏎ applies it (the journal stays narrowed), escape
123
- * cancels it. Anything else the prompt swallows unchanged.
124
- */
125
- export declare function applyFilterInput(event: RunKeyEvent, state: RunInteractionState): RunInteractionState | undefined;
126
197
  /** What an advertisement looks like once the handler is stripped away. */
127
198
  export type KeybarEntry = {
128
199
  readonly key: string;
129
200
  readonly label: string;
130
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[];
131
210
  /**
132
211
  * The keybar's entries, derived from a binding registry. This is the only way
133
212
  * a keybar list is produced: remove a handler and its entry disappears.
@@ -138,11 +217,27 @@ export declare function keybarEntries(bindings: readonly {
138
217
  }[]): readonly KeybarEntry[];
139
218
  /** The binding a key event activates, or undefined when no handler owns it. */
140
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;
141
226
  /**
142
227
  * Send a key event to the registry: the matching binding's handler produces
143
- * the next interaction state. An event no handler owns changes nothing.
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.
144
239
  */
145
- export declare function dispatchRunKey(event: RunKeyEvent, state: RunInteractionState, bindings?: readonly RunKeyBinding[]): RunInteractionState | undefined;
240
+ export declare function dispatchRunSurfaceKey(event: RunKeyEvent, surface: RunSurfaceState, bindings?: readonly RunKeyBinding[], rowIds?: readonly string[], columns?: number): RunSurfaceState | undefined;
146
241
  /** The setup binding a key event activates, or undefined when none owns it. */
147
242
  export declare function resolveSetupKeyBinding(bindings: readonly SetupKeyBinding[], event: RunKeyEvent): SetupKeyBinding | undefined;
148
243
  /** Send a key event through the setup half of the shared surface registry. */