create-claude-context 1.0.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.
Files changed (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +146 -0
  3. package/bin/create-claude-context.js +61 -0
  4. package/lib/detector.js +373 -0
  5. package/lib/index.js +170 -0
  6. package/lib/installer.js +362 -0
  7. package/lib/placeholder.js +208 -0
  8. package/lib/prompts.js +287 -0
  9. package/lib/spinner.js +60 -0
  10. package/lib/validate.js +147 -0
  11. package/package.json +59 -0
  12. package/templates/CLAUDE.md.template +235 -0
  13. package/templates/base/README.md +257 -0
  14. package/templates/base/RPI_WORKFLOW_PLAN.md +320 -0
  15. package/templates/base/agents/api-developer.md +76 -0
  16. package/templates/base/agents/context-engineer.md +525 -0
  17. package/templates/base/agents/core-architect.md +76 -0
  18. package/templates/base/agents/database-ops.md +76 -0
  19. package/templates/base/agents/deployment-ops.md +76 -0
  20. package/templates/base/agents/integration-hub.md +76 -0
  21. package/templates/base/analytics/README.md +114 -0
  22. package/templates/base/ci-templates/README.md +108 -0
  23. package/templates/base/ci-templates/github-actions/context-check.yml +144 -0
  24. package/templates/base/ci-templates/github-actions/validate-docs.yml +105 -0
  25. package/templates/base/commands/analytics.md +238 -0
  26. package/templates/base/commands/collab.md +194 -0
  27. package/templates/base/commands/help.md +450 -0
  28. package/templates/base/commands/rpi-implement.md +115 -0
  29. package/templates/base/commands/rpi-plan.md +93 -0
  30. package/templates/base/commands/rpi-research.md +88 -0
  31. package/templates/base/commands/validate-all.md +77 -0
  32. package/templates/base/commands/verify-docs-current.md +86 -0
  33. package/templates/base/config/base.json +57 -0
  34. package/templates/base/config/environments/development.json +13 -0
  35. package/templates/base/config/environments/production.json +17 -0
  36. package/templates/base/config/environments/staging.json +13 -0
  37. package/templates/base/config/local.json.example +21 -0
  38. package/templates/base/context/ARCHITECTURE_SNAPSHOT.md +156 -0
  39. package/templates/base/context/CODE_TO_WORKFLOW_MAP.md +94 -0
  40. package/templates/base/context/KNOWN_GOTCHAS.md +195 -0
  41. package/templates/base/context/WORKFLOW_INDEX.md +129 -0
  42. package/templates/base/context/workflows/WORKFLOW_TEMPLATE.md +294 -0
  43. package/templates/base/indexes/agents/CAPABILITY_MATRIX.md +255 -0
  44. package/templates/base/indexes/agents/CATEGORY_INDEX.md +44 -0
  45. package/templates/base/indexes/code/CATEGORY_INDEX.md +38 -0
  46. package/templates/base/indexes/routing/CATEGORY_INDEX.md +39 -0
  47. package/templates/base/indexes/search/CATEGORY_INDEX.md +39 -0
  48. package/templates/base/indexes/workflows/CATEGORY_INDEX.md +38 -0
  49. package/templates/base/knowledge/README.md +98 -0
  50. package/templates/base/knowledge/sessions/README.md +88 -0
  51. package/templates/base/knowledge/sessions/TEMPLATE.md +150 -0
  52. package/templates/base/knowledge/shared/decisions/0001-adopt-context-engineering.md +144 -0
  53. package/templates/base/knowledge/shared/decisions/README.md +49 -0
  54. package/templates/base/knowledge/shared/decisions/TEMPLATE.md +123 -0
  55. package/templates/base/knowledge/shared/patterns/README.md +62 -0
  56. package/templates/base/knowledge/shared/patterns/TEMPLATE.md +120 -0
  57. package/templates/base/plans/PLAN_TEMPLATE.md +250 -0
  58. package/templates/base/plans/active/.gitkeep +0 -0
  59. package/templates/base/plans/completed/.gitkeep +0 -0
  60. package/templates/base/research/RESEARCH_TEMPLATE.md +153 -0
  61. package/templates/base/research/active/.gitkeep +0 -0
  62. package/templates/base/research/completed/.gitkeep +0 -0
  63. package/templates/base/schemas/agent.schema.json +141 -0
  64. package/templates/base/schemas/command.schema.json +134 -0
  65. package/templates/base/schemas/manifest.schema.json +117 -0
  66. package/templates/base/schemas/plan.schema.json +136 -0
  67. package/templates/base/schemas/research.schema.json +115 -0
  68. package/templates/base/schemas/settings.schema.json +244 -0
  69. package/templates/base/schemas/workflow.schema.json +126 -0
  70. package/templates/base/settings.json +57 -0
  71. package/templates/base/standards/COMPATIBILITY.md +219 -0
  72. package/templates/base/standards/EXTENSION_GUIDELINES.md +280 -0
  73. package/templates/base/standards/QUALITY_CHECKLIST.md +211 -0
  74. package/templates/base/standards/README.md +66 -0
  75. package/templates/base/team/README.md +168 -0
  76. package/templates/base/team/config.json +79 -0
  77. package/templates/base/team/roles.json +145 -0
  78. package/templates/base/tools/bin/claude-context.js +151 -0
  79. package/templates/base/tools/lib/config-loader.js +363 -0
  80. package/templates/base/tools/lib/detector.js +350 -0
  81. package/templates/base/tools/lib/diagnose.js +206 -0
  82. package/templates/base/tools/lib/errors.js +199 -0
  83. package/templates/base/tools/lib/index.js +24 -0
  84. package/templates/base/tools/lib/init.js +192 -0
  85. package/templates/base/tools/lib/logger.js +230 -0
  86. package/templates/base/tools/lib/placeholder.js +201 -0
  87. package/templates/base/tools/lib/validate.js +521 -0
  88. package/templates/base/tools/package.json +49 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 SireJeff
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,146 @@
1
+ # create-claude-context
2
+
3
+ Set up Claude Context Engineering for any project with a single command.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ npx create-claude-context
9
+ ```
10
+
11
+ Or with npm init:
12
+
13
+ ```bash
14
+ npm init claude-context
15
+ ```
16
+
17
+ ## What It Does
18
+
19
+ This CLI tool sets up a complete context engineering system for your codebase:
20
+
21
+ 1. **Creates `.claude/` directory** - Context engineering documentation
22
+ 2. **Creates `CLAUDE.md`** - Entry point for Claude Code
23
+ 3. **Detects tech stack** - Auto-configures for your project
24
+ 4. **Installs plugin** - Adds ongoing commands (optional)
25
+
26
+ ## Options
27
+
28
+ ```bash
29
+ npx create-claude-context [project-name] [options]
30
+
31
+ Options:
32
+ -y, --yes Skip prompts, use defaults
33
+ --no-plugin Skip Claude Code plugin installation
34
+ -t, --template Use a tech stack preset
35
+ --no-git Skip git initialization
36
+ --dry-run Show what would be done
37
+ -v, --verbose Show detailed output
38
+ -V, --version Output version number
39
+ -h, --help Display help
40
+ ```
41
+
42
+ ## Tech Stack Presets
43
+
44
+ ```bash
45
+ # Python
46
+ npx create-claude-context -t python-fastapi
47
+ npx create-claude-context -t python-django
48
+
49
+ # JavaScript/TypeScript
50
+ npx create-claude-context -t node-express
51
+ npx create-claude-context -t node-nestjs
52
+ npx create-claude-context -t typescript-nextjs
53
+ npx create-claude-context -t typescript-remix
54
+
55
+ # Other Languages
56
+ npx create-claude-context -t go-gin
57
+ npx create-claude-context -t rust-actix
58
+ npx create-claude-context -t ruby-rails
59
+ npx create-claude-context -t java-spring
60
+ npx create-claude-context -t csharp-dotnet
61
+ npx create-claude-context -t php-laravel
62
+ ```
63
+
64
+ ## Features
65
+
66
+ After setup, you get:
67
+
68
+ ### RPI Workflow
69
+ - `/rpi-research` - Systematic codebase exploration
70
+ - `/rpi-plan` - Implementation blueprints with file:line precision
71
+ - `/rpi-implement` - Atomic changes with continuous testing
72
+
73
+ ### Specialized Agents
74
+ - `@context-engineer` - Setup and maintenance
75
+ - `@core-architect` - System design
76
+ - `@database-ops` - Database operations
77
+ - `@api-developer` - API development
78
+ - `@integration-hub` - External services
79
+ - `@deployment-ops` - CI/CD and infrastructure
80
+
81
+ ### Documentation System
82
+ - 3-level index hierarchy
83
+ - File:line references
84
+ - Self-maintaining documentation
85
+ - Validation commands
86
+
87
+ ## Directory Structure
88
+
89
+ ```
90
+ your-project/
91
+ ├── CLAUDE.md # Entry point for Claude
92
+ └── .claude/
93
+ ├── agents/ # Specialized agents
94
+ ├── commands/ # Slash commands
95
+ ├── context/ # Pre-computed knowledge
96
+ │ ├── workflows/ # Workflow documentation
97
+ │ └── WORKFLOW_INDEX.md # Master index
98
+ ├── indexes/ # Navigation hierarchy
99
+ ├── plans/ # Implementation plans
100
+ ├── research/ # Research documents
101
+ └── schemas/ # JSON validation
102
+ ```
103
+
104
+ ## Requirements
105
+
106
+ - Node.js 18+
107
+ - Claude Code CLI
108
+
109
+ ## Development
110
+
111
+ ```bash
112
+ # Clone the repo
113
+ git clone https://github.com/SireJeff/claude-context-engineering-template.git
114
+ cd claude-context-engineering-template/packages/create-claude-context
115
+
116
+ # Install dependencies
117
+ npm install
118
+
119
+ # Run tests
120
+ npm test
121
+
122
+ # Run tests with coverage
123
+ npm run test:coverage
124
+
125
+ # Run tests in watch mode
126
+ npm run test:watch
127
+ ```
128
+
129
+ ## Contributing
130
+
131
+ 1. Fork the repository
132
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
133
+ 3. Run tests (`npm test`)
134
+ 4. Commit your changes (`git commit -m 'Add amazing feature'`)
135
+ 5. Push to the branch (`git push origin feature/amazing-feature`)
136
+ 6. Open a Pull Request
137
+
138
+ ## License
139
+
140
+ MIT
141
+
142
+ ## Links
143
+
144
+ - [GitHub](https://github.com/SireJeff/claude-context-engineering-template)
145
+ - [Documentation](https://github.com/SireJeff/claude-context-engineering-template#readme)
146
+ - [Issues](https://github.com/SireJeff/claude-context-engineering-template/issues)
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * create-claude-context CLI
5
+ *
6
+ * Set up Claude Context Engineering for any project with a single command.
7
+ *
8
+ * Usage:
9
+ * npx create-claude-context
10
+ * npx create-claude-context my-project
11
+ * npx create-claude-context --yes
12
+ */
13
+
14
+ const { program } = require('commander');
15
+ const chalk = require('chalk');
16
+ const { run } = require('../lib');
17
+ const packageJson = require('../package.json');
18
+
19
+ // ASCII Banner
20
+ const banner = `
21
+ ${chalk.cyan('╔═══════════════════════════════════════════════════════════╗')}
22
+ ${chalk.cyan('║')} ${chalk.bold.white('Claude Context Engineering')} ${chalk.cyan('║')}
23
+ ${chalk.cyan('║')} ${chalk.gray('Optimize AI-assisted development with pre-computed')} ${chalk.cyan('║')}
24
+ ${chalk.cyan('║')} ${chalk.gray('system knowledge and structured documentation.')} ${chalk.cyan('║')}
25
+ ${chalk.cyan('╚═══════════════════════════════════════════════════════════╝')}
26
+ `;
27
+
28
+ program
29
+ .name('create-claude-context')
30
+ .description('Set up Claude Context Engineering for your project')
31
+ .version(packageJson.version)
32
+ .argument('[project-name]', 'Name of the project (defaults to current directory name)')
33
+ .option('-y, --yes', 'Skip prompts and use defaults')
34
+ .option('--no-plugin', 'Skip Claude Code plugin installation')
35
+ .option('-t, --template <preset>', 'Use a tech stack preset (python-fastapi, node-express, etc.)')
36
+ .option('--no-git', 'Skip git initialization')
37
+ .option('--dry-run', 'Show what would be done without making changes')
38
+ .option('-v, --verbose', 'Show detailed output')
39
+ .action(async (projectName, options) => {
40
+ console.log(banner);
41
+
42
+ try {
43
+ await run({
44
+ projectName,
45
+ skipPrompts: options.yes,
46
+ installPlugin: options.plugin !== false,
47
+ template: options.template,
48
+ initGit: options.git !== false,
49
+ dryRun: options.dryRun,
50
+ verbose: options.verbose
51
+ });
52
+ } catch (error) {
53
+ console.error(chalk.red('\n✖ Error:'), error.message);
54
+ if (options.verbose) {
55
+ console.error(chalk.gray(error.stack));
56
+ }
57
+ process.exit(1);
58
+ }
59
+ });
60
+
61
+ program.parse();
@@ -0,0 +1,373 @@
1
+ /**
2
+ * Claude Context Engineering - Tech Stack Detector
3
+ *
4
+ * Auto-detects technology stack from project files.
5
+ */
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+ const { glob } = require('glob');
10
+
11
+ /**
12
+ * Tech stack detection signatures
13
+ */
14
+ const TECH_SIGNATURES = {
15
+ // Languages
16
+ languages: {
17
+ python: {
18
+ files: ['requirements.txt', 'pyproject.toml', 'setup.py', 'Pipfile', 'poetry.lock'],
19
+ extensions: ['.py'],
20
+ },
21
+ javascript: {
22
+ files: ['package.json', 'yarn.lock', 'pnpm-lock.yaml'],
23
+ extensions: ['.js', '.mjs', '.cjs'],
24
+ },
25
+ typescript: {
26
+ files: ['tsconfig.json'],
27
+ extensions: ['.ts', '.tsx'],
28
+ },
29
+ go: {
30
+ files: ['go.mod', 'go.sum'],
31
+ extensions: ['.go'],
32
+ },
33
+ rust: {
34
+ files: ['Cargo.toml', 'Cargo.lock'],
35
+ extensions: ['.rs'],
36
+ },
37
+ java: {
38
+ files: ['pom.xml', 'build.gradle', 'build.gradle.kts'],
39
+ extensions: ['.java'],
40
+ },
41
+ csharp: {
42
+ files: ['*.csproj', '*.sln'],
43
+ extensions: ['.cs'],
44
+ },
45
+ ruby: {
46
+ files: ['Gemfile', 'Gemfile.lock'],
47
+ extensions: ['.rb'],
48
+ },
49
+ php: {
50
+ files: ['composer.json', 'composer.lock'],
51
+ extensions: ['.php'],
52
+ },
53
+ },
54
+
55
+ // Frameworks
56
+ frameworks: {
57
+ // Python
58
+ fastapi: {
59
+ language: 'python',
60
+ patterns: ['fastapi', 'FastAPI', '@router', 'APIRouter'],
61
+ files: [],
62
+ },
63
+ django: {
64
+ language: 'python',
65
+ patterns: ['django.conf', 'INSTALLED_APPS', 'from django'],
66
+ files: ['manage.py'],
67
+ },
68
+ flask: {
69
+ language: 'python',
70
+ patterns: ['Flask(__name__)', '@app.route', 'from flask'],
71
+ files: [],
72
+ },
73
+
74
+ // JavaScript/TypeScript
75
+ react: {
76
+ language: 'javascript',
77
+ patterns: ['react', 'React', 'useState', 'useEffect'],
78
+ packageDeps: ['react', 'react-dom'],
79
+ },
80
+ nextjs: {
81
+ language: 'javascript',
82
+ patterns: ['next/'],
83
+ files: ['next.config.js', 'next.config.mjs'],
84
+ packageDeps: ['next'],
85
+ },
86
+ express: {
87
+ language: 'javascript',
88
+ patterns: ['express()', 'app.use', 'app.get', 'router.'],
89
+ packageDeps: ['express'],
90
+ },
91
+ nestjs: {
92
+ language: 'typescript',
93
+ patterns: ['@nestjs/', '@Controller', '@Injectable'],
94
+ packageDeps: ['@nestjs/core'],
95
+ },
96
+ vue: {
97
+ language: 'javascript',
98
+ patterns: ['<template>', 'Vue.'],
99
+ packageDeps: ['vue'],
100
+ },
101
+
102
+ // Go
103
+ gin: {
104
+ language: 'go',
105
+ patterns: ['gin.', 'gin-gonic'],
106
+ files: [],
107
+ },
108
+ echo: {
109
+ language: 'go',
110
+ patterns: ['echo.', 'labstack/echo'],
111
+ files: [],
112
+ },
113
+
114
+ // Ruby
115
+ rails: {
116
+ language: 'ruby',
117
+ patterns: ['Rails.application', 'ActionController', 'ActiveRecord'],
118
+ files: ['config/routes.rb'],
119
+ },
120
+
121
+ // Rust
122
+ actix: {
123
+ language: 'rust',
124
+ patterns: ['actix_web', 'actix-web'],
125
+ files: [],
126
+ },
127
+ axum: {
128
+ language: 'rust',
129
+ patterns: ['axum::'],
130
+ files: [],
131
+ },
132
+ },
133
+
134
+ // Databases
135
+ databases: {
136
+ postgresql: {
137
+ patterns: ['postgresql', 'postgres', 'psycopg', 'pg'],
138
+ envVars: ['DATABASE_URL', 'POSTGRES_'],
139
+ },
140
+ mysql: {
141
+ patterns: ['mysql', 'mariadb'],
142
+ envVars: ['MYSQL_'],
143
+ },
144
+ mongodb: {
145
+ patterns: ['mongodb', 'mongoose', 'pymongo'],
146
+ envVars: ['MONGO_'],
147
+ },
148
+ redis: {
149
+ patterns: ['redis', 'ioredis'],
150
+ envVars: ['REDIS_'],
151
+ },
152
+ sqlite: {
153
+ patterns: ['sqlite', 'sqlite3'],
154
+ files: ['*.db', '*.sqlite'],
155
+ },
156
+ },
157
+ };
158
+
159
+ /**
160
+ * Detect technology stack
161
+ */
162
+ async function detectTechStack(projectRoot, options = {}) {
163
+ const { hint = null } = options;
164
+
165
+ const result = {
166
+ stack: '',
167
+ summary: '',
168
+ languages: [],
169
+ frameworks: [],
170
+ databases: [],
171
+ projectName: path.basename(projectRoot),
172
+ fileCount: 0,
173
+ loc: 0,
174
+ };
175
+
176
+ // If hint provided, use it
177
+ if (hint) {
178
+ result.stack = hint;
179
+ result.summary = hint;
180
+ return result;
181
+ }
182
+
183
+ // Detect languages
184
+ for (const [lang, signature] of Object.entries(TECH_SIGNATURES.languages)) {
185
+ // Check for signature files
186
+ for (const sigFile of signature.files) {
187
+ if (fs.existsSync(path.join(projectRoot, sigFile))) {
188
+ if (!result.languages.includes(lang)) {
189
+ result.languages.push(lang);
190
+ }
191
+ break;
192
+ }
193
+ }
194
+
195
+ // Check for file extensions
196
+ if (signature.extensions) {
197
+ for (const ext of signature.extensions) {
198
+ try {
199
+ const files = await glob(`**/*${ext}`, {
200
+ cwd: projectRoot,
201
+ ignore: ['node_modules/**', 'vendor/**', '.git/**', 'dist/**', 'build/**'],
202
+ nodir: true,
203
+ });
204
+
205
+ if (files.length > 0) {
206
+ if (!result.languages.includes(lang)) {
207
+ result.languages.push(lang);
208
+ }
209
+ result.fileCount += files.length;
210
+ break;
211
+ }
212
+ } catch {
213
+ // Ignore glob errors
214
+ }
215
+ }
216
+ }
217
+ }
218
+
219
+ // Detect frameworks
220
+ for (const [framework, signature] of Object.entries(TECH_SIGNATURES.frameworks)) {
221
+ // Check for package.json dependencies
222
+ if (signature.packageDeps) {
223
+ const pkgPath = path.join(projectRoot, 'package.json');
224
+ if (fs.existsSync(pkgPath)) {
225
+ try {
226
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
227
+ const allDeps = {
228
+ ...pkg.dependencies,
229
+ ...pkg.devDependencies,
230
+ };
231
+
232
+ for (const dep of signature.packageDeps) {
233
+ if (allDeps[dep]) {
234
+ if (!result.frameworks.includes(framework)) {
235
+ result.frameworks.push(framework);
236
+ }
237
+ break;
238
+ }
239
+ }
240
+ } catch {
241
+ // Ignore JSON parse errors
242
+ }
243
+ }
244
+ }
245
+
246
+ // Check for signature files
247
+ if (signature.files) {
248
+ for (const sigFile of signature.files) {
249
+ if (fs.existsSync(path.join(projectRoot, sigFile))) {
250
+ if (!result.frameworks.includes(framework)) {
251
+ result.frameworks.push(framework);
252
+ }
253
+ break;
254
+ }
255
+ }
256
+ }
257
+
258
+ // Check for patterns in source files (sample)
259
+ if (signature.patterns && result.languages.includes(signature.language)) {
260
+ // Sample a few source files
261
+ const ext = TECH_SIGNATURES.languages[signature.language]?.extensions?.[0];
262
+ if (ext) {
263
+ try {
264
+ const sampleFiles = await glob(`**/*${ext}`, {
265
+ cwd: projectRoot,
266
+ ignore: ['node_modules/**', 'vendor/**', '.git/**'],
267
+ nodir: true,
268
+ });
269
+
270
+ // Check first 5 files
271
+ for (const file of sampleFiles.slice(0, 5)) {
272
+ try {
273
+ const content = fs.readFileSync(path.join(projectRoot, file), 'utf8');
274
+
275
+ for (const pattern of signature.patterns) {
276
+ if (content.includes(pattern)) {
277
+ if (!result.frameworks.includes(framework)) {
278
+ result.frameworks.push(framework);
279
+ }
280
+ break;
281
+ }
282
+ }
283
+ } catch {
284
+ // Ignore file read errors
285
+ }
286
+ }
287
+ } catch {
288
+ // Ignore glob errors
289
+ }
290
+ }
291
+ }
292
+ }
293
+
294
+ // Detect databases
295
+ for (const [db, signature] of Object.entries(TECH_SIGNATURES.databases)) {
296
+ // Check environment files
297
+ const envFiles = ['.env', '.env.example', '.env.local'];
298
+ for (const envFile of envFiles) {
299
+ const envPath = path.join(projectRoot, envFile);
300
+ if (fs.existsSync(envPath)) {
301
+ try {
302
+ const content = fs.readFileSync(envPath, 'utf8');
303
+
304
+ if (signature.envVars) {
305
+ for (const envVar of signature.envVars) {
306
+ if (content.includes(envVar)) {
307
+ if (!result.databases.includes(db)) {
308
+ result.databases.push(db);
309
+ }
310
+ break;
311
+ }
312
+ }
313
+ }
314
+ } catch {
315
+ // Ignore read errors
316
+ }
317
+ }
318
+ }
319
+
320
+ // Check for patterns in config files
321
+ if (signature.patterns) {
322
+ const configFiles = ['package.json', 'requirements.txt', 'pyproject.toml', 'Cargo.toml'];
323
+ for (const configFile of configFiles) {
324
+ const configPath = path.join(projectRoot, configFile);
325
+ if (fs.existsSync(configPath)) {
326
+ try {
327
+ const content = fs.readFileSync(configPath, 'utf8').toLowerCase();
328
+
329
+ for (const pattern of signature.patterns) {
330
+ if (content.includes(pattern.toLowerCase())) {
331
+ if (!result.databases.includes(db)) {
332
+ result.databases.push(db);
333
+ }
334
+ break;
335
+ }
336
+ }
337
+ } catch {
338
+ // Ignore read errors
339
+ }
340
+ }
341
+ }
342
+ }
343
+ }
344
+
345
+ // Build stack string
346
+ const stackParts = [];
347
+ if (result.languages.length > 0) {
348
+ stackParts.push(result.languages.map(l => capitalize(l)).join(', '));
349
+ }
350
+ if (result.frameworks.length > 0) {
351
+ stackParts.push(result.frameworks.map(f => capitalize(f)).join(', '));
352
+ }
353
+ if (result.databases.length > 0) {
354
+ stackParts.push(result.databases.map(d => capitalize(d)).join(', '));
355
+ }
356
+
357
+ result.stack = stackParts.join(' + ') || 'Unknown';
358
+ result.summary = result.stack;
359
+
360
+ return result;
361
+ }
362
+
363
+ /**
364
+ * Capitalize first letter
365
+ */
366
+ function capitalize(str) {
367
+ return str.charAt(0).toUpperCase() + str.slice(1);
368
+ }
369
+
370
+ module.exports = {
371
+ detectTechStack,
372
+ TECH_SIGNATURES,
373
+ };