Skip to content

fix interactive menu#162

Merged
alexcos20 merged 4 commits into
mainfrom
bug/fix_interactive_menu
Jul 22, 2026
Merged

fix interactive menu#162
alexcos20 merged 4 commits into
mainfrom
bug/fix_interactive_menu

Conversation

@alexcos20

@alexcos20 alexcos20 commented Jul 22, 2026

Copy link
Copy Markdown
Member

Fix #161 (Interactive menu (REPL) mode)

Summary

Rewrites the interactive command loop in src/index.ts. In menu mode (npm run cli
with no AVOID_LOOP_RUN), many commands silently failed or behaved differently than
their one-shot equivalents. This PR makes menu mode behave identically to one-shot mode,
fixes several ways the REPL could hang or drop input, and lets getComputeEnvironments
accept an optional target node.

Menu-mode bugs fixed

  1. Bare start broke every menu command. The fake node/script-path prefix that
    Commander's default parsing expects was only populated when the process was started
    with an initial command. Starting with plain npm run cli left it empty, so the
    first two tokens of every typed command were consumed as "node binary" + "script
    path" and the command dumped help instead of running. Fixed by parsing with
    { from: "user" }, which removes the prefix mechanism entirely — bare start and
    initial-command start now behave the same.

  2. Commands with ≥2 arguments were silently discarded. Input with ≥3 tokens was
    only handled if it literally began with npm run cli; otherwise it was dropped with
    no output. Affected most of the CLI in menu mode (download, startCompute,
    editAsset, stopCompute, authorizeEscrow, …). Fixed by treating all tokens
    uniformly after stripping an optional npm run cli prefix.

  3. An empty Enter bricked the session. readLine() busy-waited
    while (answer == "") on an already-closed interface, spinning forever on one empty
    line. Fixed: empty input simply re-prompts.

  4. A command error could kill the whole session. exitOverride() was only set on
    the root program, so a subcommand parse error (e.g. getDDO with no did) was raised
    by the subcommand itself and called process.exit(1), dropping the user back to the
    shell. exitOverride() is now applied recursively to every subcommand, so any parse
    error is caught, reported, and the loop continues waiting for the next command.
    Initial-command failures (previously swallowed by an empty catch) are surfaced the
    same way.

  5. Naive tokenization. commandLine.split(" ") could not parse quotes, so JSON
    arguments (startCompute resources/datasets, editAsset bodies) never worked in the
    menu, and double spaces injected empty tokens. Replaced with a small quote-aware
    tokenizer that honors "…" / '…' and drops empty tokens. (Wrap JSON in single
    quotes, per the documented convention, so its inner double quotes are preserved.)

New in menu mode:

  • Tab completion for command names. Typing a prefix and pressing Tab completes a
    unique command (e.g. getComputeEgetComputeEnvironments) or lists the candidates
    when several match (e.g. getgetDDO, getComputeEnvironments, getJobStatus, …).
    Completion applies to the command name only, not its arguments.

Also fixed as part of the rewrite:

  • Piped input was truncated. Reading via a fresh readline interface per prompt
    discards buffered stdin beyond the first line. The loop now uses a single persistent
    interface consumed via its async iterator, which respects backpressure and never drops
    lines — important for scripted/piped usage and the regression tests below.
  • help no longer prints a stack trace. Benign CommanderError codes
    (commander.helpDisplayed, commander.help, commander.version) are suppressed;
    real errors are shown.
  • EOF exits cleanly. When stdin is exhausted without an explicit exit, the loop
    terminates instead of hanging.
  • Polish: undefined aliases are no longer pushed into the supported-commands list;
    unknown commands suggest help; option-style first tokens (--help, --version) are
    routed to Commander instead of being rejected as "Invalid option"; the dead
    length < 1 check was removed. Commander already prints its own message for parse
    errors, so those are no longer double-reported. A single descriptive prompt
    (Enter command ('exit' | 'quit' or CTRL-C to terminate):) is shown at startup and
    after every command, with no separate redundant banner.

Coordination with the payment prompt

The startCompute flow opens its own stdin interface for payment confirmation
(src/cli.ts). The REPL pauses its interface around command execution so the two never
compete for stdin. (The payment prompt is disabled on non-TTY stdin anyway.)

getComputeEnvironments accepts an optional node

getComputeEnvironments (alias getC2DEnvs) now takes an optional node argument —
getComputeEnvironments <nodeUrlOrPeerId> or --node <nodeUrlOrPeerId> — to query a
specific Ocean Node, defaulting to NODE_URL when omitted. Previously the command
declared zero arguments, so any extra token (e.g. getComputeEnvironments peerID)
hard-errored with "too many arguments" under Commander v13. Every other command keeps
strict excess-argument checking, which gives users a clear error rather than silently
ignoring typos.

Behavior preserved

  • One-shot mode (AVOID_LOOP_RUN=true) is unchanged: it still parses process.argv
    directly with Commander's default parsing.
  • Existing DID/flag usage is unchanged; the new node argument is purely additive.

Regression tests

Adds test/replMenu.test.ts, an infra-free system test that spawns the CLI with piped
stdin and drives the REPL. It points PRIVATE_KEY/RPC/NODE_URL at an unreachable
port, so a command that actually parses and runs surfaces a Command error (connection
refused) while a dropped or parse-rejected command does not — letting the test
distinguish "ran" from "silently ignored" without any live node. Covered cases:

  • single-token command on bare start
  • multi-argument command (previously silently dropped)
  • a line typed with the npm run cli prefix
  • single-quoted JSON argument stays one token (no "too many arguments")
  • empty input re-prompts and does not hang
  • unknown command reports "Invalid option" and suggests help
  • EOF without exit terminates cleanly
  • getComputeEnvironments <node> accepts the optional node argument

Housekeeping

  • Adds an engines field ("node": ">=22") to package.json so the Node version in
    .nvmrc is actually enforced by npm. The wrong Node version silently produces a stale
    node_modules / boot failure, which is easy to miss.
  • Updates the README getComputeEnvironments docs to show the new optional node argument
    and the -n, --node option.

Other verification

  • npm run build:tsc and npm run lint — pass (only pre-existing no-explicit-any
    warnings remain; all touched files are clean).
  • resolveComputeInputs unit test — 11 passing.
  • setup.test.ts — 4 passing (the getComputeEnvironments help line now reads
    getComputeEnvironments|getC2DEnvs [options] [node]; existing assertions still hold).

Summary by CodeRabbit

  • New Features

    • getComputeEnvironments now supports targeting a specific node by URL or peer ID.
    • Improved interactive CLI with command validation, quoted-argument handling, tab completion, and support for npm run cli prefixes.
    • Added documentation for algorithm permissions, persistent-storage bucket workflows, and node-log downloads.
  • Documentation

    • Expanded CLI command examples and available option references.
  • Chores

    • Node.js 22 or newer is now required.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@alexcos20, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 17 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ded2a2d5-c8ea-4053-8c42-d7dedc44aab4

📥 Commits

Reviewing files that changed from the base of the PR and between 23ee79c and 08112a9.

📒 Files selected for processing (3)
  • README.md
  • src/cli.ts
  • src/index.ts
📝 Walkthrough

Walkthrough

Changes

Interactive CLI and node targeting

Layer / File(s) Summary
Async REPL command execution
src/index.ts, test/replMenu.test.ts
The menu uses async readline iteration, quoted-token parsing, command validation, tab completion, Commander error handling, prompt recovery, and integration coverage.
Targeted compute-environment queries
src/cli.ts, src/commands.ts, test/paidComputeFlow.test.ts
getComputeEnvironments accepts a positional or named node target, resolves the target URL, and prints the corrected output label.
CLI documentation and runtime requirement
README.md, package.json
Documentation covers new commands and options, while package metadata requires Node.js 22 or newer.

Estimated code review effort: 4 (Complex) | ~45 minutes

Suggested reviewers: bogdanfazakas, giurgiur99, andreip136

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant REPL
  participant Commander
  participant Command
  User->>REPL: Enter command
  REPL->>REPL: Tokenize and normalize input
  REPL->>Commander: parseAsync(tokens)
  Commander->>Command: Execute command
  Command-->>Commander: Result or error
  Commander-->>REPL: Completion
  REPL-->>User: Display output and prompt
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately reflects the main change to the interactive menu.
Linked Issues check ✅ Passed The PR addresses the interactive menu fixes, optional getComputeEnvironments node, tab completion, and Node 22 requirement requested in #161.
Out of Scope Changes check ✅ Passed The changes stay focused on menu fixes, related CLI docs, tests, and the Node version update, with no clear unrelated additions.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bug/fix_interactive_menu

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (4)
src/index.ts (4)

148-148: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

main() is missing an explicit return type annotation.

As per coding guidelines, **/*.{ts,tsx}: "Always provide explicit type annotations for function parameters and return types."

♻️ Proposed fix
-async function main() {
+async function main(): Promise<void> {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/index.ts` at line 148, Add an explicit return type annotation to the
async main() function, using the appropriate Promise-based type for its existing
return behavior. Do not alter the function’s implementation or surrounding
control flow.

Source: Coding guidelines


182-182: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Top-level error log doesn't use chalk, unlike the rest of the CLI's error output.

As per coding guidelines, **/*.{ts,tsx}: "Use chalk library for colored console output in error messages."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/index.ts` at line 182, Update the top-level error logging around the
console.error call to use chalk for colored error output, matching the CLI’s
existing error-message conventions. Preserve the “Program Error:” context and
error.message content while applying the established chalk symbol or import.

Source: Coding guidelines


1-19: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

program module-state variable has no type annotation.

let program (line 6) is later assigned await createCLI() but declared without a type, so it's implicitly typed loosely through inference gaps rather than an explicit Command annotation.

As per coding guidelines, **/*.{ts,tsx}: "Always provide explicit type annotations for function parameters and return types" / "Avoid any type; use unknown if necessary."

♻️ Proposed fix
-let program
+let program: Command
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/index.ts` around lines 1 - 19, Annotate the module-level program variable
as Command in src/index.ts, matching the Command instance returned by createCLI
and the type expected by enableExitOverride. Keep its existing assignment and
command setup behavior unchanged.

Source: Coding guidelines


67-94: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

User-facing error output bypasses chalk styling used elsewhere in the CLI.

console.log(\Invalid option: ...`)(line 81) andconsole.error("Command error:", ...)(line 91) print unstyled text, unlike the rest of the codebase (e.g.src/cli.tsconsistently wraps errors inchalk.red(...)`).

As per coding guidelines, **/*.{ts,tsx}: "Use chalk library for colored console output in error messages."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/index.ts` around lines 67 - 94, The user-facing errors in runTokens are
printed without the CLI’s required chalk styling. Wrap the invalid-command
message in chalk.red before console.log, and wrap the unexpected runtime error
output in chalk.red before console.error, preserving the existing CommanderError
filtering and message content.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Around line 443-444: Update the “Named Options” allowAlgo example to include
the required datasetDid and algoDid positional arguments alongside the named
options, matching the current src/cli.ts contract.

In `@src/cli.ts`:
- Around line 469-478: Update the node option definition in the command action
to require a string value rather than allowing an optional argument, ensuring
options.node cannot become true when --node is passed without a value. Preserve
the existing fallback between options.node and the positional node argument when
calling Commands.getComputeEnvironments.

In `@src/index.ts`:
- Around line 157-176: Return immediately after handling --help or -h in the
startup flow, before the AVOID_LOOP_RUN branch and initial command processing,
so help is printed once and neither parseAsync nor runTokens/runLoop executes.

---

Nitpick comments:
In `@src/index.ts`:
- Line 148: Add an explicit return type annotation to the async main() function,
using the appropriate Promise-based type for its existing return behavior. Do
not alter the function’s implementation or surrounding control flow.
- Line 182: Update the top-level error logging around the console.error call to
use chalk for colored error output, matching the CLI’s existing error-message
conventions. Preserve the “Program Error:” context and error.message content
while applying the established chalk symbol or import.
- Around line 1-19: Annotate the module-level program variable as Command in
src/index.ts, matching the Command instance returned by createCLI and the type
expected by enableExitOverride. Keep its existing assignment and command setup
behavior unchanged.
- Around line 67-94: The user-facing errors in runTokens are printed without the
CLI’s required chalk styling. Wrap the invalid-command message in chalk.red
before console.log, and wrap the unexpected runtime error output in chalk.red
before console.error, preserving the existing CommanderError filtering and
message content.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f8bed695-ad00-4bb5-b5ab-40361de90f2a

📥 Commits

Reviewing files that changed from the base of the PR and between ee97bfd and 23ee79c.

📒 Files selected for processing (7)
  • README.md
  • package.json
  • src/cli.ts
  • src/commands.ts
  • src/index.ts
  • test/paidComputeFlow.test.ts
  • test/replMenu.test.ts

Comment thread README.md Outdated
Comment thread src/cli.ts
Comment thread src/index.ts Outdated
@alexcos20 alexcos20 self-assigned this Jul 22, 2026
@alexcos20

Copy link
Copy Markdown
Member Author

/run-security-scan

@alexcos20 alexcos20 left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

AI automated code review (Gemini 3).

Overall risk: low

Summary:
Excellent refactoring of the interactive REPL to use readline/promises and async iterators, significantly improving stability and developer experience. Command execution is handled robustly without killing the REPL loop. Added new functionality and better argument parsing. LGTM!

Comments:
• [INFO][style] The custom tokenize function is a great addition for handling string arguments with spaces, like JSON strings. Note that it doesn't currently support backslash escaping (e.g., "{\"key\": \"value\"}"), so users must use single quotes to wrap JSON (e.g., '{"key": "value"}'). This is standard practice and acceptable, but worth keeping in mind if users report issues with nested quotes.
• [INFO][style] Using for await (const rawLine of rl) is an excellent and modern approach to handling the REPL loop. It cleanly manages backpressure and eliminates the need for recursive prompt functions.
• [WARNING][other] Bumping the engine requirement to node: >=22 is quite aggressive, as Node 20 is still in LTS until April 2026. Unless there are specific Node 22 features required, consider lowering this to >=20 to support a wider range of environments. If this is an intentional project-wide decision, feel free to ignore.
• [INFO][style] Good design choice allowing both a positional argument [node] and a flag -n, --node <node>. This greatly enhances flexibility and ease of use for CLI users.

@alexcos20
alexcos20 merged commit 5727f0c into main Jul 22, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix interactive menu

2 participants