From 910342fd80dfec714962c803c6daa1a920588d9c Mon Sep 17 00:00:00 2001 From: gavrielc Date: Thu, 23 Apr 2026 10:59:12 +0300 Subject: [PATCH] =?UTF-8?q?style(setup):=20lift=20text=20weight=20?= =?UTF-8?q?=E2=80=94=20prose=20becomes=20regular,=20outcomes=20bold?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dimmed explanatory prose blocks were hard to read against dark terminals. Shift the weight ladder up a notch: - dimWrap() no longer dims. Multi-line prose (the step-intro copy, etc.) renders at the terminal's regular weight. - Spinner outcome labels (done/failed/skipped) are now bold via runUnderSpinner, so each step's headline reads stronger than the body copy around it. - Un-dim two command-hint blocks in auto.ts (docker-group setfacl + service restart; the socket-error remediation commands) — those are commands the user may need to type. Dim is still used where it helps — (Ns) spinner timings, URLs, short inline parentheticals — and for the preview/debug blocks dim is explicitly reserved for: dumpTranscriptOnFailure tail and claude-assist streams. Co-Authored-By: Claude Opus 4.7 (1M context) --- setup/auto.ts | 14 ++++++-------- setup/lib/runner.ts | 6 ++++-- setup/lib/theme.ts | 15 ++++++--------- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/setup/auto.ts b/setup/auto.ts index b5b0113..369f05a 100644 --- a/setup/auto.ts +++ b/setup/auto.ts @@ -215,10 +215,8 @@ async function main(): Promise { "NanoClaw's permissions need a tweak before it can reach Docker.", ); p.log.message( - k.dim( - ' sudo setfacl -m u:$(whoami):rw /var/run/docker.sock\n' + - ' systemctl --user restart nanoclaw', - ), + ' sudo setfacl -m u:$(whoami):rw /var/run/docker.sock\n' + + ` systemctl --user restart ${getSystemdUnit()}`, ); } } @@ -442,13 +440,13 @@ async function confirmAssistantResponds(): Promise { const elapsed = Math.round((Date.now() - start) / 1000); const suffix = ` (${elapsed}s)`; if (result === 'ok') { - s.stop(`${fitToWidth('Your assistant is ready.', suffix)}${k.dim(suffix)}`); + s.stop(`${k.bold(fitToWidth('Your assistant is ready.', suffix))}${k.dim(suffix)}`); } else { const msg = result === 'socket_error' ? "Couldn't reach the NanoClaw service." : "Your assistant didn't reply in time."; - s.stop(`${fitToWidth(msg, suffix)}${k.dim(suffix)}`, 1); + s.stop(`${k.bold(fitToWidth(msg, suffix))}${k.dim(suffix)}`, 1); } return result; } @@ -462,8 +460,8 @@ function renderPingFailureNote(result: PingResult): void { 6, ), '', - k.dim(` macOS: launchctl kickstart -k gui/$(id -u)/${getLaunchdLabel()}`), - k.dim(` Linux: systemctl --user restart ${getSystemdUnit()}`), + ` macOS: launchctl kickstart -k gui/$(id -u)/${getLaunchdLabel()}`, + ` Linux: systemctl --user restart ${getSystemdUnit()}`, ].join('\n') : wrapForGutter( 'No reply from your assistant within 30 seconds. Check `logs/nanoclaw.log` for clues, then try `pnpm run chat hi`.', diff --git a/setup/lib/runner.ts b/setup/lib/runner.ts index 1e02d0d..c1599e4 100644 --- a/setup/lib/runner.ts +++ b/setup/lib/runner.ts @@ -322,10 +322,12 @@ async function runUnderSpinner< if (result.ok) { const isSkipped = result.terminal?.fields.STATUS === 'skipped'; const msg = isSkipped && labels.skipped ? labels.skipped : labels.done; - s.stop(`${fitToWidth(msg, suffix)}${k.dim(suffix)}`); + // Bold the outcome so the step's headline reads stronger than the prose + // body copy around it. The trailing `(Ns)` timing stays dim. + s.stop(`${k.bold(fitToWidth(msg, suffix))}${k.dim(suffix)}`); } else { const failMsg = labels.failed ?? labels.running.replace(/…$/, ' failed'); - s.stop(`${fitToWidth(failMsg, suffix)}${k.dim(suffix)}`, 1); + s.stop(`${k.bold(fitToWidth(failMsg, suffix))}${k.dim(suffix)}`, 1); dumpTranscriptOnFailure(result.transcript); } return result; diff --git a/setup/lib/theme.ts b/setup/lib/theme.ts index 6f21d15..35b5ca3 100644 --- a/setup/lib/theme.ts +++ b/setup/lib/theme.ts @@ -58,17 +58,14 @@ export function wrapForGutter(text: string, gutter: number): string { } /** - * Wrap + dim together. Needed instead of `k.dim(wrapForGutter(...))` - * because clack resets styling at each line break when rendering - * multi-line log content — a single outer dim envelope only colors the - * first line. Applying dim per-line gives each wrapped row its own - * `\x1b[2m…\x1b[0m` envelope so the whole block reads as one block. + * Wrap multi-line explanatory prose to the clack gutter. Previously + * dimmed its output (hence the name) — that made body copy hard to read + * against dark terminals. Dim is now reserved for preview/debug blocks + * (failure transcript tails, claude-assist streams); prose renders at + * the terminal's regular weight. */ export function dimWrap(text: string, gutter: number): string { - return wrapForGutter(text, gutter) - .split('\n') - .map((line) => k.dim(line)) - .join('\n'); + return wrapForGutter(text, gutter); } const ANSI_RE = /\x1b\[[0-9;]*m/g;