feat(setup): paint card and log bodies in brand cyan

Adds a `brandBody` helper in setup/lib/theme.ts that wraps prose in
brand cyan (#2BB7CE), with the same TTY/NO_COLOR/truecolor gating used
by `brand`/`brandBold`/`brandChip`. The helper splits multi-line input
and colors each line independently so the SGR sequence doesn't bleed
across clack's gutter prefix.

Routing:
  - `note()` (the un-dim card wrapper from #2095) now passes
    `brandBody` as its `format` callback, so card bodies render
    cyan line-by-line.
  - Every prose `p.log.{message,info,success,step,warn}` call in the
    setup flow wraps its body argument in `brandBody`. Calls whose
    body is explicitly `k.dim(...)` (failure transcript tails, log
    paths, claude-assist response previews) are left alone — those
    are the "preview/debug" cases the dim-policy comment in
    theme.ts already carves out.
  - Spinner-finish lines in windowed-runner / claude-assist color
    only the message portion; the `(5s)` elapsed suffix stays dim.

Brand cyan accents (chips, wordmark, inline emphasis) are unchanged.
This PR only adds the body color.

A follow-up will add OSC 11 dark/light detection so light-mode
terminals get a brand blue (#2b6fdc) variant — opt-in upgrade with
no regression for the dark-mode default.
This commit is contained in:
exe.dev user
2026-04-29 11:43:30 +00:00
parent e0f813603e
commit ab2d509671
8 changed files with 78 additions and 46 deletions

View File

@@ -20,7 +20,7 @@ import k from 'kleur';
import * as setupLog from '../logs.js';
import { offerClaudeAssist } from './claude-assist.js';
import { emit as phEmit } from './diagnostics.js';
import { fitToWidth } from './theme.js';
import { brandBody, fitToWidth } from './theme.js';
export type Fields = Record<string, string>;
export type Block = { type: string; fields: Fields };
@@ -390,7 +390,7 @@ export async function fail(
const skipList = [
...new Set([...existingSkip, ...setupLog.completedStepNames()]),
].join(',');
p.log.step(`Retrying from ${stepName}`);
p.log.step(brandBody(`Retrying from ${stepName}`));
const result = spawnSync('pnpm', ['--silent', 'run', 'setup:auto'], {
stdio: 'inherit',
env: { ...process.env, NANOCLAW_SKIP: skipList },