mirror of
https://github.com/mvschwarz/openrig.git
synced 2026-11-07 22:58:42 -10:00
fix(tui): slice-17 guard residual — locked runtime · ctx% meta always, names truncate (guard BLOCKING at b55d95c6)
Meta is the locked form with the middle dot, including honest 'runtime · —'; the display name yields with … under the fixed pane width, never the meta. The whole meta paints dim as one run. Pins: typical-name truncation, null-context, short-name untruncated, extreme-name, whole-meta styling. Display-truncation consequence (namespaced agents can render ambiguously at depth 4 in the 30-col pane) flagged to guard/pm for the founder polish loop — row identity remains exact in the row model, hit actions, and detail pane. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
1 parent
b55d95c602
commit
a53fcb2e78
3 files changed
+64
-45
No files matched your search
@@ -63,32 +63,28 @@ function contentOf(row: ExplorerRow, kind: string): string {
|
||||
return stripped;
|
||||
}
|
||||
|
||||
/** meta candidates, RICHEST first — the renderer picks the first that fits
|
||||
* WITHOUT sacrificing row identity (names never become ambiguous to make
|
||||
* room for telemetry) */
|
||||
function metaOf(row: ExplorerRow, snap: FleetSnapshot): string[] {
|
||||
function metaOf(row: ExplorerRow, snap: FleetSnapshot): string {
|
||||
const parsed = parseKey(row.key);
|
||||
if (!parsed) return [];
|
||||
if (!parsed) return "";
|
||||
if (parsed.kind === "agent") {
|
||||
const [host, rig, pod, ...name] = parsed.parts;
|
||||
const agent = snap.hosts
|
||||
.find((h) => h.name === host)?.rigs.find((r) => r.name === rig)
|
||||
?.pods.find((p) => p.name === pod)?.agents.find((a) => a.name === name.join("/"));
|
||||
if (!agent) return [];
|
||||
// Locked meta = runtime · ctx% (mini-req 1). The runtime's DISPLAY form is
|
||||
// its first hyphen token — the literal mockups render exactly "claude 18%"
|
||||
// for claude-code seats (tui-ascii-aesthetic.html) — served data unchanged.
|
||||
// Honest-unknown: no served ctx → an explicit —, never a fabricated value.
|
||||
if (!agent) return "";
|
||||
// LOCKED meta form (mini-req 1, guard-ruled): ALWAYS `runtime · ctx%` —
|
||||
// never context-only. The runtime's DISPLAY form is its first hyphen
|
||||
// token (the literal mockups render "claude" for claude-code seats);
|
||||
// honest-unknown ctx renders `runtime · —`, never a fabricated value.
|
||||
const runtimeToken = agent.runtime.split("-")[0] || agent.runtime;
|
||||
const ctx = agent.context == null ? "—" : `${agent.context}%`;
|
||||
return [`${runtimeToken} ${ctx}`, ctx];
|
||||
return `${runtimeToken} · ${agent.context == null ? "—" : `${agent.context}%`}`;
|
||||
}
|
||||
if (parsed.kind === "pod") {
|
||||
const [host, rig, pod] = parsed.parts;
|
||||
const found = snap.hosts.find((h) => h.name === host)?.rigs.find((r) => r.name === rig)?.pods.find((p) => p.name === pod);
|
||||
return found ? [String(found.agents.length)] : [];
|
||||
return found ? String(found.agents.length) : "";
|
||||
}
|
||||
return [];
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,19 +120,14 @@ export function navigatorLabels(rows: ExplorerRow[], snap: FleetSnapshot, width:
|
||||
const branch = isLast[i] ? "└─ " : "├─ ";
|
||||
const parsed = parseKey(row.key)!;
|
||||
let content = contentOf(row, parsed.kind);
|
||||
const candidates = metaOf(row, snap);
|
||||
const meta = metaOf(row, snap);
|
||||
const prefix = ` ${guides}${branch}`;
|
||||
if (candidates.length === 0) return `${prefix}${content}`;
|
||||
// IDENTITY-FIRST width policy: pick the richest meta that fits beside the
|
||||
// FULL name (runtime · ctx% where geometry allows, ctx% otherwise); only
|
||||
// when even the leanest meta cannot fit does the name truncate with … —
|
||||
// rows must never become ambiguous to make room for telemetry.
|
||||
const fits = candidates.find((m) => prefix.length + content.length + 1 + m.length <= width);
|
||||
const meta = fits ?? candidates.at(-1)!;
|
||||
if (!fits) {
|
||||
const contentMax = width - prefix.length - meta.length - 1;
|
||||
content = `${content.slice(0, Math.max(contentMax - 1, 0))}…`;
|
||||
}
|
||||
if (!meta) return `${prefix}${content}`;
|
||||
// LOCKED width policy (guard-ruled): the complete right-aligned meta is
|
||||
// ALWAYS preserved; an over-long display name truncates with … instead
|
||||
// of the meta ever dropping its runtime.
|
||||
const contentMax = width - prefix.length - meta.length - 1;
|
||||
if (content.length > contentMax) content = `${content.slice(0, Math.max(contentMax - 1, 0))}…`;
|
||||
const gap = Math.max(width - prefix.length - content.length - meta.length, 1);
|
||||
return `${prefix}${content}${" ".repeat(gap)}${meta}`;
|
||||
});
|
||||
|
||||
@@ -39,7 +39,9 @@ function paintExplorer(text: string, s: Style, focused: boolean): string {
|
||||
/** row-body treatment (VISUAL-TARGETS: rig teal · pod dim · meta faint ·
|
||||
* names default ink); the right-aligned meta column always dims */
|
||||
function paintExplorerBody(text: string, s: Style): string {
|
||||
const meta = text.match(/^(.*?\S)( {2,})([0-9]+%|—|[0-9]+)$/);
|
||||
// the right-aligned meta dims as a WHOLE — `runtime · ctx%` (or honest
|
||||
// `runtime · —`) and bare pod counts alike, never just the trailing token
|
||||
const meta = text.match(/^(.*?\S)( +)((?:\S+ · )?(?:[0-9]+%|—)|[0-9]+)$/);
|
||||
if (meta) return paintExplorerBody(meta[1]!, s) + meta[2]! + s.paint("dim", meta[3]!);
|
||||
if (text.includes("⚑")) return s.paint("warn", text);
|
||||
if (/\(unreachable\)/.test(text)) {
|
||||
|
||||
@@ -50,35 +50,45 @@ describe("file-tree re-skin (Direction B navigator)", () => {
|
||||
s.dispatch({ type: "drill", resource: "pod", name: "dev50", target: { host: "vm-host", rig: "openrig-build" } });
|
||||
screen = renderScreen(s.get(), snap, { cols: 120, rows: 32 });
|
||||
const pane = explorerPane(screen.lines);
|
||||
expect(pane.find((l) => l.includes("dev50") && !l.includes("driver") && !l.includes("guard") && !l.includes("qa"))).toContain("▾");
|
||||
expect(pane.some((l) => l.includes("dev50.driver"))).toBe(true);
|
||||
expect(pane.find((l) => l.includes("dev50") && !l.includes("●"))).toContain("▾");
|
||||
// the agent rows appear (identity by ROW MODEL key — display names may
|
||||
// truncate under the locked meta-always policy)
|
||||
expect(screen.explorerRows.some((r) => r.key === "agent:vm-host/openrig-build/dev50/dev50.driver")).toBe(true);
|
||||
});
|
||||
|
||||
it("agent meta is right-aligned runtime · ctx% where it fits, ctx% otherwise — IDENTITY-FIRST (locked mini-req + guard finding 3)", () => {
|
||||
// demo names are long: full identity is kept, the meta degrades to ctx-only
|
||||
it("agent meta is ALWAYS the locked `runtime · ctx%` form — typical name truncates rather than the meta degrading (guard residual)", () => {
|
||||
const s = makeStore();
|
||||
s.dispatch({ type: "drill", resource: "pod", name: "dev50", target: { host: "vm-host", rig: "openrig-build" } });
|
||||
const pane = explorerPane(renderScreen(s.get(), snap, { cols: 120, rows: 32 }).lines);
|
||||
const driver = pane.find((l) => l.includes("dev50.driver"))!;
|
||||
expect(driver.trimEnd()).toMatch(/62%$/); // full name preserved, ctx at the edge
|
||||
const qa = pane.find((l) => l.includes("dev50.qa"))!;
|
||||
expect(qa.trimEnd()).toMatch(/—$/); // ctx null → honest-unknown
|
||||
// typical long name: the NAME yields with …; the meta stays complete
|
||||
const driver = pane.find((l) => l.trimEnd().endsWith("claude · 62%"))!;
|
||||
expect(driver).toBeDefined();
|
||||
expect(driver).toMatch(/● dev/); // still recognizably the agent row
|
||||
expect(driver).toMatch(/…/);
|
||||
});
|
||||
|
||||
// a short name leaves room: the FULL runtime · ctx meta renders (the
|
||||
// mockup's "claude 18%" display form for a claude-code seat)
|
||||
it("null context renders the honest `runtime · —` — runtime never drops, unknown never fabricates", () => {
|
||||
const s = makeStore();
|
||||
s.dispatch({ type: "drill", resource: "pod", name: "dev50", target: { host: "vm-host", rig: "openrig-build" } });
|
||||
const pane = explorerPane(renderScreen(s.get(), snap, { cols: 120, rows: 32 }).lines);
|
||||
expect(pane.some((l) => l.trimEnd().endsWith("codex · —"))).toBe(true); // demo: dev50.qa ctx null
|
||||
});
|
||||
|
||||
it("a short name renders untruncated beside the full meta (mockup display form, middle dot included)", () => {
|
||||
const shortSnap = {
|
||||
...snap,
|
||||
hosts: [{ name: "h", reachable: true, rigs: [{ name: "r", pods: [{ name: "p", agents: [
|
||||
{ name: "ok", runtime: "claude-code", spec: "", context: 5, tokens: null, status: "active", live: true },
|
||||
] }] }] }],
|
||||
};
|
||||
const s2 = createViewState({ instanceId: "nav-short", getSnapshot: () => shortSnap });
|
||||
s2.dispatch({ type: "drill", resource: "pod", name: "p", target: { host: "h", rig: "r" } });
|
||||
const shortPane = explorerPane(renderScreen(s2.get(), shortSnap, { cols: 120, rows: 32 }).lines);
|
||||
expect(shortPane.find((l) => l.includes("● ok"))!.trimEnd()).toMatch(/claude 5%$/);
|
||||
const s = createViewState({ instanceId: "nav-short", getSnapshot: () => shortSnap });
|
||||
s.dispatch({ type: "drill", resource: "pod", name: "p", target: { host: "h", rig: "r" } });
|
||||
const row = explorerPane(renderScreen(s.get(), shortSnap, { cols: 120, rows: 32 }).lines).find((l) => l.includes("● ok"))!;
|
||||
expect(row).not.toMatch(/…/);
|
||||
expect(row.trimEnd()).toMatch(/● ok\s+claude · 5%$/);
|
||||
});
|
||||
|
||||
it("only an identity too long for even the leanest meta truncates with … — meta stays complete at the edge", () => {
|
||||
it("an extreme name still truncates with … while the whole meta survives at the edge", () => {
|
||||
const longSnap = {
|
||||
...snap,
|
||||
hosts: [{ name: "h", reachable: true, rigs: [{ name: "r", pods: [{ name: "p", agents: [
|
||||
@@ -87,9 +97,21 @@ describe("file-tree re-skin (Direction B navigator)", () => {
|
||||
};
|
||||
const s = createViewState({ instanceId: "nav-long", getSnapshot: () => longSnap });
|
||||
s.dispatch({ type: "drill", resource: "pod", name: "p", target: { host: "h", rig: "r" } });
|
||||
const row = explorerPane(renderScreen(s.get(), longSnap, { cols: 120, rows: 32 }).lines).find((l) => l.includes("an-extre"))!;
|
||||
const row = explorerPane(renderScreen(s.get(), longSnap, { cols: 120, rows: 32 }).lines).find((l) => l.includes("● an-"))!;
|
||||
expect(row).toMatch(/…/);
|
||||
expect(row.trimEnd()).toMatch(/9%$/);
|
||||
expect(row.trimEnd()).toMatch(/codex · 9%$/);
|
||||
});
|
||||
|
||||
it("the WHOLE right-aligned meta paints dim as one run — runtime, middle dot, and value together", () => {
|
||||
const s = makeStore();
|
||||
s.dispatch({ type: "drill", resource: "pod", name: "dev50", target: { host: "vm-host", rig: "openrig-build" } });
|
||||
const screen = renderScreen(s.get(), snap, { cols: 120, rows: 32 });
|
||||
const styled = stylizeLines(screen, createStyle("truecolor"));
|
||||
const i = screen.lines.findIndex((l) => l.slice(0, 30).trimEnd().endsWith("claude · 62%"));
|
||||
expect(i).toBeGreaterThanOrEqual(0);
|
||||
// the dim SGR opens immediately before the runtime token, covering the full meta
|
||||
expect(styled[i]).toMatch(/\x1b\[38;2;109;116;128mclaude · 62%\x1b\[0m/);
|
||||
styled.forEach((line, j) => expect(stripAnsi(line), `line ${j}`).toBe(screen.lines[j]));
|
||||
});
|
||||
|
||||
it("an expanded namespaced spec folder renders its child ONE level deeper, never a sibling (guard finding 2)", () => {
|
||||
@@ -145,8 +167,12 @@ describe("file-tree re-skin (Direction B navigator)", () => {
|
||||
const rows = computeExplorerRows(s.get(), snap);
|
||||
expect(rows[s.get().selection]?.key).toBe("agent:vm-host/openrig-build/dev50/dev50.guard");
|
||||
const screen = renderScreen(s.get(), snap, { cols: 120, rows: 32 });
|
||||
// the selected ROW is the drilled agent (row-model identity); its display
|
||||
// line carries the marker and the agent's own locked meta at the edge
|
||||
const selectedRow = screen.explorerRows.find((r) => r.y === screen.lines.findIndex((l) => l.startsWith("›")) + 1);
|
||||
expect(selectedRow?.key).toBe("agent:vm-host/openrig-build/dev50/dev50.guard");
|
||||
const selectedLine = screen.lines.find((l) => l.startsWith("›"))!;
|
||||
expect(selectedLine).toContain("dev50.guard");
|
||||
expect(selectedLine.slice(0, 30).trimEnd()).toMatch(/codex · 31%$/); // demo: guard ctx 31
|
||||
});
|
||||
|
||||
it("stylize keeps the strip-invariant over the re-skinned labels", () => {
|
||||
|
||||
Reference in new issue
Block a user