gherkin-ai 1.3.0 → 1.4.0

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/README.md CHANGED
@@ -16,29 +16,33 @@ While simple AI prompt generators produce generic text instructions, AI agents o
16
16
  - **`contracts.ts`**: Strict domain interfaces, event schemas, Zod DTOs, CQRS Event Store ports, and Architecture Decision Records (ADRs).
17
17
  - **`openapi.json`**: Auto-generated OpenAPI 3.0 specification derived directly from Gherkin AST schemas.
18
18
  - **`fixtures.ts` & `seed.sql`**: Concrete database seeds (hashed passwords, bcrypt cost factor 12, pre-conditions) raising AI acceptance test success rates from ~30% to ~85%.
19
- - **Brownfield Integration (`ghk detect` & `ghk add`)**: Inject contracts directly into existing project module folders without starting from scratch.
19
+ - **Interactive Spec Wizard (`ghk create`)**: Create Gherkin specifications step-by-step directly from your terminal.
20
+ - **Brownfield Integration (`ghk detect` & `ghk add`)**: Inject contracts directly into existing project module folders (Laravel, Rails, .NET, Angular, NestJS, etc.).
20
21
  - **Bilingual Gherkin Parsing**: Native support for English (`Given/When/Then`) and Spanish (`Dado/Cuando/Entonces`).
21
- - **Strict Stack Versions**: Enforces explicit package versions (e.g., NestJS v10 + Prisma + Zod + Redis) so agents never diverge.
22
- - **Runnable Infrastructure**: Includes pre-configured `docker-compose.yml` (PostgreSQL, Redis, RabbitMQ) and native AWS Lambda `serverless.yml` for FaaS architectures.
23
- - **`ghk validate`**: Deep Architectural Linter checking layer boundary import isolation, step coverage, and circular dependency rules.
24
22
 
25
23
  ---
26
24
 
27
- ## 🚀 Usage Modes: Greenfield vs. Brownfield (Existing Projects)
25
+ ## 🚀 Quick Start Commands
28
26
 
29
- ### 1. Existing Projects (Brownfield Mode)
27
+ ### 1. Create a Gherkin Spec Interactively (`ghk create`)
30
28
 
31
- If you have an existing codebase, auto-detect your stack and inject feature contracts into specific module folders:
29
+ Don't have a `.feature` file ready? Build one interactively step-by-step in terminal:
32
30
 
33
31
  ```bash
34
- # 1. Auto-detect stack (reads package.json, prisma, tsconfig, etc.)
32
+ ghk create # (or: ghk new)
33
+ ```
34
+
35
+ ### 2. Existing Projects (Brownfield Mode)
36
+
37
+ ```bash
38
+ # 1. Auto-detect stack (Laravel, Rails, .NET, NestJS, Angular, Flutter, etc.)
35
39
  ghk detect
36
40
 
37
41
  # 2. Inject contract directly into an existing module folder
38
42
  ghk add --feature ./specs/payments.feature --target ./src/modules/payments
39
43
  ```
40
44
 
41
- ### 2. New Projects (Greenfield Mode)
45
+ ### 3. New Projects (Greenfield Mode)
42
46
 
43
47
  ```bash
44
48
  # 1. Initialize project configuration interactively
@@ -53,17 +57,6 @@ ghk validate --feature ./specs/auth.feature
53
57
 
54
58
  ---
55
59
 
56
- ## 🏗️ Supported Architecture Styles
57
-
58
- - **Hexagonal Architecture (Ports & Adapters)**
59
- - **Domain-Driven Design (DDD)**
60
- - **Clean Architecture**
61
- - **CQRS + Event Sourcing (Real Event Store & Aggregate Versions)**
62
- - **Serverless / FaaS (Native AWS Lambda & `serverless.yml`)**
63
- - **Microservices Architecture**
64
-
65
- ---
66
-
67
60
  ## 📖 Complete Documentation
68
61
 
69
62
  - [Comprehensive Usage Guide](docs/USAGE_GUIDE.md)
@@ -1 +1 @@
1
- {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAaA,wBAAsB,gBAAgB,CAAC,OAAO,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAwDrH"}
1
+ {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAeA,wBAAsB,gBAAgB,CAAC,OAAO,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAwErH"}
@@ -8,24 +8,40 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.handleAddCommand = handleAddCommand;
10
10
  const path_1 = __importDefault(require("path"));
11
+ const inquirer_1 = __importDefault(require("inquirer"));
11
12
  const config_1 = require("../core/config");
12
13
  const stack_detector_1 = require("../core/stack-detector");
13
14
  const gherkin_parser_1 = require("../core/gherkin-parser");
14
15
  const contracts_1 = require("../generators/contracts");
15
16
  const prompts_1 = require("../generators/prompts");
17
+ const create_1 = require("./create");
16
18
  const file_system_1 = require("../utils/file-system");
17
19
  const logger_1 = require("../utils/logger");
18
20
  async function handleAddCommand(options) {
19
21
  logger_1.logger.banner();
20
22
  if (!options.feature) {
21
- logger_1.logger.error('Missing required option: --feature <file>');
22
- logger_1.logger.info('Usage: ghk add --feature ./specs/my-feature.feature [--target ./src/modules/my-feature]');
23
- process.exit(1);
23
+ logger_1.logger.info('No --feature file specified. Launching interactive spec wizard...');
24
+ await (0, create_1.handleCreateCommand)({ target: options.target });
25
+ return;
24
26
  }
25
27
  const featurePath = path_1.default.resolve(process.cwd(), options.feature);
26
28
  if (!(0, file_system_1.fileExistsSync)(featurePath)) {
27
- logger_1.logger.error(`Feature file not found at: ${featurePath}`);
28
- process.exit(1);
29
+ logger_1.logger.warn(`Feature file not found at: ${featurePath}`);
30
+ const answer = await inquirer_1.default.prompt([
31
+ {
32
+ type: 'confirm',
33
+ name: 'createNow',
34
+ message: '¿Deseas crear la especificación Gherkin paso a paso ahora (wizard interactivo)?',
35
+ default: true
36
+ }
37
+ ]);
38
+ if (answer.createNow) {
39
+ await (0, create_1.handleCreateCommand)({ output: options.feature, target: options.target });
40
+ return;
41
+ }
42
+ else {
43
+ process.exit(1);
44
+ }
29
45
  }
30
46
  // Load config or auto-detect if config doesn't exist
31
47
  let config = (0, config_1.loadConfig)(options.config);
@@ -1 +1 @@
1
- {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare function handleCreateCommand(options: {
2
+ output?: string;
3
+ target?: string;
4
+ lang?: string;
5
+ }): Promise<void>;
6
+ //# sourceMappingURL=create.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAWA,wBAAsB,mBAAmB,CAAC,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAiIrH"}
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ /* ==========================================================================
3
+ gherkin-ai-cli - 'create' Command Handler (Localized Interactive Spec Wizard)
4
+ ========================================================================== */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.handleCreateCommand = handleCreateCommand;
10
+ const path_1 = __importDefault(require("path"));
11
+ const inquirer_1 = __importDefault(require("inquirer"));
12
+ const add_1 = require("./add");
13
+ const i18n_cli_1 = require("../utils/i18n-cli");
14
+ const file_system_1 = require("../utils/file-system");
15
+ const logger_1 = require("../utils/logger");
16
+ async function handleCreateCommand(options) {
17
+ logger_1.logger.banner();
18
+ const locale = await (0, i18n_cli_1.ensureCliLanguage)(options.lang);
19
+ const isEs = locale === 'es';
20
+ logger_1.logger.info(isEs ? 'Asistente Interactivo Gherkin - Creación paso a paso' : 'Interactive Gherkin Spec Wizard - Step-by-step feature creator');
21
+ const answers = await inquirer_1.default.prompt([
22
+ {
23
+ type: 'input',
24
+ name: 'featureName',
25
+ message: (0, i18n_cli_1.t)('featureNamePrompt', locale),
26
+ default: isEs ? 'Autenticación de Doble Factor 2FA' : 'Two Factor Authentication 2FA',
27
+ validate: (input) => input.trim().length > 0 || 'Name cannot be empty.'
28
+ },
29
+ {
30
+ type: 'input',
31
+ name: 'actor',
32
+ message: (0, i18n_cli_1.t)('actorPrompt', locale),
33
+ default: isEs ? 'usuario autenticado del sistema' : 'authenticated system user'
34
+ },
35
+ {
36
+ type: 'input',
37
+ name: 'action',
38
+ message: (0, i18n_cli_1.t)('actionPrompt', locale),
39
+ default: isEs ? 'habilitar y verificar un código OTP de dos factores' : 'enable and verify a two-factor OTP code'
40
+ },
41
+ {
42
+ type: 'input',
43
+ name: 'outcome',
44
+ message: (0, i18n_cli_1.t)('outcomePrompt', locale),
45
+ default: isEs ? 'proteger mi cuenta contra accesos no autorizados' : 'protect my account against unauthorized access'
46
+ },
47
+ {
48
+ type: 'input',
49
+ name: 'scenarioName',
50
+ message: (0, i18n_cli_1.t)('scenarioNamePrompt', locale),
51
+ default: isEs ? 'Habilitar y verificar código 2FA exitosamente' : 'Enable and verify 2FA code successfully'
52
+ }
53
+ ]);
54
+ const steps = [];
55
+ console.log(isEs ? '\n--- Asistente de Pasos Gherkin (Dado / Cuando / Entonces) ---' : '\n--- Step-by-step Gherkin Scenario Builder (Given / When / Then) ---');
56
+ let addMore = true;
57
+ let defaultKw = isEs ? 'Dado' : 'Given';
58
+ const choicesEn = ['Given', 'When', 'Then', 'And', 'But'];
59
+ const choicesEs = ['Dado', 'Cuando', 'Entonces', 'Y', 'Pero'];
60
+ while (addMore) {
61
+ const stepAnswers = await inquirer_1.default.prompt([
62
+ {
63
+ type: 'list',
64
+ name: 'keyword',
65
+ message: (0, i18n_cli_1.t)('stepKeywordPrompt', locale),
66
+ choices: isEs ? choicesEs : choicesEn,
67
+ default: defaultKw
68
+ },
69
+ {
70
+ type: 'input',
71
+ name: 'text',
72
+ message: (0, i18n_cli_1.t)('stepDescPrompt', locale),
73
+ validate: (input) => input.trim().length > 0 || 'Description cannot be empty.'
74
+ },
75
+ {
76
+ type: 'confirm',
77
+ name: 'next',
78
+ message: (0, i18n_cli_1.t)('addAnotherStepPrompt', locale),
79
+ default: true
80
+ }
81
+ ]);
82
+ steps.push({ keyword: stepAnswers.keyword, text: stepAnswers.text });
83
+ if (['Dado', 'Given'].includes(stepAnswers.keyword))
84
+ defaultKw = isEs ? 'Cuando' : 'When';
85
+ else if (['Cuando', 'When'].includes(stepAnswers.keyword))
86
+ defaultKw = isEs ? 'Entonces' : 'Then';
87
+ else
88
+ defaultKw = isEs ? 'Y' : 'And';
89
+ addMore = stepAnswers.next;
90
+ }
91
+ // Construct Gherkin File Content
92
+ const featureKw = isEs ? 'Característica:' : 'Feature:';
93
+ const asKw = isEs ? 'Como' : 'As a';
94
+ const wantKw = isEs ? 'Quiero' : 'I want to';
95
+ const soKw = isEs ? 'Para' : 'So that';
96
+ const scKw = isEs ? 'Escenario:' : 'Scenario:';
97
+ let gherkinContent = `${featureKw} ${answers.featureName}\n`;
98
+ gherkinContent += ` ${asKw} ${answers.actor}\n`;
99
+ gherkinContent += ` ${wantKw} ${answers.action}\n`;
100
+ gherkinContent += ` ${soKw} ${answers.outcome}\n\n`;
101
+ gherkinContent += ` ${scKw} ${answers.scenarioName}\n`;
102
+ steps.forEach(st => {
103
+ gherkinContent += ` ${st.keyword} ${st.text}\n`;
104
+ });
105
+ const defaultFileName = answers.featureName.toLowerCase().replace(/[^a-z0-9]/g, '_') + '.feature';
106
+ const targetSpecPath = options.output
107
+ ? path_1.default.resolve(process.cwd(), options.output)
108
+ : path_1.default.resolve(process.cwd(), 'specs', defaultFileName);
109
+ (0, file_system_1.writeFileSync)(targetSpecPath, gherkinContent);
110
+ logger_1.logger.success(`${(0, i18n_cli_1.t)('specCreated', locale)} ${targetSpecPath}`);
111
+ console.log('\n------------------------------------------------------------');
112
+ console.log(gherkinContent);
113
+ console.log('------------------------------------------------------------\n');
114
+ // Prompt to immediately inject contracts into project
115
+ const injectAnswer = await inquirer_1.default.prompt([
116
+ {
117
+ type: 'confirm',
118
+ name: 'inject',
119
+ message: (0, i18n_cli_1.t)('injectPrompt', locale),
120
+ default: true
121
+ }
122
+ ]);
123
+ if (injectAnswer.inject) {
124
+ await (0, add_1.handleAddCommand)({
125
+ feature: targetSpecPath,
126
+ target: options.target
127
+ });
128
+ }
129
+ }
130
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function handleLangCommand(options: {
2
+ set?: string;
3
+ }): Promise<void>;
4
+ //# sourceMappingURL=lang.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lang.d.ts","sourceRoot":"","sources":["../../src/commands/lang.ts"],"names":[],"mappings":"AAQA,wBAAsB,iBAAiB,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA4BhF"}
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ /* ==========================================================================
3
+ gherkin-ai-cli - 'lang' Command Handler (Language Switcher)
4
+ ========================================================================== */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.handleLangCommand = handleLangCommand;
10
+ const inquirer_1 = __importDefault(require("inquirer"));
11
+ const i18n_cli_1 = require("../utils/i18n-cli");
12
+ const logger_1 = require("../utils/logger");
13
+ async function handleLangCommand(options) {
14
+ logger_1.logger.banner();
15
+ if (options.set === 'en' || options.set === 'es') {
16
+ (0, i18n_cli_1.saveGlobalUserLocale)(options.set);
17
+ logger_1.logger.success((0, i18n_cli_1.t)('langUpdated', options.set));
18
+ return;
19
+ }
20
+ const current = (0, i18n_cli_1.getGlobalUserLocale)() || 'en';
21
+ logger_1.logger.info(`${(0, i18n_cli_1.t)('langCurrent', current)} ${current === 'es' ? '🇪🇸 Español' : '🇺🇸 English'}`);
22
+ const answer = await inquirer_1.default.prompt([
23
+ {
24
+ type: 'list',
25
+ name: 'locale',
26
+ message: (0, i18n_cli_1.t)('selectLanguagePrompt', current),
27
+ choices: [
28
+ { name: '🇺🇸 English', value: 'en' },
29
+ { name: '🇪🇸 Español', value: 'es' }
30
+ ],
31
+ default: current
32
+ }
33
+ ]);
34
+ const selected = answer.locale;
35
+ (0, i18n_cli_1.saveGlobalUserLocale)(selected);
36
+ logger_1.logger.success((0, i18n_cli_1.t)('langUpdated', selected));
37
+ }
38
+ //# sourceMappingURL=lang.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lang.js","sourceRoot":"","sources":["../../src/commands/lang.ts"],"names":[],"mappings":";AAAA;;gFAEgF;;;;;AAMhF,8CA4BC;AAhCD,wDAAgC;AAChC,gDAAqH;AACrH,4CAAyC;AAElC,KAAK,UAAU,iBAAiB,CAAC,OAAyB;IAC/D,eAAM,CAAC,MAAM,EAAE,CAAC;IAEhB,IAAI,OAAO,CAAC,GAAG,KAAK,IAAI,IAAI,OAAO,CAAC,GAAG,KAAK,IAAI,EAAE,CAAC;QACjD,IAAA,+BAAoB,EAAC,OAAO,CAAC,GAAsB,CAAC,CAAC;QACrD,eAAM,CAAC,OAAO,CAAC,IAAA,YAAC,EAAC,aAAa,EAAE,OAAO,CAAC,GAAsB,CAAC,CAAC,CAAC;QACjE,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,IAAA,8BAAmB,GAAE,IAAI,IAAI,CAAC;IAC9C,eAAM,CAAC,IAAI,CAAC,GAAG,IAAA,YAAC,EAAC,aAAa,EAAE,OAAO,CAAC,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC;IAElG,MAAM,MAAM,GAAG,MAAM,kBAAQ,CAAC,MAAM,CAAC;QACnC;YACE,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,IAAA,YAAC,EAAC,sBAAsB,EAAE,OAAO,CAAC;YAC3C,OAAO,EAAE;gBACP,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,IAAI,EAAE;gBACrC,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,IAAI,EAAE;aACtC;YACD,OAAO,EAAE,OAAO;SACjB;KACF,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAyB,CAAC;IAClD,IAAA,+BAAoB,EAAC,QAAQ,CAAC,CAAC;IAC/B,eAAM,CAAC,OAAO,CAAC,IAAA,YAAC,EAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC;AAC7C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"stack-detector.d.ts","sourceRoot":"","sources":["../../src/core/stack-detector.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAiB,MAAM,UAAU,CAAC;AAE1D,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,MAAsB,GAAG,eAAe,CA0FpF"}
1
+ {"version":3,"file":"stack-detector.d.ts","sourceRoot":"","sources":["../../src/core/stack-detector.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,eAAe,EAAiB,MAAM,UAAU,CAAC;AAE1D,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,MAAsB,GAAG,eAAe,CAmNpF"}
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  /* ==========================================================================
3
- gherkin-ai-cli - Stack & Architecture Auto-Detector for Existing Projects
3
+ gherkin-ai-cli - Multi-Language Stack & Architecture Auto-Detector
4
+ Supports: PHP/Laravel, Ruby/Rails, C#/.NET, Java/Spring, Python/Django/FastAPI,
5
+ Go, Node/Nest/Express, Angular, Ionic, React, Vue, Svelte, Flutter.
4
6
  ========================================================================== */
5
7
  var __importDefault = (this && this.__importDefault) || function (mod) {
6
8
  return (mod && mod.__esModule) ? mod : { "default": mod };
@@ -19,84 +21,196 @@ function detectExistingStack(rootDir = process.cwd()) {
19
21
  rules: { ...config_1.defaultConfig.rules },
20
22
  outputDir: './src'
21
23
  };
22
- const packageJsonPath = path_1.default.join(rootDir, 'package.json');
24
+ const gemfilePath = path_1.default.join(rootDir, 'Gemfile');
25
+ const composerJsonPath = path_1.default.join(rootDir, 'composer.json');
26
+ const artisanPath = path_1.default.join(rootDir, 'artisan');
27
+ const goModPath = path_1.default.join(rootDir, 'go.mod');
23
28
  const pyProjectPath = path_1.default.join(rootDir, 'pyproject.toml');
24
29
  const reqTxtPath = path_1.default.join(rootDir, 'requirements.txt');
30
+ const managePyPath = path_1.default.join(rootDir, 'manage.py');
25
31
  const pomXmlPath = path_1.default.join(rootDir, 'pom.xml');
26
- // 1. Node.js / TypeScript Stack Detection
27
- if ((0, file_system_1.fileExistsSync)(packageJsonPath)) {
32
+ const buildGradlePath = path_1.default.join(rootDir, 'build.gradle');
33
+ const angularJsonPath = path_1.default.join(rootDir, 'angular.json');
34
+ const pubspecPath = path_1.default.join(rootDir, 'pubspec.yaml');
35
+ const packageJsonPath = path_1.default.join(rootDir, 'package.json');
36
+ // 1. Ruby on Rails Stack Detection
37
+ if ((0, file_system_1.fileExistsSync)(gemfilePath)) {
38
+ detected.stack.language = 'ruby';
39
+ detected.stack.framework = 'rails';
40
+ detected.stack.orm = 'active-record';
41
+ detected.stack.database = 'postgresql';
42
+ detected.stack.validation = 'active-model-validations';
43
+ detected.stack.testing = 'rspec';
44
+ detected.architecture = 'monolith';
45
+ detected.outputDir = './app';
46
+ try {
47
+ const gemContent = (0, file_system_1.readFileSync)(gemfilePath);
48
+ if (gemContent.includes('rspec-rails'))
49
+ detected.stack.testing = 'rspec';
50
+ else
51
+ detected.stack.testing = 'minitest';
52
+ }
53
+ catch {
54
+ // Ignore
55
+ }
56
+ }
57
+ // 2. C# / .NET / ASP.NET Core Stack Detection
58
+ else if ((0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'Program.cs')) || (0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'appsettings.json'))) {
59
+ detected.stack.language = 'csharp';
60
+ detected.stack.framework = 'dotnet-aspnetcore';
61
+ detected.stack.orm = 'entity-framework-core';
62
+ detected.stack.database = 'sql-server';
63
+ detected.stack.validation = 'fluent-validation';
64
+ detected.stack.testing = 'xunit';
65
+ }
66
+ // 3. PHP / Laravel Stack Detection
67
+ else if ((0, file_system_1.fileExistsSync)(artisanPath) || (0, file_system_1.fileExistsSync)(composerJsonPath)) {
68
+ detected.stack.language = 'php';
69
+ detected.stack.framework = 'laravel';
70
+ detected.stack.orm = 'eloquent';
71
+ detected.stack.database = 'postgresql';
72
+ detected.stack.validation = 'laravel-validation';
73
+ detected.stack.auth = 'laravel-sanctum';
74
+ detected.stack.testing = 'phpunit';
75
+ detected.architecture = 'monolith';
76
+ detected.outputDir = './app';
77
+ if ((0, file_system_1.fileExistsSync)(composerJsonPath)) {
78
+ try {
79
+ const raw = (0, file_system_1.readFileSync)(composerJsonPath);
80
+ const composer = JSON.parse(raw);
81
+ if (composer.name)
82
+ detected.projectName = composer.name.split('/')[1] || composer.name;
83
+ const reqs = { ...(composer.require || {}), ...(composer['require-dev'] || {}) };
84
+ if (reqs['pestphp/pest'])
85
+ detected.stack.testing = 'pest';
86
+ if (reqs['symfony/symfony']) {
87
+ detected.stack.framework = 'symfony';
88
+ detected.stack.orm = 'doctrine';
89
+ }
90
+ }
91
+ catch {
92
+ // Ignore
93
+ }
94
+ }
95
+ }
96
+ // 4. Flutter / Dart Mobile Detection
97
+ else if ((0, file_system_1.fileExistsSync)(pubspecPath)) {
98
+ detected.stack.language = 'dart';
99
+ detected.stack.framework = 'flutter';
100
+ detected.stack.orm = 'sqflite';
101
+ detected.stack.database = 'sqlite';
102
+ detected.stack.validation = 'form-validation';
103
+ detected.stack.testing = 'flutter_test';
104
+ detected.outputDir = './lib';
105
+ }
106
+ // 5. Python Stack Detection (Django / FastAPI / Flask)
107
+ else if ((0, file_system_1.fileExistsSync)(managePyPath) || (0, file_system_1.fileExistsSync)(pyProjectPath) || (0, file_system_1.fileExistsSync)(reqTxtPath)) {
108
+ detected.stack.language = 'python';
109
+ detected.stack.testing = 'pytest';
110
+ detected.stack.database = 'postgresql';
111
+ if ((0, file_system_1.fileExistsSync)(managePyPath)) {
112
+ detected.stack.framework = 'django';
113
+ detected.stack.orm = 'django-orm';
114
+ detected.stack.validation = 'django-forms';
115
+ }
116
+ else {
117
+ detected.stack.framework = 'fastapi';
118
+ detected.stack.orm = 'sqlalchemy';
119
+ detected.stack.validation = 'pydantic';
120
+ }
121
+ }
122
+ // 6. Go Stack Detection
123
+ else if ((0, file_system_1.fileExistsSync)(goModPath)) {
124
+ detected.stack.language = 'go';
125
+ detected.stack.framework = 'gin';
126
+ detected.stack.orm = 'gorm';
127
+ detected.stack.database = 'postgresql';
128
+ detected.stack.validation = 'validator-v10';
129
+ detected.stack.testing = 'testing';
130
+ }
131
+ // 7. Java / Kotlin Stack Detection
132
+ else if ((0, file_system_1.fileExistsSync)(pomXmlPath) || (0, file_system_1.fileExistsSync)(buildGradlePath)) {
133
+ detected.stack.language = 'java';
134
+ detected.stack.framework = 'spring-boot';
135
+ detected.stack.orm = 'hibernate';
136
+ detected.stack.database = 'postgresql';
137
+ detected.stack.validation = 'jakarta-validation';
138
+ detected.stack.testing = 'junit';
139
+ }
140
+ // 8. Node.js / Frontend / Ionic / Angular / React / Vue Stack Detection
141
+ else if ((0, file_system_1.fileExistsSync)(packageJsonPath)) {
28
142
  try {
29
143
  const raw = (0, file_system_1.readFileSync)(packageJsonPath);
30
144
  const pkg = JSON.parse(raw);
31
145
  const allDeps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
32
146
  if (pkg.name)
33
147
  detected.projectName = pkg.name;
34
- // Language
35
- if (allDeps['typescript'] || (0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'tsconfig.json'))) {
148
+ // Language Detection (TypeScript if angular, tsconfig or typescript dep exists)
149
+ if (allDeps['typescript'] || (0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'tsconfig.json')) || (0, file_system_1.fileExistsSync)(angularJsonPath) || allDeps['@angular/core']) {
36
150
  detected.stack.language = 'typescript';
37
151
  }
38
152
  else {
39
153
  detected.stack.language = 'javascript';
40
154
  }
41
- // Framework
42
- if (allDeps['@nestjs/core'])
155
+ // Angular / Ionic Frontend Detection
156
+ if ((0, file_system_1.fileExistsSync)(angularJsonPath) || allDeps['@angular/core']) {
157
+ if (allDeps['@ionic/angular']) {
158
+ detected.stack.framework = 'ionic-angular';
159
+ }
160
+ else {
161
+ detected.stack.framework = 'angular';
162
+ }
163
+ detected.stack.orm = 'http-client-rxjs';
164
+ detected.stack.database = 'localstorage-indexeddb';
165
+ detected.stack.validation = 'angular-reactive-forms';
166
+ detected.stack.testing = 'jasmine-karma';
167
+ detected.architecture = 'modular';
168
+ detected.outputDir = './src/app';
169
+ }
170
+ // React Native Detection
171
+ else if (allDeps['react-native']) {
172
+ detected.stack.framework = 'react-native';
173
+ detected.stack.orm = 'async-storage';
174
+ detected.stack.database = 'sqlite-capacitor';
175
+ detected.stack.validation = 'zod';
176
+ detected.stack.testing = 'jest';
177
+ detected.architecture = 'modular';
178
+ }
179
+ // React / Next.js Frontend
180
+ else if (allDeps['react'] || allDeps['next']) {
181
+ detected.stack.framework = allDeps['next'] ? 'nextjs' : 'react';
182
+ detected.stack.orm = allDeps['prisma'] ? 'prisma' : 'tanstack-query';
183
+ detected.stack.database = 'postgresql';
184
+ detected.stack.validation = 'zod';
185
+ detected.stack.testing = 'vitest';
186
+ }
187
+ // Vue / Nuxt Frontend
188
+ else if (allDeps['vue'] || allDeps['nuxt']) {
189
+ detected.stack.framework = allDeps['nuxt'] ? 'nuxtjs' : 'vue';
190
+ detected.stack.orm = 'pinia-axios';
191
+ detected.stack.database = 'localstorage';
192
+ detected.stack.validation = 'vee-validate';
193
+ detected.stack.testing = 'vitest';
194
+ }
195
+ // Node.js Backend Frameworks (NestJS, Express, Fastify)
196
+ else if (allDeps['@nestjs/core']) {
43
197
  detected.stack.framework = 'nestjs';
44
- else if (allDeps['express'])
198
+ detected.stack.orm = allDeps['prisma'] ? 'prisma' : 'typeorm';
199
+ detected.stack.validation = 'zod';
200
+ detected.stack.testing = 'jest';
201
+ }
202
+ else if (allDeps['express']) {
45
203
  detected.stack.framework = 'express';
46
- else if (allDeps['fastify'])
47
- detected.stack.framework = 'fastify';
48
- else if (allDeps['next'])
49
- detected.stack.framework = 'nextjs';
50
- // ORM / Persistence
51
- if (allDeps['prisma'] || (0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'prisma', 'schema.prisma')))
52
- detected.stack.orm = 'prisma';
53
- else if (allDeps['typeorm'])
54
- detected.stack.orm = 'typeorm';
55
- else if (allDeps['sequelize'])
56
- detected.stack.orm = 'sequelize';
57
- else if (allDeps['mongoose'])
58
- detected.stack.orm = 'mongoose';
59
- // Database
60
- if (allDeps['pg'] || allDeps['postgres'] || allDeps['@prisma/client'])
61
- detected.stack.database = 'postgresql';
62
- else if (allDeps['mongodb'] || allDeps['mongoose'])
63
- detected.stack.database = 'mongodb';
64
- else if (allDeps['redis'] || allDeps['ioredis'])
65
- detected.stack.database = 'redis';
66
- // Validation
67
- if (allDeps['zod'])
204
+ detected.stack.orm = allDeps['prisma'] ? 'prisma' : 'sequelize';
68
205
  detected.stack.validation = 'zod';
69
- else if (allDeps['class-validator'])
70
- detected.stack.validation = 'class-validator';
71
- else if (allDeps['joi'])
72
- detected.stack.validation = 'joi';
73
- // Testing
74
- if (allDeps['jest'])
75
206
  detected.stack.testing = 'jest';
76
- else if (allDeps['vitest'])
77
- detected.stack.testing = 'vitest';
207
+ }
78
208
  }
79
209
  catch {
80
210
  // Ignore JSON parse errors
81
211
  }
82
212
  }
83
- // 2. Python Stack Detection
84
- else if ((0, file_system_1.fileExistsSync)(pyProjectPath) || (0, file_system_1.fileExistsSync)(reqTxtPath)) {
85
- detected.stack.language = 'python';
86
- detected.stack.framework = 'fastapi';
87
- detected.stack.orm = 'sqlalchemy';
88
- detected.stack.validation = 'pydantic';
89
- detected.stack.testing = 'pytest';
90
- }
91
- // 3. Java Stack Detection
92
- else if ((0, file_system_1.fileExistsSync)(pomXmlPath)) {
93
- detected.stack.language = 'java';
94
- detected.stack.framework = 'spring-boot';
95
- detected.stack.orm = 'hibernate';
96
- detected.stack.validation = 'jakarta-validation';
97
- detected.stack.testing = 'junit';
98
- }
99
- // 4. Architecture Style Heuristic Detection
213
+ // 9. Architecture Style Heuristic Detection
100
214
  if ((0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'src', 'domain')) && (0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'src', 'ports'))) {
101
215
  detected.architecture = 'hexagonal';
102
216
  }
@@ -106,7 +220,10 @@ function detectExistingStack(rootDir = process.cwd()) {
106
220
  else if ((0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'serverless.yml'))) {
107
221
  detected.architecture = 'serverless';
108
222
  }
109
- else if ((0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'src', 'modules'))) {
223
+ else if ((0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'app', 'Http', 'Controllers')) || (0, file_system_1.fileExistsSync)(artisanPath)) {
224
+ detected.architecture = 'monolith';
225
+ }
226
+ else if ((0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'src', 'modules')) || (0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'src', 'app'))) {
110
227
  detected.architecture = 'modular';
111
228
  }
112
229
  return detected;