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.
- package/LICENSE +21 -0
- package/README.md +146 -0
- package/bin/create-claude-context.js +61 -0
- package/lib/detector.js +373 -0
- package/lib/index.js +170 -0
- package/lib/installer.js +362 -0
- package/lib/placeholder.js +208 -0
- package/lib/prompts.js +287 -0
- package/lib/spinner.js +60 -0
- package/lib/validate.js +147 -0
- package/package.json +59 -0
- package/templates/CLAUDE.md.template +235 -0
- package/templates/base/README.md +257 -0
- package/templates/base/RPI_WORKFLOW_PLAN.md +320 -0
- package/templates/base/agents/api-developer.md +76 -0
- package/templates/base/agents/context-engineer.md +525 -0
- package/templates/base/agents/core-architect.md +76 -0
- package/templates/base/agents/database-ops.md +76 -0
- package/templates/base/agents/deployment-ops.md +76 -0
- package/templates/base/agents/integration-hub.md +76 -0
- package/templates/base/analytics/README.md +114 -0
- package/templates/base/ci-templates/README.md +108 -0
- package/templates/base/ci-templates/github-actions/context-check.yml +144 -0
- package/templates/base/ci-templates/github-actions/validate-docs.yml +105 -0
- package/templates/base/commands/analytics.md +238 -0
- package/templates/base/commands/collab.md +194 -0
- package/templates/base/commands/help.md +450 -0
- package/templates/base/commands/rpi-implement.md +115 -0
- package/templates/base/commands/rpi-plan.md +93 -0
- package/templates/base/commands/rpi-research.md +88 -0
- package/templates/base/commands/validate-all.md +77 -0
- package/templates/base/commands/verify-docs-current.md +86 -0
- package/templates/base/config/base.json +57 -0
- package/templates/base/config/environments/development.json +13 -0
- package/templates/base/config/environments/production.json +17 -0
- package/templates/base/config/environments/staging.json +13 -0
- package/templates/base/config/local.json.example +21 -0
- package/templates/base/context/ARCHITECTURE_SNAPSHOT.md +156 -0
- package/templates/base/context/CODE_TO_WORKFLOW_MAP.md +94 -0
- package/templates/base/context/KNOWN_GOTCHAS.md +195 -0
- package/templates/base/context/WORKFLOW_INDEX.md +129 -0
- package/templates/base/context/workflows/WORKFLOW_TEMPLATE.md +294 -0
- package/templates/base/indexes/agents/CAPABILITY_MATRIX.md +255 -0
- package/templates/base/indexes/agents/CATEGORY_INDEX.md +44 -0
- package/templates/base/indexes/code/CATEGORY_INDEX.md +38 -0
- package/templates/base/indexes/routing/CATEGORY_INDEX.md +39 -0
- package/templates/base/indexes/search/CATEGORY_INDEX.md +39 -0
- package/templates/base/indexes/workflows/CATEGORY_INDEX.md +38 -0
- package/templates/base/knowledge/README.md +98 -0
- package/templates/base/knowledge/sessions/README.md +88 -0
- package/templates/base/knowledge/sessions/TEMPLATE.md +150 -0
- package/templates/base/knowledge/shared/decisions/0001-adopt-context-engineering.md +144 -0
- package/templates/base/knowledge/shared/decisions/README.md +49 -0
- package/templates/base/knowledge/shared/decisions/TEMPLATE.md +123 -0
- package/templates/base/knowledge/shared/patterns/README.md +62 -0
- package/templates/base/knowledge/shared/patterns/TEMPLATE.md +120 -0
- package/templates/base/plans/PLAN_TEMPLATE.md +250 -0
- package/templates/base/plans/active/.gitkeep +0 -0
- package/templates/base/plans/completed/.gitkeep +0 -0
- package/templates/base/research/RESEARCH_TEMPLATE.md +153 -0
- package/templates/base/research/active/.gitkeep +0 -0
- package/templates/base/research/completed/.gitkeep +0 -0
- package/templates/base/schemas/agent.schema.json +141 -0
- package/templates/base/schemas/command.schema.json +134 -0
- package/templates/base/schemas/manifest.schema.json +117 -0
- package/templates/base/schemas/plan.schema.json +136 -0
- package/templates/base/schemas/research.schema.json +115 -0
- package/templates/base/schemas/settings.schema.json +244 -0
- package/templates/base/schemas/workflow.schema.json +126 -0
- package/templates/base/settings.json +57 -0
- package/templates/base/standards/COMPATIBILITY.md +219 -0
- package/templates/base/standards/EXTENSION_GUIDELINES.md +280 -0
- package/templates/base/standards/QUALITY_CHECKLIST.md +211 -0
- package/templates/base/standards/README.md +66 -0
- package/templates/base/team/README.md +168 -0
- package/templates/base/team/config.json +79 -0
- package/templates/base/team/roles.json +145 -0
- package/templates/base/tools/bin/claude-context.js +151 -0
- package/templates/base/tools/lib/config-loader.js +363 -0
- package/templates/base/tools/lib/detector.js +350 -0
- package/templates/base/tools/lib/diagnose.js +206 -0
- package/templates/base/tools/lib/errors.js +199 -0
- package/templates/base/tools/lib/index.js +24 -0
- package/templates/base/tools/lib/init.js +192 -0
- package/templates/base/tools/lib/logger.js +230 -0
- package/templates/base/tools/lib/placeholder.js +201 -0
- package/templates/base/tools/lib/validate.js +521 -0
- 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();
|
package/lib/detector.js
ADDED
|
@@ -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
|
+
};
|