tickmarkr 1.85.0 → 1.86.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 -2
- package/dist/adapters/catalog-remote.d.ts +64 -0
- package/dist/adapters/catalog-remote.js +287 -0
- package/dist/adapters/catalog.d.ts +96 -0
- package/dist/adapters/catalog.js +176 -0
- package/dist/adapters/claude-code.js +5 -3
- package/dist/adapters/fake.js +33 -4
- package/dist/adapters/model-lints.d.ts +25 -5
- package/dist/adapters/model-lints.js +184 -50
- package/dist/adapters/model-windows.d.ts +31 -0
- package/dist/adapters/model-windows.js +69 -0
- package/dist/adapters/prompt.d.ts +5 -1
- package/dist/adapters/prompt.js +13 -4
- package/dist/adapters/registry.d.ts +25 -26
- package/dist/adapters/registry.js +173 -110
- package/dist/adapters/types.js +15 -3
- package/dist/brand.d.ts +5 -1
- package/dist/brand.js +18 -2
- package/dist/cli/commands/doctor.d.ts +3 -0
- package/dist/cli/commands/doctor.js +43 -21
- package/dist/cli/commands/fleet.d.ts +7 -0
- package/dist/cli/commands/fleet.js +94 -74
- package/dist/cli/commands/init.js +118 -5
- package/dist/cli/commands/status.js +44 -18
- package/dist/compile/gsd.d.ts +2 -1
- package/dist/compile/gsd.js +68 -2
- package/dist/compile/native.d.ts +14 -0
- package/dist/compile/native.js +161 -12
- package/dist/config/config.d.ts +20 -5
- package/dist/config/config.js +96 -64
- package/dist/config/fleet-overlay.d.ts +25 -20
- package/dist/config/fleet-overlay.js +195 -77
- package/dist/config/fleet-why.d.ts +23 -0
- package/dist/config/fleet-why.js +42 -0
- package/dist/drivers/herdr.d.ts +1 -0
- package/dist/drivers/herdr.js +70 -19
- package/dist/gates/acceptance.js +7 -2
- package/dist/gates/llm.d.ts +0 -1
- package/dist/gates/llm.js +5 -30
- package/dist/gates/review.d.ts +2 -1
- package/dist/gates/review.js +9 -7
- package/dist/gates/verdict-cause.d.ts +4 -0
- package/dist/gates/verdict-cause.js +63 -0
- package/dist/graph/schema.d.ts +6 -0
- package/dist/graph/schema.js +8 -5
- package/dist/route/router.d.ts +0 -5
- package/dist/route/router.js +16 -20
- package/dist/run/consult.d.ts +6 -0
- package/dist/run/consult.js +35 -25
- package/dist/run/daemon.js +71 -15
- package/dist/run/journal.js +87 -7
- package/dist/tui/cockpit/capture.d.ts +12 -0
- package/dist/tui/cockpit/capture.js +37 -1
- package/dist/tui/cockpit/components.js +8 -8
- package/dist/tui/cockpit/theme.d.ts +32 -26
- package/dist/tui/cockpit/theme.js +11 -5
- package/dist/tui/ink/components.d.ts +0 -15
- package/dist/tui/ink/components.js +0 -17
- package/dist/tui/ink/fleet-app.d.ts +4 -1
- package/dist/tui/ink/fleet-app.js +134 -13
- package/fixtures/sample.native.md +1 -1
- package/package.json +1 -1
- package/skills/tickmarkr-overseer/SKILL.md +354 -34
- package/skills/tickmarkr-overseer/scripts/watch-artifacts.sh +70 -0
- package/skills/tickmarkr-overseer/scripts/watch-panes.sh +1 -1
- package/dist/tui/ink/studio-app.d.ts +0 -59
- package/dist/tui/ink/studio-app.js +0 -320
- package/dist/tui/save.d.ts +0 -38
- package/dist/tui/save.js +0 -96
- package/dist/tui/staging.d.ts +0 -29
- package/dist/tui/staging.js +0 -78
package/dist/run/journal.js
CHANGED
|
@@ -195,7 +195,7 @@ export function structuredFindings(gate, details, _scopeFiles = []) {
|
|
|
195
195
|
const VOLATILE_TOKENS = [
|
|
196
196
|
[/\u001b\[[0-9;]*[a-zA-Z]/g, ""], // ANSI styling
|
|
197
197
|
[/\b\d{4}-\d{2}-\d{2}[T ][\d:]+(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?\b/g, "<ts>"], // timestamps
|
|
198
|
-
[/\brun-\d{8}-\d{6}
|
|
198
|
+
[/\brun-\d{8}-\d{6}(?:-\d{16})?\b/g, "<run>"], // run identifiers
|
|
199
199
|
[/\b0x[0-9a-fA-F]+\b/g, "<addr>"], // memory addresses
|
|
200
200
|
// An absolute path INTO the repo keeps its repo-relative tail — that tail IS identity (a defect in
|
|
201
201
|
// daemon.ts is not a defect in journal.ts); only the machine/worktree prefix ahead of it is volatile.
|
|
@@ -227,15 +227,67 @@ const eraseVolatile = (text) => VOLATILE_TOKENS.reduce((out, [re, replacement])
|
|
|
227
227
|
// difference and banned a retry that was never redundant. Newlines survive (payload spans cannot
|
|
228
228
|
// cross one) and the line-wise trim below finishes the job.
|
|
229
229
|
const collapseRuns = (text) => text.replace(/[^\S\n]+/g, " ");
|
|
230
|
+
// v1.85 T34: the runner's TALLY moves with the base, not with the defect. When another task merges
|
|
231
|
+
// ahead and adds test files, vitest re-counts the suite — `192 passed (197)` becomes `193 passed
|
|
232
|
+
// (198)` — while the FAIL headlines name the same defect in the same order, so a substantively
|
|
233
|
+
// identical gate failure re-fingerprinted and gate-fingerprint-cap never counted the repeat
|
|
234
|
+
// (measured on T21 in run-20260805-164546: details at 17:33:02 and 18:11:01 differ only so).
|
|
235
|
+
//
|
|
236
|
+
// Why provenance AND shape, and why not digits as a class: a blanket \d+ collapse also erases counts
|
|
237
|
+
// that ARE identity — the failed-assertion count, the failing-suite count, an exit status, an error
|
|
238
|
+
// code — and the rule above governs: a missed cap costs one extra round, a false cap bans a
|
|
239
|
+
// legitimate retry. So the mask is gated on PROVENANCE first: only lines inside the `failing tests:`
|
|
240
|
+
// block baseline.ts:209-219 emits (up to its blank-line/`new failure fingerprints` boundary) are
|
|
241
|
+
// eligible, which keeps review prose, quoted diffs and assertion payloads structurally unreachable —
|
|
242
|
+
// and that block's own `FAIL … > test name` headlines are excluded by SHAPE: only a line that starts
|
|
243
|
+
// with the runner's own `Tests`/`Test Files` summary token is a tally line.
|
|
244
|
+
//
|
|
245
|
+
// Masked tally FIELDS, exactly: the passed count, the skipped and todo counts, and the derived
|
|
246
|
+
// parenthesized total immediately following the tally sequence. Deliberately KEPT (a reader uses
|
|
247
|
+
// each of them to tell two failures apart): every `N failed` count on the line (which suites and how
|
|
248
|
+
// many assertions actually broke — the defect's identity), everything after the derived total (an
|
|
249
|
+
// appended `| exit 1`, an appended `(404)` code), and every other number anywhere.
|
|
250
|
+
const RUNNER_TALLY_LINE = /^([ \t]*(?:Test Files|Tests)[ \t]+)((?:\d+ (?:failed|passed|skipped|todo)[ \t]*\|[ \t]*)*\d+ (?:failed|passed|skipped|todo))([ \t]*\(\d+\))?(.*)$/;
|
|
251
|
+
const TALLY_MOVED_FIELD = /\d+ (?=passed|skipped|todo)/g;
|
|
252
|
+
const maskTallyLine = (line) => {
|
|
253
|
+
const m = RUNNER_TALLY_LINE.exec(line);
|
|
254
|
+
if (!m)
|
|
255
|
+
return line;
|
|
256
|
+
const fields = m[2].replace(TALLY_MOVED_FIELD, "#");
|
|
257
|
+
const total = (m[3] ?? "").replace(/\d+/, "#");
|
|
258
|
+
return m[1] + fields + total + m[4];
|
|
259
|
+
};
|
|
260
|
+
// Computed on the FULL details text BEFORE any payload split: every recorded tally-bearing detail
|
|
261
|
+
// carries the `failing tests:` header, so gating on it closes the false-line-start axis (the mask
|
|
262
|
+
// never sees a slice boundary) and the wrong-provenance axis in one place.
|
|
263
|
+
const maskRunnerTallies = (text) => {
|
|
264
|
+
let inBlock = false;
|
|
265
|
+
return text
|
|
266
|
+
.split("\n")
|
|
267
|
+
.map((line) => {
|
|
268
|
+
if (!inBlock) {
|
|
269
|
+
if (line.trim() === "failing tests:")
|
|
270
|
+
inBlock = true;
|
|
271
|
+
return line;
|
|
272
|
+
}
|
|
273
|
+
if (line.trim() === "" || line.startsWith("new failure fingerprints")) {
|
|
274
|
+
inBlock = false;
|
|
275
|
+
return line;
|
|
276
|
+
}
|
|
277
|
+
return maskTallyLine(line);
|
|
278
|
+
})
|
|
279
|
+
.join("\n");
|
|
280
|
+
};
|
|
230
281
|
/** Normalized identity of a gate failure: the same defect, seen twice, normalizes to the same bytes. */
|
|
231
282
|
export function normalizeGateFailure(details) {
|
|
283
|
+
const masked = maskRunnerTallies(details);
|
|
232
284
|
let out = "";
|
|
233
285
|
let last = 0;
|
|
234
|
-
for (const m of
|
|
235
|
-
out += collapseRuns(eraseVolatile(
|
|
286
|
+
for (const m of masked.matchAll(PAYLOAD_SPAN)) {
|
|
287
|
+
out += collapseRuns(eraseVolatile(masked.slice(last, m.index))) + m[0];
|
|
236
288
|
last = m.index + m[0].length;
|
|
237
289
|
}
|
|
238
|
-
out += collapseRuns(eraseVolatile(
|
|
290
|
+
out += collapseRuns(eraseVolatile(masked.slice(last)));
|
|
239
291
|
return out.split("\n").map((l) => l.trim()).filter(Boolean).join("\n");
|
|
240
292
|
}
|
|
241
293
|
// Two normalized-identical failures of one gate on one task buy no more rounds (the ladder cannot fix
|
|
@@ -538,9 +590,37 @@ export function engagementComparable(events, loadedHash) {
|
|
|
538
590
|
return { comparable: false, reason: "unbound" };
|
|
539
591
|
return recorded === loadedHash ? { comparable: true, recorded } : { comparable: false, reason: "mismatch", recorded };
|
|
540
592
|
}
|
|
593
|
+
const RUN_SEQUENCE_WIDTH = 16;
|
|
594
|
+
// The daemon mints before acquiring graph.lock, and each CLI invocation has fresh module state. Claim
|
|
595
|
+
// a repository-state ticket with mkdir's atomic EEXIST boundary instead: a losing process advances and
|
|
596
|
+
// retries, while the winning directory remains as the durable high-water evidence for later invocations.
|
|
597
|
+
function claimRunSequence(repoRoot = process.cwd()) {
|
|
598
|
+
const dir = join(tickmarkrDir(repoRoot), "run-id-sequence");
|
|
599
|
+
mkdirSync(dir, { recursive: true });
|
|
600
|
+
const allocated = readdirSync(dir).filter((name) => /^\d{16}$/.test(name));
|
|
601
|
+
let candidate = allocated.reduce((max, name) => {
|
|
602
|
+
const value = BigInt(name);
|
|
603
|
+
return value > max ? value : max;
|
|
604
|
+
}, 0n) + 1n;
|
|
605
|
+
while (true) {
|
|
606
|
+
const suffix = candidate.toString().padStart(RUN_SEQUENCE_WIDTH, "0");
|
|
607
|
+
if (suffix.length > RUN_SEQUENCE_WIDTH)
|
|
608
|
+
throw new Error("run id sequence exhausted");
|
|
609
|
+
try {
|
|
610
|
+
mkdirSync(join(dir, suffix));
|
|
611
|
+
return suffix;
|
|
612
|
+
}
|
|
613
|
+
catch (error) {
|
|
614
|
+
if (error.code !== "EEXIST")
|
|
615
|
+
throw error;
|
|
616
|
+
candidate += 1n;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
541
620
|
export function newRunId(now = new Date()) {
|
|
542
621
|
const p = (n, w = 2) => String(n).padStart(w, "0");
|
|
543
|
-
|
|
622
|
+
const instant = `${now.getUTCFullYear()}${p(now.getUTCMonth() + 1)}${p(now.getUTCDate())}-${p(now.getUTCHours())}${p(now.getUTCMinutes())}${p(now.getUTCSeconds())}`;
|
|
623
|
+
return `run-${instant}-${claimRunSequence()}`;
|
|
544
624
|
}
|
|
545
625
|
// Sol #4: one strict parser for every journal open/create path — generated run-… ids plus test
|
|
546
626
|
// suffix chars only; forbid path separators, dot-segments, and empty ids.
|
|
@@ -578,7 +658,7 @@ function readJsonl(path) {
|
|
|
578
658
|
return out;
|
|
579
659
|
}
|
|
580
660
|
// Cross-run telemetry for Phase-12 profile derivation: the last K runs' rows, each
|
|
581
|
-
// tagged with its runId (runIds are zero-padded run-
|
|
661
|
+
// tagged with its runId (runIds are zero-padded run-UTCYYYYMMDD-HHMMSS-sequence ⇒ plain .sort() is
|
|
582
662
|
// chronological, same as latestRunId). Rows are facts, not classifications — Phase 12
|
|
583
663
|
// owns the quality-denominator/reward policy. A safeParse failure drops that one row
|
|
584
664
|
// (same posture as a torn line); a garbage row must never crash profile derivation.
|
|
@@ -589,7 +669,7 @@ export function readAllTelemetry(repoRoot, lastK, opts = {}) {
|
|
|
589
669
|
if (!existsSync(dir))
|
|
590
670
|
return [];
|
|
591
671
|
let runIds = readdirSync(dir).filter((d) => d.startsWith("run-")).sort();
|
|
592
|
-
// VIS-03 reset cursor:
|
|
672
|
+
// VIS-03 reset cursor: UTC clock fields and a fixed-width sequence make string > chronological
|
|
593
673
|
if (opts.after)
|
|
594
674
|
runIds = runIds.filter((id) => id > opts.after);
|
|
595
675
|
runIds = runIds.slice(-lastK);
|
|
@@ -209,6 +209,18 @@ export type RegeneratedGoldenFrame = GoldenFrameCase & {
|
|
|
209
209
|
readonly emitted: string;
|
|
210
210
|
};
|
|
211
211
|
export declare function regenerateGoldenFrames(binaryVersion?: string): Promise<readonly RegeneratedGoldenFrame[]>;
|
|
212
|
+
/**
|
|
213
|
+
* Canonicalize the one release-owned token in an ACTIVE golden frame.
|
|
214
|
+
*
|
|
215
|
+
* The grammar is deliberately positional: plain output owns the whole first
|
|
216
|
+
* line, while a setup frame owns the right-anchored `v<semver> · binary ✓`
|
|
217
|
+
* suffix. The latter preserves the suffix's right edge, so a longer version
|
|
218
|
+
* does not turn renderer padding into drift while any actual alignment change
|
|
219
|
+
* still does. Retired rendered frames never enter this exception.
|
|
220
|
+
*/
|
|
221
|
+
export declare function normalizeGoldenFrameVersionForComparison(frame: GoldenFrameCase, bytes: string): string;
|
|
222
|
+
/** An absent committed frame is a mismatch; it is never an empty agreement. */
|
|
223
|
+
export declare function goldenFrameMatchesCommitted(frame: RegeneratedGoldenFrame, committed: string | undefined): boolean;
|
|
212
224
|
export declare function findGoldenFrameMismatches(regenerated: readonly RegeneratedGoldenFrame[], committed: ReadonlyMap<string, string>): string[];
|
|
213
225
|
export type RegeneratedColourFrame = ColourFrameCase & {
|
|
214
226
|
readonly output: string;
|
|
@@ -564,13 +564,49 @@ export async function regenerateGoldenFrames(binaryVersion) {
|
|
|
564
564
|
}
|
|
565
565
|
return regenerated;
|
|
566
566
|
}
|
|
567
|
+
const SEMVER_TOKEN = String.raw `\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?`;
|
|
568
|
+
const PLAIN_VERSION_HEADER = new RegExp(`^(tickmarkr v)(${SEMVER_TOKEN})$`, "u");
|
|
569
|
+
const FRAME_VERSION_HEADER = new RegExp(`^(.*\\S)( +)v(${SEMVER_TOKEN})( · binary ✓)$`, "u");
|
|
570
|
+
const COMPARISON_VERSION = "<binary-version>";
|
|
571
|
+
/**
|
|
572
|
+
* Canonicalize the one release-owned token in an ACTIVE golden frame.
|
|
573
|
+
*
|
|
574
|
+
* The grammar is deliberately positional: plain output owns the whole first
|
|
575
|
+
* line, while a setup frame owns the right-anchored `v<semver> · binary ✓`
|
|
576
|
+
* suffix. The latter preserves the suffix's right edge, so a longer version
|
|
577
|
+
* does not turn renderer padding into drift while any actual alignment change
|
|
578
|
+
* still does. Retired rendered frames never enter this exception.
|
|
579
|
+
*/
|
|
580
|
+
export function normalizeGoldenFrameVersionForComparison(frame, bytes) {
|
|
581
|
+
if (isRetiredGoldenFrame(frame))
|
|
582
|
+
return bytes;
|
|
583
|
+
const lineBreak = bytes.indexOf("\n");
|
|
584
|
+
const header = lineBreak === -1 ? bytes : bytes.slice(0, lineBreak);
|
|
585
|
+
const rest = lineBreak === -1 ? "" : bytes.slice(lineBreak);
|
|
586
|
+
let normalized = header;
|
|
587
|
+
if (!frame.interactive || frame.ci) {
|
|
588
|
+
normalized = header.replace(PLAIN_VERSION_HEADER, `$1${COMPARISON_VERSION}`);
|
|
589
|
+
}
|
|
590
|
+
else {
|
|
591
|
+
normalized = header.replace(FRAME_VERSION_HEADER, (_match, prefix, gap, versionToken, suffix) => `${prefix}${" ".repeat(gap.length + versionToken.length)}v${COMPARISON_VERSION}${suffix}`);
|
|
592
|
+
}
|
|
593
|
+
return normalized === header ? bytes : `${normalized}${rest}`;
|
|
594
|
+
}
|
|
595
|
+
/** An absent committed frame is a mismatch; it is never an empty agreement. */
|
|
596
|
+
export function goldenFrameMatchesCommitted(frame, committed) {
|
|
597
|
+
return committed !== undefined
|
|
598
|
+
&& normalizeGoldenFrameVersionForComparison(frame, committed)
|
|
599
|
+
=== normalizeGoldenFrameVersionForComparison(frame, frame.output);
|
|
600
|
+
}
|
|
567
601
|
export function findGoldenFrameMismatches(regenerated, committed) {
|
|
568
602
|
// Membership is judged against the whole shipped manifest, retired cases
|
|
569
603
|
// included: a retired fixture is claimed, so only its bytes are exempt.
|
|
570
604
|
// Anything committed that no case claims is still named.
|
|
571
605
|
const expected = new Set(GOLDEN_FRAME_CASES.map((frame) => frame.fixture));
|
|
572
606
|
return [
|
|
573
|
-
...regenerated.flatMap((frame) => committed.get(frame.fixture)
|
|
607
|
+
...regenerated.flatMap((frame) => goldenFrameMatchesCommitted(frame, committed.get(frame.fixture))
|
|
608
|
+
? []
|
|
609
|
+
: [frame.fixture]),
|
|
574
610
|
...[...committed.keys()].filter((fixture) => !expected.has(fixture)),
|
|
575
611
|
].sort();
|
|
576
612
|
}
|
|
@@ -170,24 +170,24 @@ function statePresentation(state) {
|
|
|
170
170
|
case "active":
|
|
171
171
|
return {
|
|
172
172
|
glyph: GLYPHS.toggleActive,
|
|
173
|
-
color:
|
|
173
|
+
color: COCKPIT_DATA_RAMP[1].hex,
|
|
174
174
|
};
|
|
175
175
|
case "inactive":
|
|
176
176
|
return { glyph: GLYPHS.toggleInactive, dimmed: true };
|
|
177
177
|
case "pass":
|
|
178
178
|
return {
|
|
179
179
|
glyph: GLYPHS.pass,
|
|
180
|
-
color:
|
|
180
|
+
color: COCKPIT_DATA_RAMP[1].hex,
|
|
181
181
|
};
|
|
182
182
|
case "fail":
|
|
183
183
|
return {
|
|
184
184
|
glyph: GLYPHS.fail,
|
|
185
|
-
color:
|
|
185
|
+
color: COCKPIT_INKS.failure.hex,
|
|
186
186
|
};
|
|
187
187
|
case "warn":
|
|
188
188
|
return {
|
|
189
189
|
glyph: GLYPHS.attention,
|
|
190
|
-
color:
|
|
190
|
+
color: COCKPIT_INKS.warning.hex,
|
|
191
191
|
};
|
|
192
192
|
case "neutral":
|
|
193
193
|
return { glyph: GLYPHS.neutral, dimmed: true };
|
|
@@ -201,7 +201,7 @@ export function Panel({ title, focused = false, width, flexGrow, children, }) {
|
|
|
201
201
|
const content = Children.map(children, (child) => typeof child === "string" || typeof child === "number"
|
|
202
202
|
? _jsx(BodyText, { children: child })
|
|
203
203
|
: child);
|
|
204
|
-
return (_jsxs(Box, { flexDirection: "column", flexGrow: flexGrow, width: width, paddingX: 1, borderStyle: focused ? "double" : "round", borderColor:
|
|
204
|
+
return (_jsxs(Box, { flexDirection: "column", flexGrow: flexGrow, width: width, paddingX: 1, borderStyle: focused ? "double" : "round", borderColor: focused ? COCKPIT_DATA_RAMP[0].hex : COCKPIT_DATA_RAMP[3].hex, borderDimColor: !focused, children: [_jsx(Box, { children: focused ? (_jsxs(_Fragment, { children: [_jsx(Text, { color: COCKPIT_DATA_RAMP[0].hex, children: GLYPHS.pointer }), _jsxs(BodyText, { emphasis: "strong", children: [" ", title] })] })) : (_jsx(BodyText, { emphasis: "strong", children: title })) }), _jsx(Box, { flexDirection: "column", children: content })] }));
|
|
205
205
|
}
|
|
206
206
|
export function CockpitGrid({ children, columns, columnContents, allocation, }) {
|
|
207
207
|
const items = Children.toArray(children);
|
|
@@ -229,7 +229,7 @@ export function Sparkline({ samples, }) {
|
|
|
229
229
|
const level = sparklineLevel(sample, minimum, maximum);
|
|
230
230
|
const rampIndex = COCKPIT_DATA_RAMP.length - 1 - Math.round((level / (SPARKLINE_GLYPHS.length - 1)) * (COCKPIT_DATA_RAMP.length - 1));
|
|
231
231
|
const ink = COCKPIT_DATA_RAMP[rampIndex] ?? COCKPIT_DATA_RAMP[0];
|
|
232
|
-
return (_jsx(Text, { color:
|
|
232
|
+
return (_jsx(Text, { color: ink.hex, children: SPARKLINE_GLYPHS[level] }, `${index}:${sample}`));
|
|
233
233
|
}) }));
|
|
234
234
|
}
|
|
235
235
|
export function StatTile({ label, value, samples, focused, width, }) {
|
|
@@ -242,7 +242,7 @@ export function ProgressMeter({ value, width = 24, }) {
|
|
|
242
242
|
const valueLabel = Number.isInteger(percentage)
|
|
243
243
|
? percentage.toFixed(0)
|
|
244
244
|
: percentage.toFixed(1);
|
|
245
|
-
return (_jsxs(Box, { flexDirection: "row", flexWrap: "nowrap", height: 1, overflow: "hidden", "aria-role": "progressbar", "aria-label": `${valueLabel}% complete`, children: [_jsx(Text, { color:
|
|
245
|
+
return (_jsxs(Box, { flexDirection: "row", flexWrap: "nowrap", height: 1, overflow: "hidden", "aria-role": "progressbar", "aria-label": `${valueLabel}% complete`, children: [_jsx(Text, { color: COCKPIT_DATA_RAMP[0].hex, children: "█".repeat(filled) }), _jsx(Text, { dimColor: true, children: "░".repeat(safeWidth - filled) }), _jsxs(BodyText, { emphasis: "strong", children: [" ", valueLabel, "%"] })] }));
|
|
246
246
|
}
|
|
247
247
|
function OneLineItems({ children, width, label, }) {
|
|
248
248
|
return (_jsx(Box, { flexDirection: "row", flexWrap: "nowrap", width: width, height: 1, overflow: "hidden", "aria-label": label, children: children }));
|
|
@@ -285,6 +285,6 @@ export function StatusStrip({ items, width, }) {
|
|
|
285
285
|
}
|
|
286
286
|
export function JournalRowPanel({ rows, width, focused, title = "JOURNAL", selection, hover, }) {
|
|
287
287
|
return (_jsx(Panel, { title: title, focused: focused, width: width, children: rows.map((row, index) => (_jsxs(Box, { flexDirection: "row", flexWrap: "nowrap", height: 1, overflow: "hidden", children: [_jsx(BodyText, { emphasis: "dim", children: row.time }), _jsx(BodyText, { children: " " }), _jsx(StateGlyph, { state: row.state }), _jsx(BodyText, { emphasis: index === hover ? "strong" : "normal", children: index === hover ? HOVER_MARKER : " " }), index === selection && (_jsxs(BodyText, { emphasis: "strong", children: [GLYPHS.pointer, " "] })), index === hover
|
|
288
|
-
? (_jsx(Text, { inverse: true, color:
|
|
288
|
+
? (_jsx(Text, { inverse: true, color: COCKPIT_DATA_RAMP[0].hex, children: row.text }))
|
|
289
289
|
: _jsx(BodyText, { children: row.text })] }, row.id))) }));
|
|
290
290
|
}
|
|
@@ -7,19 +7,25 @@ export type ColourValue = {
|
|
|
7
7
|
export declare const LOGO_RAMP: readonly [84, 78, 41, 35];
|
|
8
8
|
/** Near-black panel fill against which every data shade must remain legible. */
|
|
9
9
|
export declare const COCKPIT_SURFACE: "#1a1a19";
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Bright-to-deep, single-hue data ink. Depth communicates magnitude, never tile identity.
|
|
12
|
+
* Anchored on xterm 114 (#87d787) — operator-chosen 2026-08-03 — with the hue (OKLab 144.2°)
|
|
13
|
+
* held constant down the ramp; steps descend in even OKLab lightness (0.094) and were searched
|
|
14
|
+
* and verified through guardDataRamp below. hex is the rendered ink (truecolor terminals);
|
|
15
|
+
* xterm is the nearest-distinct 256-colour fallback, documentation not render source.
|
|
16
|
+
*/
|
|
11
17
|
export declare const COCKPIT_DATA_RAMP: readonly [{
|
|
12
|
-
readonly xterm:
|
|
13
|
-
readonly hex: "#
|
|
18
|
+
readonly xterm: 114;
|
|
19
|
+
readonly hex: "#87d787";
|
|
14
20
|
}, {
|
|
15
|
-
readonly xterm:
|
|
16
|
-
readonly hex: "#
|
|
21
|
+
readonly xterm: 71;
|
|
22
|
+
readonly hex: "#5bbc5e";
|
|
17
23
|
}, {
|
|
18
|
-
readonly xterm:
|
|
19
|
-
readonly hex: "#
|
|
24
|
+
readonly xterm: 65;
|
|
25
|
+
readonly hex: "#4f9a51";
|
|
20
26
|
}, {
|
|
21
27
|
readonly xterm: 29;
|
|
22
|
-
readonly hex: "#
|
|
28
|
+
readonly hex: "#437944";
|
|
23
29
|
}];
|
|
24
30
|
/** Documented near-misses retained as guard fixtures, not special cases in the guard. */
|
|
25
31
|
export declare const EXCLUDED_DATA_SHADES: {
|
|
@@ -38,17 +44,17 @@ export declare const EXCLUDED_DATA_SHADES: {
|
|
|
38
44
|
*/
|
|
39
45
|
export declare const COCKPIT_INKS: {
|
|
40
46
|
readonly dataRamp: readonly [{
|
|
41
|
-
readonly xterm:
|
|
42
|
-
readonly hex: "#
|
|
47
|
+
readonly xterm: 114;
|
|
48
|
+
readonly hex: "#87d787";
|
|
43
49
|
}, {
|
|
44
|
-
readonly xterm:
|
|
45
|
-
readonly hex: "#
|
|
50
|
+
readonly xterm: 71;
|
|
51
|
+
readonly hex: "#5bbc5e";
|
|
46
52
|
}, {
|
|
47
|
-
readonly xterm:
|
|
48
|
-
readonly hex: "#
|
|
53
|
+
readonly xterm: 65;
|
|
54
|
+
readonly hex: "#4f9a51";
|
|
49
55
|
}, {
|
|
50
56
|
readonly xterm: 29;
|
|
51
|
-
readonly hex: "#
|
|
57
|
+
readonly hex: "#437944";
|
|
52
58
|
}];
|
|
53
59
|
readonly warning: {
|
|
54
60
|
readonly xterm: 214;
|
|
@@ -65,17 +71,17 @@ export declare const COCKPIT_INKS: {
|
|
|
65
71
|
};
|
|
66
72
|
/** Every drawable cockpit ink; the panel surface and text emphasis are not inks. */
|
|
67
73
|
export declare const COCKPIT_INK_VOCABULARY: readonly [{
|
|
68
|
-
readonly xterm:
|
|
69
|
-
readonly hex: "#
|
|
74
|
+
readonly xterm: 114;
|
|
75
|
+
readonly hex: "#87d787";
|
|
70
76
|
}, {
|
|
71
|
-
readonly xterm:
|
|
72
|
-
readonly hex: "#
|
|
77
|
+
readonly xterm: 71;
|
|
78
|
+
readonly hex: "#5bbc5e";
|
|
73
79
|
}, {
|
|
74
|
-
readonly xterm:
|
|
75
|
-
readonly hex: "#
|
|
80
|
+
readonly xterm: 65;
|
|
81
|
+
readonly hex: "#4f9a51";
|
|
76
82
|
}, {
|
|
77
83
|
readonly xterm: 29;
|
|
78
|
-
readonly hex: "#
|
|
84
|
+
readonly hex: "#437944";
|
|
79
85
|
}, {
|
|
80
86
|
readonly xterm: 214;
|
|
81
87
|
readonly hex: "#ffaf00";
|
|
@@ -105,16 +111,16 @@ export declare const TEXT_EMPHASIS_TOKENS: {
|
|
|
105
111
|
/** Deliberate 16-colour choices. Renderers select this map; they do not infer one. */
|
|
106
112
|
export declare const REDUCED_COLOUR_MAPPING: {
|
|
107
113
|
readonly dataRamp: readonly [{
|
|
108
|
-
readonly from: "#
|
|
114
|
+
readonly from: "#87d787";
|
|
109
115
|
readonly to: "bright-green";
|
|
110
116
|
}, {
|
|
111
|
-
readonly from: "#
|
|
117
|
+
readonly from: "#5bbc5e";
|
|
112
118
|
readonly to: "green";
|
|
113
119
|
}, {
|
|
114
|
-
readonly from: "#
|
|
120
|
+
readonly from: "#4f9a51";
|
|
115
121
|
readonly to: "green";
|
|
116
122
|
}, {
|
|
117
|
-
readonly from: "#
|
|
123
|
+
readonly from: "#437944";
|
|
118
124
|
readonly to: "dim-green";
|
|
119
125
|
}];
|
|
120
126
|
readonly warning: {
|
|
@@ -3,12 +3,18 @@ import { BRAND_RAMP, GLYPHS } from "../../brand.js";
|
|
|
3
3
|
export const LOGO_RAMP = BRAND_RAMP;
|
|
4
4
|
/** Near-black panel fill against which every data shade must remain legible. */
|
|
5
5
|
export const COCKPIT_SURFACE = "#1a1a19";
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Bright-to-deep, single-hue data ink. Depth communicates magnitude, never tile identity.
|
|
8
|
+
* Anchored on xterm 114 (#87d787) — operator-chosen 2026-08-03 — with the hue (OKLab 144.2°)
|
|
9
|
+
* held constant down the ramp; steps descend in even OKLab lightness (0.094) and were searched
|
|
10
|
+
* and verified through guardDataRamp below. hex is the rendered ink (truecolor terminals);
|
|
11
|
+
* xterm is the nearest-distinct 256-colour fallback, documentation not render source.
|
|
12
|
+
*/
|
|
7
13
|
export const COCKPIT_DATA_RAMP = [
|
|
8
|
-
{ xterm:
|
|
9
|
-
{ xterm:
|
|
10
|
-
{ xterm:
|
|
11
|
-
{ xterm: 29, hex: "#
|
|
14
|
+
{ xterm: 114, hex: "#87d787" },
|
|
15
|
+
{ xterm: 71, hex: "#5bbc5e" },
|
|
16
|
+
{ xterm: 65, hex: "#4f9a51" },
|
|
17
|
+
{ xterm: 29, hex: "#437944" },
|
|
12
18
|
];
|
|
13
19
|
/** Documented near-misses retained as guard fixtures, not special cases in the guard. */
|
|
14
20
|
export const EXCLUDED_DATA_SHADES = {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
|
-
import { type SaveTarget } from "../save.js";
|
|
3
2
|
export type FleetListRow = {
|
|
4
3
|
id: string;
|
|
5
4
|
content: ReactNode;
|
|
@@ -22,17 +21,3 @@ export declare function FleetReviewScreen({ title, legend, diff, }: {
|
|
|
22
21
|
legend: string;
|
|
23
22
|
diff: string;
|
|
24
23
|
}): import("react").JSX.Element;
|
|
25
|
-
export type DiffConfirmationProps = {
|
|
26
|
-
target: SaveTarget;
|
|
27
|
-
targetPath: string;
|
|
28
|
-
diff: string;
|
|
29
|
-
liveRun: boolean;
|
|
30
|
-
};
|
|
31
|
-
export declare function DiffConfirmationScreen(props: DiffConfirmationProps): import("react").JSX.Element;
|
|
32
|
-
export declare function StudioScreen({ tabs, active, lines, status, children, }: {
|
|
33
|
-
tabs: string[];
|
|
34
|
-
active: number;
|
|
35
|
-
lines: string[];
|
|
36
|
-
status?: string;
|
|
37
|
-
children?: ReactNode;
|
|
38
|
-
}): import("react").JSX.Element;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
3
|
import { GLYPHS } from "../../brand.js";
|
|
4
|
-
import { RELOAD_GUARD_NOTICE } from "../save.js";
|
|
5
4
|
function keyedLines(lines) {
|
|
6
5
|
const occurrences = new Map();
|
|
7
6
|
return lines.map((text) => {
|
|
@@ -24,19 +23,3 @@ export function FleetListScreen({ title, legend, rows, cursor, details = [], })
|
|
|
24
23
|
export function FleetReviewScreen({ title, legend, diff, }) {
|
|
25
24
|
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: title }), _jsx(Text, { dimColor: true, children: legend }), _jsx(Text, { children: diff })] }));
|
|
26
25
|
}
|
|
27
|
-
export function DiffConfirmationScreen(props) {
|
|
28
|
-
return _jsx(TextLines, { lines: [
|
|
29
|
-
`Save overlay — ${props.targetPath} (${props.target === "repo" ? "repository" : "global"} target)`,
|
|
30
|
-
"t toggle target · y confirm · n/esc cancel",
|
|
31
|
-
...(props.liveRun ? [RELOAD_GUARD_NOTICE] : []),
|
|
32
|
-
"─ diff ─",
|
|
33
|
-
props.diff || "(no overlay changes)",
|
|
34
|
-
] });
|
|
35
|
-
}
|
|
36
|
-
export function StudioScreen({ tabs, active, lines, status = "no staged changes", children, }) {
|
|
37
|
-
const tabBar = [
|
|
38
|
-
"tickmarkr ui ──",
|
|
39
|
-
...tabs.map((label, index) => `[${index + 1}]${index === active ? "*" : ""}${label}`),
|
|
40
|
-
].join(" ");
|
|
41
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: tabBar }), children ?? _jsx(TextLines, { lines: lines }), _jsx(Text, { dimColor: true, children: status })] }));
|
|
42
|
-
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type AuthHealth, type WorkerAdapter } from "../../adapters/types.js";
|
|
2
2
|
import type { MapEntry, RoutingMode, Tier } from "../../config/config.js";
|
|
3
3
|
import { type Shape } from "../../graph/schema.js";
|
|
4
4
|
export type FleetSteeringKey = "review" | "consult";
|
|
@@ -40,6 +40,7 @@ type AgentCli = {
|
|
|
40
40
|
};
|
|
41
41
|
export type FleetModelGroup = {
|
|
42
42
|
adapter: string;
|
|
43
|
+
vendor?: string;
|
|
43
44
|
rows: Array<{
|
|
44
45
|
model: string;
|
|
45
46
|
tier?: Tier;
|
|
@@ -51,6 +52,8 @@ export type FleetClassification = {
|
|
|
51
52
|
model: string;
|
|
52
53
|
tier: Tier;
|
|
53
54
|
note: string;
|
|
55
|
+
vendor?: string;
|
|
56
|
+
channel?: "sub" | "api";
|
|
54
57
|
};
|
|
55
58
|
export type FleetModeOption = {
|
|
56
59
|
id: RoutingMode;
|