Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions apps/backend/analysis/analyzers/project_analyzer_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,24 @@ def _find_and_analyze_services(self) -> None:
"language"
): # Only include if we detected something
services[item.name] = service_info

# Also check the project root itself for dependencies.
# Monorepo roots often have their own package.json + node_modules
# (e.g., npm/pnpm workspaces) that need to be shared with worktrees.
already_covered = self.project_dir in {
Path(s.get("path", "")) for s in services.values()
}
if not already_covered:
dep_indicators = ("package.json", "requirements.txt", "pyproject.toml")
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This tuple of dependency indicator files is hardcoded. For better maintainability and clarity, consider defining this as a named constant at the module level, for example ROOT_DEPENDENCY_FILES. This makes the purpose of this list explicit and easier to update in the future.

root_has_deps = any(
(self.project_dir / f).exists() for f in dep_indicators
)
if root_has_deps:
root_analyzer = ServiceAnalyzer(self.project_dir, "root")
root_info = root_analyzer.analyze()
root_deps = root_info.get("dependency_locations", [])
if root_deps:
services["root"] = root_info
Comment on lines +123 to +136
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

Avoid overwriting a real root service and harden root coverage detection.

Line 136 unconditionally writes services["root"], which can clobber an actual discovered service named root. Also, Line 123-Line 125 compares non-normalized paths, which can mis-detect already_covered and trigger unintended insertion.

Proposed fix
-            already_covered = self.project_dir in {
-                Path(s.get("path", "")) for s in services.values()
-            }
+            discovered_paths: set[Path] = set()
+            for service in services.values():
+                raw_path = service.get("path")
+                if not raw_path:
+                    continue
+                discovered_paths.add(Path(raw_path).resolve())
+            already_covered = self.project_dir in discovered_paths
             if not already_covered:
                 dep_indicators = ("package.json", "requirements.txt", "pyproject.toml")
                 root_has_deps = any(
                     (self.project_dir / f).exists() for f in dep_indicators
                 )
                 if root_has_deps:
                     root_analyzer = ServiceAnalyzer(self.project_dir, "root")
                     root_info = root_analyzer.analyze()
                     root_deps = root_info.get("dependency_locations", [])
                     if root_deps:
-                        services["root"] = root_info
+                        root_key = "root" if "root" not in services else "project_root"
+                        services[root_key] = root_info
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/backend/analysis/analyzers/project_analyzer_module.py` around lines 123
- 136, The check for already_covered should compare normalized/resolved paths
and the insertion of a synthetic root should not clobber a real service named
"root"; modify the logic that builds already_covered to use Path(...).resolve()
(or .absolute()) for each s.get("path") and self.project_dir.resolve(), and
before assigning services["root"] ensure you do not overwrite an existing key
(e.g., skip if "root" in services or choose a non-colliding key), and keep the
existing creation flow that uses ServiceAnalyzer(self.project_dir, "root") and
root_info.get("dependency_locations") to populate the synthetic root only when
safe.

else:
# Single project - analyze root
analyzer = ServiceAnalyzer(self.project_dir, "main")
Expand Down
6 changes: 4 additions & 2 deletions apps/frontend/src/main/app-logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ log.transports.file.fileName = 'main.log';
// Note: We use electron-log's default archiveLogFn which properly rotates logs
// by renaming old files to .old format. Custom implementations were problematic.

// Console transport - always show warnings and errors, debug only in dev mode
log.transports.console.level = process.env.NODE_ENV === 'development' ? 'debug' : 'warn';
// Console transport - enable in dev mode only; in production (packaged app) console.log
// writes to a pipe/PTY whose buffer can fill up, blocking the main thread synchronously
// and causing UI hangs (see: hang report 2026-02-25, 66s freeze on write()).
log.transports.console.level = process.env.NODE_ENV === 'development' ? 'debug' : false;
log.transports.console.format = '[{h}:{i}:{s}] [{level}] {text}';
// Guard console transport writes so broken stdio streams do not crash the app.
{
Expand Down
Loading