Skip to content

Conversation

@borisarzentar
Copy link
Member

@borisarzentar borisarzentar commented Nov 26, 2025

Description

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Code refactoring
  • Performance improvement
  • Other (please specify):

Screenshots/Videos (if applicable)

Pre-submission Checklist

  • I have tested my changes thoroughly before submitting this PR
  • This PR contains minimal changes necessary to address the issue/feature
  • My code follows the project's coding standards and style guidelines
  • I have added tests that prove my fix is effective or that my feature works
  • I have added necessary documentation (if applicable)
  • All new and existing tests pass
  • I have searched existing PRs to ensure this change hasn't been submitted already
  • I have linked any relevant issues in the description
  • My commits have clear and descriptive messages

DCO Affirmation

I affirm that all code in every commit of this pull request conforms to the terms of the Topoteretes Developer Certificate of Origin.

Summary by CodeRabbit

  • New Features

    • Enhanced Node.js and npm environment management for improved system compatibility on Unix-like platforms.
  • Chores

    • Updated Next.js to v16, React to v19.2, and Auth0 SDK to v4.13.1 for compatibility and performance improvements.
    • Removed CrewAI workflow trigger component.
    • Removed user feedback submission form.

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

@pull-checklist
Copy link

Please make sure all the checkboxes are checked:

  • I have tested these changes locally.
  • I have reviewed the code changes.
  • I have added end-to-end and unit tests (if applicable).
  • I have updated the documentation and README.md file (if necessary).
  • I have removed unnecessary code and debug statements.
  • PR title is clear and follows the convention.
  • I have tagged reviewers or team members for feedback.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 26, 2025

Walkthrough

Updates frontend dependencies (Next.js 16, React 19.2, Auth0), refactors React ref types from MutableRefObject to RefObject across multiple components, removes CrewAI and Feedback UI components and their exports, changes some page components to client mode, adjusts TS JSX runtime, renames a middleware export to proxy, and adds backend Node/NVM/npm utilities with nvm-aware frontend startup.

Changes

Cohort / File(s) Summary
Dependency Updates
cognee-frontend/package.json
Bumped auth0/nextjs-auth0, Next.js -> 16.0.4, React -> 19.2.0, react-dom, @types/react, @types/react-dom, eslint-config-next versions.
Ref Type Refactor (MutableRefObject → RefObject)
cognee-frontend/src/app/(graph)/GraphView.tsx, cognee-frontend/src/app/(graph)/GraphVisualization.tsx, cognee-frontend/src/ui/elements/Notebook/Notebook.tsx
Swapped MutableRefObject -> RefObject, initialized refs with null, updated prop types/casts and added nullability guards.
Removed UI Components & Exports
cognee-frontend/src/app/(graph)/CrewAITrigger.tsx, cognee-frontend/src/ui/Partials/FeedbackForm.tsx, cognee-frontend/src/ui/Partials/index.ts
Deleted CrewAITrigger component (WebSocket/form/streaming logic), removed FeedbackForm component and its export from the Partials barrel.
GraphControls minor edits
cognee-frontend/src/app/(graph)/GraphControls.tsx
Removed commented FeedbackForm import/usage and initialized timeout ref with null.
Page/component directive & async changes
cognee-frontend/src/app/page.tsx, cognee-frontend/src/app/dashboard/page.tsx
Enabled export const dynamic = "force-dynamic" in page.tsx; converted dashboard page from an async server component to a client component (use client, synchronous function).
Misc TypeScript & small edits
cognee-frontend/tsconfig.json, cognee-frontend/src/modules/ingestion/useDatasets.ts, cognee-frontend/src/proxy.ts, cognee-frontend/src/ui/elements/Notebook/NotebookCellHeader.tsx
Switched TSX runtime to react-jsx, added dev types include, removed a lint-comment, renamed exported function middlewareproxy, made runInstance read-only.
Backend: Node/NVM/npm utilities added
cognee/api/v1/ui/node_setup.py, cognee/api/v1/ui/npm_utils.py
New cross-platform nvm detection/install and Node install helpers; added run_npm_command with nvm fallback (sourcing nvm.sh) and platform-specific handling.
Frontend startup integration
cognee/api/v1/ui/ui.py
Replaced local Node/npm checks with imports from node_setup, use run_npm_command for installs, and start frontend with nvm-aware command (bash sourcing nvm.sh) on Unix-like systems while preserving Windows behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

  • Areas to focus review on:
    • Cross-platform subprocess/nvm sourcing and PATH augmentation in node_setup.py, npm_utils.py, and ui.py.
    • Ref type changes across GraphVisualization/GraphView/Notebook to ensure props and consumers align and null checks are correct.
    • Removal of CrewAITrigger and FeedbackForm: search for lingering references or imports elsewhere.
    • Client vs server component change in dashboard page and enabled dynamic export impact on rendering/SSR behavior.

Possibly related PRs

Suggested labels

run-checks

Suggested reviewers

  • Vasilije1990
  • hajdul88

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description uses the template but the Description section is empty with only template comments, and most checklist items remain unchecked despite significant code changes. Fill in the Description section with clear details about the changes, the issue being fixed, and why frontend changes were necessary. Check relevant pre-submission checklist items.
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: install nvm and node for -ui cli command' accurately summarizes the main change: adding NVM and Node.js installation support for the UI CLI command.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/cog-3441-cognee-cli-ui-fix

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

Copy link
Contributor

@siillee siillee left a comment

Choose a reason for hiding this comment

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

Looks good to me

@daukadolt
Copy link
Contributor

nit: most of the changes in the frontend seem not related, maybe can be split?

@borisarzentar borisarzentar marked this pull request as ready for review December 2, 2025 09:44
@borisarzentar borisarzentar requested a review from siillee December 2, 2025 09:44
@borisarzentar
Copy link
Member Author

nit: most of the changes in the frontend seem not related, maybe can be split?

Frontend had some critical dependency issues, so took a chance to fix that as well. Frontend can be also built now, don't need to be served as dev version.

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: 2

♻️ Duplicate comments (1)
cognee/api/v1/ui/node_setup.py (1)

91-91: Update nvm version to latest stable.

As noted in a previous review, the nvm version v0.39.7 is outdated.

🧹 Nitpick comments (12)
cognee-frontend/src/app/dashboard/page.tsx (1)

1-11: Client page implementation is correct; consider whether top-level use client is needed

This component is syntactically and semantically fine as a client page and will render Dashboard as expected. If Page itself doesn’t need hooks or browser-only APIs and Dashboard is already a client component, you could keep Page as a server component (remove "use client" and keep a plain/default export) for slightly better SSR behavior. If the intent is to make the entire dashboard route client-only for consistency with other changes in this PR, the current version is OK as-is.

cognee/api/v1/ui/npm_utils.py (2)

37-47: Potential shell injection risk when joining command arguments.

Line 40 uses ' '.join(cmd) to construct a shell command string, which could be problematic if any element in cmd contains spaces, special characters, or shell metacharacters. While this is an internal utility, consider using shlex.join() for safer command construction.

+import shlex
+
 from cognee.shared.logging_utils import get_logger
 from .node_setup import get_nvm_sh_path
-                nvm_cmd = f"source {nvm_path} && {' '.join(cmd)}"
+                nvm_cmd = f"source {nvm_path} && {shlex.join(cmd)}"

12-50: Missing subprocess.TimeoutExpired exception handling.

The function specifies a timeout parameter but doesn't handle the TimeoutExpired exception. The calling code in ui.py handles it, but this function should either handle it internally for consistency or document that callers must handle it.

Consider adding exception handling or documenting the expected behavior:

 def run_npm_command(cmd: List[str], cwd: Path, timeout: int = 300) -> subprocess.CompletedProcess:
     """
     Run an npm command, ensuring nvm is sourced if needed (Unix-like systems only).
     Returns the CompletedProcess result.
+
+    Raises:
+        subprocess.TimeoutExpired: If the command does not complete within the timeout.
     """
cognee/api/v1/ui/node_setup.py (3)

126-131: Bare except clause with pass silently swallows all errors.

Line 130 uses a bare except Exception with pass, which could hide important cleanup failures. Consider logging at debug level.

         finally:
             # Clean up temporary script
             try:
                 os.unlink(install_script_path)
-            except Exception:
-                pass
+            except Exception as e:
+                logger.debug(f"Failed to clean up temp script: {e}")

210-360: Significant code duplication in check_node_npm function.

This function is ~150 lines with substantial duplicated patterns:

  1. The "try direct command, then try with nvm sourced" pattern appears 4+ times
  2. The nvm/node installation fallback logic is duplicated in both the main try block and FileNotFoundError handler
  3. Similar error handling and logging throughout

Consider extracting helper functions to reduce duplication and improve maintainability.

Example refactor approach:

def _run_with_nvm_fallback(cmd: List[str], timeout: int = 10) -> subprocess.CompletedProcess:
    """Run a command, falling back to nvm-sourced execution if direct fails."""
    result = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
    if result.returncode != 0:
        nvm_path = get_nvm_sh_path()
        if nvm_path.exists():
            result = subprocess.run(
                ["bash", "-c", f"source {nvm_path} && {' '.join(cmd)}"],
                capture_output=True, text=True, timeout=timeout,
            )
    return result


def _ensure_node_installed() -> tuple[bool, str]:
    """Ensure Node.js is installed, installing via nvm if needed."""
    # Consolidated installation logic here
    ...

312-358: Near-duplicate logic in FileNotFoundError handler.

The FileNotFoundError exception handler (lines 314-358) largely duplicates the logic in the main try block (lines 231-274) for installing nvm and Node.js. This violates DRY principles.

Consider consolidating into a single code path by catching FileNotFoundError alongside the returncode check, or extracting the installation logic into a helper function.

cognee/api/v1/ui/ui.py (2)

588-601: Duplicated version-finding logic with node_setup.py.

This PATH augmentation logic (lines 594-601) duplicates the version-finding code from install_node_with_nvm() in node_setup.py (lines 186-195). Both have the same lexicographic sorting issue that may not correctly identify the "latest" version.

Consider extracting this into a shared helper function in node_setup.py.

Add a helper function to node_setup.py:

def get_nvm_node_bin_path() -> Optional[Path]:
    """Get the bin path for the latest nvm-installed Node.js version."""
    nvm_versions = get_nvm_dir() / "versions" / "node"
    if nvm_versions.exists():
        versions = sorted(nvm_versions.iterdir(), reverse=True)
        if versions:
            bin_path = versions[0] / "bin"
            if bin_path.exists():
                return bin_path
    return None

Then use it in both ui.py and node_setup.py.


610-639: Consider consolidating npm execution logic.

Both branches (Windows at lines 610-618 and Unix with nvm at lines 620-630) could potentially be simplified by leveraging run_npm_command from npm_utils.py with a Popen-compatible variant, though this may require additional abstraction.

cognee-frontend/src/app/(graph)/GraphView.tsx (1)

3-3: Ref setup looks correct; consider dropping casts and making handlers null‑safe

The useRef<...>(null) migration for graphRef, graphControls, and activityLog is consistent with React 19 ref typing, and the new RefObject import is appropriate. The repeated as RefObject<...> casts when passing refs to GraphVisualization, ActivityLog, and GraphControls are likely unnecessary; TypeScript should accept the refs directly. Also, using graphRef.current! in the handlers can be made a bit safer with optional chaining so calls are simply no‑ops if the visualization isn’t ready yet.

Example refactor (if TS types allow):

-  const graphRef = useRef<GraphVisualizationAPI>(null);
-  const graphControls = useRef<GraphControlsAPI>(null);
-  const activityLog = useRef<ActivityLogAPI>(null);
+  const graphRef = useRef<GraphVisualizationAPI>(null);
+  const graphControls = useRef<GraphControlsAPI>(null);
+  const activityLog = useRef<ActivityLogAPI>(null);

-        <GraphVisualization
+        <GraphVisualization
           key={data?.nodes.length}
-          ref={graphRef as RefObject<GraphVisualizationAPI>}
+          ref={graphRef}
           data={data}
-          graphControls={graphControls as RefObject<GraphControlsAPI>}
+          graphControls={graphControls}
         />
...
-            <ActivityLog ref={activityLog as RefObject<ActivityLogAPI>} />
+            <ActivityLog ref={activityLog} />
...
-            <GraphControls
+            <GraphControls
               data={data}
-              ref={graphControls as RefObject<GraphControlsAPI>}
+              ref={graphControls}
               isAddNodeFormOpen={isAddNodeFormOpen}
-              onFitIntoView={() => graphRef.current!.zoomToFit(1000, 50)}
-              onGraphShapeChange={(shape) => graphRef.current!.setGraphShape(shape)}
+              onFitIntoView={() => graphRef.current?.zoomToFit(1000, 50)}
+              onGraphShapeChange={(shape) => graphRef.current?.setGraphShape(shape)}
             />

If TypeScript still complains without the casts, keeping only the ?. change would already improve robustness.

Also applies to: 50-55, 75-100

cognee-frontend/src/app/(graph)/GraphVisualization.tsx (1)

4-5: RefObject‑based API for GraphVisualization is consistent with callers; cast could be simplified

Using RefObject<GraphVisualizationAPI> / RefObject<GraphControlsAPI> on the props and initializing graphRef with useRef<ForceGraphMethods>(null) lines up cleanly with how GraphView and Notebook are now consuming this component. The zoomToFit wrapper and its null guard are appropriate given the async nature of the ForceGraph ref.

The cast on the ForceGraph ref is probably not needed:

-  const graphRef = useRef<ForceGraphMethods>(null);
...
-      <ForceGraph
-        ref={graphRef as RefObject<ForceGraphMethods>}
+  const graphRef = useRef<ForceGraphMethods>(null);
+  ...
+      <ForceGraph
+        ref={graphRef}

If the library’s ref typing is narrower, keeping the cast is fine; functionally the current code is sound.

Also applies to: 18-22, 30-37, 208-209, 243-244

cognee-frontend/src/ui/elements/Notebook/NotebookCellHeader.tsx (1)

36-36: runInstance doesn’t need state; compute it directly from the environment

Since runInstance is never updated and the UI doesn’t currently allow switching between local/cloud (the Select is commented out), you can simplify by removing useState entirely and deriving it once per render:

-  const [runInstance] = useState<string>(isCloudEnvironment() ? "cloud" : "local");
+  const runInstance: "cloud" | "local" = isCloudEnvironment() ? "cloud" : "local";

This keeps behavior the same while avoiding an unnecessary piece of state.

Also applies to: 59-69

cognee-frontend/src/ui/elements/Notebook/Notebook.tsx (1)

5-5: GraphVisualization ref wiring in CellResult is correct but currently unused

The new useRef<GraphVisualizationAPI>(null) plus RefObject import are consistent with the updated GraphVisualization API, and the stubbed graphControls implementation prevents undefined‑access issues in this notebook context.

However, CellResult never reads graphRef.current, so the ref is effectively unused and only serves to satisfy the ref prop type. If you don’t plan to control these embedded graphs imperatively (e.g., calling zoomToFit), you could either:

  • Keep the current pattern as is (harmless but a bit noisy), or
  • Replace graphRef with a simple dummy ref (e.g., useRef<GraphVisualizationAPI | null>(null) without exporting it from the component) and clearly comment that it’s intentionally unused, to avoid confusion for future readers.

Functionally, no changes are required; this is just a clarity/cleanup consideration.

Also applies to: 282-305, 343-353, 377-383

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c17f838 and 5fe6a17.

⛔ Files ignored due to path filters (1)
  • cognee-frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (17)
  • cognee-frontend/package.json (2 hunks)
  • cognee-frontend/src/app/(graph)/CrewAITrigger.tsx (0 hunks)
  • cognee-frontend/src/app/(graph)/GraphControls.tsx (1 hunks)
  • cognee-frontend/src/app/(graph)/GraphView.tsx (3 hunks)
  • cognee-frontend/src/app/(graph)/GraphVisualization.tsx (5 hunks)
  • cognee-frontend/src/app/dashboard/page.tsx (1 hunks)
  • cognee-frontend/src/app/page.tsx (1 hunks)
  • cognee-frontend/src/modules/ingestion/useDatasets.ts (0 hunks)
  • cognee-frontend/src/proxy.ts (1 hunks)
  • cognee-frontend/src/ui/Partials/FeedbackForm.tsx (0 hunks)
  • cognee-frontend/src/ui/Partials/index.ts (0 hunks)
  • cognee-frontend/src/ui/elements/Notebook/Notebook.tsx (5 hunks)
  • cognee-frontend/src/ui/elements/Notebook/NotebookCellHeader.tsx (1 hunks)
  • cognee-frontend/tsconfig.json (2 hunks)
  • cognee/api/v1/ui/node_setup.py (1 hunks)
  • cognee/api/v1/ui/npm_utils.py (1 hunks)
  • cognee/api/v1/ui/ui.py (4 hunks)
💤 Files with no reviewable changes (4)
  • cognee-frontend/src/modules/ingestion/useDatasets.ts
  • cognee-frontend/src/app/(graph)/CrewAITrigger.tsx
  • cognee-frontend/src/ui/Partials/index.ts
  • cognee-frontend/src/ui/Partials/FeedbackForm.tsx
🧰 Additional context used
📓 Path-based instructions (4)
{cognee-mcp,cognee-frontend}/**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Follow local README.md and ESLint/TypeScript configuration in cognee-frontend/ for MCP server and Frontend code

Files:

  • cognee-frontend/src/proxy.ts
  • cognee-frontend/src/app/dashboard/page.tsx
  • cognee-frontend/src/ui/elements/Notebook/NotebookCellHeader.tsx
  • cognee-frontend/src/app/page.tsx
  • cognee-frontend/src/ui/elements/Notebook/Notebook.tsx
  • cognee-frontend/src/app/(graph)/GraphVisualization.tsx
  • cognee-frontend/src/app/(graph)/GraphControls.tsx
  • cognee-frontend/src/app/(graph)/GraphView.tsx
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Use 4-space indentation in Python code
Use snake_case for Python module and function names
Use PascalCase for Python class names
Use ruff format before committing Python code
Use ruff check for import hygiene and style enforcement with line-length 100 configured in pyproject.toml
Prefer explicit, structured error handling in Python code

Files:

  • cognee/api/v1/ui/npm_utils.py
  • cognee/api/v1/ui/node_setup.py
  • cognee/api/v1/ui/ui.py

⚙️ CodeRabbit configuration file

**/*.py: When reviewing Python code for this project:

  1. Prioritize portability over clarity, especially when dealing with cross-Python compatibility. However, with the priority in mind, do still consider improvements to clarity when relevant.
  2. As a general guideline, consider the code style advocated in the PEP 8 standard (excluding the use of spaces for indentation) and evaluate suggested changes for code style compliance.
  3. As a style convention, consider the code style advocated in CEP-8 and evaluate suggested changes for code style compliance.
  4. As a general guideline, try to provide any relevant, official, and supporting documentation links to any tool's suggestions in review comments. This guideline is important for posterity.
  5. As a general rule, undocumented function definitions and class definitions in the project's Python code are assumed incomplete. Please consider suggesting a short summary of the code for any of these incomplete definitions as docstrings when reviewing.

Files:

  • cognee/api/v1/ui/npm_utils.py
  • cognee/api/v1/ui/node_setup.py
  • cognee/api/v1/ui/ui.py
cognee/api/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Public APIs should be type-annotated in Python where practical

Files:

  • cognee/api/v1/ui/npm_utils.py
  • cognee/api/v1/ui/node_setup.py
  • cognee/api/v1/ui/ui.py
cognee/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use shared logging utilities from cognee.shared.logging_utils in Python code

Files:

  • cognee/api/v1/ui/npm_utils.py
  • cognee/api/v1/ui/node_setup.py
  • cognee/api/v1/ui/ui.py
🧠 Learnings (2)
📚 Learning: 2025-11-24T16:45:09.996Z
Learnt from: CR
Repo: topoteretes/cognee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T16:45:09.996Z
Learning: Applies to {cognee-mcp,cognee-frontend}/**/*.{js,ts,tsx} : Follow local README.md and ESLint/TypeScript configuration in cognee-frontend/ for MCP server and Frontend code

Applied to files:

  • cognee-frontend/tsconfig.json
  • cognee-frontend/package.json
📚 Learning: 2025-11-24T16:45:09.996Z
Learnt from: CR
Repo: topoteretes/cognee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T16:45:09.996Z
Learning: Applies to cognee/**/*.py : Use shared logging utilities from cognee.shared.logging_utils in Python code

Applied to files:

  • cognee/api/v1/ui/ui.py
🧬 Code graph analysis (6)
cognee/api/v1/ui/npm_utils.py (2)
cognee/shared/logging_utils.py (1)
  • get_logger (212-224)
cognee/api/v1/ui/node_setup.py (1)
  • get_nvm_sh_path (25-29)
cognee-frontend/src/ui/elements/Notebook/NotebookCellHeader.tsx (1)
cognee-frontend/src/utils/isCloudEnvironment.ts (1)
  • isCloudEnvironment (2-4)
cognee-frontend/src/ui/elements/Notebook/Notebook.tsx (1)
cognee-frontend/src/app/(graph)/GraphVisualization.tsx (1)
  • GraphVisualizationAPI (25-28)
cognee-frontend/src/app/(graph)/GraphVisualization.tsx (1)
cognee-frontend/src/app/(graph)/GraphControls.tsx (1)
  • GraphControlsAPI (22-25)
cognee-frontend/src/app/(graph)/GraphView.tsx (3)
cognee-frontend/src/app/(graph)/GraphVisualization.tsx (1)
  • GraphVisualizationAPI (25-28)
cognee-frontend/src/app/(graph)/GraphControls.tsx (2)
  • GraphControlsAPI (22-25)
  • GraphControls (66-235)
cognee-frontend/src/app/(graph)/ActivityLog.tsx (2)
  • ActivityLogAPI (11-13)
  • ActivityLog (21-54)
cognee/api/v1/ui/ui.py (2)
cognee/api/v1/ui/node_setup.py (3)
  • check_node_npm (210-360)
  • get_nvm_dir (14-22)
  • get_nvm_sh_path (25-29)
cognee/api/v1/ui/npm_utils.py (1)
  • run_npm_command (12-50)
⏰ 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). (17)
  • GitHub Check: CLI Tests / CLI Unit Tests
  • GitHub Check: CLI Tests / CLI Functionality Tests
  • GitHub Check: CLI Tests / CLI Integration Tests
  • GitHub Check: Basic Tests / Run Integration Tests
  • GitHub Check: Basic Tests / Run Unit Tests
  • GitHub Check: End-to-End Tests / Test Entity Extraction
  • GitHub Check: End-to-End Tests / Test using different async databases in parallel in Cognee
  • GitHub Check: End-to-End Tests / Conversation sessions test (Redis)
  • GitHub Check: End-to-End Tests / Concurrent Subprocess access test
  • GitHub Check: End-to-End Tests / Test permissions with different situations in Cognee
  • GitHub Check: End-to-End Tests / Test multi tenancy with different situations in Cognee
  • GitHub Check: End-to-End Tests / S3 Bucket Test
  • GitHub Check: End-to-End Tests / Conversation sessions test (FS)
  • GitHub Check: End-to-End Tests / Deduplication Test
  • GitHub Check: End-to-End Tests / Test Feedback Enrichment
  • GitHub Check: End-to-End Tests / Run Telemetry Pipeline Test
  • GitHub Check: End-to-End Tests / Server Start Test
🔇 Additional comments (11)
cognee-frontend/package.json (1)

11-31: Framework and type version bumps look coherent; please confirm compatibility and scope

Bumping Next to 16.0.4, React/ReactDOM to ^19.2.0, Auth0 SDK, React types, and eslint-config-next keeps the stack internally consistent, but this is a substantial upgrade surface. Please double‑check against the official Next 16 / React 19 upgrade notes and your local ESLint/TS setup, and confirm this broader frontend upgrade is intentional for a PR aimed at the CLI UI fix. As per coding guidelines, ensure this remains compatible with the existing frontend tooling configuration.

cognee-frontend/tsconfig.json (1)

17-37: Verify jsx: "react-jsx" aligns with Next 16 TS guidance

Switching jsx from the typical "preserve" to "react-jsx" while noEmit is true will mostly influence type‑checking, but Next’s docs have historically recommended "preserve" so that the framework’s own compiler controls the JSX transform. Please confirm this new setting is explicitly recommended for Next 16, and that linting/build still pass cleanly with your local config. The added .next/.../types includes look fine and consistent with using Next’s generated types.

cognee-frontend/src/app/page.tsx (1)

1-3: Forcing dynamic = "force-dynamic" changes / to fully dynamic; confirm this is required

Making the root page fully dynamic will prevent static/ISR caching for /, which may be appropriate for a live CLI‑driven dashboard but can have performance implications. Please confirm this behavior change is intentional for the UI flow you’re fixing and not broader than necessary.

cognee-frontend/src/proxy.ts (1)

5-17: The proxy function export is not currently wired as a middleware entrypoint

This code appears to be unused. The proxy function is marked with @typescript-eslint/no-unused-vars and is never imported anywhere in the codebase. There is no middleware.ts entry file, no Next.js middleware configuration in next.config.mjs, and the config.matcher export is not referenced.

If this is preparatory code for future middleware implementation, consider either:

  • Adding a middleware.ts at cognee-frontend/src/middleware.ts that properly imports and re-exports proxy and config, or
  • Removing this dead code if it's no longer needed.

The commented Auth0 authorization logic suggests this may be legacy code from a previous authentication implementation that was disabled.

Likely an incorrect or invalid review comment.

cognee/api/v1/ui/npm_utils.py (1)

1-10: LGTM: Proper module setup with shared logging utilities.

The imports are clean and the logger is correctly initialized using the shared logging utilities. Based on learnings, using get_logger from cognee.shared.logging_utils is the project convention.

cognee/api/v1/ui/node_setup.py (2)

1-11: LGTM: Clean imports and logger setup.

The module correctly uses shared logging utilities from cognee.shared.logging_utils as per project conventions.


14-22: Good implementation of XDG_CONFIG_HOME handling.

The get_nvm_dir() function correctly follows the XDG Base Directory specification by checking XDG_CONFIG_HOME before falling back to ~/.nvm. This aligns with standard nvm installation logic.

cognee/api/v1/ui/ui.py (3)

18-19: LGTM: Clean integration of new utility modules.

The imports correctly reference the new node_setup and npm_utils modules, consolidating nvm/node functionality.


304-304: Good use of the new run_npm_command abstraction.

The install_frontend_dependencies function now correctly uses the centralized npm command runner, which handles nvm sourcing automatically.


620-639: Good nvm integration for frontend startup.

The conditional logic correctly sources nvm when available on Unix-like systems while preserving the direct npm execution fallback. The preexec_fn=os.setsid ensures clean process group handling for termination.

cognee-frontend/src/app/(graph)/GraphControls.tsx (1)

112-151: Explicit null initialization for shapeChangeTimeout matches the cleanup logic

Initializing shapeChangeTimeout with useRef<number | null>(null) aligns with the if (shapeChangeTimeout.current) { clearTimeout(...) } checks in the effect and teardown, avoiding any undefined/null ambiguity. The auto‑cycling and cleanup behavior remain correct with this change.

Comment on lines 89 to 110
try:
# Download and install nvm
nvm_install_script = "https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh"
logger.info(f"Downloading nvm installer from {nvm_install_script}...")

response = requests.get(nvm_install_script, timeout=60)
response.raise_for_status()

# Create a temporary script file
with tempfile.NamedTemporaryFile(mode="w", suffix=".sh", delete=False) as f:
f.write(response.text)
install_script_path = f.name

try:
# Make the script executable and run it
os.chmod(install_script_path, 0o755)
result = subprocess.run(
["bash", install_script_path],
capture_output=True,
text=True,
timeout=120,
)
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 | 🟠 Major

🧩 Analysis chain

🌐 Web query:

nvm install script verification checksum integrity best practices

💡 Result:

Short checklist — best practices for verifying nvm (or any) install scripts and checksums:

  1. Don’t pipe to shell. Download first, review, then run. Example: curl -fsSLo install.sh URL; less install.sh; bash install.sh. This avoids executing unreviewed/partial downloads. [3][4]

  2. Verify integrity with a strong checksum (SHA-256) published by a trusted channel before running: compute shasum -a 256 install.sh and compare to the publisher’s value. If the publisher offers a checksum file, fetch it over HTTPS. [1][2]

  3. Prefer cryptographic signatures over plain checksums when available (GPG/PKI). Verify the signature and the signer’s key trust chain. If using git tags, prefer signed commits/tags and verify them. [4]

  4. Prefer safer install methods: official packages via your distro’s package manager, Homebrew, or cloning the repo and checking out a specific commit/tag you can verify, rather than an ad-hoc curl|bash. nvm’s README shows the curl installer but also documents installing from the repo. [1]

  5. Validate transport security and source authenticity: use HTTPS, check the host (github.com), and prefer pinned URLs that include a release tag or commit hash (and verify the tag/commit didn’t change). Beware tag re‑assignment risks. [1][4]

  6. Use small blast-radius execution: run installers as an unprivileged user, in a container, or VM when you must run potentially risky scripts. Inspect the script for network/privilege changes and unexpected behavior before granting sudo. [3][5]

  7. Automate verification in CI: store and compare expected checksums/signatures in your repo or artifact store; fail the build if verification fails. Log the exact installer version/commit used for audits. [4]

  8. Tools and helpers: consider utilities like checksum.sh (or simple shell functions) to fetch+verify before execution, or maintain your own signed release metadata. [2]

References:

  • nvm installer and recommendations (official README). [1]
  • checksum.sh — example workflow for downloading+verifying install scripts. [2]
  • Guidance on risks of curl|bash and safer alternatives. [3][5]
  • Notes on git tag reassignments and supply-chain risks / verification best practices. [4]

Security concern: Downloading and executing remote scripts without verification.

This code downloads a shell script from the internet and executes it directly without integrity verification, which follows the risky "curl|bash" pattern. Per official nvm documentation and security best practices, add:

  1. Checksum verification: Fetch the published SHA-256 checksum for the installer version and verify it before execution (see checksum.sh for implementation patterns).
  2. User logging/warning: Log explicitly what script version is being downloaded and executed so users can audit the action.
  3. Consider safer alternatives: nvm's README documents installation directly from the repository (cloning and checking out a specific commit/tag you can verify) as a more secure alternative to the installer script.
🤖 Prompt for AI Agents
In cognee/api/v1/ui/node_setup.py around lines 89 to 110, the code downloads and
executes the nvm install script directly which is unsafe; update it to verify
integrity and improve logging: fetch the expected SHA-256 checksum for the
specific nvm version you plan to install (or include a pinned commit/tag),
compute the checksum of the downloaded script and compare before executing, and
abort with a clear error and logged details if the checksums do not match; also
log the exact nvm version/URL being downloaded and that a checksum check will be
performed; optionally replace the installer execution with a safer alternative
by cloning the nvm repo and checking out a specific tag/commit and verifying
that commit before running any install steps.

Comment on lines +186 to +195
# Update PATH for current process
nvm_bin = nvm_dir / "versions" / "node"
# Find the latest installed version
if nvm_bin.exists():
versions = sorted(nvm_bin.iterdir(), reverse=True)
if versions:
latest_node_bin = versions[0] / "bin"
if latest_node_bin.exists():
current_path = os.environ.get("PATH", "")
os.environ["PATH"] = f"{latest_node_bin}:{current_path}"
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 | 🟡 Minor

Version sorting may not produce semantic version order.

Using sorted(nvm_bin.iterdir(), reverse=True) sorts directory names lexicographically, not by semantic version. For example, v9.0.0 would sort after v18.0.0. Consider using a semver-aware sort or relying on nvm's current symlink.

-                if nvm_bin.exists():
-                    versions = sorted(nvm_bin.iterdir(), reverse=True)
-                    if versions:
-                        latest_node_bin = versions[0] / "bin"
+                # Try to use nvm's 'default' alias symlink first
+                default_bin = nvm_dir / "alias" / "default"
+                if default_bin.exists():
+                    # Follow the symlink to get the actual version
+                    pass  # Implementation depends on nvm's structure
+                elif nvm_bin.exists():
+                    # Fallback to sorting (note: lexicographic, not semver)
+                    versions = sorted(nvm_bin.iterdir(), reverse=True)
+                    if versions:
+                        latest_node_bin = versions[0] / "bin"

Alternatively, use nvm current to get the active version.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In cognee/api/v1/ui/node_setup.py around lines 186 to 195, the code sorts nvm
version directories lexicographically which can mis-order semantic versions;
update the logic to pick the latest version semantically (for example, list the
subdirs, extract/normalize their version strings (strip leading "v"), and select
the max using a semver-aware comparator such as packaging.version.parse or a
semver library), then use that directory's "bin" path; alternatively, prefer
reading nvm's active version via the "current" symlink or by invoking "nvm
current" and use that result as the bin path, and ensure you keep a safe
fallback if parsing or lookup fails.

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: 2

♻️ Duplicate comments (2)
cognee/api/v1/ui/node_setup.py (2)

141-207: Avoid lexicographic version sorting when choosing the Node version directory.

When updating PATH, you sort nvm_dir / "versions" / "node" lexicographically and pick the first entry:

versions = sorted(nvm_bin.iterdir(), reverse=True)
if versions:
    latest_node_bin = versions[0] / "bin"

Lexicographic order does not match semantic version order (e.g., v9.0.0 sorts after v18.0.0), so you can end up choosing an older Node version if both <10 and >=10 majors are installed. Prefer either:

  • Asking nvm for the active/default version and deriving the directory (e.g. run nvm current or read the alias/default file), or
  • Parsing the directory names semantically, e.g.:
from packaging.version import parse as parse_version

versions = [d for d in nvm_bin.iterdir() if d.is_dir()]
if versions:
    latest_dir = max(versions, key=lambda d: parse_version(d.name.lstrip("v")))
    latest_node_bin = latest_dir / "bin"

This will consistently pick the newest installed Node.


76-139: Security risk: downloading and executing the nvm installer script without verification.

install_nvm() downloads a remote shell script and executes it directly, with no checksum/signature verification or explicit user confirmation. Even with a pinned tag, this is effectively a curl | bash pattern and is a non-trivial supply‑chain risk (previously raised in this file and still present).

At minimum, consider:

  • Logging a clear warning that a remote script from a specific URL/version is about to be executed.
  • Verifying a published checksum or signature for the installer before execution and aborting on mismatch.
  • Providing a non-automated fallback (e.g., logging instructions for manual nvm installation) instead of silently running unverified shell code.
🧹 Nitpick comments (1)
cognee/api/v1/ui/node_setup.py (1)

14-29: Consider honoring $NVM_DIR when resolving the nvm path.

get_nvm_dir() currently only derives the directory from XDG_CONFIG_HOME or HOME, so a user with a custom NVM_DIR export will be treated as if nvm is not installed. Consider preferring the environment variable when present:

nvm_dir_env = os.environ.get("NVM_DIR")
if nvm_dir_env:
    return Path(nvm_dir_env)

xdg_config_home = os.environ.get("XDG_CONFIG_HOME")
if xdg_config_home:
    return Path(xdg_config_home) / "nvm"
return Path.home() / ".nvm"

This aligns better with the standard nvm initialization snippet.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5fe6a17 and 0ff836b.

📒 Files selected for processing (1)
  • cognee/api/v1/ui/node_setup.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Use 4-space indentation in Python code
Use snake_case for Python module and function names
Use PascalCase for Python class names
Use ruff format before committing Python code
Use ruff check for import hygiene and style enforcement with line-length 100 configured in pyproject.toml
Prefer explicit, structured error handling in Python code

Files:

  • cognee/api/v1/ui/node_setup.py

⚙️ CodeRabbit configuration file

**/*.py: When reviewing Python code for this project:

  1. Prioritize portability over clarity, especially when dealing with cross-Python compatibility. However, with the priority in mind, do still consider improvements to clarity when relevant.
  2. As a general guideline, consider the code style advocated in the PEP 8 standard (excluding the use of spaces for indentation) and evaluate suggested changes for code style compliance.
  3. As a style convention, consider the code style advocated in CEP-8 and evaluate suggested changes for code style compliance.
  4. As a general guideline, try to provide any relevant, official, and supporting documentation links to any tool's suggestions in review comments. This guideline is important for posterity.
  5. As a general rule, undocumented function definitions and class definitions in the project's Python code are assumed incomplete. Please consider suggesting a short summary of the code for any of these incomplete definitions as docstrings when reviewing.

Files:

  • cognee/api/v1/ui/node_setup.py
cognee/api/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Public APIs should be type-annotated in Python where practical

Files:

  • cognee/api/v1/ui/node_setup.py
cognee/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Use shared logging utilities from cognee.shared.logging_utils in Python code

Files:

  • cognee/api/v1/ui/node_setup.py
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: topoteretes/cognee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T16:45:09.996Z
Learning: Applies to {cognee-mcp,cognee-frontend}/**/*.{js,ts,tsx} : Follow local README.md and ESLint/TypeScript configuration in cognee-frontend/ for MCP server and Frontend code
🧬 Code graph analysis (1)
cognee/api/v1/ui/node_setup.py (1)
cognee/shared/logging_utils.py (3)
  • get_logger (212-224)
  • debug (209-209)
  • info (205-205)
⏰ 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). (18)
  • GitHub Check: Basic Tests / Run Unit Tests
  • GitHub Check: Basic Tests / Run Integration Tests
  • GitHub Check: Basic Tests / Run Simple Examples
  • GitHub Check: CLI Tests / CLI Functionality Tests
  • GitHub Check: Basic Tests / Run Basic Graph Tests
  • GitHub Check: CLI Tests / CLI Unit Tests
  • GitHub Check: CLI Tests / CLI Integration Tests
  • GitHub Check: End-to-End Tests / Test Feedback Enrichment
  • GitHub Check: End-to-End Tests / Concurrent Subprocess access test
  • GitHub Check: End-to-End Tests / Test Entity Extraction
  • GitHub Check: End-to-End Tests / Server Start Test
  • GitHub Check: End-to-End Tests / Test permissions with different situations in Cognee
  • GitHub Check: End-to-End Tests / Run Telemetry Pipeline Test
  • GitHub Check: End-to-End Tests / Test multi tenancy with different situations in Cognee
  • GitHub Check: End-to-End Tests / S3 Bucket Test
  • GitHub Check: End-to-End Tests / Deduplication Test
  • GitHub Check: End-to-End Tests / Conversation sessions test (Redis)
  • GitHub Check: End-to-End Tests / Conversation sessions test (FS)
🔇 Additional comments (1)
cognee/api/v1/ui/node_setup.py (1)

9-11: Consistent use of shared logger.

Using get_logger() from cognee.shared.logging_utils keeps logging consistent with the rest of the project; no issues here. As per coding guidelines, this matches the expected logging conventions.

Comment on lines +32 to +73
def check_nvm_installed() -> bool:
"""
Check if nvm (Node Version Manager) is installed.
"""
try:
# Check if nvm is available in the shell
# nvm is typically sourced in shell config files, so we need to check via shell
if platform.system() == "Windows":
# On Windows, nvm-windows uses a different approach
result = subprocess.run(
["nvm", "version"],
capture_output=True,
text=True,
timeout=10,
shell=True,
)
else:
# On Unix-like systems, nvm is a shell function, so we need to source it
# First check if nvm.sh exists
nvm_path = get_nvm_sh_path()
if not nvm_path.exists():
logger.debug(f"nvm.sh not found at {nvm_path}")
return False

# Try to source nvm and check version, capturing errors
result = subprocess.run(
["bash", "-c", f"source {nvm_path} && nvm --version"],
capture_output=True,
text=True,
timeout=10,
)

if result.returncode != 0:
# Log the error to help diagnose configuration issues
if result.stderr:
logger.debug(f"nvm check failed: {result.stderr.strip()}")
return False

return result.returncode == 0
except Exception as e:
logger.debug(f"Exception checking nvm: {str(e)}")
return False
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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n cognee/api/v1/ui/node_setup.py | head -80

Repository: topoteretes/cognee

Length of output: 3000


🏁 Script executed:

python3 << 'EOF'
import subprocess
import sys

# Test 1: Verify shell=True with sequence args behavior
print("=== Test 1: shell=True with sequence args ===")
print("Python version:", sys.version)
print()

# On most systems, let's check what happens with shell=True and a list
print("Subprocess.run documentation notes:")
print("- When shell=True and args is a sequence, Python passes args[0] to shell")
print("- This means with ['nvm', 'version'] + shell=True, only 'nvm' is executed")
print()

# Test with a simple command we can verify
print("Test with 'echo hello world':")
try:
    result = subprocess.run(
        ["echo", "hello", "world"],
        capture_output=True,
        text=True,
        shell=True
    )
    print(f"Command: ['echo', 'hello', 'world'] with shell=True")
    print(f"Output: {result.stdout}")
    print(f"Return code: {result.returncode}")
except Exception as e:
    print(f"Error: {e}")

print()
print("Test with string instead:")
try:
    result = subprocess.run(
        "echo hello world",
        capture_output=True,
        text=True,
        shell=True
    )
    print(f"Command: 'echo hello world' with shell=True")
    print(f"Output: {result.stdout}")
    print(f"Return code: {result.returncode}")
except Exception as e:
    print(f"Error: {e}")

print()
print("=== Test 2: Path with spaces in bash -c ===")
test_path_no_space = "/home/user/.nvm/nvm.sh"
test_path_with_space = "/home/user with space/.nvm/nvm.sh"

print(f"Unquoted path without spaces: source {test_path_no_space}")
print(f"Unquoted path with spaces: source {test_path_with_space}")
print("^ With spaces, bash would interpret it as multiple arguments")
EOF

Repository: topoteretes/cognee

Length of output: 148


🌐 Web query:

subprocess.run shell=True sequence args Python documentation

💡 Result:

Short answer: With shell=True you should pass args as a single string. If you pass a sequence, the first item is treated as the command string and any remaining items become arguments to the shell itself (not separate commands). On POSIX the effect is like Popen(['/bin/sh', '-c', args[0], args[1], ...]). Use a loop or join commands into one shell string if you want to run multiple shell commands. [1][2]

Examples:

  • Recommended: subprocess.run("ls -l /tmp; echo done", shell=True). [1]
  • If you pass a sequence: subprocess.run(["ls -l /tmp; echo done"], shell=True) — the sequence’s first element is given to the shell; additional list items become argv[1:], not additional shell commands. [1][2]

Sources: Python subprocess docs. [1][2]


🌐 Web query:

subprocess.run shell=True Windows behavior nvm command

💡 Result:

Short answer

  • On Windows, subprocess.run(..., shell=True) runs your command via the system shell (COMSPEC, normally cmd.exe). That means cmd.exe does the resolution/dispatch, not a POSIX shell. [1]
  • That causes two common nvm problems:
    1. nvm for Unix (the nvm.sh shell function) won’t work from cmd.exe — it’s a shell function that must be sourced in a compatible shell (bash). Use bash -c '. ~/.nvm/nvm.sh; nvm ...' instead. [3]
    2. nvm-windows may not be on the child process PATH (installer sets NVM_HOME/NVM_SYMLINK and requires a restart or correct PATH), or the Python CreateProcess path lookup behaves differently than cmd.exe. Call nvm by its installed executable path (or ensure NVM_HOME/NVM_SYMLINK are in os.environ['PATH'] for the Python process) or restart so PATH changes take effect. [2][1]
      Recommendations
  • Prefer calling the exact executable (shutil.which('nvm') or full path) instead of shell=True. This avoids shell semantics and security issues. [4][1]
  • If you must use a shell:
    • For nvm (POSIX): subprocess.run(['bash','-c', ". ~/.nvm/nvm.sh; nvm use 14; node -v"]) . [3]
    • For nvm-windows: ensure PATH contains NVM_HOME and NVM_SYMLINK for the Python process, or run cmd /c "nvm list" (but you may need to use full path or restart after install). [2][1]
      Sources
      [1] Python subprocess docs (shell=True on Windows / COMSPEC).
      [2] nvm-windows installation/FAQ and issues (NVM_HOME/NVM_SYMLINK / cmd vs PowerShell).
      [3] Stack Overflow: nvm works in bash but not when executed from Python (nvm is a shell function; source nvm.sh).
      [4] Blog/notes on subprocess on Windows: prefer resolving executable (shutil.which) vs using shell=True.

Fix Windows nvm check and quote sourced path for Unix shells.

Two issues here:

  1. On Windows, subprocess.run(["nvm", "version"], shell=True) is incorrect. With shell=True and a sequence, Python passes args[0] to the shell and remaining items become shell arguments (not command arguments). This means "version" is passed as an argument to the shell itself, not to nvm, potentially mis-detecting installation status.

    Use either:

    result = subprocess.run(
        ["nvm", "version"],
        capture_output=True,
        text=True,
        timeout=10,
    )

    or:

    result = subprocess.run(
        "nvm version",
        capture_output=True,
        text=True,
        timeout=10,
        shell=True,
    )
  2. On Unix-like systems, source {nvm_path} fails if nvm_path contains spaces. Quote the path:

    cmd = f'source "{nvm_path}" && nvm --version'
    result = subprocess.run(
        ["bash", "-c", cmd],
        capture_output=True,
        text=True,
        timeout=10,
    )
🤖 Prompt for AI Agents
cognee/api/v1/ui/node_setup.py around lines 32-73: the Windows nvm check is
using subprocess.run with shell=True and a sequence which mispasses arguments,
and the Unix `source {nvm_path}` invocation is unquoted so it will break on
paths with spaces. Fix by calling subprocess.run on Windows without shell=True
when passing a list (or alternatively pass a single string and keep shell=True),
e.g. use subprocess.run([...], capture_output=True, text=True, timeout=10)
instead of the current call; and on Unix build the bash -c command with the
nvm_path quoted (wrap the path in double quotes) before passing it to
subprocess.run(["bash","-c", cmd], capture_output=True, text=True, timeout=10).
Ensure the rest of the checks (returncode and stderr handling) remain unchanged.

Comment on lines +210 to +360
def check_node_npm() -> tuple[bool, str]: # (is_available, error_message)
"""
Check if Node.js and npm are available.
If not available, attempts to install nvm and Node.js automatically.
"""

try:
# Check Node.js - try direct command first, then with nvm if needed
result = subprocess.run(["node", "--version"], capture_output=True, text=True, timeout=10)
if result.returncode != 0:
# If direct command fails, try with nvm sourced (in case nvm is installed but not in PATH)
nvm_path = get_nvm_sh_path()
if nvm_path.exists():
result = subprocess.run(
["bash", "-c", f"source {nvm_path} && node --version"],
capture_output=True,
text=True,
timeout=10,
)
if result.returncode != 0 and result.stderr:
logger.debug(f"Failed to source nvm or run node: {result.stderr.strip()}")
if result.returncode != 0:
# Node.js is not installed, try to install it
logger.info("Node.js is not installed. Attempting to install automatically...")

# Check if nvm is installed
if not check_nvm_installed():
logger.info("nvm is not installed. Installing nvm first...")
if not install_nvm():
return (
False,
"Failed to install nvm. Please install Node.js manually from https://nodejs.org/",
)

# Install Node.js using nvm
if not install_node_with_nvm():
return (
False,
"Failed to install Node.js. Please install Node.js manually from https://nodejs.org/",
)

# Verify installation after automatic setup
# Try with nvm sourced first
nvm_path = get_nvm_sh_path()
if nvm_path.exists():
result = subprocess.run(
["bash", "-c", f"source {nvm_path} && node --version"],
capture_output=True,
text=True,
timeout=10,
)
if result.returncode != 0 and result.stderr:
logger.debug(
f"Failed to verify node after installation: {result.stderr.strip()}"
)
else:
result = subprocess.run(
["node", "--version"], capture_output=True, text=True, timeout=10
)
if result.returncode != 0:
nvm_path = get_nvm_sh_path()
return (
False,
f"Node.js installation completed but node command is not available. Please restart your terminal or source {nvm_path}",
)

node_version = result.stdout.strip()
logger.debug(f"Found Node.js version: {node_version}")

# Check npm - handle Windows PowerShell scripts
if platform.system() == "Windows":
# On Windows, npm might be a PowerShell script, so we need to use shell=True
result = subprocess.run(
["npm", "--version"], capture_output=True, text=True, timeout=10, shell=True
)
else:
# On Unix-like systems, if we just installed via nvm, we may need to source nvm
# Try direct command first
result = subprocess.run(
["npm", "--version"], capture_output=True, text=True, timeout=10
)
if result.returncode != 0:
# Try with nvm sourced
nvm_path = get_nvm_sh_path()
if nvm_path.exists():
result = subprocess.run(
["bash", "-c", f"source {nvm_path} && npm --version"],
capture_output=True,
text=True,
timeout=10,
)
if result.returncode != 0 and result.stderr:
logger.debug(f"Failed to source nvm or run npm: {result.stderr.strip()}")

if result.returncode != 0:
return False, "npm is not installed or not in PATH"

npm_version = result.stdout.strip()
logger.debug(f"Found npm version: {npm_version}")

return True, f"Node.js {node_version}, npm {npm_version}"

except subprocess.TimeoutExpired:
return False, "Timeout checking Node.js/npm installation"
except FileNotFoundError:
# Node.js is not installed, try to install it
logger.info("Node.js is not found. Attempting to install automatically...")

# Check if nvm is installed
if not check_nvm_installed():
logger.info("nvm is not installed. Installing nvm first...")
if not install_nvm():
return (
False,
"Failed to install nvm. Please install Node.js manually from https://nodejs.org/",
)

# Install Node.js using nvm
if not install_node_with_nvm():
return (
False,
"Failed to install Node.js. Please install Node.js manually from https://nodejs.org/",
)

# Retry checking Node.js after installation
try:
result = subprocess.run(
["node", "--version"], capture_output=True, text=True, timeout=10
)
if result.returncode == 0:
node_version = result.stdout.strip()
# Check npm
nvm_path = get_nvm_sh_path()
if nvm_path.exists():
result = subprocess.run(
["bash", "-c", f"source {nvm_path} && npm --version"],
capture_output=True,
text=True,
timeout=10,
)
if result.returncode == 0:
npm_version = result.stdout.strip()
return True, f"Node.js {node_version}, npm {npm_version}"
elif result.stderr:
logger.debug(f"Failed to source nvm or run npm: {result.stderr.strip()}")
except Exception as e:
logger.debug(f"Exception retrying node/npm check: {str(e)}")

return False, "Node.js/npm not found. Please install Node.js from https://nodejs.org/"
except Exception as e:
return False, f"Error checking Node.js/npm: {str(e)}"
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 | 🟠 Major

Fix subprocess argument handling and shell command path quoting in check_node_npm()

Two critical issues in the npm and nvm path handling:

  1. Windows npm check (around line 260): Using a list with shell=True drops arguments. Change:

    result = subprocess.run(
        ["npm", "--version"],
        capture_output=True,
        text=True,
        timeout=10,
        shell=True,
    )

    to use a string instead:

    result = subprocess.run(
        "npm --version",
        capture_output=True,
        text=True,
        timeout=10,
        shell=True,
    )
  2. Unquoted nvm.sh paths in shell commands: All occurrences of f"source {nvm_path} && ..." assume no spaces in the path. Quote the path to handle non-standard XDG/home directories:

    cmd = f'source "{nvm_path}" && node --version'

    Apply the same quoting pattern to all similar shell command constructions (nvm + npm checks).

Optional: Factor the repeated "ensure nvm + Node installed" logic (appearing in both main try block and FileNotFoundError handler) into a helper function to reduce duplication.

🤖 Prompt for AI Agents
In cognee/api/v1/ui/node_setup.py around lines 210 to 360, fix two subprocess
invocation bugs: when calling subprocess.run(..., shell=True) on Windows pass a
single string command (e.g. "npm --version") instead of a list so arguments are
not dropped, and wrap any inserted nvm_sh path in quotes in the bash -c commands
(e.g. source "{nvm_path}" && ...) to handle paths with spaces; update all
occurrences of f"source {nvm_path} && ..." to use quoted paths and change the
Windows npm subprocess.run call to use a string command with shell=True;
optionally extract the repeated "ensure nvm + node installed" sequence into a
helper to remove duplication.

@Vasilije1990 Vasilije1990 merged commit 40bbdd1 into dev Dec 8, 2025
108 of 111 checks passed
@Vasilije1990 Vasilije1990 deleted the feature/cog-3441-cognee-cli-ui-fix branch December 8, 2025 04:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants