Refactor context module: extract utilities, consolidate error handling#112
Merged
Conversation
Quality pass from a four-angle review (reuse, simplification, efficiency, altitude) over aai_cli/: - stdio.interactive_stdio(): one TTY predicate for the bare-`assembly` setup offer, the onboarding prompter, and the init template picker (was three inline copies, one shadowing context's different _interactive_session) - context: drop the four module-level resolve_* pass-throughs in favor of the AppState methods; fold the six emit_error+Exit pairs into one _fail helper; lazy-import the auth package so the login stack stays off every command's import path - procs.spawn_detached(): the shared detached-spawn recipe for the telemetry flusher and update-check refresh (was two hand-synced Popen incantations) - environments.SANDBOX_ENV: single source for the sandbox name; --env help is derived from ENVIRONMENTS - main: derive the misplaced-global-flag hint set from the root callback's own declarations (the hand list had already drifted — --version got no hint); JSON flag spellings shared via argscan.JSON_FLAGS - doctor.render_check_lines(): shared with the onboarding wizard's environment section (was a verbatim copy including the symbol map) - output.hidden_note(): one phrasing for the "Hidden: N …" footnotes in usage/audit - speak_exec: reuse stdio.piped_stdin_text; merge the duplicated single/multi emit fork - config: collapse the validate_profile pass-through; flow: single _no_project_error; llm: collapse the --list-models closure factory - tests: contract test pinning that the -o field maps cover every TranscriptOutput member exactly https://claude.ai/code/session_01APHW6krqHMsPQ7MsMuBR9n
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR refactors the
aai_cli/context.pymodule to improve code organization and reduce duplication. The changes extract reusable utilities into dedicated modules, consolidate error-handling patterns, and remove thin adapter functions that are no longer needed.Key Changes
Extract
stdioutilities: Moveinteractive_stdio()frommain.pyto a newaai_cli/stdio.pymodule (alongside existingpiped_stdin_text()andstdin_is_piped()), making the "is this a real terminal?" predicate reusable across the codebase.Extract subprocess spawning: Create
aai_cli/procs.pywithspawn_detached()to centralize the detached-subprocess recipe used by both telemetry and update-check, eliminating duplication and ensuring consistency.Consolidate error handling: Introduce
_fail()helper incontext.pyto unify the error-emit-and-exit pattern used throughoutrun_command()and_auto_login_and_exit(), replacing repeatedoutput.emit_error()+typer.Exit()sequences.Lazy-load auth module: Move the
from aai_cli.auth import run_login_flowimport insidepersist_browser_login()to avoid importing the auth package (httpx, Stytch, loopback server) on every command's import path—only when a browser login actually starts.Remove thin adapters: Delete module-level
resolve_profile(),resolve_environment(),resolve_session(), andenv_override_warning()functions that merely delegated toAppStatemethods; callers now invoke the methods directly.Simplify
speak_exec.py: Use the newstdio.piped_stdin_text()helper and extract a_emit()function to deduplicate JSON/human output logic in_emit_single()and_emit_multi().Update
main.py: Replace the hand-maintained_ROOT_ONLY_FLAGSlist with dynamic flag discovery from the root callback's parameter declarations, ensuring new global flags automatically get placement hints without manual updates.Refactor
llm.py: Simplify_list_models()by removing the higher-order function wrapper and inlining the body directly into the command handler.Extract
render_check_lines(): Move the doctor-check rendering logic toaai_cli/commands/doctor.pyso the onboarding wizard can reuse it without duplication.Update test mocks: Adjust all test patches to target
aai_cli.auth.run_login_flow(the new import location) instead ofaai_cli.context.run_login_flow.Consolidate error factories: Extract
_no_project_error()inauth/flow.pyto avoid repeating the same error message in two branches.Simplify config validation: Remove the private
_validate_profile()wrapper; callers now usevalidate_profile()directly.Notable Implementation Details
The
_fail()helper usesfrom Noneto suppress the exception chain for user-facing errors (keeping output clean), but the internal-error path inrun_command()preserves the chain withfrom excfor debugging.stdio.interactive_stdio()is now the single source of truth for "can we prompt the user?" across the setup wizard, onboarding prompter, andassembly inittemplate picker.The
procs.spawn_detached()recipe ensures detached children have their own session, discarded stdio, and a self-disabling env var to prevent recursive spawning.argscan.JSON_FLAGSis now a module-level constant shared withmain.py's misplaced-flag hint logic, preventing drift between the two.https://claude.ai/code/session_01APHW6krqHMsPQ7MsMuBR9n