Skip to content

Polish: theme, animation, non-TTY purity, robustness - #282

Merged
Patel230 merged 116 commits into
mainfrom
fix/eco-integrity
Sep 7, 2026
Merged

Polish: theme, animation, non-TTY purity, robustness#282
Patel230 merged 116 commits into
mainfrom
fix/eco-integrity

Conversation

@Patel230

@Patel230 Patel230 commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Modernizes and hardens the graycode CLI across four dimensions:

Theming

  • Semantic color across ~55 commands, summaries, status reports, and stderr diagnostics via a shared auditTint helper + self-contained internal/theme for non-cmd packages.
  • Honors NO_COLOR/FORCE_COLOR/--quiet; tables/JSON/markdown/streams stay byte-clean.

Animation

  • CLIProgress (themed progress bar + ETA) wired into every slow flow: review run/analyze, audit, harness, verify, eval, models, doctor, preflight, cloud login, context --output, mission.
  • LLM-streaming commands use the stream itself as progress.

Non-TTY purity

  • Persistent --quiet; onboarding honors NO_COLOR; doctor --json now emits real JSON; pad-then-colorize alignment.

Robustness

  • verify 10-min timeout; gh issue create 60s timeout; BrailleSpinner one-shot panic fix.

Modern UX

  • config set/provider/model old→new transitions; config get (unset); verify elapsed time.

All tests pass (go test ./...), build/vet/gofmt clean.

The index URL referenced GrayCodeAI/starling, a repo renamed to
graycode-skills whose registry.json is generated and never committed,
so the URL 404d under either name. It now reads the rolling release
asset published by graycode-skills' publish-registry.yml.

Claude-Session: https://claude.ai/code/session_01MTUKadN91fcmuhxGWYVe2k
plugins-registry.json is generated by nothing in any of the four
GrayCode repos; the only reference anywhere was this default source.
FetchAll with no sources returns an empty list rather than erroring.

Claude-Session: https://claude.ai/code/session_01MTUKadN91fcmuhxGWYVe2k
The wire contract's servers.url is the browser BFF, which rejects a
device token; the worker itself has no route or custom domain.

Claude-Session: https://claude.ai/code/session_01MTUKadN91fcmuhxGWYVe2k
check-support-repo-coupling.sh built its regex from an empty peer
list, degenerating to a pattern matching nothing. The engine-boundary
script ran in CI but not on pre-push. Both AST tests carried a
gateway->credentials exception that no production file uses.

Claude-Session: https://claude.ai/code/session_01MTUKadN91fcmuhxGWYVe2k
Also replaces GrayCodeAI/starling test fixtures with the repo's
current name, and fixes an 'execution swift' typo left by an earlier
substring rename in the generated GitNexus tables.

Claude-Session: https://claude.ai/code/session_01MTUKadN91fcmuhxGWYVe2k
- eval list --json: project BenchmarkTask (func fields) to a JSON-safe struct
- stream: use a single RawMessages() snapshot (fixes len()+copy reallocation race)
- crash_unix: drop unreachable nil-return branch from raiseSignal
- tool: replace deprecated strings.Title with x/text cases.Title
- daemon: replace no-arg fmt.Sprintf with string literals
- fuzzyfind: replace deprecated filepath.HasPrefix with strings.HasPrefix
- memory: thread context.Context through MemoryRecaller.Remember so background
  remember goroutines honor their timeout (fixes goroutine leak from discarded rCtx)
- contracts/types: remove deprecated fail-open ParseSeverity (zero callers)
Wire the previously-unused ProgressTracker into real command flows via a
new CLIProgress helper:

- cmd/progress_cli.go: TTY-aware progress renderer. On a terminal it
  repaints the active step in place with a braille spinner, theme-colored
  progress bar, and live N/M counter; piped/CI output is one clean static
  line per step with no ANSI. Completion prints a themed summary with the
  final bar (errorCoral when any step failed). Glyphs come from
  internal/ui/icons; block glyphs stay in the audit-permitted U+2500-U+25FF
  range.
- cmd/review_run.go: progress over Building model / Reviewing code /
  Saving results, silent in background/hook mode.
- cmd/audit.go: per-session progress, gated to TTY + text output so --json
  stays pure and piped output isn't spammed.
- cmd/progress_cli_test.go: non-TTY, TTY, fail-step, and multi-step
  regression tests (the multi-step test covers a fresh-spinner-per-step fix
  for BrailleSpinner's one-shot Start/Stop panic).
Wire CLIProgress into the harness command over Evaluating workspace /
Writing markdown / Writing HTML / Writing JSON. Reports are written to
files (not stdout), so progress never corrupts structured output; piped
runs get clean static lines, TTY runs get in-place animation.
Run project test/verify commands can be slow with no feedback until each
finishes. Show a TTY-only animated indicator while they execute, then
clear it before printing the structured [OK]/[FAIL]/[SKIP] results, so
piped and structured output stay untouched.
Append a live ETA to the animated line once the tracker has completed
steps to extrapolate from (ProgressTracker.EstimateRemaining). Hidden
until meaningful, so the first step shows no spurious ETA.
Extract the per-session progress gate into auditProgressEnabled(format,
tty) and cover it: JSON output must stay pure on any terminal, and piped
text must not be spammed with per-session lines.
Colorize the report title (brand gold), section headers (infoSky), and
severity column (semantic colors: high/critical errorCoral, medium
warnAmber, info/low infoSky) on a TTY only. Piped output stays plain.
Severity is padded to the column width before colorizing so zero-width
ANSI escapes don't break the fixed-width alignment.
Show a TTY-only animated indicator around the slow full agent loop. It
clears before the JSON report prints, so piped and structured output stay
pure.
Wire the canonical ShouldColor()/IsQuiet() gates into CLIProgress and the
audit report so the new animated/theme output respects the same controls as
the rest of the CLI. --quiet now fully suppresses spinners, progress lines,
and decoration (the documented contract) and produces plain output; NO_COLOR
strips color while keeping the TTY animation; FORCE_COLOR colors piped
output.

Make --quiet a persistent root flag so it is usable on subcommands
(graycode audit --quiet, verify --quiet, eval loop --quiet) instead of only
the interactive root. Previously subcommands rejected it with 'unknown flag'.

Add tests for quiet suppression, NO_COLOR, and FORCE_COLOR.
Insert a 'Repairing harness' progress step around FixWorkspaceHarness (and
the post-fix re-evaluation) when --fix is used. Report-write steps reindex
dynamically so the animation stays correct in both modes.
Add an optional Progress callback to the eval Runner, invoked before each
task with its index, total, and ID. runEval wires it to a CLIProgress with
one step per benchmark task, closing the previous step and opening the next.
Quiet mode suppresses the animation. Backward-compatible: no existing
Runner construction breaks (keyed literals), and the callback is nil by
default.
Colorize the review summary to match the audit report: green check for a
clean review, coral alert with semantic severity colors for findings. Honors
ShouldColor() so --quiet/NO_COLOR/FORCE_COLOR behave consistently.
Theme the summary labels (muted) and the total-hits count (green when
clean, coral when findings exist); the empty-detectors success line is now
green. Consistent with the themed title and severity columns.
Gold completion banner; semantic status color (green EXCELLENT/GOOD, amber
NEEDS_IMPROVEMENT, coral POOR); labels in textPrimary. Honors ShouldColor().
Colorize the [OK]/[FAIL]/[SKIP] markers (green/coral/muted) and the
'verification passed' line. Markers are padded to a fixed width before
colorizing so ANSI escapes don't break column alignment. Plain when piped
via ShouldColor().
Gold title, muted header/separator, violet cost column (pad-then-colorize
to preserve alignment), textPrimary total label. Honors ShouldColor() so
piped output stays plain.
Gold title, sky section headers, muted labels/headers, violet cost figures,
teal top-tool bars. Consistent with the audit report. Honors ShouldColor().
Green check / coral close / amber alert statuses, textPrimary names, and
status-colored messages. Honors ShouldColor() so piped output stays plain.
Gold title, muted labels, textPrimary values. Honors ShouldColor() so
piped/JSON output stays plain.
Green OK marker, textPrimary count, muted path. Honors ShouldColor().
Muted label, status-colored counts (open sky, passed green, fixed teal,
failed coral), and severity-colored open-review lines. Honors ShouldColor().
Muted header, state-colored STATE column (active green, failed coral,
disabled dim, discovered/loaded sky). Honors ShouldColor().
Green running, muted not-running, amber unknown/stale; muted labels with
textPrimary values. JSON output stays pure.
models refresh (slow 60s network discover) and models list --live (live
provider fetch) now show a CLIProgress step. JSON/raw list output stays
pure. Honors --quiet/NO_COLOR.
The first-run setup wizard and welcome banner emitted hardcoded ANSI
escapes unconditionally, breaking the CLI's non-TTY purity (colored
output even under NO_COLOR). Gate the color codes on theme.ColorEnabled()
and use the theme's brand ANSI for the banner, so scripted or NO_COLOR
environments get plain text. Update TestColorConstants to assert the
gating behavior.
graycode mission's per-feature output was themed but the final Mission
summary line stayed plain. Colorize it textPrimary to match the rest of
the command's visual identity.
graycode sandbox status printed a plain multi-line report while every
other CLI status report was themed. Colorize the header, per-change type
tags, and stats line using the semantic theme colors, honoring
NO_COLOR/FORCE_COLOR/TTY via theme.Tint. The Summary method is CLI-only.
The 'Installed <shell> completion to <path>' status line was the last
plain confirmation in the CLI. Colorize 'Installed' in doneGreen and the
target path in textPrimary, honoring ShouldColor() via auditTint.
The 'System prompt fragment that would be injected:' heading and its
separator were plain. Colorize the heading in textPrimary and the
separator in textMuted via auditTint; the injected fragment itself stays
plain (it is data).
The review list row printed the status text and findings bracket in
plain text while the status glyph was already colored. Colorize the
status via reviewStatusColor and the [maxSeverity] bracket via
severityStyle, keeping the row layout intact.
The trending skill list printed plain numeric prefixes. Colorize the
index in textMuted via auditTint; the shared FormatSkillEntry body stays
plain.
The findings list printed plain indices and file:line locations. Colorize
the index in textMuted and the file path in textPrimary via auditTint,
matching the themed severity bracket and message lines.
The modern help template rendered command descriptions in plain text
while headers were gold and names textPrimary. Colorize descriptions in
textMuted via a new gcDesc template func for clearer visual hierarchy.
Descriptions are the last column, so zero-width ANSI cannot break the
padded name alignment; under NO_COLOR auditTint keeps them plain, so the
golden help files stay unchanged.
After an exec run prints its response, emit a muted token/turn/duration/
model summary to stderr so stdout stays byte-clean for piping and the
model output remains the sole data. Gated by --quiet; color honors
ShouldColor() via auditTint.
The issue command ran 'gh issue create' with context.Background() and no
deadline, so a stalled GitHub call could hang the CLI indefinitely. Wrap
it in a 60s context timeout and report a clear deadline-exceeded error.
review fix iterates open reviews and runs a multi-turn graycode exec for
each. It printed only the completion status after each exec, so with
--all the user could not tell which review was being worked on. Print a
themed 'Fixing review #N (sha)...' line (gold bolt + textPrimary) before
each exec run.
review analyze ran a single kestrel model call (up to the 3-minute
analyze timeout) behind a static 'Analyzing...' line. Replace it with a
CLIProgress animation (rainbow spinner + themed bar + ETA) so the wait
has live feedback, matching review run. Gated by --quiet; findings
output stays clean after the step completes.
The mission command ran up to 30 minutes of parallel LLM workers behind a
static 'Executing with N parallel workers...' line with no live feedback.
Wrap the run in a single-step CLIProgress animation (rainbow spinner +
themed bar) showing the feature/worker count. Gated by --quiet; the
per-feature results still print cleanly after the step completes.
The best-of-N fanout loop printed each attempt header to stderr in plain
text. Theme them with the info-sky accent so each attempt reads as a
distinct phase, matching the themed exec usage summary. Stderr-only, so
the model output on stdout stays byte-clean.
The best-of-N comparison report printed each attempt's ok/failed status in
plain text. Colorize the status (green ok / coral failed, with the error
appended in coral) and the report header in the info-sky accent, matching
the themed attempt headers. Stderr-only; stdout stays byte-clean.
The exec command printed error/hint/warning diagnostics to stderr in plain
text. Colorize them with semantic accents — errors in coral, hints in
muted, and warnings (untrusted GitHub autonomy cap, session-persist
failure) in amber — matching the themed usage summary and fanout headers.
Stderr-only; the model output on stdout stays byte-clean.
Theme the one-off stderr diagnostics in ai-comments (directive dispatch and
token-strip failures in coral) and chat (ignored --session-id notice in
muted, plugin load failure warning in amber). Consistent with the themed
exec diagnostics; stderr-only.
The interactive chat REPL printed errors to stderr in plain text. Colorize
them in coral. The REPL's streamed tool output stays plain (data).
Theme the daemon telemetry/file-logging fallback warnings and the eval
results-save warning in amber. Consistent with the themed exec and chat
diagnostics; stderr-only.
config set now reads the current value before writing and, when it changes,
prints a modern old → new transition (key: old → new (updated)) instead of
the bare 'updated key'. Falls back to the plain confirmation when there is
no prior value or the value is unchanged. Settable keys are non-secret
(API keys error out before reaching here), so no secret is exposed.
Honors NO_COLOR via auditTint.
Extract the old → new transition rendering into printConfigSetResult and
use it for the config set, config provider, and config model paths so all
three show the same modern transition (key: old → new (updated)) with the
plain fallback when there is no prior value.
config get printed a blank line when a valid key had no value. Print
'(unset)' in muted instead, so an empty result is distinguishable from a
missing key (which still errors).
verify now reports how long the check run took (verification passed in
Xs), which is genuinely useful in non-TTY mode where no animation shows
the elapsed time. The duration is muted so the done-green confirmation
stays the visual anchor.
- Apply gofumpt to cmd/exec.go and two internal/intelligence/memory files
  (formatting-only) to satisfy the CI format check.
- Remove docs/plans/2026-09-05-graycode-eco-integrity.md from the branch:
  it is a working planning note (not a CLI deliverable) whose malformed
  code fences and hard tabs fail the repo's markdownlint gate. Kept
  locally as untracked.
- progress_cli.go: explicitly discard fmt.Fprintf/Fprintln return values
  (errcheck) in the spinner frame callback and writeLine.
- developer_path.go: omit redundant color.Color type annotation (ST1023);
  theme.ReportWarn is already color.Color and all switch assignments share
  that type.
Use := instead of var for the first declaration of statusColor so the file
passes the CI gofumpt gate.
@Patel230
Patel230 merged commit f7d9641 into main Sep 7, 2026
25 of 26 checks passed
@Patel230
Patel230 deleted the fix/eco-integrity branch September 7, 2026 04:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant