Repository navigation
fix: allow custom commands to merge into built-in namespaces at any level - #2191
Conversation
…at any level What changed: - Generalized collision detection in processCustomCommands to work at any nesting depth - Custom commands can now extend built-in command trees (e.g., mcp aws install alongside mcp start) - Built-in commands are preserved when custom commands collide; warning emitted if custom has conflicting steps - Removed topLevel bool parameter in favor of universal findSubcommand() check on parent - Extracted command creation logic into createCustomCommand() helper to reduce complexity Why: Custom commands in atmos.yaml silently failed when sharing a namespace with built-in commands. - Top-level collisions were detected but only at the top level (topLevel=true branch) - Non-top-level collisions had no detection; Cobra's AddCommand silently replaced built-in subcommands This prevented users from extending built-in namespaces with custom subcommands (e.g., mcp aws install). Tests added: - TestCustomCommand_NamespaceMerge_SubcommandsAdded: custom subcommands merge into built-in namespace - TestCustomCommand_NonTopLevelCollision_BuiltinPreserved: built-in subcommands preserved, not replaced - TestCustomCommand_DeepNesting_MergeWorks: merging works at arbitrary nesting depth All existing custom command tests pass. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Dependency Review✅ No vulnerabilities or license issues found.Scanned FilesNone |
📝 WalkthroughWalkthroughRefactors custom command processing: removes the topLevel parameter, centralizes command creation and flag validation into Changes
Sequence Diagram(s)sequenceDiagram
participant Config as AtmosConfig
participant Processor as processCustomCommands
participant Cobra as Cobra RootCmd
participant UI as ui.Writeln
participant Flags as pflag Registry
Config->>Processor: provide custom command definitions
Processor->>Cobra: findSubcommand(name) ?
alt subcommand exists
Processor->>UI: warn about step conflict (if any)
Processor->>Cobra: reuse existing subcommand (merge children)
else no existing
Processor->>Processor: createCustomCommand(config)
Processor->>Flags: validateCustomCommandFlags(config.flags)
Flags-->>Processor: validation result
Processor->>Cobra: registerCustomCommandFlags + add command
end
Processor->>Processor: recurse into nested command configs with parent cmd
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2191 +/- ##
==========================================
+ Coverage 77.38% 77.40% +0.02%
==========================================
Files 962 962
Lines 91239 91284 +45
==========================================
+ Hits 70601 70655 +54
+ Misses 16558 16548 -10
- Partials 4080 4081 +1
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
cmd/custom_command_collision_test.go (1)
130-132: Consider asserting the conflict warning path too.This test triggers the “custom steps ignored on collision” branch, but it currently validates only command behavior. Adding a stderr/UI warning assertion would lock in the full contract.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cmd/custom_command_collision_test.go` around lines 130 - 132, The test currently calls processCustomCommands(atmosConfig, atmosConfig.Commands, RootCmd) and only asserts no error; add an assertion that the collision warning UI/stderr was emitted by capturing the command output (or the test UI/stderr buffer used by RootCmd) and checking it contains the expected "custom steps ignored on collision" (or similar) warning text so the collision branch is verified; place this capture/assert immediately after the processCustomCommands call and keep the existing require.NoError assertion.cmd/cmd_utils.go (1)
519-522: Wrap required-flag registration failures with sentinel/context.At Line 521, returning raw
errloses structured context and diverges from project error-handling policy.As per coding guidelines: "Error Handling (MANDATORY): All errors MUST be wrapped using static errors defined in `errors/errors.go`."Proposed patch
if flag.Required { err := customCommand.MarkPersistentFlagRequired(flag.Name) if err != nil { - return nil, err + return nil, errUtils.Build(errUtils.ErrInvalidFlag). + WithCause(err). + WithExplanationf("Failed to mark flag '--%s' as required for custom command '%s'", flag.Name, commandConfig.Name). + WithContext("command", commandConfig.Name). + WithContext("flag", flag.Name). + Err() } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cmd/cmd_utils.go` around lines 519 - 522, Replace the raw return of err from customCommand.MarkPersistentFlagRequired(flag.Name) with a wrapped error using the static sentinel from errors/errors.go (e.g. errors.ErrRegisterFlag or the appropriate sentinel defined there), include the flag.Name and the original err as context, and use Go error wrapping (fmt.Errorf("%w: ...", sentinel, err) or equivalent) so callers receive the sentinel plus original detail; also add any required imports (fmt and the errors package) and update the return to return nil, wrappedErr instead of nil, err.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@cmd/cmd_utils.go`:
- Around line 95-99: The format string passed to ui.Warningf (in the block
referencing commandConfig.Name and existing.CommandPath()) includes a trailing
"\n" which produces an extra blank line; remove the explicit newline from the
format string so ui.Warningf's built-in newline is used instead and the warning
prints with a single line.
---
Nitpick comments:
In `@cmd/cmd_utils.go`:
- Around line 519-522: Replace the raw return of err from
customCommand.MarkPersistentFlagRequired(flag.Name) with a wrapped error using
the static sentinel from errors/errors.go (e.g. errors.ErrRegisterFlag or the
appropriate sentinel defined there), include the flag.Name and the original err
as context, and use Go error wrapping (fmt.Errorf("%w: ...", sentinel, err) or
equivalent) so callers receive the sentinel plus original detail; also add any
required imports (fmt and the errors package) and update the return to return
nil, wrappedErr instead of nil, err.
In `@cmd/custom_command_collision_test.go`:
- Around line 130-132: The test currently calls
processCustomCommands(atmosConfig, atmosConfig.Commands, RootCmd) and only
asserts no error; add an assertion that the collision warning UI/stderr was
emitted by capturing the command output (or the test UI/stderr buffer used by
RootCmd) and checking it contains the expected "custom steps ignored on
collision" (or similar) warning text so the collision branch is verified; place
this capture/assert immediately after the processCustomCommands call and keep
the existing require.NoError assertion.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 9a91a132-1168-4ec3-9091-a486f37c22a2
📒 Files selected for processing (6)
cmd/cmd_utils.gocmd/custom_command_collision_test.gocmd/custom_command_flag_conflict_test.gocmd/custom_command_identity_test.gocmd/custom_command_integration_test.gocmd/root.go
…and code - Remove trailing \n from Warningf format string (ui.Warningf already appends newline) - Pass atmosConfig by pointer to avoid copying 7KB struct (gocritic hugeParam) - Pass schema.CommandFlag by pointer in all helpers (gocritic hugeParam) - Extract flag validation into validateCustomCommandFlags/validateFlag helpers (gocognit) - Extract flag registration into registerCustomCommandFlags/registerFlag helpers (nestif) Co-Authored-By: Claude Haiku 4.5 <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 `@cmd/cmd_utils.go`:
- Around line 462-566: The shorthand validation must enforce that
flag.Shorthand, when non-empty, is exactly one rune to avoid pflag panics;
update validateFlagShorthand to check len([]rune(flag.Shorthand)) == 1 and if
not return a structured error (similar style to existing errors) indicating
invalid shorthand for the command (include cmdName, shorthand, and config path
"commands.<cmdName>.flags"), so invalid shorthands are caught at parse time
before registerBoolFlag/registerStringFlag call sites that call BoolP/StringP.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: c54d35d5-ed78-492f-bebb-119435dce5e7
📒 Files selected for processing (1)
cmd/cmd_utils.go
pflag panics when BoolP/StringP receives a shorthand longer than one character. Add validation in validateFlagShorthand to catch this at config parsing time and return a structured error instead. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
cmd/cmd_utils.go (1)
91-116: Clean refactor for namespace merging.The collision detection now works at any nesting depth. The warning for conflicting steps is helpful.
One consideration: when a custom command collides with an existing command, flags from the custom config are silently ignored while only steps trigger a warning. Consider warning about ignored flags too if any are defined.
Optional: Warn about ignored flags on collision
existing := findSubcommand(parentCommand, commandConfig.Name) if existing != nil { if len(commandConfig.Steps) > 0 { ui.Warningf( "Custom command %q defines steps that conflict with built-in command %q; "+ "built-in behavior preserved, custom steps ignored", commandConfig.Name, existing.CommandPath(), ) } + if len(commandConfig.Flags) > 0 { + ui.Warningf( + "Custom command %q defines flags that conflict with built-in command %q; "+ + "built-in behavior preserved, custom flags ignored", + commandConfig.Name, existing.CommandPath(), + ) + } command = existing🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@cmd/cmd_utils.go` around lines 91 - 116, When a custom command collides with an existing command (detected by findSubcommand returning non-nil), we currently warn only if commandConfig.Steps is non-empty; extend this to also warn when commandConfig.Flags (or any flag-like field) is non-empty so custom flags aren’t silently ignored. Update the collision branch that uses existing := findSubcommand(parentCommand, commandConfig.Name) to inspect commandConfig.Flags (and commandConfig.Args/options if applicable) and call ui.Warningf with a clear message referencing commandConfig.Name and existing.CommandPath() (similar style to the steps warning) whenever flags are present; leave reuse of existing and subsequent calls to processCustomCommands/createCustomCommand unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@cmd/cmd_utils.go`:
- Around line 91-116: When a custom command collides with an existing command
(detected by findSubcommand returning non-nil), we currently warn only if
commandConfig.Steps is non-empty; extend this to also warn when
commandConfig.Flags (or any flag-like field) is non-empty so custom flags aren’t
silently ignored. Update the collision branch that uses existing :=
findSubcommand(parentCommand, commandConfig.Name) to inspect commandConfig.Flags
(and commandConfig.Args/options if applicable) and call ui.Warningf with a clear
message referencing commandConfig.Name and existing.CommandPath() (similar style
to the steps warning) whenever flags are present; leave reuse of existing and
subsequent calls to processCustomCommands/createCustomCommand unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: a3c077ba-9b8d-4378-9f96-1ed70d507dfd
📒 Files selected for processing (1)
cmd/cmd_utils.go
|
These changes were released in v1.210.0-rc.0. |
|
These changes were released in v1.210.0-test.25. |
…de claims Add docs/prd/custom-command-builtin-override.md specifying how a step-based custom command can override a user-facing built-in (opt-in `override: true`) and call the native built-in via an `invoke: built-in` step modifier on `type: atmos` steps — cycle-proof by invoking the retained handler in-process (no ATMOS_REEXEC_DEPTH counter). Correct command-registry-pattern.md (Scenario 1 / Why This Works / FAQ) to reflect shipped behavior since #2191 (built-in preserved, custom steps ignored on collision) and document `invoke:` on the atmos step in workflow-step-types.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…EV-2969) (#1899) * feat: Implement workflow step types with registry pattern (DEV-263, DEV-2969) Add 20+ step types across 4 categories (Interactive, Output, UI, Command) with extensible registry pattern. Supports Go template variable passing between steps and per-step output modes (viewport, raw, log, none) for flexible result display. Key features: - StepHandler interface with auto-registration via init() - Variables struct supporting Go template resolution of step outputs - Interactive handlers (input, confirm, choose, filter, file, write) with TTY detection - UI message handlers (success, info, warn, error, markdown) - Output handlers (spin, table, pager, format, join, style) - Command handlers (atmos, shell) with output mode support - OutputModeWriter for viewport paging, raw passthrough, grouped logging, or silent modes - Full test coverage for registry, variables, handlers, and output modes - Schema extensions for new step fields (prompt, options, content, viewport config, env vars) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * feat: Add input type and workflow step types with complete TUI support (DEV-263, DEV-2969) - Implement workflow step registry pattern for extensible step types - Add style step (renamed from box) with configurable borders, padding, margin, width, alignment, text decorations - Add markdown field to style step for rendering markdown within styled containers with width-aware rendering - Add log step with structured logging support (level, fields) using atmos logger - Add linebreak step for spacing with configurable count - Add pager step displaying file content with scrolling and search - Add DefaultThemeName constant to theme package for proper theme management - Implement width-aware markdown rendering in style step using glamour - Pre-populate Variables with OS environment variables for template access via {{ .env.USER }} - Add comprehensive demo workflow showing all step types with real-world deployment scenario - Update schema to support new step configurations and input type - Add complete documentation for workflow step types and usage - Implement CategoryUI for display-only steps vs CategoryOutput for output-producing steps 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * refactor: Consolidate success/info/warn/error steps into unified toast step type Replace individual success, info, warn, and error step types with a single toast step type that uses a level field to specify the message style. This reduces code duplication and simplifies the step registry. Usage: - type: toast level: success # success, info, warning, error (default: info) content: "Deployment complete!" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Render markdown in pager step for .md files The pager step now automatically renders markdown content when: - The `markdown: true` flag is explicitly set - The file has a .md or .markdown extension (auto-detected) This ensures README.md and other markdown files display properly with styled headings, links, code blocks, etc. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: Address CodeRabbit review feedback for workflow steps - Add performance tracking to all workflow step handlers (AtmosHandler, FilterHandler, InputHandler, MarkdownHandler, ShellHandler, StyleHandler, SpinHandler) - Remove dead code in containsStackFlag function - Fix SpinHandler to use prepared environment from Variables.Env instead of os.Environ() - Update executor to use static ErrWorkflowStepFailed error - Update tests to use errors.Is() instead of string matching - Add comprehensive test coverage for RunAll function - Fix pager resolveTitle to use resolved path for template paths 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: Add separator field to join step and complete step type documentation - Add separator field to WorkflowStep schema for join step type - Update join handler to use configurable separator (default: newline) - Add missing documentation for pager, format, style, linebreak, log steps - Fix join step docs to show correct options field usage - Update PRD with correct join step example - Fix blog post step count ("18 interactive" → "18") - Add tests for join separator functionality 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: Add alert, title, clear, env, and exit workflow step types Add five new workflow step types that expose existing atmos terminal/UI capabilities: - alert: Plays terminal bell to notify user (uses terminal.Alert()) - title: Sets/restores terminal window title (uses terminal.SetTitle()) - clear: Clears current terminal line (uses ui.ClearLine()) - env: Sets environment variables for subsequent steps - exit: Exits workflow with specific exit code (returns error with code) The exit step returns an ErrWorkflowExit error with an exit code attached via WithExitCode(), following the pattern established in the avoiding-deep-exits-pattern.md PRD. This increases the total step count from 18 to 23, organized across five categories: Command, Interactive, UI Messages, Output, and Terminal. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Update workflow error snapshots to use correct explanation/hint separation Regenerate golden snapshots to reflect the correct semantic separation: - Explanation section: "The following command failed to execute" (what happened) - Hints section: "To resume the workflow" with 💡 prefix (what to do) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: Add show configuration, sleep, stage step types for workflows Add automatic workflow formatting with show configuration: - header: Display workflow description as styled markdown header - flags: Show command-line flags (stack, identity, etc.) - count: Show step count prefix [1/5] with step name in muted style - progress: Show progress bar (TTY only) - command: Show command before execution Add new step types: - sleep: Pause execution for specified duration (for demos) - stage: Display position among stage steps only [Stage 1/3] Integrate show features into legacy workflow executor with ShowRenderer for header/flags and ProgressRenderer for progress bar. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Correct progress bar rendering to clear line before step output - Change RenderWithLabel to render without newline for in-place display - Add RenderPermanent method to render with newline as permanent record - Clear progress line before step execution, then re-render as permanent - Ensures progress line appears as header with step output below it 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: Add workflow step test coverage improvement plan Add comprehensive PRD for increasing pkg/workflow/step/ test coverage from 26.3% to 80%+. The plan identifies critical files (output_mode.go, shell.go, atmos.go) and outlines a 4-phase approach focusing on Execute() method testing across all step handlers. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test: Increase pkg/workflow/step test coverage to 77% Add comprehensive tests for workflow step handlers: - Add Execute() tests for UI handlers (alert, clear, env, linebreak, etc.) - Add Execute() tests for output handlers (format, join, style, table, etc.) - Add helper method tests for interactive handlers (choose, filter, input, file) - Add shell handler execution tests with real commands - Add atmos handler helper method tests - Add output mode execution tests - Add registry tests for handler registration and lookup - Fix errorlint issues in config/load.go (use errors.As instead of type switch) Coverage improved from 26.3% to 77.3%. Remaining uncovered code is in TTY-dependent interactive handlers and external dependency code. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: Fix NOTICE file license URLs Update license URLs to correct paths: - aws-sdk-go-v2/internal/endpoints: Remove extra v2/ in path - googleapis/gax-go: Remove v2/ subdirectory from path 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * [autofix.ci] apply automated fixes * fix: Address CodeRabbit review comments - Add trailing punctuation to README.md list item - Clarify misleading conditional execution comment in interactive.yaml - Add perf.Track to ToastHandler.Execute per coding guidelines 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * fix: Make file_test.go cross-platform for Windows Use t.TempDir() instead of hardcoded /tmp paths that don't exist on Windows. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: Update roadmap with detailed workflow step types Expand workflow milestones to list all step types introduced in PR #1899: - Output step types: toast, alert, title, clear, linebreak, markdown, style, table, format, join, pager, spin - Interactive step types: input, confirm, choose, filter, file, write - Flow control: sleep, stage, exit, env, show Update quarter to q4-2025 and add PR reference. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Address CodeRabbit review comments for workflow execution - Move RenderHeaderIfNeeded call outside the step loop - Add perf.Track to public functions in step/executor.go - Add perf.Track to public functions in step/output_mode.go - Replace direct os.Stdout/Stderr with I/O context abstraction 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Add perf.Track to remaining public functions - Add perf.Track to NewStepExecutorWithVars - Add perf.Track to StepExecutor.RunAll - Add perf.Track to OutputModeWriter.Execute - Add perf.Track to RenderCommand 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: Move step handlers to pkg/runner for unified execution This commit integrates workflow step handlers into the unified pkg/runner package, enabling both workflows AND custom commands to use extended step types (input, choose, confirm, markdown, etc.). Key changes: - Move all 65+ step handler files from pkg/workflow/step/ to pkg/runner/step/ - Extend schema.Task with all interactive/UI step fields - Add step handler registry lookup in pkg/runner.Run() - Update custom commands to support extended step types - Add perf.Track to all public step handler functions - Update imports in workflow executor and related files This enables a unified experience where custom commands defined in atmos.yaml can now use interactive step types like: steps: - type: input prompt: "Enter your name" name: user_name - type: confirm prompt: "Deploy to production?" name: confirmed 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: Add step types partial for workflows and custom commands - Create reusable _step-types.mdx partial with all 25+ step types documentation - Update workflows.mdx to import partial instead of inline content - Add "Extended Step Types" section to custom commands docs - Add examples showing interactive deployment wizards in custom commands - Both workflows and custom commands now share the same step types reference This ensures consistent documentation across both features and reduces duplication. Custom commands can now use input, choose, confirm, and all other extended step types just like workflows. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Address CodeRabbit and security scanning review comments - choose.go: Fix Option.Selected() return value assignment The huh.Option.Selected() method returns a new Option rather than modifying in place, so the return value must be assigned back to the slice for the default selection to take effect. - log.go: Guard against integer overflow in slice capacity Add bounds check before computing len(step.Fields)*2 to prevent potential overflow for extremely large field maps. - spin.go: Guard against integer overflow in slice capacity Add bounds check before computing len(vars.Env)+len(step.Env) to prevent potential overflow for extremely large environment maps. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: Add blog post and update roadmap for custom commands step types - Add blog post announcing custom commands now support 25+ interactive step types - Update roadmap milestone with correct quarter, docs link, changelog, and PR reference - Include practical examples for deploy-wizard, multi-select, and input collection 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: Remove duplicate blog post and update roadmap changelog refs - Remove 2025-12-20-interactive-workflow-steps.mdx (superseded by 2026-01-03-custom-commands-step-types.mdx which covers both workflows and custom commands) - Add changelog references to workflow milestones in roadmap 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Apply Copilot suggestions for overflow protection - log.go: Check fieldsLen >= maxCapacity/2 before multiplication - spin.go: Extract safeEnvCapacity helper to clamp values before adding, reducing cyclomatic complexity while ensuring sum can't overflow 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Use min() for cleaner overflow protection Using Go's builtin min() makes the overflow protection clearer and more analyzable by static analysis tools like CodeQL. - log.go: fieldsLen := min(len(step.Fields), maxCapacity/2) - spin.go: Use min() to clamp both inputs before addition 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Make SpinHandler tests platform-aware for Windows compatibility Tests in spin_test.go used Unix-specific commands (pwd, echo $VAR) that fail on Windows. Added platform-specific helper functions that use appropriate commands for each platform: - pwd -> cd on Windows - echo $VAR -> echo %VAR% on Windows - /tmp -> C:\Windows\Temp on Windows 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Add overflow protection to PrepareEnvironment map allocation CodeQL flagged that len(environ)+6 could overflow on 32-bit systems. Applied the same min() clamping pattern used in other overflow fixes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Address CodeQL overflow alert and CodeRabbit refactor suggestion 1. Simplified overflow protection in env.go to avoid any arithmetic that CodeQL might flag - just clamp environLen directly without addition. 2. Removed duplicate containsStr function from spin_test.go and use strings.Contains from stdlib instead (CodeRabbit suggestion). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Use explicit if-guard for CodeQL overflow detection in log.go CodeQL couldn't infer that min(x, maxCapacity/2) * 2 is safe because it doesn't trace the relationship between clamped values and subsequent multiplication. Changed to an explicit if-guard pattern that CodeQL recognizes: if fieldsLen > maxFields { fieldsLen = maxFields } This pattern is explicitly documented in CodeQL's recommendation for guarding against allocation size overflow. Fixes: https://github.com/cloudposse/atmos/security/code-scanning/5211 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Extract safeKeyvalsCapacity helper for CodeQL overflow detection CodeQL couldn't trace that an if-guard on fieldsLen bounds the subsequent multiplication. Moving the guarded multiplication into a helper function with an explicit if-guard pattern allows CodeQL to recognize the safety: if fieldsLen > maxCapacity/2 { return maxCapacity } return fieldsLen * 2 This pattern explicitly shows that fieldsLen*2 only executes when fieldsLen <= maxCapacity/2, which CodeQL can verify is safe. Fixes: https://github.com/cloudposse/atmos/security/code-scanning/5211 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: Rename demo-interactive-workflows to interactive-workflows - Rename examples/demo-interactive-workflows to examples/interactive-workflows - Add EmbedExample for interactive-workflows to workflow documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: Add custom-commands example with interactive and advanced commands - Rename demo-custom-command to custom-commands - Add .atmos.d/interactive.yaml with interactive step types (choose, confirm, input, etc.) - Add .atmos.d/advanced.yaml with boolean flags, env vars, and working directory examples - Update README.md with comprehensive documentation - Add EmbedExample component to commands.mdx documentation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: Update file-browser plugin for renamed examples - Rename demo-custom-command to custom-commands in TAGS_MAP and DOCS_MAP - Add interactive-workflows mapping (renamed from demo-interactive-workflows) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Update test paths for renamed custom-commands example directory The examples/demo-custom-command directory was renamed to examples/custom-commands but test files were not updated, causing CI failures on all platforms. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: Address CodeRabbit review feedback - Reuse single StepExecutor across custom command steps for variable persistence - Fix directory path in interactive-workflows README - Move header rendering before step loop in workflow_utils.go - Wrap confirmation errors with static ErrWorkflowStepFailed sentinel - Fix multi-select limit to allow unlimited when Multiple=true and Limit<=0 - Wrap format.go errors with static error sentinels - Validate stdin TTY (not just stdout) for interactive steps - Use static error sentinels for template resolution failures - Wrap join.go errors with static error sentinels - Assert actual log level values in log_test.go - Implement per-line prefixing in StreamingOutputWriter - Wrap sleep.go duration/context errors with static sentinels - Surface invalid timeout values instead of silently ignoring - Wrap style.go errors with static error sentinels - Update spacing docs to include 3-value form - Make LoadOSEnv test portable with t.Setenv Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes (attempt 3/3) * [autofix.ci] apply automated fixes * fix: Address CodeRabbit review comments for workflow execution - Propagate working_directory to extended steps so handlers like spin run from the correct directory - Always print step labels when progress is disabled, not just when show.count is true - Fall back to log output when viewport commands fail to ensure diagnostic output is visible Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: Add viewport dimension constraints to pager Allow the pager to respect configurable max height/width instead of always using full terminal dimensions. This enables workflow viewport settings to control the pager display area. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style: apply gofumpt formatting to pkg/pager Fixes the go-fumpt pre-commit CI hook, which reformatted pager.go and model.go and failed because the committed source was not gofumpt-canonical. Extract the note-width max() into a variable so the //nolint:gosec directive stays on the uint() conversion line after gofumpt reflows the call, keeping both gofumpt and golangci-lint (gosec/nolintlint) happy. Formatting-only change, no behavior impact. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(prd): add built-in command override design; correct stale override claims Add docs/prd/custom-command-builtin-override.md specifying how a step-based custom command can override a user-facing built-in (opt-in `override: true`) and call the native built-in via an `invoke: built-in` step modifier on `type: atmos` steps — cycle-proof by invoking the retained handler in-process (no ATMOS_REEXEC_DEPTH counter). Correct command-registry-pattern.md (Scenario 1 / Why This Works / FAQ) to reflect shipped behavior since #2191 (built-in preserved, custom steps ignored on collision) and document `invoke:` on the atmos step in workflow-step-types.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(prd): clarify nested-collision and invoke schema; add step Execute tests Address CodeRabbit feedback on PR #1899: - command-registry-pattern.md: split the nested custom-command bullet to call out the name-collision case (findSubcommand reuses the existing command and ignores custom steps with a warning at every level, not just top-level). - workflow-step-types.md: add the `invoke` field to the WorkflowStep schema block for consistency with the atmos step reference. Increase pkg/runner/step coverage 78.9% -> 82.3% with hang-safe Execute tests: - spin: full Execute orchestration (non-TTY runs the command directly). - input/confirm/choose/write/filter/file: fail-fast Execute contract. - pager: Execute error paths before the pager launches. - atmos: Execute resolution errors before re-exec. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(workflow): raise step-type patch coverage above 80% Add unit tests for the new workflow step-type subsystem to clear the Codecov patch target (was 73.94%, target 80%). - pkg/workflow/progress_test.go: inject a fake terminal.Terminal to cover formatProgressLine, renderers, Done/IsEnabled, and nil/disabled guards (8.6% -> ~100%). - pkg/workflow/show_renderer_test.go: cover formatHeader, formatFlags (sort + styled/nil branches), and RenderHeaderIfNeeded paths (17% -> 100%). - pkg/runner/step/interactive_execute_test.go: assert each interactive Execute returns ErrStepTTYRequired under go test (no TTY), covering the CheckTTY guard for confirm/write/input/choose/filter/file. - pkg/runner/step/testmain_test.go + atmos_test.go: a sentinel-gated TestMain lets the test binary impersonate atmos so Execute, runAtmosCommand, and ExecuteWithWorkflow are tested cross-platform (0% -> ~85%). Package coverage: pkg/workflow 76.5% -> 96.9%, pkg/runner/step 78.9% -> 82.3%. No production code changed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * updates * test: skip interactive Execute TTY test when stdin/stdout are TTYs Address CodeRabbit feedback on PR #1899: TestInteractiveHandlers_ExecuteWithoutTTY asserts ErrStepTTYRequired, but CheckTTY only triggers when stdin or stdout is not a TTY. Run from an interactive terminal (both TTYs), Execute would fall through and block on the huh prompt, hanging the test. Add a pre-check that skips in that case; the hang-proof sibling TestInteractiveHandlersExecuteFailFast covers the TTY-present path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(workflow): only print step label when show.count is enabled The workflow executor printed the bare step label (e.g. "step1") to stderr on every run when the progress bar was disabled, breaking backward compatibility — the show.* features are documented as opt-in (default false). Gate the label print on show.count so default output is unchanged while the count feature still works in non-progress/non-TTY mode. Also regenerate the workflow-retries snapshot to match the intended WithExplanationf error formatting (## Explanation before ## Hints), and add the invoke field to the WorkflowStep schema block in the PRD for consistency with the documented exec/built-in behavior. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(prd): remove invoke field from WorkflowStep schema Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * updates --------- Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Andriy Knysh <aknysh@users.noreply.github.com> Co-authored-by: aknysh <andriy.knysh@gmail.com>
what
atmos.yamlcan now be merged into built-in command namespaces at any nesting depthwhy
Custom commands silently failed when sharing a namespace with built-in commands. For example, users couldn't define
mcp aws installbecause the built-inmcpcommand existed. The root causes were:topLevel=truebranch) using a separategetTopLevelCommands()mapAddCommandto silently replace existing subcommandsThis fix generalizes collision detection to all nesting depths by using a universal
findSubcommand(parent, name)check that works on any cobra command's children.how
topLevelbool parameter fromprocessCustomCommands()findSubcommand()that checks the parent command's subcommands at any levelcreateCustomCommand()helper to reduce nesting complexity (fixes golangci-lint nestif warning)Summary by CodeRabbit
Bug Fixes
Tests