feat: Import Existing Projects (#134)#140
feat: Import Existing Projects (#134)#140cabana8471-arch wants to merge 9 commits intoAutoForgeAI:masterfrom
Conversation
Add analyzers module with support for: - React/Next.js projects (App Router, Pages Router) - Node.js/Express/NestJS/Fastify/Koa - Python/FastAPI/Django/Flask - Vue.js/Nuxt Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Endpoints: - POST /api/import/analyze - Detect tech stack - POST /api/import/extract-features - Generate features - POST /api/import/create-features - Create in database - GET /api/import/quick-detect - Fast UI preview Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Closes AutoForgeAI#134 - Add ImportProjectModal with 6-step wizard - Add useImportProject hook for state management - Update NewProjectModal with project type selection - Migrate styling to neobrutalism design system Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📝 WalkthroughWalkthroughAdds a suite of analyzers and a StackDetector to detect project stacks, a feature extractor to turn detections into Autocoder features, server endpoints to analyze/extract/create features, and a multi-step UI + hook to import projects and persist detected features. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant UI as "Browser UI"
participant API as "FastAPI /api/import"
participant Detector as "StackDetector"
participant Analyzer as "Analyzers (Node/Python/React/Vue)"
participant Extractor as "FeatureExtractor"
participant DB as "Database"
User->>UI: select folder
UI->>API: POST /analyze
API->>Detector: detect(project_dir)
Detector->>Analyzer: can_analyze() / analyze()
Analyzer-->>Detector: AnalysisResult
Detector-->>API: StackDetectionResult
API-->>UI: detected stacks & counts
User->>UI: request feature extraction
UI->>API: POST /extract-features
API->>Extractor: extract_from_project(project_dir)
Extractor->>Detector: uses detection result
Extractor-->>API: FeatureExtractionResult
API-->>UI: features by category
User->>UI: create features
UI->>API: POST /create-features
API->>DB: create features (bulk)
DB-->>API: creation summary
API-->>UI: success
sequenceDiagram
participant StackDetector
participant NodeAnalyzer
participant PythonAnalyzer
participant ReactAnalyzer
participant VueAnalyzer
StackDetector->>NodeAnalyzer: can_analyze()
alt confidence > 0.3
StackDetector->>NodeAnalyzer: analyze()
NodeAnalyzer-->>StackDetector: AnalysisResult
end
StackDetector->>PythonAnalyzer: can_analyze()
alt confidence > 0.3
StackDetector->>PythonAnalyzer: analyze()
PythonAnalyzer-->>StackDetector: AnalysisResult
end
StackDetector->>ReactAnalyzer: can_analyze()
alt confidence > 0.3
StackDetector->>ReactAnalyzer: analyze()
ReactAnalyzer-->>StackDetector: AnalysisResult
end
StackDetector->>VueAnalyzer: can_analyze()
alt confidence > 0.3
StackDetector->>VueAnalyzer: analyze()
VueAnalyzer-->>StackDetector: AnalysisResult
end
StackDetector->>StackDetector: aggregate & pick primaries
StackDetector-->>Caller: StackDetectionResult
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Fix all issues with AI agents
In `@analyzers/feature_extractor.py`:
- Around line 242-278: The feature name for endpoint-derived features is
generated with _route_to_feature_name(path, method) which yields page-style
names for non-/api paths (e.g., "/users" -> "View Users page"); force API-style
naming by calling a dedicated API naming path or helper: either call a
new/available _route_to_api_feature_name(path, method) or normalize the input to
_route_to_feature_name by prefixing the path with "/api" when path does not
start with "/api" before computing feature_name; update the feature_name
assignment (and optionally the description) where _route_to_feature_name is used
so endpoint features are always labeled as API features and keep the rest of the
feature object/population (features.append, seen_features logic) unchanged.
In `@analyzers/node_analyzer.py`:
- Around line 223-271: The _extract_nestjs_routes function constructs base_path
by unconditionally prepending "/" to controller_match.group(1), causing "//"
when the controller decorator already has a leading slash; update the logic that
computes base_path (look for controller_match and the variable base_path) to
strip any leading/trailing slashes from controller_match.group(1) first and then
prefix a single "/" (or use empty string when no controller path), and build
full_path by joining base_path and method path while ensuring you don't rely on
a trailing .replace("//", "/") hack so controllers without method paths don't
emit malformed routes.
In `@analyzers/react_analyzer.py`:
- Around line 173-213: _extract_app_router_routes currently only searches for
"page.tsx" and "page.jsx", missing "page.ts" and "page.js" files; update the
function to scan all four Next.js page filename patterns (page.js, page.jsx,
page.ts, page.tsx) — e.g., loop over a list of patterns or use a single glob
that matches those extensions — and reuse the same path-normalization (rel_path,
route_path, dynamic route regex, cleanup) and route dict creation (path, method,
handler, file using self.project_dir) for each matched file so JavaScript-only
and TypeScript-only pages are discovered too.
In `@analyzers/stack_detector.py`:
- Around line 95-105: The categorization logic for analyzer.stack_name only
matches exact base names, so variants like "react-vite", "react-cra",
"vue-vite", "vue-cli" or other stacks such as "nodejs", "fastify", and "koa"
fall into "other"; update the code that sets category to normalize and
pattern-match stack names instead of exact equality: convert analyzer.stack_name
to lower(), strip common suffixes/prefixes (e.g., "-vite", "-cra", "-cli"), and
then check membership or use startswith/contains for core identifiers ("react",
"vue", "next", "angular" → frontend; "express", "fastapi", "fastify", "django",
"flask", "nestjs", "node", "nodejs", "koa" → backend; "postgres", "mysql",
"mongodb", "sqlite" → database), assigning category accordingly to ensure
primary_frontend/primary_backend are set.
In `@server/routers/import_project.py`:
- Around line 40-45: The validate_path function is too permissive (it rejects
any substring ".." but misses path parts like "foo..bar") and the
/extract-features and /quick-detect handlers lack directory checks; update
validate_path to normalize and inspect path parts (e.g., use
pathlib.Path(path).parts) and explicitly reject any path part equal to ".." or
containing null bytes, and require absolute or expected base path semantics
consistent with the existing /analyze behavior; then add an is_dir() guard in
the extract-features and quick-detect handlers (functions named extract_features
and quick_detect) to verify the target is a directory before proceeding,
returning an appropriate error if not.
In `@ui/src/components/ImportProjectModal.tsx`:
- Around line 138-147: The Back/“Try Again” flow ignores the 'analyzing' state,
so update the handleBack function to handle step === 'analyzing' by resetting to
the folder selection: add an else-if branch for "analyzing" that calls
setStep('folder') and reset() (same behavior as the 'detected' branch) so the
button correctly backs out after a failed analysis; reference the handleBack
function, step variable, setStep and reset calls to locate where to add this
case.
- Fix API feature naming for non-/api paths - Normalize NestJS controller paths to avoid // routes - Include .js/.ts page files in Next.js route discovery - Categorize stack variants (react-vite, vue-cli, etc.) - Tighten path validation with Path.parts check - Add is_dir() checks to extract-features/quick-detect - Fix Back button in import modal for failed analysis Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@ui/src/components/ImportProjectModal.tsx`:
- Line 12: The modal may leave a pending setTimeout that later calls
onProjectImported/handleClose after the modal has closed; update the
ImportProjectModal component to store the timeout id (e.g., in a ref or state)
when you call setTimeout (the timeout created in the import completion flow) and
clear it via clearTimeout both when the modal is programmatically closed
(handleClose) and in a useEffect cleanup/unmount; ensure any code paths that
call onProjectImported use the cleared/checked timeout so no callback fires
after unmount.
- Line 36: The Step union lacks an 'error' variant and the analyze/extract
failure paths never update step, so users get stuck; add 'error' to the Step
type (type Step = 'folder' | 'analyzing' | 'detected' | 'features' | 'register'
| 'complete' | 'error'), add a component state like errorMessage (or reuse
existing error state) and update all async failure handlers (the analyze/extract
functions that set step to 'analyzing' or 'detected' — e.g., the
analyzeProject/extractFeatures handlers referenced around lines 76-91) to set
step = 'error' and set the errorMessage; ensure the render logic for the 'error'
step displays the errorMessage so the error view becomes reachable.
- Around line 101-112: Validate projectName in handleRegisterAndCreate before
calling createProject.mutateAsync: add a regex test (matching the same pattern
used by the input control) and if it fails call setRegisterError with a clear
message and return early; ensure you still trim the name, and only proceed to
invoke createProject.mutateAsync with the validated trimmed name when the regex
passes.
🧹 Nitpick comments (6)
analyzers/react_analyzer.py (3)
148-171: Potential duplicate routes when bothapp/andsrc/app/exist.If a project has both
app/andsrc/app/directories (or bothpages/andsrc/pages/), routes from both will be collected, potentially leading to duplicates. Consider deduplicating or checking for this edge case.♻️ Suggested approach
def _extract_nextjs_routes(self) -> list[RouteInfo]: """Extract routes from Next.js file-based routing.""" routes: list[RouteInfo] = [] + seen_paths: set[str] = set() # Check for App Router (Next.js 13+) app_dir = self.project_dir / "app" - if app_dir.exists(): + if app_dir.exists() and app_dir.is_dir(): routes.extend(self._extract_app_router_routes(app_dir)) + seen_paths.update(r["path"] for r in routes) # Check for Pages Router pages_dir = self.project_dir / "pages" - if pages_dir.exists(): - routes.extend(self._extract_pages_router_routes(pages_dir)) + if pages_dir.exists() and pages_dir.is_dir(): + for route in self._extract_pages_router_routes(pages_dir): + if route["path"] not in seen_paths: + routes.append(route) + seen_paths.add(route["path"]) # Also check src/app and src/pages (skip if root versions exist) src_app = self.project_dir / "src" / "app" - if src_app.exists(): - routes.extend(self._extract_app_router_routes(src_app)) + if src_app.exists() and src_app.is_dir() and not app_dir.exists(): + routes.extend(self._extract_app_router_routes(src_app)) src_pages = self.project_dir / "src" / "pages" - if src_pages.exists(): - routes.extend(self._extract_pages_router_routes(src_pages)) + if src_pages.exists() and src_pages.is_dir() and not pages_dir.exists(): + routes.extend(self._extract_pages_router_routes(src_pages)) return routes
232-262: Missing.tsxand.jsxextensions for App Router API routes.Lines 257-260 only scan for
route.tsandroute.js, but Next.js App Router also supportsroute.tsxandroute.jsxfor API routes (though less common). For consistency with page file handling, consider including all extensions.♻️ Suggested fix
for app_api in app_api_dirs: if app_api.exists(): - for route_file in app_api.rglob("route.ts"): - endpoints.extend(self._parse_app_router_api(route_file, app_api)) - for route_file in app_api.rglob("route.js"): - endpoints.extend(self._parse_app_router_api(route_file, app_api)) + for pattern in ("route.ts", "route.js", "route.tsx", "route.jsx"): + for route_file in app_api.rglob(pattern): + endpoints.extend(self._parse_app_router_api(route_file, app_api))
279-308: Consider handling named exports withconstfor App Router API methods.The method detection pattern only matches
export async function GETorexport function GET. Next.js App Router also supports arrow function exports likeexport const GET = async (req) => {...}. This could miss valid API handlers.♻️ Suggested fix to detect both patterns
# Try to detect which methods are exported content = self._read_file_safe(route_file) methods = [] if content: for method in ["GET", "POST", "PUT", "PATCH", "DELETE"]: - if f"export async function {method}" in content or \ - f"export function {method}" in content: + if (f"export async function {method}" in content or + f"export function {method}" in content or + f"export const {method}" in content): methods.append(method)analyzers/feature_extractor.py (2)
284-328: Consider expanding the skip list for common/generic components.The current skip list (
index,app,main,layout,_app,_document) covers common Next.js/React files but might miss other generic components that provide little value as features. Consider expanding this list.♻️ Suggested expansion
# Skip common/generic components - skip_names = ["index", "app", "main", "layout", "_app", "_document"] + skip_names = [ + "index", "app", "main", "layout", "_app", "_document", + "header", "footer", "sidebar", "navbar", "nav", + "loading", "error", "not-found", "404", "500", + ] if name.lower() in skip_names: continue
326-348: Magic number for component feature limit.The threshold of 10 features and the limit of 10 component features are magic numbers. Consider extracting these as named constants for clarity and easier adjustment.
♻️ Suggested refactor
+# Feature extraction thresholds +MIN_FEATURES_BEFORE_COMPONENTS = 10 +MAX_COMPONENT_FEATURES = 10 + def extract_features(detection_result: StackDetectionResult) -> FeatureExtractionResult: ... # Add component features if we don't have many from routes/endpoints - if len(features) < 10: - features.extend(component_features[:10]) # Limit to 10 component features + if len(features) < MIN_FEATURES_BEFORE_COMPONENTS: + features.extend(component_features[:MAX_COMPONENT_FEATURES])analyzers/stack_detector.py (1)
126-128: Use logging instead of print for warnings.Line 128 uses
print()for warning output. For consistency with production code and proper log management, use theloggingmodule instead.♻️ Suggested fix
+import logging + +logger = logging.getLogger(__name__) + ... except Exception as e: # Log but don't fail - continue with other analyzers - print(f"Warning: {analyzer.stack_name} analyzer failed: {e}") + logger.warning(f"{analyzer.stack_name} analyzer failed: {e}")
- Add setTimeout cleanup to prevent callback after unmount - Add 'error' to Step type for proper error state handling - Validate projectName format before API call - Deduplicate Next.js routes (prefer root over src/) - Scan all extensions for App Router API routes (.tsx, .jsx) - Detect const export pattern for API handlers - Expand component skip list with common generic names - Extract magic numbers as named constants - Use logging instead of print for analyzer warnings Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@analyzers/feature_extractor.py`:
- Around line 256-260: The code currently prefixes "/api" blindly causing "/api"
to become "/api/api"; fix by special-casing the root API path: if the incoming
path (variable path / name_path) equals "/api" or "/api/" (use rstrip to
normalize) leave name_path as "/api" (ensure it has a leading slash), otherwise
apply the existing prefix logic only when
name_path.lstrip("/").startswith("api") is false; then pass the normalized
name_path to _route_to_feature_name(name_path, method).
In `@analyzers/react_analyzer.py`:
- Around line 116-120: The entry-point detection loop in react_analyzer.py only
checks .tsx/.jsx files so self.project_dir / entry may leave entry_point unset
for pure .ts/.js projects; update the loop that iterates over the entry list to
include .ts and .js variants for common entries (e.g., add "src/main.ts",
"src/main.js", "src/index.ts", "src/index.js", and "pages/_app.ts",
"pages/_app.js") and remove the invalid "app/layout.ts" entry; ensure the code
still assigns entry_point when (self.project_dir / entry).exists().
In `@analyzers/stack_detector.py`:
- Around line 98-115: The stack categorization maps analyzer.stack_name to
category but currently omits the generic "python" value, causing
analyzer.stack_name == "python" to be classified as "other"; update the backend
branch that checks analyzer.stack_name (the tuple in the elif that sets category
= "backend") to include "python" among the listed backend identifiers so generic
Python projects are classified as backend (no other logic changes needed; note
stack_name is already lowercased).
🧹 Nitpick comments (4)
ui/src/components/ImportProjectModal.tsx (3)
267-268: Inconsistent error state check may cause unreliable error display.The error render condition checks only
state.step === 'error'(from the hook), but the component also manages a localstepstate that gets set to'error'inhandleFolderSelectandhandleExtractFeatures. While the hook likely also sets its internal step to'error', for consistency with the'analyzing'step pattern (line 236), consider using a unified check.🔧 Suggested fix for consistency
- if (state.step === 'error') { + if (step === 'error' || state.step === 'error') {
474-480: Consider using a stable key instead of array index.Using the array index
ias the React key can cause issues if features are reordered or filtered. Since features havenameandcategory, a composite key would be more stable.🔧 Suggested fix
- {featuresByCategory[category]?.map((feature, i) => { + {featuresByCategory[category]?.map((feature) => { const isSelected = state.selectedFeatures.some( f => f.name === feature.name && f.category === feature.category ) return ( <div - key={i} + key={`${feature.category}-${feature.name}`} onClick={() => toggleFeature(feature)}
199-206: Consider adding keyboard accessibility for the modal.The modal closes on backdrop click but doesn't handle the Escape key. Adding keyboard support and ARIA attributes would improve accessibility.
🔧 Suggested improvement
+ // Handle Escape key to close modal + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === 'Escape') { + handleClose() + } + } + if (isOpen) { + document.addEventListener('keydown', handleKeyDown) + return () => document.removeEventListener('keydown', handleKeyDown) + } + }, [isOpen]) // Folder selection step if (step === 'folder') { return ( - <div className="neo-modal-backdrop" onClick={handleClose}> + <div className="neo-modal-backdrop" onClick={handleClose} role="dialog" aria-modal="true" aria-labelledby="import-modal-title"> <div className="neo-modal w-full max-w-3xl max-h-[85vh] flex flex-col" onClick={(e) => e.stopPropagation()} > <div className="flex items-center justify-between p-4 border-b-3 border-[var(--color-neo-border)]"> <div className="flex items-center gap-3"> <Folder size={24} className="text-[var(--color-neo-progress)]" /> <div> - <h2 className="font-display font-bold text-xl text-[var(--color-neo-text)]"> + <h2 id="import-modal-title" className="font-display font-bold text-xl text-[var(--color-neo-text)]"> Import Existing Project </h2>analyzers/react_analyzer.py (1)
312-358: Include.ts/.jsfiles in React Router route discovery.React Router's
createBrowserRouteris commonly defined in plain.ts/.jsfiles (usingRouteObjectarrays withComponent/ErrorBoundaryfields instead of JSX), but the current scan at line 317 only covers.tsx/.jsxfiles. This limitation causes route configurations in.ts/.jsfiles to be missed.Suggested update
- route_files = self._find_files("**/*.tsx") + self._find_files("**/*.jsx") + route_files = ( + self._find_files("**/*.tsx") + self._find_files("**/*.jsx") + + self._find_files("**/*.ts") + self._find_files("**/*.js") + )
- Fix API path double-prefixing bug (/api becoming /api/api) - Add .ts/.js entry-point variants for pure JS/TS projects - Classify Python stack as backend (not other) - Fix inconsistent error state check in ImportProjectModal - Use stable composite keys for feature list items - Add Escape key support for modal accessibility - Include .ts/.js files in React Router route discovery Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@analyzers/react_analyzer.py`:
- Around line 372-386: The component and page discovery currently builds
component_files and page_files by calling _find_files with only **/*.tsx and
**/*.jsx patterns; update both calls to also include **/*.js (i.e., call
self._find_files("**/components/**/*.js") and
self._find_files("**/pages/**/*.js") alongside the existing patterns) so that
JavaScript files are included when populating components and pages (look for the
component_files, page_files variables and the _find_files helper).
In `@ui/src/components/ImportProjectModal.tsx`:
- Around line 113-175: Add an "active" ref guard to bail out of async handlers
when the modal is closed/unmounted: create a ref like isActiveRef and set
isActiveRef.current = true on mount/open and false on close/unmount (e.g., in
the modal's open/close lifecycle or useEffect cleanup). In handleFolderSelect,
handleExtractFeatures, and handleRegisterAndCreate check isActiveRef.current
immediately after each await (and before calling setStep, setProjectName,
setRegisterError, redirectTimeoutRef.current assignment, or calling
onProjectImported/handleClose) and return early if false; also clear any pending
redirectTimeoutRef when closing. Ensure you reference the existing
functions/values analyze, extractFeatures, createFeatures,
createProject.mutateAsync, state.projectPath, projectName, and handleClose so
the guard prevents stale state updates after the modal is closed.
🧹 Nitpick comments (1)
analyzers/feature_extractor.py (1)
120-123: Normalize stack variants before infra checks.
primary_frontendandprimary_backendcan be variant names (e.g.,react-vite,vue-cli,fastify,koa,nodejs,python), so the infra features/steps won’t trigger. Consider normalizing or extending the lists.🛠️ Proposed refactor
def _generate_page_steps(path: str, stack: str | None) -> list[str]: @@ - if stack in ("react", "nextjs", "vue", "nuxt"): + base_stack = stack.split("-")[0] if stack else None + if base_stack in ("react", "nextjs", "vue", "nuxt", "angular"): steps.append("Verify no console errors in browser developer tools") steps.append("Verify responsive layout at mobile and desktop widths") @@ def _generate_basic_features(detection_result: StackDetectionResult) -> list[DetectedFeature]: @@ - if primary_frontend in ("react", "nextjs", "vue", "nuxt"): + frontend_base = primary_frontend.split("-")[0] if primary_frontend else None + if frontend_base in ("react", "nextjs", "vue", "nuxt", "angular"): features.append({ @@ - if primary_backend in ("express", "fastapi", "django", "flask", "nestjs"): + backend_base = primary_backend.split("-")[0] if primary_backend else None + if backend_base in ("express", "fastify", "koa", "nodejs", "fastapi", "django", "flask", "nestjs", "python"): features.append({Also applies to: 385-404
- Add .js files to component/page discovery in react_analyzer.py - Normalize stack variants (react-vite, fastify, etc.) for infra features - Add isActiveRef guard to prevent state updates after modal closes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@analyzers/react_analyzer.py`:
- Around line 249-255: The API route discovery loop in react_analyzer.py only
handles .ts and .js, missing .tsx and .jsx so Pages Router API routes are
skipped; update the loop that iterates api_dirs (the block that calls
self._parse_api_route for each api_file and extends endpoints) to include .tsx
and .jsx files as well (or refactor to iterate a list of extensions like
[".ts",".js",".tsx",".jsx"] and call self._parse_api_route for each match)
ensuring the endpoints list is populated from .tsx/.jsx files too.
🧹 Nitpick comments (7)
analyzers/react_analyzer.py (4)
117-125: Removeapp/layout.tsfrom entry point candidates.Next.js App Router only supports
.js,.jsx, and.tsxextensions for layout files—not.ts. Includingapp/layout.tsadds an unnecessary file check that will never match a valid Next.js project.♻️ Suggested fix
for entry in [ "src/main.tsx", "src/main.ts", "src/main.jsx", "src/main.js", "src/index.tsx", "src/index.ts", "src/index.jsx", "src/index.js", "pages/_app.tsx", "pages/_app.ts", "pages/_app.jsx", "pages/_app.js", - "app/layout.tsx", "app/layout.ts", "app/layout.jsx", "app/layout.js", + "app/layout.tsx", "app/layout.jsx", "app/layout.js", ]:
180-205: Potential duplicate routes when multiple page file extensions exist.If a directory contains both
page.tsxandpage.js(e.g., during a migration), this will emit duplicate routes for the same path. Consider deduplicating by route path.♻️ Optional: deduplicate by path
def _extract_app_router_routes(self, app_dir: Path) -> list[RouteInfo]: """Extract routes from Next.js App Router.""" routes: list[RouteInfo] = [] + seen_paths: set[str] = set() # Check all page file extensions: .tsx, .jsx, .ts, .js for pattern in ("page.tsx", "page.jsx", "page.ts", "page.js"): for page_file in app_dir.rglob(pattern): rel_path = page_file.relative_to(app_dir) route_path = "/" + "/".join(rel_path.parent.parts) # Handle dynamic routes: [id] -> :id route_path = re.sub(r"\[([^\]]+)\]", r":\1", route_path) # Clean up if route_path == "/.": route_path = "/" route_path = route_path.replace("//", "/") + # Skip if we've already seen this route + if route_path in seen_paths: + continue + seen_paths.add(route_path) + routes.append({ "path": route_path, "method": "GET", "handler": "Page", "file": str(page_file.relative_to(self.project_dir)), }) return routes
293-304: Consider detectingHEADandOPTIONSHTTP methods.Next.js App Router also supports
HEADandOPTIONSexports. Currently onlyGET,POST,PUT,PATCH,DELETEare detected. This is a minor completeness gap.♻️ Optional enhancement
- for method in ["GET", "POST", "PUT", "PATCH", "DELETE"]: + for method in ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]:
328-337: Consider removingre.IGNORECASEfrom route patterns.JSX/TSX is case-sensitive, and
<Route>must be capitalized. TheIGNORECASEflag on line 330 is unnecessary and could potentially match unintended patterns. Thebrowser_router_patternon line 334 also uses it unnecessarily for JavaScript object syntax.♻️ Optional: remove IGNORECASE
# Pattern for React Router <Route> elements route_pattern = re.compile( - r'<Route\s+[^>]*path=["\']([^"\']+)["\'][^>]*>', - re.IGNORECASE + r'<Route\s+[^>]*path=["\']([^"\']+)["\'][^>]*>' ) # Pattern for createBrowserRouter routes browser_router_pattern = re.compile( - r'{\s*path:\s*["\']([^"\']+)["\']', - re.IGNORECASE + r'{\s*path:\s*["\']([^"\']+)["\']' )ui/src/components/ImportProjectModal.tsx (3)
273-303: Missing accessibility attributes on analyzing modal.The folder step (line 240) has
role="dialog",aria-modal="true", andaria-labelledby, but the analyzing step modal (line 276) and other step modals lack these attributes. For consistent accessibility, all modal backdrops should have these attributes.♻️ Add accessibility attributes
- <div className="neo-modal-backdrop" onClick={handleClose}> + <div className="neo-modal-backdrop" role="dialog" aria-modal="true" onClick={handleClose}>Apply this pattern to all modal backdrops (analyzing, error, detected, features, register, complete steps).
322-332: Handle missing error message gracefully.Line 327 displays
{state.error}which could benullorundefinedif the error state was triggered without a message. Consider providing a fallback message.♻️ Add fallback error message
- <p className="text-[var(--color-neo-error-text)] mb-4">{state.error}</p> + <p className="text-[var(--color-neo-error-text)] mb-4"> + {state.error || 'An unexpected error occurred. Please try again.'} + </p>
516-551: Add keyboard accessibility to feature selection.The feature items use
onClickon adiv(line 519) but lack keyboard support. Users navigating with keyboards cannot select/deselect features. Consider addingrole="checkbox",tabIndex={0}, andonKeyDownhandler for Enter/Space.♻️ Add keyboard accessibility
<div key={`${feature.category}-${feature.name}`} onClick={() => toggleFeature(feature)} + onKeyDown={(e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault() + toggleFeature(feature) + } + }} + role="checkbox" + aria-checked={isSelected} + tabIndex={0} className={` flex items-start gap-3 p-3 cursor-pointer transition-all
| for api_dir in api_dirs: | ||
| if api_dir.exists(): | ||
| for api_file in api_dir.rglob("*.ts"): | ||
| endpoints.extend(self._parse_api_route(api_file, api_dir)) | ||
| for api_file in api_dir.rglob("*.js"): | ||
| endpoints.extend(self._parse_api_route(api_file, api_dir)) | ||
|
|
There was a problem hiding this comment.
Missing .tsx/.jsx extensions for Pages Router API routes.
Lines 251-254 only scan .ts and .js files, but Pages Router API routes can also use .tsx and .jsx extensions. This is inconsistent with other file discovery patterns in this analyzer.
🐛 Proposed fix
for api_dir in api_dirs:
if api_dir.exists():
- for api_file in api_dir.rglob("*.ts"):
- endpoints.extend(self._parse_api_route(api_file, api_dir))
- for api_file in api_dir.rglob("*.js"):
- endpoints.extend(self._parse_api_route(api_file, api_dir))
+ for ext in ("ts", "tsx", "js", "jsx"):
+ for api_file in api_dir.rglob(f"*.{ext}"):
+ endpoints.extend(self._parse_api_route(api_file, api_dir))🤖 Prompt for AI Agents
In `@analyzers/react_analyzer.py` around lines 249 - 255, The API route discovery
loop in react_analyzer.py only handles .ts and .js, missing .tsx and .jsx so
Pages Router API routes are skipped; update the loop that iterates api_dirs (the
block that calls self._parse_api_route for each api_file and extends endpoints)
to include .tsx and .jsx files as well (or refactor to iterate a list of
extensions like [".ts",".js",".tsx",".jsx"] and call self._parse_api_route for
each match) ensuring the endpoints list is populated from .tsx/.jsx files too.
- Remove app/layout.ts from entry points (not valid in Next.js) - Deduplicate App Router routes when multiple extensions exist - Add HEAD and OPTIONS HTTP method detection - Remove unnecessary re.IGNORECASE from route patterns - Add accessibility attributes to all modal backdrops - Add fallback error message for error state - Add keyboard accessibility to feature selection checkboxes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Renamed 'content' to 'main_content' and 'app_content' in python_analyzer.py to avoid type narrowing conflicts with earlier str-typed variable - Added type annotation for _analyzers list in stack_detector.py Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…lidator (Feature AutoForgeAI#140) - Added LintCleanValidator to api/validators.py following existing validator pattern - Accepts linter command in config, runs it, checks exit code for zero errors - Supports error_pattern regex for counting lint issues in output - Registered in VALIDATOR_REGISTRY so it can be resolved by name - Exported from api/__init__.py - 52 tests in test_feature_140_lint_clean_validator.py all passing - Verified with sample linter commands (flake8, ruff-style output) - No regressions in existing 172 validator tests Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
@cabana8471-arch this would be a sweet feature! |
Summary
Closes #134 - Adds ability to import existing codebases into Autocoder.
Changes
Backend
analyzers/- New module with stack detection and feature extractionserver/routers/import_project.py- REST API endpointsFrontend
ui/src/components/ImportProjectModal.tsx- 6-step import wizardui/src/hooks/useImportProject.ts- Import workflow hookui/src/components/NewProjectModal.tsx- Add "Import Existing" optionTest plan
ruff check .mypy .cd ui && npm run build🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Backend
Analyzers
UI
✏️ Tip: You can customize this high-level summary in your review settings.