feat: add interactive mode to strategy-builder CLI#2546
feat: add interactive mode to strategy-builder CLI#2546hardyjosh wants to merge 19 commits intostrategy-builder-clifrom
Conversation
WalkthroughThis pull request introduces an interactive CLI mode for the strategy builder that guides users through strategy deployment configuration. New dependencies are added for terminal UI and HTTP requests. The interactive flow fetches available strategies, collects user inputs for owner, strategy selection, and builder parameters, then generates and outputs deployment transaction calldata. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant CLI as StrategyBuilder<br/>(mod.rs)
participant Interactive as Interactive<br/>Wizard
participant UI as Terminal UI<br/>(select.rs)
participant Registry as Registry API
participant Calldata as Calldata<br/>Generator
User->>CLI: Run with --interactive flag
CLI->>Interactive: run_interactive(registry_url)
Interactive->>Registry: Fetch available strategies
Registry-->>Interactive: Strategy list
Interactive->>UI: Render strategy selection
UI->>User: Display selectable list
User->>UI: Select strategy + deployment variant
UI-->>Interactive: Selected indices
Interactive->>UI: Prompt owner address input
User->>UI: Enter owner address
UI-->>Interactive: Owner address
Interactive->>UI: Prompt order tokens selection
User->>UI: Select tokens (optional)
UI-->>Interactive: Token choices
Interactive->>UI: Prompt builder field inputs
User->>UI: Fill required fields
UI-->>Interactive: Field values
Interactive->>UI: Prompt deposit amounts
User->>UI: Enter deposits
UI-->>Interactive: Deposit values
Interactive->>Calldata: Generate deployment calldata<br/>(with approvals + deployment)
Calldata-->>Interactive: Calldata lines
Interactive->>UI: Prompt output mode (stdout/file)
User->>UI: Choose output destination
UI-->>Interactive: Output preference
Interactive->>User: Write calldata to stdout or file
User-->>Interactive: Output complete
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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 |
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
5b81496 to
09b6e85
Compare
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
Guided deployment flow mirroring the webapp: 1. Fuzzy-select strategy from registry (shows name + description) 2. Pick deployment (shows name + description) 3. Select tokens with search across available token lists 4. Fill required fields with preset selection or custom input 5. Optional deposits with preset amounts 6. Enter owner address 7. Generate calldata — print to stdout or save to .calldata file Usage: raindex strategy-builder -i --registry <url> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ments - Add bold/dim/underlined styling via console crate - Structured headings and separators between sections - Ask for owner address first (needed for balance display) - Show token symbol/name instead of raw key in deposit prompts - Show token balance when prompting for deposits - Remove stox-specific language from output hints — describe the format (address:calldata lines) so any submitter can consume it - Improve preset display with bold labels and dim values Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add max_length(10) to all Select/FuzzySelect prompts so they scroll within a fixed window instead of reprinting the full list on every keystroke. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Long descriptions were wrapping to multiple lines, making each list item 2-3 rows tall and causing the display to scroll erratically. Now truncates all display strings to fit within the terminal width. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The core issue was dialoguer redrawing the list on every keystroke, wiping lines printed above it. Fix: keep list items short (just keys or names), then show the full name + description AFTER the user makes their choice. This way dialoguer only redraws its own compact list. Also: "Generating Calldata" is now a status message, not a heading. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
FuzzySelect redraws on every keystroke, which with long token lists causes severe terminal corruption. Replace with a printed list of all available tokens, then a text input that matches by symbol, name substring, or raw address. Shows disambiguation when multiple tokens match a partial query. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The root cause: dialoguer's Select redraws by clearing lines above it. When items wrap to multiple lines, it miscalculates and wipes content printed before the list. Fix: call clear_screen() before each Select that has multi-line items (strategies, deployments, tokens). Previous output scrolls into terminal scrollback. Full descriptions are shown in the items with wrapping — no truncation. Also: bring back arrow-key Select for token lists (was accidentally replaced with text input), drop FuzzySelect dependency. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Restore the approach that worked: Select items include full descriptions (wrapping is fine), no headings/content printed directly above Select widgets, details shown after selection. Removes clear_screen() and FuzzySelect, drops console dependency. Token selection uses Select with symbol/name/address in items. Deposits show token symbol and balance before the input prompt. Minimal eprintln between steps — each Select starts clean at the bottom of the terminal. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Root cause: dialoguer counts items as single lines. When items wrap, cursor-up overshoots and wipes content above. Fix: print full descriptions as a reference table above the Select (with headings), then use short single-line items (just keys/names) in the Select. dialoguer only redraws its own short items, leaving the table intact. Verified with pexpect: cursor-up count matches item count, headings and descriptions survive arrow navigation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use explicit \n in Select items to wrap descriptions ourselves. dialoguer counts \n characters for its cursor-up math, so the height tracking is correct and headings above the Select survive navigation. Each strategy/deployment item shows: bold name dim wrapped description (indented, word-wrapped to terminal width) Headings print above and are preserved during arrow-key navigation. Verified with pexpect: cursor-up count matches actual rendered lines. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Root cause of narrow terminal corruption: ANSI escape codes in items made the terminal-rendered width different from what we calculated. Fix: wrap plain text first (using actual char count, no ANSI), then apply bold/dim styling after wrapping. Also account for dialoguer's 2-char prefix on the first line vs our own indent on continuation lines. Tested at 60 cols with pexpect — heading appears exactly once, survives all navigation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Lines from before the app (cargo output, long commands) can wrap at the terminal edge. dialoguer's cursor-up math doesn't account for these pre-existing wrapped lines, causing it to overshoot and corrupt them. Clearing the screen at startup gives us a clean slate. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Lines rendered at exactly the terminal width can cause the cursor to wrap to the next line on some terminals, creating a phantom blank line that throws off dialoguer's cursor-up count. Fix: wrap to term_width - 1 instead of term_width. Also remove the registry URL display line which could wrap uncontrollably. Verified: zero lines at or over terminal width at 60 cols. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
dialoguer's Select is fundamentally broken for multi-line items — it uses cursor-up math that miscounts when text wraps at the terminal edge. No amount of wrapping workarounds fixes this. Replace with a custom Select built on crossterm that uses the alternate screen buffer. This gives us: - Proper word-wrapping responsive to terminal width - Scrolling with ▲▼ indicators for long lists - Bold name + dim description per item - Highlighted selection in cyan - No interference with main terminal scrollback - Works at any terminal width Keep dialoguer only for Input prompts (which work fine). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After each alternate-screen selection, clear the main screen and reprint a summary of all choices made so far (owner, strategy, deployment). This gives the user context as they progress through the wizard. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Stay in one alternate screen for the whole interactive session.
No more flashing between screens. Each step shows all prior
selections as context at the top:
Owner: 0xABCD
Strategy: fixed-limit
Deployment: base
Token to Buy — Select the token you want to purchase
❯ wtSPYM (Wrapped SPDR Portfolio S&P 500 ETF ST0x)
0x31C2C14134e6E3...
The select, input prompts, and progress all render in the same
alternate screen. On completion, the final summary prints to the
normal terminal with calldata on stdout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- All text inputs (owner, custom fields, deposits) now render in the alternate screen using our own crossterm-based input widget. No more dropping back to the main terminal mid-wizard. - Field/token descriptions are passed separately to Select and rendered as dim lighter text directly under the bold-underlined title, not embedded in the title (which was making them bold+underlined too). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Extract ANSI codes as named constants (BOLD, DIM, etc.) - Factor out write_header, write_title, wrap_lines, write_wrapped helpers shared between Select and Input rendering - Add SelectContext::new()/with_description() builder methods - Add 10 unit tests covering wrap_lines, item_height, and count_items_fitting edge cases - Simplify render_select signature (query terminal size internally) - Apply rustfmt Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
09b6e85 to
9a36b8f
Compare
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@crates/cli/src/commands/strategy_builder/interactive.rs`:
- Around line 165-185: Replace the catch-all `_ => Ok(calldata_lines)` in the
match on `output_choice` with an explicit `0 => Ok(calldata_lines)` arm to
self-document the intended case; also add a fallback arm (e.g., `_ =>
unreachable!("invalid output_choice")` or return a descriptive error) to catch
unexpected indices at runtime. Update the match that references `output_choice`,
`calldata_lines`, and `path` accordingly so the two intended branches are
explicit and any other values are handled explicitly.
- Around line 29-37: Wrap the terminal setup/teardown with a panic-safe guard so
raw mode and cursor/screen state are always restored if run_wizard panics: after
calling terminal::enable_raw_mode() and execute!(w,
terminal::EnterAlternateScreen, cursor::Hide), create a small RAII guard type
(or use std::panic::catch_unwind) whose Drop implementation calls execute!(w,
terminal::LeaveAlternateScreen, cursor::Show) and terminal::disable_raw_mode();
then call run_wizard(&mut w, ®istry, &mut progress).await normally and let
the guard handle cleanup (or explicitly dismiss the guard) to ensure w, raw
mode, and cursor state are restored even on panic.
In `@crates/cli/src/commands/strategy_builder/select.rs`:
- Around line 284-292: The code risks underflow when computing positions like
cols as u16 - 3 and rows as u16 - 2; change these to use saturating subtraction
on the usize values before casting (e.g., let xpos = cols.saturating_sub(3) as
u16 and let ypos = rows.saturating_sub(2) as u16) and use xpos/ypos in the
execute! calls so cursor::MoveTo gets a safe u16; update both places where
cols/rows are adjusted and keep existing variables (scroll, total_header,
count_items_fitting, items) unchanged.
🪄 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: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 70e78f15-8e44-4f16-805a-db1cd610bebd
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (4)
crates/cli/Cargo.tomlcrates/cli/src/commands/strategy_builder/interactive.rscrates/cli/src/commands/strategy_builder/mod.rscrates/cli/src/commands/strategy_builder/select.rs
- RAII TerminalGuard restores raw mode/alt screen/cursor on panic - Explicit 0 => arm + unreachable! for output_choice match - saturating_sub for cursor position u16 cast to avoid underflow

Motivation
Constructing a non-interactive
raindex strategy-builderinvocation requires knowing the strategy key, deployment key, which select-tokens apply, which fields the deployment asks for, and the presets for each field. That is the exact flow the webapp walks users through visually. Asking a human or agent to read the raw.rainYAML to assemble those flags is a poor UX.Solution
Add
-i/--interactivetostrategy-builder. It drives a TUI wizard in the terminal's alternate-screen buffer that mirrors the webapp flow:Built on
crosstermrather thandialoguerbecause dialoguer's cursor-up redraw maths miscounts multi-line wrapped items and corrupts the terminal. The alt-screen avoids all of that — the wizard owns its own screen and leaves the main terminal untouched.All prior selections are shown as context at the top of every screen so the user can see how choices accumulate.
Checks
Summary by CodeRabbit