Skip to content

Conversation

@Sahilbhatane
Copy link
Collaborator

@Sahilbhatane Sahilbhatane commented Dec 7, 2025

Summary

  • The --simulate flag enables preview mode for installations, showing what would be installed without making any changes. This helps users:
  • Preview what would be installed with real package sizes from LLM
  • Check actual disk space availability on your system
  • Verify system compatibility before installation
  • See package information quickly
# Simulate Docker installation
cortex install docker --simulate

# Simulate Python installation
cortex install python --simulate

# Simulate nginx installation
cortex install nginx --simulate

Type of Change

  • Bug fix
  • New feature
  • Documentation update

Checklist

Testing

can be testes with pytest or simply run test_preflight.py for this implementation test only or can run this command to check it as user perspective -

# Simulate Docker installation
cortex install docker --simulate

# Simulate Python installation
cortex install python --simulate

# Simulate nginx installation
cortex install nginx --simulate

output example -

🔍 Simulation mode: No changes will be made

System Information:
  OS: Windows 10.0.26200
  Kernel: 11
  Architecture: AMD64

Would install:
  - containerd 1.4.3-1 (80 MB)

Total download: 80 MB
Disk space required: 240 MB
Disk space available: 117 GB ✓

Potential issues: None detected

Note -

make sure to test it with API and without API for both scenarios.

video

https://drive.google.com/file/d/12duXG6eFfzVUKfpZxEyLClhEsw13a54s/view?usp=sharing

Summary by CodeRabbit

  • New Features

    • Added an installation "simulate" mode (CLI flag) that runs a full preflight check, prints a human-readable report, and returns an exit code.
    • Introduced a Preflight system checker to assess OS, disk, packages, services, and installation requirements.
  • Documentation

    • Added a Simulation Mode guide with usage examples, API-key notes, expected outputs, and preflight behavior.
  • Tests

    • Added tests for preflight checks, report formatting, and CLI simulate behavior.
  • Chores

    • Added PyYAML to project requirements.

✏️ Tip: You can customize this high-level summary in your review settings.

Copilot AI review requested due to automatic review settings December 7, 2025 12:38
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 7, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds a Simulation Mode to the CLI: --simulate invokes CortexCLI._run_simulation(), which instantiates PreflightChecker to inspect OS, disk, packages (with optional LLM fallback), builds a PreflightReport, prints a formatted report, and returns a success/failure exit code without performing installations.

Changes

Cohort / File(s) Summary
CLI Simulation Integration
cortex/cli.py, test/test_cli.py
CortexCLI.install() signature extended with simulate: bool = False; added _run_simulation(self, software: str) -> int; CLI parser accepts --simulate and main passes flag; tests updated to expect simulate arg.
Preflight Checker Implementation
cortex/preflight_checker.py
New dataclasses DiskInfo, PackageInfo, ServiceInfo, PreflightReport; new PreflightChecker(api_key: Optional[str]=None, provider: str='openai') with OS/distro detection, disk/package/service checks, Docker/containerd helpers, optional LLM metadata fallback, calculate_requirements(), run_all_checks(), plus format_report() and export_report().
Documentation
docs/SIMULATION_MODE.md
New documentation describing Simulation Mode usage, examples (with/without API key), checks performed, expected outputs, and report export guidance.
Dependencies
requirements.txt
Added PyYAML dependency.
Preflight Tests
test/test_preflight_checker.py
New comprehensive tests for PreflightChecker (OS info, disk, package detection, full run, report formatting) and CLI simulate/dry-run interactions with mocks.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant CLI as cortex/cli.py
    participant Checker as PreflightChecker
    participant Host as Host System
    participant LLM as LLM Client
    participant Reporter as format_report

    User->>CLI: run "cortex install <software> --simulate"
    CLI->>Checker: instantiate (api_key, provider)
    CLI->>Checker: run_all_checks(software)
    Checker->>Host: detect OS / distro / kernel
    Host-->>Checker: os info
    Checker->>Host: check disk paths, packages, services
    Host-->>Checker: DiskInfo / PackageInfo / ServiceInfo
    alt provider/API key available
        Checker->>LLM: request package metadata (sizes, config)
        LLM-->>Checker: metadata / suggestions
    end
    Checker->>Checker: calculate_requirements()
    Checker-->>CLI: PreflightReport
    CLI->>Reporter: format_report(report, software)
    Reporter-->>CLI: formatted text
    CLI->>User: print report and exit code (0 success / 1 failure)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Files needing extra attention:
    • cortex/preflight_checker.py — OS/distro detection, disk-space calculations, command execution wrappers, LLM integration and error handling.
    • cortex/cli.py — simulation control flow, exception handling, and integration with report formatting/export.
    • test/test_preflight_checker.py — validity of mocks and coverage of edge cases for different platforms.

Possibly related PRs

  • cortexlinux/cortex#190 — modifies CortexCLI.install and introduces simulation-related control flow similar to this PR; strong overlap in CLI behavior and Preflight integration.

Suggested reviewers

  • dhvll

Poem

🐇 I hop and peek at disks and gears,
I whisper plans — no need for fears.
I list what comes and what will fit,
A careful scout with tiny wit.
Snap a carrot, read my bit!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.74% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title mentions issue #103 but the phrasing 'fix' suggests a bug resolution when this is a new feature implementation.
Description check ✅ Passed The description covers the main feature with examples, testing instructions, and output samples, though it doesn't follow the required template format with 'Related Issue' section explicitly.
Linked Issues check ✅ Passed The implementation addresses all core requirements from issue #103: simulation mode with --simulate flag, package display with sizes, disk space prediction vs available, and comprehensive tests; configuration preview is partially covered via suggestions field.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the simulation mode feature. No unrelated or out-of-scope changes detected in the codebase modifications.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 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
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

🧹 Nitpick comments (9)
test/test_preflight_checker.py (2)

54-54: Use assertGreater for clearer failure messages.

Per static analysis, prefer assertGreater over assertTrue(len(...) > 0) for better error messages on failure.

-        self.assertTrue(len(disk_info) > 0)
+        self.assertGreater(len(disk_info), 0)

56-59: Redundant assertion—consider simplifying.

The assertion cwd_checked or len(disk_info) > 0 is always true if line 54 passes, making it ineffective at verifying the current directory is actually included. Consider asserting cwd_checked directly if that's the intent:

-        # Check that current directory is included
-        cwd = os.getcwd()
-        cwd_checked = any(d.path == cwd or cwd.startswith(d.path) for d in disk_info)
-        self.assertTrue(cwd_checked or len(disk_info) > 0)
+        # Check that current directory or a parent path is included
+        cwd = os.getcwd()
+        cwd_checked = any(d.path == cwd or cwd.startswith(d.path) for d in disk_info)
+        self.assertTrue(cwd_checked, "Current directory should be covered by disk checks")
docs/SIMULATION_MODE.md (1)

37-53: Add language specifiers to fenced code blocks.

Several code blocks showing example CLI output are missing language specifiers, which affects syntax highlighting and linting. While these are output examples (not shell commands), using text or console would satisfy the linter.

-```
+```text
 🔍 Simulation mode: No changes will be made

Apply the same fix to code blocks at lines 57, 116, and 124.

cortex/cli.py (2)

216-218: Use explicit conversion flag in f-string.

Per linting (Ruff RUF010), prefer explicit conversion flag over str() call.

-            self._print_error(f"Simulation failed: {str(e)}")
+            self._print_error(f"Simulation failed: {e!s}")

23-23: export_report is imported but unused.

The export_report function is imported but not used anywhere in cli.py. Consider removing it unless there are plans to add report export functionality soon.

-from cortex.preflight_checker import PreflightChecker, format_report, export_report
+from cortex.preflight_checker import PreflightChecker, format_report
cortex/preflight_checker.py (4)

79-81: Annotate class-level mutable attributes with ClassVar.

DISK_CHECK_PATHS is a mutable list at class level. Per Ruff (RUF012), annotate with ClassVar to indicate it's not an instance attribute and prevent accidental mutation issues.

+from typing import ClassVar
+
 class PreflightChecker:
     # Paths to check for disk space
-    DISK_CHECK_PATHS = ['/', '/var/lib/docker', '/opt']
+    DISK_CHECK_PATHS: ClassVar[List[str]] = ['/', '/var/lib/docker', '/opt']

109-123: Avoid shell=True to prevent potential command injection.

_run_shell_command uses shell=True (line 114), and _get_filesystem_type passes a path into a shell command. While current paths come from trusted sources, this pattern is fragile. Consider using subprocess without shell:

 def _get_filesystem_type(self, path: str) -> str:
     """Get filesystem type for a path on Linux"""
-    success, output = self._run_shell_command(f"df -T '{path}' | tail -1 | awk '{{print $2}}'")
-    if success and output:
-        return output
+    success, output = self._run_command(['df', '-T', path])
+    if success and output:
+        lines = output.strip().split('\n')
+        if len(lines) >= 2:
+            # Parse second line, second column (filesystem type)
+            parts = lines[1].split()
+            if len(parts) >= 2:
+                return parts[1]
     return 'unknown'

This avoids shell injection risks entirely.

Also applies to: 256-261


526-588: Consider extracting helper functions to reduce complexity.

format_report has cognitive complexity of 25 (exceeds the 15 threshold). While the logic is linear, extracting section formatters would improve maintainability:

def _format_system_info(report: PreflightReport) -> List[str]:
    """Format system information section."""
    lines = ["System Information:"]
    lines.append(f"  OS: {report.os_info.get('distro', 'Unknown')} {report.os_info.get('distro_version', '')}")
    if report.kernel_info.get('version'):
        lines.append(f"  Kernel: {report.kernel_info.get('version')}")
    if report.cpu_arch:
        lines.append(f"  Architecture: {report.cpu_arch}")
    return lines

def _format_packages_section(report: PreflightReport, software: str, using_estimates: bool) -> List[str]:
    # ... similar extraction for packages section
    pass

Then compose them in format_report. This can be deferred if time-constrained.


168-169: Consider logging silently swallowed exceptions.

Multiple try-except-pass blocks silently swallow exceptions (lines 168, 240, 369). While graceful fallbacks are appropriate for preflight checks, consider logging at DEBUG level for troubleshooting:

import logging
logger = logging.getLogger(__name__)

# Then in exception handlers:
except Exception as e:
    logger.debug(f"Failed to get distro info: {e}")

This maintains the graceful degradation while providing visibility for debugging.

Also applies to: 240-241, 369-371

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c04485e and 32a52bc.

📒 Files selected for processing (6)
  • cortex/cli.py (6 hunks)
  • cortex/preflight_checker.py (1 hunks)
  • docs/SIMULATION_MODE.md (1 hunks)
  • requirements.txt (1 hunks)
  • test/test_cli.py (1 hunks)
  • test/test_preflight_checker.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
test/test_cli.py (1)
cortex/cli.py (1)
  • main (519-607)
cortex/cli.py (1)
cortex/preflight_checker.py (4)
  • PreflightChecker (72-523)
  • format_report (526-588)
  • export_report (591-605)
  • run_all_checks (500-523)
cortex/preflight_checker.py (1)
LLM/interpreter.py (1)
  • CommandInterpreter (12-158)
🪛 GitHub Check: SonarCloud Code Analysis
cortex/cli.py

[failure] 65-65: Refactor this function to reduce its Cognitive Complexity from 45 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZr40lwtv78fvmSAsNj6&open=AZr40lwtv78fvmSAsNj6&pullRequest=264

test/test_preflight_checker.py

[warning] 54-54: Consider using "assertGreater" instead.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZr40l00v78fvmSAsNkA&open=AZr40l00v78fvmSAsNkA&pullRequest=264

cortex/preflight_checker.py

[warning] 469-469: Remove the unused local variable "software_lower".

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZr40l0pv78fvmSAsNj8&open=AZr40l0pv78fvmSAsNj8&pullRequest=264


[warning] 529-529: Add replacement fields or use a normal string instead of an f-string.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZr40l0pv78fvmSAsNj-&open=AZr40l0pv78fvmSAsNj-&pullRequest=264


[warning] 321-321: Remove the unused local variable "distro".

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZr40l0pv78fvmSAsNj7&open=AZr40l0pv78fvmSAsNj7&pullRequest=264


[warning] 544-544: Add replacement fields or use a normal string instead of an f-string.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZr40l0pv78fvmSAsNj_&open=AZr40l0pv78fvmSAsNj_&pullRequest=264


[failure] 526-526: Refactor this function to reduce its Cognitive Complexity from 25 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZr40l0pv78fvmSAsNj9&open=AZr40l0pv78fvmSAsNj9&pullRequest=264

🪛 markdownlint-cli2 (0.18.1)
docs/SIMULATION_MODE.md

37-37: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


57-57: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


116-116: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


124-124: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.7)
cortex/cli.py

214-214: Consider moving this statement to an else block

(TRY300)


216-216: Do not catch blind exception: Exception

(BLE001)


217-217: Use explicit conversion flag

Replace with conversion flag

(RUF010)

cortex/preflight_checker.py

80-80: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)


95-95: subprocess call: check for execution of untrusted input

(S603)


106-106: Do not catch blind exception: Exception

(BLE001)


112-112: subprocess call with shell=True identified, security issue

(S602)


122-122: Do not catch blind exception: Exception

(BLE001)


168-169: try-except-pass detected, consider logging the exception

(S110)


168-168: Do not catch blind exception: Exception

(BLE001)


240-241: try-except-pass detected, consider logging the exception

(S110)


240-240: Do not catch blind exception: Exception

(BLE001)


297-297: Consider moving this statement to an else block

(TRY300)


298-298: Do not catch blind exception: Exception

(BLE001)


308-309: try-except-pass detected, consider logging the exception

(S110)


308-308: Do not catch blind exception: Exception

(BLE001)


321-321: Local variable distro is assigned to but never used

Remove assignment to unused variable distro

(F841)


369-371: try-except-pass detected, consider logging the exception

(S110)


369-369: Do not catch blind exception: Exception

(BLE001)


469-469: Local variable software_lower is assigned to but never used

Remove assignment to unused variable software_lower

(F841)


529-529: f-string without any placeholders

Remove extraneous f prefix

(F541)


544-544: f-string without any placeholders

Remove extraneous f prefix

(F541)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Agent
🔇 Additional comments (7)
test/test_cli.py (1)

181-181: LGTM!

The test assertions correctly verify that simulate=False is passed by default when the --simulate flag is not provided, aligning with the updated CortexCLI.install signature.

Also applies to: 189-189, 197-197

test/test_preflight_checker.py (1)

164-197: Well-structured integration tests for simulate flag.

The CLI integration tests properly mock PreflightChecker, verify the --simulate flag parsing, and confirm the correct parameters are passed to CortexCLI.install. Good coverage for the new feature.

docs/SIMULATION_MODE.md (1)

1-228: Comprehensive documentation for the simulation feature.

The documentation thoroughly covers usage, outputs, API reference, and the distinction from --dry-run. This aligns well with the acceptance criteria from Issue #103.

cortex/cli.py (1)

553-553: CLI argument wiring is correct.

The --simulate flag is properly added to the argument parser and correctly passed through to CortexCLI.install. The implementation aligns with the documented behavior.

Also applies to: 590-590

cortex/preflight_checker.py (2)

20-69: Well-structured dataclasses for preflight reporting.

The dataclasses are correctly defined with appropriate type hints and use field(default_factory=...) for mutable defaults, avoiding the common pitfall of shared mutable state.


284-311: LLM client fallback logic is well-designed.

The fallback from primary to secondary LLM provider (OpenAI ↔ Claude) provides good resilience. The implementation handles failures gracefully and falls back to estimates when no LLM is available.

requirements.txt (1)

9-9: Pin PyYAML version and verify its necessity.

PyYAML is added without version pinning, which can cause reproducibility issues. Additionally, PyYAML is not imported or used in the new preflight checker or CLI changes—the export_report function uses JSON, not YAML.

If PyYAML is needed, pin it like other dependencies:

-PyYAML
+PyYAML>=6.0.0

Otherwise, consider removing this dependency if it's not actively used in the codebase.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements a simulation mode for Cortex installations (Issue #103), adding a --simulate flag that allows users to preview what would be installed without making changes. The feature performs real system checks and optionally queries LLMs for accurate package information.

Key Changes

  • Added preflight checking system that performs real-time OS detection, disk space analysis, and package status verification
  • Integrated optional LLM querying (OpenAI/Anthropic) to fetch accurate package sizes with automatic fallback to estimates when no API key is provided
  • Extended CLI with --simulate flag that takes precedence over other execution flags

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 24 comments.

Show a summary per file
File Description
cortex/preflight_checker.py Core preflight checking implementation with system detection, disk analysis, and LLM integration for package information
cortex/cli.py Added --simulate flag support and _run_simulation() method to handle simulation mode execution
test/test_preflight_checker.py Comprehensive unit tests for preflight checker functionality and CLI integration
test/test_cli.py Updated existing tests to include the new simulate parameter in assertions
docs/SIMULATION_MODE.md Complete documentation covering usage, features, API reference, and differences from --dry-run
requirements.txt Added PyYAML dependency (already used elsewhere in codebase)

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

Copy link
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: 0

♻️ Duplicate comments (1)
cortex/preflight_checker.py (1)

527-527: Remove extraneous f prefix from string without placeholders.

This was flagged in a previous review. The f-string on line 527 has no placeholders.

🧹 Nitpick comments (7)
cortex/preflight_checker.py (5)

79-81: Annotate mutable class attributes with ClassVar.

DISK_CHECK_PATHS and MIN_DISK_SPACE_MB are class-level constants that shouldn't be instance attributes. Annotating them with ClassVar makes intent clearer and satisfies static analysis.

+from typing import List, Dict, Optional, Tuple, ClassVar
 ...
 class PreflightChecker:
     ...
     # Paths to check for disk space
-    DISK_CHECK_PATHS = ['/', '/var/lib/docker', '/opt']
-    MIN_DISK_SPACE_MB = 500
+    DISK_CHECK_PATHS: ClassVar[List[str]] = ['/', '/var/lib/docker', '/opt']
+    MIN_DISK_SPACE_MB: ClassVar[int] = 500

168-169: Consider logging exceptions instead of silently ignoring them.

Multiple try-except-pass blocks throughout the file (lines 168, 240, 308, 368) silently swallow exceptions. While this is acceptable for non-critical paths, consider adding debug logging to aid troubleshooting.

+import logging
+
+logger = logging.getLogger(__name__)
 ...
             except Exception:
-                pass
+                logger.debug("Failed to read /etc/os-release", exc_info=True)

293-311: Fallback logic imports CommandInterpreter twice.

The import statement from LLM.interpreter import CommandInterpreter appears both at line 295 and line 305. Since the import is at module-level scope within the method, the second import is redundant but harmless.

     def _get_llm_client(self):
         """Lazy initialize LLM client with fallback"""
         if self._llm_client is not None:
             return self._llm_client
         
         if not self.api_key:
             return None
         
+        # Import once for both primary and fallback
+        try:
+            sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
+            from LLM.interpreter import CommandInterpreter
+        except ImportError:
+            return None
+        
         # Try to initialize with primary provider
         try:
-            sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
-            from LLM.interpreter import CommandInterpreter
             self._llm_client = CommandInterpreter(api_key=self.api_key, provider=self.provider)
             return self._llm_client
         except Exception:
             # Fallback to other provider
             try:
                 fallback_provider = 'claude' if self.provider == 'openai' else 'openai'
                 fallback_key = os.environ.get('ANTHROPIC_API_KEY' if fallback_provider == 'claude' else 'OPENAI_API_KEY')
                 if fallback_key:
-                    from LLM.interpreter import CommandInterpreter
                     self._llm_client = CommandInterpreter(api_key=fallback_key, provider=fallback_provider)
                     return self._llm_client
             except Exception:
                 pass
         
         return None

466-485: Unused software parameter in calculate_requirements.

The software parameter is never used in this method. Either remove it or use it for software-specific calculations.

-    def calculate_requirements(self, software: str) -> None:
+    def calculate_requirements(self) -> None:
         """Calculate installation requirements based on software to install"""

Then update the call site at line 519:

-        self.calculate_requirements(software)
+        self.calculate_requirements()

524-586: High cognitive complexity in format_report function.

SonarCloud flags this function with cognitive complexity of 25 (allowed: 15). Consider extracting helper functions for each section (system info, packages, disk space, config changes, issues).

Example extraction:

def _format_system_info(report: PreflightReport) -> List[str]:
    """Format system information section."""
    lines = ["System Information:"]
    lines.append(f"  OS: {report.os_info.get('distro', 'Unknown')} {report.os_info.get('distro_version', '')}")
    if report.kernel_info.get('version'):
        lines.append(f"  Kernel: {report.kernel_info.get('version')}")
    if report.cpu_arch:
        lines.append(f"  Architecture: {report.cpu_arch}")
    return lines

def _format_packages_section(report: PreflightReport, software: str, using_estimates: bool) -> List[str]:
    """Format packages to install section."""
    # ... extracted logic
cortex/cli.py (2)

196-218: Simulation method addresses previous review feedback.

The previous review flagged that _get_api_key() would print an error when no key exists. This is now correctly handled by using os.environ.get() directly (line 200), which silently returns None when no key is set.

One minor improvement per static analysis - use explicit conversion flag in the f-string:

         except Exception as e:
-            self._print_error(f"Simulation failed: {str(e)}")
+            self._print_error(f"Simulation failed: {e!s}")
             return 1

65-194: Very high cognitive complexity in install method.

SonarCloud flags cognitive complexity of 45 (allowed: 15). While the simulation changes are minimal (lines 66-68), this method was already complex. Consider extracting the execution logic into separate helper methods in a follow-up.

Potential extraction points:

  • _execute_installation(commands, software, history, install_id) for the execute block (lines 121-173)
  • _record_installation_start(history, commands, execute, dry_run) for history setup
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 32a52bc and 91d4b9b.

📒 Files selected for processing (2)
  • cortex/cli.py (6 hunks)
  • cortex/preflight_checker.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
cortex/cli.py (1)
cortex/preflight_checker.py (4)
  • PreflightChecker (72-521)
  • format_report (524-586)
  • export_report (589-600)
  • run_all_checks (498-521)
cortex/preflight_checker.py (1)
LLM/interpreter.py (1)
  • CommandInterpreter (12-158)
🪛 GitHub Check: SonarCloud Code Analysis
cortex/cli.py

[failure] 65-65: Refactor this function to reduce its Cognitive Complexity from 45 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZr40lwtv78fvmSAsNj6&open=AZr40lwtv78fvmSAsNj6&pullRequest=264

cortex/preflight_checker.py

[failure] 524-524: Refactor this function to reduce its Cognitive Complexity from 25 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZr40l0pv78fvmSAsNj9&open=AZr40l0pv78fvmSAsNj9&pullRequest=264

🪛 Ruff (0.14.7)
cortex/cli.py

214-214: Consider moving this statement to an else block

(TRY300)


216-216: Do not catch blind exception: Exception

(BLE001)


217-217: Use explicit conversion flag

Replace with conversion flag

(RUF010)

cortex/preflight_checker.py

80-80: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)


95-95: subprocess call: check for execution of untrusted input

(S603)


106-106: Do not catch blind exception: Exception

(BLE001)


112-112: subprocess call with shell=True identified, security issue

(S602)


122-122: Do not catch blind exception: Exception

(BLE001)


168-169: try-except-pass detected, consider logging the exception

(S110)


168-168: Do not catch blind exception: Exception

(BLE001)


240-241: try-except-pass detected, consider logging the exception

(S110)


240-240: Do not catch blind exception: Exception

(BLE001)


297-297: Consider moving this statement to an else block

(TRY300)


298-298: Do not catch blind exception: Exception

(BLE001)


308-309: try-except-pass detected, consider logging the exception

(S110)


308-308: Do not catch blind exception: Exception

(BLE001)


368-370: try-except-pass detected, consider logging the exception

(S110)


368-368: Do not catch blind exception: Exception

(BLE001)


466-466: Unused method argument: software

(ARG002)

🔇 Additional comments (6)
cortex/preflight_checker.py (3)

20-70: Well-structured dataclasses for preflight reporting.

The dataclass definitions are clean and provide good type safety. Using field(default_factory=...) for mutable defaults is the correct pattern.


109-123: Security concern: shell=True with user-influenced input.

_run_shell_command uses shell=True, which can be a security risk if the cmd string contains unsanitized user input. Currently it's used with path from _get_filesystem_type. While path originates from known paths in DISK_CHECK_PATHS or os.getcwd(), ensure this method isn't called with arbitrary user input in the future.

Consider adding a comment documenting this assumption, or switching to shlex.quote() for the path:

 def _get_filesystem_type(self, path: str) -> str:
     """Get filesystem type for a path on Linux"""
-    success, output = self._run_shell_command(f"df -T '{path}' | tail -1 | awk '{{print $2}}'")
+    import shlex
+    success, output = self._run_shell_command(f"df -T {shlex.quote(path)} | tail -1 | awk '{{print $2}}'")

589-600: Redundant manual conversion after asdict already fixed.

The code now correctly relies on asdict(report) without redundant conversions. Good fix from the previous review.

cortex/cli.py (3)

23-23: Import added for preflight checker integration.

Clean import of the new preflight functionality.


65-68: Good early return pattern for simulation mode.

The simulation check at the start of install() provides a clean separation of concerns and doesn't require an API key, which aligns with the design intent.


528-528: CLI integration for --simulate flag is complete.

The flag is properly added to the argument parser, documented in the epilog, and correctly passed through to cli.install().

Also applies to: 553-553, 590-590

Copy link
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: 0

♻️ Duplicate comments (6)
cortex/preflight_checker.py (5)

11-11: Remove unused socket import.

The socket module is imported but never used in this file.

Apply this diff:

-import socket

390-480: Consider extracting duplicated logic into a helper method.

The check_docker, check_containerd, and check_software methods share a common pattern:

  1. Check if package is installed
  2. If not installed and API key exists, query LLM for package info
  3. Fall back to estimates if LLM fails or no API key

Extract this logic into a shared helper method to improve maintainability and reduce duplication.

Example helper method:

def _check_and_add_package(self, pkg: PackageInfo, software: str, 
                           default_estimates: List[Dict[str, str]],
                           default_config_changes: Optional[List[str]] = None) -> PackageInfo:
    """Helper to check package and add to install list if not present"""
    self.report.package_status.append(pkg)
    
    if not pkg.installed:
        if self.api_key:
            pkg_info = self._get_package_info_from_llm(software, self.report.os_info)
            if pkg_info.get('packages'):
                self.report.packages_to_install.extend(pkg_info['packages'])
                if pkg_info.get('config_changes'):
                    self.report.config_changes.extend(pkg_info['config_changes'])
            else:
                self.report.packages_to_install.extend(default_estimates)
                if default_config_changes:
                    self.report.config_changes.extend(default_config_changes)
        else:
            self.report.packages_to_install.extend(default_estimates)
            if default_config_changes:
                self.report.config_changes.extend(default_config_changes)
            if not any('estimate' in str(p.get('size_mb', '')) for p in self.report.packages_to_install):
                self.report.warnings.append('Package sizes are estimates - provide API key for accurate sizes')
    
    return pkg

616-626: Remove redundant module import.

The json module is already imported at the module level (line 14), so there's no need to import it again locally. Remove the redundant import and use the module-level import.

Apply this diff:

 def export_report(report: PreflightReport, filepath: str) -> None:
     """Export preflight report to a JSON file"""
-    import json
     from dataclasses import asdict
     
     # Convert dataclass to dict
     report_dict = asdict(report)

     # `asdict` already converts nested dataclasses recursively, so we can
     # directly write the result to JSON.
     with open(filepath, 'w') as f:
         json.dump(report_dict, f, indent=2)

328-328: Fix type hint: use Any instead of any.

The return type annotation uses the built-in any type instead of typing.Any. Import Any from the typing module (already imported at line 16) and use it correctly.

Apply this diff:

-    def _get_package_info_from_llm(self, software: str, os_info: Dict[str, str]) -> Dict[str, any]:
+    def _get_package_info_from_llm(self, software: str, os_info: Dict[str, str]) -> Dict[str, Any]:
         """Query LLM for real package information including sizes"""

Note: Any is already imported from typing at line 16.


270-275: Fix command injection vulnerability in shell command.

Using an f-string with a user-controlled path in a shell command creates a command injection risk. While the path is wrapped in single quotes, special characters could still be exploited.

Apply this diff to use shlex.quote() for proper escaping:

+import shlex
+
 def _get_filesystem_type(self, path: str) -> str:
     """Get filesystem type for a path on Linux"""
-    success, output = self._run_shell_command(f"df -T '{path}' | tail -1 | awk '{{print $2}}'")
+    success, output = self._run_shell_command(f"df -T {shlex.quote(path)} | tail -1 | awk '{{print $2}}'")
     if success and output:
         return output
     return 'unknown'
docs/SIMULATION_MODE.md (1)

213-214: Fix type documentation to match implementation.

The documentation states that total_download_mb and total_disk_required_mb are floats, but in the code (preflight_checker.py lines 67-68), they are declared as int.

Apply this diff:

-- `total_download_mb`: Total download size (float)
-- `total_disk_required_mb`: Total disk space needed (float)
+- `total_download_mb`: Total download size (int)
+- `total_disk_required_mb`: Total disk space needed (int)
🧹 Nitpick comments (7)
cortex/preflight_checker.py (3)

80-80: Add ClassVar annotation for mutable class attribute.

The DISK_CHECK_PATHS class attribute is mutable and should be annotated with typing.ClassVar to indicate it's a class-level variable that shouldn't be treated as an instance attribute.

Apply this diff:

+from typing import List, Dict, Optional, Tuple, ClassVar
+
 class PreflightChecker:
     """
     Real system checker for Cortex installation preflight checks.
     
     All checks are performed against the actual system - no simulation.
     """
     
     # Default paths - will be set based on platform in __init__
-    DISK_CHECK_PATHS = []
+    DISK_CHECK_PATHS: ClassVar[List[str]] = []
     MIN_DISK_SPACE_MB = 500

482-517: Remove unused software parameter.

The software parameter in calculate_requirements is not used in the method body. The method calculates requirements based on self.report.packages_to_install, which is already populated.

Apply this diff:

-    def calculate_requirements(self, software: str) -> None:
+    def calculate_requirements(self) -> None:
         """Calculate installation requirements based on software to install"""

And update the call site at line 539:

         # Calculate requirements
-        self.calculate_requirements(software)
+        self.calculate_requirements()

544-613: Consider splitting this function to reduce complexity.

SonarCloud reports cognitive complexity of 27 (threshold: 15). While the function is readable, consider extracting sections into helper functions for better maintainability:

  • _format_system_info(report)
  • _format_packages_to_install(report)
  • _format_disk_space(report)
  • _format_issues(report)

This is optional, as the current implementation is functional and clear.

docs/SIMULATION_MODE.md (4)

37-53: Add language specifier to code block.

For better syntax highlighting and clarity, add a language specifier to this code block.

Apply this diff:

-```
+```text
 🔍 Simulation mode: No changes will be made

57-75: Add language specifier to code block.

For better syntax highlighting and clarity, add a language specifier to this code block.

Apply this diff:

-```
+```text
 🔍 Simulation mode: No changes will be made

116-120: Add language specifier to code block.

For better syntax highlighting and clarity, add a language specifier to this code block.

Apply this diff:

-```
+```text
 ❌ Errors:
   - Insufficient disk space: 200 MB available, 500 MB required

124-128: Add language specifier to code block.

For better syntax highlighting and clarity, add a language specifier to this code block.

Apply this diff:

-```
+```text
 ⚠️ Warnings:
   - API key not found, using estimates for package sizes
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 91d4b9b and 0ffa3d8.

📒 Files selected for processing (2)
  • cortex/preflight_checker.py (1 hunks)
  • docs/SIMULATION_MODE.md (1 hunks)
🧰 Additional context used
🪛 GitHub Check: SonarCloud Code Analysis
cortex/preflight_checker.py

[warning] 386-386: Remove this unneeded "pass".

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZr46DrSki_2q7OKI3It&open=AZr46DrSki_2q7OKI3It&pullRequest=264


[failure] 544-544: Refactor this function to reduce its Cognitive Complexity from 27 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZr40l0pv78fvmSAsNj9&open=AZr40l0pv78fvmSAsNj9&pullRequest=264

🪛 markdownlint-cli2 (0.18.1)
docs/SIMULATION_MODE.md

37-37: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


57-57: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


116-116: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


124-124: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🪛 Ruff (0.14.7)
cortex/preflight_checker.py

80-80: Mutable class attributes should be annotated with typing.ClassVar

(RUF012)


107-107: subprocess call: check for execution of untrusted input

(S603)


118-118: Do not catch blind exception: Exception

(BLE001)


124-124: subprocess call with shell=True identified, security issue

(S602)


134-134: Do not catch blind exception: Exception

(BLE001)


180-182: try-except-pass detected, consider logging the exception

(S110)


180-180: Do not catch blind exception: Exception

(BLE001)


253-255: try-except-pass detected, consider logging the exception

(S110)


253-253: Do not catch blind exception: Exception

(BLE001)


311-311: Consider moving this statement to an else block

(TRY300)


312-312: Do not catch blind exception: Exception

(BLE001)


322-324: try-except-pass detected, consider logging the exception

(S110)


322-322: Do not catch blind exception: Exception

(BLE001)


383-383: Do not catch blind exception: Exception

(BLE001)


482-482: Unused method argument: software

(ARG002)

🔇 Additional comments (2)
cortex/preflight_checker.py (1)

198-268: LGTM - Good handling of disk space checks.

The disk space checking logic properly handles:

  • Path deduplication
  • Non-existent paths by walking up to nearest parent
  • Low disk space warnings
  • Silent failures with documented reasons and sensible defaults
docs/SIMULATION_MODE.md (1)

221-228: LGTM - API examples are accurate.

The export_report example correctly shows the function writing to a file, which matches the implementation in preflight_checker.py.

@Sahilbhatane Sahilbhatane self-assigned this Dec 7, 2025
Copy link
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: 0

♻️ Duplicate comments (1)
cortex/cli.py (1)

28-28: Unused export_report import and incomplete wiring for report export

export_report is imported but never used here. Given that export_report exists in cortex.preflight_checker and the issue acceptance criteria mention exporting simulation reports, this looks either like a leftover or an uncompleted CLI feature.

I’d suggest either:

  • Remove export_report from this import if export is intentionally handled elsewhere, or
  • Add a CLI option (e.g. --export-report PATH) for cortex install ... --simulate and call export_report(report, PATH) inside _run_simulation.
🧹 Nitpick comments (2)
cortex/cli.py (2)

255-277: Tighten error handling in _run_simulation and address static-analysis noise

Functionality-wise, _run_simulation() looks fine, but a couple of refinements would improve quality and clear lints:

  • You’re catching a blind Exception (Line 275). For a CLI, it’s often better to either:

    • Catch specific expected exceptions (e.g. OSError, subprocess.TimeoutExpired raised inside PreflightChecker helpers), or
    • Let unexpected errors propagate to the global main() handler, which already catches Exception and prints a generic “Unexpected error”.
  • Ruff’s TRY300 complaint about the if report.errors: return 1 followed by return 0 can be trivially satisfied (or ignored), but if you care about the warning, an explicit else keeps the structure clearer:

-            # Return error code if blocking issues found
-            if report.errors:
-                return 1
-            return 0
+            # Return error code if blocking issues found
+            if report.errors:
+                return 1
+            else:
+                return 0
  • For better diagnostics you might prefer repr(e) or an explicit conversion flag:
-        except Exception as e:
-            self._print_error(f"Simulation failed: {str(e)}")
+        except Exception as e:
+            self._print_error(f"Simulation failed: {e!r}")

These are non-functional, but they will appease the linters and make debugging simulation failures easier.


793-818: Document --simulate consistently across help text and examples

The new --simulate flag is wired into argparse (Line 878) and showcased in the epilog examples (Lines 831‑837), which is good. Two small UX/doc tweaks will make it more discoverable and less redundant:

  1. Rich help flags section (Lines 815‑818)
    The show_rich_help() “Flags” list doesn’t mention --simulate. Consider adding it:
-    console.print("[bold cyan]Flags:[/bold cyan]")
-    console.print("  --execute    Actually run the commands (default: preview only)")
-    console.print("  --dry-run    Show what would happen without doing anything")
+    console.print("[bold cyan]Flags:[/bold cyan]")
+    console.print("  --execute     Actually run the commands (default: preview only)")
+    console.print("  --dry-run     Show what would happen without doing anything")
+    console.print("  --simulate    Run preflight checks and disk/package analysis only")
     console.print("  --verbose    Show debug information")
  1. Avoid duplicated example blocks in the epilog (Lines 831‑845 vs 845‑850)
    The epilog now has two example groups that both include cortex install docker variants. You might want to merge them into a single concise examples block that includes --execute, --dry-run, and --simulate together to prevent confusion.

These are documentation-level changes but will help users understand the new simulation mode more quickly.

Also applies to: 831-845, 874-879

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0ffa3d8 and a8fec36.

📒 Files selected for processing (2)
  • cortex/cli.py (6 hunks)
  • requirements.txt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • requirements.txt
🧰 Additional context used
🧬 Code graph analysis (1)
cortex/cli.py (1)
cortex/preflight_checker.py (4)
  • PreflightChecker (72-541)
  • format_report (544-613)
  • export_report (616-626)
  • run_all_checks (518-541)
🪛 GitHub Check: SonarCloud Code Analysis
cortex/cli.py

[warning] 115-115: Remove the unused function parameter "execute".

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZr9it4TOHUXk6syDWSs&open=AZr9it4TOHUXk6syDWSs&pullRequest=264


[warning] 115-115: Remove the unused function parameter "dry_run".

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZr9it4TOHUXk6syDWSt&open=AZr9it4TOHUXk6syDWSt&pullRequest=264

🪛 Ruff (0.14.7)
cortex/cli.py

115-115: Unused method argument: execute

(ARG002)


115-115: Unused method argument: dry_run

(ARG002)


273-273: Consider moving this statement to an else block

(TRY300)


275-275: Do not catch blind exception: Exception

(BLE001)


276-276: Use explicit conversion flag

Replace with conversion flag

(RUF010)

🔇 Additional comments (1)
cortex/cli.py (1)

115-120: Fix duplicated install() definition and broken simulate parameter wiring

You currently define CortexCLI.install twice:

  • Lines 115‑119: install(..., simulate: bool = False) that short-circuits to _run_simulation.
  • Line 120 onward: install(..., dry_run: bool = False) (original implementation), which overwrites the first definition in Python.

As a result:

  • The active install() method does not accept simulate, but
  • main() calls cli.install(..., simulate=args.simulate) (lines 914‑915),

which will raise TypeError: install() got an unexpected keyword argument 'simulate' at runtime.

Additionally, the second elif args.command == 'install' branch at lines 922‑923 is now dead/unreachable.

Recommend:

  1. Merge simulation handling into a single install() implementation:
-    def install(self, software: str, execute: bool = False, dry_run: bool = False, simulate: bool = False):
-        # Handle simulation mode first - no API key needed
-        if simulate:
-            return self._run_simulation(software)
-        
-
-    def install(self, software: str, execute: bool = False, dry_run: bool = False):
+    def install(self, software: str, execute: bool = False, dry_run: bool = False, simulate: bool = False):
+        # Handle simulation mode first - no API key needed
+        if simulate:
+            return self._run_simulation(software)
+
         # Validate input first
         is_valid, error = validate_install_request(software)
  1. Clean up the dispatcher to remove the duplicate install branch:
-        elif args.command == 'install':
-            return cli.install(args.software, execute=args.execute, dry_run=args.dry_run)
         elif args.command == 'status':
             return cli.status()

This resolves the runtime error, removes dead code, and clears static-analysis warnings about unused parameters.

@sonarqubecloud
Copy link

Copy link
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 (3)
cortex/cli.py (3)

27-27: Unused export_report import (and missing CLI hook for report export)

export_report is imported here but never used in this module. Either wire it into _run_simulation (e.g., behind a CLI flag to export the simulation report) or remove it to avoid an unused import and keep the API surface clear.


320-342: Simulation path works but can be tightened and better aligned with CLI style

_run_simulation correctly:

  • Uses an optional API key from the environment (avoiding _get_api_key’s hard error).
  • Instantiates PreflightChecker, runs checks, prints a formatted report, and maps report.errors to exit codes.

Two follow-ups would improve this:

  1. Add the return type hint for clarity and to align with your type-hint guideline:
-    def _run_simulation(self, software: str) -> int:
+    def _run_simulation(self, software: str) -> int:
  1. If simulation-report export is a requirement for this CLI (since export_report is imported), consider adding an optional export/output flag at the CLI level and calling export_report(report, path_or_format) here. Otherwise, drop the unused import as noted above.

These are non-blocking but will make the feature more consistent and maintainable.


606-611: --simulate flag wiring is correct, but consider mutual exclusivity with execute/dry-run

The new --simulate flag is added to the install subparser and passed through from main() to CortexCLI.install, which is the right wiring for the feature.

Once the single install method is fixed as suggested above, --simulate will short-circuit to _run_simulation, ignoring --execute/--dry-run. To avoid confusing combinations like cortex install docker --execute --simulate, consider making these flags mutually exclusive via an argparse mutually exclusive group on the install subparser.

This is a usability improvement rather than a correctness blocker.

Also applies to: 659-662

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a8fec36 and a7f018b.

📒 Files selected for processing (3)
  • cortex/cli.py (5 hunks)
  • requirements.txt (1 hunks)
  • test/test_cli.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • requirements.txt
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Follow PEP 8 style guide
Type hints required in Python code
Docstrings required for all public APIs

Files:

  • cortex/cli.py
  • test/test_cli.py
🧬 Code graph analysis (1)
test/test_cli.py (1)
cortex/cli.py (1)
  • main (583-689)
🪛 GitHub Check: SonarCloud Code Analysis
cortex/cli.py

[warning] 116-116: Remove the unused function parameter "dry_run".

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZr9it4TOHUXk6syDWSt&open=AZr9it4TOHUXk6syDWSt&pullRequest=264


[warning] 116-116: Remove the unused function parameter "execute".

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZr9it4TOHUXk6syDWSs&open=AZr9it4TOHUXk6syDWSs&pullRequest=264

🔇 Additional comments (1)
test/test_cli.py (1)

177-199: Main → CortexCLI.install wiring with simulate looks correct

The updated expectations for mock_install.assert_called_once_with(..., simulate=False) in these three tests match the new main() wiring and keep the tests focused on CLI argument propagation. No issues here.

Comment on lines +116 to +120
def install(self, software: str, execute: bool = False, dry_run: bool = False, simulate: bool = False):
# Handle simulation mode first - no API key needed
if simulate:
return self._run_simulation(software)

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Duplicate install definitions cause a TypeError with --simulate

There are two CortexCLI.install methods:

  • Lines 116–120: a stub that only handles simulate and then returns.
  • Lines 185–303: the full install implementation that does not accept simulate.

Because Python uses the last definition, the stub at 116–120 is completely shadowed. The active signature is install(self, software, execute=False, dry_run=False). However, main() now calls:

return cli.install(args.software, execute=args.execute, dry_run=args.dry_run, simulate=args.simulate)

This will raise TypeError: install() got an unexpected keyword argument 'simulate' at runtime. The new tests don’t catch this because they patch CortexCLI.install.

You should consolidate to a single install method that supports simulate and remove the duplicate definition and unreachable elif args.command == 'install' branch. For example:

@@
-    def _clear_line(self):
-        sys.stdout.write('\r\033[K')
-        sys.stdout.flush()
-    
-    def install(self, software: str, execute: bool = False, dry_run: bool = False, simulate: bool = False):
-        # Handle simulation mode first - no API key needed
-        if simulate:
-            return self._run_simulation(software)
-       
+    def _clear_line(self):
+        sys.stdout.write('\r\033[K')
+        sys.stdout.flush()
@@
-    def install(self, software: str, execute: bool = False, dry_run: bool = False):
-        # Validate input first
+    def install(
+        self,
+        software: str,
+        execute: bool = False,
+        dry_run: bool = False,
+        simulate: bool = False,
+    ) -> int:
+        # Handle simulation mode first - no API key needed
+        if simulate:
+            return self._run_simulation(software)
+
+        # Validate input first
         is_valid, error = validate_install_request(software)
@@
-    try:
-        if args.command == 'install':
-            return cli.install(args.software, execute=args.execute, dry_run=args.dry_run, simulate=args.simulate)
+    try:
+        if args.command == 'install':
+            return cli.install(
+                args.software,
+                execute=args.execute,
+                dry_run=args.dry_run,
+                simulate=args.simulate,
+            )
@@
-        elif args.command == 'status':
-            return cli.status()
-        elif args.command == 'install':
-            return cli.install(args.software, execute=args.execute, dry_run=args.dry_run)
+        elif args.command == 'status':
+            return cli.status()

This preserves all existing behavior, fixes the --simulate runtime error, and resolves the static-analysis warnings about unused parameters in the stub.

Also applies to: 185-303, 660-669

🧰 Tools
🪛 GitHub Check: SonarCloud Code Analysis

[warning] 116-116: Remove the unused function parameter "dry_run".

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZr9it4TOHUXk6syDWSt&open=AZr9it4TOHUXk6syDWSt&pullRequest=264


[warning] 116-116: Remove the unused function parameter "execute".

See more on https://sonarcloud.io/project/issues?id=cortexlinux_cortex&issues=AZr9it4TOHUXk6syDWSs&open=AZr9it4TOHUXk6syDWSs&pullRequest=264

🤖 Prompt for AI Agents
In cortex/cli.py around lines 116-120 (duplicate stub), lines 185-303 (full
implementation), and lines 660-669 (another duplicate), there are multiple
install() definitions causing a TypeError when --simulate is passed because the
active method signature lacks the simulate parameter; remove the duplicate
stub(s) and consolidate into a single install(self, software: str, execute: bool
= False, dry_run: bool = False, simulate: bool = False) implementation that
preserves the full install behavior and handles the simulate branch up front
(returning _run_simulation when simulate is True), and also delete the
now-unreachable elif args.command == 'install' branch to avoid dead code and
static-analysis warnings.

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.

Installation Simulation Mode

1 participant