Skip to content

add hard clippy rules and fix init#4

Merged
Bechma merged 5 commits intocyberfabric:mainfrom
Bechma:clippy
Feb 25, 2026
Merged

add hard clippy rules and fix init#4
Bechma merged 5 commits intocyberfabric:mainfrom
Bechma:clippy

Conversation

@Bechma
Copy link
Copy Markdown
Collaborator

@Bechma Bechma commented Feb 23, 2026

Summary by CodeRabbit

  • Chores
    • Updated dependencies (toml, syn, serde-saphyr) and added toml_edit; added workspace clippy lint rules.
  • New Features
    • Added a CLI "tools" command to install/upgrade developer tools with prompts and verbose/force options.
    • Added a CLI "module" command to scaffold modules from local or remote templates and integrate them into the workspace.
  • Bug Fixes / Improvements
    • Refined CLI run/restart behavior and more robust command spawning.
  • Documentation
    • Improved CLI help text, prompts, and error diagnostics.

Signed-off-by: Bechma <19294519+Bechma@users.noreply.github.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 23, 2026

📝 Walkthrough

Walkthrough

Update workspace dependencies and Clippy lint config; refactor CLI internals (arg rename, const ctor, cargo spawn/current_dir, error formatting, restart handling); add tools management (rustup-aware install/upgrade) and module generation (cargo-generate + toml_edit workspace updates).

Changes

Cohort / File(s) Summary
Workspace manifest
Cargo.toml
Bump serde-saphyr, syn, toml; add toml_edit = "0.25.3"; add [workspace.lints.clippy] pedantic/nursery = warn and struct_excessive_bools = "allow".
CLI: common helpers & cargo invocation
crates/cli/src/common.rs
Use lazy env fallback for CARGO, set current_dir when spawning cargo, move localized imports, and switch server-main dependency string building to fold + writeln!.
CLI: run args & control flow
crates/cli/src/run/mod.rs, crates/cli/src/run/run_loop.rs
Rename build_run_argsbr_args; make RunLoop::new a const fn; move cargo_dir into thread (no clone); swap dependency creation call to module_parser::Config::create_dependencies; use .display() for paths; consume Rerun signals (no immediate continue).
CLI: setup small changes
crates/cli/src/setup/init.rs, crates/cli/src/setup/mod.rs
Adjust local_path arg attribute and help text; preserve subfolder behavior when local_path absent; internal enum pattern matches use Self::Variant.
CLI: tools manager (new, large)
crates/cli/src/setup/tools.rs
Add ToolsArgs::run and full tools management: tool catalog, resolve/validate selection, install/upgrade flows, rustup-awareness, platform install helpers, interactive prompts, verbose execution and expanded error contexts.
CLI: module generator (new, large)
crates/cli/src/setup/module.rs, crates/cli/Cargo.toml
Add ModuleArgs CLI and run flow using cargo_generate and toml_edit: generate modules from git/local templates, update workspace members and merge module dependencies into workspace dependencies.
Module parser types
crates/module-parser/src/config.rs
Change CargoToml.dependencies type to new public alias CargoTomlDependencies = HashMap<String, ConfigModuleMetadata>.

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant CLI as CLI
    participant OS as OS/Runtime
    participant Rustup as rustup
    participant CargoGen as cargo-generate

    User->>CLI: run `cli tools install/upgrade [names]` (flags: yolo, verbose)
    CLI->>CLI: resolve requested tools vs TOOLS catalog
    alt unknown tool
        CLI->>User: error (list known tools)
    else known tools
        CLI->>OS: check `is_installed(binary)`
        OS-->>CLI: installed? (yes/no)
        alt needs rustup/component
            CLI->>Rustup: ensure_rustup (may call install_rustup)
            Rustup-->>CLI: installed/available
            CLI->>Rustup: add components / run prerequisites
            Rustup-->>CLI: result
        else prerequisite binary
            CLI->>OS: run installer/command (with verbose option)
            OS-->>CLI: result
        end
        CLI->>User: report per-tool result
    end

    User->>CLI: run `cli module create ...` (local/git, subfolder, branch)
    CLI->>CLI: compute template path & destination
    alt git template
        CLI->>CargoGen: generate with `TemplatePath::Git`
    else local template
        CLI->>CargoGen: generate with local `TemplatePath`
    end
    CargoGen-->>CLI: generation result
    CLI->>CLI: update workspace `Cargo.toml` via `toml_edit` (add members, merge deps)
    CLI->>User: print created module path(s)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Build cmd #3: Overlaps CLI run/init plumbing and server-template changes (touches same run/* and setup/* files).
  • Skeleton + init|run cmd #2: Related to module-parser config types and toml_edit-backed workspace handling; shares the CargoTomlDependencies/workspace edits.

Poem

🐰 I hopped through crates and nudged the locks,
Linted the paths and polished the clocks.
Rustup hummed while tools lined in rows,
Templates sprouted where new module grows.
Carrot-cheers — the little CLI glows!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.17% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title 'add hard clippy rules and fix init' is vague and only partially captures the scope of changes. While clippy rules are added, the changeset includes numerous other modifications across multiple modules. Consider a more specific title that better reflects the primary changes, such as 'Add clippy lints, refactor module setup, and update dependencies' to more accurately represent the full scope of this multi-file changeset.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (4)
crates/cli/src/run/mod.rs (1)

14-14: Optional: align br_args naming with build/mod.rs.

crates/cli/src/build/mod.rs uses build_run_args for the same embedded BuildRunArgs field. Using br_args here is inconsistent — either rename the build module's field to match or restore the full name here for uniformity.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/run/mod.rs` at line 14, The field name br_args in the Run
module is inconsistent with the build module which uses build_run_args; rename
the field to build_run_args (type BuildRunArgs) in the struct that currently
declares br_args to align naming across modules, and update all
references/usages of br_args within functions/methods in this file (and any
callers) to use build_run_args so the symbol BuildRunArgs is consistently
exposed as build_run_args like in build/mod.rs.
crates/cli/src/run/run_loop.rs (1)

52-55: cargo_dir_clone is now a move, not a clone — misleading name.

After line 52, cargo_dir is consumed; naming the destination cargo_dir_clone implies a .clone() occurred. A simple rename to cargo_dir (move-shadowing the original) avoids the confusion.

♻️ Rename for clarity
-        let cargo_dir_clone = cargo_dir;
-        let runner_handle = std::thread::spawn(move || {
-            cargo_run_loop(&cargo_dir_clone, &signal_rx);
-        });
+        let runner_handle = std::thread::spawn(move || {
+            cargo_run_loop(&cargo_dir, &signal_rx);
+        });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/run/run_loop.rs` around lines 52 - 55, The variable
cargo_dir_clone is misleading because it's moved, not cloned; change the moved
variable name to cargo_dir (shadowing the outer one) inside the thread spawn to
reflect a move instead of implying a clone and update the closure call to
cargo_run_loop(&cargo_dir, &signal_rx) so the move uses the new cargo_dir
identifier; reference occurrences: the spawned thread block that calls
cargo_run_loop, the cargo_dir_clone identifier, and signal_rx/runner_handle to
locate and rename.
Cargo.toml (1)

36-39: LGTM on the lint config — one advisory on nursery.

pedantic with priority = -1 is the idiomatic way to enable it below specific overrides (e.g. struct_excessive_bools = "allow"). The nursery group is explicitly marked unstable and its lint set can change between rustc releases, occasionally introducing new warnings on untouched code. Since both are set to "warn", CI won't break — but a future toolchain bump could surface a wave of new warnings.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Cargo.toml` around lines 36 - 39, The nursery lint group is unstable and may
introduce unexpected warnings on toolchain bumps; update the
workspace.lints.clippy block so nursery uses a lower priority like pedantic
(e.g., nursery = { level = "warn", priority = -1 }) or explicitly change its
level to "allow" to prevent future waves of warnings—modify the entries for
nursery and/or pedantic in the workspace.lints.clippy section (referencing the
pedantic, nursery, and struct_excessive_bools keys) to keep CI stable.
crates/cli/src/common.rs (1)

213-217: Non-deterministic ordering in generated use … as _; lines.

HashMap::keys() has no guaranteed iteration order, so each run of prepare_cargo_server_main may produce a differently-ordered block. While the watcher doesn't observe .cyberfabric/src/main.rs, the output is non-reproducible (e.g. diffs will be noisy, hermetic builds differ).

♻️ Sort keys before folding
-    let dependencies = dependencies.keys().fold(String::new(), |mut acc, name| {
-        _ = writeln!(acc, "use {name} as _;");
-        acc
-    });
+    let mut keys: Vec<&String> = dependencies.keys().collect();
+    keys.sort();
+    let dependencies = keys.iter().fold(String::new(), |mut acc, name| {
+        _ = writeln!(acc, "use {name} as _;");
+        acc
+    });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/common.rs` around lines 213 - 217, The generated `use {name}
as _;` lines are non-deterministic because dependencies.keys() iterates HashMap
keys in arbitrary order; in prepare_cargo_server_main, collect the keys into a
Vec, sort that Vec (e.g., ascending), then fold/iterate over the sorted keys to
build the dependencies string so output is deterministic (refer to the
dependencies variable construction where keys().fold(...) is used).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@Cargo.toml`:
- Around line 36-39: The nursery lint group is unstable and may introduce
unexpected warnings on toolchain bumps; update the workspace.lints.clippy block
so nursery uses a lower priority like pedantic (e.g., nursery = { level =
"warn", priority = -1 }) or explicitly change its level to "allow" to prevent
future waves of warnings—modify the entries for nursery and/or pedantic in the
workspace.lints.clippy section (referencing the pedantic, nursery, and
struct_excessive_bools keys) to keep CI stable.

In `@crates/cli/src/common.rs`:
- Around line 213-217: The generated `use {name} as _;` lines are
non-deterministic because dependencies.keys() iterates HashMap keys in arbitrary
order; in prepare_cargo_server_main, collect the keys into a Vec, sort that Vec
(e.g., ascending), then fold/iterate over the sorted keys to build the
dependencies string so output is deterministic (refer to the dependencies
variable construction where keys().fold(...) is used).

In `@crates/cli/src/run/mod.rs`:
- Line 14: The field name br_args in the Run module is inconsistent with the
build module which uses build_run_args; rename the field to build_run_args (type
BuildRunArgs) in the struct that currently declares br_args to align naming
across modules, and update all references/usages of br_args within
functions/methods in this file (and any callers) to use build_run_args so the
symbol BuildRunArgs is consistently exposed as build_run_args like in
build/mod.rs.

In `@crates/cli/src/run/run_loop.rs`:
- Around line 52-55: The variable cargo_dir_clone is misleading because it's
moved, not cloned; change the moved variable name to cargo_dir (shadowing the
outer one) inside the thread spawn to reflect a move instead of implying a clone
and update the closure call to cargo_run_loop(&cargo_dir, &signal_rx) so the
move uses the new cargo_dir identifier; reference occurrences: the spawned
thread block that calls cargo_run_loop, the cargo_dir_clone identifier, and
signal_rx/runner_handle to locate and rename.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 51e32d9 and b735053.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • Cargo.toml
  • crates/cli/src/common.rs
  • crates/cli/src/run/mod.rs
  • crates/cli/src/run/run_loop.rs
  • crates/cli/src/setup/init.rs
  • crates/cli/src/setup/mod.rs
  • crates/cli/src/setup/tools.rs

Signed-off-by: Bechma <19294519+Bechma@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
crates/cli/src/setup/tools.rs (1)

175-187: Use the home crate for getting the home directory.

std::env::home_dir() is deprecated (though Rust 1.86+ may remove the deprecation warning). The canonical replacement is the home crate, maintained by the Cargo team and used by Cargo and Rustup themselves. Add home to dependencies and use home::home_dir(), or alternatively access $HOME/$USERPROFILE directly via std::env::var_os().

♻️ Suggested replacement
+    let home = home::home_dir().unwrap_or_default();

Requires adding to Cargo.toml:

home = { workspace = true }  # Add to [workspace.dependencies] in root Cargo.toml
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/setup/tools.rs` around lines 175 - 187, The function
cargo_bin_path uses deprecated std::env::home_dir(); replace it with the `home`
crate: add home = { workspace = true } to workspace dependencies and change the
call to home::home_dir().unwrap_or_default() in cargo_bin_path, leaving the
existing logic that builds bin (using cfg!(target_family = "windows") to append
".exe") and the subsequent
.join(".cargo").join("bin").join(bin).to_string_lossy().into_owned() intact;
this preserves behavior while removing the deprecation.
🤖 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/setup/tools.rs`:
- Around line 65-85: resolve_tools currently returns all entries from TOOLS
whenever self.install is None, which ignores the --all flag; update
resolve_tools to explicitly check the --all flag (e.g. a field like self.all)
and only return TOOLS.iter().collect() when that flag is true, otherwise return
an empty Vec or a user-facing error instructing to pass --install or --all;
ensure the code path that handles names (self.install) remains unchanged and
keep the with_context logic for unknown names, or alternatively remove/adjust
the --all flag/help text to reflect the new behavior if you prefer to default to
installing everything.
- Around line 156-173: ensure_rustup currently auto-installs rustup
unconditionally; update it to respect the confirmation flow by checking the
existing confirmation flag (e.g., yolo) or accepting a confirmation parameter.
If yolo is false, do not call install_rustup(); instead prompt the user for
consent (via the existing prompt/confirm helper) or return an error instructing
them to re-run with --yolo. Change the signature of ensure_rustup (or read the
shared confirmation state) so the function can access yolo, and only call
install_rustup() when consent is granted or yolo == true; otherwise bail with a
clear message.

---

Nitpick comments:
In `@crates/cli/src/setup/tools.rs`:
- Around line 175-187: The function cargo_bin_path uses deprecated
std::env::home_dir(); replace it with the `home` crate: add home = { workspace =
true } to workspace dependencies and change the call to
home::home_dir().unwrap_or_default() in cargo_bin_path, leaving the existing
logic that builds bin (using cfg!(target_family = "windows") to append ".exe")
and the subsequent
.join(".cargo").join("bin").join(bin).to_string_lossy().into_owned() intact;
this preserves behavior while removing the deprecation.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b735053 and 5d9f0a4.

📒 Files selected for processing (1)
  • crates/cli/src/setup/tools.rs

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
crates/cli/src/setup/module.rs (2)

36-52: Consider checking if the module already exists before generation.

If a user runs module create foo twice, cargo_generate will fail (since overwrite defaults to false), but the error message may be cryptic. A pre-check would give a friendlier message:

Proposed pre-existence check
         if !modules_dir.exists() {
             bail!(
                 "modules directory does not exist at {}. Make sure you are in a workspace initialized with 'init'.",
                 modules_dir.display()
             );
         }
 
+        let target = modules_dir.join(&self.name);
+        if target.exists() {
+            bail!("module '{}' already exists at {}", self.name, target.display());
+        }
+
         // Generate the main module
         self.generate_module("Modules", &self.name)?;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/setup/module.rs` around lines 36 - 52, Before calling
self.generate_module("Modules", &self.name) add a pre-existence check for the
target module directory (e.g., compute let module_path =
modules_dir.join(&self.name) and check module_path.exists()). If it exists,
return an error/bail with a clear, user-friendly message that the module already
exists (mention the module name) and suggest removing it or using an
overwrite/force option; otherwise proceed to call generate_module as before.
This change should be made in the run() function near the modules_dir and
generate_module calls.

16-18: no_sdk field is unused; commented-out code is already stale.

The --no-sdk flag is accepted by the CLI but has no effect since the SDK generation code is entirely commented out. The commented-out code on line 58 also references a 3-parameter generate_module signature that no longer matches the current 2-parameter version, so it can't simply be uncommented.

Consider removing both the no_sdk field and the commented-out block until the SDK feature is ready, to avoid exposing a no-op flag to users.

Also applies to: 54-65

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/setup/module.rs` around lines 16 - 18, The no_sdk flag is
defined but unused; remove the unused struct field `no_sdk` from the CLI args in
module.rs and delete the stale commented-out SDK generation block that
references the old 3-parameter `generate_module` signature so we don't expose a
no-op flag; also search for and remove any help text, tests, or code paths that
reference `--no-sdk` so the CLI help and parsing no longer advertise the flag,
and if/when SDK generation is reintroduced, re-add a properly wired `no_sdk`
check against the current `generate_module` (2-parameter) API.
🤖 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/setup/module.rs`:
- Around line 27-29: The CLI `--subfolder` value (self.subfolder) is defined but
never used because generate_module is called with a hardcoded "Modules" string
and that value is used for auto_path and local path construction; update
generate_module usage to use self.subfolder (or remove the redundant parameter
and reference self.subfolder inside generate_module) so the CLI input is
honored, and reconcile the template name casing/plurality (choose either
"Module" or "Modules" and apply it consistently to auto_path and local path
logic); ensure references to auto_path and any local path construction in
generate_module or its callers use the chosen self.subfolder value.

---

Nitpick comments:
In `@crates/cli/src/setup/module.rs`:
- Around line 36-52: Before calling self.generate_module("Modules", &self.name)
add a pre-existence check for the target module directory (e.g., compute let
module_path = modules_dir.join(&self.name) and check module_path.exists()). If
it exists, return an error/bail with a clear, user-friendly message that the
module already exists (mention the module name) and suggest removing it or using
an overwrite/force option; otherwise proceed to call generate_module as before.
This change should be made in the run() function near the modules_dir and
generate_module calls.
- Around line 16-18: The no_sdk flag is defined but unused; remove the unused
struct field `no_sdk` from the CLI args in module.rs and delete the stale
commented-out SDK generation block that references the old 3-parameter
`generate_module` signature so we don't expose a no-op flag; also search for and
remove any help text, tests, or code paths that reference `--no-sdk` so the CLI
help and parsing no longer advertise the flag, and if/when SDK generation is
reintroduced, re-add a properly wired `no_sdk` check against the current
`generate_module` (2-parameter) API.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5d9f0a4 and e98e57e.

📒 Files selected for processing (1)
  • crates/cli/src/setup/module.rs

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 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/setup/module.rs`:
- Around line 16-17: The struct field local_path in ModuleArgs is missing a doc
comment so the --local-path CLI flag is undocumented; add a /// doc comment
above the local_path field describing its purpose (e.g., "Path to a local
module" or similar) so it appears in --help, keeping the existing attribute
#[arg(long = "local-path", conflicts_with_all = ["git", "branch"])] and the
Option<String> type unchanged.
- Around line 54-88: generate_module currently uses self.path as the generate
destination so cargo_generate creates self.path/self.name (workspace root)
instead of placing the new crate inside modules/ computed in run(); thread the
validated modules_dir into generate_module (either by adding a modules_dir
parameter to generate_module or storing it on the struct) and change the
GenerateArgs destination to Some(modules_dir.clone()) (not
modules_dir.join(name)); also update the success message in run() to display
modules_dir.display() as the creation path; reference generate_module, run,
GenerateArgs, destination, and modules_dir when making the change.
- Around line 72-85: The GenerateArgs struct construction in module.rs omits
no_workspace, causing cargo_generate to try updating the workspace manifest;
update the generate(...) call to set no_workspace: true in the GenerateArgs
literal (alongside existing fields like template_path, destination, name, quiet,
verbose) so it matches init.rs behavior and prevents unintended workspace
Cargo.toml modifications.
- Around line 82-85: The GenerateArgs construction in module.rs sets quiet and
verbose but falls back to GenerateArgs::default(), which leaves
no_workspace=false and allows cargo_generate to modify the workspace Cargo.toml;
update the builder for GenerateArgs used in module.rs to include no_workspace:
true alongside quiet: !self.verbose and verbose: self.verbose so the final args
explicitly disable workspace registration (match the init.rs usage), ensuring
the new module crate is not auto-registered in the workspace.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e98e57e and 4fd8e59.

📒 Files selected for processing (1)
  • crates/cli/src/setup/module.rs

Signed-off-by: Bechma <19294519+Bechma@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
crates/cli/src/setup/module.rs (1)

47-51: ⚠️ Potential issue | 🟡 Minor

Success message shows the parent directory, not the generated module path.

modules_dir.display() resolves to e.g. /workspace/modules, while the module is actually created at /workspace/modules/<name>. The message is therefore misleading.

📝 Proposed fix
-        println!(
-            "Module '{}' created at {}",
-            self.name,
-            modules_dir.display()
-        );
+        println!(
+            "Module '{}' created at {}",
+            self.name,
+            modules_dir.join(&self.name).display()
+        );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/setup/module.rs` around lines 47 - 51, The println! currently
prints modules_dir (parent) instead of the actual created module path, so update
the success message to show the real path by joining the module name to
modules_dir; e.g., compute the module path (modules_dir.join(&self.name) or
reuse an existing module_dir variable) and use module_dir.display() in the
println! while still including self.name in the message.
🧹 Nitpick comments (2)
Cargo.toml (1)

38-41: clippy::nursery is explicitly flagged as unstable — consider cherry-picking instead of enabling the whole group.

The clippy::nursery group contains lints which are buggy or need more work. It is not recommended to enable the whole group, but rather cherry-pick lints that are useful for your code base. Enabling it workspace-wide means any Rust toolchain upgrade can introduce new nursery lints that silently start emitting warnings (or break CI if deny(warnings) is in effect). clippy::pedantic carries the same risk at a lower degree since it's stable but contains some very aggressive lints prone to false positives.

If the intent is to enforce a strict style, prefer listing individual lints explicitly rather than opting into the whole nursery category.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Cargo.toml` around lines 38 - 41, The Cargo.toml currently enables the entire
clippy nursery group under [workspace.lints.clippy] (nursery = { level = "warn",
priority = -1 }), which is unstable and may introduce new/broken lints on
toolchain updates; instead, remove or disable the nursery group and replace it
by listing only the specific clippy lints you want (or keep pedantic if desired)
— update the [workspace.lints.clippy] block to drop nursery and add explicit
lint keys (e.g., add individual entries for any needed nursery lints) while
keeping or adjusting pedantic and struct_excessive_bools as appropriate so CI
won't break on future toolchain changes.
crates/cli/src/setup/module.rs (1)

36-46: modules_dir and modules_path compute the same path independently.

run() builds modules_dir (line 36) for the existence check, then generate_module() re-derives the identical path as modules_path (line 74). Consider passing it as a parameter to avoid the redundant join.

♻️ Proposed refactor
-        self.generate_module()?;
+        self.generate_module(modules_dir.clone())?;
-    fn generate_module(&self) -> anyhow::Result<()> {
+    fn generate_module(&self, modules_path: PathBuf) -> anyhow::Result<()> {
         // ...
-        let modules_path = self.path.join("modules");
         let module_path = modules_path.join(&self.name);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/setup/module.rs` around lines 36 - 46, In run() the
modules_dir is computed and checked for existence, then generate_module()
recomputes the same path as modules_path; change generate_module() to accept the
precomputed modules_dir (or PathBuf) as an argument (update its signature and
all callers) and pass modules_dir from run() so the join isn't performed twice;
update references to modules_path inside generate_module() to use the passed
parameter (modules_dir) to remove the redundant join.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Cargo.toml`:
- Line 28: The workspace declares toml = "1.0.3" which conflicts with
cargo-generate v0.23.7 that requires toml 0.9.x; resolve by either pinning toml
to a 0.9.x range or updating cargo-generate to a version that supports toml 1.x:
open Cargo.toml and change the toml dependency to ~0.9 (e.g., "0.9") to match
cargo-generate, or update the cargo-generate entry (or
toolchain/dev-dependencies referencing cargo-generate) to a newer release that
accepts toml 1.0; ensure you run cargo update and verify the lockfile no longer
contains both toml versions.

In `@crates/cli/src/setup/module.rs`:
- Around line 93-116: The workspace registration is delayed until after optional
SDK generation, risking a partial-failure that leaves the main crate on disk but
not listed in Cargo.toml; after the main module generate(...) call succeeds,
immediately call self.add_modules_to_workspace with the main module path (the
generated vec containing format!("modules/{}", self.name)) to register it before
attempting the SDK-specific logic (the sdk_template branch that calls
generate(GenerateArgs) and fs::remove_dir_all); keep the SDK generation and
removal as-is but ensure failures there do not prevent the workspace update
already performed for the main module.

---

Duplicate comments:
In `@crates/cli/src/setup/module.rs`:
- Around line 47-51: The println! currently prints modules_dir (parent) instead
of the actual created module path, so update the success message to show the
real path by joining the module name to modules_dir; e.g., compute the module
path (modules_dir.join(&self.name) or reuse an existing module_dir variable) and
use module_dir.display() in the println! while still including self.name in the
message.

---

Nitpick comments:
In `@Cargo.toml`:
- Around line 38-41: The Cargo.toml currently enables the entire clippy nursery
group under [workspace.lints.clippy] (nursery = { level = "warn", priority = -1
}), which is unstable and may introduce new/broken lints on toolchain updates;
instead, remove or disable the nursery group and replace it by listing only the
specific clippy lints you want (or keep pedantic if desired) — update the
[workspace.lints.clippy] block to drop nursery and add explicit lint keys (e.g.,
add individual entries for any needed nursery lints) while keeping or adjusting
pedantic and struct_excessive_bools as appropriate so CI won't break on future
toolchain changes.

In `@crates/cli/src/setup/module.rs`:
- Around line 36-46: In run() the modules_dir is computed and checked for
existence, then generate_module() recomputes the same path as modules_path;
change generate_module() to accept the precomputed modules_dir (or PathBuf) as
an argument (update its signature and all callers) and pass modules_dir from
run() so the join isn't performed twice; update references to modules_path
inside generate_module() to use the passed parameter (modules_dir) to remove the
redundant join.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4fd8e59 and de3a0ac.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • Cargo.toml
  • crates/cli/Cargo.toml
  • crates/cli/src/setup/init.rs
  • crates/cli/src/setup/module.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/cli/src/setup/init.rs

Signed-off-by: Bechma <19294519+Bechma@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/module-parser/src/config.rs (1)

17-17: ⚠️ Potential issue | 🟠 Major

clippy::single_char_pattern – use char literals instead of single-char strings.

"-" and "_" should be '-' and '_' to satisfy the hard Clippy rules this PR is adding.

♻️ Proposed fix
-            let package = package.replace("-", "_");
+            let package = package.replace('-', '_');
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/module-parser/src/config.rs` at line 17, The code uses
single-character string literals in package.replace("-", "_") which triggers
clippy::single_char_pattern; change the call to use the char overload by
replacing the string literals with char literals so the package variable
assignment becomes package.replace('-', '_') (locate the line that assigns to
the package variable and update the replace call accordingly).
♻️ Duplicate comments (2)
crates/cli/src/setup/tools.rs (2)

65-85: ⚠️ Potential issue | 🟡 Minor

--all is effectively a no-op in tool selection.

Line 84 returns all tools whenever --install is absent, so --all does not alter behavior. Either require explicit selection (--all/--install) or update the flag/help semantics to “default: all”.

Suggested fix (explicit selection)
 fn resolve_tools(&self) -> anyhow::Result<Vec<&'static Tool>> {
+    if self.all {
+        return Ok(TOOLS.iter().collect());
+    }
     if let Some(names) = &self.install {
         let mut tools = Vec::with_capacity(names.len());
         for name in names {
             let tool = TOOLS
                 .iter()
                 .find(|t| t.name == name.as_str())
                 .with_context(|| {
                     format!(
                         "unknown tool '{}'. known tools: {}",
                         name,
                         TOOLS.iter().map(|t| t.name).collect::<Vec<_>>().join(", ")
                     )
                 })?;
             tools.push(tool);
         }
         return Ok(tools);
     }

-    Ok(TOOLS.iter().collect())
+    bail!("no tools selected; use --all or --install")
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/setup/tools.rs` around lines 65 - 85, resolve_tools currently
ignores an explicit --all flag because it returns all TOOLS when self.install is
None; update resolve_tools to honor an explicit selection by first checking for
self.install (Vec names) then for a boolean self.all (or require one of them)
and only return Ok(TOOLS.iter().collect()) when self.all is true; if neither
self.install nor self.all is set, return an error explaining that the caller
must pass --install or --all. Ensure you reference resolve_tools, self.install,
self.all (or equivalent flag), and TOOLS when making the change so the logic
enforces explicit selection.

88-89: ⚠️ Potential issue | 🟡 Minor

Rustup bootstrap bypasses confirmation controls.

Line 161 auto-installs rustup even when yolo is false. This is inconsistent with the rest of the prompt/consent flow and can surprise users.

Suggested fix (thread `yolo` into rustup bootstrap)
-        ensure_rustup()?;
+        ensure_rustup(self.yolo)?;
...
-        ensure_rustup()?;
+        ensure_rustup(self.yolo)?;
...
-fn ensure_rustup() -> anyhow::Result<()> {
+fn ensure_rustup(yolo: bool) -> anyhow::Result<()> {
     if is_installed("rustup") {
         return Ok(());
     }

+    if !yolo && !confirm("rustup is required. Install it now?")? {
+        bail!("rustup is required to continue");
+    }
     println!("rustup is not installed. Attempting to install it...");
     install_rustup().context("failed to install rustup")?;

Also applies to: 119-120, 156-163

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/setup/tools.rs` around lines 88 - 89, The ensure_rustup
function currently auto-installs rustup without checking the user confirmation
flag; change ensure_rustup to accept a yolo: bool parameter (e.g., fn
ensure_rustup(yolo: bool) -> Result<...>) and thread that flag into the internal
rustup bootstrap/installer call so it only auto-installs when yolo is true;
update every call site that invoked ensure_rustup() (the callers around the
other mentioned blocks) to pass the local yolo variable through (e.g.,
ensure_rustup(yolo)?), and ensure the internal prompt/confirmation code inside
ensure_rustup uses yolo to skip or enforce prompting accordingly.
🧹 Nitpick comments (1)
crates/module-parser/src/config.rs (1)

11-11: Return type should use the new CargoTomlDependencies alias.

create_dependencies returns HashMap<String, ConfigModuleMetadata>, which is the exact type that CargoTomlDependencies aliases. Using the raw type here is inconsistent with the alias introduced below and in module.rs.

♻️ Proposed fix
-    pub fn create_dependencies(self) -> anyhow::Result<HashMap<String, ConfigModuleMetadata>> {
+    pub fn create_dependencies(self) -> anyhow::Result<CargoTomlDependencies> {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/module-parser/src/config.rs` at line 11, The function
create_dependencies currently returns anyhow::Result<HashMap<String,
ConfigModuleMetadata>>; change its signature to return
anyhow::Result<CargoTomlDependencies> (the alias introduced for HashMap<String,
ConfigModuleMetadata>) and update any local type annotations or casts within
create_dependencies to use CargoTomlDependencies instead of the raw HashMap type
so the function and its callers (e.g., places referencing create_dependencies in
module.rs) consistently use the alias.
🤖 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/setup/module.rs`:
- Around line 204-230: In the dependency loop handling ConfigModuleMetadata,
path and deps are never written into dep_table; update the block that builds
dep_table (the code around dep_table, the handling of metadata.version/features,
and before workspace_deps.insert) to also: if let Some(path) = metadata.path {
dep_table.insert("path", path.into()); } and if !metadata.deps.is_empty() { let
deps_array: toml_edit::Array =
metadata.deps.into_iter().map(toml_edit::Value::from).collect();
dep_table.insert("deps", toml_edit::Value::Array(deps_array)); } so the path and
deps from ConfigModuleMetadata are preserved when inserting into workspace_deps.
- Around line 132-138: Update the error messages in function get_cargo_toml so
they don't always say "workspace Cargo.toml": use the actual cargo_toml_path (or
path) in the context strings—e.g., change the fs::read_to_string context and the
parse context to include cargo_toml_path.display() (or format!("Cargo.toml at
{}", cargo_toml_path.display())) so callers of get_cargo_toml for module paths
show the correct file location; keep the logic in get_cargo_toml, only change
the context messages.
- Around line 140-145: The get_dependencies function currently bails with
context("dependencies section not found or not a table") when a Cargo.toml
legitimately has no [dependencies], causing valid crates to error; change the
logic so that when doc.get("dependencies") is None you treat it as an empty
table and return an empty CargoTomlDependencies instead of failing. In practice,
remove the .context(...) check and branch on the presence of
doc.get("dependencies").and_then(|d| d.as_table()) — if Some(table) parse as
before, if None return Ok(CargoTomlDependencies::default() or an empty map) so
templates with no dependencies succeed; update references to dependencies
parsing in get_dependencies to handle an empty table case.
- Around line 123-124: The code reads Cargo.toml from the un-rendered template
(sdk_template) instead of the freshly generated crate; update the call that
builds dependencies so it loads Cargo.toml from the generated output directory
produced by generate() (use the generated crate path/variable returned by
generate() or the module's sdk output path) rather than sdk_template: replace
the use of sdk_template in the call to get_cargo_toml/get_dependencies with the
generated crate path variable (keeping fs::remove_dir_all(sdk_template) to clean
up the template afterwards) so get_cargo_toml(...) reads the rendered
Cargo.toml.

---

Outside diff comments:
In `@crates/module-parser/src/config.rs`:
- Line 17: The code uses single-character string literals in
package.replace("-", "_") which triggers clippy::single_char_pattern; change the
call to use the char overload by replacing the string literals with char
literals so the package variable assignment becomes package.replace('-', '_')
(locate the line that assigns to the package variable and update the replace
call accordingly).

---

Duplicate comments:
In `@crates/cli/src/setup/tools.rs`:
- Around line 65-85: resolve_tools currently ignores an explicit --all flag
because it returns all TOOLS when self.install is None; update resolve_tools to
honor an explicit selection by first checking for self.install (Vec names) then
for a boolean self.all (or require one of them) and only return
Ok(TOOLS.iter().collect()) when self.all is true; if neither self.install nor
self.all is set, return an error explaining that the caller must pass --install
or --all. Ensure you reference resolve_tools, self.install, self.all (or
equivalent flag), and TOOLS when making the change so the logic enforces
explicit selection.
- Around line 88-89: The ensure_rustup function currently auto-installs rustup
without checking the user confirmation flag; change ensure_rustup to accept a
yolo: bool parameter (e.g., fn ensure_rustup(yolo: bool) -> Result<...>) and
thread that flag into the internal rustup bootstrap/installer call so it only
auto-installs when yolo is true; update every call site that invoked
ensure_rustup() (the callers around the other mentioned blocks) to pass the
local yolo variable through (e.g., ensure_rustup(yolo)?), and ensure the
internal prompt/confirmation code inside ensure_rustup uses yolo to skip or
enforce prompting accordingly.

---

Nitpick comments:
In `@crates/module-parser/src/config.rs`:
- Line 11: The function create_dependencies currently returns
anyhow::Result<HashMap<String, ConfigModuleMetadata>>; change its signature to
return anyhow::Result<CargoTomlDependencies> (the alias introduced for
HashMap<String, ConfigModuleMetadata>) and update any local type annotations or
casts within create_dependencies to use CargoTomlDependencies instead of the raw
HashMap type so the function and its callers (e.g., places referencing
create_dependencies in module.rs) consistently use the alias.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between de3a0ac and 5471f21.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • Cargo.toml
  • crates/cli/src/setup/module.rs
  • crates/cli/src/setup/tools.rs
  • crates/module-parser/src/config.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • Cargo.toml

Signed-off-by: Bechma <19294519+Bechma@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (3)
crates/cli/src/setup/module.rs (3)

150-156: ⚠️ Potential issue | 🟡 Minor

Use the concrete Cargo.toml path in parse/read error context.

Lines 153 and 155 currently report the directory path (path.display()), which makes debugging harder than reporting the actual Cargo.toml file path.

💡 Proposed fix
 fn get_cargo_toml(path: &Path) -> anyhow::Result<toml_edit::DocumentMut> {
     let cargo_toml_path = path.join("Cargo.toml");
     fs::read_to_string(&cargo_toml_path)
-        .with_context(|| format!("can't read {}", path.display()))?
+        .with_context(|| format!("can't read {}", cargo_toml_path.display()))?
         .parse::<toml_edit::DocumentMut>()
-        .with_context(|| format!("can't parse {}", path.display()))
+        .with_context(|| format!("can't parse {}", cargo_toml_path.display()))
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/setup/module.rs` around lines 150 - 156, The error contexts in
get_cargo_toml report the directory path instead of the actual Cargo.toml file;
change the with_context closures to reference the concrete cargo_toml_path (use
cargo_toml_path.display()) so both the read_to_string and parse error messages
include the full Cargo.toml file path for easier debugging.

57-62: ⚠️ Potential issue | 🟠 Major

Register the main module before SDK steps to prevent orphaned workspace state.

Line 57 waits for all generation work to finish before mutating Cargo.toml at Lines 60-61. If SDK generation/cleanup fails later (Lines 115-133), the main crate is already created on disk but never added to workspace.members, and reruns fail on “already exists”.

Also applies to: 93-136

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/setup/module.rs` around lines 57 - 62, The main crate is being
created on disk before updating the workspace, which can leave an orphaned crate
if subsequent SDK generation/cleanup (the later SDK steps) fails; move the
workspace registration so add_modules_to_workspace(&mut doc, modules)? is called
immediately after let (modules, dependencies) = self.generate_module()? (and
before any SDK generation/cleanup), then proceed with
add_dependencies_to_workspace(&mut doc, dependencies)?. Ensure the change is
applied both in the earlier block and the duplicate block around the SDK
generation/cleanup so the main module is always added to workspace.members
before any further operations.

116-133: ⚠️ Potential issue | 🟠 Major

Read SDK dependencies from the generated SDK crate, not the SDK template directory.

Line 131 currently reads Cargo.toml from sdk_template (the template under modules/<name>/sdk) instead of the generated output at modules/<name>-sdk, so parsed dependencies can be stale/unrendered.

💡 Proposed fix
         if sdk_template.exists() {
             let name = format!("{}-sdk", self.name);
             generated.push(format!("modules/{name}"));
             generate(GenerateArgs {
                 template_path: TemplatePath {
                     path: Some(sdk_template.to_string_lossy().to_string()),
                     ..TemplatePath::default()
                 },
                 destination: Some(modules_path),
-                name: Some(name),
+                name: Some(name.clone()),
                 quiet: !self.verbose,
                 verbose: self.verbose,
                 no_workspace: true,
                 ..GenerateArgs::default()
             })
             .with_context(|| format!("can't generate sdk module '{}-sdk'", self.name))?;
-            dependencies.extend(get_cargo_toml(&sdk_template).map(|x| get_dependencies(&x))?);
+            let sdk_output_path = self.path.join("modules").join(&name);
+            dependencies.extend(get_cargo_toml(&sdk_output_path).map(|x| get_dependencies(&x))?);
             fs::remove_dir_all(sdk_template)
                 .with_context(|| format!("can't remove sdk template for module '{}'", self.name))?;
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/cli/src/setup/module.rs` around lines 116 - 133, The code reads
Cargo.toml from the template directory (sdk_template) instead of the generated
crate, causing stale/unrendered dependencies; after calling generate(...) use
the generated crate path (the destination modules_path joined with name, where
name = format!("{}-sdk", self.name)) when invoking get_cargo_toml and then
get_dependencies, and only afterward call fs::remove_dir_all(sdk_template) so
you parse the rendered Cargo.toml from the generated module rather than the
template.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@crates/cli/src/setup/module.rs`:
- Around line 150-156: The error contexts in get_cargo_toml report the directory
path instead of the actual Cargo.toml file; change the with_context closures to
reference the concrete cargo_toml_path (use cargo_toml_path.display()) so both
the read_to_string and parse error messages include the full Cargo.toml file
path for easier debugging.
- Around line 57-62: The main crate is being created on disk before updating the
workspace, which can leave an orphaned crate if subsequent SDK
generation/cleanup (the later SDK steps) fails; move the workspace registration
so add_modules_to_workspace(&mut doc, modules)? is called immediately after let
(modules, dependencies) = self.generate_module()? (and before any SDK
generation/cleanup), then proceed with add_dependencies_to_workspace(&mut doc,
dependencies)?. Ensure the change is applied both in the earlier block and the
duplicate block around the SDK generation/cleanup so the main module is always
added to workspace.members before any further operations.
- Around line 116-133: The code reads Cargo.toml from the template directory
(sdk_template) instead of the generated crate, causing stale/unrendered
dependencies; after calling generate(...) use the generated crate path (the
destination modules_path joined with name, where name = format!("{}-sdk",
self.name)) when invoking get_cargo_toml and then get_dependencies, and only
afterward call fs::remove_dir_all(sdk_template) so you parse the rendered
Cargo.toml from the generated module rather than the template.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5471f21 and cfdff44.

📒 Files selected for processing (2)
  • crates/cli/src/setup/module.rs
  • crates/cli/src/setup/tools.rs

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.

1 participant