tickmarkr 1.78.0 → 1.80.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 (39) hide show
  1. package/dist/adapters/claude-code.d.ts +11 -0
  2. package/dist/adapters/claude-code.js +105 -16
  3. package/dist/adapters/kimi.d.ts +6 -0
  4. package/dist/adapters/kimi.js +88 -26
  5. package/dist/adapters/registry.js +6 -1
  6. package/dist/brand.d.ts +4 -0
  7. package/dist/brand.js +4 -0
  8. package/dist/cli/commands/doctor.d.ts +2 -0
  9. package/dist/cli/commands/doctor.js +23 -0
  10. package/dist/cli/commands/status.d.ts +4 -0
  11. package/dist/cli/commands/status.js +237 -18
  12. package/dist/cli/commands/ui.d.ts +1 -1
  13. package/dist/cli/commands/ui.js +11 -1
  14. package/dist/drivers/herdr.js +36 -7
  15. package/dist/drivers/types.d.ts +22 -1
  16. package/dist/gates/acceptance.d.ts +5 -0
  17. package/dist/gates/acceptance.js +5 -3
  18. package/dist/gates/llm.d.ts +9 -0
  19. package/dist/gates/llm.js +74 -0
  20. package/dist/gates/review.d.ts +5 -0
  21. package/dist/gates/review.js +5 -3
  22. package/dist/run/journal.d.ts +1 -1
  23. package/dist/tui/cockpit/capture.d.ts +117 -0
  24. package/dist/tui/cockpit/capture.js +329 -0
  25. package/dist/tui/cockpit/components.d.ts +179 -0
  26. package/dist/tui/cockpit/components.js +280 -0
  27. package/dist/tui/cockpit/demo.d.ts +41 -0
  28. package/dist/tui/cockpit/demo.js +144 -0
  29. package/dist/tui/cockpit/derive.d.ts +39 -0
  30. package/dist/tui/cockpit/derive.js +390 -0
  31. package/dist/tui/cockpit/layout.d.ts +76 -0
  32. package/dist/tui/cockpit/layout.js +84 -0
  33. package/dist/tui/cockpit/run-cockpit.d.ts +19 -0
  34. package/dist/tui/cockpit/run-cockpit.js +194 -0
  35. package/dist/tui/cockpit/setup-cockpit.d.ts +41 -0
  36. package/dist/tui/cockpit/setup-cockpit.js +488 -0
  37. package/dist/tui/cockpit/theme.d.ts +161 -0
  38. package/dist/tui/cockpit/theme.js +170 -0
  39. package/package.json +2 -1
@@ -0,0 +1,194 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Box } from "ink";
3
+ import { cloneElement, } from "react";
4
+ import { GLYPHS, PLAIN_COMPACT_LOCKUP, } from "../../brand.js";
5
+ import { allocateBandColumns, BandLines, BodyText, CockpitGrid, composeBandLine, JournalRowPanel, KEYBAR_KEYS, Keybar, Panel, PANEL_CHROME_ROWS, ProgressMeter, StatTile, StatusStrip, } from "./components.js";
6
+ import { resolveCockpitLayout, } from "./layout.js";
7
+ export { deriveRunCockpitData } from "./derive.js";
8
+ export { PANEL_CHROME_ROWS } from "./components.js";
9
+ const APPROVED_SIDE_RAIL_COLUMN_FLOOR = 80;
10
+ const NARROW_HEADER_ALLOCATION = {
11
+ chromeColumns: 0,
12
+ minimumReadableColumns: 1,
13
+ };
14
+ /**
15
+ * How many rows one line of body text occupies once the renderer wraps it into
16
+ * `columns`. This mirrors the renderer's own word wrap — greedy, and breaking a
17
+ * word that cannot fit on a line of its own — so a frame can charge a panel the
18
+ * rows it will really occupy instead of a hand-tuned constant.
19
+ */
20
+ export function wrappedRows(text, columns) {
21
+ if (columns < 1)
22
+ return 1;
23
+ let rows = 1;
24
+ let used = 0;
25
+ for (const [index, word] of text.split(" ").entries()) {
26
+ // ponytail: code points, not display columns — every glyph the cockpit
27
+ // draws is one column wide. Reach for a width table only if it stops being.
28
+ const length = [...word].length;
29
+ if (index !== 0) {
30
+ if (used >= columns) {
31
+ rows += 1;
32
+ used = 0;
33
+ }
34
+ used += 1;
35
+ }
36
+ if (length > columns) {
37
+ const startsThisLine = 1 + Math.floor((length - (columns - used) - 1) / columns);
38
+ if (Math.floor((length - 1) / columns) < startsThisLine) {
39
+ rows += 1;
40
+ used = 0;
41
+ }
42
+ for (let taken = 0; taken < length; taken += 1) {
43
+ if (used < columns)
44
+ used += 1;
45
+ else {
46
+ rows += 1;
47
+ used = 1;
48
+ }
49
+ }
50
+ continue;
51
+ }
52
+ if (used > 0 && used + length > columns) {
53
+ rows += 1;
54
+ used = 0;
55
+ }
56
+ used += length;
57
+ }
58
+ return rows;
59
+ }
60
+ /** The rows a bordered panel occupies when its body wraps into `columns`. */
61
+ export function panelRows(lines, columns) {
62
+ return lines.reduce((rows, line) => rows + composeBandLine(line, columns).length, PANEL_CHROME_ROWS);
63
+ }
64
+ function IdentityHeader({ data, columns, secondary = true, }) {
65
+ const lockup = PLAIN_COMPACT_LOCKUP.split("\n");
66
+ if (columns < APPROVED_SIDE_RAIL_COLUMN_FLOOR) {
67
+ const primary = [
68
+ { title: "", lines: [lockup[0] ?? "tickmarkr"] },
69
+ {
70
+ title: "",
71
+ lines: [`v${data.binaryVersion} · binary ${GLYPHS.pass}`],
72
+ },
73
+ ];
74
+ const secondaryBand = [
75
+ { title: "", lines: [lockup[1] ?? "tickmarkr"] },
76
+ {
77
+ title: "",
78
+ lines: [
79
+ `${data.runId} · ${data.branch} ${data.status} · ${data.elapsed}`,
80
+ ],
81
+ },
82
+ ];
83
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(NarrowHeaderBand, { columns: columns, content: primary, rightStrong: true }), secondary && (_jsx(NarrowHeaderBand, { columns: columns, content: secondaryBand }))] }));
84
+ }
85
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsx(BodyText, { emphasis: "strong", children: lockup[0] ?? "tickmarkr" }), _jsxs(BodyText, { emphasis: "strong", children: ["v", data.binaryVersion, " \u00B7 binary ", GLYPHS.pass] })] }), secondary && (_jsxs(Box, { justifyContent: "space-between", children: [_jsx(BodyText, { emphasis: "strong", children: lockup[1] ?? "tickmarkr" }), _jsxs(BodyText, { children: [data.runId, " \u00B7 ", data.branch, " ", data.status, " \u00B7 ", data.elapsed] })] }))] }));
86
+ }
87
+ function NarrowHeaderBand({ columns, content, rightStrong = false, }) {
88
+ const widths = allocateBandColumns(columns, content, NARROW_HEADER_ALLOCATION);
89
+ return (_jsxs(CockpitGrid, { columns: columns, columnContents: content, allocation: NARROW_HEADER_ALLOCATION, children: [_jsx(BandLines, { columns: Math.max(1, widths[0]), lines: content[0].lines, emphasis: "strong" }), _jsx(Box, { alignItems: "flex-end", flexDirection: "column", children: _jsx(BandLines, { columns: Math.max(1, widths[1]), lines: content[1].lines, emphasis: rightStrong ? "strong" : "normal" }) })] }));
90
+ }
91
+ function NavigationPanel() {
92
+ return (_jsxs(Panel, { title: "VIEWS", width: 16, children: [_jsxs(BodyText, { emphasis: "strong", children: [GLYPHS.pointer, " Run"] }), _jsx(BodyText, { children: " Tasks" }), _jsx(BodyText, { children: " Gates" }), _jsx(BodyText, { children: " Journal" }), _jsx(BodyText, { children: " Fleet" })] }));
93
+ }
94
+ function KeysPanel() {
95
+ return (_jsx(Panel, { title: "KEYS", width: 16, children: KEYBAR_KEYS.run.map((item) => (_jsxs(Box, { children: [_jsx(BodyText, { emphasis: "strong", children: item.key }), _jsxs(BodyText, { children: [" ", item.label] })] }, item.key))) }));
96
+ }
97
+ function SizedJournalPanel({ rows, bodyRows, }) {
98
+ const visible = rows.slice(0, bodyRows);
99
+ const emptyRows = Math.max(0, bodyRows - visible.length);
100
+ const journal = JournalRowPanel({ rows: visible });
101
+ const journalProps = journal.props;
102
+ return cloneElement(journal, {}, journalProps.children, emptyRows > 0 ? _jsx(Box, { height: emptyRows }, "journal-space") : null);
103
+ }
104
+ function RunStats({ data, mode, }) {
105
+ if (mode === "summary") {
106
+ return (_jsx(BodyText, { children: `tasks ${data.tasks.done}/${data.tasks.total} · gates ${data.gates.passed}/${data.gates.total} · pass ${data.passRate.value}%` }));
107
+ }
108
+ return (_jsxs(CockpitGrid, { children: [_jsx(StatTile, { label: "TASKS", value: `${data.tasks.done}/${data.tasks.total}`, samples: data.tasks.samples }), _jsx(StatTile, { label: "GATES", value: `${data.gates.passed}/${data.gates.total}`, samples: data.gates.samples }), _jsx(StatTile, { label: "PASS RATE", value: `${data.passRate.value}%`, samples: data.passRate.samples })] }));
109
+ }
110
+ function ApprovedProgress({ data, caption, }) {
111
+ return (_jsxs(Panel, { title: "PROGRESS", children: [_jsx(ProgressMeter, { value: data.progress, width: 28 }), caption && _jsx(BodyText, { emphasis: "dim", children: data.progressCaption })] }));
112
+ }
113
+ function CompactProgress({ data, caption, meterWidth = 28, }) {
114
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { flexDirection: "row", flexWrap: "nowrap", children: [_jsx(BodyText, { emphasis: "strong", children: "PROGRESS " }), _jsx(ProgressMeter, { value: data.progress, width: meterWidth })] }), caption && _jsx(BodyText, { emphasis: "dim", children: data.progressCaption })] }));
115
+ }
116
+ function pairedTextRows(left, right, columns) {
117
+ const leftWidth = [...left].length;
118
+ const rightWidth = [...right].length;
119
+ const required = leftWidth + rightWidth;
120
+ if (required <= columns)
121
+ return 1;
122
+ const leftColumns = Math.max(1, Math.floor((Math.max(1, columns) * leftWidth) / required));
123
+ const rightColumns = Math.max(1, Math.max(1, columns) - leftColumns);
124
+ return Math.max(wrappedRows(left, leftColumns), wrappedRows(right, rightColumns));
125
+ }
126
+ function narrowHeaderRows(left, right, columns) {
127
+ const content = [
128
+ { title: "", lines: [left] },
129
+ { title: "", lines: [right] },
130
+ ];
131
+ const widths = allocateBandColumns(columns, content, NARROW_HEADER_ALLOCATION);
132
+ return Math.max(...content.map((column, index) => composeBandLine(column.lines[0], Math.max(1, widths[index])).length));
133
+ }
134
+ function headerRowsFor(layout, data, columns) {
135
+ const lockup = PLAIN_COMPACT_LOCKUP.split("\n");
136
+ const measure = columns < APPROVED_SIDE_RAIL_COLUMN_FLOOR
137
+ ? narrowHeaderRows
138
+ : pairedTextRows;
139
+ const primaryRows = measure(lockup[0] ?? "tickmarkr", `v${data.binaryVersion} · binary ${GLYPHS.pass}`, columns);
140
+ if (!layout.elements.secondaryHeader)
141
+ return primaryRows;
142
+ return primaryRows + measure(lockup[1] ?? "tickmarkr", `${data.runId} · ${data.branch} ${data.status} · ${data.elapsed}`, columns);
143
+ }
144
+ function compactJournalRows(rows, layout, data, columns) {
145
+ const statRows = layout.stats.mode === "tiles" ? 5 : 1;
146
+ const progressRows = layout.elements.progressBar
147
+ ? 1 + (layout.elements.progressCaption ? 1 : 0)
148
+ : 0;
149
+ const fixedRows = headerRowsFor(layout, data, columns)
150
+ + 2 // permanent status strip and keybar
151
+ + 3 // outer RUN panel border and title
152
+ + statRows
153
+ + progressRows
154
+ + 3; // journal border and title
155
+ return Math.max(1, Math.min(layout.journalRows, Math.floor(rows) - fixedRows));
156
+ }
157
+ function LadderRunPanel({ data, layout, columns, rows, compactMeterWidth, }) {
158
+ const compactBodyRows = compactJournalRows(rows, layout, data, columns);
159
+ // The approved bordered progress panel has the same meter/caption as the
160
+ // compact form plus its border, title row and closing border. It is restored
161
+ // only after the resolved ladder has retained every full-arrangement element
162
+ // and the journal can pay those three chrome rows without disappearing.
163
+ const approvedProgressChromeRows = 3;
164
+ const approvedArrangement = layout.elements.secondaryHeader
165
+ && layout.elements.progressBar
166
+ && layout.elements.progressCaption
167
+ && layout.stats.mode === "tiles"
168
+ && compactBodyRows > approvedProgressChromeRows;
169
+ const journalBodyRows = approvedArrangement
170
+ ? compactBodyRows - approvedProgressChromeRows
171
+ : compactBodyRows;
172
+ return (_jsxs(Panel, { title: "RUN", focused: true, flexGrow: 1, children: [_jsx(RunStats, { data: data, mode: layout.stats.mode }), layout.elements.progressBar && (approvedArrangement
173
+ ? (_jsx(ApprovedProgress, { data: data, caption: layout.elements.progressCaption }))
174
+ : (_jsx(CompactProgress, { data: data, caption: layout.elements.progressCaption, meterWidth: compactMeterWidth }))), _jsx(SizedJournalPanel, { rows: data.journalRows, bodyRows: journalBodyRows })] }));
175
+ }
176
+ function LegacyRunPanel({ data }) {
177
+ return (_jsxs(Panel, { title: "RUN", focused: true, flexGrow: 1, children: [_jsx(RunStats, { data: data, mode: "tiles" }), _jsxs(Panel, { title: "PROGRESS", children: [_jsx(ProgressMeter, { value: data.progress, width: 28 }), _jsx(BodyText, { emphasis: "dim", children: data.progressCaption })] }), _jsx(JournalRowPanel, { rows: data.journalRows })] }));
178
+ }
179
+ export function RunCockpitFrame({ data, columns, rows, }) {
180
+ if (rows === undefined) {
181
+ return (_jsxs(Box, { flexDirection: "column", width: columns, children: [_jsx(IdentityHeader, { data: data, columns: columns }), _jsxs(Box, { flexDirection: "row", gap: 1, children: [_jsx(NavigationPanel, {}), _jsx(LegacyRunPanel, { data: data }), _jsx(KeysPanel, {})] }), _jsx(StatusStrip, { items: data.statusItems, width: columns }), _jsx(Keybar, { surface: "run", width: columns })] }));
182
+ }
183
+ const layout = resolveCockpitLayout(columns, rows);
184
+ if (layout.renderer === "plain")
185
+ return _jsx(_Fragment, {});
186
+ const showSideRails = columns >= APPROVED_SIDE_RAIL_COLUMN_FLOOR;
187
+ const contentLayout = showSideRails
188
+ ? layout
189
+ : {
190
+ ...layout,
191
+ stats: { ...layout.stats, mode: "summary", rows: 1 },
192
+ };
193
+ return (_jsxs(Box, { flexDirection: "column", width: columns, children: [_jsx(IdentityHeader, { data: data, columns: columns, secondary: layout.elements.secondaryHeader }), _jsxs(Box, { flexDirection: "row", gap: showSideRails ? 1 : 0, children: [showSideRails && _jsx(NavigationPanel, {}), _jsx(LadderRunPanel, { data: data, layout: contentLayout, columns: columns, rows: rows, compactMeterWidth: showSideRails ? undefined : 24 }), showSideRails && _jsx(KeysPanel, {})] }), _jsx(StatusStrip, { items: data.statusItems, width: columns }), _jsx(Keybar, { surface: "run", width: columns })] }));
194
+ }
@@ -0,0 +1,41 @@
1
+ import { type ReactElement } from "react";
2
+ import { type TickmarkrConfig } from "../../config/config.js";
3
+ import { type ComponentState, type JournalRow } from "./components.js";
4
+ import type { DemoCaptures } from "./demo.js";
5
+ export type SetupCockpitData = {
6
+ readonly binaryVersion: string;
7
+ readonly harnesses: readonly {
8
+ readonly id: string;
9
+ readonly version: string;
10
+ readonly modelCount: number;
11
+ readonly state: ComponentState;
12
+ readonly stateWord: string;
13
+ }[];
14
+ readonly deniedChannels: readonly {
15
+ readonly channel: string;
16
+ readonly reason: string;
17
+ }[];
18
+ readonly counts: {
19
+ readonly found: number;
20
+ readonly authenticated: number;
21
+ readonly routable: number;
22
+ };
23
+ readonly config: TickmarkrConfig;
24
+ readonly overlayDiff: string;
25
+ readonly stagedChanges: readonly string[];
26
+ readonly reviewRows: readonly JournalRow[];
27
+ readonly overlayTarget: string;
28
+ };
29
+ export declare function deriveSetupCockpitData(captures: DemoCaptures, binaryVersion: string): SetupCockpitData;
30
+ /**
31
+ * The contracted ladder (§5.4) governs the elements every surface shares. The
32
+ * detail panels below it are the setup body, so they surrender first, from the
33
+ * bottom of this list upward: what a step is *about* outlives what merely
34
+ * describes the fleet.
35
+ */
36
+ export declare const SETUP_DETAIL_ORDER: readonly ["detected", "consultsAndReviewers", "overlayDiff", "fleetAndGates"];
37
+ export declare function SetupCockpitFrame({ data, columns, rows, }: {
38
+ data: SetupCockpitData;
39
+ columns: number;
40
+ rows?: number;
41
+ }): ReactElement;