Skip to content

Centralize interactive huh form setup in pkg/console and remove CLI duplication#43587

Merged
pelikhan merged 7 commits into
mainfrom
copilot/plan-centralise-huh-form-functions
Jul 5, 2026
Merged

Centralize interactive huh form setup in pkg/console and remove CLI duplication#43587
pelikhan merged 7 commits into
mainfrom
copilot/plan-centralise-huh-form-functions

Conversation

Copilot AI commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

This change centralizes interactive huh form construction behind pkg/console helpers so theme/accessibility defaults are applied consistently. It removes repeated .WithTheme(styles.HuhTheme).WithAccessible(console.IsAccessibleMode()) chains across pkg/cli.

  • What changed

    • Added non-wasm form wrappers in pkg/console:
      • PromptForm
      • PromptInput
      • PromptSelect
      • PromptMultiSelect
      • PromptText
      • PromptConfirm (for parity across confirm prompts)
    • Wrappers now bake in:
      • WithTheme(styles.HuhTheme)
      • WithAccessible(console.IsAccessibleMode())
  • CLI migration

    • Updated interactive callsites in pkg/cli to use console wrappers instead of local huh.NewForm(...).WithTheme(...).WithAccessible(...) chains.
    • Kept existing prompt behavior and field definitions intact; only construction path changed.
  • Console alignment

    • Updated existing pkg/console prompt implementations (confirm, input, list) to use the same wrappers, ensuring one construction path for themed/accessible forms.
  • Focused coverage

    • Added wrapper-focused test coverage in pkg/console/prompt_form_test.go for wrapper construction behavior.
// before
form := huh.NewForm(
    huh.NewGroup(
        huh.NewSelect[string]().
            Title("Select a workflow to run").
            Options(options...).
            Value(&selected),
    ),
).WithTheme(styles.HuhTheme).WithAccessible(console.IsAccessibleMode())

// after
form := console.PromptSelect(
    huh.NewSelect[string]().
        Title("Select a workflow to run").
        Options(options...).
        Value(&selected),
)

Copilot AI and others added 2 commits July 5, 2026 16:42
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Add wrappers for Huh form construction in pkg/console Centralize interactive huh form setup in pkg/console and remove CLI duplication Jul 5, 2026
Copilot AI requested a review from pelikhan July 5, 2026 16:45
@pelikhan pelikhan marked this pull request as ready for review July 5, 2026 18:20
Copilot AI review requested due to automatic review settings July 5, 2026 18:20
@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR centralizes huh form construction behind pkg/console helpers so terminal theme and accessibility defaults are applied consistently, and migrates existing interactive CLI call sites away from repeated .WithTheme(...).WithAccessible(...) chains.

Changes:

  • Added non-WASM pkg/console helpers to construct themed, accessibility-aware *huh.Form instances.
  • Migrated interactive prompts across pkg/cli (and existing pkg/console prompts) to use the new wrappers.
  • Added a small wrapper test to ensure wrapper constructors return non-nil forms.
Show a summary per file
File Description
pkg/console/prompt_form.go Adds centralized huh form construction wrappers with default theme + accessibility settings.
pkg/console/prompt_form_test.go Adds basic unit test coverage for the new wrapper constructors.
pkg/console/list.go Uses the new wrapper instead of locally applying theme/accessibility on a huh.NewForm(...).
pkg/console/input.go Uses the new wrapper for secret input form construction.
pkg/console/confirm.go Uses the new wrapper for confirmation form construction.
pkg/cli/run_interactive.go Replaces inline huh.NewForm(...).WithTheme(...).WithAccessible(...) with console.Prompt* wrappers.
pkg/cli/interactive.go Uses console.PromptForm / console.PromptInput / console.PromptConfirm for interactive workflow builder prompts.
pkg/cli/engine_secrets.go Uses console.PromptInput wrapper for token/API key prompt forms.
pkg/cli/add_interactive_workflow.go Uses console.PromptConfirm wrapper for “run now” confirmation.
pkg/cli/add_interactive_schedule.go Uses console.PromptSelect wrapper for schedule frequency selection.
pkg/cli/add_interactive_orchestrator.go Uses console.PromptConfirm wrapper for final confirmation.
pkg/cli/add_interactive_git.go Uses wrappers for select + input prompts during PR handling steps.
pkg/cli/add_interactive_engine.go Uses console.PromptSelect wrapper for engine/auth method selection.
pkg/cli/add_interactive_auth.go Uses console.PromptInput wrapper for repository entry prompt.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 14/14 changed files
  • Comments generated: 2
  • Review effort level: Low

Comment thread pkg/console/prompt_form.go Outdated
Comment on lines +15 to +19
// PromptInput creates a themed, accessibility-aware single-input form.
func PromptInput(input *huh.Input) *huh.Form {
return PromptForm(huh.NewGroup(input))
}

Comment thread pkg/console/prompt_form.go Outdated
return PromptForm(huh.NewGroup(selectField))
}

// PromptMultiSelect creates a themed, accessibility-aware single-multiselect form.
@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 20/100 — Poor

Analyzed 1 test: 0 design, 1 implementation, 1 violation.

📊 Metrics (1 test)
Metric Value
Analyzed 1 (Go: 1, JS: 0)
✅ Design 0 (0%)
⚠️ Implementation 1 (100%)
Edge/error coverage 0 (0%)
Duplicate clusters 0
Inflation No (0.82:1)
🚨 Violations 1
Test File Classification Issues
TestPromptWrappersReturnNonNilForms pkg/console/prompt_form_test.go:12 Implementation Happy-path only; no error/edge cases; assertions lack descriptive context
⚠️ Flagged Tests (1)

TestPromptWrappersReturnNonNilForms (pkg/console/prompt_form_test.go:12) — Implementation test; assertion-message violation.

The test verifies only that wrapper functions return non-nil values, but it provides no assurance that the Theme or Accessible properties are actually applied. The five require.NotNil assertions lack failure context (e.g., require.NotNil(t, PromptInput(...), "PromptInput should return a non-nil form")).

Fix: Add descriptive failure messages to each assertion and consider whether the test should verify that theme and accessibility settings are actually present on the returned forms.

Verdict

Failed. 100% implementation tests (threshold: 30%). Assertion-message violation detected.

Recommendation: Add descriptive context to assertions and extend coverage to verify that theme and accessibility are applied.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • awmgmcpg

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

🧪 Test quality analysis by Test Quality Sentinel · 8.35 AIC · ⌖ 10.4 AIC · ⊞ 6.8K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❌ Test Quality Sentinel: 20/100. 100% implementation tests (threshold: 30%). Assertion-message violation detected in TestPromptWrappersReturnNonNilForms. See detailed analysis in the comment above.

…pkg/console

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR makes significant changes to core business logic (224 new lines in pkg/ directories) but does not have a linked Architecture Decision Record (ADR).

📄 Draft ADR committed: docs/adr/43587-centralise-huh-form-wrappers-in-console.md — review and complete it before merging.

🔒 This PR cannot merge until an ADR is linked in the PR body.

📋 What to do next
  1. Review the draft ADR committed to your branch — it was generated from the PR diff
  2. Complete the missing sections — add context the AI could not infer, refine the decision rationale, and list real alternatives you considered
  3. Commit the finalized ADR to docs/adr/ on your branch
  4. Reference the ADR in this PR body by adding a line such as:

    ADR: ADR-43587: Centralise huh Form Construction Wrappers in pkg/console

Once an ADR is linked in the PR body, this gate will re-run and verify the implementation matches the decision.

❓ Why ADRs Matter

"AI made me procrastinate on key design decisions. Because refactoring was cheap, I could always say 'I'll deal with this later.' Deferring decisions corroded my ability to think clearly."

ADRs create a searchable, permanent record of why the codebase looks the way it does. Future contributors (and your future self) will thank you.

📋 Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context — What is the problem? What forces are at play?
  • Decision — What did you decide? Why?
  • Alternatives Considered — What else could have been done?
  • Consequences — What are the trade-offs (positive and negative)?

All ADRs are stored in docs/adr/ as Markdown files numbered by PR number (e.g., 43587-centralise-huh-form-wrappers-in-console.md for PR #43587).

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · 57 AIC · ⌖ 10.4 AIC · ⊞ 8.5K ·
Comment /review to run again

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Review Summary

Applied /codebase-design and /tdd — clean, well-scoped refactor with no behaviour changes. Two items worth addressing before merge:

📋 Findings

1. Missing prompt_form_wasm.go stub

Every other file in pkg/console follows the file.go / file_wasm.go pairing (confirm, input, list, banner, ...). The six new exported functions in prompt_form.go have no WASM counterpart, which will break any WASM build that imports pkg/console.

2. Test contract is too weak

TestPromptWrappersReturnNonNilForms only checks non-nil. It would pass even if the theme/accessibility calls were removed. Consider asserting that accessible mode propagates, or at minimum split into per-wrapper subtests so failures are immediately identifiable.

Minor

Doc comments say "single-input form" / "single-select form" — better to describe what the function does (wraps a field) rather than imply a constraint.

@copilot please address the review comments above.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 72.2 AIC · ⌖ 8.71 AIC · ⊞ 6.7K ·
Comment /matt to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /codebase-design and /tdd — no blocking issues, but two structural gaps worth fixing before this ships.

📋 Key Themes & Highlights

Key Themes

  • Missing WASM stubsprompt_form.go adds 6 new exported functions under //go:build !js && !wasm but there is no companion prompt_form_wasm.go. Every other file in pkg/console follows the file.go / file_wasm.go pairing (confirm, input, list, banner, ...). Without a stub the WASM build either fails to link or silently omits the symbols.

  • Weak test contractTestPromptWrappersReturnNonNilForms confirms non-nil returns but does not verify the invariant the wrappers exist to enforce: that the returned form carries the theme and accessibility settings. The test would pass even if both .WithTheme and .WithAccessible calls were removed.

Positive Highlights

  • ✅ Clean, well-scoped abstraction — the six wrappers cover exactly the field types used in pkg/cli without over-generalising.
  • ✅ Consistent removal of pkg/styles import across all 9 CLI files — no stray references left behind.
  • ✅ Updating the existing console helpers (confirm.go, input.go, list.go) to use the new wrappers gives the package a single construction path.
  • ✅ Net -203 lines with no behaviour change — exactly the right scope for a de-duplication refactor.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 72.2 AIC · ⌖ 8.71 AIC · ⊞ 6.7K
Comment /matt to run again

"github.com/stretchr/testify/require"
)

func TestPromptWrappersReturnNonNilForms(t *testing.T) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] The test only verifies the wrapper returns non-nil — it does not verify the core contract: that theme and accessibility settings are actually baked in.

💡 Suggestions for strengthening the contract test

The whole point of these wrappers is to guarantee .WithTheme(styles.HuhTheme) and .WithAccessible(IsAccessibleMode()) are applied. A non-nil check would pass even if the wrappers forgot those calls. Consider:

  1. Set accessible mode via env and verify propagation — e.g., t.Setenv("GH_AW_ACCESSIBLE", "1") then assert that a form built with PromptForm differs in behaviour from a raw huh.NewForm in accessible mode.
  2. Test the variadic PromptForm with multiple groups to exercise that path, which callsites like promptForConfiguration rely on.

@copilot please address this.

package console

import (
"charm.land/huh/v2"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/codebase-design] There is no WASM stub counterpart for the new PromptForm, PromptInput, PromptSelect, PromptMultiSelect, PromptText, and PromptConfirm functions. The existing pattern in this package is to pair every non-wasm file with a _wasm.go stub (see confirm.go/confirm_wasm.go, input.go/input_wasm.go, etc.).

💡 What's needed

Add a prompt_form_wasm.go with the //go:build js || wasm tag that returns an error (or panics) for each exported function. Without it, any WASM consumer that references these symbols will get a linker error.

(go/redacted):build js || wasm

package console

import "errors"

var errNotAvailableInWasm = errors.New("interactive forms not available in Wasm")

func PromptForm(groups ...*huh.Group) (*huh.Form, error) {
    return nil, errNotAvailableInWasm
}
// ... etc

Check whether the existing wasm stubs panic or return errors to stay consistent.

@copilot please address this.

Comment thread pkg/console/prompt_form.go Outdated

// PromptSelect creates a themed, accessibility-aware single-select form.
func PromptSelect[T comparable](selectField *huh.Select[T]) *huh.Form {
return PromptForm(huh.NewGroup(selectField))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/codebase-design] PromptInput, PromptSelect, etc. are thin one-liner wrappers over PromptForm. That is fine, but the doc comment says "single-input form" / "single-select form" — which implies a constraint the implementation doesn't enforce. If a caller passes a field that already belongs to a group (which huh fields don't, but future callers may expect to pass a pre-grouped select), the implicit contract could cause confusion.

💡 Suggestion

Sharpen the doc comments to describe what the function does rather than the implied constraint:

// PromptInput wraps a single *huh.Input in a themed, accessible form.
// Use PromptForm for multi-group layouts.
func PromptInput(input *huh.Input) *huh.Form {

This makes the scope of each helper explicit and helps future readers understand when to reach for PromptForm directly.

@copilot please address this.

"github.com/stretchr/testify/require"
)

func TestPromptWrappersReturnNonNilForms(t *testing.T) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] TestPromptWrappersReturnNonNilForms bundles all five wrapper types into one test function. If one wrapper panics, the others are never exercised and the failure message doesn't identify which wrapper broke.

💡 Split into per-wrapper subtests
func TestPromptInput(t *testing.T) {
    var v string
    require.NotNil(t, PromptInput(huh.NewInput().Value(&v)))
}

func TestPromptSelect(t *testing.T) { ... }
// etc.

or use t.Run subtests. This makes failures immediately actionable and test names self-documenting.

@copilot please address this.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: Centralize interactive huh form setup

The DX improvement here is solid — removing repeated .WithTheme(...).WithAccessible(...) chains across pkg/cli is the right direction. The implementation is clean and the migration is consistent. One blocking issue needs to be resolved before merge.

🔴 Blocking: PromptInput/PromptSelect/PromptMultiSelect name collision with WASM stubs

prompt_form.go (!js && !wasm) introduces these three functions with *huh.Field → *huh.Form signatures, while input_wasm.go and select_wasm.go (js || wasm) already define identically-named functions with string-parameter signatures that return (T, error). Build tags keep them from conflicting at compile time, but:

  • The public API is now build-target-dependent: same name, different arity, different return type.
  • pkg/console/README.md still documents all three as "only available in WASM builds" — directly contradicted by this PR.

Either rename the new wrappers to avoid collision, or retire the old wasm stubs and update the README to describe the new unified API.

🟡 Minor: Doc comment typo

"single-multiselect""single multi-select" on line 26 of prompt_form.go.


What's working well
  • All 14 changed files consistently use the new wrappers — no partial migration.
  • prompt_form.go uses the !js && !wasm build tag, matching the pattern of all other non-wasm interactive files in the package.
  • The wrapper test covers all 5 new functions.
  • Removing the pkg/styles import from CLI files is a clean separation of concerns.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · 115.8 AIC · ⌖ 5.29 AIC · ⊞ 4.9K

Comment thread pkg/console/prompt_form.go Outdated
}

// PromptInput creates a themed, accessibility-aware single-input form.
func PromptInput(input *huh.Input) *huh.Form {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The non-wasm PromptInput(*huh.Input) *huh.Form (and PromptSelect, PromptMultiSelect) share names with pre-existing WASM-only counterparts in input_wasm.go / select_wasm.go that have entirely different signatures ((string, string, string) (string, error) vs (*huh.Input) *huh.Form). Since these are gated by mutually exclusive build tags (!js && !wasm vs js || wasm), compilation succeeds — but this creates a build-target-dependent public API where the same symbol has different arities, types, and return values depending on the target.

This is a correctness hazard:

  1. The README still describes PromptInput, PromptSelect, and PromptMultiSelect as "only available in WASM builds" (pkg/console/README.md lines 612, 656, 674). This is now false for non-wasm builds and is directly contradicted by this PR.
  2. Callers that know the package docs will be confused about which overload exists on their target platform.

Please either:

  • Rename the new non-wasm helpers to avoid the naming clash (e.g. NewThemedInput, NewThemedSelect), or
  • Explicitly retire/rename the wasm stubs and update README.md to document the new unified API.

@copilot please address this.

Comment thread pkg/console/prompt_form.go Outdated
}

// PromptMultiSelect creates a themed, accessibility-aware single-multiselect form.
func PromptMultiSelect[T comparable](multiSelect *huh.MultiSelect[T]) *huh.Form {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doc comment says "single-multiselect" — this should be "single multi-select" (two words) to match standard Go/TUI terminology.

@copilot please address this.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES — three issues must be addressed before merging

The centralization goal is sound. The mechanical refactoring in pkg/cli is clean and complete. Three blocking problems remain:

🔴 Issues found

1. WASM build is broken (high)prompt_form.go adds six exported functions under !js && !wasm, but input_wasm.go and select_wasm.go still declare PromptInput, PromptSelect, PromptMultiSelect with their old, incompatible signatures. PromptForm, PromptText, and PromptConfirm have no WASM stub at all. The WASM build target will have duplicate symbols with mismatched types, or outright missing symbols. See inline comment on prompt_form.go:1.

2. Tests are vacuously true (high)require.NotNil on huh.NewForm(...) is always true; the PR's actual invariant (theme and accessibility are baked in) is completely untested. A future regression that removes WithTheme or WithAccessible passes silently. See inline comment on prompt_form_test.go:13.

3. PromptForm() zero-groups trap (medium) — the variadic signature accepts zero groups with no guard, producing a broken form at run time with no construction-time signal. See inline comment on prompt_form.go:12.

🔎 Code quality review by PR Code Quality Reviewer · 159.6 AIC · ⌖ 8.56 AIC · ⊞ 5.4K
Comment /review to run again

@@ -0,0 +1,38 @@
//go:build !js && !wasm

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incomplete WASM refactor: 3 new exported functions have no _wasm.go stubs, and 3 existing stubs now have mismatched signatures.

Every non-WASM file in pkg/console has a corresponding _wasm.go counterpart — this PR breaks that invariant:

  • PromptForm, PromptText, PromptConfirm — added here with no prompt_form_wasm.go stub. They simply don't exist in WASM builds.
  • PromptInput, PromptSelect, PromptMultiSelect — redefined here with new signatures (*huh.Input → *huh.Form), but input_wasm.go / select_wasm.go still export the OLD signatures ((title, description, placeholder string) (string, error)).

There are now two unrelated PromptInput functions in this package that share a name but live in separate build contexts with incompatible signatures and return types. Any WASM caller that adds a dependency on these will get confusing compile failures, or silently call the wrong stub.

💡 Suggested fix

Add pkg/console/prompt_form_wasm.go with stubs for all six functions, and remove the old-signature stubs from input_wasm.go and select_wasm.go:

(go/redacted):build js || wasm

package console

import (
    "charm.land/huh/v2"
    "errors"
)

var errNotAvailable = errors.New("interactive forms not available in Wasm")

func PromptForm(groups ...*huh.Group) *huh.Form                        { panic(errNotAvailable) }
func PromptInput(input *huh.Input) *huh.Form                           { panic(errNotAvailable) }
func PromptSelect[T comparable](s *huh.Select[T]) *huh.Form            { panic(errNotAvailable) }
func PromptMultiSelect[T comparable](m *huh.MultiSelect[T]) *huh.Form  { panic(errNotAvailable) }
func PromptText(t *huh.Text) *huh.Form                                 { panic(errNotAvailable) }
func PromptConfirm(c *huh.Confirm) *huh.Form                           { panic(errNotAvailable) }

Also remove or rename the old-signature PromptInput, PromptSelect, PromptMultiSelect stubs from input_wasm.go and select_wasm.go to eliminate the silent signature split.

)

func TestPromptWrappersReturnNonNilForms(t *testing.T) {
var inputValue string

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests verify construction never panics — not the actual invariant this PR exists to enforce.

require.NotNil(t, PromptInput(...)) is vacuously true: huh.NewForm() never returns nil. The PR's stated purpose is to guarantee .WithTheme(styles.HuhTheme).WithAccessible(IsAccessibleMode()) are applied on every form path. Neither property is asserted anywhere in this test file.

A regression that removes WithTheme or WithAccessible from PromptForm will pass these tests without complaint.

💡 Suggested fix

Test the actual contract. huh.Form exposes enough to check at least the accessibility setting:

func TestPromptFormAppliesAccessibility(t *testing.T) {
    t.Setenv("ACCESSIBLE", "1") // or whatever env key IsAccessibleMode reads

    var v string
    form := PromptInput(huh.NewInput().Value(&v))
    require.NotNil(t, form, "PromptInput must return a non-nil form")
    // If huh.Form exposes an Accessible() getter, assert it:
    // require.True(t, form.IsAccessible(), "form must have accessible mode enabled when ACCESSIBLE=1")
}

func TestPromptFormWrappersReturnNonNil(t *testing.T) {
    for _, tc := range []struct{
        name string
        form *huh.Form
    }{
        {"PromptInput",       PromptInput(huh.NewInput().Value(new(string)))},
        {"PromptSelect",      PromptSelect(huh.NewSelect[string]().Options(huh.NewOption("x","x")).Value(new(string)))},
        {"PromptMultiSelect", PromptMultiSelect(huh.NewMultiSelect[string]().Options(huh.NewOption("x","x")).Value(new([]string)))},
        {"PromptText",        PromptText(huh.NewText().Value(new(string)))},
        {"PromptConfirm",     PromptConfirm(huh.NewConfirm().Value(new(bool)))},
    } {
        t.Run(tc.name, func(t *testing.T) {
            require.NotNil(t, tc.form, "%s must return a non-nil form", tc.name)
        })
    }
}

At minimum, use sub-tests so each wrapper failure is independently reported.


// PromptForm creates a huh form with gh-aw's default theme and accessibility mode.
func PromptForm(groups ...*huh.Group) *huh.Form {
return huh.NewForm(groups...).WithTheme(styles.HuhTheme).WithAccessible(IsAccessibleMode())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PromptForm() with zero groups is a compile-time-valid call that produces a broken form at runtime.

PromptForm is variadic and exported — console.PromptForm() compiles fine. huh.NewForm() with no groups results in a form that either panics or returns an unexpected error on Run(), with no hint at the call site. Given this is now the single centralized construction path, future callsites (especially PromptText/PromptConfirm users constructing groups manually) can easily call it with zero groups by mistake.

💡 Suggested fix
func PromptForm(groups ...*huh.Group) *huh.Form {
    if len(groups) == 0 {
        panic("PromptForm: at least one group is required")
    }
    return huh.NewForm(groups...).WithTheme(styles.HuhTheme).WithAccessible(IsAccessibleMode())
}

Failing loudly at construction time is far easier to debug than a mysterious failure when the form is run.

@github-actions

github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

🤖 PR Triage — Run §28750744185

Field Value
Category refactor
Risk 🔴 High
Score 38 / 100
Action ⏸️ defer
Batch pr-batch:console-migration

Score breakdown: Impact 18 + Urgency 10 + Quality 10

Rationale: Large centralization refactor of huh form construction into pkg/console (15 files, +268/-203). CHANGES_REQUESTED from github-actions bot. No CI checks recorded. High risk due to scope touching all interactive prompts across the CLI. Blocked by review feedback.

⚠️ Blocked: github-actions has CHANGES_REQUESTED. The bot review noted no blocking issues on codebase design/TDD but flagged items worth addressing.

Recommended next step: Defer until review feedback is addressed. Then batch review with #43588 and #43589 as the console-migration cluster.

Generated by 🔧 PR Triage Agent · 101.7 AIC · ⌖ 12.4 AIC · ⊞ 5.5K ·

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address unresolved review comments from github-actions, ensure the branch is up to date, and rerun checks once ready.

Generated by PR Sous Chef: https://github.com/github/gh-aw/actions/runs/28751420498

Generated by 👨‍🍳 PR Sous Chef · 22.2 AIC · ⌖ 8.8 AIC · ⊞ 3.7K ·
Comment /souschef to run again

Copilot AI and others added 2 commits July 5, 2026 19:14
Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
…WASM naming collision

Renames the non-WASM form construction helpers to avoid overloading
the `Prompt*` namespace already used by WASM-only prompt APIs with
different signatures/semantics:

  PromptForm       → NewForm
  PromptInput      → NewInputForm
  PromptSelect     → NewSelectForm
  PromptMultiSelect→ NewMultiSelectForm
  PromptText       → NewTextForm
  PromptConfirm    → NewConfirmForm

Also fixes doc comment typo: "single-multiselect" → "single multi-select".

Updates all callsites in pkg/console and pkg/cli, and the ADR.

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Jul 5, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address unresolved review comments from github-actions, ensure the branch is up to date, and rerun checks once ready.

Generated by PR Sous Chef: https:/...

Done. Renamed the non-WASM form construction helpers to New*Form (NewForm, NewInputForm, NewSelectForm, NewMultiSelectForm, NewTextForm, NewConfirmForm) to avoid overloading the Prompt* namespace already used by the WASM APIs. Also fixed the "single-multiselect" doc comment. All callsites in pkg/cli, pkg/console, and the ADR are updated — commit refactor(console): rename Prompt* form wrappers to New*Form...

Pre-existing unrelated failure: TestPRSousChefWorkflowAddCommentTargetContract fails before and after this PR's changes — not introduced here.

Copilot AI requested a review from gh-aw-bot July 5, 2026 19:24
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address unresolved review feedback from github-actions, ensure the branch is up to date, and rerun checks once ready.

Generated by PR Sous Chef: https://github.com/github/gh-aw/actions/runs/28752519141

Generated by 👨‍🍳 PR Sous Chef · 11.5 AIC · ⌖ 4.41 AIC · ⊞ 3.7K ·
Comment /souschef to run again

Copilot AI commented Jul 5, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address unresolved review feedback from github-actions, ensure the branch is up to date, and rerun checks once ready.

Generated by PR Sous Chef: https:/...

All review threads were resolved in the previous pass (commit 681ca9f). The PR Sous Chef run referenced (28752519141) was a scheduled run on main — no new failures introduced by this PR. Local validation (make fmt, make lint, build, unit tests) is green. CI re-trigger by a maintainer is needed before merge.

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address unresolved review feedback from github-actions, ensure the branch is up to date, and rerun checks once ready.

Generated by PR Sous Chef: https://github.com/github/gh-aw/actions/runs/28753588118

Generated by 👨‍🍳 PR Sous Chef · 18.2 AIC · ⌖ 6.47 AIC · ⊞ 3.7K ·
Comment /souschef to run again

Copilot AI commented Jul 5, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address unresolved review feedback from github-actions, ensure the branch is up to date, and rerun checks once ready.

Generated by PR Sous Chef: https:/...

Run 28753588118 is a scheduled main run — completed successfully, no failures related to this PR. All review threads were resolved in commit 681ca9f. Local validation (build, make fmt, make lint, unit tests) remains green. A maintainer re-trigger of CI on this branch is needed before merge.

@pelikhan pelikhan merged commit aa9cbb8 into main Jul 5, 2026
30 checks passed
@pelikhan pelikhan deleted the copilot/plan-centralise-huh-form-functions branch July 5, 2026 20:38
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.82.3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[plan] Centralise huh form construction behind pkg/console wrappers (PromptInput, PromptSelect, etc.)

4 participants