feat: CLI global options infrastructure, UI modes, exit codes, env vars#891
feat: CLI global options infrastructure, UI modes, exit codes, env vars#891
Conversation
…d env vars (#886) Add GlobalOpts struct (--quiet, --verbose, --no-color, --plain, --json, --yes) threaded via Cobra context. Extend UI package with Options for plain mode (ASCII-only icons, box-drawing, dividers), quiet mode (suppress non-essential output), and categorized hint methods (HintError, HintNextStep, HintTip, HintGuidance) with auto/always/never control. Add ExitError type for typed exit codes. Add SYNTHORG_* env var layer (data-dir, log-level, ports, channel, image-tag, no-verify, auto-update-cli, auto-pull, auto-restart). Migrate all 15 command files to use GetGlobalOpts and NewUIWithOptions. Migrate all Hint() calls to categorized hint methods. Closes: PR 1 of #886 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…s, reexec Pre-reviewed by 5 agents, 16 findings addressed: - Fix cmd.Flags().Changed() querying wrong flag set for persistent flags on subcommands -- use flag variables directly instead - Move SYNTHORG_SKIP_VERIFY env var resolution from init() to setupGlobalOpts for consistency with other env var overrides - Add EnvQuiet and EnvYes constants to envvars.go (were string literals) - Remove envString wrapper (trivial os.Getenv indirection) - Fix "Wipe cancelled" hints using HintGuidance (suppressed by default) -- changed to HintNextStep so users see confirmation - Fix non-interactive cleanup hint using HintGuidance -- changed to HintNextStep so CI users see why nothing was removed - Remove local --json flag from status command that shadowed global persistent --json flag - Forward new global flags (--quiet, --verbose, --no-color, --plain, --json, --yes) in reexecUpdate for CLI self-update re-exec - Fix performRestart ignoring global UI options -- accept ui.Options parameter instead of using bare ui.NewUI - Suppress ChildExitError printing in Execute() (internal message) - Add validHintsMode validation for hints config - Document CLI global flags, env vars, and exit codes in CLAUDE.md - Update Package Structure in CLAUDE.md for new cmd/ files - Update operations.md CLI info-box with output modes and exit codes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📜 Recent review details⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
🧰 Additional context used📓 Path-based instructions (1)cli/**/*.go📄 CodeRabbit inference engine (CLAUDE.md)
Files:
🧠 Learnings (6)📓 Common learnings📚 Learning: 2026-03-27T17:07:16.441ZApplied to files:
📚 Learning: 2026-03-19T11:30:29.217ZApplied to files:
📚 Learning: 2026-03-19T11:19:40.044ZApplied to files:
📚 Learning: 2026-03-21T12:54:22.557ZApplied to files:
📚 Learning: 2026-03-21T14:12:17.848ZApplied to files:
🔇 Additional comments (7)
WalkthroughCentralizes CLI global options into a new GlobalOpts type with context setters/getters and wires root persistent flags ( Suggested labels
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Snapshot WarningsEnsure that dependencies are being submitted on PR branches. Re-running this action after a short time may resolve the issue. See the documentation for more information and troubleshooting advice. Scanned FilesNone |
There was a problem hiding this comment.
Code Review
This pull request implements a centralized global options system for the CLI, introducing persistent flags for quiet mode, plain text, JSON output, and automatic confirmation. It also standardizes exit codes and environment variable handling while refactoring the UI package to respect these settings. Feedback highlights an opportunity to migrate legacy interactivity checks to the new ShouldPrompt method, ensuring consistent behavior across all commands when the --yes flag is active.
| func (g *GlobalOpts) ShouldPrompt() bool { | ||
| if g.Yes { | ||
| return false | ||
| } | ||
| fi, err := os.Stdin.Stat() | ||
| if err != nil { | ||
| return false | ||
| } | ||
| return fi.Mode()&os.ModeCharDevice != 0 | ||
| } |
There was a problem hiding this comment.
This ShouldPrompt method is a great addition for centralizing interactivity checks. However, the legacy isInteractive() function still exists in root.go and is used in several commands (cleanup, init, update, wipe).
Those usages should be migrated to use !GetGlobalOpts(ctx).ShouldPrompt() to ensure consistent behavior, especially for the new --yes flag which isInteractive() does not respect.
For example, synthorg wipe will fail in a non-interactive environment even with --yes because it checks isInteractive() at the beginning. Using ShouldPrompt would correctly handle the --yes flag in this case.
This would require some refactoring in functions like confirmUpdateWithDefault to accept a context.Context, but it would make the CLI behavior more robust and predictable.
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
cli/internal/ui/livebox.go (1)
117-128:⚠️ Potential issue | 🟠 MajorQuiet/JSON failures can leak human output to stdout.
Adding
lb.ui.quietto this immediate-print path routes quiet-mode failures through the stdout-backed UI.--jsonhits this path becauseGlobalOpts.UIOptions()coerces JSON into quiet, andpullServicesLivebuilds the live box fromoutincli/cmd/start.go. A failed pull can therefore emit human-readable lines on stdout before the command returns its error. Quiet mode should stay silent here, orLiveBoxneeds a separate stderr UI for failure lines.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cli/internal/ui/livebox.go` around lines 117 - 128, The current branch prints failures to the stdout-backed UI when lb.ui.quiet is true, leaking human output; modify the logic in the immediate-print path so quiet mode is a no-op: at the start of the function check if lb.ui.quiet and return early (or skip printing) instead of including lb.ui.quiet in the if-condition, then keep the existing behavior for non-TTY and lb.ui.plain; update the condition around the block that calls lb.ui.Error / lb.ui.Success (and references lb.lines[index].status and IconError/PlainIconError) to only run for !lb.ui.isTTY || lb.ui.plain so quiet mode does not route failures to stdout.cli/internal/ui/ui.go (2)
65-80:⚠️ Potential issue | 🟡 MinorTip dedup resets every time a new
UIis constructed.Because
tipsSeenlives on theUIinstance, separate stdout/stderr UIs do not share it. That falls short of session-level dedup and will re-show the same tip whenever a command creates anotherUI. Consider moving the cache out of the instance or threading a shared store throughOptions.Also applies to: 229-244
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cli/internal/ui/ui.go` around lines 65 - 80, The tipsSeen sync.Map on the UI struct causes tip dedup to reset whenever a new UI is constructed; move the dedup store out of the UI instance so it is shared for the session (either make a package-level/shared sync.Map or add a shared TipsStore pointer into the UI creation Options and have NewUI/FromOptions use that shared map) and update all places that construct UI (references to UI.tipsSeen and any HintTip logic) to use the shared store (also adjust related code around the HintTip usage referenced in the same diff block).
90-119:⚠️ Potential issue | 🟠 Major
jsonModeis tracked but never actually suppresses human emitters.
NewUIWithOptionsrecords JSON mode, but the normal UI helpers still write human text.Success,Warn,Error, and the existing undecorated output path can therefore leak into a--jsonstdout stream and make the payload unparseable. Right now JSON mode is effectively quiet mode plus a dead field.Also applies to: 156-191
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cli/internal/ui/ui.go` around lines 90 - 119, NewUIWithOptions sets UI.jsonMode but the human-facing emitters still write plain text into stdout; update the UI methods (e.g., Success, Warn, Error, Print/Write or any helper that emits decorated/human output) to check ui.jsonMode and, when true, avoid emitting human text to stdout (either suppress the human output entirely or emit only machine/json payloads), and route any non-JSON diagnostics to stderr instead; touch the methods named Success, Warn, Error, Print (or Write) and ensure they consult UI.jsonMode (and/or UI.quiet) before writing to the provided writer so --json no longer leaks human text into the JSON stdout stream.cli/cmd/update.go (1)
391-417:⚠️ Potential issue | 🟠 MajorUse the resolved
SkipVerifyvalue here, notflagSkipVerify.
pullAndPersistalready loadsGetGlobalOpts(cmd.Context()), butverifyAndPinForUpdatestill branches on the package flag variable. That only reflects the explicit CLI flag, so env/config-driven skip-verify settings will be ignored during the update pull flow.🛠️ Suggested wiring
func pullAndPersist(ctx context.Context, cmd *cobra.Command, info docker.Info, state config.State, tag, safeDir string, preserveCompose bool) (config.State, error) { opts := GetGlobalOpts(cmd.Context()) out := ui.NewUIWithOptions(cmd.OutOrStdout(), opts.UIOptions()) @@ - digestPins, err := verifyAndPinForUpdate(ctx, state, tag, safeDir, preserveCompose, out, errOut) + digestPins, err := verifyAndPinForUpdate(ctx, state, tag, safeDir, preserveCompose, opts.SkipVerify, out, errOut) @@ -func verifyAndPinForUpdate(ctx context.Context, state config.State, tag, safeDir string, preserveCompose bool, out *ui.UI, errOut *ui.UI) (map[string]string, error) { +func verifyAndPinForUpdate(ctx context.Context, state config.State, tag, safeDir string, preserveCompose bool, skipVerify bool, out *ui.UI, errOut *ui.UI) (map[string]string, error) { @@ - if flagSkipVerify { + if skipVerify {Also applies to: 447-452
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cli/cmd/update.go` around lines 391 - 417, The call sites should use the resolved SkipVerify from GetGlobalOpts(cmd.Context()) instead of the raw CLI package flag variable; replace uses of flagSkipVerify with opts.SkipVerify (where opts := GetGlobalOpts(cmd.Context()) is already set) when calling verifyAndPinForUpdate and the other pull/update helper (e.g., pullAndPersist) so env/config-driven skip-verify takes effect; locate references to flagSkipVerify and change them to read opts.SkipVerify or pass opts into the helper so verifyAndPinForUpdate and related functions observe the resolved SkipVerify value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@cli/cmd/backup.go`:
- Around line 404-407: The missing --confirm path returns a plain error causing
exit code 1; change the return to an ExitUsage error so callers get the usage
exit code. In the restore command handler (the block that calls errOut.Error and
errOut.HintNextStep when !confirm), replace returning errors.New("--confirm flag
is required") with returning NewExitError(ExitUsage, "--confirm flag is
required") (or equivalent constructor used in this codebase) so the CLI exits
with the documented usage code; keep the existing errOut messages intact.
In `@cli/cmd/envvars.go`:
- Around line 27-37: The envBool function fails to handle env values with
surrounding whitespace; update envBool to trim the retrieved env string (use
strings.TrimSpace on the value from os.Getenv) before checking for empty and
before strings.ToLower/switch comparisons (i.e., operate on the trimmed
variable). Keep the same truthy cases ("1","true","yes") but perform them
against the trimmed, lowercased value so inputs like " true " or "yes " are
correctly parsed.
In `@cli/cmd/global_opts.go`:
- Around line 35-46: The confirmation logic currently ignores GlobalOpts.Yes
because callers still call isInteractive() directly; update the confirm code
paths to consume the resolved global option instead: thread GlobalOpts (or at
least its ShouldPrompt() result) into the confirmation helpers used by the
synthorg update flow and replace direct calls to isInteractive() with
g.ShouldPrompt() (or use the passed-in bool) in those helpers (look for
functions named isInteractive, confirmUpdate/confirmAction or the update command
handler that performs the prompt). Ensure the synthorg update command's
run/handler signature accepts the GlobalOpts (or a prompt boolean) and forward
it to the confirmation helper so --yes disables prompts; update associated tests
to pass the GlobalOpts or bool instead of relying on isInteractive().
In `@cli/cmd/root.go`:
- Around line 61-66: Compute the effective option values before running the
mutual-exclusion checks: use the explicit-flag presence indicators together with
environment-derived overrides to produce resolvedQuiet, resolvedVerbose (or an
integer), resolvedPlain, and resolvedJSON, then validate those resolved
variables rather than the raw flag booleans (e.g. replace checks of
flagQuiet/flagVerbose/flagPlain/flagJSON with
resolvedQuiet/resolvedVerbose/resolvedPlain/resolvedJSON). If a conflict is
detected return ExitUsage with a clear error (e.g. "--quiet and --verbose are
mutually exclusive" or "--plain and --json are mutually exclusive"). Apply this
same pattern for the other validation blocks referenced in the comment (lines
~69-91) so all mutual-exclusion checks use the resolved values.
In `@cli/cmd/start.go`:
- Around line 160-163: The helper verifyAndPinImages currently checks the raw
flag variable flagSkipVerify instead of the resolved option from
setupGlobalOpts; update its skip logic to use the resolved value
(state.GlobalOpts.SkipVerify or the equivalent field on the passed config.State)
so SYNTHORG_SKIP_VERIFY/SYNTHORG_NO_VERIFY are honored across start/wipe/update
flows and remove reliance on flagSkipVerify; keep the warning text and behavior
the same but gate it with the resolved GlobalOpts.SkipVerify.
In `@cli/cmd/wipe.go`:
- Around line 91-93: runWipe is still prompting interactively even when the
global --yes flag is set; update runWipe to consult the GetGlobalOpts() result
(opts.Yes) immediately and take a fast path that skips the huh/confirmation
prompt when true. Specifically, in the wipe command flow that creates opts, out
and errOut, add an early check in runWipe (or the confirmation branch) that if
opts.Yes is true it proceeds with the destructive action using the existing
out/errOut/UIs instead of calling huh; otherwise keep the current interactive
prompt path. Ensure references to GetGlobalOpts, opts.Yes, runWipe, and the
huh/confirmation logic are adjusted so non-interactive automation can run with
--yes or SYNTHORG_YES=1.
---
Outside diff comments:
In `@cli/cmd/update.go`:
- Around line 391-417: The call sites should use the resolved SkipVerify from
GetGlobalOpts(cmd.Context()) instead of the raw CLI package flag variable;
replace uses of flagSkipVerify with opts.SkipVerify (where opts :=
GetGlobalOpts(cmd.Context()) is already set) when calling verifyAndPinForUpdate
and the other pull/update helper (e.g., pullAndPersist) so env/config-driven
skip-verify takes effect; locate references to flagSkipVerify and change them to
read opts.SkipVerify or pass opts into the helper so verifyAndPinForUpdate and
related functions observe the resolved SkipVerify value.
In `@cli/internal/ui/livebox.go`:
- Around line 117-128: The current branch prints failures to the stdout-backed
UI when lb.ui.quiet is true, leaking human output; modify the logic in the
immediate-print path so quiet mode is a no-op: at the start of the function
check if lb.ui.quiet and return early (or skip printing) instead of including
lb.ui.quiet in the if-condition, then keep the existing behavior for non-TTY and
lb.ui.plain; update the condition around the block that calls lb.ui.Error /
lb.ui.Success (and references lb.lines[index].status and
IconError/PlainIconError) to only run for !lb.ui.isTTY || lb.ui.plain so quiet
mode does not route failures to stdout.
In `@cli/internal/ui/ui.go`:
- Around line 65-80: The tipsSeen sync.Map on the UI struct causes tip dedup to
reset whenever a new UI is constructed; move the dedup store out of the UI
instance so it is shared for the session (either make a package-level/shared
sync.Map or add a shared TipsStore pointer into the UI creation Options and have
NewUI/FromOptions use that shared map) and update all places that construct UI
(references to UI.tipsSeen and any HintTip logic) to use the shared store (also
adjust related code around the HintTip usage referenced in the same diff block).
- Around line 90-119: NewUIWithOptions sets UI.jsonMode but the human-facing
emitters still write plain text into stdout; update the UI methods (e.g.,
Success, Warn, Error, Print/Write or any helper that emits decorated/human
output) to check ui.jsonMode and, when true, avoid emitting human text to stdout
(either suppress the human output entirely or emit only machine/json payloads),
and route any non-JSON diagnostics to stderr instead; touch the methods named
Success, Warn, Error, Print (or Write) and ensure they consult UI.jsonMode
(and/or UI.quiet) before writing to the provided writer so --json no longer
leaks human text into the JSON stdout stream.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: b4ae348b-d0ce-4114-8ae3-0d36a929a3fd
📒 Files selected for processing (30)
CLAUDE.mdcli/cmd/backup.gocli/cmd/cleanup.gocli/cmd/completion_install.gocli/cmd/config.gocli/cmd/doctor.gocli/cmd/doctor_report.gocli/cmd/envvars.gocli/cmd/exitcodes.gocli/cmd/exitcodes_test.gocli/cmd/global_opts.gocli/cmd/global_opts_test.gocli/cmd/init.gocli/cmd/root.gocli/cmd/start.gocli/cmd/status.gocli/cmd/stop.gocli/cmd/uninstall.gocli/cmd/update.gocli/cmd/update_cleanup.gocli/cmd/update_health.gocli/cmd/version.gocli/cmd/wipe.gocli/internal/ui/box.gocli/internal/ui/livebox.gocli/internal/ui/spinner.gocli/internal/ui/ui.gocli/internal/ui/ui_test.gocli/main.godocs/design/operations.md
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: CLI Test (windows-latest)
- GitHub Check: Dependency Review
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (2)
cli/**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
Go CLI: golangci-lint + go vet checked in pre-commit hooks and CI (conditional on cli/**/*.go changes)
Files:
cli/cmd/version.gocli/cmd/doctor.gocli/cmd/stop.gocli/cmd/update_health.gocli/cmd/completion_install.gocli/cmd/doctor_report.gocli/cmd/init.gocli/internal/ui/spinner.gocli/cmd/uninstall.gocli/main.gocli/cmd/start.gocli/cmd/update_cleanup.gocli/cmd/status.gocli/internal/ui/box.gocli/cmd/backup.gocli/cmd/wipe.gocli/cmd/root.gocli/cmd/exitcodes_test.gocli/internal/ui/livebox.gocli/cmd/global_opts_test.gocli/internal/ui/ui_test.gocli/cmd/update.gocli/cmd/config.gocli/cmd/global_opts.gocli/cmd/exitcodes.gocli/cmd/cleanup.gocli/cmd/envvars.gocli/internal/ui/ui.go
docs/design/*.md
📄 CodeRabbit inference engine (CLAUDE.md)
Update the relevant docs/design/ page to reflect approved deviations from the spec
Files:
docs/design/operations.md
🧠 Learnings (22)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Applies to cli/**/*.go : Use Cobra for CLI command structure, charmbracelet/huh for interactive prompts, and charmbracelet/lipgloss for terminal styling
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Go 1.26+ required; CLI dependencies in `cli/go.mod` (Cobra, charmbracelet/huh, charmbracelet/lipgloss, sigstore-go, go-containerregistry, go-tuf)
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).
Applied to files:
cli/cmd/version.gocli/cmd/doctor.gocli/cmd/completion_install.gocli/cmd/uninstall.gocli/main.gocli/cmd/start.godocs/design/operations.mdcli/cmd/backup.gocli/cmd/root.gocli/cmd/global_opts_test.gocli/cmd/update.gocli/cmd/config.gocli/cmd/global_opts.gocli/cmd/exitcodes.gocli/cmd/envvars.goCLAUDE.mdcli/internal/ui/ui.go
📚 Learning: 2026-03-21T12:54:22.557Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Applies to cli/**/*.go : Use Cobra for CLI command structure, charmbracelet/huh for interactive prompts, and charmbracelet/lipgloss for terminal styling
Applied to files:
cli/cmd/doctor.gocli/cmd/uninstall.gocli/cmd/start.godocs/design/operations.mdcli/cmd/backup.gocli/cmd/root.gocli/cmd/config.gocli/cmd/global_opts.gocli/cmd/envvars.goCLAUDE.mdcli/internal/ui/ui.go
📚 Learning: 2026-03-15T20:45:14.430Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T20:45:14.430Z
Learning: Shell commands: for Go CLI work, cd cli is an exception because Go tooling requires working directory to be the module root. Go commands require `cd cli` for other work, never use `cd`.
Applied to files:
cli/main.gocli/cmd/exitcodes.goCLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.
Applied to files:
cli/cmd/start.godocs/design/operations.mdcli/cmd/backup.gocli/cmd/global_opts_test.gocli/cmd/global_opts.gocli/cmd/envvars.goCLAUDE.md
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: Applies to go.mod : Maintain Go 1.26+ requirement. Dependencies: Cobra (CLI framework), charmbracelet/huh and charmbracelet/lipgloss (UI), sigstore-go (code signing), go-containerregistry (container image verification), go-tuf (TUF client for Sigstore).
Applied to files:
cli/cmd/start.godocs/design/operations.mdcli/cmd/global_opts.gocli/internal/ui/ui.go
📚 Learning: 2026-03-21T12:54:22.557Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Go 1.26+ required; CLI dependencies in `cli/go.mod` (Cobra, charmbracelet/huh, charmbracelet/lipgloss, sigstore-go, go-containerregistry, go-tuf)
Applied to files:
cli/cmd/start.godocs/design/operations.mdcli/cmd/config.gocli/cmd/global_opts.gocli/cmd/envvars.goCLAUDE.mdcli/internal/ui/ui.go
📚 Learning: 2026-03-21T14:12:17.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T14:12:17.848Z
Learning: Applies to cli/go.mod : CLI uses Go 1.26+. Dependencies: Cobra, charmbracelet/huh, charmbracelet/lipgloss, sigstore-go, go-containerregistry, go-tuf
Applied to files:
docs/design/operations.mdcli/cmd/global_opts.gocli/cmd/exitcodes.gocli/cmd/envvars.goCLAUDE.mdcli/internal/ui/ui.go
📚 Learning: 2026-03-21T14:12:17.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T14:12:17.848Z
Learning: CLI workflow (`cli.yml`): Go lint/test/build (cross-compile) + govulncheck + fuzz. GoReleaser release on `v*` tags with cosign signing + SLSA provenance
Applied to files:
docs/design/operations.mdCLAUDE.md
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/go.mod : Go CLI dependencies: Go 1.26+, Cobra (commands), charmbracelet/huh (interactive CLI), charmbracelet/lipgloss (styled output).
Applied to files:
docs/design/operations.mdcli/cmd/config.gocli/cmd/global_opts.gocli/cmd/exitcodes.gocli/cmd/envvars.goCLAUDE.mdcli/internal/ui/ui.go
📚 Learning: 2026-03-27T17:07:16.441Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T17:07:16.441Z
Learning: Applies to cli/**/*_fuzz_test.go : Go CLI uses native 'testing.F' fuzz functions (FuzzYamlStr, etc.)
Applied to files:
cli/cmd/exitcodes_test.gocli/cmd/global_opts_test.gocli/internal/ui/ui_test.gocli/cmd/global_opts.goCLAUDE.md
📚 Learning: 2026-03-16T19:52:03.656Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T19:52:03.656Z
Learning: Applies to cli/**/*.go : Lint CLI Go code with golangci-lint and go vet; test with go test -race; check vulnerabilities with govulncheck
Applied to files:
cli/cmd/exitcodes_test.gocli/cmd/global_opts_test.gocli/cmd/envvars.goCLAUDE.md
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: Applies to cli/**/*.go : Use native Go testing with `testing.F` fuzz functions (`Fuzz*`) for fuzz testing.
Applied to files:
cli/cmd/global_opts_test.goCLAUDE.md
📚 Learning: 2026-03-19T11:30:29.217Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:30:29.217Z
Learning: Applies to cli/**/*.go : Use native `testing.F` fuzz functions (`Fuzz*`) for fuzz testing Go code
Applied to files:
cli/cmd/global_opts_test.goCLAUDE.md
📚 Learning: 2026-03-21T14:12:17.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T14:12:17.848Z
Learning: Applies to cli/**/*.go : Use native `testing.F` fuzz functions (`Fuzz*`) for fuzzing
Applied to files:
cli/cmd/global_opts_test.goCLAUDE.md
📚 Learning: 2026-03-21T12:54:22.557Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Applies to cli/**/*.go : Use native Go `testing.F` fuzz functions (`Fuzz*`) for property-based testing
Applied to files:
cli/cmd/global_opts_test.goCLAUDE.md
📚 Learning: 2026-03-19T11:30:29.217Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:30:29.217Z
Learning: Applies to cli/**/*.go : Run Go lint via `golangci-lint run`, vet via `go vet`, tests via `go test ./...`, and fuzz via `go test -fuzz=FuzzTarget -fuzztime=30s`
Applied to files:
cli/cmd/global_opts_test.goCLAUDE.md
📚 Learning: 2026-03-27T17:07:16.441Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T17:07:16.441Z
Learning: Applies to cli/**/*.go : Go CLI: golangci-lint + go vet checked in pre-commit hooks and CI (conditional on cli/**/*.go changes)
Applied to files:
cli/cmd/global_opts_test.gocli/cmd/global_opts.gocli/cmd/envvars.go
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Applied to files:
cli/cmd/global_opts.goCLAUDE.md
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: CLI workflow (`.github/workflows/cli.yml`) runs Go lint (golangci-lint + go vet) + test (race, coverage) + build (cross-compile matrix) + vulnerability check (govulncheck) + fuzz testing. Cross-compiles for linux/darwin/windows × amd64/arm64. GoReleaser release on v* tags with cosign keyless signing and SLSA L3 attestations.
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-21T12:54:22.557Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Applies to cli/**/*.go : Run Go lint via `golangci-lint run`, vet via `go vet ./...`, tests via `go test ./...` from the `cli/` directory (Go module root)
Applied to files:
CLAUDE.md
📚 Learning: 2026-03-19T07:12:14.508Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T07:12:14.508Z
Learning: Applies to src/synthorg/**/*.py : Package structure: src/synthorg/ organized as: api/ (REST+WebSocket, Litestar), auth/ (auth subpackage), backup/ (scheduled/manual backups), budget/ (cost tracking, CFO), cli/ (superseded by Go CLI), communication/ (message bus, meetings), config/ (YAML loading), core/ (domain models, resilience config), engine/ (orchestration, task state, coordination, approval gates, stagnation detection, context budget, compaction), hr/ (hiring, performance, promotion), memory/ (pluggable backend, Mem0, retrieval, consolidation), persistence/ (operational data, SQLite, settings), observability/ (logging, correlation, sinks), providers/ (LLM abstraction, LiteLLM, auth types, presets, runtime CRUD), settings/ (runtime-editable, typed definitions, encryption, config bridge), security/ (SecOps, rule engine, output scanning, progressive trust, autonomy levels), templates/ (company templates, personalities), tools/ (registry, built-in tools, git, sandbox, code_runner, MCP...
Applied to files:
CLAUDE.md
🔇 Additional comments (27)
cli/cmd/envvars.go (1)
41-52: Standard color-disable env handling is well implemented.The
NO_COLOR/CLICOLOR=0/TERM=dumbchecks are clear and match expected CLI behavior.cli/cmd/doctor.go (2)
30-31: Global UI option wiring looks correct.Using
GetGlobalOpts+NewUIWithOptionskeeps doctor output aligned with root-level flags.
75-76: Hint categorization update is good.Switching to
HintNextStepimproves guidance semantics without changing flow.cli/cmd/version.go (1)
13-14: Nice alignment with global CLI output modes.
versionnow respects shared output flags viaNewUIWithOptions.cli/internal/ui/spinner.go (1)
31-45: Spinner mode gating is solid.The quiet/plain/non-TTY handling and
clearLineguard are consistent and prevent noisy terminal control output.Also applies to: 76-76
cli/cmd/init.go (2)
37-38: Good: both stdout and stderr UIs now honor global options.This keeps init flow output consistent across modes.
Also applies to: 62-62
99-99:HintNextStepusage is appropriate here.The post-init guidance now uses the categorized hint path as intended.
cli/cmd/config.go (2)
78-79: Global UI option adoption in config commands looks good.Both show/set paths now correctly inherit root output behavior.
Also applies to: 178-179
90-90: Good migration toHintNextStep.This keeps onboarding guidance consistent with the new hint taxonomy.
cli/cmd/doctor_report.go (2)
31-32: UI initialization via global opts is correct.
doctor reportnow properly respects global output flags.
62-63: Step-oriented hint text migration is clean.Using
HintNextStephere improves consistency with the new guidance model.cli/cmd/stop.go (1)
43-44: Global output mode wiring instopis good.This keeps spinner and status rendering behavior consistent with root flags.
cli/cmd/update_health.go (1)
28-29: LGTM!The migration to
GetGlobalOptsandNewUIWithOptionsis correct and consistent with the PR-wide pattern. The UI instance now respects global configuration for quiet/plain/json modes.docs/design/operations.md (1)
1078-1081: LGTM!The documentation accurately reflects the new global output modes and typed exit codes introduced in this PR. The exit code semantics (0=success, 1=runtime, 2=usage, 3=unhealthy, 4=unreachable, 10=update-available) are clearly documented and align with the implementation in
cli/cmd/exitcodes.go.cli/cmd/update_cleanup.go (2)
37-38: LGTM!The migration to
GetGlobalOptsandNewUIWithOptionsfollows the PR-wide pattern correctly.
108-109: LGTM!The migration to global options is correct, and
HintTipis the appropriate hint category for this passive suggestion about disk space cleanup.Also applies to: 124-125
cli/cmd/uninstall.go (3)
39-41: LGTM!Creating separate UI instances for stdout (
out) and stderr (errUI) with consistent global options is the correct approach for proper output stream separation.
304-308: LGTM!The migration is correct, and
HintNextStepis the appropriate hint category for actionable instructions (manual binary removal).
378-382: LGTM!Consistent with the pattern used elsewhere in this file.
HintNextStepcorrectly indicates an action the user should take.cli/cmd/status.go (1)
41-43: LGTM!The local
--jsonflag removal and migration to globalopts.JSONis correct. This promotes consistency across all commands and simplifies the flag management.cli/main.go (1)
12-22: LGTM!The error handling cascade is well-structured:
ChildExitCodefor re-exec'd binary failures (preserves child's exit code)ExitErrorfor typed exit codes from commands- Default
os.Exit(1)as fallbackUsing
errors.Asis the idiomatic Go approach for unwrapping typed errors.cli/cmd/cleanup.go (4)
39-40: LGTM!The migration to
GetGlobalOptsandNewUIWithOptionsis correct.
66-66: LGTM!
HintTipis the correct category for an optional configuration suggestion.
92-92: LGTM!
HintNextStepis appropriate for providing actionable guidance in non-interactive mode.
138-138: LGTM!
HintErroris the correct category for explaining why some images couldn't be removed (error-related context).cli/cmd/completion_install.go (2)
28-29: LGTM!The migration to
GetGlobalOptsandNewUIWithOptionsis correct.
49-49: LGTM!
HintNextStepis the appropriate category for this actionable instruction to restart the shell.
| // ShouldPrompt reports whether the CLI should show interactive prompts. | ||
| // Returns false when --yes is active or stdin is not a terminal. | ||
| func (g *GlobalOpts) ShouldPrompt() bool { | ||
| if g.Yes { | ||
| return false | ||
| } | ||
| fi, err := os.Stdin.Stat() | ||
| if err != nil { | ||
| return false | ||
| } | ||
| return fi.Mode()&os.ModeCharDevice != 0 | ||
| } |
There was a problem hiding this comment.
The new prompt helper is still disconnected from real confirmations.
GlobalOpts.Yes is only exercised here and in tests. The update confirmation paths still gate on isInteractive() directly, so synthorg update --yes will continue to prompt on a terminal. Please thread the resolved global opts into those confirm paths before relying on this flag.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@cli/cmd/global_opts.go` around lines 35 - 46, The confirmation logic
currently ignores GlobalOpts.Yes because callers still call isInteractive()
directly; update the confirm code paths to consume the resolved global option
instead: thread GlobalOpts (or at least its ShouldPrompt() result) into the
confirmation helpers used by the synthorg update flow and replace direct calls
to isInteractive() with g.ShouldPrompt() (or use the passed-in bool) in those
helpers (look for functions named isInteractive, confirmUpdate/confirmAction or
the update command handler that performs the prompt). Ensure the synthorg update
command's run/handler signature accepts the GlobalOpts (or a prompt boolean) and
forward it to the confirmation helper so --yes disables prompts; update
associated tests to pass the GlobalOpts or bool instead of relying on
isInteractive().
cli/cmd/root.go
Outdated
| // Validate mutual exclusivity. | ||
| if flagQuiet && flagVerbose > 0 { | ||
| return fmt.Errorf("--quiet and --verbose are mutually exclusive") | ||
| } | ||
| if flagPlain && flagJSON { | ||
| return fmt.Errorf("--plain and --json are mutually exclusive") |
There was a problem hiding this comment.
Resolve the effective flag values before validating them.
These branches use the bool value itself to mean “flag not passed” and perform the conflict check before env resolution. That breaks both precedence and mutual exclusion: SYNTHORG_QUIET=1 synthorg --quiet=false ... still resolves to quiet, and SYNTHORG_QUIET=1 synthorg -v ... slips past the conflict check because the env override is applied later. Compute the effective values first from explicit-flag presence + env, then validate those effective opts and return ExitUsage for invalid combinations.
Also applies to: 69-91
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@cli/cmd/root.go` around lines 61 - 66, Compute the effective option values
before running the mutual-exclusion checks: use the explicit-flag presence
indicators together with environment-derived overrides to produce resolvedQuiet,
resolvedVerbose (or an integer), resolvedPlain, and resolvedJSON, then validate
those resolved variables rather than the raw flag booleans (e.g. replace checks
of flagQuiet/flagVerbose/flagPlain/flagJSON with
resolvedQuiet/resolvedVerbose/resolvedPlain/resolvedJSON). If a conflict is
detected return ExitUsage with a clear error (e.g. "--quiet and --verbose are
mutually exclusive" or "--plain and --json are mutually exclusive"). Apply this
same pattern for the other validation blocks referenced in the comment (lines
~69-91) so all mutual-exclusion checks use the resolved values.
…on, resolveDataDir consolidation - Use GlobalOpts.SkipVerify instead of raw flagSkipVerify in start.go and update.go so SYNTHORG_NO_VERIFY/SYNTHORG_SKIP_VERIFY env vars take effect - Migrate isInteractive() to ShouldPrompt() in confirmUpdate, confirmUpdateWithDefault, restartIfRunning, promptHealthRecover, and confirmAndCleanup so --yes/SYNTHORG_YES flag is respected - Allow --yes to bypass TTY requirement for destructive commands (wipe, uninstall) per design spec: "require --yes or interactive" - Replace redundant resolveDataDir() calls with opts.DataDir from GlobalOpts across all 15 command files for single-source-of-truth resolution - Add filepath.Abs normalization in resolveDataDir for env-sourced paths - Sanitize execPath/dataDir against double-quote injection in Windows .bat cleanup script (uninstall.go) - Add PersistentPreRunE chaining warning comment on root command - Document validHintsMode as defensive/forward-looking dead code - Clarify envBool behavior, NewExitError nil intent, isInteractive usage - Fix operations.md env var claim accuracy Addresses 11 findings from go-reviewer, go-conventions, go-security, docs-consistency agents and gemini-code-assist. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…sion, livebox quiet, tip dedup - Return ExitUsage (code 2) for missing --confirm in backup restore - Trim whitespace in envBool before parsing boolean env values - Move mutual exclusion checks (--quiet vs --verbose, --plain vs --json) after env var resolution so SYNTHORG_QUIET=1 + --verbose is caught - Fix LiveBox quiet/JSON mode leaking human output to stdout by suppressing Error/Success in the immediate-print path when quiet - Make HintTip dedup store package-level (sessionTipsSeen) so all UI instances share session-level deduplication Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (3)
cli/cmd/root.go (1)
65-71:⚠️ Potential issue | 🟠 MajorMutual exclusivity checks use raw flags, not resolved effective values.
The validation runs before environment variable resolution (lines 77-95). This means combinations like
SYNTHORG_QUIET=1 synthorg -vorSYNTHORG_JSON=1 synthorg --plainbypass the conflict check because the env-derived value hasn't been applied yet.Move the conflict checks after computing effective values, or compute effective values first then validate:
🔧 Suggested fix
func setupGlobalOpts(cmd *cobra.Command) error { - // Validate mutual exclusivity. - if flagQuiet && flagVerbose > 0 { - return fmt.Errorf("--quiet and --verbose are mutually exclusive") - } - if flagPlain && flagJSON { - return fmt.Errorf("--plain and --json are mutually exclusive") - } - // Resolve env var overrides for flags that were NOT explicitly passed. // ... noColor := flagNoColor if !flagNoColor && noColorFromEnv() { noColor = true } quiet := flagQuiet if !flagQuiet && envBool(EnvQuiet) { quiet = true } + verbose := flagVerbose + // Note: no env override for verbose count currently + + plain := flagPlain + // Note: no env override for plain currently + + jsonMode := flagJSON + // Note: no env override for json currently + + // Validate mutual exclusivity after resolving effective values. + if quiet && verbose > 0 { + return fmt.Errorf("--quiet and --verbose are mutually exclusive") + } + if plain && jsonMode { + return fmt.Errorf("--plain and --json are mutually exclusive") + } + yes := flagYes // ...🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cli/cmd/root.go` around lines 65 - 71, The mutual-exclusivity validation currently checks raw flags (flagQuiet, flagVerbose, flagPlain, flagJSON) before environment-based resolution, so env-derived values can bypass the checks; fix by computing the effective values first (the resolved variables set after the env resolution logic) or move the conflict checks to after the code that resolves environment variables, then validate using the effective values (e.g., use the resolvedQuiet/resolvedVerbose or the same variables updated after env resolution) for the checks involving flagQuiet/flagVerbose and flagPlain/flagJSON.cli/cmd/wipe.go (1)
67-70:⚠️ Potential issue | 🟠 MajorStandard migration applied, but
--yesstill doesn't fully bypass prompts.The check now allows
--yesto bypass the initial interactive gate (good), but the subsequenthuhprompts inconfirmWipe,promptForBackup,promptSavePath, etc. still require interactive input. Runningsynthorg wipe --yesin a non-interactive environment will pass line 68 but then fail at the first prompt.For
--yesto work in automation, each prompt method needs to checkopts.Yesand return the affirmative/default value without showing thehuhform.🔧 Conceptual fix pattern for prompts
func (wc *wipeContext) confirmWipe() (bool, error) { + if GetGlobalOpts(wc.ctx).Yes { + return true, nil // auto-confirm in non-interactive mode + } var confirmed bool err := wc.runForm(huh.NewForm(huh.NewGroup( // ...Apply similar pattern to
promptForBackup,promptStartForBackup,promptSavePath,checkOverwrite,askContinueWithoutBackup, andpromptStartAfterWipe.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cli/cmd/wipe.go` around lines 67 - 70, The various interactive prompt helpers (promptForBackup, promptStartForBackup, promptSavePath, checkOverwrite, askContinueWithoutBackup, promptStartAfterWipe) still display "huh" prompts even when the global opts.Yes is set; update each function to read opts := GetGlobalOpts(ctx) (or accept opts) and if opts.Yes return the affirmative/default response immediately (e.g., treat as confirmed/keep default path/overwrite allowed) without invoking the interactive prompt or huh form, so that --yes fully bypasses all prompts during non-interactive runs while preserving existing behavior when opts.Yes is false.cli/cmd/backup.go (1)
400-403:⚠️ Potential issue | 🟠 MajorMissing
--confirmshould return the usage exit code.This is a bad invocation (user error), but Line 403 returns a plain error, so
main.gofalls back to exit code 1 instead of the documented usage code 2. Wrap this path inNewExitError(ExitUsage, ...)so scripts can distinguish user mistakes from runtime failures.🔧 Suggested fix
if !confirm { errOut.Error("Restore requires the --confirm flag as a safety gate") errOut.HintNextStep(fmt.Sprintf("Run 'synthorg backup restore %s --confirm' to proceed", backupID)) - return errors.New("--confirm flag is required") + return NewExitError(ExitUsage, "--confirm flag is required") }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cli/cmd/backup.go` around lines 400 - 403, The missing --confirm branch currently returns a plain error; change it to return a usage exit error so callers get exit code 2. Keep the errOut.Error and errOut.HintNextStep calls, but replace the final return of errors.New("--confirm flag is required") with return NewExitError(ExitUsage, errors.New("--confirm flag is required")) (or NewExitError(ExitUsage, "--confirm flag is required") if that overload exists). This change affects the restore path where the confirm boolean is checked (look for the confirm variable and the errOut.Error / errOut.HintNextStep calls) and uses the NewExitError and ExitUsage symbols to signal a user-usage error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@cli/cmd/global_opts_test.go`:
- Around line 89-99: The test TestShouldPromptDefault currently doesn't assert a
deterministic outcome; update it to inspect the current stdin state and assert
accordingly: call os.Stdin.Stat() or use a terminal check (e.g.,
term.IsTerminal) to determine whether stdin is a TTY, then assert
GlobalOpts{}.ShouldPrompt() == true when stdin is a TTY and == false when it is
not. Modify TestShouldPromptDefault to branch on that runtime check and use
t.Fatalf/t.Errorf to fail when the observed value of ShouldPrompt() doesn't
match the detected stdin terminal state.
In `@cli/cmd/update.go`:
- Around line 392-393: The code calls GetGlobalOpts(cmd.Context()) and
constructs the UI with ui.NewUIWithOptions(...), but it should use the
function's ctx parameter for consistency; change the call to GetGlobalOpts to
pass ctx instead of cmd.Context() and ensure any subsequent uses in this block
(e.g., opts := GetGlobalOpts(...), out := ui.NewUIWithOptions(...)) continue to
use the ctx parameter.
- Around line 187-194: The comment is inaccurate: GlobalOpts is available when
resolveUpdateChannel runs, so either update the comment or (preferred) make
resolveUpdateChannel use GlobalOpts for consistency—change resolveUpdateChannel
to accept ctx (e.g., resolveUpdateChannel(ctx context.Context)), replace
resolveDataDir() with GetGlobalOpts(ctx).DataDir inside resolveUpdateChannel,
and update its callers (runUpdate / updateCLI) to pass the current ctx; also
update the comment to reflect that it reads DataDir from GlobalOpts via the
context.
---
Duplicate comments:
In `@cli/cmd/backup.go`:
- Around line 400-403: The missing --confirm branch currently returns a plain
error; change it to return a usage exit error so callers get exit code 2. Keep
the errOut.Error and errOut.HintNextStep calls, but replace the final return of
errors.New("--confirm flag is required") with return NewExitError(ExitUsage,
errors.New("--confirm flag is required")) (or NewExitError(ExitUsage, "--confirm
flag is required") if that overload exists). This change affects the restore
path where the confirm boolean is checked (look for the confirm variable and the
errOut.Error / errOut.HintNextStep calls) and uses the NewExitError and
ExitUsage symbols to signal a user-usage error.
In `@cli/cmd/root.go`:
- Around line 65-71: The mutual-exclusivity validation currently checks raw
flags (flagQuiet, flagVerbose, flagPlain, flagJSON) before environment-based
resolution, so env-derived values can bypass the checks; fix by computing the
effective values first (the resolved variables set after the env resolution
logic) or move the conflict checks to after the code that resolves environment
variables, then validate using the effective values (e.g., use the
resolvedQuiet/resolvedVerbose or the same variables updated after env
resolution) for the checks involving flagQuiet/flagVerbose and
flagPlain/flagJSON.
In `@cli/cmd/wipe.go`:
- Around line 67-70: The various interactive prompt helpers (promptForBackup,
promptStartForBackup, promptSavePath, checkOverwrite, askContinueWithoutBackup,
promptStartAfterWipe) still display "huh" prompts even when the global opts.Yes
is set; update each function to read opts := GetGlobalOpts(ctx) (or accept opts)
and if opts.Yes return the affirmative/default response immediately (e.g., treat
as confirmed/keep default path/overwrite allowed) without invoking the
interactive prompt or huh form, so that --yes fully bypasses all prompts during
non-interactive runs while preserving existing behavior when opts.Yes is false.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 07fe8ff3-be25-4f0f-97ea-75e417a22ccc
📒 Files selected for processing (19)
cli/cmd/backup.gocli/cmd/cleanup.gocli/cmd/config.gocli/cmd/doctor.gocli/cmd/doctor_report.gocli/cmd/envvars.gocli/cmd/exitcodes.gocli/cmd/global_opts_test.gocli/cmd/logs.gocli/cmd/root.gocli/cmd/start.gocli/cmd/status.gocli/cmd/stop.gocli/cmd/uninstall.gocli/cmd/update.gocli/cmd/update_compose.gocli/cmd/update_health.gocli/cmd/wipe.godocs/design/operations.md
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: CLI Test (windows-latest)
- GitHub Check: Dependency Review
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (2)
cli/**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
Go CLI: golangci-lint + go vet checked in pre-commit hooks and CI (conditional on cli/**/*.go changes)
Files:
cli/cmd/update_compose.gocli/cmd/status.gocli/cmd/logs.gocli/cmd/update_health.gocli/cmd/doctor_report.gocli/cmd/stop.gocli/cmd/doctor.gocli/cmd/cleanup.gocli/cmd/start.gocli/cmd/root.gocli/cmd/backup.gocli/cmd/global_opts_test.gocli/cmd/uninstall.gocli/cmd/wipe.gocli/cmd/config.gocli/cmd/envvars.gocli/cmd/exitcodes.gocli/cmd/update.go
docs/design/*.md
📄 CodeRabbit inference engine (CLAUDE.md)
Update the relevant docs/design/ page to reflect approved deviations from the spec
Files:
docs/design/operations.md
🧠 Learnings (18)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Applies to cli/**/*.go : Use Cobra for CLI command structure, charmbracelet/huh for interactive prompts, and charmbracelet/lipgloss for terminal styling
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Go 1.26+ required; CLI dependencies in `cli/go.mod` (Cobra, charmbracelet/huh, charmbracelet/lipgloss, sigstore-go, go-containerregistry, go-tuf)
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/go.mod : Go CLI dependencies: Go 1.26+, Cobra (commands), charmbracelet/huh (interactive CLI), charmbracelet/lipgloss (styled output).
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).
Applied to files:
cli/cmd/update_compose.godocs/design/operations.mdcli/cmd/cleanup.gocli/cmd/start.gocli/cmd/root.gocli/cmd/backup.gocli/cmd/global_opts_test.gocli/cmd/uninstall.gocli/cmd/config.gocli/cmd/envvars.gocli/cmd/exitcodes.gocli/cmd/update.go
📚 Learning: 2026-03-21T14:12:17.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T14:12:17.848Z
Learning: Applies to cli/go.mod : CLI uses Go 1.26+. Dependencies: Cobra, charmbracelet/huh, charmbracelet/lipgloss, sigstore-go, go-containerregistry, go-tuf
Applied to files:
cli/cmd/update_compose.godocs/design/operations.mdcli/cmd/envvars.go
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.
Applied to files:
docs/design/operations.mdcli/cmd/start.gocli/cmd/envvars.go
📚 Learning: 2026-03-21T12:54:22.557Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Go 1.26+ required; CLI dependencies in `cli/go.mod` (Cobra, charmbracelet/huh, charmbracelet/lipgloss, sigstore-go, go-containerregistry, go-tuf)
Applied to files:
docs/design/operations.mdcli/cmd/start.gocli/cmd/config.gocli/cmd/envvars.go
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: Applies to go.mod : Maintain Go 1.26+ requirement. Dependencies: Cobra (CLI framework), charmbracelet/huh and charmbracelet/lipgloss (UI), sigstore-go (code signing), go-containerregistry (container image verification), go-tuf (TUF client for Sigstore).
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-21T14:12:17.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T14:12:17.848Z
Learning: CLI workflow (`cli.yml`): Go lint/test/build (cross-compile) + govulncheck + fuzz. GoReleaser release on `v*` tags with cosign signing + SLSA provenance
Applied to files:
docs/design/operations.md
📚 Learning: 2026-03-21T12:54:22.557Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Applies to cli/**/*.go : Use Cobra for CLI command structure, charmbracelet/huh for interactive prompts, and charmbracelet/lipgloss for terminal styling
Applied to files:
docs/design/operations.mdcli/cmd/root.gocli/cmd/envvars.go
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/go.mod : Go CLI dependencies: Go 1.26+, Cobra (commands), charmbracelet/huh (interactive CLI), charmbracelet/lipgloss (styled output).
Applied to files:
docs/design/operations.mdcli/cmd/envvars.go
📚 Learning: 2026-03-27T17:07:16.441Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T17:07:16.441Z
Learning: Applies to cli/**/*.go : Go CLI: golangci-lint + go vet checked in pre-commit hooks and CI (conditional on cli/**/*.go changes)
Applied to files:
cli/cmd/start.gocli/cmd/global_opts_test.gocli/cmd/envvars.go
📚 Learning: 2026-03-27T17:07:16.441Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T17:07:16.441Z
Learning: Applies to cli/**/*_fuzz_test.go : Go CLI uses native 'testing.F' fuzz functions (FuzzYamlStr, etc.)
Applied to files:
cli/cmd/global_opts_test.go
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: Applies to cli/**/*.go : Use native Go testing with `testing.F` fuzz functions (`Fuzz*`) for fuzz testing.
Applied to files:
cli/cmd/global_opts_test.go
📚 Learning: 2026-03-21T14:12:17.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T14:12:17.848Z
Learning: Applies to cli/**/*.go : Use native `testing.F` fuzz functions (`Fuzz*`) for fuzzing
Applied to files:
cli/cmd/global_opts_test.go
📚 Learning: 2026-03-21T12:54:22.557Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Applies to cli/**/*.go : Use native Go `testing.F` fuzz functions (`Fuzz*`) for property-based testing
Applied to files:
cli/cmd/global_opts_test.go
📚 Learning: 2026-03-19T11:30:29.217Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:30:29.217Z
Learning: Applies to cli/**/*.go : Use native `testing.F` fuzz functions (`Fuzz*`) for fuzz testing Go code
Applied to files:
cli/cmd/global_opts_test.go
📚 Learning: 2026-03-19T11:30:29.217Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:30:29.217Z
Learning: Applies to cli/**/*.go : Run Go lint via `golangci-lint run`, vet via `go vet`, tests via `go test ./...`, and fuzz via `go test -fuzz=FuzzTarget -fuzztime=30s`
Applied to files:
cli/cmd/global_opts_test.go
📚 Learning: 2026-03-16T19:52:03.656Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T19:52:03.656Z
Learning: Applies to cli/**/*.go : Lint CLI Go code with golangci-lint and go vet; test with go test -race; check vulnerabilities with govulncheck
Applied to files:
cli/cmd/global_opts_test.go
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: Applies to cli/**/*.go : Lint Go code with `golangci-lint` and `go vet`. Run tests with `-race` flag to detect race conditions.
Applied to files:
cli/cmd/global_opts_test.go
🔇 Additional comments (52)
cli/cmd/global_opts_test.go (1)
1-22: LGTM — solid test coverage for GlobalOpts defaults and context plumbing.The tests verify that
GetGlobalOptsnever returns nil, defaults are correct (Hints == "auto", booleans false), and the set/get round-trip preserves pointer identity. Good use oft.Parallel().cli/cmd/exitcodes.go (1)
1-63: LGTM — well-designed exit code system with proper error wrapping.The exit codes follow Unix conventions (0=success, 1=general error, 2=usage).
ExitErrorcorrectly implementsUnwrap()forerrors.Is/Aschains, andChildExitErrorcleanly separates re-exec exit code propagation. The gap between codes 4 and 10 allows future expansion.cli/cmd/update_compose.go (1)
139-139: LGTM — context propagation for global options access.Passing
cmd.Context()toconfirmUpdateenables it to accessGlobalOptsfor prompt gating viaShouldPrompt(), consistent with the PR's migration pattern.cli/cmd/logs.go (1)
42-42: LGTM — migrated to global options for data directory resolution.Using
GetGlobalOpts(ctx).DataDircentralizes data directory handling and ensures--data-dirflag andSYNTHORG_DATA_DIRenv var are respected consistently.docs/design/operations.md (1)
1078-1081: LGTM — documentation accurately reflects the new CLI global options and exit codes.The documented flags (
--quiet,--verbose/-v,--plain,--json,--no-color,--yes) and exit codes (0, 1, 2, 3, 4, 10) align with the implementation inexitcodes.goand the PR objectives.cli/cmd/update_health.go (2)
28-29: LGTM — UI initialization migrated to global options pattern.Using
GetGlobalOpts(cmd.Context())andopts.UIOptions()ensures health check output respects--quiet,--plain,--json, and--no-colorflags.
90-94: LGTM — prompt gating migrated toShouldPrompt().Replacing
isInteractive()withGetGlobalOpts(cmd.Context()).ShouldPrompt()ensures--yesflag andSYNTHORG_YESenv var are respected for non-interactive recovery flows.cli/cmd/doctor_report.go (2)
30-33: LGTM — migrated to global options for UI and config loading.Consistent with the PR-wide pattern of using
GetGlobalOpts(ctx)for data directory and UI options.
61-62: LGTM — hint rendering migrated to categorizedHintNextStep.Using
HintNextStepfor actionable instructions aligns with the PR's expanded hint system that supports always/auto/never behavior and categorized methods.cli/cmd/doctor.go (2)
29-32: LGTM — migrated to global options pattern.Using
GetGlobalOpts(ctx)for both UI options and data directory resolution ensures consistent flag/env var handling across all commands.
74-75: LGTM — hint rendering updated toHintNextStep.Categorized hints (
HintNextStep) for actionable commands likedoctor reportandlogsalign with the PR's hint system migration.cli/cmd/status.go (1)
34-41: LGTM!The migration to
GetGlobalOptsfor data directory and JSON mode, along withNewUIWithOptionsfor UI construction, is consistent with the PR's global options infrastructure. The removal of the local--jsonflag in favor of the global one simplifies the command interface.cli/cmd/stop.go (1)
27-42: LGTM!Standard migration to global options for data directory resolution and UI construction. The control flow remains intact.
cli/cmd/config.go (3)
77-89: LGTM!The migration correctly uses
config.SecurePath(opts.DataDir)for direct path access before checking file existence, andHintNextStepappropriately guides the user when config is not found.
135-135: LGTM!Consistent use of
config.SecurePathfor direct path resolution inrunConfigGet.
175-178: LGTM!The migration to global options is correct. Using
config.Load(opts.DataDir)directly here is consistent with other commands (start, stop, backup) sinceconfig.Loadhandles path security internally.cli/cmd/cleanup.go (4)
32-38: LGTM!Standard migration pattern applied correctly.
64-64: LGTM!
HintTipis the appropriate category for this optional suggestion about auto-cleanup configuration.
89-90: LGTM!Using
ShouldPrompt()here is correct—cleanup is not a destructive command requiring separate TTY/--yes evaluation (unlike wipe/uninstall per the context snippet from root.go). The hint appropriately guides users in non-interactive mode.
136-136: LGTM!
HintErroris appropriate for error recovery guidance when images couldn't be removed.cli/cmd/backup.go (5)
301-308: LGTM!Standard migration pattern for
runBackupCreatewith both stdout and stderr UI instances.
342-349: LGTM!Standard migration pattern for
runBackupList.
376-376: LGTM!
HintNextStepis appropriate for guiding the user to create a backup.
392-417: LGTM!The migration for
runBackupRestorecorrectly uses global options for UI and data directory. TheHintNextStepcalls provide clear guidance.
475-515: LGTM!The
HintNextStepcalls in error handlers and post-restore guidance are appropriate for directing user actions.cli/cmd/start.go (4)
37-56: LGTM!Standard migration to global options for data directory and UI construction with both stdout and stderr instances.
108-108: LGTM!
HintErroris appropriate for error recovery guidance on health check failure.
159-162: LGTM!The previous review comment has been addressed—
verifyAndPinImagesnow correctly usesGetGlobalOpts(ctx).SkipVerifyinstead of the raw flag variable, ensuring thatSYNTHORG_NO_VERIFY/SYNTHORG_SKIP_VERIFYenvironment variables are properly respected.
177-177: LGTM!
HintErrorappropriately guides users on how to handle transport errors in air-gapped environments.cli/cmd/root.go (7)
16-26: LGTM!Clear declaration of persistent flag storage variables.
37-44: LGTM!The warning comment about Cobra's
PersistentPreRunEbehavior is important documentation—Cobra does not chain these hooks, so subcommands with their own hooks must explicitly callsetupGlobalOpts.
47-60: LGTM!Persistent flags are correctly registered with appropriate types (
CountVarPfor stackable verbose,BoolVarPfor shortcuts).
77-106: LGTM!Environment variable resolution correctly applies overrides only when flags weren't explicitly set. The
GlobalOptsstruct is populated with all resolved values.
120-140: LGTM!
resolveDataDircorrectly implements the priority chain (flag → env → default) and normalizes to absolute path with symlink resolution for security.
148-158: LGTM!The updated comment correctly documents when to use
isInteractive()vsShouldPrompt()—the former is for destructive commands (wipe, uninstall) that need separate TTY/--yes evaluation.
187-194: LGTM!Correctly suppresses stderr printing for
ChildExitErrorsincemain.gohandles exit code propagation and the internal message isn't user-facing.cli/cmd/wipe.go (6)
74-91: LGTM!Standard migration to global options for data directory and UI construction.
127-165: LGTM!
HintNextStepcalls provide appropriate guidance for post-wipe actions, browser opening, and manual start instructions.
333-354: LGTM!
HintNextStepcalls for cancellation messaging are appropriate.
379-436: LGTM!
HintNextStepcalls in path prompts and overwrite handling provide clear user guidance.
457-457: LGTM!
HintErroris appropriate here—the backup exists in the container but will be destroyed, which is an error-recovery situation requiring user awareness.
577-583: LGTM!
HintNextStepfor cancellation messaging is consistent with other prompt handlers.cli/cmd/envvars.go (3)
30-40: Trim whitespace before parsing boolean env values.The
envBoolfunction does not handle leading/trailing whitespace in environment variable values. Values like" true "or"yes "will silently fall back tofalse, which can cause unexpected behavior when users accidentally include whitespace.Suggested fix
func envBool(name string) bool { - v := os.Getenv(name) + v := strings.TrimSpace(os.Getenv(name)) if v == "" { return false } switch strings.ToLower(v) { case "1", "true", "yes": return true } return false }
10-24: Well-structured environment variable constants.The constants are clearly documented with the precedence comment and include a backward-compatibility alias for
EnvSkipVerify. The naming convention follows theSYNTHORG_*prefix consistently.
44-55: Correct implementation of the NO_COLOR spec and related standards.The function properly handles:
NO_COLOR(any non-empty value per https://no-color.org/)CLICOLOR=0(the de-facto standard)TERM=dumb(common in non-interactive environments)cli/cmd/uninstall.go (3)
34-39: Correct guard for destructive operations in non-interactive mode.The condition
!isInteractive() && !opts.Yescorrectly requires the--yesflag when stdin is not a TTY. This is intentionally stricter thanShouldPrompt()(which auto-accepts in non-interactive mode) — appropriate for a destructive uninstall operation that should fail-safe rather than auto-proceed.
323-327: Good security hardening against command injection.Validating that paths don't contain double-quote characters before embedding them in the
.batscript prevents potential command injection. The fallback to manual cleanup is the correct mitigation.
240-241: LGTM — consistent migration to global opts pattern.The UI construction now correctly uses
GetGlobalOpts(cmd.Context())andopts.UIOptions()throughout the file (removeDataDir,removeUnixBinary,scheduleWindowsCleanup,fallbackManualCleanup).cli/cmd/update.go (4)
49-52: Consistent use of GlobalOpts for config loading.Using
GetGlobalOpts(cmd.Context()).DataDiraligns with the PR-wide migration and ensures the resolved data directory respects flag/env/config precedence.
226-250: Comprehensive forwarding of global flags in re-exec.All relevant global flags are now reconstructed and forwarded to the re-launched binary:
--data-dir,--skip-verify,--quiet,-v(repeated per verbosity level),--no-color,--plain,--json, and--yes. This ensures consistent behavior across the re-exec boundary.
366-384: Correct use of ShouldPrompt for non-destructive confirmations.Using
ShouldPrompt()here is appropriate — unlike the destructiveuninstallcommand, update confirmations can safely auto-accept their defaults in non-interactive mode.
503-506: Appropriate behavior: skip restart in non-interactive mode.Unlike
uninstall(which errors out), skipping the restart prompt and printing guidance is the right choice here — failing to restart is recoverable, and the user is informed how to proceed manually.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@cli/internal/ui/ui.go`:
- Around line 182-194: The Success, Warn and Error methods (UI.Success, UI.Warn,
UI.Error) currently always call u.printLine and can leak human text while
u.jsonMode is enabled; update each method to return early when u.jsonMode is
true (i.e. if u.jsonMode { return }) so JSON mode suppresses human output, while
keeping existing behavior otherwise; reference these three methods and ensure
the logic mirrors the Options/jsonMode contract in the Options comment.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 8dec177c-fdde-4d0c-8aed-7c6b75439444
📒 Files selected for processing (5)
cli/cmd/backup.gocli/cmd/envvars.gocli/cmd/root.gocli/internal/ui/livebox.gocli/internal/ui/ui.go
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
cli/**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
Go CLI: golangci-lint + go vet checked in pre-commit hooks and CI (conditional on cli/**/*.go changes)
Files:
cli/cmd/backup.gocli/internal/ui/livebox.gocli/cmd/envvars.gocli/cmd/root.gocli/internal/ui/ui.go
🧠 Learnings (8)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Applies to cli/**/*.go : Use Cobra for CLI command structure, charmbracelet/huh for interactive prompts, and charmbracelet/lipgloss for terminal styling
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Go 1.26+ required; CLI dependencies in `cli/go.mod` (Cobra, charmbracelet/huh, charmbracelet/lipgloss, sigstore-go, go-containerregistry, go-tuf)
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).
Applied to files:
cli/cmd/envvars.gocli/internal/ui/ui.go
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/go.mod : Go CLI dependencies: Go 1.26+, Cobra (commands), charmbracelet/huh (interactive CLI), charmbracelet/lipgloss (styled output).
Applied to files:
cli/cmd/envvars.gocli/internal/ui/ui.go
📚 Learning: 2026-03-21T12:54:22.557Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Applies to cli/**/*.go : Use Cobra for CLI command structure, charmbracelet/huh for interactive prompts, and charmbracelet/lipgloss for terminal styling
Applied to files:
cli/cmd/envvars.gocli/cmd/root.gocli/internal/ui/ui.go
📚 Learning: 2026-03-27T17:07:16.441Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T17:07:16.441Z
Learning: Applies to cli/**/*.go : Go CLI: golangci-lint + go vet checked in pre-commit hooks and CI (conditional on cli/**/*.go changes)
Applied to files:
cli/cmd/envvars.go
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.
Applied to files:
cli/cmd/envvars.go
📚 Learning: 2026-03-21T14:12:17.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T14:12:17.848Z
Learning: Applies to cli/go.mod : CLI uses Go 1.26+. Dependencies: Cobra, charmbracelet/huh, charmbracelet/lipgloss, sigstore-go, go-containerregistry, go-tuf
Applied to files:
cli/cmd/envvars.go
📚 Learning: 2026-03-21T12:54:22.557Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Go 1.26+ required; CLI dependencies in `cli/go.mod` (Cobra, charmbracelet/huh, charmbracelet/lipgloss, sigstore-go, go-containerregistry, go-tuf)
Applied to files:
cli/cmd/envvars.go
🔇 Additional comments (17)
cli/cmd/envvars.go (2)
30-40: LGTM!The
envBoolfunction correctly trims whitespace before parsing (addressing the prior review feedback) and handles the standard truthy values case-insensitively.
42-55: LGTM!The
noColorFromEnvfunction correctly implements the standard environment signals for disabling color output:NO_COLOR(any non-empty value per the spec),CLICOLOR=0, andTERM=dumb.cli/cmd/backup.go (3)
299-308: LGTM!The migration to
GetGlobalOpts(ctx)andui.NewUIWithOptionsfollows the new global options pattern consistently.
400-403: LGTM!The missing
--confirmpath now correctly returnsNewExitError(ExitUsage, ...)so scripts can distinguish user mistakes (exit code 2) from runtime failures (exit code 1).
374-377: LGTM!The migration from
Hint()toHintNextStep()is semantically correct here — this is guidance for the user's next action after seeing "no backups found".cli/internal/ui/livebox.go (4)
58-67: LGTM!The width calculation correctly uses
PlainIconSuccesswhen in plain mode to ensure proper column alignment.
80-89: LGTM!The quiet mode early return and plain mode fallback to
Step()are correctly implemented, preventing any live-box rendering in those modes while still allowing the title to be displayed as a step in plain/non-TTY contexts.
117-131: LGTM!The
UpdateLinemethod correctly gates output based on UI modes: quiet/JSON suppresses human output entirely (with errors propagating through return values), while plain mode uses ASCII icons for finish events.
217-221: LGTM!The
redrawmethod correctly no-ops for non-TTY, plain, and quiet modes, preventing ANSI cursor movement sequences from corrupting output in those contexts.cli/cmd/root.go (4)
37-44: Cobra hook behavior documented.Good documentation of the Cobra limitation where subcommand pre-run hooks silently override the parent's
PersistentPreRunE. This warns future developers to callsetupGlobalOptsexplicitly if they add pre-run hooks to subcommands.
64-96: LGTM!The mutual exclusivity checks now correctly use the resolved values (after env var overrides are applied), addressing the prior review feedback. The check at line 91 uses the resolved
quiet(which incorporatesSYNTHORG_QUIET) againstflagVerbose, and line 94 uses the raw flags for--plain/--jsonwhich have no env var counterparts.
121-141: LGTM!The
resolveDataDirfunction correctly implements the precedence (flag > env > default), normalizes to an absolute path, and resolves symlinks to prevent path traversal — good defense-in-depth for security.
186-198: LGTM!The
Executefunction correctly suppressesChildExitErrorfrom being printed to stderr (since its message "re-launched CLI exited with code N" is internal), while still returning the error somain.gocan extract and propagate the exit code.cli/internal/ui/ui.go (4)
52-64: LGTM!The
Optionsstruct clearly documents each mode, and the package-levelsessionTipsSeenensures tip deduplication is shared across all UI instances (stdout/stderr) within a CLI invocation.
93-123: LGTM!The
NewUIWithOptionsconstructor correctly:
- Uses
termenv.Asciiprofile whenNoColororPlainto disable ANSI styling- Defaults
hintsto"auto"if unset- Sets
quietto true when eitheropts.Quietoropts.JSONis set, ensuring JSON mode suppresses human-oriented output
232-247: LGTM!The
HintTipimplementation correctly usessync.Map.LoadOrStorefor thread-safe session-wide deduplication in"auto"mode, and respects the"never"mode to suppress tips entirely.
373-381: LGTM!The
JSONOutputmethod usesMarshalIndentfor human-readable JSON and correctly propagates marshaling errors to the caller.
…y, wipe --yes, JSON mode - Make TestShouldPromptDefault deterministic by detecting stdin TTY state and asserting accordingly instead of a no-op - Use ctx parameter instead of cmd.Context() in pullAndPersist for consistency with function signature - Make resolveUpdateChannel accept ctx and use GlobalOpts.DataDir instead of calling resolveDataDir directly (GlobalOpts IS available) - Wire --yes through all 7 wipe prompt helpers via wipeContext.shouldPrompt: confirmWipe, promptStartForBackup, promptForBackup, promptSavePath, checkOverwrite, askContinueWithoutBackup, promptStartAfterWipe - Suppress Success/Warn/Error output in JSON mode to prevent human text leaking into JSON stdout stream Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
cli/cmd/update.go (2)
151-182:⚠️ Potential issue | 🟠 Major
updatestill bypasses the global output modes.This path, plus several helpers in the same file, still writes directly with
fmt.Fprint*instead of going throughui.NewUIWithOptions(...). That meanssynthorg update --jsonstill emits human text like “Checking for updates...”, and-qstill prints status chatter. Please either thread UI objects through the rest of this command or explicitly reject--jsonhere.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cli/cmd/update.go` around lines 151 - 182, The update command currently writes directly to stdout/stderr with fmt.Fprint* and ignores global UI modes; replace those calls by constructing a UI via ui.NewUIWithOptions using cmd.OutOrStdout()/cmd.ErrOrStderr() and the command context/flags (JSON/quiet modes) and then use the UI methods (e.g., ui.Info/ ui.Warn/ ui.Error/ ui.Printf) instead of fmt.Fprintln/Fprintf in this function and its helpers (resolveUpdateChannel, isDevChannelMismatch reporting, and calls around selfupdate.CheckForChannel and downloadAndApplyCLI), or alternatively explicitly detect and reject --json/quiet usage up front; ensure all user-visible writes in update.go go through the UI instance rather than fmt.* so --json and -q behave correctly.
501-515:⚠️ Potential issue | 🟠 MajorDon't turn
--yesinto “skip restart”.
confirmRestart()defaults to yes, but this branch returnsfalsewheneverShouldPrompt()is false. SinceShouldPrompt()is also false for an explicit--yes,synthorg update --yeswill leave already-running containers on the old revision instead of taking the default-yes restart path thatcli/cmd/root.go:46-58promises for “assume yes for all prompts”.Proposed fix
- if !GetGlobalOpts(ctx).ShouldPrompt() { + opts := GetGlobalOpts(ctx) + if opts.Yes { + return performRestart(ctx, out, info, safeDir, state, opts.UIOptions()) + } + if !opts.ShouldPrompt() { _, _ = fmt.Fprintln(out, "Non-interactive mode: skipping restart. Run 'synthorg stop && synthorg start' to apply new images.") return false, nil } @@ - opts := GetGlobalOpts(cmd.Context()) return performRestart(ctx, out, info, safeDir, state, opts.UIOptions())🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cli/cmd/update.go` around lines 501 - 515, The current branch treats any non-prompting context as "skip restart", which incorrectly makes --yes skip restart; instead fetch the global options once (opts := GetGlobalOpts(ctx)) and, when opts.ShouldPrompt() is false, check opts.AssumeYes() (or the equivalent flag that represents --yes) — if AssumeYes is true, proceed to call confirmRestart/performRestart as the default-yes path, otherwise keep the existing non-interactive message and return; update the code around GetGlobalOpts/ShouldPrompt/confirmRestart/performRestart accordingly so explicit --yes triggers the restart.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@cli/internal/ui/ui.go`:
- Around line 181-197: Success and Warn currently only suppress output when
u.jsonMode is true, so --quiet/-q still prints; update UI.Success and UI.Warn to
also short-circuit when u.quiet is true (check u.quiet || u.jsonMode) before
calling u.printLine; locate methods Success and Warn on type UI (and verify
NewUIWithOptions populates u.quiet) and return early when quiet is enabled.
---
Outside diff comments:
In `@cli/cmd/update.go`:
- Around line 151-182: The update command currently writes directly to
stdout/stderr with fmt.Fprint* and ignores global UI modes; replace those calls
by constructing a UI via ui.NewUIWithOptions using
cmd.OutOrStdout()/cmd.ErrOrStderr() and the command context/flags (JSON/quiet
modes) and then use the UI methods (e.g., ui.Info/ ui.Warn/ ui.Error/ ui.Printf)
instead of fmt.Fprintln/Fprintf in this function and its helpers
(resolveUpdateChannel, isDevChannelMismatch reporting, and calls around
selfupdate.CheckForChannel and downloadAndApplyCLI), or alternatively explicitly
detect and reject --json/quiet usage up front; ensure all user-visible writes in
update.go go through the UI instance rather than fmt.* so --json and -q behave
correctly.
- Around line 501-515: The current branch treats any non-prompting context as
"skip restart", which incorrectly makes --yes skip restart; instead fetch the
global options once (opts := GetGlobalOpts(ctx)) and, when opts.ShouldPrompt()
is false, check opts.AssumeYes() (or the equivalent flag that represents --yes)
— if AssumeYes is true, proceed to call confirmRestart/performRestart as the
default-yes path, otherwise keep the existing non-interactive message and
return; update the code around
GetGlobalOpts/ShouldPrompt/confirmRestart/performRestart accordingly so explicit
--yes triggers the restart.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 13bdee03-e1be-47bd-aa3c-596d885297a3
📒 Files selected for processing (4)
cli/cmd/global_opts_test.gocli/cmd/update.gocli/cmd/wipe.gocli/internal/ui/ui.go
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
cli/**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
Go CLI: golangci-lint + go vet checked in pre-commit hooks and CI (conditional on cli/**/*.go changes)
Files:
cli/cmd/global_opts_test.gocli/cmd/wipe.gocli/cmd/update.gocli/internal/ui/ui.go
🧠 Learnings (13)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Applies to cli/**/*.go : Use Cobra for CLI command structure, charmbracelet/huh for interactive prompts, and charmbracelet/lipgloss for terminal styling
📚 Learning: 2026-03-27T17:07:16.441Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T17:07:16.441Z
Learning: Applies to cli/**/*_fuzz_test.go : Go CLI uses native 'testing.F' fuzz functions (FuzzYamlStr, etc.)
Applied to files:
cli/cmd/global_opts_test.go
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: Applies to cli/**/*.go : Use native Go testing with `testing.F` fuzz functions (`Fuzz*`) for fuzz testing.
Applied to files:
cli/cmd/global_opts_test.go
📚 Learning: 2026-03-21T12:54:22.557Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Applies to cli/**/*.go : Use native Go `testing.F` fuzz functions (`Fuzz*`) for property-based testing
Applied to files:
cli/cmd/global_opts_test.go
📚 Learning: 2026-03-19T11:30:29.217Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:30:29.217Z
Learning: Applies to cli/**/*.go : Use native `testing.F` fuzz functions (`Fuzz*`) for fuzz testing Go code
Applied to files:
cli/cmd/global_opts_test.go
📚 Learning: 2026-03-21T14:12:17.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T14:12:17.848Z
Learning: Applies to cli/**/*.go : Use native `testing.F` fuzz functions (`Fuzz*`) for fuzzing
Applied to files:
cli/cmd/global_opts_test.go
📚 Learning: 2026-03-19T11:30:29.217Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:30:29.217Z
Learning: Applies to cli/**/*.go : Run Go lint via `golangci-lint run`, vet via `go vet`, tests via `go test ./...`, and fuzz via `go test -fuzz=FuzzTarget -fuzztime=30s`
Applied to files:
cli/cmd/global_opts_test.go
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).
Applied to files:
cli/cmd/global_opts_test.gocli/cmd/update.gocli/internal/ui/ui.go
📚 Learning: 2026-03-27T17:07:16.441Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T17:07:16.441Z
Learning: Applies to cli/**/*.go : Go CLI: golangci-lint + go vet checked in pre-commit hooks and CI (conditional on cli/**/*.go changes)
Applied to files:
cli/cmd/global_opts_test.go
📚 Learning: 2026-03-16T19:52:03.656Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-16T19:52:03.656Z
Learning: Applies to cli/**/*.go : Lint CLI Go code with golangci-lint and go vet; test with go test -race; check vulnerabilities with govulncheck
Applied to files:
cli/cmd/global_opts_test.go
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.
Applied to files:
cli/cmd/global_opts_test.go
📚 Learning: 2026-03-15T21:32:02.880Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/go.mod : Go CLI dependencies: Go 1.26+, Cobra (commands), charmbracelet/huh (interactive CLI), charmbracelet/lipgloss (styled output).
Applied to files:
cli/internal/ui/ui.go
📚 Learning: 2026-03-21T12:54:22.557Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Applies to cli/**/*.go : Use Cobra for CLI command structure, charmbracelet/huh for interactive prompts, and charmbracelet/lipgloss for terminal styling
Applied to files:
cli/internal/ui/ui.go
🔇 Additional comments (1)
cli/cmd/global_opts_test.go (1)
90-104: Deterministic TTY assertion looks good.This now tracks the same runtime condition that
GlobalOpts.ShouldPrompt()uses, so the test no longer depends on a specific CI stdin setup.
…pt, update UI migration - Suppress Success and Warn in quiet mode (--quiet = errors only); Error remains visible. Update tests to match new semantics. - Fix --yes incorrectly skipping restart/cleanup/recovery: distinguish opts.Yes (auto-accept default) from non-interactive (skip) in restartIfRunning, confirmAndCleanup, and promptHealthRecover - Migrate updateCLI and downloadAndApplyCLI from raw fmt.Fprintln to UI methods so --quiet and --json modes are respected during updates Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@cli/internal/ui/ui_test.go`:
- Around line 597-638: The HintTip deduplication test relies on the
package-level sessionTipsSeen sync.Map, so make the test use unique messages per
run to avoid cross-test interference; update TestHintCategories to call HintTip
with a unique string (e.g., include t.Name() or another per-test identifier)
when asserting deduplication and when sending the "try this" and "different tip"
messages, so HintTip and sessionTipsSeen won’t collide across tests while
keeping the same assertions; locate usages in TestHintCategories and the HintTip
calls that interact with sessionTipsSeen and NewUIWithOptions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 43753490-7fb4-4c79-b4cc-83428a7dae79
📒 Files selected for processing (5)
cli/cmd/cleanup.gocli/cmd/update.gocli/cmd/update_health.gocli/internal/ui/ui.gocli/internal/ui/ui_test.go
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
cli/**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
Go CLI: golangci-lint + go vet checked in pre-commit hooks and CI (conditional on cli/**/*.go changes)
Files:
cli/cmd/cleanup.gocli/cmd/update_health.gocli/internal/ui/ui_test.gocli/internal/ui/ui.gocli/cmd/update.go
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Applies to cli/**/*.go : Use Cobra for CLI command structure, charmbracelet/huh for interactive prompts, and charmbracelet/lipgloss for terminal styling
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Go 1.26+ required; CLI dependencies in `cli/go.mod` (Cobra, charmbracelet/huh, charmbracelet/lipgloss, sigstore-go, go-containerregistry, go-tuf)
📚 Learning: 2026-03-15T18:17:43.675Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).
Applied to files:
cli/cmd/cleanup.gocli/cmd/update.go
📚 Learning: 2026-03-27T17:07:16.441Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T17:07:16.441Z
Learning: Applies to cli/**/*_fuzz_test.go : Go CLI uses native 'testing.F' fuzz functions (FuzzYamlStr, etc.)
Applied to files:
cli/internal/ui/ui_test.go
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: Applies to cli/**/*.go : Use native Go testing with `testing.F` fuzz functions (`Fuzz*`) for fuzz testing.
Applied to files:
cli/internal/ui/ui_test.go
📚 Learning: 2026-03-19T11:30:29.217Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:30:29.217Z
Learning: Applies to cli/**/*.go : Run Go lint via `golangci-lint run`, vet via `go vet`, tests via `go test ./...`, and fuzz via `go test -fuzz=FuzzTarget -fuzztime=30s`
Applied to files:
cli/internal/ui/ui_test.go
📚 Learning: 2026-03-21T12:54:22.557Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Applies to cli/**/*.go : Use Cobra for CLI command structure, charmbracelet/huh for interactive prompts, and charmbracelet/lipgloss for terminal styling
Applied to files:
cli/internal/ui/ui.go
🔇 Additional comments (20)
cli/cmd/update_health.go (2)
28-29: LGTM!The UI construction correctly uses
GetGlobalOptsandNewUIWithOptionsto respect global output modes (quiet/plain/json).
90-97: LGTM!The prompt gating logic correctly distinguishes between
--yes(auto-recover) and non-interactive mode without--yes(abort with guidance). WhenShouldPrompt()returns false:
- If
opts.Yesis true → auto-recover (user explicitly requested non-interactive acceptance)- Otherwise → print guidance and abort (piped/redirected input without explicit consent)
cli/cmd/cleanup.go (3)
30-38: LGTM!The migration to
GetGlobalOptsandNewUIWithOptionscorrectly threads global options through the cleanup command.
89-106: LGTM!The prompt gating logic correctly handles three scenarios:
- Non-interactive without
--yes→ print hint and exit without removal--yesflag set → auto-confirm removal (skip prompt)- Interactive without
--yes→ show confirmation formThe
&& !opts.Yescondition is necessary to distinguish explicit--yesfrom mere non-TTY input.
64-64: LGTM!The hint category updates are appropriate:
HintTipfor the auto-cleanup suggestion (one-time tip, deduplicated in auto mode)HintErrorfor skipped images (error-recovery context, always shown unless quiet)Also applies to: 140-140
cli/internal/ui/ui_test.go (3)
430-476: LGTM!Comprehensive test coverage for quiet mode behavior: verifies that non-essential output (Logo, Step, Section, KeyValue, hints, etc.) is suppressed while
ErrorandPlainremain visible. The assertion thatSuccessandWarnare suppressed aligns with the "errors only" contract for--quiet.
478-595: LGTM!Thorough plain mode tests verify ASCII-only rendering for icons, boxes, dividers, tables, logo, and icon accessors. The negative assertions (no Unicode characters) ensure the plain mode contract is enforced.
681-726: LGTM!Good coverage for spinner modes and JSON output:
- Quiet spinner produces no output on start or success
- Plain spinner uses ASCII icon and prints step message
- JSON output is properly indented with expected fields
cli/internal/ui/ui.go (5)
52-64: LGTM!The
Optionsstruct clearly documents the purpose of each mode. ThesessionTipsSeensync.Map provides thread-safe deduplication forHintTipmessages across all UI instances.
93-123: LGTM!
NewUIWithOptionscorrectly:
- Disables ANSI styling when
NoColororPlainis set viatermenv.Asciiprofile- Defaults hints to
"auto"when empty- Sets
quiettoopts.Quiet || opts.JSONto suppress non-essential output in both modes
181-207: LGTM!The quiet/JSON mode handling is correct:
SuccessandWarnreturn early whenu.quietis true (suppressed in both--quietand--jsonmodes)Errorreturns early only whenu.jsonModeis true (visible in--quietmode, suppressed in--jsonmode)This correctly implements "errors only" for
--quietand "no human output" for--json.
221-281: LGTM!The hint category system is well-designed:
Hint()deprecated with clear guidance to use category-specific methodsHintErrorandHintNextStepalways shown unless quiet (critical guidance)HintTipdeduplicated in "auto" mode, suppressed in "never" modeHintGuidanceonly shown in "always" mode (for verbose users)The
printHintshared implementation ensures consistent styling across all hint types.
386-394: LGTM!
JSONOutputcorrectly marshals data with 2-space indentation and writes to the UI writer. The error is properly propagated.cli/cmd/update.go (7)
49-49: LGTM!Using
GetGlobalOpts(cmd.Context()).DataDirprovides consistent data directory resolution through the global options infrastructure.
107-131: LGTM!
downloadAndApplyCLInow uses UI methods (Step,Success,HintNextStep) instead of rawfmt.Fprintf, ensuring output respects global modes (--quiet,--plain,--json).
188-193: LGTM!
resolveUpdateChannelnow correctly accepts context and usesGetGlobalOpts(ctx).DataDirfor consistent data directory resolution.
225-249: LGTM!The flag forwarding in
reexecUpdatecorrectly propagates all global output/behavior flags to the re-executed child process:
--data-dir,--skip-verify(existing)--quiet,-v(repeated for verbosity level),--no-color,--plain,--json,--yes(new)Using flag variables directly (
flagDataDir,flagVerbose, etc.) ensures consistency with the root command's persistent flag registration.
363-382: LGTM!The confirm functions correctly use
GetGlobalOpts(ctx).ShouldPrompt()to respect both--yesand non-TTY detection. ThedefaultValparameter allows callers to specify appropriate defaults for different confirmation contexts (e.g.,truefor standard updates,falsefor risky operations after user declined compose changes).
502-519: LGTM!The restart logic correctly distinguishes:
--yes→ auto-restart (line 504-506)- Non-interactive without
--yes→ skip with guidance (line 508-509)- Interactive → show confirmation prompt (line 512-518)
This matches the semantic pattern established in other commands.
447-447: LGTM!
GetGlobalOpts(ctx).SkipVerifyreplaces the local boolean for consistent global option accessHintErroris the appropriate category for the air-gapped environment hint (error recovery context)Also applies to: 466-466
…nterference sessionTipsSeen is package-level, so parallel tests sharing the same tip string would collide. Prefix tip messages with t.Name() to ensure each subtest has its own dedup namespace. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@cli/internal/ui/ui_test.go`:
- Around line 503-507: The negative Unicode-icon check is missing IconWarning
and is wrongly checking IconHint even though no Hint was invoked; update the
test loop to include IconWarning in the checked set and remove IconHint (or
alternatively call u.Hint("...") if you intended to test Hint), ensuring the
verification covers IconSuccess, IconError, IconInProgress and IconWarning to
match calls like u.Warn("hmm") and the actual methods used.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 89751394-ac74-4c89-bb08-60949fdcedef
📒 Files selected for processing (1)
cli/internal/ui/ui_test.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: CLI Test (windows-latest)
- GitHub Check: Dependency Review
- GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (1)
cli/**/*.go
📄 CodeRabbit inference engine (CLAUDE.md)
Go CLI: golangci-lint + go vet checked in pre-commit hooks and CI (conditional on cli/**/*.go changes)
Files:
cli/internal/ui/ui_test.go
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to .github/workflows/cli.yml : CLI workflow: Go lint (golangci-lint + go vet) + test (-race -coverprofile) + build (cross-compile: linux/darwin/windows × amd64/arm64) + govulncheck + fuzz testing (main-only, 30s/target, continue-on-error, matrix over 4 packages). cli-pass gate includes fuzz as informational. GoReleaser release on v* tags. Cosign keyless signing of checksums.txt. SLSA L3 provenance attestations. Sigstore bundle (.sigstore.json) attached. Post-release appends checksums/verification/provenance to draft release notes.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Applies to cli/**/*.go : Use Cobra for CLI command structure, charmbracelet/huh for interactive prompts, and charmbracelet/lipgloss for terminal styling
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T18:17:43.675Z
Learning: Applies to cli/** : CLI: Go 1.26+, dependencies in cli/go.mod (Cobra, charmbracelet/huh).
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T21:32:02.880Z
Learning: Applies to cli/**/*.go : Go CLI (Go 1.26+) uses Cobra for commands, charmbracelet/huh for interactive CLI, charmbracelet/lipgloss for styled output. Cross-platform builds (linux/darwin/windows × amd64/arm64). GoReleaser for releases with cosign keyless signing of checksums.txt. SLSA L3 provenance attestations via actions/attest-build-provenance.
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Go 1.26+ required; CLI dependencies in `cli/go.mod` (Cobra, charmbracelet/huh, charmbracelet/lipgloss, sigstore-go, go-containerregistry, go-tuf)
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T14:12:17.848Z
Learning: Applies to cli/go.mod : CLI uses Go 1.26+. Dependencies: Cobra, charmbracelet/huh, charmbracelet/lipgloss, sigstore-go, go-containerregistry, go-tuf
📚 Learning: 2026-03-27T17:07:16.441Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T17:07:16.441Z
Learning: Applies to cli/**/*_fuzz_test.go : Go CLI uses native 'testing.F' fuzz functions (FuzzYamlStr, etc.)
Applied to files:
cli/internal/ui/ui_test.go
📚 Learning: 2026-03-19T11:30:29.217Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:30:29.217Z
Learning: Applies to cli/**/*.go : Run Go lint via `golangci-lint run`, vet via `go vet`, tests via `go test ./...`, and fuzz via `go test -fuzz=FuzzTarget -fuzztime=30s`
Applied to files:
cli/internal/ui/ui_test.go
📚 Learning: 2026-03-19T11:19:40.044Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:19:40.044Z
Learning: Applies to cli/**/*.go : Use native Go testing with `testing.F` fuzz functions (`Fuzz*`) for fuzz testing.
Applied to files:
cli/internal/ui/ui_test.go
📚 Learning: 2026-03-21T12:54:22.557Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Applies to cli/**/*.go : Use native Go `testing.F` fuzz functions (`Fuzz*`) for property-based testing
Applied to files:
cli/internal/ui/ui_test.go
📚 Learning: 2026-03-21T14:12:17.848Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T14:12:17.848Z
Learning: Applies to cli/**/*.go : Use native `testing.F` fuzz functions (`Fuzz*`) for fuzzing
Applied to files:
cli/internal/ui/ui_test.go
📚 Learning: 2026-03-19T11:30:29.217Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-19T11:30:29.217Z
Learning: Applies to cli/**/*.go : Use native `testing.F` fuzz functions (`Fuzz*`) for fuzz testing Go code
Applied to files:
cli/internal/ui/ui_test.go
📚 Learning: 2026-03-27T17:07:16.441Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-27T17:07:16.441Z
Learning: Applies to cli/**/*.go : Go CLI: golangci-lint + go vet checked in pre-commit hooks and CI (conditional on cli/**/*.go changes)
Applied to files:
cli/internal/ui/ui_test.go
📚 Learning: 2026-03-21T12:54:22.557Z
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-21T12:54:22.557Z
Learning: Applies to cli/**/*.go : Use Cobra for CLI command structure, charmbracelet/huh for interactive prompts, and charmbracelet/lipgloss for terminal styling
Applied to files:
cli/internal/ui/ui_test.go
🔇 Additional comments (10)
cli/internal/ui/ui_test.go (10)
430-476: LGTM! Comprehensive quiet mode test with proper isolation.The test correctly validates that quiet mode suppresses non-essential output while preserving Error and Plain output. The use of
t.Name()for the HintTip message (line 443) properly addresses the test isolation concern for the session-level deduplication mechanism.
510-530: LGTM!The test properly validates ASCII-only box rendering in plain mode by checking for
+and|characters while ensuring Unicode box-drawing characters are absent.
532-545: LGTM!Correctly validates ASCII divider rendering in plain mode.
547-560: LGTM!Correctly validates plain mode table rendering without Unicode separators.
562-579: LGTM!Correctly validates plain text logo rendering with version string.
581-595: LGTM!Correctly validates that icon accessor methods return plain constants in plain mode.
597-680: LGTM! Comprehensive hint category testing with proper isolation.The test thoroughly validates hint visibility rules across all three modes (auto/always/never). The use of
t.Name()prefixes for tip messages (lines 617, 629, 660, 661) ensures proper test isolation when the package-levelsessionTipsSeenmap is shared across parallel tests.
682-694: LGTM!Correctly validates that spinner output is completely suppressed in quiet mode, including the success message.
696-709: LGTM!Correctly validates plain mode spinner uses ASCII icon and prints the step message.
711-727: LGTM!Correctly validates JSON output format with expected field structure. The check for
": "(colon-space) confirms pretty-printed/indented JSON output.
… test The test calls Warn() but the negative-check loop verified IconHint (never invoked) instead of IconWarning. Replace to match the actual methods under test. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
🤖 I have created a release *beep* *boop* --- #MAJOR CHANGES; We got a somewhat working webui :) ## [0.5.0](v0.4.9...v0.5.0) (2026-03-30) ### Features * add analytics trends and budget forecast API endpoints ([#798](#798)) ([16b61f5](16b61f5)) * add department policies to default templates ([#852](#852)) ([7a41548](7a41548)) * add remaining activity event types (task_started, tool_used, delegation, cost_incurred) ([#832](#832)) ([4252fac](4252fac)) * agent performance, activity, and history API endpoints ([#811](#811)) ([9b75c1d](9b75c1d)) * Agent Profiles and Detail pages (biography, career, performance) ([#874](#874)) ([62d7880](62d7880)) * app shell, Storybook, and CI/CD pipeline ([#819](#819)) ([d4dde90](d4dde90)) * Approvals page with risk grouping, urgency indicators, batch actions ([#889](#889)) ([4e9673d](4e9673d)) * Budget Panel page (P&L dashboard, breakdown charts, forecast) ([#890](#890)) ([b63b0f1](b63b0f1)) * build infrastructure layer (API client, auth, WebSocket) ([#815](#815)) ([9f01d3e](9f01d3e)) * CLI global options infrastructure, UI modes, exit codes, env vars ([#891](#891)) ([fef4fc5](fef4fc5)) * CodeMirror editor and theme preferences toggle ([#905](#905), [#807](#807)) ([#909](#909)) ([41fbedc](41fbedc)) * Company page (department/agent management) ([#888](#888)) ([cfb88b0](cfb88b0)) * comprehensive hint coverage across all CLI commands ([#900](#900)) ([937974e](937974e)) * config system extensions, per-command flags for init/start/stop/status/logs ([#895](#895)) ([32f83fe](32f83fe)) * configurable currency system replacing hardcoded USD ([#854](#854)) ([b372551](b372551)) * Dashboard page (metric cards, activity feed, budget burn) ([#861](#861)) ([7d519d5](7d519d5)) * department health, provider status, and activity feed endpoints ([#818](#818)) ([6d5f196](6d5f196)) * design tokens and core UI components ([#833](#833)) ([ed887f2](ed887f2)) * extend approval, meeting, and budget API responses ([#834](#834)) ([31472bf](31472bf)) * frontend polish -- real-time UX, accessibility, responsive, performance ([#790](#790), [#792](#792), [#791](#791), [#793](#793)) ([#917](#917)) ([f04a537](f04a537)) * implement human roles and access control levels ([#856](#856)) ([d6d8a06](d6d8a06)) * implement semantic conflict detection in workspace merge ([#860](#860)) ([d97283b](d97283b)) * interaction components and animation patterns ([#853](#853)) ([82d4b01](82d4b01)) * Login page + first-run bootstrap + Company page ([#789](#789), [#888](#888)) ([#896](#896)) ([8758e8d](8758e8d)) * Meetings page with timeline viz, token bars, contribution formatting ([#788](#788)) ([#904](#904)) ([b207f46](b207f46)) * Messages page with threading, channel badges, sender indicators ([#787](#787)) ([#903](#903)) ([28293ad](28293ad)) * Org Chart force-directed view and drag-drop reassignment ([#872](#872), [#873](#873)) ([#912](#912)) ([a68a938](a68a938)) * Org Chart page (living nodes, status, CRUD, department health) ([#870](#870)) ([0acbdae](0acbdae)) * per-command flags for remaining commands, auto-behavior wiring, help/discoverability ([#897](#897)) ([3f7afa2](3f7afa2)) * Providers page with backend rework -- health, CRUD, subscription auth ([#893](#893)) ([9f8dd98](9f8dd98)) * scaffold React + Vite + TypeScript + Tailwind project ([#799](#799)) ([bd151aa](bd151aa)) * Settings page with search, dependency indicators, grouped rendering ([#784](#784)) ([#902](#902)) ([a7b9870](a7b9870)) * Setup Wizard rebuild with template comparison, cost estimator, theme customization ([#879](#879)) ([ae8b50b](ae8b50b)) * setup wizard UX -- template filters, card metadata, provider form reuse ([#910](#910)) ([7f04676](7f04676)) * setup wizard UX overhaul -- mode choice, step reorder, provider fixes ([#907](#907)) ([ee964c4](ee964c4)) * structured ModelRequirement in template agent configs ([#795](#795)) ([7433548](7433548)) * Task Board page (rich Kanban, filtering, dependency viz) ([#871](#871)) ([04a19b0](04a19b0)) ### Bug Fixes * align frontend types with backend and debounce WS refetches ([#916](#916)) ([134c11b](134c11b)) * auto-cleanup targets newly pulled images instead of old ones ([#884](#884)) ([50e6591](50e6591)) * correct wipe backup-skip flow and harden error handling ([#808](#808)) ([c05860f](c05860f)) * improve provider setup in wizard, subscription auth, dashboard bugs ([#914](#914)) ([87bf8e6](87bf8e6)) * improve update channel detection and add config get command ([#814](#814)) ([6b137f0](6b137f0)) * resolve all ESLint warnings, add zero-warnings enforcement ([#899](#899)) ([079b46a](079b46a)) * subscription auth uses api_key, base URL optional for cloud providers ([#915](#915)) ([f0098dd](f0098dd)) ### Refactoring * semantic analyzer cleanup -- shared filtering, concurrency, extraction ([#908](#908)) ([81372bf](81372bf)) ### Documentation * brand identity and UX design system from [#765](#765) exploration ([#804](#804)) ([389a9f4](389a9f4)) * page structure and information architecture for v0.5.0 dashboard ([#809](#809)) ([f8d6d4a](f8d6d4a)) * write UX design guidelines with WCAG-verified color system ([#816](#816)) ([4a4594e](4a4594e)) ### Tests * add unit tests for agent hooks and page components ([#875](#875)) ([#901](#901)) ([1d81546](1d81546)) ### CI/CD * bump actions/deploy-pages from 4.0.5 to 5.0.0 in the major group ([#831](#831)) ([01c19de](01c19de)) * bump astral-sh/setup-uv from 7.6.0 to 8.0.0 in /.github/actions/setup-python-uv in the all group ([#920](#920)) ([5f6ba54](5f6ba54)) * bump codecov/codecov-action from 5.5.3 to 6.0.0 in the major group ([#868](#868)) ([f22a181](f22a181)) * bump github/codeql-action from 4.34.1 to 4.35.0 in the all group ([#883](#883)) ([87a4890](87a4890)) * bump sigstore/cosign-installer from 4.1.0 to 4.1.1 in the minor-and-patch group ([#830](#830)) ([7a69050](7a69050)) * bump the all group with 3 updates ([#923](#923)) ([ff27c8e](ff27c8e)) * bump wrangler from 4.76.0 to 4.77.0 in /.github in the minor-and-patch group ([#822](#822)) ([07d43eb](07d43eb)) * bump wrangler from 4.77.0 to 4.78.0 in /.github in the all group ([#882](#882)) ([f84118d](f84118d)) ### Maintenance * add design system enforcement hook and component inventory ([#846](#846)) ([15abc43](15abc43)) * add dev-only auth bypass for frontend testing ([#885](#885)) ([6cdcd8a](6cdcd8a)) * add pre-push rebase check hook ([#855](#855)) ([b637a04](b637a04)) * backend hardening -- eviction/size-caps and model validation ([#911](#911)) ([81253d9](81253d9)) * bump axios from 1.13.6 to 1.14.0 in /web in the all group across 1 directory ([#922](#922)) ([b1b0232](b1b0232)) * bump brace-expansion from 5.0.4 to 5.0.5 in /web ([#862](#862)) ([ba4a565](ba4a565)) * bump eslint-plugin-react-refresh from 0.4.26 to 0.5.2 in /web ([#801](#801)) ([7574bb5](7574bb5)) * bump faker from 40.11.0 to 40.11.1 in the minor-and-patch group ([#803](#803)) ([14d322e](14d322e)) * bump https://github.com/astral-sh/ruff-pre-commit from v0.15.7 to 0.15.8 ([#864](#864)) ([f52901e](f52901e)) * bump nginxinc/nginx-unprivileged from `6582a34` to `f99cc61` in /docker/web in the all group ([#919](#919)) ([df85e4f](df85e4f)) * bump nginxinc/nginx-unprivileged from `ccbac1a` to `6582a34` in /docker/web ([#800](#800)) ([f4e9450](f4e9450)) * bump node from `44bcbf4` to `71be405` in /docker/sandbox ([#827](#827)) ([91bec67](91bec67)) * bump node from `5209bca` to `cf38e1f` in /docker/web ([#863](#863)) ([66d6043](66d6043)) * bump picomatch in /site ([#842](#842)) ([5f20bcc](5f20bcc)) * bump recharts 2->3 and @types/node 22->25 in /web ([#802](#802)) ([a908800](a908800)) * Bump requests from 2.32.5 to 2.33.0 ([#843](#843)) ([41daf69](41daf69)) * bump smol-toml from 1.6.0 to 1.6.1 in /site ([#826](#826)) ([3e5dbe4](3e5dbe4)) * bump the all group with 3 updates ([#921](#921)) ([7bace0b](7bace0b)) * bump the minor-and-patch group across 1 directory with 2 updates ([#829](#829)) ([93e611f](93e611f)) * bump the minor-and-patch group across 1 directory with 3 updates ([#841](#841)) ([7010c8e](7010c8e)) * bump the minor-and-patch group across 1 directory with 3 updates ([#869](#869)) ([548cee5](548cee5)) * bump the minor-and-patch group in /site with 2 updates ([#865](#865)) ([9558101](9558101)) * bump the minor-and-patch group with 2 updates ([#867](#867)) ([4830706](4830706)) * consolidate Dependabot groups to 1 PR per ecosystem ([06d2556](06d2556)) * consolidate Dependabot groups to 1 PR per ecosystem ([#881](#881)) ([06d2556](06d2556)) * improve worktree skill with full dep sync and status enhancements ([#906](#906)) ([772c625](772c625)) * remove Vue remnants and document framework decision ([#851](#851)) ([bf2adf6](bf2adf6)) * update web dependencies and fix brace-expansion CVE ([#880](#880)) ([a7a0ed6](a7a0ed6)) * upgrade to Storybook 10 and TypeScript 6 ([#845](#845)) ([52d95f2](52d95f2)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Summary
GlobalOptsstruct threaded via Cobra context with 8 persistent flags:--quiet/-q,--verbose/-v(stackable),--no-color,--plain,--json,--yes/-y, plus existing--data-dirand--skip-verifyOptionsfor plain mode (ASCII-only icons, box-drawing, dividers), quiet mode (suppress non-essential output), and JSON modeHintError,HintNextStep,HintTip,HintGuidance) withalways/auto/nevercontrol -- migrate all 37 existingHint()callsExitErrortype with typed exit codes (0=success, 1=runtime, 2=usage, 3=unhealthy, 4=unreachable, 10=update-available)ChildExitErrorfrom update.go to exitcodes.goSYNTHORG_*env var constants withNO_COLOR/CLICOLOR/TERM=dumbstandard supportGetGlobalOpts/NewUIWithOptions--jsonflag from status command (now global)reexecUpdatefor CLI self-update re-execPR 1 of 3 for #886
Test plan
go -C cli build ./...-- builds cleango -C cli vet ./...-- no issuesgo -C cli tool golangci-lint run-- 0 issuesgo -C cli test ./...-- all passTestQuietModeSuppresses,TestPlainModeASCIIIcons,TestPlainModeBox,TestHintCategories(auto/always/never),TestSpinnerQuietMode,TestSpinnerPlainMode,TestJSONOutput,TestExitError,TestChildExitCode,TestGetGlobalOptsDefault,TestSetGetGlobalOpts,TestUIOptionsQuietImpliedByJSONsynthorg --quiet versionproduces no outputsynthorg --plain versionshows ASCII "SynthOrg" not Unicode logosynthorg --json versionproduces valid JSONPre-reviewed by 5 agents (go-reviewer, go-conventions, go-security, docs-consistency, issue-resolution), 16 findings addressed.
Part of #886
🤖 Generated with Claude Code