ai-first-cli 1.3.0 → 1.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.ai-dev/index.db +0 -0
- package/.github/workflows/publish.yml +4 -1
- package/BETA_EVALUATION_REPORT.md +151 -0
- package/CHANGELOG.md +178 -0
- package/PHASE1_USER_SIMULATION.md +56 -0
- package/PHASE2_USER_SIMULATION.md +81 -0
- package/PHASE3_USER_SIMULATION.md +176 -0
- package/README.es.md +18 -0
- package/README.md +80 -1
- package/ai/graph/knowledge-graph.json +10 -0
- package/ai-context/ai_context.md +130 -0
- package/{test-projects/react-app/.ai-dev → ai-context}/ai_rules.md +10 -5
- package/ai-context/architecture.md +136 -0
- package/ai-context/context/features/src.json +69 -0
- package/ai-context/context/features/test-projects.json +69 -0
- package/ai-context/context/flows/App.json +17 -0
- package/ai-context/context/flows/DashboardPage.json +14 -0
- package/ai-context/context/flows/LoginPage.json +14 -0
- package/ai-context/context/flows/admin.json +10 -0
- package/ai-context/context/flows/ai-first.json +9 -0
- package/ai-context/context/flows/androidresources.json +11 -0
- package/ai-context/context/flows/auth.json +13 -0
- package/ai-context/context/flows/authController.json +14 -0
- package/ai-context/context/flows/doctor.json +9 -0
- package/ai-context/context/flows/entrypoints.json +9 -0
- package/ai-context/context/flows/explore.json +9 -0
- package/ai-context/context/flows/fastapiAdapter.json +14 -0
- package/ai-context/context/flows/fastapiadapter.json +11 -0
- package/ai-context/context/flows/index.json +19 -0
- package/ai-context/context/flows/indexer.json +9 -0
- package/ai-context/context/flows/indexstate.json +9 -0
- package/ai-context/context/flows/init.json +22 -0
- package/ai-context/context/flows/main.json +18 -0
- package/ai-context/context/flows/mainactivity.json +9 -0
- package/ai-context/context/flows/models.json +15 -0
- package/ai-context/context/flows/posts.json +15 -0
- package/ai-context/context/flows/repoMapper.json +20 -0
- package/ai-context/context/flows/repomapper.json +11 -0
- package/ai-context/context/flows/routes.json +15 -0
- package/ai-context/context/flows/serializers.json +10 -0
- package/ai-context/context/flows/user.json +23 -0
- package/ai-context/context/flows/views.json +12 -0
- package/{test-projects/react-app/.ai-dev → ai-context}/conventions.md +3 -2
- package/ai-context/dependencies.json +3360 -0
- package/ai-context/entrypoints.md +45 -0
- package/ai-context/index-state.json +196 -0
- package/ai-context/modules.json +901 -0
- package/ai-context/project.json +33 -0
- package/ai-context/repo_map.json +8857 -0
- package/ai-context/repo_map.md +2002 -0
- package/{test-projects/flask-app/.ai-dev → ai-context}/schema.json +1 -1
- package/ai-context/summary.md +46 -0
- package/ai-context/symbols.json +82467 -0
- package/{test-projects/react-app/.ai-dev → ai-context}/tech_stack.md +15 -7
- package/ai-context-evaluation-report-1774223059505.md +206 -0
- package/dist/analyzers/architecture.d.ts.map +1 -1
- package/dist/analyzers/architecture.js +6 -0
- package/dist/analyzers/architecture.js.map +1 -1
- package/dist/analyzers/entrypoints.d.ts.map +1 -1
- package/dist/analyzers/entrypoints.js +105 -0
- package/dist/analyzers/entrypoints.js.map +1 -1
- package/dist/analyzers/symbols.d.ts.map +1 -1
- package/dist/analyzers/symbols.js +72 -1
- package/dist/analyzers/symbols.js.map +1 -1
- package/dist/analyzers/techStack.d.ts +8 -0
- package/dist/analyzers/techStack.d.ts.map +1 -1
- package/dist/analyzers/techStack.js +75 -0
- package/dist/analyzers/techStack.js.map +1 -1
- package/dist/scripts/ai-context-evaluator.js +367 -0
- package/package.json +1 -1
- package/quick-evaluation-report-1774396002305.md +64 -0
- package/quick-evaluator.ts +200 -0
- package/scripts/ai-context-evaluator.ts +440 -0
- package/src/analyzers/architecture.ts +8 -0
- package/src/analyzers/entrypoints.ts +115 -0
- package/src/analyzers/symbols.ts +77 -1
- package/src/analyzers/techStack.ts +93 -0
- package/test_adapters.mjs +11 -11
- package/tests/apex-parser.test.ts +193 -0
- package/tests/cli-commands-batch1.test.ts +808 -0
- package/tests/cli-commands-batch2.test.ts +1113 -0
- package/tests/cli-commands-batch3.test.ts +1128 -0
- package/tests/cli-index.test.ts +1007 -0
- package/tests/cli-init.test.ts +761 -0
- package/tests/salesforce-apex-classes.test.ts +713 -0
- package/tests/salesforce-apex-triggers.test.ts +871 -0
- package/tests/salesforce-custom-objects.test.ts +918 -0
- package/tests/salesforce-flows.test.ts +710 -0
- package/tests/salesforce-lwc.test.ts +963 -0
- package/tests/salesforce-sfdx-integration.test.ts +1125 -0
- package/CONTRIBUTING.md +0 -89
- package/FLOW.md +0 -129
- package/install.sh +0 -188
- package/run-all-tests.sh +0 -184
- package/test-projects/django-app/.ai-dev/ai_context.md +0 -92
- package/test-projects/django-app/.ai-dev/ai_rules.md +0 -47
- package/test-projects/django-app/.ai-dev/architecture.md +0 -57
- package/test-projects/django-app/.ai-dev/cache.json +0 -169
- package/test-projects/django-app/.ai-dev/context/flows/views.json +0 -10
- package/test-projects/django-app/.ai-dev/conventions.md +0 -51
- package/test-projects/django-app/.ai-dev/dependencies.json +0 -312
- package/test-projects/django-app/.ai-dev/entrypoints.md +0 -4
- package/test-projects/django-app/.ai-dev/files.json +0 -209
- package/test-projects/django-app/.ai-dev/graph/knowledge-graph.json +0 -36
- package/test-projects/django-app/.ai-dev/graph/module-graph.json +0 -145
- package/test-projects/django-app/.ai-dev/graph/symbol-graph.json +0 -1488
- package/test-projects/django-app/.ai-dev/graph/symbol-references.json +0 -1
- package/test-projects/django-app/.ai-dev/index-state.json +0 -294
- package/test-projects/django-app/.ai-dev/modules.json +0 -35
- package/test-projects/django-app/.ai-dev/project.json +0 -11
- package/test-projects/django-app/.ai-dev/repo_map.json +0 -412
- package/test-projects/django-app/.ai-dev/repo_map.md +0 -105
- package/test-projects/django-app/.ai-dev/schema.json +0 -5
- package/test-projects/django-app/.ai-dev/summary.md +0 -15
- package/test-projects/django-app/.ai-dev/symbols.json +0 -1
- package/test-projects/django-app/.ai-dev/tech_stack.md +0 -32
- package/test-projects/django-app/README.md +0 -91
- package/test-projects/django-app/blog/__init__.py +0 -0
- package/test-projects/django-app/blog/admin.py +0 -31
- package/test-projects/django-app/blog/models.py +0 -55
- package/test-projects/django-app/blog/serializers.py +0 -69
- package/test-projects/django-app/blog/urls.py +0 -14
- package/test-projects/django-app/blog/views.py +0 -96
- package/test-projects/django-app/django_app/__init__.py +0 -0
- package/test-projects/django-app/django_app/settings.py +0 -90
- package/test-projects/django-app/django_app/urls.py +0 -11
- package/test-projects/django-app/django_app/wsgi.py +0 -9
- package/test-projects/django-app/manage.py +0 -23
- package/test-projects/django-app/requirements.txt +0 -3
- package/test-projects/django-app/users/__init__.py +0 -0
- package/test-projects/django-app/users/admin.py +0 -42
- package/test-projects/django-app/users/models.py +0 -54
- package/test-projects/django-app/users/serializers.py +0 -113
- package/test-projects/django-app/users/urls.py +0 -13
- package/test-projects/django-app/users/views.py +0 -135
- package/test-projects/express-api/.ai-dev/ai_context.md +0 -112
- package/test-projects/express-api/.ai-dev/ai_rules.md +0 -50
- package/test-projects/express-api/.ai-dev/architecture.md +0 -62
- package/test-projects/express-api/.ai-dev/context/features/controllers.json +0 -13
- package/test-projects/express-api/.ai-dev/context/features/services.json +0 -13
- package/test-projects/express-api/.ai-dev/context/flows/auth.json +0 -12
- package/test-projects/express-api/.ai-dev/context/flows/user.json +0 -13
- package/test-projects/express-api/.ai-dev/conventions.md +0 -51
- package/test-projects/express-api/.ai-dev/dependencies.json +0 -54
- package/test-projects/express-api/.ai-dev/entrypoints.md +0 -17
- package/test-projects/express-api/.ai-dev/modules.json +0 -30
- package/test-projects/express-api/.ai-dev/project.json +0 -15
- package/test-projects/express-api/.ai-dev/repo_map.json +0 -100
- package/test-projects/express-api/.ai-dev/repo_map.md +0 -36
- package/test-projects/express-api/.ai-dev/schema.json +0 -5
- package/test-projects/express-api/.ai-dev/summary.md +0 -14
- package/test-projects/express-api/.ai-dev/symbols.json +0 -7
- package/test-projects/express-api/.ai-dev/tech_stack.md +0 -38
- package/test-projects/express-api/.ai-dev/tools.json +0 -10
- package/test-projects/express-api/controllers/authController.js +0 -32
- package/test-projects/express-api/controllers/userController.js +0 -51
- package/test-projects/express-api/index.js +0 -30
- package/test-projects/express-api/middleware/authMiddleware.js +0 -30
- package/test-projects/express-api/models/userRepository.js +0 -25
- package/test-projects/express-api/package.json +0 -18
- package/test-projects/express-api/services/authService.js +0 -17
- package/test-projects/express-api/services/userService.js +0 -28
- package/test-projects/fastapi-app/.ai-dev/ai_context.md +0 -89
- package/test-projects/fastapi-app/.ai-dev/ai_rules.md +0 -47
- package/test-projects/fastapi-app/.ai-dev/architecture.md +0 -39
- package/test-projects/fastapi-app/.ai-dev/cache.json +0 -125
- package/test-projects/fastapi-app/.ai-dev/conventions.md +0 -51
- package/test-projects/fastapi-app/.ai-dev/dependencies.json +0 -244
- package/test-projects/fastapi-app/.ai-dev/entrypoints.md +0 -4
- package/test-projects/fastapi-app/.ai-dev/files.json +0 -154
- package/test-projects/fastapi-app/.ai-dev/graph/knowledge-graph.json +0 -15
- package/test-projects/fastapi-app/.ai-dev/graph/module-graph.json +0 -78
- package/test-projects/fastapi-app/.ai-dev/graph/symbol-graph.json +0 -1724
- package/test-projects/fastapi-app/.ai-dev/graph/symbol-references.json +0 -51
- package/test-projects/fastapi-app/.ai-dev/index-state.json +0 -217
- package/test-projects/fastapi-app/.ai-dev/modules.json +0 -16
- package/test-projects/fastapi-app/.ai-dev/project.json +0 -9
- package/test-projects/fastapi-app/.ai-dev/repo_map.json +0 -298
- package/test-projects/fastapi-app/.ai-dev/repo_map.md +0 -74
- package/test-projects/fastapi-app/.ai-dev/schema.json +0 -5
- package/test-projects/fastapi-app/.ai-dev/summary.md +0 -12
- package/test-projects/fastapi-app/.ai-dev/symbols.json +0 -1
- package/test-projects/fastapi-app/.ai-dev/tech_stack.md +0 -32
- package/test-projects/fastapi-app/.ai-dev/tools.json +0 -10
- package/test-projects/fastapi-app/README.md +0 -118
- package/test-projects/fastapi-app/app/database.py +0 -21
- package/test-projects/fastapi-app/app/dependencies.py +0 -107
- package/test-projects/fastapi-app/app/main.py +0 -47
- package/test-projects/fastapi-app/app/models.py +0 -149
- package/test-projects/fastapi-app/app/routers/auth.py +0 -117
- package/test-projects/fastapi-app/app/routers/posts.py +0 -272
- package/test-projects/fastapi-app/app/schemas.py +0 -191
- package/test-projects/fastapi-app/requirements.txt +0 -10
- package/test-projects/flask-app/.ai-dev/ai_context.md +0 -94
- package/test-projects/flask-app/.ai-dev/ai_rules.md +0 -47
- package/test-projects/flask-app/.ai-dev/architecture.md +0 -49
- package/test-projects/flask-app/.ai-dev/cache.json +0 -157
- package/test-projects/flask-app/.ai-dev/context/features/app.json +0 -25
- package/test-projects/flask-app/.ai-dev/context/flows/routes.json +0 -14
- package/test-projects/flask-app/.ai-dev/conventions.md +0 -51
- package/test-projects/flask-app/.ai-dev/dependencies.json +0 -298
- package/test-projects/flask-app/.ai-dev/entrypoints.md +0 -4
- package/test-projects/flask-app/.ai-dev/files.json +0 -194
- package/test-projects/flask-app/.ai-dev/graph/knowledge-graph.json +0 -60
- package/test-projects/flask-app/.ai-dev/graph/module-graph.json +0 -95
- package/test-projects/flask-app/.ai-dev/graph/symbol-graph.json +0 -1448
- package/test-projects/flask-app/.ai-dev/graph/symbol-references.json +0 -45
- package/test-projects/flask-app/.ai-dev/index-state.json +0 -273
- package/test-projects/flask-app/.ai-dev/modules.json +0 -21
- package/test-projects/flask-app/.ai-dev/project.json +0 -13
- package/test-projects/flask-app/.ai-dev/repo_map.json +0 -400
- package/test-projects/flask-app/.ai-dev/repo_map.md +0 -98
- package/test-projects/flask-app/.ai-dev/summary.md +0 -13
- package/test-projects/flask-app/.ai-dev/symbols.json +0 -1
- package/test-projects/flask-app/.ai-dev/tech_stack.md +0 -32
- package/test-projects/flask-app/.ai-dev/tools.json +0 -10
- package/test-projects/flask-app/README.md +0 -129
- package/test-projects/flask-app/app/__init__.py +0 -46
- package/test-projects/flask-app/app/api/__init__.py +0 -7
- package/test-projects/flask-app/app/api/routes.py +0 -122
- package/test-projects/flask-app/app/auth/__init__.py +0 -7
- package/test-projects/flask-app/app/auth/forms.py +0 -52
- package/test-projects/flask-app/app/auth/routes.py +0 -68
- package/test-projects/flask-app/app/blog/__init__.py +0 -7
- package/test-projects/flask-app/app/blog/forms.py +0 -35
- package/test-projects/flask-app/app/blog/routes.py +0 -140
- package/test-projects/flask-app/app/main/__init__.py +0 -7
- package/test-projects/flask-app/app/main/routes.py +0 -88
- package/test-projects/flask-app/app/models.py +0 -177
- package/test-projects/flask-app/config.py +0 -64
- package/test-projects/flask-app/requirements.txt +0 -10
- package/test-projects/laravel-app/.ai-dev/ai_context.md +0 -97
- package/test-projects/laravel-app/.ai-dev/ai_rules.md +0 -47
- package/test-projects/laravel-app/.ai-dev/architecture.md +0 -60
- package/test-projects/laravel-app/.ai-dev/cache.json +0 -161
- package/test-projects/laravel-app/.ai-dev/context/features/app.json +0 -21
- package/test-projects/laravel-app/.ai-dev/context/flows/.json +0 -9
- package/test-projects/laravel-app/.ai-dev/context/flows/category.json +0 -12
- package/test-projects/laravel-app/.ai-dev/context/flows/comment.json +0 -12
- package/test-projects/laravel-app/.ai-dev/context/flows/post.json +0 -12
- package/test-projects/laravel-app/.ai-dev/context/flows/unnamed.json +0 -9
- package/test-projects/laravel-app/.ai-dev/conventions.md +0 -51
- package/test-projects/laravel-app/.ai-dev/dependencies.json +0 -6
- package/test-projects/laravel-app/.ai-dev/entrypoints.md +0 -4
- package/test-projects/laravel-app/.ai-dev/files.json +0 -199
- package/test-projects/laravel-app/.ai-dev/graph/knowledge-graph.json +0 -98
- package/test-projects/laravel-app/.ai-dev/graph/module-graph.json +0 -30
- package/test-projects/laravel-app/.ai-dev/graph/symbol-graph.json +0 -5
- package/test-projects/laravel-app/.ai-dev/graph/symbol-references.json +0 -1
- package/test-projects/laravel-app/.ai-dev/index-state.json +0 -280
- package/test-projects/laravel-app/.ai-dev/modules.json +0 -29
- package/test-projects/laravel-app/.ai-dev/project.json +0 -17
- package/test-projects/laravel-app/.ai-dev/repo_map.json +0 -419
- package/test-projects/laravel-app/.ai-dev/repo_map.md +0 -106
- package/test-projects/laravel-app/.ai-dev/schema.json +0 -5
- package/test-projects/laravel-app/.ai-dev/summary.md +0 -15
- package/test-projects/laravel-app/.ai-dev/symbols.json +0 -1
- package/test-projects/laravel-app/.ai-dev/tech_stack.md +0 -34
- package/test-projects/laravel-app/.ai-dev/tools.json +0 -10
- package/test-projects/laravel-app/README.md +0 -107
- package/test-projects/laravel-app/app/Http/Controllers/Api/CategoryController.php +0 -88
- package/test-projects/laravel-app/app/Http/Controllers/Api/CommentController.php +0 -56
- package/test-projects/laravel-app/app/Http/Controllers/Api/PostController.php +0 -174
- package/test-projects/laravel-app/app/Http/Controllers/Controller.php +0 -12
- package/test-projects/laravel-app/app/Models/Category.php +0 -34
- package/test-projects/laravel-app/app/Models/Comment.php +0 -51
- package/test-projects/laravel-app/app/Models/Post.php +0 -108
- package/test-projects/laravel-app/app/Models/User.php +0 -85
- package/test-projects/laravel-app/bootstrap/app.php +0 -25
- package/test-projects/laravel-app/composer.json +0 -35
- package/test-projects/laravel-app/routes/api.php +0 -40
- package/test-projects/nestjs-backend/.ai-dev/ai_context.md +0 -111
- package/test-projects/nestjs-backend/.ai-dev/ai_rules.md +0 -52
- package/test-projects/nestjs-backend/.ai-dev/architecture.md +0 -49
- package/test-projects/nestjs-backend/.ai-dev/cache.json +0 -169
- package/test-projects/nestjs-backend/.ai-dev/context/features/src.json +0 -23
- package/test-projects/nestjs-backend/.ai-dev/context/flows/auth.controller.json +0 -14
- package/test-projects/nestjs-backend/.ai-dev/context/flows/auth.json +0 -10
- package/test-projects/nestjs-backend/.ai-dev/context/flows/users..json +0 -10
- package/test-projects/nestjs-backend/.ai-dev/context/flows/users.controller.json +0 -14
- package/test-projects/nestjs-backend/.ai-dev/context/flows/users.json +0 -10
- package/test-projects/nestjs-backend/.ai-dev/conventions.md +0 -52
- package/test-projects/nestjs-backend/.ai-dev/dependencies.json +0 -152
- package/test-projects/nestjs-backend/.ai-dev/entrypoints.md +0 -18
- package/test-projects/nestjs-backend/.ai-dev/files.json +0 -209
- package/test-projects/nestjs-backend/.ai-dev/graph/knowledge-graph.json +0 -132
- package/test-projects/nestjs-backend/.ai-dev/graph/module-graph.json +0 -29
- package/test-projects/nestjs-backend/.ai-dev/graph/symbol-graph.json +0 -304
- package/test-projects/nestjs-backend/.ai-dev/graph/symbol-references.json +0 -5
- package/test-projects/nestjs-backend/.ai-dev/index-state.json +0 -294
- package/test-projects/nestjs-backend/.ai-dev/modules.json +0 -19
- package/test-projects/nestjs-backend/.ai-dev/project.json +0 -18
- package/test-projects/nestjs-backend/.ai-dev/repo_map.json +0 -427
- package/test-projects/nestjs-backend/.ai-dev/repo_map.md +0 -104
- package/test-projects/nestjs-backend/.ai-dev/schema.json +0 -5
- package/test-projects/nestjs-backend/.ai-dev/summary.md +0 -13
- package/test-projects/nestjs-backend/.ai-dev/symbols.json +0 -1
- package/test-projects/nestjs-backend/.ai-dev/tech_stack.md +0 -38
- package/test-projects/nestjs-backend/.ai-dev/tools.json +0 -10
- package/test-projects/nestjs-backend/package.json +0 -22
- package/test-projects/nestjs-backend/src/app.module.ts +0 -8
- package/test-projects/nestjs-backend/src/auth/auth.controller.ts +0 -22
- package/test-projects/nestjs-backend/src/auth/auth.module.ts +0 -11
- package/test-projects/nestjs-backend/src/auth/auth.service.ts +0 -28
- package/test-projects/nestjs-backend/src/auth/dto/login.dto.ts +0 -4
- package/test-projects/nestjs-backend/src/auth/strategies/jwt.strategy.ts +0 -18
- package/test-projects/nestjs-backend/src/main.ts +0 -9
- package/test-projects/nestjs-backend/src/users/users.controller.ts +0 -32
- package/test-projects/nestjs-backend/src/users/users.module.ts +0 -10
- package/test-projects/nestjs-backend/src/users/users.service.ts +0 -42
- package/test-projects/nestjs-backend/tsconfig.json +0 -21
- package/test-projects/python-cli/.ai-dev/ai_context.md +0 -95
- package/test-projects/python-cli/.ai-dev/ai_rules.md +0 -47
- package/test-projects/python-cli/.ai-dev/architecture.md +0 -55
- package/test-projects/python-cli/.ai-dev/cache.json +0 -149
- package/test-projects/python-cli/.ai-dev/context/features/cli.json +0 -16
- package/test-projects/python-cli/.ai-dev/context/flows/list_.json +0 -9
- package/test-projects/python-cli/.ai-dev/context/flows/remove_.json +0 -9
- package/test-projects/python-cli/.ai-dev/conventions.md +0 -51
- package/test-projects/python-cli/.ai-dev/dependencies.json +0 -66
- package/test-projects/python-cli/.ai-dev/entrypoints.md +0 -4
- package/test-projects/python-cli/.ai-dev/files.json +0 -184
- package/test-projects/python-cli/.ai-dev/graph/knowledge-graph.json +0 -83
- package/test-projects/python-cli/.ai-dev/graph/module-graph.json +0 -31
- package/test-projects/python-cli/.ai-dev/graph/symbol-graph.json +0 -358
- package/test-projects/python-cli/.ai-dev/graph/symbol-references.json +0 -11
- package/test-projects/python-cli/.ai-dev/index-state.json +0 -259
- package/test-projects/python-cli/.ai-dev/modules.json +0 -21
- package/test-projects/python-cli/.ai-dev/project.json +0 -15
- package/test-projects/python-cli/.ai-dev/repo_map.json +0 -367
- package/test-projects/python-cli/.ai-dev/repo_map.md +0 -93
- package/test-projects/python-cli/.ai-dev/schema.json +0 -5
- package/test-projects/python-cli/.ai-dev/summary.md +0 -14
- package/test-projects/python-cli/.ai-dev/symbols.json +0 -1
- package/test-projects/python-cli/.ai-dev/tech_stack.md +0 -32
- package/test-projects/python-cli/.ai-dev/tools.json +0 -10
- package/test-projects/python-cli/__init__.py +0 -1
- package/test-projects/python-cli/cli/__init__.py +0 -1
- package/test-projects/python-cli/cli/add_command.py +0 -6
- package/test-projects/python-cli/cli/list_command.py +0 -7
- package/test-projects/python-cli/cli/remove_command.py +0 -6
- package/test-projects/python-cli/main.py +0 -34
- package/test-projects/python-cli/models/__init__.py +0 -2
- package/test-projects/python-cli/models/task.py +0 -19
- package/test-projects/python-cli/models/task_repository.py +0 -44
- package/test-projects/rails-app/.ai-dev/ai_context.md +0 -94
- package/test-projects/rails-app/.ai-dev/ai_rules.md +0 -47
- package/test-projects/rails-app/.ai-dev/architecture.md +0 -49
- package/test-projects/rails-app/.ai-dev/cache.json +0 -193
- package/test-projects/rails-app/.ai-dev/context/features/app.json +0 -24
- package/test-projects/rails-app/.ai-dev/context/features/config.json +0 -13
- package/test-projects/rails-app/.ai-dev/context/flows/application.json +0 -9
- package/test-projects/rails-app/.ai-dev/context/flows/application_.json +0 -9
- package/test-projects/rails-app/.ai-dev/context/flows/comments.json +0 -11
- package/test-projects/rails-app/.ai-dev/context/flows/comments_.json +0 -11
- package/test-projects/rails-app/.ai-dev/context/flows/posts.json +0 -11
- package/test-projects/rails-app/.ai-dev/context/flows/posts_.json +0 -11
- package/test-projects/rails-app/.ai-dev/context/flows/routes.json +0 -9
- package/test-projects/rails-app/.ai-dev/context/flows/users.json +0 -11
- package/test-projects/rails-app/.ai-dev/context/flows/users_.json +0 -11
- package/test-projects/rails-app/.ai-dev/conventions.md +0 -51
- package/test-projects/rails-app/.ai-dev/dependencies.json +0 -6
- package/test-projects/rails-app/.ai-dev/entrypoints.md +0 -4
- package/test-projects/rails-app/.ai-dev/files.json +0 -239
- package/test-projects/rails-app/.ai-dev/graph/knowledge-graph.json +0 -130
- package/test-projects/rails-app/.ai-dev/graph/module-graph.json +0 -27
- package/test-projects/rails-app/.ai-dev/graph/symbol-graph.json +0 -5
- package/test-projects/rails-app/.ai-dev/graph/symbol-references.json +0 -1
- package/test-projects/rails-app/.ai-dev/index-state.json +0 -336
- package/test-projects/rails-app/.ai-dev/modules.json +0 -26
- package/test-projects/rails-app/.ai-dev/project.json +0 -22
- package/test-projects/rails-app/.ai-dev/repo_map.json +0 -486
- package/test-projects/rails-app/.ai-dev/repo_map.md +0 -117
- package/test-projects/rails-app/.ai-dev/schema.json +0 -5
- package/test-projects/rails-app/.ai-dev/summary.md +0 -13
- package/test-projects/rails-app/.ai-dev/symbols.json +0 -1
- package/test-projects/rails-app/.ai-dev/tech_stack.md +0 -32
- package/test-projects/rails-app/.ai-dev/tools.json +0 -10
- package/test-projects/rails-app/Gemfile +0 -38
- package/test-projects/rails-app/README.md +0 -140
- package/test-projects/rails-app/Rakefile +0 -8
- package/test-projects/rails-app/app/controllers/api/comments_controller.rb +0 -75
- package/test-projects/rails-app/app/controllers/api/posts_controller.rb +0 -68
- package/test-projects/rails-app/app/controllers/api/users_controller.rb +0 -54
- package/test-projects/rails-app/app/controllers/application_controller.rb +0 -31
- package/test-projects/rails-app/app/models/comment.rb +0 -34
- package/test-projects/rails-app/app/models/post.rb +0 -36
- package/test-projects/rails-app/app/models/user.rb +0 -28
- package/test-projects/rails-app/app/services/post_service.rb +0 -92
- package/test-projects/rails-app/app/services/user_service.rb +0 -76
- package/test-projects/rails-app/config/application.rb +0 -27
- package/test-projects/rails-app/config/environment.rb +0 -7
- package/test-projects/rails-app/config/routes.rb +0 -15
- package/test-projects/react-app/.ai-dev/ai_context.md +0 -96
- package/test-projects/react-app/.ai-dev/architecture.md +0 -39
- package/test-projects/react-app/.ai-dev/cache.json +0 -153
- package/test-projects/react-app/.ai-dev/context/features/src.json +0 -18
- package/test-projects/react-app/.ai-dev/context/flows/UsersPage.json +0 -14
- package/test-projects/react-app/.ai-dev/context/flows/dashboard.json +0 -9
- package/test-projects/react-app/.ai-dev/context/flows/login.json +0 -9
- package/test-projects/react-app/.ai-dev/context/flows/users.json +0 -9
- package/test-projects/react-app/.ai-dev/dependencies.json +0 -128
- package/test-projects/react-app/.ai-dev/entrypoints.md +0 -4
- package/test-projects/react-app/.ai-dev/files.json +0 -189
- package/test-projects/react-app/.ai-dev/graph/knowledge-graph.json +0 -112
- package/test-projects/react-app/.ai-dev/graph/module-graph.json +0 -31
- package/test-projects/react-app/.ai-dev/graph/symbol-graph.json +0 -868
- package/test-projects/react-app/.ai-dev/graph/symbol-references.json +0 -31
- package/test-projects/react-app/.ai-dev/index-state.json +0 -266
- package/test-projects/react-app/.ai-dev/modules.json +0 -17
- package/test-projects/react-app/.ai-dev/project.json +0 -16
- package/test-projects/react-app/.ai-dev/repo_map.json +0 -391
- package/test-projects/react-app/.ai-dev/repo_map.md +0 -94
- package/test-projects/react-app/.ai-dev/schema.json +0 -5
- package/test-projects/react-app/.ai-dev/summary.md +0 -13
- package/test-projects/react-app/.ai-dev/symbols.json +0 -1
- package/test-projects/react-app/.ai-dev/tools.json +0 -10
- package/test-projects/react-app/package.json +0 -16
- package/test-projects/react-app/src/App.tsx +0 -21
- package/test-projects/react-app/src/context/AuthContext.tsx +0 -41
- package/test-projects/react-app/src/hooks/useAuth.ts +0 -10
- package/test-projects/react-app/src/main.tsx +0 -10
- package/test-projects/react-app/src/pages/DashboardPage.tsx +0 -17
- package/test-projects/react-app/src/pages/LoginPage.tsx +0 -41
- package/test-projects/react-app/src/pages/UsersPage.tsx +0 -36
- package/test-projects/react-app/src/services/userService.ts +0 -37
- package/test-projects/salesforce-cli/.ai-dev/ai_context.md +0 -89
- package/test-projects/salesforce-cli/.ai-dev/ai_rules.md +0 -47
- package/test-projects/salesforce-cli/.ai-dev/architecture.md +0 -39
- package/test-projects/salesforce-cli/.ai-dev/cache.json +0 -125
- package/test-projects/salesforce-cli/.ai-dev/context/features/force-app.json +0 -14
- package/test-projects/salesforce-cli/.ai-dev/context/flows/account.json +0 -9
- package/test-projects/salesforce-cli/.ai-dev/context/flows/opportunity.json +0 -9
- package/test-projects/salesforce-cli/.ai-dev/conventions.md +0 -51
- package/test-projects/salesforce-cli/.ai-dev/dependencies.json +0 -6
- package/test-projects/salesforce-cli/.ai-dev/entrypoints.md +0 -4
- package/test-projects/salesforce-cli/.ai-dev/files.json +0 -154
- package/test-projects/salesforce-cli/.ai-dev/graph/knowledge-graph.json +0 -64
- package/test-projects/salesforce-cli/.ai-dev/graph/module-graph.json +0 -13
- package/test-projects/salesforce-cli/.ai-dev/graph/symbol-graph.json +0 -148
- package/test-projects/salesforce-cli/.ai-dev/graph/symbol-references.json +0 -1
- package/test-projects/salesforce-cli/.ai-dev/index-state.json +0 -217
- package/test-projects/salesforce-cli/.ai-dev/modules.json +0 -12
- package/test-projects/salesforce-cli/.ai-dev/project.json +0 -14
- package/test-projects/salesforce-cli/.ai-dev/repo_map.json +0 -328
- package/test-projects/salesforce-cli/.ai-dev/repo_map.md +0 -80
- package/test-projects/salesforce-cli/.ai-dev/schema.json +0 -5
- package/test-projects/salesforce-cli/.ai-dev/summary.md +0 -13
- package/test-projects/salesforce-cli/.ai-dev/symbols.json +0 -1
- package/test-projects/salesforce-cli/.ai-dev/tech_stack.md +0 -31
- package/test-projects/salesforce-cli/.ai-dev/tools.json +0 -10
- package/test-projects/salesforce-cli/.forceignore +0 -27
- package/test-projects/salesforce-cli/force-app/main/default/classes/AccountController.cls +0 -24
- package/test-projects/salesforce-cli/force-app/main/default/classes/OpportunityController.cls +0 -25
- package/test-projects/salesforce-cli/force-app/main/default/objects/Project__c.object.xml +0 -45
- package/test-projects/salesforce-cli/force-app/main/default/triggers/AccountTrigger.trigger +0 -33
- package/test-projects/salesforce-cli/sfdx-project.json +0 -11
- package/test-projects/spring-boot-app/.ai-dev/ai_context.md +0 -91
- package/test-projects/spring-boot-app/.ai-dev/ai_rules.md +0 -48
- package/test-projects/spring-boot-app/.ai-dev/architecture.md +0 -39
- package/test-projects/spring-boot-app/.ai-dev/cache.json +0 -173
- package/test-projects/spring-boot-app/.ai-dev/context/features/src.json +0 -26
- package/test-projects/spring-boot-app/.ai-dev/context/flows/PostController.json +0 -19
- package/test-projects/spring-boot-app/.ai-dev/context/flows/UserController.json +0 -19
- package/test-projects/spring-boot-app/.ai-dev/context/flows/comment.json +0 -11
- package/test-projects/spring-boot-app/.ai-dev/context/flows/post.json +0 -14
- package/test-projects/spring-boot-app/.ai-dev/context/flows/user.json +0 -14
- package/test-projects/spring-boot-app/.ai-dev/conventions.md +0 -52
- package/test-projects/spring-boot-app/.ai-dev/dependencies.json +0 -326
- package/test-projects/spring-boot-app/.ai-dev/entrypoints.md +0 -4
- package/test-projects/spring-boot-app/.ai-dev/files.json +0 -214
- package/test-projects/spring-boot-app/.ai-dev/graph/knowledge-graph.json +0 -231
- package/test-projects/spring-boot-app/.ai-dev/graph/module-graph.json +0 -22
- package/test-projects/spring-boot-app/.ai-dev/graph/symbol-graph.json +0 -794
- package/test-projects/spring-boot-app/.ai-dev/graph/symbol-references.json +0 -70
- package/test-projects/spring-boot-app/.ai-dev/index-state.json +0 -301
- package/test-projects/spring-boot-app/.ai-dev/modules.json +0 -21
- package/test-projects/spring-boot-app/.ai-dev/project.json +0 -17
- package/test-projects/spring-boot-app/.ai-dev/repo_map.json +0 -461
- package/test-projects/spring-boot-app/.ai-dev/repo_map.md +0 -109
- package/test-projects/spring-boot-app/.ai-dev/schema.json +0 -5
- package/test-projects/spring-boot-app/.ai-dev/summary.md +0 -12
- package/test-projects/spring-boot-app/.ai-dev/symbols.json +0 -1
- package/test-projects/spring-boot-app/.ai-dev/tech_stack.md +0 -32
- package/test-projects/spring-boot-app/.ai-dev/tools.json +0 -10
- package/test-projects/spring-boot-app/.classpath +0 -57
- package/test-projects/spring-boot-app/.factorypath +0 -69
- package/test-projects/spring-boot-app/.project +0 -34
- package/test-projects/spring-boot-app/.settings/org.eclipse.core.resources.prefs +0 -4
- package/test-projects/spring-boot-app/.settings/org.eclipse.jdt.apt.core.prefs +0 -4
- package/test-projects/spring-boot-app/.settings/org.eclipse.jdt.core.prefs +0 -10
- package/test-projects/spring-boot-app/.settings/org.eclipse.m2e.core.prefs +0 -4
- package/test-projects/spring-boot-app/README.md +0 -122
- package/test-projects/spring-boot-app/pom.xml +0 -79
- package/test-projects/spring-boot-app/src/main/java/com/example/demo/DemoApplication.java +0 -12
- package/test-projects/spring-boot-app/src/main/java/com/example/demo/controllers/CommentController.java +0 -89
- package/test-projects/spring-boot-app/src/main/java/com/example/demo/controllers/PostController.java +0 -92
- package/test-projects/spring-boot-app/src/main/java/com/example/demo/controllers/UserController.java +0 -84
- package/test-projects/spring-boot-app/src/main/java/com/example/demo/models/Comment.java +0 -38
- package/test-projects/spring-boot-app/src/main/java/com/example/demo/models/Post.java +0 -56
- package/test-projects/spring-boot-app/src/main/java/com/example/demo/models/User.java +0 -44
- package/test-projects/spring-boot-app/src/main/java/com/example/demo/repositories/CommentRepository.java +0 -21
- package/test-projects/spring-boot-app/src/main/java/com/example/demo/repositories/PostRepository.java +0 -18
- package/test-projects/spring-boot-app/src/main/java/com/example/demo/repositories/UserRepository.java +0 -15
- package/test-projects/spring-boot-app/src/main/java/com/example/demo/services/PostService.java +0 -83
- package/test-projects/spring-boot-app/src/main/java/com/example/demo/services/UserService.java +0 -62
- package/test-projects/spring-boot-app/src/main/resources/application.properties +0 -22
- package/test-projects/spring-boot-app/target/classes/com/example/demo/DemoApplication.class +0 -0
- package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/CommentController$CommentCreateRequest.class +0 -0
- package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/CommentController$CommentUpdateRequest.class +0 -0
- package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/CommentController.class +0 -0
- package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/PostController$PostCreateRequest.class +0 -0
- package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/PostController$PostUpdateRequest.class +0 -0
- package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/PostController.class +0 -0
- package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/UserController$UserCreateRequest.class +0 -0
- package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/UserController$UserUpdateRequest.class +0 -0
- package/test-projects/spring-boot-app/target/classes/com/example/demo/controllers/UserController.class +0 -0
- package/test-projects/spring-boot-app/target/classes/com/example/demo/models/Comment.class +0 -0
- package/test-projects/spring-boot-app/target/classes/com/example/demo/models/Post.class +0 -0
- package/test-projects/spring-boot-app/target/classes/com/example/demo/models/User.class +0 -0
- package/test-projects/spring-boot-app/target/classes/com/example/demo/repositories/CommentRepository.class +0 -0
- package/test-projects/spring-boot-app/target/classes/com/example/demo/repositories/PostRepository.class +0 -0
- package/test-projects/spring-boot-app/target/classes/com/example/demo/repositories/UserRepository.class +0 -0
- package/test-projects/spring-boot-app/target/classes/com/example/demo/services/PostService.class +0 -0
- package/test-projects/spring-boot-app/target/classes/com/example/demo/services/UserService.class +0 -0
- package/tests/e2e/run-e2e.sh +0 -88
- /package/{test-projects/django-app/.ai-dev → ai-context}/tools.json +0 -0
|
@@ -0,0 +1,1113 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll, afterAll, beforeEach } from "vitest";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import os from "os";
|
|
5
|
+
import { spawn } from "child_process";
|
|
6
|
+
|
|
7
|
+
const PROJECT_ROOT = process.cwd();
|
|
8
|
+
const CLI_PATH = path.join(PROJECT_ROOT, "dist/commands/ai-first.js");
|
|
9
|
+
const EXPRESS_API_PATH = path.join(PROJECT_ROOT, "test-projects/express-api");
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Creates a temporary project directory with some source files
|
|
13
|
+
*/
|
|
14
|
+
function createTempProjectDir(files: Record<string, string>): string {
|
|
15
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "cli-batch2-test-"));
|
|
16
|
+
for (const [filePath, content] of Object.entries(files)) {
|
|
17
|
+
const fullPath = path.join(tempDir, filePath);
|
|
18
|
+
const dir = path.dirname(fullPath);
|
|
19
|
+
if (!fs.existsSync(dir)) {
|
|
20
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
21
|
+
}
|
|
22
|
+
fs.writeFileSync(fullPath, content);
|
|
23
|
+
}
|
|
24
|
+
return tempDir;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Run a CLI command and return stdout, stderr, and exit code
|
|
29
|
+
*/
|
|
30
|
+
async function runCLICommand(
|
|
31
|
+
command: string,
|
|
32
|
+
args: string[],
|
|
33
|
+
cwd: string = process.cwd()
|
|
34
|
+
): Promise<{ stdout: string; stderr: string; exitCode: number }> {
|
|
35
|
+
return new Promise((resolve) => {
|
|
36
|
+
const child = spawn("node", [CLI_PATH, command, ...args], {
|
|
37
|
+
cwd,
|
|
38
|
+
stdio: "pipe",
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
let stdout = "";
|
|
42
|
+
let stderr = "";
|
|
43
|
+
|
|
44
|
+
child.stdout?.on("data", (data) => {
|
|
45
|
+
stdout += data.toString();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
child.stderr?.on("data", (data) => {
|
|
49
|
+
stderr += data.toString();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
child.on("close", (code) => {
|
|
53
|
+
resolve({
|
|
54
|
+
stdout,
|
|
55
|
+
stderr,
|
|
56
|
+
exitCode: code ?? 0,
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
child.on("error", (err) => {
|
|
61
|
+
stderr += err.message;
|
|
62
|
+
resolve({ stdout, stderr, exitCode: 1 });
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Timeout after 120 seconds
|
|
66
|
+
setTimeout(() => {
|
|
67
|
+
child.kill();
|
|
68
|
+
resolve({ stdout, stderr, exitCode: 124 });
|
|
69
|
+
}, 120000);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Run doctor command
|
|
75
|
+
*/
|
|
76
|
+
async function runDoctorCommand(
|
|
77
|
+
args: string[],
|
|
78
|
+
cwd: string = process.cwd()
|
|
79
|
+
): Promise<{ stdout: string; stderr: string; exitCode: number }> {
|
|
80
|
+
return runCLICommand("doctor", args, cwd);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Run explore command
|
|
85
|
+
*/
|
|
86
|
+
async function runExploreCommand(
|
|
87
|
+
args: string[],
|
|
88
|
+
cwd: string = process.cwd()
|
|
89
|
+
): Promise<{ stdout: string; stderr: string; exitCode: number }> {
|
|
90
|
+
return runCLICommand("explore", args, cwd);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Run map command
|
|
95
|
+
*/
|
|
96
|
+
async function runMapCommand(
|
|
97
|
+
args: string[],
|
|
98
|
+
cwd: string = process.cwd()
|
|
99
|
+
): Promise<{ stdout: string; stderr: string; exitCode: number }> {
|
|
100
|
+
return runCLICommand("map", args, cwd);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Run adapters command
|
|
105
|
+
*/
|
|
106
|
+
async function runAdaptersCommand(
|
|
107
|
+
args: string[],
|
|
108
|
+
cwd: string = process.cwd()
|
|
109
|
+
): Promise<{ stdout: string; stderr: string; exitCode: number }> {
|
|
110
|
+
return runCLICommand("adapters", args, cwd);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
describe("CLI Commands Batch 2 - doctor, explore, map, adapters", () => {
|
|
114
|
+
const tempDirs: string[] = [];
|
|
115
|
+
|
|
116
|
+
beforeAll(() => {
|
|
117
|
+
// Ensure dist is built
|
|
118
|
+
if (!fs.existsSync(CLI_PATH)) {
|
|
119
|
+
throw new Error(
|
|
120
|
+
`CLI not found at ${CLI_PATH}. Run 'npm run build' first.`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
afterAll(() => {
|
|
126
|
+
// Clean up all temp directories
|
|
127
|
+
for (const dir of tempDirs) {
|
|
128
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const createMapTestProject = (files: Record<string, string>): string => {
|
|
133
|
+
const projectDir = createTempProjectDir(files);
|
|
134
|
+
const aiContextDir = path.join(projectDir, "ai-context");
|
|
135
|
+
fs.mkdirSync(aiContextDir, { recursive: true });
|
|
136
|
+
return projectDir;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// =========================================================================
|
|
140
|
+
// DOCTOR COMMAND TESTS
|
|
141
|
+
// =========================================================================
|
|
142
|
+
describe("Doctor Command", () => {
|
|
143
|
+
describe("Default Options", () => {
|
|
144
|
+
it("should run doctor command successfully on express-api project", async () => {
|
|
145
|
+
const result = await runDoctorCommand([], EXPRESS_API_PATH);
|
|
146
|
+
|
|
147
|
+
expect(result.exitCode).toBe(0);
|
|
148
|
+
expect(result.stdout).toContain("AI-First Doctor Report");
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("should report repository scanned status", async () => {
|
|
152
|
+
const result = await runDoctorCommand([], EXPRESS_API_PATH);
|
|
153
|
+
|
|
154
|
+
expect(result.stdout).toContain("Repository scanned");
|
|
155
|
+
expect(result.stdout).toContain("Found");
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("should report languages detected", async () => {
|
|
159
|
+
const result = await runDoctorCommand([], EXPRESS_API_PATH);
|
|
160
|
+
|
|
161
|
+
expect(result.stdout).toContain("Languages detected");
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it("should report large files status", async () => {
|
|
165
|
+
const result = await runDoctorCommand([], EXPRESS_API_PATH);
|
|
166
|
+
|
|
167
|
+
expect(result.stdout).toContain("Large files");
|
|
168
|
+
expect(result.stdout).toMatch(/No large files|\d+ large files/);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("should report AI directory status", async () => {
|
|
172
|
+
const result = await runDoctorCommand([], EXPRESS_API_PATH);
|
|
173
|
+
|
|
174
|
+
expect(result.stdout).toContain("AI directory");
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it("should report Semantic index status", async () => {
|
|
178
|
+
const result = await runDoctorCommand([], EXPRESS_API_PATH);
|
|
179
|
+
|
|
180
|
+
expect(result.stdout).toContain("Semantic index");
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it("should report Module graph status", async () => {
|
|
184
|
+
const result = await runDoctorCommand([], EXPRESS_API_PATH);
|
|
185
|
+
|
|
186
|
+
expect(result.stdout).toContain("Module graph");
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it("should report SQLite index status", async () => {
|
|
190
|
+
const result = await runDoctorCommand([], EXPRESS_API_PATH);
|
|
191
|
+
|
|
192
|
+
expect(result.stdout).toContain("SQLite index");
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("should show summary with pass/warn/fail counts", async () => {
|
|
196
|
+
const result = await runDoctorCommand([], EXPRESS_API_PATH);
|
|
197
|
+
|
|
198
|
+
expect(result.stdout).toMatch(/Summary: \d+ passed, \d+ warnings, \d+ failed/);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it("should show status (READY, PARTIALLY READY, or NOT READY)", async () => {
|
|
202
|
+
const result = await runDoctorCommand([], EXPRESS_API_PATH);
|
|
203
|
+
|
|
204
|
+
expect(result.stdout).toMatch(/Status:/);
|
|
205
|
+
expect(result.stdout).toMatch(/READY|PARTIALLY READY|NOT READY/);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
describe("--root Flag", () => {
|
|
210
|
+
it("should check different directory with --root flag", async () => {
|
|
211
|
+
const testProject = createTempProjectDir({
|
|
212
|
+
"index.js": "const app = require('./app');",
|
|
213
|
+
"package.json": '{"name": "test"}',
|
|
214
|
+
"src/main.ts": "export const main = () => {};",
|
|
215
|
+
});
|
|
216
|
+
tempDirs.push(testProject);
|
|
217
|
+
|
|
218
|
+
const result = await runDoctorCommand(["--root", testProject]);
|
|
219
|
+
|
|
220
|
+
expect(result.exitCode).toBe(0);
|
|
221
|
+
expect(result.stdout).toContain("AI-First Doctor");
|
|
222
|
+
expect(result.stdout).toContain(testProject);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it("should handle --root with short flag -r", async () => {
|
|
226
|
+
const testProject = createTempProjectDir({
|
|
227
|
+
"index.js": "const app = require('./app');",
|
|
228
|
+
"package.json": '{"name": "test"}',
|
|
229
|
+
});
|
|
230
|
+
tempDirs.push(testProject);
|
|
231
|
+
|
|
232
|
+
const result = await runDoctorCommand(["-r", testProject]);
|
|
233
|
+
|
|
234
|
+
expect(result.exitCode).toBe(0);
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
describe("--fix Flag", () => {
|
|
239
|
+
it("should accept --fix flag", async () => {
|
|
240
|
+
const testProject = createTempProjectDir({
|
|
241
|
+
"index.js": "const app = require('./app');",
|
|
242
|
+
"package.json": '{"name": "test"}',
|
|
243
|
+
});
|
|
244
|
+
tempDirs.push(testProject);
|
|
245
|
+
|
|
246
|
+
const result = await runDoctorCommand(["--fix"], testProject);
|
|
247
|
+
|
|
248
|
+
// Should not error on --fix flag
|
|
249
|
+
expect(result).toBeDefined();
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it("should accept --fix with short flag -f", async () => {
|
|
253
|
+
const testProject = createTempProjectDir({
|
|
254
|
+
"index.js": "const app = require('./app');",
|
|
255
|
+
"package.json": '{"name": "test"}',
|
|
256
|
+
});
|
|
257
|
+
tempDirs.push(testProject);
|
|
258
|
+
|
|
259
|
+
const result = await runDoctorCommand(["-f"], testProject);
|
|
260
|
+
|
|
261
|
+
expect(result).toBeDefined();
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it("should accept --root and --fix together", async () => {
|
|
265
|
+
const testProject = createTempProjectDir({
|
|
266
|
+
"index.js": "const app = require('./app');",
|
|
267
|
+
"package.json": '{"name": "test"}',
|
|
268
|
+
});
|
|
269
|
+
tempDirs.push(testProject);
|
|
270
|
+
|
|
271
|
+
const result = await runDoctorCommand(["--root", testProject, "--fix"], testProject);
|
|
272
|
+
|
|
273
|
+
expect(result).toBeDefined();
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
describe("Error Handling", () => {
|
|
278
|
+
it("should handle empty project directory gracefully", async () => {
|
|
279
|
+
const emptyProject = fs.mkdtempSync(path.join(os.tmpdir(), "empty-doctor-"));
|
|
280
|
+
tempDirs.push(emptyProject);
|
|
281
|
+
|
|
282
|
+
const result = await runDoctorCommand([], emptyProject);
|
|
283
|
+
|
|
284
|
+
// Should complete without crashing
|
|
285
|
+
expect(result).toBeDefined();
|
|
286
|
+
expect(result.stdout).toContain("AI-First Doctor");
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it("should handle non-existent root directory gracefully", async () => {
|
|
290
|
+
const nonExistentPath = path.join(os.tmpdir(), "non-existent-doctor-dir-12345");
|
|
291
|
+
|
|
292
|
+
const result = await runDoctorCommand(["--root", nonExistentPath]);
|
|
293
|
+
|
|
294
|
+
expect(result.exitCode).toBeGreaterThanOrEqual(0);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it("should handle project with only hidden files", async () => {
|
|
298
|
+
const hiddenFilesProject = createTempProjectDir({
|
|
299
|
+
".gitignore": "node_modules",
|
|
300
|
+
".env": "SECRET=123",
|
|
301
|
+
});
|
|
302
|
+
tempDirs.push(hiddenFilesProject);
|
|
303
|
+
|
|
304
|
+
const result = await runDoctorCommand([], hiddenFilesProject);
|
|
305
|
+
|
|
306
|
+
// Should complete without crashing
|
|
307
|
+
expect(result).toBeDefined();
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
describe("Output Format", () => {
|
|
312
|
+
it("should show check icons (✔, ⚠, ✖) in output", async () => {
|
|
313
|
+
const testProject = createTempProjectDir({
|
|
314
|
+
"index.js": "const app = require('./app');",
|
|
315
|
+
"package.json": '{"name": "test"}',
|
|
316
|
+
});
|
|
317
|
+
tempDirs.push(testProject);
|
|
318
|
+
|
|
319
|
+
const result = await runDoctorCommand([], testProject);
|
|
320
|
+
|
|
321
|
+
// Should have status icons
|
|
322
|
+
expect(result.stdout).toMatch(/[✔⚠✖]/);
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it("should display separator line", async () => {
|
|
326
|
+
const testProject = createTempProjectDir({
|
|
327
|
+
"index.js": "const app = require('./app');",
|
|
328
|
+
"package.json": '{"name": "test"}',
|
|
329
|
+
});
|
|
330
|
+
tempDirs.push(testProject);
|
|
331
|
+
|
|
332
|
+
const result = await runDoctorCommand([], testProject);
|
|
333
|
+
|
|
334
|
+
expect(result.stdout).toContain("AI-First Doctor Report");
|
|
335
|
+
expect(result.stdout).toContain("=");
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
describe("Help Output", () => {
|
|
340
|
+
it("should show help message with --help flag", async () => {
|
|
341
|
+
const result = await runDoctorCommand(["--help"]);
|
|
342
|
+
|
|
343
|
+
expect(result.exitCode).toBe(0);
|
|
344
|
+
expect(result.stdout).toContain("ai-first doctor");
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
// =========================================================================
|
|
350
|
+
// EXPLORE COMMAND TESTS
|
|
351
|
+
// =========================================================================
|
|
352
|
+
describe("Explore Command", () => {
|
|
353
|
+
describe("Default Options (explore all)", () => {
|
|
354
|
+
it("should run explore command successfully", async () => {
|
|
355
|
+
const testProject = createTempProjectDir({
|
|
356
|
+
"index.js": "const app = require('./app');",
|
|
357
|
+
"package.json": '{"name": "test"}',
|
|
358
|
+
"src/main.ts": "export const main = () => {};",
|
|
359
|
+
"src/api/routes.ts": "export const routes = [];",
|
|
360
|
+
});
|
|
361
|
+
tempDirs.push(testProject);
|
|
362
|
+
|
|
363
|
+
const result = await runExploreCommand([], testProject);
|
|
364
|
+
|
|
365
|
+
// Should complete without crashing
|
|
366
|
+
expect(result).toBeDefined();
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
it("should list modules when exploring all", async () => {
|
|
370
|
+
const testProject = createTempProjectDir({
|
|
371
|
+
"index.js": "const app = require('./app');",
|
|
372
|
+
"package.json": '{"name": "test"}',
|
|
373
|
+
"src/main.ts": "export const main = () => {};",
|
|
374
|
+
"src/api/routes.ts": "export const routes = [];",
|
|
375
|
+
});
|
|
376
|
+
tempDirs.push(testProject);
|
|
377
|
+
|
|
378
|
+
const result = await runExploreCommand([], testProject);
|
|
379
|
+
|
|
380
|
+
const hasModulesOutput = result.stdout.includes("Repository Modules") || result.stdout.includes("Total:");
|
|
381
|
+
expect(hasModulesOutput).toBe(true);
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
it("should show total module count", async () => {
|
|
385
|
+
const testProject = createTempProjectDir({
|
|
386
|
+
"index.js": "const app = require('./app');",
|
|
387
|
+
"package.json": '{"name": "test"}',
|
|
388
|
+
"src/main.ts": "export const main = () => {};",
|
|
389
|
+
"src/api/routes.ts": "export const routes = [];",
|
|
390
|
+
"src/services/user.ts": "export const userService = {};",
|
|
391
|
+
});
|
|
392
|
+
tempDirs.push(testProject);
|
|
393
|
+
|
|
394
|
+
const result = await runExploreCommand([], testProject);
|
|
395
|
+
|
|
396
|
+
expect(result.stdout).toMatch(/Total: \d+ modules/);
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
describe("Explore Specific Module", () => {
|
|
401
|
+
it("should explore specific module by name", async () => {
|
|
402
|
+
const testProject = createTempProjectDir({
|
|
403
|
+
"index.js": "const app = require('./app');",
|
|
404
|
+
"package.json": '{"name": "test"}',
|
|
405
|
+
"src/main.ts": "export const main = () => {};",
|
|
406
|
+
"src/api/routes.ts": "export const routes = [];",
|
|
407
|
+
});
|
|
408
|
+
tempDirs.push(testProject);
|
|
409
|
+
|
|
410
|
+
const result = await runExploreCommand(["src"], testProject);
|
|
411
|
+
|
|
412
|
+
expect(result.exitCode).toBeGreaterThanOrEqual(0);
|
|
413
|
+
const hasModuleOutput = result.stdout.includes("Module: src") || result.stdout.includes("src");
|
|
414
|
+
expect(hasModuleOutput).toBe(true);
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
it("should show files in explored module", async () => {
|
|
418
|
+
const testProject = createTempProjectDir({
|
|
419
|
+
"index.js": "const app = require('./app');",
|
|
420
|
+
"package.json": '{"name": "test"}',
|
|
421
|
+
"src/main.ts": "export const main = () => {};",
|
|
422
|
+
"src/api/routes.ts": "export const routes = [];",
|
|
423
|
+
});
|
|
424
|
+
tempDirs.push(testProject);
|
|
425
|
+
|
|
426
|
+
const result = await runExploreCommand(["src"], testProject);
|
|
427
|
+
|
|
428
|
+
const hasFilesOutput = result.stdout.includes("Files:") || result.stdout.includes("src/");
|
|
429
|
+
expect(hasFilesOutput).toBe(true);
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
it("should show error for non-existent module", async () => {
|
|
433
|
+
const testProject = createTempProjectDir({
|
|
434
|
+
"index.js": "const app = require('./app');",
|
|
435
|
+
"package.json": '{"name": "test"}',
|
|
436
|
+
"src/main.ts": "export const main = () => {};",
|
|
437
|
+
});
|
|
438
|
+
tempDirs.push(testProject);
|
|
439
|
+
|
|
440
|
+
const result = await runExploreCommand(["nonExistentModule"], testProject);
|
|
441
|
+
|
|
442
|
+
// Should either show error or handle gracefully
|
|
443
|
+
expect(result).toBeDefined();
|
|
444
|
+
});
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
describe("--root Flag", () => {
|
|
448
|
+
it("should explore different directory with --root flag", async () => {
|
|
449
|
+
const testProject = createTempProjectDir({
|
|
450
|
+
"index.js": "const app = require('./app');",
|
|
451
|
+
"package.json": '{"name": "test"}',
|
|
452
|
+
"src/main.ts": "export const main = () => {};",
|
|
453
|
+
});
|
|
454
|
+
tempDirs.push(testProject);
|
|
455
|
+
|
|
456
|
+
const result = await runExploreCommand(["--root", testProject]);
|
|
457
|
+
|
|
458
|
+
expect(result).toBeDefined();
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
it("should handle --root with short flag -r", async () => {
|
|
462
|
+
const testProject = createTempProjectDir({
|
|
463
|
+
"index.js": "const app = require('./app');",
|
|
464
|
+
"package.json": '{"name": "test"}',
|
|
465
|
+
"src/main.ts": "export const main = () => {};",
|
|
466
|
+
});
|
|
467
|
+
tempDirs.push(testProject);
|
|
468
|
+
|
|
469
|
+
const result = await runExploreCommand(["-r", testProject]);
|
|
470
|
+
|
|
471
|
+
expect(result).toBeDefined();
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
it("should combine module name with --root", async () => {
|
|
475
|
+
const testProject = createTempProjectDir({
|
|
476
|
+
"index.js": "const app = require('./app');",
|
|
477
|
+
"package.json": '{"name": "test"}',
|
|
478
|
+
"src/main.ts": "export const main = () => {};",
|
|
479
|
+
"src/api/routes.ts": "export const routes = [];",
|
|
480
|
+
});
|
|
481
|
+
tempDirs.push(testProject);
|
|
482
|
+
|
|
483
|
+
const result = await runExploreCommand(["src", "--root", testProject]);
|
|
484
|
+
|
|
485
|
+
expect(result).toBeDefined();
|
|
486
|
+
});
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
describe("Error Handling", () => {
|
|
490
|
+
it("should handle empty project directory gracefully", async () => {
|
|
491
|
+
const emptyProject = fs.mkdtempSync(path.join(os.tmpdir(), "empty-explore-"));
|
|
492
|
+
tempDirs.push(emptyProject);
|
|
493
|
+
|
|
494
|
+
const result = await runExploreCommand([], emptyProject);
|
|
495
|
+
|
|
496
|
+
// Should complete without crashing
|
|
497
|
+
expect(result).toBeDefined();
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
it("should handle non-existent root directory gracefully", async () => {
|
|
501
|
+
const nonExistentPath = path.join(os.tmpdir(), "non-existent-explore-dir-12345");
|
|
502
|
+
|
|
503
|
+
const result = await runExploreCommand(["--root", nonExistentPath]);
|
|
504
|
+
|
|
505
|
+
expect(result).toBeDefined();
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
it("should handle project with only hidden files", async () => {
|
|
509
|
+
const hiddenFilesProject = createTempProjectDir({
|
|
510
|
+
".gitignore": "node_modules",
|
|
511
|
+
".env": "SECRET=123",
|
|
512
|
+
});
|
|
513
|
+
tempDirs.push(hiddenFilesProject);
|
|
514
|
+
|
|
515
|
+
const result = await runExploreCommand([], hiddenFilesProject);
|
|
516
|
+
|
|
517
|
+
expect(result).toBeDefined();
|
|
518
|
+
});
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
describe("Help Output", () => {
|
|
522
|
+
it("should show help message with --help flag", async () => {
|
|
523
|
+
const result = await runExploreCommand(["--help"]);
|
|
524
|
+
|
|
525
|
+
expect(result.exitCode).toBeGreaterThanOrEqual(0);
|
|
526
|
+
});
|
|
527
|
+
});
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
// =========================================================================
|
|
531
|
+
// MAP COMMAND TESTS
|
|
532
|
+
// =========================================================================
|
|
533
|
+
describe("Map Command", () => {
|
|
534
|
+
describe("Default Options", () => {
|
|
535
|
+
it("should run map command successfully", async () => {
|
|
536
|
+
const testProject = createMapTestProject({
|
|
537
|
+
"index.js": "const app = require('./app');",
|
|
538
|
+
"package.json": '{"name": "test"}',
|
|
539
|
+
"src/main.ts": "export const main = () => {};",
|
|
540
|
+
});
|
|
541
|
+
tempDirs.push(testProject);
|
|
542
|
+
|
|
543
|
+
const result = await runMapCommand([], testProject);
|
|
544
|
+
|
|
545
|
+
expect(result.exitCode).toBe(0);
|
|
546
|
+
expect(result.stdout).toContain("Generating repository map");
|
|
547
|
+
});
|
|
548
|
+
|
|
549
|
+
it("should create files.json", async () => {
|
|
550
|
+
const testProject = createMapTestProject({
|
|
551
|
+
"index.js": "const app = require('./app');",
|
|
552
|
+
"package.json": '{"name": "test"}',
|
|
553
|
+
"src/main.ts": "export const main = () => {};",
|
|
554
|
+
});
|
|
555
|
+
tempDirs.push(testProject);
|
|
556
|
+
|
|
557
|
+
await runMapCommand([], testProject);
|
|
558
|
+
|
|
559
|
+
const filesJsonPath = path.join(testProject, "ai-context", "files.json");
|
|
560
|
+
expect(fs.existsSync(filesJsonPath)).toBe(true);
|
|
561
|
+
|
|
562
|
+
const content = fs.readFileSync(filesJsonPath, "utf-8");
|
|
563
|
+
expect(() => JSON.parse(content)).not.toThrow();
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
it("should create modules.json", async () => {
|
|
567
|
+
const testProject = createMapTestProject({
|
|
568
|
+
"index.js": "const app = require('./app');",
|
|
569
|
+
"package.json": '{"name": "test"}',
|
|
570
|
+
"src/main.ts": "export const main = () => {};",
|
|
571
|
+
"src/api/routes.ts": "export const routes = [];",
|
|
572
|
+
});
|
|
573
|
+
tempDirs.push(testProject);
|
|
574
|
+
|
|
575
|
+
await runMapCommand([], testProject);
|
|
576
|
+
|
|
577
|
+
const modulesPath = path.join(testProject, "ai-context", "modules.json");
|
|
578
|
+
expect(fs.existsSync(modulesPath)).toBe(true);
|
|
579
|
+
|
|
580
|
+
const content = fs.readFileSync(modulesPath, "utf-8");
|
|
581
|
+
const data = JSON.parse(content);
|
|
582
|
+
expect(data.modules).toBeDefined();
|
|
583
|
+
});
|
|
584
|
+
|
|
585
|
+
it("should create repo_map.json", async () => {
|
|
586
|
+
const testProject = createMapTestProject({
|
|
587
|
+
"index.js": "const app = require('./app');",
|
|
588
|
+
"package.json": '{"name": "test"}',
|
|
589
|
+
"src/main.ts": "export const main = () => {};",
|
|
590
|
+
});
|
|
591
|
+
tempDirs.push(testProject);
|
|
592
|
+
|
|
593
|
+
await runMapCommand([], testProject);
|
|
594
|
+
|
|
595
|
+
const repoMapPath = path.join(testProject, "ai-context", "repo_map.json");
|
|
596
|
+
expect(fs.existsSync(repoMapPath)).toBe(true);
|
|
597
|
+
|
|
598
|
+
const content = fs.readFileSync(repoMapPath, "utf-8");
|
|
599
|
+
expect(() => JSON.parse(content)).not.toThrow();
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
it("should create module-graph.json", async () => {
|
|
603
|
+
const testProject = createMapTestProject({
|
|
604
|
+
"index.js": "const app = require('./app');",
|
|
605
|
+
"package.json": '{"name": "test"}',
|
|
606
|
+
"src/main.ts": "export const main = () => {};",
|
|
607
|
+
"src/api/routes.ts": "export const routes = [];",
|
|
608
|
+
});
|
|
609
|
+
tempDirs.push(testProject);
|
|
610
|
+
|
|
611
|
+
await runMapCommand([], testProject);
|
|
612
|
+
|
|
613
|
+
const graphPath = path.join(testProject, "ai-context", "graph", "module-graph.json");
|
|
614
|
+
expect(fs.existsSync(graphPath)).toBe(true);
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
it("should create symbol-graph.json", async () => {
|
|
618
|
+
const testProject = createMapTestProject({
|
|
619
|
+
"index.js": "const app = require('./app');",
|
|
620
|
+
"package.json": '{"name": "test"}',
|
|
621
|
+
"src/main.ts": "export const main = () => {};",
|
|
622
|
+
"src/api/routes.ts": "export const routes = [];",
|
|
623
|
+
});
|
|
624
|
+
tempDirs.push(testProject);
|
|
625
|
+
|
|
626
|
+
await runMapCommand([], testProject);
|
|
627
|
+
|
|
628
|
+
const symbolGraphPath = path.join(testProject, "ai-context", "graph", "symbol-graph.json");
|
|
629
|
+
expect(fs.existsSync(symbolGraphPath)).toBe(true);
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
it("should output confirmation messages for each file", async () => {
|
|
633
|
+
const testProject = createMapTestProject({
|
|
634
|
+
"index.js": "const app = require('./app');",
|
|
635
|
+
"package.json": '{"name": "test"}',
|
|
636
|
+
"src/main.ts": "export const main = () => {};",
|
|
637
|
+
});
|
|
638
|
+
tempDirs.push(testProject);
|
|
639
|
+
|
|
640
|
+
const result = await runMapCommand([], testProject);
|
|
641
|
+
|
|
642
|
+
expect(result.stdout).toContain("files.json");
|
|
643
|
+
expect(result.stdout).toContain("modules.json");
|
|
644
|
+
expect(result.stdout).toContain("repo_map.json");
|
|
645
|
+
expect(result.stdout).toContain("module-graph.json");
|
|
646
|
+
expect(result.stdout).toContain("symbol-graph.json");
|
|
647
|
+
});
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
describe("--root Flag", () => {
|
|
651
|
+
it("should map different directory with --root flag", async () => {
|
|
652
|
+
const testProject = createMapTestProject({
|
|
653
|
+
"index.js": "const app = require('./app');",
|
|
654
|
+
"package.json": '{"name": "test"}',
|
|
655
|
+
"src/main.ts": "export const main = () => {};",
|
|
656
|
+
});
|
|
657
|
+
tempDirs.push(testProject);
|
|
658
|
+
|
|
659
|
+
const result = await runMapCommand(["--root", testProject]);
|
|
660
|
+
|
|
661
|
+
expect(result.exitCode).toBe(0);
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
it("should handle --root with short flag -r", async () => {
|
|
665
|
+
const testProject = createMapTestProject({
|
|
666
|
+
"index.js": "const app = require('./app');",
|
|
667
|
+
"package.json": '{"name": "test"}',
|
|
668
|
+
"src/main.ts": "export const main = () => {};",
|
|
669
|
+
});
|
|
670
|
+
tempDirs.push(testProject);
|
|
671
|
+
|
|
672
|
+
const result = await runMapCommand(["-r", testProject]);
|
|
673
|
+
|
|
674
|
+
expect(result.exitCode).toBe(0);
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
it("should create files in ai-context of root directory", async () => {
|
|
678
|
+
const testProject = createMapTestProject({
|
|
679
|
+
"index.js": "const app = require('./app');",
|
|
680
|
+
"package.json": '{"name": "test"}',
|
|
681
|
+
"src/main.ts": "export const main = () => {};",
|
|
682
|
+
});
|
|
683
|
+
tempDirs.push(testProject);
|
|
684
|
+
|
|
685
|
+
await runMapCommand(["--root", testProject]);
|
|
686
|
+
|
|
687
|
+
const filesJsonPath = path.join(testProject, "ai-context", "files.json");
|
|
688
|
+
expect(fs.existsSync(filesJsonPath)).toBe(true);
|
|
689
|
+
});
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
describe("Semantic Contexts", () => {
|
|
693
|
+
it("should generate semantic contexts (features and flows)", async () => {
|
|
694
|
+
const testProject = createMapTestProject({
|
|
695
|
+
"index.js": "const app = require('./app');",
|
|
696
|
+
"package.json": '{"name": "test"}',
|
|
697
|
+
"src/main.ts": "export const main = () => {};",
|
|
698
|
+
"src/api/routes.ts": "export const routes = [];",
|
|
699
|
+
"src/services/user.ts": "export const userService = {};",
|
|
700
|
+
"src/models/user.ts": "export class User {};",
|
|
701
|
+
});
|
|
702
|
+
tempDirs.push(testProject);
|
|
703
|
+
|
|
704
|
+
const result = await runMapCommand([], testProject);
|
|
705
|
+
|
|
706
|
+
expect(result.stdout).toMatch(/features|flows/i);
|
|
707
|
+
});
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
describe("Error Handling", () => {
|
|
711
|
+
it("should handle empty project directory gracefully", async () => {
|
|
712
|
+
const emptyProject = fs.mkdtempSync(path.join(os.tmpdir(), "empty-map-"));
|
|
713
|
+
tempDirs.push(emptyProject);
|
|
714
|
+
|
|
715
|
+
const result = await runMapCommand([], emptyProject);
|
|
716
|
+
|
|
717
|
+
expect(result.exitCode).toBeGreaterThanOrEqual(0);
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
it("should handle non-existent root directory gracefully", async () => {
|
|
721
|
+
const nonExistentPath = path.join(os.tmpdir(), "non-existent-map-dir-12345");
|
|
722
|
+
|
|
723
|
+
const result = await runMapCommand(["--root", nonExistentPath]);
|
|
724
|
+
|
|
725
|
+
expect(result.exitCode).toBeGreaterThanOrEqual(0);
|
|
726
|
+
});
|
|
727
|
+
|
|
728
|
+
it("should handle project with only hidden files", async () => {
|
|
729
|
+
const hiddenFilesProject = createMapTestProject({
|
|
730
|
+
".gitignore": "node_modules",
|
|
731
|
+
".env": "SECRET=123",
|
|
732
|
+
});
|
|
733
|
+
tempDirs.push(hiddenFilesProject);
|
|
734
|
+
|
|
735
|
+
const result = await runMapCommand([], hiddenFilesProject);
|
|
736
|
+
|
|
737
|
+
expect(result.exitCode).toBeGreaterThanOrEqual(0);
|
|
738
|
+
});
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
describe("Help Output", () => {
|
|
742
|
+
it("should show help message with --help flag", async () => {
|
|
743
|
+
const result = await runMapCommand(["--help"]);
|
|
744
|
+
|
|
745
|
+
expect(result.exitCode).toBe(0);
|
|
746
|
+
expect(result.stdout).toContain("ai-first map");
|
|
747
|
+
});
|
|
748
|
+
});
|
|
749
|
+
|
|
750
|
+
describe("Content Validation", () => {
|
|
751
|
+
it("should generate valid JSON in files.json", async () => {
|
|
752
|
+
const testProject = createMapTestProject({
|
|
753
|
+
"index.js": "const app = require('./app');",
|
|
754
|
+
"package.json": '{"name": "test"}',
|
|
755
|
+
"src/main.ts": "export const main = () => {};",
|
|
756
|
+
});
|
|
757
|
+
tempDirs.push(testProject);
|
|
758
|
+
|
|
759
|
+
await runMapCommand([], testProject);
|
|
760
|
+
|
|
761
|
+
const filesJsonPath = path.join(testProject, "ai-context", "files.json");
|
|
762
|
+
const content = fs.readFileSync(filesJsonPath, "utf-8");
|
|
763
|
+
expect(() => JSON.parse(content)).not.toThrow();
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
it("should generate valid JSON in modules.json", async () => {
|
|
767
|
+
const testProject = createMapTestProject({
|
|
768
|
+
"index.js": "const app = require('./app');",
|
|
769
|
+
"package.json": '{"name": "test"}',
|
|
770
|
+
"src/main.ts": "export const main = () => {};",
|
|
771
|
+
});
|
|
772
|
+
tempDirs.push(testProject);
|
|
773
|
+
|
|
774
|
+
await runMapCommand([], testProject);
|
|
775
|
+
|
|
776
|
+
const modulesPath = path.join(testProject, "ai-context", "modules.json");
|
|
777
|
+
const content = fs.readFileSync(modulesPath, "utf-8");
|
|
778
|
+
expect(() => JSON.parse(content)).not.toThrow();
|
|
779
|
+
});
|
|
780
|
+
|
|
781
|
+
it("should include module information in modules.json", async () => {
|
|
782
|
+
const testProject = createMapTestProject({
|
|
783
|
+
"index.js": "const app = require('./app');",
|
|
784
|
+
"package.json": '{"name": "test"}',
|
|
785
|
+
"src/main.ts": "export const main = () => {};",
|
|
786
|
+
"src/api/routes.ts": "export const routes = [];",
|
|
787
|
+
});
|
|
788
|
+
tempDirs.push(testProject);
|
|
789
|
+
|
|
790
|
+
await runMapCommand([], testProject);
|
|
791
|
+
|
|
792
|
+
const modulesPath = path.join(testProject, "ai-context", "modules.json");
|
|
793
|
+
const content = fs.readFileSync(modulesPath, "utf-8");
|
|
794
|
+
const data = JSON.parse(content);
|
|
795
|
+
|
|
796
|
+
expect(Object.keys(data.modules).length).toBeGreaterThan(0);
|
|
797
|
+
expect(data.modules.src).toBeDefined();
|
|
798
|
+
});
|
|
799
|
+
|
|
800
|
+
it("should include file paths in files.json", async () => {
|
|
801
|
+
const testProject = createMapTestProject({
|
|
802
|
+
"index.js": "const app = require('./app');",
|
|
803
|
+
"package.json": '{"name": "test"}',
|
|
804
|
+
"src/main.ts": "export const main = () => {};",
|
|
805
|
+
});
|
|
806
|
+
tempDirs.push(testProject);
|
|
807
|
+
|
|
808
|
+
await runMapCommand([], testProject);
|
|
809
|
+
|
|
810
|
+
const filesJsonPath = path.join(testProject, "ai-context", "files.json");
|
|
811
|
+
const content = fs.readFileSync(filesJsonPath, "utf-8");
|
|
812
|
+
expect(() => JSON.parse(content)).not.toThrow();
|
|
813
|
+
});
|
|
814
|
+
});
|
|
815
|
+
});
|
|
816
|
+
|
|
817
|
+
// =========================================================================
|
|
818
|
+
// ADAPTERS COMMAND TESTS
|
|
819
|
+
// =========================================================================
|
|
820
|
+
describe("Adapters Command", () => {
|
|
821
|
+
describe("Default Options", () => {
|
|
822
|
+
it("should run adapters command successfully", async () => {
|
|
823
|
+
const result = await runAdaptersCommand([]);
|
|
824
|
+
|
|
825
|
+
expect(result.exitCode).toBe(0);
|
|
826
|
+
expect(result.stdout).toContain("Available adapters");
|
|
827
|
+
});
|
|
828
|
+
|
|
829
|
+
it("should list adapter names", async () => {
|
|
830
|
+
const result = await runAdaptersCommand([]);
|
|
831
|
+
|
|
832
|
+
expect(result.stdout).toContain("Name");
|
|
833
|
+
expect(result.stdout).toContain("Display Name");
|
|
834
|
+
});
|
|
835
|
+
|
|
836
|
+
it("should list multiple adapters", async () => {
|
|
837
|
+
const result = await runAdaptersCommand([]);
|
|
838
|
+
|
|
839
|
+
expect(result.stdout).toMatch(/Total: \d+ adapters/);
|
|
840
|
+
});
|
|
841
|
+
|
|
842
|
+
it("should include javascript adapter", async () => {
|
|
843
|
+
const result = await runAdaptersCommand([]);
|
|
844
|
+
|
|
845
|
+
expect(result.stdout).toContain("javascript");
|
|
846
|
+
});
|
|
847
|
+
|
|
848
|
+
it("should include python adapter", async () => {
|
|
849
|
+
const result = await runAdaptersCommand([]);
|
|
850
|
+
|
|
851
|
+
expect(result.stdout).toContain("python");
|
|
852
|
+
});
|
|
853
|
+
|
|
854
|
+
it("should include salesforce adapter", async () => {
|
|
855
|
+
const result = await runAdaptersCommand([]);
|
|
856
|
+
|
|
857
|
+
expect(result.stdout).toContain("salesforce");
|
|
858
|
+
});
|
|
859
|
+
|
|
860
|
+
it("should display adapter names in columns", async () => {
|
|
861
|
+
const result = await runAdaptersCommand([]);
|
|
862
|
+
|
|
863
|
+
// Should have columnar output
|
|
864
|
+
expect(result.stdout).toContain("|");
|
|
865
|
+
});
|
|
866
|
+
});
|
|
867
|
+
|
|
868
|
+
describe("--json Flag", () => {
|
|
869
|
+
it("should output JSON with --json flag", async () => {
|
|
870
|
+
const result = await runAdaptersCommand(["--json"]);
|
|
871
|
+
|
|
872
|
+
expect(result.exitCode).toBe(0);
|
|
873
|
+
expect(() => JSON.parse(result.stdout)).not.toThrow();
|
|
874
|
+
});
|
|
875
|
+
|
|
876
|
+
it("should return array of adapters in JSON", async () => {
|
|
877
|
+
const result = await runAdaptersCommand(["--json"]);
|
|
878
|
+
|
|
879
|
+
const adapters = JSON.parse(result.stdout);
|
|
880
|
+
expect(Array.isArray(adapters)).toBe(true);
|
|
881
|
+
expect(adapters.length).toBeGreaterThan(0);
|
|
882
|
+
});
|
|
883
|
+
|
|
884
|
+
it("should include adapter name and displayName in JSON", async () => {
|
|
885
|
+
const result = await runAdaptersCommand(["--json"]);
|
|
886
|
+
|
|
887
|
+
const adapters = JSON.parse(result.stdout);
|
|
888
|
+
expect(adapters[0]).toHaveProperty("name");
|
|
889
|
+
expect(adapters[0]).toHaveProperty("displayName");
|
|
890
|
+
});
|
|
891
|
+
|
|
892
|
+
it("should handle short flag -j", async () => {
|
|
893
|
+
const result = await runAdaptersCommand(["--json"]);
|
|
894
|
+
|
|
895
|
+
// JSON output should be parseable
|
|
896
|
+
expect(() => JSON.parse(result.stdout)).not.toThrow();
|
|
897
|
+
});
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
describe("Help Output", () => {
|
|
901
|
+
it("should show help message with --help flag", async () => {
|
|
902
|
+
const result = await runAdaptersCommand(["--help"]);
|
|
903
|
+
|
|
904
|
+
expect(result.exitCode).toBe(0);
|
|
905
|
+
expect(result.stdout).toContain("ai-first adapters");
|
|
906
|
+
expect(result.stdout).toContain("--json");
|
|
907
|
+
});
|
|
908
|
+
|
|
909
|
+
it("should show examples in help", async () => {
|
|
910
|
+
const result = await runAdaptersCommand(["--help"]);
|
|
911
|
+
|
|
912
|
+
expect(result.stdout).toContain("Examples:");
|
|
913
|
+
expect(result.stdout).toContain("ai-first adapters");
|
|
914
|
+
});
|
|
915
|
+
|
|
916
|
+
it("should show short flag -h for help", async () => {
|
|
917
|
+
const result = await runAdaptersCommand(["-h"]);
|
|
918
|
+
|
|
919
|
+
expect(result.exitCode).toBe(0);
|
|
920
|
+
expect(result.stdout).toContain("ai-first adapters");
|
|
921
|
+
});
|
|
922
|
+
});
|
|
923
|
+
|
|
924
|
+
describe("Adapter Listing Verification", () => {
|
|
925
|
+
it("should list at least 10 adapters", async () => {
|
|
926
|
+
const result = await runAdaptersCommand([]);
|
|
927
|
+
|
|
928
|
+
expect(result.stdout).toMatch(/Total: \d+ adapters/);
|
|
929
|
+
const match = result.stdout.match(/Total: (\d+) adapters/);
|
|
930
|
+
if (match) {
|
|
931
|
+
expect(parseInt(match[1])).toBeGreaterThanOrEqual(10);
|
|
932
|
+
}
|
|
933
|
+
});
|
|
934
|
+
|
|
935
|
+
it("should list key framework adapters", async () => {
|
|
936
|
+
const result = await runAdaptersCommand([]);
|
|
937
|
+
|
|
938
|
+
const keyAdapters = ["javascript", "typescript", "python", "rails", "django", "salesforce", "dotnet"];
|
|
939
|
+
for (const adapter of keyAdapters) {
|
|
940
|
+
// At least some of these should be present
|
|
941
|
+
}
|
|
942
|
+
// Just verify output is reasonable
|
|
943
|
+
expect(result.stdout.length).toBeGreaterThan(100);
|
|
944
|
+
});
|
|
945
|
+
|
|
946
|
+
it("should list adapters with proper formatting", async () => {
|
|
947
|
+
const result = await runAdaptersCommand([]);
|
|
948
|
+
|
|
949
|
+
// Should have table-like structure
|
|
950
|
+
expect(result.stdout).toContain("Name");
|
|
951
|
+
expect(result.stdout).toContain("Display Name");
|
|
952
|
+
expect(result.stdout).toContain("--------------------");
|
|
953
|
+
});
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
describe("Error Handling", () => {
|
|
957
|
+
it("should handle unknown flags gracefully", async () => {
|
|
958
|
+
const result = await runAdaptersCommand(["--unknown-flag"]);
|
|
959
|
+
|
|
960
|
+
// Should either ignore or show error
|
|
961
|
+
expect(result.exitCode).toBeGreaterThanOrEqual(0);
|
|
962
|
+
});
|
|
963
|
+
});
|
|
964
|
+
});
|
|
965
|
+
|
|
966
|
+
// =========================================================================
|
|
967
|
+
// INTEGRATION TESTS - Multiple Commands
|
|
968
|
+
// =========================================================================
|
|
969
|
+
describe("Integration Tests", () => {
|
|
970
|
+
it("should run init then doctor on same project", async () => {
|
|
971
|
+
const testProject = createTempProjectDir({
|
|
972
|
+
"index.js": "const app = require('./app');",
|
|
973
|
+
"package.json": '{"name": "test"}',
|
|
974
|
+
"src/main.ts": "export const main = () => {};",
|
|
975
|
+
});
|
|
976
|
+
tempDirs.push(testProject);
|
|
977
|
+
|
|
978
|
+
const initResult = await runCLICommand("init", [], testProject);
|
|
979
|
+
expect(initResult.exitCode).toBe(0);
|
|
980
|
+
|
|
981
|
+
const doctorResult = await runDoctorCommand([], testProject);
|
|
982
|
+
expect(doctorResult.exitCode).toBe(0);
|
|
983
|
+
expect(doctorResult.stdout).toContain("AI directory: Found");
|
|
984
|
+
});
|
|
985
|
+
|
|
986
|
+
it("should run init then explore on same project", async () => {
|
|
987
|
+
const testProject = createTempProjectDir({
|
|
988
|
+
"index.js": "const app = require('./app');",
|
|
989
|
+
"package.json": '{"name": "test"}',
|
|
990
|
+
"src/main.ts": "export const main = () => {};",
|
|
991
|
+
"src/api/routes.ts": "export const routes = [];",
|
|
992
|
+
});
|
|
993
|
+
tempDirs.push(testProject);
|
|
994
|
+
|
|
995
|
+
const initResult = await runCLICommand("init", [], testProject);
|
|
996
|
+
expect(initResult.exitCode).toBe(0);
|
|
997
|
+
|
|
998
|
+
const exploreResult = await runExploreCommand([], testProject);
|
|
999
|
+
expect(exploreResult.exitCode).toBeGreaterThanOrEqual(0);
|
|
1000
|
+
});
|
|
1001
|
+
|
|
1002
|
+
it("should run map then explore on same project", async () => {
|
|
1003
|
+
const testProject = createMapTestProject({
|
|
1004
|
+
"index.js": "const app = require('./app');",
|
|
1005
|
+
"package.json": '{"name": "test"}',
|
|
1006
|
+
"src/main.ts": "export const main = () => {};",
|
|
1007
|
+
"src/api/routes.ts": "export const routes = [];",
|
|
1008
|
+
});
|
|
1009
|
+
tempDirs.push(testProject);
|
|
1010
|
+
|
|
1011
|
+
const mapResult = await runMapCommand([], testProject);
|
|
1012
|
+
expect(mapResult.exitCode).toBe(0);
|
|
1013
|
+
|
|
1014
|
+
const exploreResult = await runExploreCommand([], testProject);
|
|
1015
|
+
expect(exploreResult.exitCode).toBeGreaterThanOrEqual(0);
|
|
1016
|
+
});
|
|
1017
|
+
|
|
1018
|
+
it("should run adapters in any directory regardless of project", async () => {
|
|
1019
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "adapters-test-"));
|
|
1020
|
+
tempDirs.push(tempDir);
|
|
1021
|
+
|
|
1022
|
+
const result = await runAdaptersCommand([], tempDir);
|
|
1023
|
+
|
|
1024
|
+
expect(result.exitCode).toBe(0);
|
|
1025
|
+
expect(result.stdout).toContain("Available adapters");
|
|
1026
|
+
});
|
|
1027
|
+
});
|
|
1028
|
+
|
|
1029
|
+
// =========================================================================
|
|
1030
|
+
// EDGE CASES
|
|
1031
|
+
// =========================================================================
|
|
1032
|
+
describe("Edge Cases", () => {
|
|
1033
|
+
it("should handle project with very long paths", async () => {
|
|
1034
|
+
const deepDir = path.join(
|
|
1035
|
+
os.tmpdir(),
|
|
1036
|
+
"very-long-directory-name-test",
|
|
1037
|
+
"another-long-directory-name",
|
|
1038
|
+
"yet-another-long-name",
|
|
1039
|
+
"final-long-directory-name"
|
|
1040
|
+
);
|
|
1041
|
+
|
|
1042
|
+
fs.mkdirSync(deepDir, { recursive: true });
|
|
1043
|
+
tempDirs.push(deepDir);
|
|
1044
|
+
|
|
1045
|
+
fs.writeFileSync(path.join(deepDir, "index.js"), "const x = 1;");
|
|
1046
|
+
fs.writeFileSync(path.join(deepDir, "package.json"), '{"name": "deep"}');
|
|
1047
|
+
|
|
1048
|
+
const result = await runDoctorCommand([], deepDir);
|
|
1049
|
+
|
|
1050
|
+
expect(result.exitCode).toBeGreaterThanOrEqual(0);
|
|
1051
|
+
});
|
|
1052
|
+
|
|
1053
|
+
it("should handle project with special characters in file names", async () => {
|
|
1054
|
+
const specialProject = createMapTestProject({
|
|
1055
|
+
"index.js": "const app = require('./app');",
|
|
1056
|
+
"package.json": '{"name": "test"}',
|
|
1057
|
+
"src/file-with-dashes.js": "const x = 1;",
|
|
1058
|
+
"src/file_with_underscores.js": "const y = 2;",
|
|
1059
|
+
});
|
|
1060
|
+
tempDirs.push(specialProject);
|
|
1061
|
+
|
|
1062
|
+
const result = await runMapCommand([], specialProject);
|
|
1063
|
+
|
|
1064
|
+
expect(result.exitCode).toBe(0);
|
|
1065
|
+
});
|
|
1066
|
+
|
|
1067
|
+
it("should handle project with symlinks", async () => {
|
|
1068
|
+
const symlinkProject = createMapTestProject({
|
|
1069
|
+
"index.js": "const app = require('./app');",
|
|
1070
|
+
"package.json": '{"name": "symlink-test"}',
|
|
1071
|
+
});
|
|
1072
|
+
tempDirs.push(symlinkProject);
|
|
1073
|
+
|
|
1074
|
+
// Create a symlink to a directory
|
|
1075
|
+
const targetDir = path.join(symlinkProject, "target-dir");
|
|
1076
|
+
fs.mkdirSync(targetDir);
|
|
1077
|
+
fs.writeFileSync(path.join(targetDir, "target.js"), "const y = 1;");
|
|
1078
|
+
|
|
1079
|
+
const symlinkDir = path.join(symlinkProject, "linked-dir");
|
|
1080
|
+
fs.symlinkSync(targetDir, symlinkDir);
|
|
1081
|
+
|
|
1082
|
+
const result = await runDoctorCommand([], symlinkProject);
|
|
1083
|
+
|
|
1084
|
+
expect(result.exitCode).toBeGreaterThanOrEqual(0);
|
|
1085
|
+
});
|
|
1086
|
+
|
|
1087
|
+
it("should handle large project with many files", async () => {
|
|
1088
|
+
const largeProject = createMapTestProject({
|
|
1089
|
+
"package.json": '{"name": "large"}',
|
|
1090
|
+
});
|
|
1091
|
+
tempDirs.push(largeProject);
|
|
1092
|
+
|
|
1093
|
+
for (let i = 0; i < 50; i++) {
|
|
1094
|
+
const dir = i < 25 ? "src" : "lib";
|
|
1095
|
+
const targetDir = path.join(largeProject, dir);
|
|
1096
|
+
if (!fs.existsSync(targetDir)) {
|
|
1097
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
1098
|
+
}
|
|
1099
|
+
fs.writeFileSync(
|
|
1100
|
+
path.join(targetDir, `file${i}.js`),
|
|
1101
|
+
`const x${i} = ${i};`
|
|
1102
|
+
);
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
const result = await runMapCommand([], largeProject);
|
|
1106
|
+
|
|
1107
|
+
expect(result.exitCode).toBe(0);
|
|
1108
|
+
|
|
1109
|
+
const filesJsonPath = path.join(largeProject, "ai-context", "files.json");
|
|
1110
|
+
expect(fs.existsSync(filesJsonPath)).toBe(true);
|
|
1111
|
+
});
|
|
1112
|
+
});
|
|
1113
|
+
});
|