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,1128 @@
|
|
|
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, execSync } 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-batch3-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
|
+
* Creates a git repository with some commits
|
|
29
|
+
*/
|
|
30
|
+
function createGitRepo(files: Record<string, string>): string {
|
|
31
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "cli-git-test-"));
|
|
32
|
+
|
|
33
|
+
// Initialize git repo
|
|
34
|
+
execSync("git init", { cwd: tempDir, stdio: "ignore" });
|
|
35
|
+
execSync("git config user.email 'test@test.com'", { cwd: tempDir, stdio: "ignore" });
|
|
36
|
+
execSync("git config user.name 'Test User'", { cwd: tempDir, stdio: "ignore" });
|
|
37
|
+
|
|
38
|
+
// Create files
|
|
39
|
+
for (const [filePath, content] of Object.entries(files)) {
|
|
40
|
+
const fullPath = path.join(tempDir, filePath);
|
|
41
|
+
const dir = path.dirname(fullPath);
|
|
42
|
+
if (!fs.existsSync(dir)) {
|
|
43
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
44
|
+
}
|
|
45
|
+
fs.writeFileSync(fullPath, content);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Initial commit
|
|
49
|
+
execSync("git add .", { cwd: tempDir, stdio: "ignore" });
|
|
50
|
+
execSync("git commit -m 'Initial commit'", { cwd: tempDir, stdio: "ignore" });
|
|
51
|
+
|
|
52
|
+
return tempDir;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Run a CLI command and return result
|
|
57
|
+
*/
|
|
58
|
+
async function runCLICommand(
|
|
59
|
+
command: string,
|
|
60
|
+
args: string[],
|
|
61
|
+
cwd: string = process.cwd()
|
|
62
|
+
): Promise<{ stdout: string; stderr: string; exitCode: number }> {
|
|
63
|
+
return new Promise((resolve) => {
|
|
64
|
+
const child = spawn("node", [CLI_PATH, command, ...args], {
|
|
65
|
+
cwd,
|
|
66
|
+
stdio: "pipe",
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
let stdout = "";
|
|
70
|
+
let stderr = "";
|
|
71
|
+
|
|
72
|
+
child.stdout?.on("data", (data) => {
|
|
73
|
+
stdout += data.toString();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
child.stderr?.on("data", (data) => {
|
|
77
|
+
stderr += data.toString();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
child.on("close", (code) => {
|
|
81
|
+
resolve({
|
|
82
|
+
stdout,
|
|
83
|
+
stderr,
|
|
84
|
+
exitCode: code ?? 0,
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
child.on("error", (err) => {
|
|
89
|
+
stderr += err.message;
|
|
90
|
+
resolve({ stdout, stderr, exitCode: 1 });
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// Timeout after 60 seconds
|
|
94
|
+
setTimeout(() => {
|
|
95
|
+
child.kill();
|
|
96
|
+
resolve({ stdout, stderr, exitCode: 124 });
|
|
97
|
+
}, 60000);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Run init command first (needed for some tests)
|
|
103
|
+
*/
|
|
104
|
+
async function runInitCommand(
|
|
105
|
+
args: string[],
|
|
106
|
+
cwd: string = process.cwd()
|
|
107
|
+
): Promise<{ stdout: string; stderr: string; exitCode: number }> {
|
|
108
|
+
return new Promise((resolve) => {
|
|
109
|
+
const child = spawn("node", [CLI_PATH, "init", ...args], {
|
|
110
|
+
cwd,
|
|
111
|
+
stdio: "pipe",
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
let stdout = "";
|
|
115
|
+
let stderr = "";
|
|
116
|
+
|
|
117
|
+
child.stdout?.on("data", (data) => {
|
|
118
|
+
stdout += data.toString();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
child.stderr?.on("data", (data) => {
|
|
122
|
+
stderr += data.toString();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
child.on("close", (code) => {
|
|
126
|
+
resolve({
|
|
127
|
+
stdout,
|
|
128
|
+
stderr,
|
|
129
|
+
exitCode: code ?? 0,
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
child.on("error", (err) => {
|
|
134
|
+
stderr += err.message;
|
|
135
|
+
resolve({ stdout, stderr, exitCode: 1 });
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Timeout after 60 seconds
|
|
139
|
+
setTimeout(() => {
|
|
140
|
+
child.kill();
|
|
141
|
+
resolve({ stdout, stderr, exitCode: 124 });
|
|
142
|
+
}, 60000);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
describe("CLI Commands Batch 3 - git, graph, update, help", () => {
|
|
147
|
+
const tempDirs: string[] = [];
|
|
148
|
+
|
|
149
|
+
beforeAll(() => {
|
|
150
|
+
// Ensure dist is built
|
|
151
|
+
if (!fs.existsSync(CLI_PATH)) {
|
|
152
|
+
throw new Error(
|
|
153
|
+
`CLI not found at ${CLI_PATH}. Run 'npm run build' first.`
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
afterAll(() => {
|
|
159
|
+
// Clean up all temp directories
|
|
160
|
+
for (const dir of tempDirs) {
|
|
161
|
+
try {
|
|
162
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
163
|
+
} catch {
|
|
164
|
+
// Ignore cleanup errors
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// =========================================================================
|
|
170
|
+
// GIT COMMAND TESTS
|
|
171
|
+
// =========================================================================
|
|
172
|
+
|
|
173
|
+
describe("Git Command", () => {
|
|
174
|
+
describe("Default Options", () => {
|
|
175
|
+
it("should analyze git activity on a git repository", async () => {
|
|
176
|
+
const gitRepo = createGitRepo({
|
|
177
|
+
"package.json": '{"name": "test-repo"}',
|
|
178
|
+
"src/index.js": "const x = 1;",
|
|
179
|
+
"src/app.js": "const app = {};",
|
|
180
|
+
});
|
|
181
|
+
tempDirs.push(gitRepo);
|
|
182
|
+
|
|
183
|
+
const result = await runCLICommand("git", [], gitRepo);
|
|
184
|
+
|
|
185
|
+
expect(result.exitCode).toBe(0);
|
|
186
|
+
expect(result.stdout).toContain("Analyzing git activity");
|
|
187
|
+
expect(result.stdout).toContain("Recent files:");
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it("should generate git context files", async () => {
|
|
191
|
+
const gitRepo = createGitRepo({
|
|
192
|
+
"package.json": '{"name": "test-repo"}',
|
|
193
|
+
"README.md": "# Test",
|
|
194
|
+
});
|
|
195
|
+
tempDirs.push(gitRepo);
|
|
196
|
+
|
|
197
|
+
await runCLICommand("git", [], gitRepo);
|
|
198
|
+
|
|
199
|
+
// Check that git context files were created
|
|
200
|
+
const aiGitDir = path.join(gitRepo, "ai-context", "git");
|
|
201
|
+
expect(fs.existsSync(aiGitDir)).toBe(true);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it("should handle repository with no commits", async () => {
|
|
205
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "no-commits-"));
|
|
206
|
+
tempDirs.push(tempDir);
|
|
207
|
+
|
|
208
|
+
// Initialize git but don't make any commits
|
|
209
|
+
execSync("git init", { cwd: tempDir, stdio: "ignore" });
|
|
210
|
+
fs.writeFileSync(path.join(tempDir, "README.md"), "# Test");
|
|
211
|
+
|
|
212
|
+
const result = await runCLICommand("git", [], tempDir);
|
|
213
|
+
|
|
214
|
+
// Should handle gracefully
|
|
215
|
+
expect(result).toBeDefined();
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
describe("--root Flag", () => {
|
|
220
|
+
it("should analyze git in specified directory with --root", async () => {
|
|
221
|
+
const gitRepo = createGitRepo({
|
|
222
|
+
"package.json": '{"name": "root-test"}',
|
|
223
|
+
"src/main.js": "const main = 1;",
|
|
224
|
+
});
|
|
225
|
+
tempDirs.push(gitRepo);
|
|
226
|
+
|
|
227
|
+
const result = await runCLICommand("git", ["--root", gitRepo]);
|
|
228
|
+
|
|
229
|
+
expect(result.exitCode).toBe(0);
|
|
230
|
+
expect(result.stdout).toContain("Analyzing git activity");
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it("should handle --root with short flag -r", async () => {
|
|
234
|
+
const gitRepo = createGitRepo({
|
|
235
|
+
"package.json": '{"name": "short-flag-test"}',
|
|
236
|
+
});
|
|
237
|
+
tempDirs.push(gitRepo);
|
|
238
|
+
|
|
239
|
+
const result = await runCLICommand("git", ["-r", gitRepo]);
|
|
240
|
+
|
|
241
|
+
expect(result.exitCode).toBe(0);
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
describe("--limit Flag", () => {
|
|
246
|
+
it("should limit commits with --limit flag", async () => {
|
|
247
|
+
const gitRepo = createGitRepo({
|
|
248
|
+
"package.json": '{"name": "limit-test"}',
|
|
249
|
+
});
|
|
250
|
+
tempDirs.push(gitRepo);
|
|
251
|
+
|
|
252
|
+
// Make multiple commits
|
|
253
|
+
for (let i = 0; i < 5; i++) {
|
|
254
|
+
fs.writeFileSync(path.join(gitRepo, `file${i}.js`), `const x = ${i};`);
|
|
255
|
+
execSync("git add .", { cwd: gitRepo, stdio: "ignore" });
|
|
256
|
+
execSync(`git commit -m "Commit ${i}"`, { cwd: gitRepo, stdio: "ignore" });
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const result = await runCLICommand("git", ["--limit", "3"], gitRepo);
|
|
260
|
+
|
|
261
|
+
expect(result.exitCode).toBe(0);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it("should handle --limit with short flag -n", async () => {
|
|
265
|
+
const gitRepo = createGitRepo({
|
|
266
|
+
"package.json": '{"name": "n-flag-test"}',
|
|
267
|
+
});
|
|
268
|
+
tempDirs.push(gitRepo);
|
|
269
|
+
|
|
270
|
+
const result = await runCLICommand("git", ["-n", "10"], gitRepo);
|
|
271
|
+
|
|
272
|
+
expect(result.exitCode).toBe(0);
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
describe("--activity Flag", () => {
|
|
277
|
+
it("should show commit activity details with --activity", async () => {
|
|
278
|
+
const gitRepo = createGitRepo({
|
|
279
|
+
"package.json": '{"name": "activity-test"}',
|
|
280
|
+
"src/index.js": "const x = 1;",
|
|
281
|
+
});
|
|
282
|
+
tempDirs.push(gitRepo);
|
|
283
|
+
|
|
284
|
+
const result = await runCLICommand("git", ["--activity"], gitRepo);
|
|
285
|
+
|
|
286
|
+
expect(result.exitCode).toBe(0);
|
|
287
|
+
expect(result.stdout).toMatch(/Commit activity|commits/);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it("should handle --activity with short flag -a", async () => {
|
|
291
|
+
const gitRepo = createGitRepo({
|
|
292
|
+
"package.json": '{"name": "a-flag-test"}',
|
|
293
|
+
});
|
|
294
|
+
tempDirs.push(gitRepo);
|
|
295
|
+
|
|
296
|
+
const result = await runCLICommand("git", ["-a"], gitRepo);
|
|
297
|
+
|
|
298
|
+
expect(result.exitCode).toBe(0);
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
describe("--json Flag", () => {
|
|
303
|
+
it("should output JSON with --json flag", async () => {
|
|
304
|
+
const gitRepo = createGitRepo({
|
|
305
|
+
"package.json": '{"name": "json-test"}',
|
|
306
|
+
});
|
|
307
|
+
tempDirs.push(gitRepo);
|
|
308
|
+
|
|
309
|
+
const result = await runCLICommand("git", ["--json"], gitRepo);
|
|
310
|
+
|
|
311
|
+
expect(result.exitCode).toBe(0);
|
|
312
|
+
|
|
313
|
+
const combinedOutput = result.stdout + result.stderr;
|
|
314
|
+
const jsonMatch = combinedOutput.match(/\{[\s\S]*\}$/m);
|
|
315
|
+
expect(jsonMatch).not.toBeNull();
|
|
316
|
+
expect(() => JSON.parse(jsonMatch![0])).not.toThrow();
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
describe("--help Flag", () => {
|
|
321
|
+
it("should show help message with --help", async () => {
|
|
322
|
+
const gitRepo = createGitRepo({
|
|
323
|
+
"package.json": '{"name": "help-test"}',
|
|
324
|
+
});
|
|
325
|
+
tempDirs.push(gitRepo);
|
|
326
|
+
|
|
327
|
+
const result = await runCLICommand("git", ["--help"], gitRepo);
|
|
328
|
+
|
|
329
|
+
expect(result.exitCode).toBe(0);
|
|
330
|
+
expect(result.stdout).toContain("git - Analyze recent git activity");
|
|
331
|
+
expect(result.stdout).toContain("--root");
|
|
332
|
+
expect(result.stdout).toContain("--limit");
|
|
333
|
+
expect(result.stdout).toContain("--activity");
|
|
334
|
+
});
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
describe("Non-Git Repository", () => {
|
|
338
|
+
it("should error on non-git repository", async () => {
|
|
339
|
+
const nonGitDir = createTempProjectDir({
|
|
340
|
+
"package.json": '{"name": "non-git"}',
|
|
341
|
+
});
|
|
342
|
+
tempDirs.push(nonGitDir);
|
|
343
|
+
|
|
344
|
+
const result = await runCLICommand("git", [], nonGitDir);
|
|
345
|
+
|
|
346
|
+
expect(result.exitCode).toBe(1);
|
|
347
|
+
expect(result.stdout).toContain("Not a git repository");
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
describe("Error Handling", () => {
|
|
352
|
+
it("should handle corrupted git repository gracefully", async () => {
|
|
353
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "corrupt-git-"));
|
|
354
|
+
tempDirs.push(tempDir);
|
|
355
|
+
|
|
356
|
+
// Create a fake .git directory that isn't a real repo
|
|
357
|
+
fs.mkdirSync(path.join(tempDir, ".git"), { recursive: true });
|
|
358
|
+
fs.writeFileSync(path.join(tempDir, "README.md"), "# Test");
|
|
359
|
+
|
|
360
|
+
const result = await runCLICommand("git", [], tempDir);
|
|
361
|
+
|
|
362
|
+
// Should either succeed with empty results or fail gracefully
|
|
363
|
+
expect(result).toBeDefined();
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
it("should handle git command not available", async () => {
|
|
367
|
+
// This test assumes git is available, but verifies graceful handling
|
|
368
|
+
const gitRepo = createGitRepo({
|
|
369
|
+
"package.json": '{"name": "git-missing-test"}',
|
|
370
|
+
});
|
|
371
|
+
tempDirs.push(gitRepo);
|
|
372
|
+
|
|
373
|
+
const result = await runCLICommand("git", [], gitRepo);
|
|
374
|
+
|
|
375
|
+
// Should work if git is available
|
|
376
|
+
expect(result).toBeDefined();
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
// =========================================================================
|
|
382
|
+
// GRAPH COMMAND TESTS
|
|
383
|
+
// =========================================================================
|
|
384
|
+
|
|
385
|
+
describe("Graph Command", () => {
|
|
386
|
+
describe("Default Options", () => {
|
|
387
|
+
it("should build knowledge graph on express-api project", async () => {
|
|
388
|
+
const result = await runCLICommand("graph", [], EXPRESS_API_PATH);
|
|
389
|
+
|
|
390
|
+
expect(result.exitCode).toBe(0);
|
|
391
|
+
expect(result.stdout).toMatch(/Building knowledge graph|Graph Statistics/);
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
it("should create graph directory with knowledge-graph.json", async () => {
|
|
395
|
+
const testProject = createTempProjectDir({
|
|
396
|
+
"package.json": '{"name": "graph-test"}',
|
|
397
|
+
"src/index.js": "const x = 1;",
|
|
398
|
+
"src/app.js": "const app = {};",
|
|
399
|
+
});
|
|
400
|
+
tempDirs.push(testProject);
|
|
401
|
+
|
|
402
|
+
await runCLICommand("graph", [], testProject);
|
|
403
|
+
|
|
404
|
+
// Check that graph file was created
|
|
405
|
+
const graphDir = path.join(testProject, "ai-context", "graph");
|
|
406
|
+
expect(fs.existsSync(graphDir) || fs.existsSync(path.join(testProject, "ai-context"))).toBe(true);
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
it("should handle non-git repository", async () => {
|
|
410
|
+
const testProject = createTempProjectDir({
|
|
411
|
+
"package.json": '{"name": "no-git"}',
|
|
412
|
+
"src/index.js": "const x = 1;",
|
|
413
|
+
});
|
|
414
|
+
tempDirs.push(testProject);
|
|
415
|
+
|
|
416
|
+
const result = await runCLICommand("graph", [], testProject);
|
|
417
|
+
|
|
418
|
+
// Should complete with warning but exit code 0
|
|
419
|
+
expect(result.exitCode).toBe(0);
|
|
420
|
+
expect(result.stdout).toMatch(/Not a git repository|Building knowledge graph/);
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
describe("--root Flag", () => {
|
|
425
|
+
it("should build graph in specified directory with --root", async () => {
|
|
426
|
+
const testProject = createTempProjectDir({
|
|
427
|
+
"package.json": '{"name": "graph-root"}',
|
|
428
|
+
"src/main.js": "const main = 1;",
|
|
429
|
+
});
|
|
430
|
+
tempDirs.push(testProject);
|
|
431
|
+
|
|
432
|
+
const result = await runCLICommand("graph", ["--root", testProject]);
|
|
433
|
+
|
|
434
|
+
expect(result.exitCode).toBe(0);
|
|
435
|
+
expect(result.stdout).toMatch(/Building knowledge graph|Graph Statistics/);
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
it("should handle --root with short flag -r", async () => {
|
|
439
|
+
const testProject = createTempProjectDir({
|
|
440
|
+
"package.json": '{"name": "graph-r"}',
|
|
441
|
+
});
|
|
442
|
+
tempDirs.push(testProject);
|
|
443
|
+
|
|
444
|
+
const result = await runCLICommand("graph", ["-r", testProject]);
|
|
445
|
+
|
|
446
|
+
expect(result.exitCode).toBe(0);
|
|
447
|
+
});
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
describe("--stats Flag", () => {
|
|
451
|
+
it("should show graph statistics with --stats", async () => {
|
|
452
|
+
const testProject = createTempProjectDir({
|
|
453
|
+
"package.json": '{"name": "stats-test"}',
|
|
454
|
+
"src/index.js": "const x = 1;",
|
|
455
|
+
});
|
|
456
|
+
tempDirs.push(testProject);
|
|
457
|
+
|
|
458
|
+
const result = await runCLICommand("graph", ["--stats"], testProject);
|
|
459
|
+
|
|
460
|
+
expect(result.exitCode).toBe(0);
|
|
461
|
+
expect(result.stdout).toMatch(/Graph Statistics|Nodes:|Edges:/);
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
it("should handle --stats with short flag -s", async () => {
|
|
465
|
+
const testProject = createTempProjectDir({
|
|
466
|
+
"package.json": '{"name": "stats-short"}',
|
|
467
|
+
});
|
|
468
|
+
tempDirs.push(testProject);
|
|
469
|
+
|
|
470
|
+
const result = await runCLICommand("graph", ["-s"], testProject);
|
|
471
|
+
|
|
472
|
+
expect(result.exitCode).toBe(0);
|
|
473
|
+
});
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
describe("--json Flag", () => {
|
|
477
|
+
it("should output graph as JSON with --json", async () => {
|
|
478
|
+
const testProject = createTempProjectDir({
|
|
479
|
+
"package.json": '{"name": "graph-json"}',
|
|
480
|
+
"src/index.js": "const x = 1;",
|
|
481
|
+
});
|
|
482
|
+
tempDirs.push(testProject);
|
|
483
|
+
|
|
484
|
+
const result = await runCLICommand("graph", ["--json", "--no-git"], testProject);
|
|
485
|
+
|
|
486
|
+
expect(result.exitCode).toBe(0);
|
|
487
|
+
|
|
488
|
+
const combinedOutput = result.stdout + result.stderr;
|
|
489
|
+
const jsonMatch = combinedOutput.match(/\{[\s\S]*\}$/m);
|
|
490
|
+
expect(jsonMatch).not.toBeNull();
|
|
491
|
+
|
|
492
|
+
const json = JSON.parse(jsonMatch![0]);
|
|
493
|
+
expect(json.nodes).toBeDefined();
|
|
494
|
+
expect(json.edges).toBeDefined();
|
|
495
|
+
});
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
describe("--no-git Flag", () => {
|
|
499
|
+
it("should skip git history with --no-git", async () => {
|
|
500
|
+
const testProject = createTempProjectDir({
|
|
501
|
+
"package.json": '{"name": "no-git-flag"}',
|
|
502
|
+
});
|
|
503
|
+
tempDirs.push(testProject);
|
|
504
|
+
|
|
505
|
+
const result = await runCLICommand("graph", ["--no-git"], testProject);
|
|
506
|
+
|
|
507
|
+
expect(result.exitCode).toBe(0);
|
|
508
|
+
});
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
describe("--help Flag", () => {
|
|
512
|
+
it("should show help message with --help", async () => {
|
|
513
|
+
const testProject = createTempProjectDir({
|
|
514
|
+
"package.json": '{"name": "graph-help"}',
|
|
515
|
+
});
|
|
516
|
+
tempDirs.push(testProject);
|
|
517
|
+
|
|
518
|
+
const result = await runCLICommand("graph", ["--help"], testProject);
|
|
519
|
+
|
|
520
|
+
expect(result.exitCode).toBe(0);
|
|
521
|
+
expect(result.stdout).toContain("graph - Generate repository knowledge graph");
|
|
522
|
+
expect(result.stdout).toContain("--root");
|
|
523
|
+
expect(result.stdout).toContain("--stats");
|
|
524
|
+
expect(result.stdout).toContain("--json");
|
|
525
|
+
});
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
describe("Edge Cases", () => {
|
|
529
|
+
it("should handle empty project", async () => {
|
|
530
|
+
const emptyProject = fs.mkdtempSync(path.join(os.tmpdir(), "empty-graph-"));
|
|
531
|
+
tempDirs.push(emptyProject);
|
|
532
|
+
|
|
533
|
+
const result = await runCLICommand("graph", [], emptyProject);
|
|
534
|
+
|
|
535
|
+
// Should complete without crashing
|
|
536
|
+
expect(result.exitCode).toBe(0);
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
it("should handle project with only hidden files", async () => {
|
|
540
|
+
const hiddenProject = createTempProjectDir({
|
|
541
|
+
".gitignore": "node_modules",
|
|
542
|
+
".env": "SECRET=123",
|
|
543
|
+
});
|
|
544
|
+
tempDirs.push(hiddenProject);
|
|
545
|
+
|
|
546
|
+
const result = await runCLICommand("graph", [], hiddenProject);
|
|
547
|
+
|
|
548
|
+
expect(result.exitCode).toBe(0);
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
it("should handle deeply nested project", async () => {
|
|
552
|
+
const deepDir = path.join(
|
|
553
|
+
os.tmpdir(),
|
|
554
|
+
"graph-deep",
|
|
555
|
+
"level1",
|
|
556
|
+
"level2",
|
|
557
|
+
"level3"
|
|
558
|
+
);
|
|
559
|
+
fs.mkdirSync(deepDir, { recursive: true });
|
|
560
|
+
tempDirs.push(deepDir);
|
|
561
|
+
|
|
562
|
+
fs.writeFileSync(path.join(deepDir, "package.json"), '{"name": "deep"}');
|
|
563
|
+
fs.mkdirSync(path.join(deepDir, "src"), { recursive: true });
|
|
564
|
+
fs.writeFileSync(path.join(deepDir, "src", "index.js"), "const x = 1;");
|
|
565
|
+
|
|
566
|
+
const result = await runCLICommand("graph", [], deepDir);
|
|
567
|
+
|
|
568
|
+
expect(result.exitCode).toBe(0);
|
|
569
|
+
});
|
|
570
|
+
});
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
// =========================================================================
|
|
574
|
+
// UPDATE COMMAND TESTS
|
|
575
|
+
// =========================================================================
|
|
576
|
+
|
|
577
|
+
describe("Update Command", () => {
|
|
578
|
+
describe("Default Options", () => {
|
|
579
|
+
it("should require ai-context to exist", async () => {
|
|
580
|
+
const testProject = createTempProjectDir({
|
|
581
|
+
"package.json": '{"name": "update-test"}',
|
|
582
|
+
"src/index.js": "const x = 1;",
|
|
583
|
+
});
|
|
584
|
+
tempDirs.push(testProject);
|
|
585
|
+
|
|
586
|
+
const result = await runCLICommand("update", [], testProject);
|
|
587
|
+
|
|
588
|
+
expect(result.exitCode).toBe(1);
|
|
589
|
+
expect(result.stdout).toContain("AI context not found");
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
it("should run incremental update when ai-context exists", async () => {
|
|
593
|
+
const testProject = createTempProjectDir({
|
|
594
|
+
"package.json": '{"name": "update-test"}',
|
|
595
|
+
"src/index.js": "const x = 1;",
|
|
596
|
+
});
|
|
597
|
+
tempDirs.push(testProject);
|
|
598
|
+
|
|
599
|
+
// First run init to create ai-context
|
|
600
|
+
await runInitCommand([], testProject);
|
|
601
|
+
|
|
602
|
+
// Then run update
|
|
603
|
+
const result = await runCLICommand("update", [], testProject);
|
|
604
|
+
|
|
605
|
+
expect(result.exitCode).toBe(0);
|
|
606
|
+
expect(result.stdout).toMatch(/Running incremental update|Changed files|Updated:/);
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
it("should detect changed files", async () => {
|
|
610
|
+
const testProject = createTempProjectDir({
|
|
611
|
+
"package.json": '{"name": "changed-files-test"}',
|
|
612
|
+
"src/index.js": "const x = 1;",
|
|
613
|
+
});
|
|
614
|
+
tempDirs.push(testProject);
|
|
615
|
+
|
|
616
|
+
// First run init
|
|
617
|
+
await runInitCommand([], testProject);
|
|
618
|
+
|
|
619
|
+
// Make a change
|
|
620
|
+
fs.writeFileSync(path.join(testProject, "src", "index.js"), "const x = 2;");
|
|
621
|
+
|
|
622
|
+
const result = await runCLICommand("update", [], testProject);
|
|
623
|
+
|
|
624
|
+
expect(result.exitCode).toBe(0);
|
|
625
|
+
expect(result.stdout).toMatch(/Changed files:|modified/);
|
|
626
|
+
});
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
describe("--root Flag", () => {
|
|
630
|
+
it("should update in specified directory with --root", async () => {
|
|
631
|
+
const testProject = createTempProjectDir({
|
|
632
|
+
"package.json": '{"name": "update-root"}',
|
|
633
|
+
"src/main.js": "const main = 1;",
|
|
634
|
+
});
|
|
635
|
+
tempDirs.push(testProject);
|
|
636
|
+
|
|
637
|
+
// First run init
|
|
638
|
+
await runInitCommand(["--root", testProject], testProject);
|
|
639
|
+
|
|
640
|
+
const result = await runCLICommand("update", ["--root", testProject], testProject);
|
|
641
|
+
|
|
642
|
+
expect(result.exitCode).toBe(0);
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
it("should handle --root with short flag -r", async () => {
|
|
646
|
+
const testProject = createTempProjectDir({
|
|
647
|
+
"package.json": '{"name": "update-r"}',
|
|
648
|
+
});
|
|
649
|
+
tempDirs.push(testProject);
|
|
650
|
+
|
|
651
|
+
// First run init
|
|
652
|
+
await runInitCommand(["-r", testProject], testProject);
|
|
653
|
+
|
|
654
|
+
const result = await runCLICommand("update", ["-r", testProject], testProject);
|
|
655
|
+
|
|
656
|
+
expect(result.exitCode).toBe(0);
|
|
657
|
+
});
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
describe("--no-git Flag", () => {
|
|
661
|
+
it("should use filesystem timestamps instead of git with --no-git", async () => {
|
|
662
|
+
const testProject = createTempProjectDir({
|
|
663
|
+
"package.json": '{"name": "no-git-update"}',
|
|
664
|
+
"src/index.js": "const x = 1;",
|
|
665
|
+
});
|
|
666
|
+
tempDirs.push(testProject);
|
|
667
|
+
|
|
668
|
+
// First run init
|
|
669
|
+
await runInitCommand([], testProject);
|
|
670
|
+
|
|
671
|
+
const result = await runCLICommand("update", ["--no-git"], testProject);
|
|
672
|
+
|
|
673
|
+
expect(result.exitCode).toBe(0);
|
|
674
|
+
});
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
describe("--json Flag", () => {
|
|
678
|
+
it("should output JSON with --json flag", async () => {
|
|
679
|
+
const testProject = createTempProjectDir({
|
|
680
|
+
"package.json": '{"name": "update-json"}',
|
|
681
|
+
"src/index.js": "const x = 1;",
|
|
682
|
+
});
|
|
683
|
+
tempDirs.push(testProject);
|
|
684
|
+
|
|
685
|
+
// First run init
|
|
686
|
+
await runInitCommand([], testProject);
|
|
687
|
+
|
|
688
|
+
const result = await runCLICommand("update", ["--json"], testProject);
|
|
689
|
+
|
|
690
|
+
expect(result.exitCode).toBe(0);
|
|
691
|
+
// Extract JSON from output (may have status line before JSON)
|
|
692
|
+
const jsonStart = result.stdout.indexOf('{');
|
|
693
|
+
expect(jsonStart).toBeGreaterThan(-1);
|
|
694
|
+
const jsonString = result.stdout.substring(jsonStart);
|
|
695
|
+
const json = JSON.parse(jsonString);
|
|
696
|
+
expect(json.changedFiles).toBeDefined();
|
|
697
|
+
});
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
describe("--help Flag", () => {
|
|
701
|
+
it("should show help message with --help", async () => {
|
|
702
|
+
const testProject = createTempProjectDir({
|
|
703
|
+
"package.json": '{"name": "update-help"}',
|
|
704
|
+
});
|
|
705
|
+
tempDirs.push(testProject);
|
|
706
|
+
|
|
707
|
+
const result = await runCLICommand("update", ["--help"], testProject);
|
|
708
|
+
|
|
709
|
+
expect(result.exitCode).toBe(0);
|
|
710
|
+
expect(result.stdout).toContain("update - Incrementally update repository context");
|
|
711
|
+
expect(result.stdout).toContain("--root");
|
|
712
|
+
expect(result.stdout).toContain("--no-git");
|
|
713
|
+
expect(result.stdout).toContain("--json");
|
|
714
|
+
});
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
describe("Error Handling", () => {
|
|
718
|
+
it("should handle missing ai-context gracefully", async () => {
|
|
719
|
+
const testProject = createTempProjectDir({
|
|
720
|
+
"package.json": '{"name": "no-context"}',
|
|
721
|
+
});
|
|
722
|
+
tempDirs.push(testProject);
|
|
723
|
+
|
|
724
|
+
const result = await runCLICommand("update", [], testProject);
|
|
725
|
+
|
|
726
|
+
expect(result.exitCode).toBe(1);
|
|
727
|
+
expect(result.stdout).toContain("AI context not found");
|
|
728
|
+
});
|
|
729
|
+
|
|
730
|
+
it("should handle corrupted ai-context", async () => {
|
|
731
|
+
const testProject = createTempProjectDir({
|
|
732
|
+
"package.json": '{"name": "corrupted-context"}',
|
|
733
|
+
});
|
|
734
|
+
tempDirs.push(testProject);
|
|
735
|
+
|
|
736
|
+
// Create ai-context but with invalid content
|
|
737
|
+
const aiDir = path.join(testProject, "ai-context");
|
|
738
|
+
fs.mkdirSync(aiDir, { recursive: true });
|
|
739
|
+
fs.writeFileSync(path.join(aiDir, "invalid.json"), "{ invalid json }");
|
|
740
|
+
|
|
741
|
+
const result = await runCLICommand("update", [], testProject);
|
|
742
|
+
|
|
743
|
+
// Should handle gracefully
|
|
744
|
+
expect(result).toBeDefined();
|
|
745
|
+
});
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
describe("Edge Cases", () => {
|
|
749
|
+
it("should handle project with deleted files", async () => {
|
|
750
|
+
const testProject = createTempProjectDir({
|
|
751
|
+
"package.json": '{"name": "deleted-files"}',
|
|
752
|
+
"src/index.js": "const x = 1;",
|
|
753
|
+
"src/to-delete.js": "const y = 2;",
|
|
754
|
+
});
|
|
755
|
+
tempDirs.push(testProject);
|
|
756
|
+
|
|
757
|
+
// First run init
|
|
758
|
+
await runInitCommand([], testProject);
|
|
759
|
+
|
|
760
|
+
// Delete a file
|
|
761
|
+
fs.unlinkSync(path.join(testProject, "src", "to-delete.js"));
|
|
762
|
+
|
|
763
|
+
const result = await runCLICommand("update", [], testProject);
|
|
764
|
+
|
|
765
|
+
expect(result.exitCode).toBe(0);
|
|
766
|
+
});
|
|
767
|
+
|
|
768
|
+
it("should handle project with new files", async () => {
|
|
769
|
+
const testProject = createTempProjectDir({
|
|
770
|
+
"package.json": '{"name": "new-files"}',
|
|
771
|
+
"src/index.js": "const x = 1;",
|
|
772
|
+
});
|
|
773
|
+
tempDirs.push(testProject);
|
|
774
|
+
|
|
775
|
+
// First run init
|
|
776
|
+
await runInitCommand([], testProject);
|
|
777
|
+
|
|
778
|
+
// Add new files
|
|
779
|
+
fs.mkdirSync(path.join(testProject, "src", "new"), { recursive: true });
|
|
780
|
+
fs.writeFileSync(path.join(testProject, "src", "new", "file.js"), "const z = 3;");
|
|
781
|
+
|
|
782
|
+
const result = await runCLICommand("update", [], testProject);
|
|
783
|
+
|
|
784
|
+
expect(result.exitCode).toBe(0);
|
|
785
|
+
expect(result.stdout).toMatch(/Changed files:|added/);
|
|
786
|
+
});
|
|
787
|
+
|
|
788
|
+
it("should handle multiple rapid updates", async () => {
|
|
789
|
+
const testProject = createTempProjectDir({
|
|
790
|
+
"package.json": '{"name": "rapid-updates"}',
|
|
791
|
+
"src/index.js": "const x = 1;",
|
|
792
|
+
});
|
|
793
|
+
tempDirs.push(testProject);
|
|
794
|
+
|
|
795
|
+
// First run init
|
|
796
|
+
await runInitCommand([], testProject);
|
|
797
|
+
|
|
798
|
+
// Run update multiple times
|
|
799
|
+
const result1 = await runCLICommand("update", [], testProject);
|
|
800
|
+
const result2 = await runCLICommand("update", [], testProject);
|
|
801
|
+
|
|
802
|
+
expect(result1.exitCode).toBe(0);
|
|
803
|
+
expect(result2.exitCode).toBe(0);
|
|
804
|
+
});
|
|
805
|
+
});
|
|
806
|
+
});
|
|
807
|
+
|
|
808
|
+
// =========================================================================
|
|
809
|
+
// HELP AND VERSION TESTS
|
|
810
|
+
// =========================================================================
|
|
811
|
+
|
|
812
|
+
describe("Help and Version Commands", () => {
|
|
813
|
+
describe("Global --help Flag", () => {
|
|
814
|
+
it("should handle --help as unknown command", async () => {
|
|
815
|
+
const result = await runCLICommand("--help", []);
|
|
816
|
+
// Global --help is treated as unknown command
|
|
817
|
+
expect(result.exitCode).toBe(1);
|
|
818
|
+
expect(result.stdout).toContain("Unknown command");
|
|
819
|
+
});
|
|
820
|
+
|
|
821
|
+
it("should show all available commands via init --help", async () => {
|
|
822
|
+
const result = await runCLICommand("init", ["--help"]);
|
|
823
|
+
// init --help shows a subset of commands
|
|
824
|
+
expect(result.exitCode).toBe(0);
|
|
825
|
+
expect(result.stdout).toContain("init");
|
|
826
|
+
expect(result.stdout).toContain("index");
|
|
827
|
+
expect(result.stdout).toContain("doctor");
|
|
828
|
+
expect(result.stdout).toContain("explore");
|
|
829
|
+
expect(result.stdout).toContain("adapters");
|
|
830
|
+
});
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
describe("Init --help Flag", () => {
|
|
834
|
+
it("should show init command help", async () => {
|
|
835
|
+
const result = await runCLICommand("init", ["--help"]);
|
|
836
|
+
|
|
837
|
+
expect(result.exitCode).toBe(0);
|
|
838
|
+
expect(result.stdout).toMatch(/init|Usage:/);
|
|
839
|
+
});
|
|
840
|
+
});
|
|
841
|
+
|
|
842
|
+
describe("Index --help Flag", () => {
|
|
843
|
+
it("should show index command help", async () => {
|
|
844
|
+
const result = await runCLICommand("index", ["--help"]);
|
|
845
|
+
|
|
846
|
+
expect(result.exitCode).toBe(0);
|
|
847
|
+
expect(result.stdout).toContain("ai-first index");
|
|
848
|
+
expect(result.stdout).toContain("--root");
|
|
849
|
+
expect(result.stdout).toContain("--semantic");
|
|
850
|
+
});
|
|
851
|
+
});
|
|
852
|
+
|
|
853
|
+
describe("Context --help Flag", () => {
|
|
854
|
+
it("should show context command help", async () => {
|
|
855
|
+
const result = await runCLICommand("context", ["--help"]);
|
|
856
|
+
|
|
857
|
+
expect(result.exitCode).toBe(0);
|
|
858
|
+
expect(result.stdout).toContain("context");
|
|
859
|
+
});
|
|
860
|
+
});
|
|
861
|
+
|
|
862
|
+
describe("Summarize --help Flag", () => {
|
|
863
|
+
it("should show summarize command help", async () => {
|
|
864
|
+
const result = await runCLICommand("summarize", ["--help"]);
|
|
865
|
+
|
|
866
|
+
expect(result.exitCode).toBe(0);
|
|
867
|
+
expect(result.stdout).toContain("summarize");
|
|
868
|
+
});
|
|
869
|
+
});
|
|
870
|
+
|
|
871
|
+
describe("Query --help Flag", () => {
|
|
872
|
+
it("should show query help or require index", async () => {
|
|
873
|
+
// First try with --help (may require index to exist)
|
|
874
|
+
const result = await runCLICommand("query", ["--help"]);
|
|
875
|
+
// Query command requires an index to exist, so it may show error or help
|
|
876
|
+
expect(result).toBeDefined();
|
|
877
|
+
});
|
|
878
|
+
});
|
|
879
|
+
|
|
880
|
+
describe("Doctor --help Flag", () => {
|
|
881
|
+
it("should show doctor command help", async () => {
|
|
882
|
+
const result = await runCLICommand("doctor", ["--help"]);
|
|
883
|
+
|
|
884
|
+
expect(result.exitCode).toBe(0);
|
|
885
|
+
expect(result.stdout).toContain("doctor");
|
|
886
|
+
});
|
|
887
|
+
});
|
|
888
|
+
|
|
889
|
+
describe("Explore --help Flag", () => {
|
|
890
|
+
it("should show explore help or handle module name", async () => {
|
|
891
|
+
const result = await runCLICommand("explore", ["--help"]);
|
|
892
|
+
// Explore treats --help as a module name, so output varies
|
|
893
|
+
expect(result).toBeDefined();
|
|
894
|
+
});
|
|
895
|
+
});
|
|
896
|
+
|
|
897
|
+
describe("Map --help Flag", () => {
|
|
898
|
+
it("should show map command help", async () => {
|
|
899
|
+
const result = await runCLICommand("map", ["--help"]);
|
|
900
|
+
|
|
901
|
+
expect(result.exitCode).toBe(0);
|
|
902
|
+
expect(result.stdout).toContain("map");
|
|
903
|
+
});
|
|
904
|
+
});
|
|
905
|
+
|
|
906
|
+
describe("Adapters --help Flag", () => {
|
|
907
|
+
it("should show adapters command help", async () => {
|
|
908
|
+
const result = await runCLICommand("adapters", ["--help"]);
|
|
909
|
+
|
|
910
|
+
expect(result.exitCode).toBe(0);
|
|
911
|
+
expect(result.stdout).toContain("adapters");
|
|
912
|
+
});
|
|
913
|
+
});
|
|
914
|
+
|
|
915
|
+
describe("Watch --help Flag", () => {
|
|
916
|
+
it("should show watch command help", async () => {
|
|
917
|
+
const result = await runCLICommand("watch", ["--help"]);
|
|
918
|
+
|
|
919
|
+
expect(result.exitCode).toBe(0);
|
|
920
|
+
expect(result.stdout).toContain("watch");
|
|
921
|
+
});
|
|
922
|
+
});
|
|
923
|
+
|
|
924
|
+
describe("Unknown Command", () => {
|
|
925
|
+
it("should show error for unknown command", async () => {
|
|
926
|
+
const result = await runCLICommand("unknown-command", []);
|
|
927
|
+
|
|
928
|
+
expect(result.exitCode).toBe(1);
|
|
929
|
+
expect(result.stdout).toContain("Unknown command");
|
|
930
|
+
});
|
|
931
|
+
|
|
932
|
+
it("should suggest using --help for unknown command", async () => {
|
|
933
|
+
const result = await runCLICommand("unknown-command", []);
|
|
934
|
+
|
|
935
|
+
expect(result.stdout).toMatch(/--help|help/);
|
|
936
|
+
});
|
|
937
|
+
});
|
|
938
|
+
|
|
939
|
+
describe("Version Display", () => {
|
|
940
|
+
it("should show version with --version flag if supported", async () => {
|
|
941
|
+
const result = await runCLICommand("--version", []);
|
|
942
|
+
|
|
943
|
+
// Version might be shown or it might show help
|
|
944
|
+
// Either is acceptable
|
|
945
|
+
expect(result).toBeDefined();
|
|
946
|
+
});
|
|
947
|
+
|
|
948
|
+
it("should show version with -v flag if supported", async () => {
|
|
949
|
+
const result = await runCLICommand("-v", []);
|
|
950
|
+
|
|
951
|
+
expect(result).toBeDefined();
|
|
952
|
+
});
|
|
953
|
+
});
|
|
954
|
+
});
|
|
955
|
+
|
|
956
|
+
// =========================================================================
|
|
957
|
+
// INTEGRATION TESTS
|
|
958
|
+
// =========================================================================
|
|
959
|
+
|
|
960
|
+
describe("Integration Tests", () => {
|
|
961
|
+
it("should run full workflow: init -> git -> graph -> update", async () => {
|
|
962
|
+
// Create a git repository for integration testing
|
|
963
|
+
const gitRepo = createGitRepo({
|
|
964
|
+
"package.json": '{"name": "integration-test"}',
|
|
965
|
+
"src/index.js": "const x = 1;",
|
|
966
|
+
"src/app.js": "const app = {};",
|
|
967
|
+
"src/routes.js": "const routes = [];",
|
|
968
|
+
});
|
|
969
|
+
tempDirs.push(gitRepo);
|
|
970
|
+
|
|
971
|
+
// Step 1: Init
|
|
972
|
+
const initResult = await runInitCommand([], gitRepo);
|
|
973
|
+
expect(initResult.exitCode).toBe(0);
|
|
974
|
+
|
|
975
|
+
// Step 2: Git
|
|
976
|
+
const gitResult = await runCLICommand("git", [], gitRepo);
|
|
977
|
+
expect(gitResult.exitCode).toBe(0);
|
|
978
|
+
|
|
979
|
+
// Step 3: Graph
|
|
980
|
+
const graphResult = await runCLICommand("graph", ["--stats"], gitRepo);
|
|
981
|
+
expect(graphResult.exitCode).toBe(0);
|
|
982
|
+
|
|
983
|
+
// Step 4: Update
|
|
984
|
+
const updateResult = await runCLICommand("update", [], gitRepo);
|
|
985
|
+
expect(updateResult.exitCode).toBe(0);
|
|
986
|
+
});
|
|
987
|
+
|
|
988
|
+
it("should handle multiple commands in sequence", async () => {
|
|
989
|
+
const testProject = createTempProjectDir({
|
|
990
|
+
"package.json": '{"name": "multi-command"}',
|
|
991
|
+
"src/index.js": "const x = 1;",
|
|
992
|
+
"src/app.js": "const app = {};",
|
|
993
|
+
});
|
|
994
|
+
tempDirs.push(testProject);
|
|
995
|
+
|
|
996
|
+
// Run init first
|
|
997
|
+
const initResult = await runInitCommand([], testProject);
|
|
998
|
+
expect(initResult.exitCode).toBe(0);
|
|
999
|
+
|
|
1000
|
+
// Run graph
|
|
1001
|
+
const graphResult = await runCLICommand("graph", [], testProject);
|
|
1002
|
+
expect(graphResult.exitCode).toBe(0);
|
|
1003
|
+
|
|
1004
|
+
// Run update multiple times
|
|
1005
|
+
const update1 = await runCLICommand("update", [], testProject);
|
|
1006
|
+
expect(update1.exitCode).toBe(0);
|
|
1007
|
+
|
|
1008
|
+
// Modify file
|
|
1009
|
+
fs.writeFileSync(path.join(testProject, "src", "index.js"), "const x = 2;");
|
|
1010
|
+
|
|
1011
|
+
const update2 = await runCLICommand("update", [], testProject);
|
|
1012
|
+
expect(update2.exitCode).toBe(0);
|
|
1013
|
+
});
|
|
1014
|
+
|
|
1015
|
+
it("should work with different project types", async () => {
|
|
1016
|
+
// TypeScript project with git repo
|
|
1017
|
+
const tsProject = createGitRepo({
|
|
1018
|
+
"package.json": '{"name": "ts-project"}',
|
|
1019
|
+
"tsconfig.json": '{"compilerOptions": {}}',
|
|
1020
|
+
"src/index.ts": "export const main = (): void => {};",
|
|
1021
|
+
});
|
|
1022
|
+
tempDirs.push(tsProject);
|
|
1023
|
+
|
|
1024
|
+
await runInitCommand([], tsProject);
|
|
1025
|
+
const tsGitResult = await runCLICommand("git", [], tsProject);
|
|
1026
|
+
expect(tsGitResult.exitCode).toBe(0);
|
|
1027
|
+
|
|
1028
|
+
const tsGraphResult = await runCLICommand("graph", [], tsProject);
|
|
1029
|
+
expect(tsGraphResult.exitCode).toBe(0);
|
|
1030
|
+
|
|
1031
|
+
// Python project with git repo
|
|
1032
|
+
const pyProject = createGitRepo({
|
|
1033
|
+
"main.py": "def main(): pass",
|
|
1034
|
+
"requirements.txt": "flask==2.0.0",
|
|
1035
|
+
});
|
|
1036
|
+
tempDirs.push(pyProject);
|
|
1037
|
+
|
|
1038
|
+
await runInitCommand([], pyProject);
|
|
1039
|
+
const pyGitResult = await runCLICommand("git", [], pyProject);
|
|
1040
|
+
expect(pyGitResult.exitCode).toBe(0);
|
|
1041
|
+
});
|
|
1042
|
+
|
|
1043
|
+
it("should handle concurrent command execution", async () => {
|
|
1044
|
+
const projects = [
|
|
1045
|
+
createTempProjectDir({ "package.json": '{"name": "concurrent1"}', "src/index.js": "const x = 1;" }),
|
|
1046
|
+
createTempProjectDir({ "package.json": '{"name": "concurrent2"}', "src/index.js": "const y = 2;" }),
|
|
1047
|
+
createTempProjectDir({ "package.json": '{"name": "concurrent3"}', "src/index.js": "const z = 3;" }),
|
|
1048
|
+
];
|
|
1049
|
+
tempDirs.push(...projects);
|
|
1050
|
+
|
|
1051
|
+
// Run init on all projects
|
|
1052
|
+
const initPromises = projects.map(p => runInitCommand([], p));
|
|
1053
|
+
const initResults = await Promise.all(initPromises);
|
|
1054
|
+
initResults.forEach(r => expect(r.exitCode).toBe(0));
|
|
1055
|
+
|
|
1056
|
+
// Run graph on all projects concurrently
|
|
1057
|
+
const graphPromises = projects.map(p => runCLICommand("graph", [], p));
|
|
1058
|
+
const graphResults = await Promise.all(graphPromises);
|
|
1059
|
+
graphResults.forEach(r => expect(r.exitCode).toBe(0));
|
|
1060
|
+
});
|
|
1061
|
+
});
|
|
1062
|
+
|
|
1063
|
+
// =========================================================================
|
|
1064
|
+
// VERIFICATION CHECKLIST TESTS
|
|
1065
|
+
// =========================================================================
|
|
1066
|
+
|
|
1067
|
+
describe("Verification Checklist", () => {
|
|
1068
|
+
it("should verify git command on express-api project", async () => {
|
|
1069
|
+
// This project has a .git directory
|
|
1070
|
+
const hasGit = fs.existsSync(path.join(EXPRESS_API_PATH, ".git"));
|
|
1071
|
+
|
|
1072
|
+
if (hasGit) {
|
|
1073
|
+
const result = await runCLICommand("git", [], EXPRESS_API_PATH);
|
|
1074
|
+
expect(result.exitCode).toBe(0);
|
|
1075
|
+
expect(result.stdout).toContain("Recent files:");
|
|
1076
|
+
} else {
|
|
1077
|
+
// Skip if not a git repo
|
|
1078
|
+
expect(true).toBe(true);
|
|
1079
|
+
}
|
|
1080
|
+
});
|
|
1081
|
+
|
|
1082
|
+
it("should verify graph command on express-api project", async () => {
|
|
1083
|
+
const result = await runCLICommand("graph", [], EXPRESS_API_PATH);
|
|
1084
|
+
expect(result.exitCode).toBe(0);
|
|
1085
|
+
expect(result.stdout).toMatch(/Building knowledge graph|Graph Statistics/);
|
|
1086
|
+
});
|
|
1087
|
+
|
|
1088
|
+
it("should verify git command exists via git --help", async () => {
|
|
1089
|
+
const testProject = createGitRepo({
|
|
1090
|
+
"package.json": '{"name": "git-help-test"}',
|
|
1091
|
+
});
|
|
1092
|
+
tempDirs.push(testProject);
|
|
1093
|
+
|
|
1094
|
+
const result = await runCLICommand("git", ["--help"], testProject);
|
|
1095
|
+
expect(result.exitCode).toBe(0);
|
|
1096
|
+
expect(result.stdout).toContain("git");
|
|
1097
|
+
});
|
|
1098
|
+
|
|
1099
|
+
it("should verify graph command exists via graph --help", async () => {
|
|
1100
|
+
const testProject = createTempProjectDir({
|
|
1101
|
+
"package.json": '{"name": "graph-help-test"}',
|
|
1102
|
+
});
|
|
1103
|
+
tempDirs.push(testProject);
|
|
1104
|
+
|
|
1105
|
+
const result = await runCLICommand("graph", ["--help"], testProject);
|
|
1106
|
+
expect(result.exitCode).toBe(0);
|
|
1107
|
+
expect(result.stdout).toContain("graph");
|
|
1108
|
+
});
|
|
1109
|
+
|
|
1110
|
+
it("should verify update command exists via update --help", async () => {
|
|
1111
|
+
const testProject = createTempProjectDir({
|
|
1112
|
+
"package.json": '{"name": "update-help-test"}',
|
|
1113
|
+
});
|
|
1114
|
+
tempDirs.push(testProject);
|
|
1115
|
+
|
|
1116
|
+
const result = await runCLICommand("update", ["--help"], testProject);
|
|
1117
|
+
expect(result.exitCode).toBe(0);
|
|
1118
|
+
expect(result.stdout).toContain("update");
|
|
1119
|
+
});
|
|
1120
|
+
|
|
1121
|
+
it("should verify CLI basic functionality", async () => {
|
|
1122
|
+
const result = await runCLICommand("--help", []);
|
|
1123
|
+
// --help is treated as unknown command, exits with 1
|
|
1124
|
+
expect(result.exitCode).toBe(1);
|
|
1125
|
+
expect(result.stdout).toContain("Unknown command");
|
|
1126
|
+
});
|
|
1127
|
+
});
|
|
1128
|
+
});
|