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.
- package/README.md +4 -4
- package/dist/brand.d.ts +4 -1
- package/dist/brand.js +46 -7
- package/dist/cli/commands/approve.js +53 -8
- package/dist/cli/commands/plan.js +17 -2
- package/dist/cli/commands/report.js +15 -6
- package/dist/cli/commands/ui.js +13 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/compile/collateral.d.ts +19 -0
- package/dist/compile/collateral.js +90 -0
- package/dist/compile/index.js +18 -4
- package/dist/drivers/herdr.d.ts +1 -0
- package/dist/drivers/herdr.js +19 -0
- package/dist/drivers/types.d.ts +1 -0
- package/dist/gates/acceptance.js +50 -8
- package/dist/gates/llm.js +34 -19
- package/dist/gates/review.d.ts +9 -1
- package/dist/gates/review.js +173 -7
- package/dist/gates/run-gates.d.ts +1 -0
- package/dist/gates/run-gates.js +18 -1
- package/dist/report/bundle.d.ts +6 -1
- package/dist/report/bundle.js +13 -3
- package/dist/run/daemon.d.ts +5 -0
- package/dist/run/daemon.js +188 -27
- package/dist/run/journal.d.ts +5 -0
- package/dist/run/journal.js +71 -1
- package/dist/tui/cockpit/capture.d.ts +107 -1
- package/dist/tui/cockpit/capture.js +287 -10
- package/dist/tui/cockpit/components.d.ts +12 -46
- package/dist/tui/cockpit/components.js +48 -48
- package/dist/tui/cockpit/derive.d.ts +73 -1
- package/dist/tui/cockpit/derive.js +211 -15
- package/dist/tui/cockpit/keys.d.ts +114 -19
- package/dist/tui/cockpit/keys.js +413 -44
- package/dist/tui/cockpit/layout.d.ts +162 -0
- package/dist/tui/cockpit/layout.js +229 -0
- package/dist/tui/cockpit/live.d.ts +52 -3
- package/dist/tui/cockpit/live.js +216 -40
- package/dist/tui/cockpit/run-cockpit.d.ts +64 -8
- package/dist/tui/cockpit/run-cockpit.js +686 -163
- package/dist/tui/cockpit/setup-cockpit.d.ts +146 -1
- package/dist/tui/cockpit/setup-cockpit.js +337 -5
- package/dist/tui/cockpit/views.d.ts +72 -0
- package/dist/tui/cockpit/views.js +56 -0
- package/dist/tui/cockpit/width.d.ts +105 -0
- package/dist/tui/cockpit/width.js +276 -0
- package/fixtures/speckit-sample/tasks.md +2 -2
- package/package.json +3 -1
package/dist/tui/cockpit/live.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { render, useApp, useInput } from "ink";
|
|
4
|
-
import { createElement, useEffect,
|
|
5
|
-
import { stateDirName } from "../../graph/graph.js";
|
|
4
|
+
import { createElement, useEffect, useRef, useSyncExternalStore } from "react";
|
|
5
|
+
import { graphPath, loadGraph, stateDirName } from "../../graph/graph.js";
|
|
6
6
|
import { Journal, parseRunId } from "../../run/journal.js";
|
|
7
|
-
import { deriveRunCockpitData
|
|
8
|
-
import {
|
|
7
|
+
import { deriveRunCockpitData } from "./derive.js";
|
|
8
|
+
import { deriveRunViewRows, runKeyColumns, RunCockpitFrame } from "./run-cockpit.js";
|
|
9
|
+
import { dispatchRunSurfaceKey, openingRunSurfaceState, reconcileRunInteraction, RUN_INPUT_BINDINGS, selectableRunViewRowIds, } from "./keys.js";
|
|
9
10
|
// ponytail: fixed 2s re-derive cadence, matching `status --watch`; promote to a
|
|
10
11
|
// config knob only if an operator asks.
|
|
11
12
|
const REFRESH_MS = 2_000;
|
|
@@ -30,6 +31,22 @@ export function loadEngagementSource(cwd, runId) {
|
|
|
30
31
|
const raw = readFileSync(path, "utf8");
|
|
31
32
|
return { fileName: `${id}.journal.jsonl`, raw };
|
|
32
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* The compiled graph, when the repository has one. It lends the tasks view its
|
|
36
|
+
* identities and nothing else, so an engagement with no compiled graph at all
|
|
37
|
+
* still draws every task the journal mentions rather than refusing to open.
|
|
38
|
+
*
|
|
39
|
+
* Absence is the only fallback. A graph that exists and cannot be read, parsed
|
|
40
|
+
* or validated is a fault, and swallowing it would quietly demote the surface:
|
|
41
|
+
* every task the graph alone knows about would vanish from the rows, and a
|
|
42
|
+
* selection standing on one of them would be cleared as if the engagement had
|
|
43
|
+
* dropped it. So it throws, and the caller keeps its last good frame instead.
|
|
44
|
+
*/
|
|
45
|
+
export function loadEngagementGraph(cwd) {
|
|
46
|
+
if (!existsSync(graphPath(cwd)))
|
|
47
|
+
return undefined;
|
|
48
|
+
return loadGraph(cwd);
|
|
49
|
+
}
|
|
33
50
|
// The same s/m/h age vocabulary `status` speaks (status.ts fmtAge).
|
|
34
51
|
export function formatEventAge(ageMs) {
|
|
35
52
|
const safe = Math.max(0, ageMs);
|
|
@@ -64,65 +81,223 @@ function lastEventMs(raw) {
|
|
|
64
81
|
* than as current. Throws on unreadable bytes (empty capture, no run-start) —
|
|
65
82
|
* the caller refuses instead of rendering a plausible surface from nothing.
|
|
66
83
|
*/
|
|
67
|
-
export function deriveLiveRunCockpitData(source, binaryVersion, now = Date.now) {
|
|
68
|
-
const data = deriveRunCockpitData(source, binaryVersion);
|
|
84
|
+
export function deriveLiveRunCockpitData(source, binaryVersion, now = Date.now, graph) {
|
|
85
|
+
const data = deriveRunCockpitData(source, binaryVersion, { graph });
|
|
69
86
|
const lastMs = lastEventMs(source.raw);
|
|
70
87
|
const staleness = lastMs === undefined
|
|
71
88
|
? "last event unknown"
|
|
72
89
|
: `last event ${formatEventAge(now() - lastMs)} ago`;
|
|
73
90
|
return { ...data, elapsed: `${data.elapsed} · ${staleness}` };
|
|
74
91
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Repair the interaction state against the rows a refreshed view now owns.
|
|
94
|
+
* Selection is held by the row's source identity, so it survives rows landing
|
|
95
|
+
* above it and is dropped — never slid onto whoever inherited its index —
|
|
96
|
+
* when the refreshed engagement no longer carries it.
|
|
97
|
+
*/
|
|
98
|
+
export function reconcileLiveRunInteraction(interaction, data) {
|
|
99
|
+
return reconcileRunInteraction(interaction, liveRunViewRowIds(interaction, data));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The rows the live surface hands its keys — the engagement's own identities,
|
|
103
|
+
* minus the journal's, which are never selectable in either tab. This is the
|
|
104
|
+
* one place rows enter the dispatcher, so no key can reach a journal row.
|
|
105
|
+
*/
|
|
106
|
+
export function liveRunViewRowIds(interaction, data) {
|
|
107
|
+
return selectableRunViewRowIds(interaction.activeView,
|
|
108
|
+
// The frame's own rows, so a key can never stand on a row the surface did
|
|
109
|
+
// not draw — one derivation, read by both.
|
|
110
|
+
deriveRunViewRows(data, interaction.activeView, interaction.filterQuery)
|
|
111
|
+
.map((row) => row.id));
|
|
112
|
+
}
|
|
113
|
+
function createLiveCockpitDelivery({ cwd, runId, binaryVersion, now, }) {
|
|
114
|
+
// Both sources are read every refresh: a recompile between refreshes changes
|
|
115
|
+
// which tasks exist, and the surface must draw the graph the repository has
|
|
116
|
+
// now rather than the one it had when the cockpit opened.
|
|
117
|
+
const derive = () => deriveLiveRunCockpitData(loadEngagementSource(cwd, runId), binaryVersion, now, loadEngagementGraph(cwd));
|
|
118
|
+
const opening = openingRunSurfaceState();
|
|
119
|
+
let surface = {
|
|
120
|
+
data: derive(),
|
|
121
|
+
interaction: opening.interaction,
|
|
122
|
+
stashed: opening.stashed,
|
|
123
|
+
};
|
|
124
|
+
const listeners = new Set();
|
|
125
|
+
let batchDepth = 0;
|
|
126
|
+
let pendingDraw = false;
|
|
127
|
+
const publish = () => {
|
|
128
|
+
if (batchDepth > 0) {
|
|
129
|
+
pendingDraw = true;
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
for (const listener of listeners)
|
|
133
|
+
listener();
|
|
134
|
+
};
|
|
135
|
+
const transition = (apply) => {
|
|
136
|
+
const next = apply(surface);
|
|
137
|
+
if (next === surface)
|
|
138
|
+
return false;
|
|
139
|
+
surface = next;
|
|
140
|
+
publish();
|
|
141
|
+
return true;
|
|
142
|
+
};
|
|
143
|
+
const delivery = {
|
|
144
|
+
snapshot: () => surface,
|
|
145
|
+
subscribe: (listener) => {
|
|
146
|
+
listeners.add(listener);
|
|
147
|
+
return () => listeners.delete(listener);
|
|
148
|
+
},
|
|
149
|
+
batch: (deliver) => {
|
|
150
|
+
batchDepth += 1;
|
|
151
|
+
try {
|
|
152
|
+
return deliver();
|
|
153
|
+
}
|
|
154
|
+
finally {
|
|
155
|
+
batchDepth -= 1;
|
|
156
|
+
if (batchDepth === 0 && pendingDraw) {
|
|
157
|
+
pendingDraw = false;
|
|
158
|
+
publish();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
refresh: () => {
|
|
81
163
|
try {
|
|
82
|
-
|
|
164
|
+
const refreshed = derive();
|
|
165
|
+
return transition((current) => ({
|
|
166
|
+
...current,
|
|
167
|
+
data: refreshed,
|
|
168
|
+
interaction: reconcileLiveRunInteraction(current.interaction, refreshed),
|
|
169
|
+
}));
|
|
83
170
|
}
|
|
84
171
|
catch {
|
|
85
|
-
//
|
|
172
|
+
// A torn read mid-append, or a graph caught mid-recompile, keeps the
|
|
173
|
+
// last good frame rather than demoting or blanking the surface.
|
|
174
|
+
return false;
|
|
86
175
|
}
|
|
87
|
-
},
|
|
176
|
+
},
|
|
177
|
+
// Every key goes to the one surface dispatcher, in every state the surface
|
|
178
|
+
// can be in. The prompt is a scope inside that registry rather than an
|
|
179
|
+
// owner in front of it, so a global key — Tab above all — reaches its
|
|
180
|
+
// handler with a prompt open exactly as it does without one.
|
|
181
|
+
key: (event, columns = Number.MAX_SAFE_INTEGER) => transition((current) => {
|
|
182
|
+
const next = dispatchRunSurfaceKey(event, { interaction: current.interaction, stashed: current.stashed }, RUN_INPUT_BINDINGS, liveRunViewRowIds(current.interaction, current.data),
|
|
183
|
+
// The dispatcher decides on rail visibility, and the plan owns that.
|
|
184
|
+
runKeyColumns(columns));
|
|
185
|
+
if (next === undefined)
|
|
186
|
+
return current;
|
|
187
|
+
const interaction = reconcileLiveRunInteraction(next.interaction, current.data);
|
|
188
|
+
return interaction === current.interaction && next.stashed === current.stashed
|
|
189
|
+
? current
|
|
190
|
+
: { ...current, interaction, stashed: next.stashed };
|
|
191
|
+
}),
|
|
192
|
+
};
|
|
193
|
+
return delivery;
|
|
194
|
+
}
|
|
195
|
+
function measureOutput(output) {
|
|
196
|
+
const read = () => `${output.columns ?? 80}:${output.rows ?? 24}`;
|
|
197
|
+
let size = read();
|
|
198
|
+
const listeners = new Set();
|
|
199
|
+
const heldInkResizeListeners = new Set();
|
|
200
|
+
const resized = () => {
|
|
201
|
+
size = read();
|
|
202
|
+
for (const listener of listeners)
|
|
203
|
+
listener();
|
|
204
|
+
};
|
|
205
|
+
output.on("resize", resized);
|
|
206
|
+
// Ink otherwise repaints its previous tree as soon as the stream resizes.
|
|
207
|
+
// Hold that repaint until React has published the newly measured plan.
|
|
208
|
+
const subscribe = (event, listener) => {
|
|
209
|
+
if (event === "resize")
|
|
210
|
+
heldInkResizeListeners.add(listener);
|
|
211
|
+
else
|
|
212
|
+
output.on(event, listener);
|
|
213
|
+
return stdout;
|
|
214
|
+
};
|
|
215
|
+
const unsubscribe = (event, listener) => {
|
|
216
|
+
if (event === "resize")
|
|
217
|
+
heldInkResizeListeners.delete(listener);
|
|
218
|
+
else
|
|
219
|
+
output.off(event, listener);
|
|
220
|
+
return stdout;
|
|
221
|
+
};
|
|
222
|
+
const stdout = new Proxy(output, {
|
|
223
|
+
get(target, property) {
|
|
224
|
+
if (property === "on" || property === "addListener")
|
|
225
|
+
return subscribe;
|
|
226
|
+
if (property === "off" || property === "removeListener")
|
|
227
|
+
return unsubscribe;
|
|
228
|
+
const value = Reflect.get(target, property);
|
|
229
|
+
return typeof value === "function" && !Object.hasOwn(target, property)
|
|
230
|
+
? value.bind(target)
|
|
231
|
+
: value;
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
return {
|
|
235
|
+
subscribe: (listener) => {
|
|
236
|
+
listeners.add(listener);
|
|
237
|
+
return () => listeners.delete(listener);
|
|
238
|
+
},
|
|
239
|
+
snapshot: () => size,
|
|
240
|
+
stdout,
|
|
241
|
+
settle: () => {
|
|
242
|
+
for (const listener of heldInkResizeListeners)
|
|
243
|
+
listener();
|
|
244
|
+
},
|
|
245
|
+
close: () => output.off("resize", resized),
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function LiveApp({ delivery, size, refreshMs, }) {
|
|
249
|
+
const { exit } = useApp();
|
|
250
|
+
const surface = useSyncExternalStore(delivery.subscribe, delivery.snapshot, delivery.snapshot);
|
|
251
|
+
const measuredSize = useSyncExternalStore(size.subscribe, size.snapshot, size.snapshot);
|
|
252
|
+
const [columns, rows] = measuredSize.split(":").map((part) => Math.max(0, Math.floor(Number(part))));
|
|
253
|
+
const drawnSize = useRef(measuredSize);
|
|
254
|
+
useEffect(() => {
|
|
255
|
+
if (drawnSize.current === measuredSize)
|
|
256
|
+
return;
|
|
257
|
+
drawnSize.current = measuredSize;
|
|
258
|
+
size.settle();
|
|
259
|
+
}, [measuredSize, size]);
|
|
260
|
+
useEffect(() => {
|
|
261
|
+
const timer = setInterval(delivery.refresh, refreshMs);
|
|
88
262
|
return () => clearInterval(timer);
|
|
89
|
-
}, [
|
|
263
|
+
}, [delivery, refreshMs]);
|
|
264
|
+
useEffect(() => {
|
|
265
|
+
if (surface.interaction.quit)
|
|
266
|
+
exit();
|
|
267
|
+
}, [exit, surface.interaction.quit]);
|
|
90
268
|
useInput((input, key) => {
|
|
91
269
|
if (key.ctrl && input === "c") {
|
|
92
270
|
exit();
|
|
93
271
|
return;
|
|
94
272
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
const next = dispatchRunKey({ input, key }, interaction, SURFACE_KEY_BINDINGS.run);
|
|
104
|
-
if (next === undefined)
|
|
105
|
-
return;
|
|
106
|
-
setInteraction(next);
|
|
107
|
-
if (next.quit)
|
|
108
|
-
exit();
|
|
273
|
+
delivery.key({ input, key }, columns);
|
|
274
|
+
});
|
|
275
|
+
return createElement(RunCockpitFrame, {
|
|
276
|
+
data: surface.data,
|
|
277
|
+
columns,
|
|
278
|
+
rows,
|
|
279
|
+
interaction: surface.interaction,
|
|
109
280
|
});
|
|
110
|
-
return createElement(RunCockpitFrame, { data, columns, rows, interaction });
|
|
111
281
|
}
|
|
112
|
-
export async function runLiveCockpit({ input, output, cwd, runId, binaryVersion, refreshMs = REFRESH_MS, now = Date.now, }) {
|
|
113
|
-
const
|
|
114
|
-
const rows = output.rows ?? 24;
|
|
115
|
-
const app = render(createElement(LiveApp, {
|
|
282
|
+
export async function runLiveCockpit({ input, output, cwd, runId, binaryVersion, refreshMs = REFRESH_MS, now = Date.now, debug = false, onDelivery, }) {
|
|
283
|
+
const delivery = createLiveCockpitDelivery({
|
|
116
284
|
cwd,
|
|
117
285
|
runId,
|
|
118
286
|
binaryVersion,
|
|
119
|
-
columns,
|
|
120
|
-
rows,
|
|
121
|
-
refreshMs,
|
|
122
287
|
now,
|
|
288
|
+
});
|
|
289
|
+
onDelivery?.(delivery);
|
|
290
|
+
// Subscribe before Ink mounts so no stale-size repaint can overtake the
|
|
291
|
+
// surface's newly planned frame.
|
|
292
|
+
const size = measureOutput(output);
|
|
293
|
+
const app = render(createElement(LiveApp, {
|
|
294
|
+
delivery,
|
|
295
|
+
size,
|
|
296
|
+
refreshMs,
|
|
123
297
|
}), {
|
|
124
298
|
stdin: input,
|
|
125
|
-
stdout:
|
|
299
|
+
stdout: size.stdout,
|
|
300
|
+
debug,
|
|
126
301
|
exitOnCtrlC: false,
|
|
127
302
|
patchConsole: false,
|
|
128
303
|
});
|
|
@@ -130,6 +305,7 @@ export async function runLiveCockpit({ input, output, cwd, runId, binaryVersion,
|
|
|
130
305
|
await app.waitUntilExit();
|
|
131
306
|
}
|
|
132
307
|
finally {
|
|
308
|
+
size.close();
|
|
133
309
|
app.unmount();
|
|
134
310
|
}
|
|
135
311
|
}
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { type ReactElement } from "react";
|
|
2
|
-
import type
|
|
3
|
-
import { type
|
|
2
|
+
import { type JournalRow } from "./components.js";
|
|
3
|
+
import { type RunCockpitData } from "./derive.js";
|
|
4
|
+
import { type KeybarEntry, type RunInteractionState, type RunKeyProjection } from "./keys.js";
|
|
5
|
+
import { type RunViewId } from "./views.js";
|
|
6
|
+
import { type FramePlan, type FrameRegion, type FrameState, type FrameCockpitLayout, type FrameView, type MeasuredSize, type PlannedFrame } from "./layout.js";
|
|
4
7
|
export { deriveRunCockpitData } from "./derive.js";
|
|
5
8
|
export type { RunCockpitData } from "./derive.js";
|
|
6
9
|
export { PANEL_CHROME_ROWS } from "./components.js";
|
|
10
|
+
/** The width focus and key routing resolve at. */
|
|
11
|
+
export declare function runKeyColumns(columns: number): number;
|
|
7
12
|
/**
|
|
8
13
|
* How many rows one line of body text occupies once the renderer wraps it into
|
|
9
14
|
* `columns`. This mirrors the renderer's own word wrap — greedy, and breaking a
|
|
@@ -13,14 +18,65 @@ export { PANEL_CHROME_ROWS } from "./components.js";
|
|
|
13
18
|
export declare function wrappedRows(text: string, columns: number): number;
|
|
14
19
|
/** The rows a bordered panel occupies when its body wraps into `columns`. */
|
|
15
20
|
export declare function panelRows(lines: readonly string[], columns: number): number;
|
|
16
|
-
|
|
21
|
+
/**
|
|
22
|
+
* The selectable rows owned by one view. The overview's journal is a passive
|
|
23
|
+
* tail, not its item collection; tasks, gates and fleet remain honestly empty
|
|
24
|
+
* until their dedicated derivations land. Journal rows keep the source-record
|
|
25
|
+
* identities assigned by the production journal derivation.
|
|
26
|
+
*/
|
|
27
|
+
export declare function deriveRunViewRows(data: RunCockpitData, viewId: RunViewId, filterQuery?: string): readonly JournalRow[];
|
|
28
|
+
/** What each drawn region draws: the resolved budgets its panels consume. */
|
|
29
|
+
export type RegionContent = {
|
|
30
|
+
readonly body: number;
|
|
31
|
+
readonly journal: number;
|
|
32
|
+
readonly bodyColumns: number;
|
|
33
|
+
readonly sideRails: boolean;
|
|
34
|
+
readonly stats: FrameCockpitLayout["stats"]["mode"] | "none";
|
|
35
|
+
readonly progressBar: boolean;
|
|
36
|
+
readonly progressCaption: boolean;
|
|
37
|
+
readonly approvedProgress: boolean;
|
|
38
|
+
};
|
|
39
|
+
export type PlannedRunCockpitFrame = {
|
|
40
|
+
readonly plan: FramePlan;
|
|
41
|
+
readonly columns: number;
|
|
42
|
+
readonly rows?: number;
|
|
43
|
+
/** What fills the drawn regions; absent on the unsized legacy surface. */
|
|
44
|
+
readonly content?: RegionContent;
|
|
45
|
+
/** The inputs planFrame planned from, so the guard can re-plan and refuse
|
|
46
|
+
* a span that moved after planning. */
|
|
47
|
+
readonly planning?: {
|
|
48
|
+
readonly size: MeasuredSize;
|
|
49
|
+
readonly view: FrameView;
|
|
50
|
+
readonly state: FrameState;
|
|
51
|
+
};
|
|
52
|
+
readonly interaction: RunInteractionState;
|
|
53
|
+
readonly keyEntries: readonly KeybarEntry[];
|
|
54
|
+
};
|
|
55
|
+
/** Resolve every draw-time input; the plan is planFrame's own return, consumed unmodified. */
|
|
56
|
+
export declare function planRunCockpitFrame({ data, columns, rows, interaction, keyProjection, }: {
|
|
57
|
+
data: RunCockpitData;
|
|
58
|
+
columns: number;
|
|
59
|
+
rows?: number;
|
|
60
|
+
interaction?: RunInteractionState;
|
|
61
|
+
keyProjection?: RunKeyProjection;
|
|
62
|
+
}): PlannedRunCockpitFrame;
|
|
63
|
+
/** The public surface always enters paint through one measured plan. */
|
|
64
|
+
export declare function RunCockpitFrame({ data, columns, rows, interaction, keyProjection, }: {
|
|
17
65
|
data: RunCockpitData;
|
|
18
66
|
columns: number;
|
|
19
67
|
rows?: number;
|
|
20
|
-
/**
|
|
21
|
-
* The run surface's interaction state. Omitted — or at its initial value —
|
|
22
|
-
* the frame is byte-identical to the pinned appearance; every transition a
|
|
23
|
-
* binding makes is drawn from it.
|
|
24
|
-
*/
|
|
25
68
|
interaction?: RunInteractionState;
|
|
69
|
+
keyProjection?: RunKeyProjection;
|
|
70
|
+
}): ReactElement;
|
|
71
|
+
/**
|
|
72
|
+
* Assert the plan's tiled extents, the bytes production paints, and — given
|
|
73
|
+
* the offsets read off the painted nodes — that every planned region was
|
|
74
|
+
* drawn where the plan puts it.
|
|
75
|
+
*/
|
|
76
|
+
export declare function assertFrameConformance(plan: PlannedFrame, drawnFrame: string, drawnRegions?: readonly FrameRegion[]): void;
|
|
77
|
+
/** Production paint consumes only resolved plan inputs and fails closed with
|
|
78
|
+
* the same conformance assertion the acceptance suite runs. */
|
|
79
|
+
export declare function RunCockpitFrameFromPlan({ data, plannedFrame, }: {
|
|
80
|
+
data: RunCockpitData;
|
|
81
|
+
plannedFrame: PlannedRunCockpitFrame;
|
|
26
82
|
}): ReactElement;
|