codedev-mcp 3.2.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/CHANGELOG.md +90 -0
- package/LICENSE +21 -0
- package/README.md +760 -0
- package/dist/analyzers/api-contract.d.ts +46 -0
- package/dist/analyzers/api-contract.d.ts.map +1 -0
- package/dist/analyzers/api-contract.js +319 -0
- package/dist/analyzers/api-contract.js.map +1 -0
- package/dist/analyzers/architecture.d.ts +37 -0
- package/dist/analyzers/architecture.d.ts.map +1 -0
- package/dist/analyzers/architecture.js +149 -0
- package/dist/analyzers/architecture.js.map +1 -0
- package/dist/analyzers/branch-compare.d.ts +46 -0
- package/dist/analyzers/branch-compare.d.ts.map +1 -0
- package/dist/analyzers/branch-compare.js +128 -0
- package/dist/analyzers/branch-compare.js.map +1 -0
- package/dist/analyzers/cicd.d.ts +42 -0
- package/dist/analyzers/cicd.d.ts.map +1 -0
- package/dist/analyzers/cicd.js +237 -0
- package/dist/analyzers/cicd.js.map +1 -0
- package/dist/analyzers/codebase.d.ts +64 -0
- package/dist/analyzers/codebase.d.ts.map +1 -0
- package/dist/analyzers/codebase.js +354 -0
- package/dist/analyzers/codebase.js.map +1 -0
- package/dist/analyzers/complexity-heatmap.d.ts +50 -0
- package/dist/analyzers/complexity-heatmap.d.ts.map +1 -0
- package/dist/analyzers/complexity-heatmap.js +156 -0
- package/dist/analyzers/complexity-heatmap.js.map +1 -0
- package/dist/analyzers/context-pack.d.ts +43 -0
- package/dist/analyzers/context-pack.d.ts.map +1 -0
- package/dist/analyzers/context-pack.js +232 -0
- package/dist/analyzers/context-pack.js.map +1 -0
- package/dist/analyzers/coverage.d.ts +70 -0
- package/dist/analyzers/coverage.d.ts.map +1 -0
- package/dist/analyzers/coverage.js +313 -0
- package/dist/analyzers/coverage.js.map +1 -0
- package/dist/analyzers/db-schema.d.ts +55 -0
- package/dist/analyzers/db-schema.d.ts.map +1 -0
- package/dist/analyzers/db-schema.js +237 -0
- package/dist/analyzers/db-schema.js.map +1 -0
- package/dist/analyzers/dead-code.d.ts +34 -0
- package/dist/analyzers/dead-code.d.ts.map +1 -0
- package/dist/analyzers/dead-code.js +131 -0
- package/dist/analyzers/dead-code.js.map +1 -0
- package/dist/analyzers/dep-vuln.d.ts +36 -0
- package/dist/analyzers/dep-vuln.d.ts.map +1 -0
- package/dist/analyzers/dep-vuln.js +342 -0
- package/dist/analyzers/dep-vuln.js.map +1 -0
- package/dist/analyzers/docs.d.ts +47 -0
- package/dist/analyzers/docs.d.ts.map +1 -0
- package/dist/analyzers/docs.js +473 -0
- package/dist/analyzers/docs.js.map +1 -0
- package/dist/analyzers/git.d.ts +115 -0
- package/dist/analyzers/git.d.ts.map +1 -0
- package/dist/analyzers/git.js +214 -0
- package/dist/analyzers/git.js.map +1 -0
- package/dist/analyzers/iac.d.ts +39 -0
- package/dist/analyzers/iac.d.ts.map +1 -0
- package/dist/analyzers/iac.js +233 -0
- package/dist/analyzers/iac.js.map +1 -0
- package/dist/analyzers/impact.d.ts +51 -0
- package/dist/analyzers/impact.d.ts.map +1 -0
- package/dist/analyzers/impact.js +235 -0
- package/dist/analyzers/impact.js.map +1 -0
- package/dist/analyzers/monorepo.d.ts +36 -0
- package/dist/analyzers/monorepo.d.ts.map +1 -0
- package/dist/analyzers/monorepo.js +233 -0
- package/dist/analyzers/monorepo.js.map +1 -0
- package/dist/analyzers/notebook.d.ts +53 -0
- package/dist/analyzers/notebook.d.ts.map +1 -0
- package/dist/analyzers/notebook.js +149 -0
- package/dist/analyzers/notebook.js.map +1 -0
- package/dist/analyzers/perf-profile.d.ts +39 -0
- package/dist/analyzers/perf-profile.d.ts.map +1 -0
- package/dist/analyzers/perf-profile.js +222 -0
- package/dist/analyzers/perf-profile.js.map +1 -0
- package/dist/analyzers/scaffold.d.ts +46 -0
- package/dist/analyzers/scaffold.d.ts.map +1 -0
- package/dist/analyzers/scaffold.js +313 -0
- package/dist/analyzers/scaffold.js.map +1 -0
- package/dist/analyzers/security.d.ts +42 -0
- package/dist/analyzers/security.d.ts.map +1 -0
- package/dist/analyzers/security.js +281 -0
- package/dist/analyzers/security.js.map +1 -0
- package/dist/analyzers/symbols.d.ts +49 -0
- package/dist/analyzers/symbols.d.ts.map +1 -0
- package/dist/analyzers/symbols.js +212 -0
- package/dist/analyzers/symbols.js.map +1 -0
- package/dist/analyzers/tree-sitter.d.ts +71 -0
- package/dist/analyzers/tree-sitter.d.ts.map +1 -0
- package/dist/analyzers/tree-sitter.js +333 -0
- package/dist/analyzers/tree-sitter.js.map +1 -0
- package/dist/analyzers/type-flow.d.ts +39 -0
- package/dist/analyzers/type-flow.d.ts.map +1 -0
- package/dist/analyzers/type-flow.js +75 -0
- package/dist/analyzers/type-flow.js.map +1 -0
- package/dist/cache/memory-cache.d.ts +130 -0
- package/dist/cache/memory-cache.d.ts.map +1 -0
- package/dist/cache/memory-cache.js +273 -0
- package/dist/cache/memory-cache.js.map +1 -0
- package/dist/config.d.ts +32 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +57 -0
- package/dist/config.js.map +1 -0
- package/dist/constants/instructions.d.ts +2 -0
- package/dist/constants/instructions.d.ts.map +1 -0
- package/dist/constants/instructions.js +82 -0
- package/dist/constants/instructions.js.map +1 -0
- package/dist/db/connection.d.ts +12 -0
- package/dist/db/connection.d.ts.map +1 -0
- package/dist/db/connection.js +34 -0
- package/dist/db/connection.js.map +1 -0
- package/dist/db/json-store.d.ts +111 -0
- package/dist/db/json-store.d.ts.map +1 -0
- package/dist/db/json-store.js +201 -0
- package/dist/db/json-store.js.map +1 -0
- package/dist/db/sqlite-store.d.ts +153 -0
- package/dist/db/sqlite-store.d.ts.map +1 -0
- package/dist/db/sqlite-store.js +388 -0
- package/dist/db/sqlite-store.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +116 -0
- package/dist/index.js.map +1 -0
- package/dist/resources/health.d.ts +35 -0
- package/dist/resources/health.d.ts.map +1 -0
- package/dist/resources/health.js +81 -0
- package/dist/resources/health.js.map +1 -0
- package/dist/schemas/output-schemas.d.ts +517 -0
- package/dist/schemas/output-schemas.d.ts.map +1 -0
- package/dist/schemas/output-schemas.js +296 -0
- package/dist/schemas/output-schemas.js.map +1 -0
- package/dist/search/fast-search.d.ts +90 -0
- package/dist/search/fast-search.d.ts.map +1 -0
- package/dist/search/fast-search.js +387 -0
- package/dist/search/fast-search.js.map +1 -0
- package/dist/search/semantic.d.ts +26 -0
- package/dist/search/semantic.d.ts.map +1 -0
- package/dist/search/semantic.js +458 -0
- package/dist/search/semantic.js.map +1 -0
- package/dist/tools/analysis.d.ts +7 -0
- package/dist/tools/analysis.d.ts.map +1 -0
- package/dist/tools/analysis.js +491 -0
- package/dist/tools/analysis.js.map +1 -0
- package/dist/tools/architecture.d.ts +7 -0
- package/dist/tools/architecture.d.ts.map +1 -0
- package/dist/tools/architecture.js +176 -0
- package/dist/tools/architecture.js.map +1 -0
- package/dist/tools/devops.d.ts +7 -0
- package/dist/tools/devops.d.ts.map +1 -0
- package/dist/tools/devops.js +179 -0
- package/dist/tools/devops.js.map +1 -0
- package/dist/tools/docs.d.ts +7 -0
- package/dist/tools/docs.d.ts.map +1 -0
- package/dist/tools/docs.js +102 -0
- package/dist/tools/docs.js.map +1 -0
- package/dist/tools/git.d.ts +7 -0
- package/dist/tools/git.d.ts.map +1 -0
- package/dist/tools/git.js +475 -0
- package/dist/tools/git.js.map +1 -0
- package/dist/tools/nav.d.ts +7 -0
- package/dist/tools/nav.d.ts.map +1 -0
- package/dist/tools/nav.js +275 -0
- package/dist/tools/nav.js.map +1 -0
- package/dist/tools/notebook.d.ts +7 -0
- package/dist/tools/notebook.d.ts.map +1 -0
- package/dist/tools/notebook.js +102 -0
- package/dist/tools/notebook.js.map +1 -0
- package/dist/tools/performance.d.ts +7 -0
- package/dist/tools/performance.d.ts.map +1 -0
- package/dist/tools/performance.js +59 -0
- package/dist/tools/performance.js.map +1 -0
- package/dist/tools/quality.d.ts +7 -0
- package/dist/tools/quality.d.ts.map +1 -0
- package/dist/tools/quality.js +279 -0
- package/dist/tools/quality.js.map +1 -0
- package/dist/tools/scaffold.d.ts +7 -0
- package/dist/tools/scaffold.d.ts.map +1 -0
- package/dist/tools/scaffold.js +80 -0
- package/dist/tools/scaffold.js.map +1 -0
- package/dist/tools/search.d.ts +7 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +308 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/security.d.ts +7 -0
- package/dist/tools/security.d.ts.map +1 -0
- package/dist/tools/security.js +138 -0
- package/dist/tools/security.js.map +1 -0
- package/dist/utils/analytics.d.ts +69 -0
- package/dist/utils/analytics.d.ts.map +1 -0
- package/dist/utils/analytics.js +144 -0
- package/dist/utils/analytics.js.map +1 -0
- package/dist/utils/concurrency.d.ts +43 -0
- package/dist/utils/concurrency.d.ts.map +1 -0
- package/dist/utils/concurrency.js +78 -0
- package/dist/utils/concurrency.js.map +1 -0
- package/dist/utils/fallback.d.ts +52 -0
- package/dist/utils/fallback.d.ts.map +1 -0
- package/dist/utils/fallback.js +137 -0
- package/dist/utils/fallback.js.map +1 -0
- package/dist/utils/git-hooks.d.ts +24 -0
- package/dist/utils/git-hooks.d.ts.map +1 -0
- package/dist/utils/git-hooks.js +108 -0
- package/dist/utils/git-hooks.js.map +1 -0
- package/dist/utils/languages.d.ts +72 -0
- package/dist/utils/languages.d.ts.map +1 -0
- package/dist/utils/languages.js +463 -0
- package/dist/utils/languages.js.map +1 -0
- package/dist/utils/logger.d.ts +13 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +34 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/plugins.d.ts +105 -0
- package/dist/utils/plugins.d.ts.map +1 -0
- package/dist/utils/plugins.js +325 -0
- package/dist/utils/plugins.js.map +1 -0
- package/dist/utils/security.d.ts +17 -0
- package/dist/utils/security.d.ts.map +1 -0
- package/dist/utils/security.js +48 -0
- package/dist/utils/security.js.map +1 -0
- package/dist/utils/streaming.d.ts +56 -0
- package/dist/utils/streaming.d.ts.map +1 -0
- package/dist/utils/streaming.js +95 -0
- package/dist/utils/streaming.js.map +1 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/mcp.json +100 -0
- package/package.json +89 -0
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code Generation Templates / Scaffolding
|
|
3
|
+
* Generates boilerplate code from symbol signatures.
|
|
4
|
+
* Supports: React components, Express routes, test files, API handlers,
|
|
5
|
+
* class stubs, and module scaffolds based on project conventions.
|
|
6
|
+
*/
|
|
7
|
+
import { listFiles } from '../search/fast-search.js';
|
|
8
|
+
import { readFile } from 'node:fs/promises';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
/**
|
|
11
|
+
* Detect project conventions from existing files.
|
|
12
|
+
* @param cwd - The working directory
|
|
13
|
+
* @returns Detected project type and convention patterns
|
|
14
|
+
*/
|
|
15
|
+
async function detectConventions(cwd) {
|
|
16
|
+
const patterns = [];
|
|
17
|
+
let projectType = 'generic';
|
|
18
|
+
try {
|
|
19
|
+
const pkgContent = await readFile(path.join(cwd, 'package.json'), 'utf-8');
|
|
20
|
+
const pkg = JSON.parse(pkgContent);
|
|
21
|
+
const allDeps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
|
|
22
|
+
if (allDeps.react || allDeps['react-dom']) {
|
|
23
|
+
projectType = allDeps.next ? 'nextjs' : 'react';
|
|
24
|
+
patterns.push('React project detected');
|
|
25
|
+
}
|
|
26
|
+
if (allDeps.express) {
|
|
27
|
+
projectType = projectType === 'generic' ? 'express' : projectType;
|
|
28
|
+
patterns.push('Express backend');
|
|
29
|
+
}
|
|
30
|
+
if (allDeps['@nestjs/core']) {
|
|
31
|
+
projectType = 'nestjs';
|
|
32
|
+
patterns.push('NestJS project');
|
|
33
|
+
}
|
|
34
|
+
if (allDeps.vue) {
|
|
35
|
+
projectType = 'vue';
|
|
36
|
+
patterns.push('Vue project');
|
|
37
|
+
}
|
|
38
|
+
if (allDeps.vitest)
|
|
39
|
+
patterns.push('Vitest testing');
|
|
40
|
+
if (allDeps.jest)
|
|
41
|
+
patterns.push('Jest testing');
|
|
42
|
+
if (allDeps.typescript)
|
|
43
|
+
patterns.push('TypeScript');
|
|
44
|
+
if (allDeps.tailwindcss)
|
|
45
|
+
patterns.push('Tailwind CSS');
|
|
46
|
+
if (allDeps.prisma || allDeps['@prisma/client'])
|
|
47
|
+
patterns.push('Prisma ORM');
|
|
48
|
+
if (allDeps.zod)
|
|
49
|
+
patterns.push('Zod validation');
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
/* no package.json */
|
|
53
|
+
}
|
|
54
|
+
// Check for Python
|
|
55
|
+
try {
|
|
56
|
+
await readFile(path.join(cwd, 'pyproject.toml'), 'utf-8');
|
|
57
|
+
projectType = 'python';
|
|
58
|
+
patterns.push('Python project');
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
/* skip */
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
await readFile(path.join(cwd, 'Cargo.toml'), 'utf-8');
|
|
65
|
+
projectType = 'rust';
|
|
66
|
+
patterns.push('Rust project');
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
/* skip */
|
|
70
|
+
}
|
|
71
|
+
// Check file naming conventions
|
|
72
|
+
const tsFiles = await listFiles(cwd, { glob: 'src/**/*.{ts,tsx}' });
|
|
73
|
+
const hasPascalCase = tsFiles.some((f) => /[A-Z][a-z]+[A-Z]/.test(path.basename(f, path.extname(f))));
|
|
74
|
+
const hasKebabCase = tsFiles.some((f) => /[a-z]+-[a-z]+/.test(path.basename(f, path.extname(f))));
|
|
75
|
+
if (hasPascalCase)
|
|
76
|
+
patterns.push('PascalCase file naming');
|
|
77
|
+
if (hasKebabCase)
|
|
78
|
+
patterns.push('kebab-case file naming');
|
|
79
|
+
return { projectType, patterns };
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Generate a React component scaffold.
|
|
83
|
+
* @param name - Component name
|
|
84
|
+
* @param conventions - Detected project conventions
|
|
85
|
+
* @returns Generated component code
|
|
86
|
+
*/
|
|
87
|
+
function reactComponent(name, conventions) {
|
|
88
|
+
const hasTs = conventions.includes('TypeScript');
|
|
89
|
+
const hasTailwind = conventions.includes('Tailwind CSS');
|
|
90
|
+
const propsType = hasTs ? `\ninterface ${name}Props {\n // TODO: define props\n}\n` : '';
|
|
91
|
+
const propsParam = hasTs ? `{ }: ${name}Props` : '{ }';
|
|
92
|
+
const className = hasTailwind ? ' className="flex items-center gap-2"' : '';
|
|
93
|
+
return `${propsType}
|
|
94
|
+
export default function ${name}(${propsParam}) {
|
|
95
|
+
return (
|
|
96
|
+
<div${className}>
|
|
97
|
+
<h2>${name}</h2>
|
|
98
|
+
{/* TODO: implement component */}
|
|
99
|
+
</div>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
`;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Generate a test file scaffold.
|
|
106
|
+
* @param name - Module or function name to test
|
|
107
|
+
* @param conventions - Detected project conventions
|
|
108
|
+
* @param targetFile - Path to the file being tested
|
|
109
|
+
* @returns Generated test file code
|
|
110
|
+
*/
|
|
111
|
+
function testFile(name, conventions, targetFile) {
|
|
112
|
+
const isVitest = conventions.includes('Vitest testing');
|
|
113
|
+
const importFrom = isVitest ? 'vitest' : '@jest/globals';
|
|
114
|
+
return `import { describe, it, expect } from '${importFrom}';
|
|
115
|
+
import { ${name} } from '${targetFile.replace(/\.(ts|tsx|js|jsx)$/, '')}';
|
|
116
|
+
|
|
117
|
+
describe('${name}', () => {
|
|
118
|
+
it('should exist', () => {
|
|
119
|
+
expect(${name}).toBeDefined();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('should work correctly', () => {
|
|
123
|
+
// TODO: add test cases
|
|
124
|
+
const result = ${name}();
|
|
125
|
+
expect(result).toBeTruthy();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should handle edge cases', () => {
|
|
129
|
+
// TODO: add edge case tests
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
`;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Generate an Express route scaffold.
|
|
136
|
+
* @param name - Route name
|
|
137
|
+
* @param conventions - Detected project conventions
|
|
138
|
+
* @returns Generated Express route code
|
|
139
|
+
*/
|
|
140
|
+
function expressRoute(name, conventions) {
|
|
141
|
+
const hasTs = conventions.includes('TypeScript');
|
|
142
|
+
const hasZod = conventions.includes('Zod validation');
|
|
143
|
+
const types = hasTs ? ': Router' : '';
|
|
144
|
+
const importLine = hasTs
|
|
145
|
+
? "import { Router, Request, Response } from 'express';\n"
|
|
146
|
+
: "const { Router } = require('express');\n";
|
|
147
|
+
const zodLine = hasZod
|
|
148
|
+
? "import { z } from 'zod';\n\nconst createSchema = z.object({\n // TODO: define validation schema\n});\n"
|
|
149
|
+
: '';
|
|
150
|
+
return `${importLine}${zodLine}
|
|
151
|
+
const router${types} = Router();
|
|
152
|
+
|
|
153
|
+
router.get('/${name.toLowerCase()}', async (req${hasTs ? ': Request' : ''}, res${hasTs ? ': Response' : ''}) => {
|
|
154
|
+
try {
|
|
155
|
+
// TODO: implement GET handler
|
|
156
|
+
res.json({ message: 'GET /${name.toLowerCase()}' });
|
|
157
|
+
} catch (error) {
|
|
158
|
+
res.status(500).json({ error: 'Internal server error' });
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
router.post('/${name.toLowerCase()}', async (req${hasTs ? ': Request' : ''}, res${hasTs ? ': Response' : ''}) => {
|
|
163
|
+
try {
|
|
164
|
+
${hasZod ? 'const body = createSchema.parse(req.body);\n ' : ''}// TODO: implement POST handler
|
|
165
|
+
res.status(201).json({ message: 'Created' });
|
|
166
|
+
} catch (error) {
|
|
167
|
+
res.status(500).json({ error: 'Internal server error' });
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
export default router;
|
|
172
|
+
`;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Generate a service/module scaffold.
|
|
176
|
+
* @param name - Service name
|
|
177
|
+
* @param conventions - Detected project conventions
|
|
178
|
+
* @returns Generated service class code
|
|
179
|
+
*/
|
|
180
|
+
function serviceModule(name, conventions) {
|
|
181
|
+
const hasTs = conventions.includes('TypeScript');
|
|
182
|
+
const iface = hasTs ? `\nexport interface ${name}Options {\n // TODO: define options\n}\n` : '';
|
|
183
|
+
return `${iface}
|
|
184
|
+
export class ${name}Service {
|
|
185
|
+
${hasTs ? 'private initialized = false;\n' : ''}
|
|
186
|
+
constructor(${hasTs ? `options?: ${name}Options` : 'options'}) {
|
|
187
|
+
// TODO: initialize service
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async init()${hasTs ? ': Promise<void>' : ''} {
|
|
191
|
+
// TODO: setup
|
|
192
|
+
this.initialized = true;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async execute(input${hasTs ? ': unknown' : ''})${hasTs ? ': Promise<unknown>' : ''} {
|
|
196
|
+
if (!this.initialized) throw new Error('${name}Service not initialized');
|
|
197
|
+
// TODO: implement core logic
|
|
198
|
+
return input;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async dispose()${hasTs ? ': Promise<void>' : ''} {
|
|
202
|
+
// TODO: cleanup resources
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export function create${name}(${hasTs ? `options?: ${name}Options` : 'options'}) {
|
|
207
|
+
return new ${name}Service(options);
|
|
208
|
+
}
|
|
209
|
+
`;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* List available scaffold templates based on project conventions.
|
|
213
|
+
* @param cwd - The working directory
|
|
214
|
+
* @returns Available templates, detected patterns, and project type
|
|
215
|
+
*/
|
|
216
|
+
export async function listTemplates(cwd) {
|
|
217
|
+
const { projectType, patterns } = await detectConventions(cwd);
|
|
218
|
+
const templates = [];
|
|
219
|
+
// Universal templates
|
|
220
|
+
templates.push({
|
|
221
|
+
name: 'test',
|
|
222
|
+
description: 'Test file for a module/function',
|
|
223
|
+
language: 'typescript',
|
|
224
|
+
category: 'test',
|
|
225
|
+
});
|
|
226
|
+
templates.push({
|
|
227
|
+
name: 'service',
|
|
228
|
+
description: 'Service class with init/execute/dispose lifecycle',
|
|
229
|
+
language: 'typescript',
|
|
230
|
+
category: 'service',
|
|
231
|
+
});
|
|
232
|
+
templates.push({
|
|
233
|
+
name: 'util',
|
|
234
|
+
description: 'Utility module with exported functions',
|
|
235
|
+
language: 'typescript',
|
|
236
|
+
category: 'util',
|
|
237
|
+
});
|
|
238
|
+
// React templates
|
|
239
|
+
if (['react', 'nextjs', 'vue'].includes(projectType)) {
|
|
240
|
+
templates.push({
|
|
241
|
+
name: 'component',
|
|
242
|
+
description: 'React functional component',
|
|
243
|
+
language: 'tsx',
|
|
244
|
+
category: 'component',
|
|
245
|
+
});
|
|
246
|
+
templates.push({ name: 'hook', description: 'Custom React hook', language: 'typescript', category: 'hook' });
|
|
247
|
+
}
|
|
248
|
+
// Backend templates
|
|
249
|
+
if (['express', 'nestjs'].includes(projectType) || patterns.includes('Express backend')) {
|
|
250
|
+
templates.push({
|
|
251
|
+
name: 'route',
|
|
252
|
+
description: 'Express route with GET/POST handlers',
|
|
253
|
+
language: 'typescript',
|
|
254
|
+
category: 'route',
|
|
255
|
+
});
|
|
256
|
+
templates.push({ name: 'model', description: 'Data model/entity', language: 'typescript', category: 'model' });
|
|
257
|
+
}
|
|
258
|
+
return { templates, detectedPatterns: patterns, projectType };
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Generate scaffold code for a given template and name.
|
|
262
|
+
* @param cwd - The working directory
|
|
263
|
+
* @param options - Scaffold options
|
|
264
|
+
* @param options.template - Template type to generate
|
|
265
|
+
* @param options.name - Name for the generated code
|
|
266
|
+
* @param options.targetFile - Optional target file path
|
|
267
|
+
* @returns Generated scaffold result with code and metadata
|
|
268
|
+
*/
|
|
269
|
+
export async function generateScaffold(cwd, options) {
|
|
270
|
+
const { patterns } = await detectConventions(cwd);
|
|
271
|
+
const { template, name, targetFile } = options;
|
|
272
|
+
let generatedCode;
|
|
273
|
+
let fileName;
|
|
274
|
+
let language = 'typescript';
|
|
275
|
+
switch (template) {
|
|
276
|
+
case 'component':
|
|
277
|
+
generatedCode = reactComponent(name, patterns);
|
|
278
|
+
fileName = `${name}.tsx`;
|
|
279
|
+
language = 'tsx';
|
|
280
|
+
break;
|
|
281
|
+
case 'test':
|
|
282
|
+
generatedCode = testFile(name, patterns, targetFile || `./${name}`);
|
|
283
|
+
fileName = `${name}.test.ts`;
|
|
284
|
+
break;
|
|
285
|
+
case 'route':
|
|
286
|
+
generatedCode = expressRoute(name, patterns);
|
|
287
|
+
fileName = `${name}.routes.ts`;
|
|
288
|
+
break;
|
|
289
|
+
case 'service':
|
|
290
|
+
generatedCode = serviceModule(name, patterns);
|
|
291
|
+
fileName = `${name}.service.ts`;
|
|
292
|
+
break;
|
|
293
|
+
case 'hook':
|
|
294
|
+
generatedCode = `import { useState, useEffect } from 'react';\n\nexport function use${name}() {\n const [state, setState] = useState(null);\n\n useEffect(() => {\n // TODO: implement hook logic\n }, []);\n\n return { state };\n}\n`;
|
|
295
|
+
fileName = `use${name}.ts`;
|
|
296
|
+
break;
|
|
297
|
+
case 'util':
|
|
298
|
+
generatedCode = `/**\n * ${name} utilities\n */\n\nexport function ${name.charAt(0).toLowerCase() + name.slice(1)}() {\n // TODO: implement\n}\n`;
|
|
299
|
+
fileName = `${name.toLowerCase()}.ts`;
|
|
300
|
+
break;
|
|
301
|
+
default:
|
|
302
|
+
generatedCode = `// Template '${template}' not recognized. Available: component, test, route, service, hook, util`;
|
|
303
|
+
fileName = `${name}.ts`;
|
|
304
|
+
}
|
|
305
|
+
return {
|
|
306
|
+
template,
|
|
307
|
+
generatedCode,
|
|
308
|
+
fileName,
|
|
309
|
+
language,
|
|
310
|
+
conventions: patterns,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
//# sourceMappingURL=scaffold.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../src/analyzers/scaffold.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAwB7B;;;;GAIG;AACH,KAAK,UAAU,iBAAiB,CAAC,GAAW;IAC1C,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,WAAW,GAAG,SAAS,CAAC;IAE5B,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAAC;QAC3E,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC,EAAE,CAAC;QAEhF,IAAI,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;YAC1C,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;YAChD,QAAQ,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;QAC1C,CAAC;QACD,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,WAAW,GAAG,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC;YAClE,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACnC,CAAC;QACD,IAAI,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;YAC5B,WAAW,GAAG,QAAQ,CAAC;YACvB,QAAQ,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAClC,CAAC;QACD,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;YAChB,WAAW,GAAG,KAAK,CAAC;YACpB,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC/B,CAAC;QACD,IAAI,OAAO,CAAC,MAAM;YAAE,QAAQ,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QACpD,IAAI,OAAO,CAAC,IAAI;YAAE,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAChD,IAAI,OAAO,CAAC,UAAU;YAAE,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACpD,IAAI,OAAO,CAAC,WAAW;YAAE,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACvD,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,gBAAgB,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7E,IAAI,OAAO,CAAC,GAAG;YAAE,QAAQ,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,qBAAqB;IACvB,CAAC;IAED,mBAAmB;IACnB,IAAI,CAAC;QACH,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,EAAE,OAAO,CAAC,CAAC;QAC1D,WAAW,GAAG,QAAQ,CAAC;QACvB,QAAQ,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,UAAU;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC;QACtD,WAAW,GAAG,MAAM,CAAC;QACrB,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,UAAU;IACZ,CAAC;IAED,gCAAgC;IAChC,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAC,CAAC;IACpE,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtG,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClG,IAAI,aAAa;QAAE,QAAQ,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IAC3D,IAAI,YAAY;QAAE,QAAQ,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IAE1D,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;AACnC,CAAC;AAED;;;;;GAKG;AACH,SAAS,cAAc,CAAC,IAAY,EAAE,WAAqB;IACzD,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IACjD,MAAM,WAAW,GAAG,WAAW,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IAEzD,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,eAAe,IAAI,uCAAuC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1F,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,QAAQ,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;IACvD,MAAM,SAAS,GAAG,WAAW,CAAC,CAAC,CAAC,sCAAsC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE5E,OAAO,GAAG,SAAS;0BACK,IAAI,IAAI,UAAU;;UAElC,SAAS;YACP,IAAI;;;;;CAKf,CAAC;AACF,CAAC;AAED;;;;;;GAMG;AACH,SAAS,QAAQ,CAAC,IAAY,EAAE,WAAqB,EAAE,UAAkB;IACvE,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACxD,MAAM,UAAU,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC;IAEzD,OAAO,yCAAyC,UAAU;WACjD,IAAI,YAAY,UAAU,CAAC,OAAO,CAAC,oBAAoB,EAAE,EAAE,CAAC;;YAE3D,IAAI;;aAEH,IAAI;;;;;qBAKI,IAAI;;;;;;;;CAQxB,CAAC;AACF,CAAC;AAED;;;;;GAKG;AACH,SAAS,YAAY,CAAC,IAAY,EAAE,WAAqB;IACvD,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,WAAW,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IACtD,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;IACtC,MAAM,UAAU,GAAG,KAAK;QACtB,CAAC,CAAC,wDAAwD;QAC1D,CAAC,CAAC,0CAA0C,CAAC;IAC/C,MAAM,OAAO,GAAG,MAAM;QACpB,CAAC,CAAC,yGAAyG;QAC3G,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO,GAAG,UAAU,GAAG,OAAO;cAClB,KAAK;;eAEJ,IAAI,CAAC,WAAW,EAAE,gBAAgB,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,QAAQ,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE;;;gCAG1E,IAAI,CAAC,WAAW,EAAE;;;;;;gBAMlC,IAAI,CAAC,WAAW,EAAE,gBAAgB,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,QAAQ,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE;;MAErG,MAAM,CAAC,CAAC,CAAC,kDAAkD,CAAC,CAAC,CAAC,EAAE;;;;;;;;CAQrE,CAAC;AACF,CAAC;AAED;;;;;GAKG;AACH,SAAS,aAAa,CAAC,IAAY,EAAE,WAAqB;IACxD,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,sBAAsB,IAAI,2CAA2C,CAAC,CAAC,CAAC,EAAE,CAAC;IAEjG,OAAO,GAAG,KAAK;eACF,IAAI;IACf,KAAK,CAAC,CAAC,CAAC,gCAAgC,CAAC,CAAC,CAAC,EAAE;gBACjC,KAAK,CAAC,CAAC,CAAC,aAAa,IAAI,SAAS,CAAC,CAAC,CAAC,SAAS;;;;gBAI9C,KAAK,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE;;;;;uBAKvB,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE;8CACtC,IAAI;;;;;mBAK/B,KAAK,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE;;;;;wBAKzB,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,aAAa,IAAI,SAAS,CAAC,CAAC,CAAC,SAAS;eAC/D,IAAI;;CAElB,CAAC;AACF,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAW;IAC7C,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAC/D,MAAM,SAAS,GAAuB,EAAE,CAAC;IAEzC,sBAAsB;IACtB,SAAS,CAAC,IAAI,CAAC;QACb,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,iCAAiC;QAC9C,QAAQ,EAAE,YAAY;QACtB,QAAQ,EAAE,MAAM;KACjB,CAAC,CAAC;IACH,SAAS,CAAC,IAAI,CAAC;QACb,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,mDAAmD;QAChE,QAAQ,EAAE,YAAY;QACtB,QAAQ,EAAE,SAAS;KACpB,CAAC,CAAC;IACH,SAAS,CAAC,IAAI,CAAC;QACb,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,wCAAwC;QACrD,QAAQ,EAAE,YAAY;QACtB,QAAQ,EAAE,MAAM;KACjB,CAAC,CAAC;IAEH,kBAAkB;IAClB,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QACrD,SAAS,CAAC,IAAI,CAAC;YACb,IAAI,EAAE,WAAW;YACjB,WAAW,EAAE,4BAA4B;YACzC,QAAQ,EAAE,KAAK;YACf,QAAQ,EAAE,WAAW;SACtB,CAAC,CAAC;QACH,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,mBAAmB,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/G,CAAC;IAED,oBAAoB;IACpB,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACxF,SAAS,CAAC,IAAI,CAAC;YACb,IAAI,EAAE,OAAO;YACb,WAAW,EAAE,sCAAsC;YACnD,QAAQ,EAAE,YAAY;YACtB,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;QACH,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IACjH,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AAChE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAW,EACX,OAAgE;IAEhE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAClD,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;IAE/C,IAAI,aAAqB,CAAC;IAC1B,IAAI,QAAgB,CAAC;IACrB,IAAI,QAAQ,GAAG,YAAY,CAAC;IAE5B,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,WAAW;YACd,aAAa,GAAG,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAC/C,QAAQ,GAAG,GAAG,IAAI,MAAM,CAAC;YACzB,QAAQ,GAAG,KAAK,CAAC;YACjB,MAAM;QACR,KAAK,MAAM;YACT,aAAa,GAAG,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,IAAI,KAAK,IAAI,EAAE,CAAC,CAAC;YACpE,QAAQ,GAAG,GAAG,IAAI,UAAU,CAAC;YAC7B,MAAM;QACR,KAAK,OAAO;YACV,aAAa,GAAG,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAC7C,QAAQ,GAAG,GAAG,IAAI,YAAY,CAAC;YAC/B,MAAM;QACR,KAAK,SAAS;YACZ,aAAa,GAAG,aAAa,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAC9C,QAAQ,GAAG,GAAG,IAAI,aAAa,CAAC;YAChC,MAAM;QACR,KAAK,MAAM;YACT,aAAa,GAAG,sEAAsE,IAAI,oJAAoJ,CAAC;YAC/O,QAAQ,GAAG,MAAM,IAAI,KAAK,CAAC;YAC3B,MAAM;QACR,KAAK,MAAM;YACT,aAAa,GAAG,WAAW,IAAI,sCAAsC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,iCAAiC,CAAC;YACnJ,QAAQ,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC;YACtC,MAAM;QACR;YACE,aAAa,GAAG,gBAAgB,QAAQ,0EAA0E,CAAC;YACnH,QAAQ,GAAG,GAAG,IAAI,KAAK,CAAC;IAC5B,CAAC;IAED,OAAO;QACL,QAAQ;QACR,aAAa;QACb,QAAQ;QACR,QAAQ;QACR,WAAW,EAAE,QAAQ;KACtB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security scanning module.
|
|
3
|
+
* - Dependency vulnerability checking (lock file analysis)
|
|
4
|
+
* - SAST-lite: common security anti-patterns
|
|
5
|
+
* - Secret/credential detection
|
|
6
|
+
* - No external API dependencies
|
|
7
|
+
*/
|
|
8
|
+
export interface SecurityFinding {
|
|
9
|
+
severity: 'critical' | 'high' | 'medium' | 'low' | 'info';
|
|
10
|
+
category: string;
|
|
11
|
+
message: string;
|
|
12
|
+
file: string;
|
|
13
|
+
line?: number;
|
|
14
|
+
snippet?: string;
|
|
15
|
+
recommendation: string;
|
|
16
|
+
}
|
|
17
|
+
export interface SecurityReport {
|
|
18
|
+
scanDate: string;
|
|
19
|
+
totalFindings: number;
|
|
20
|
+
bySeverity: Record<string, number>;
|
|
21
|
+
findings: SecurityFinding[];
|
|
22
|
+
dependencyInfo?: {
|
|
23
|
+
total: number;
|
|
24
|
+
directDeps: number;
|
|
25
|
+
lockfileFound: boolean;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Run security scan on codebase.
|
|
30
|
+
* @param cwd - The working directory
|
|
31
|
+
* @param options - Scan options
|
|
32
|
+
* @param options.category - Filter by finding category
|
|
33
|
+
* @param options.severity - Filter by severity level
|
|
34
|
+
* @param options.fileGlob - Glob pattern for files to scan
|
|
35
|
+
* @returns Security report with findings and dependency info
|
|
36
|
+
*/
|
|
37
|
+
export declare function securityScan(cwd: string, options?: {
|
|
38
|
+
category?: string;
|
|
39
|
+
severity?: string;
|
|
40
|
+
fileGlob?: string;
|
|
41
|
+
}): Promise<SecurityReport>;
|
|
42
|
+
//# sourceMappingURL=security.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../src/analyzers/security.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,cAAc,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,OAAO,CAAA;KAAE,CAAC;CAChF;AAyID;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,MAAM,EACX,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GACxE,OAAO,CAAC,cAAc,CAAC,CAqFzB"}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security scanning module.
|
|
3
|
+
* - Dependency vulnerability checking (lock file analysis)
|
|
4
|
+
* - SAST-lite: common security anti-patterns
|
|
5
|
+
* - Secret/credential detection
|
|
6
|
+
* - No external API dependencies
|
|
7
|
+
*/
|
|
8
|
+
import { readFile, access } from 'node:fs/promises';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import { glob } from 'glob';
|
|
11
|
+
/**
|
|
12
|
+
* SAST patterns to detect.
|
|
13
|
+
*/
|
|
14
|
+
const SAST_PATTERNS = [
|
|
15
|
+
// SQL Injection
|
|
16
|
+
{
|
|
17
|
+
name: 'SQL injection risk',
|
|
18
|
+
category: 'injection',
|
|
19
|
+
severity: 'critical',
|
|
20
|
+
pattern: /(?:query|execute|exec|raw)\s*\(\s*[`'"]\s*(?:SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER).*?\$\{|%s|%d|\+\s*\w/i,
|
|
21
|
+
recommendation: 'Use parameterized queries or an ORM instead of string concatenation in SQL.',
|
|
22
|
+
},
|
|
23
|
+
// Command Injection
|
|
24
|
+
{
|
|
25
|
+
name: 'Command injection risk',
|
|
26
|
+
category: 'injection',
|
|
27
|
+
severity: 'critical',
|
|
28
|
+
pattern: /(?:exec|spawn|system|popen|subprocess\.(?:call|run|Popen))\s*\([^)]*(?:\$\{|\+\s*\w|%s|f['"]\s*\{)/,
|
|
29
|
+
recommendation: 'Avoid passing user input to shell commands. Use parameterized APIs or allowlists.',
|
|
30
|
+
},
|
|
31
|
+
// XSS
|
|
32
|
+
{
|
|
33
|
+
name: 'Potential XSS via innerHTML',
|
|
34
|
+
category: 'xss',
|
|
35
|
+
severity: 'high',
|
|
36
|
+
pattern: /\.innerHTML\s*=|dangerouslySetInnerHTML|v-html\s*=/,
|
|
37
|
+
recommendation: 'Use textContent instead of innerHTML, or sanitize with DOMPurify.',
|
|
38
|
+
},
|
|
39
|
+
// Hardcoded secrets
|
|
40
|
+
{
|
|
41
|
+
name: 'Hardcoded secret/credential',
|
|
42
|
+
category: 'secrets',
|
|
43
|
+
severity: 'critical',
|
|
44
|
+
pattern: /(?:password|secret|api_key|apikey|token|private_key|access_key|auth_token|client_secret)\s*[:=]\s*['"]\S{8,}['"]/i,
|
|
45
|
+
recommendation: 'Move secrets to environment variables or a secret manager (AWS Secrets Manager, Vault, etc).',
|
|
46
|
+
},
|
|
47
|
+
// Hardcoded URLs with credentials
|
|
48
|
+
{
|
|
49
|
+
name: 'Credential in URL',
|
|
50
|
+
category: 'secrets',
|
|
51
|
+
severity: 'high',
|
|
52
|
+
pattern: /(?:https?|ftp):\/\/\w+:\w+@/,
|
|
53
|
+
recommendation: 'Remove credentials from URLs. Use environment variables for connection strings.',
|
|
54
|
+
},
|
|
55
|
+
// Insecure randomness
|
|
56
|
+
{
|
|
57
|
+
name: 'Insecure randomness',
|
|
58
|
+
category: 'crypto',
|
|
59
|
+
severity: 'medium',
|
|
60
|
+
pattern: /Math\.random\(\)|random\.random\(\)|rand\(\)/,
|
|
61
|
+
recommendation: 'Use crypto.randomBytes() or secrets module for security-sensitive random values.',
|
|
62
|
+
},
|
|
63
|
+
// Weak hashing
|
|
64
|
+
{
|
|
65
|
+
name: 'Weak hash algorithm (MD5/SHA1)',
|
|
66
|
+
category: 'crypto',
|
|
67
|
+
severity: 'medium',
|
|
68
|
+
pattern: /(?:createHash|hashlib\.md5|hashlib\.sha1|MD5|SHA1)\s*\(/,
|
|
69
|
+
recommendation: 'Use SHA-256 or bcrypt/argon2 for passwords.',
|
|
70
|
+
},
|
|
71
|
+
// Eval usage
|
|
72
|
+
{
|
|
73
|
+
name: 'Dangerous eval() usage',
|
|
74
|
+
category: 'injection',
|
|
75
|
+
severity: 'high',
|
|
76
|
+
pattern: /\beval\s*\((?!['"][^'"]+['"])|new\s+Function\s*\(/,
|
|
77
|
+
recommendation: 'Avoid eval(). Use JSON.parse() for data or a sandboxed environment.',
|
|
78
|
+
},
|
|
79
|
+
// CORS wildcard
|
|
80
|
+
{
|
|
81
|
+
name: 'CORS wildcard origin',
|
|
82
|
+
category: 'config',
|
|
83
|
+
severity: 'medium',
|
|
84
|
+
pattern: /(?:Access-Control-Allow-Origin|cors)\s*[:({]\s*['"]\*['"]/,
|
|
85
|
+
recommendation: 'Restrict CORS to specific trusted origins instead of wildcard *.',
|
|
86
|
+
},
|
|
87
|
+
// Unvalidated redirect
|
|
88
|
+
{
|
|
89
|
+
name: 'Open redirect risk',
|
|
90
|
+
category: 'redirect',
|
|
91
|
+
severity: 'medium',
|
|
92
|
+
pattern: /(?:redirect|location\.href|window\.location)\s*=\s*(?:req\.|request\.|params\.|query\.)/,
|
|
93
|
+
recommendation: 'Validate redirect URLs against an allowlist of trusted domains.',
|
|
94
|
+
},
|
|
95
|
+
// Disabled security features
|
|
96
|
+
{
|
|
97
|
+
name: 'TLS/SSL verification disabled',
|
|
98
|
+
category: 'config',
|
|
99
|
+
severity: 'high',
|
|
100
|
+
pattern: /verify\s*=\s*False|rejectUnauthorized\s*:\s*false|NODE_TLS_REJECT_UNAUTHORIZED\s*=\s*['"]?0/,
|
|
101
|
+
recommendation: 'Never disable TLS verification in production.',
|
|
102
|
+
},
|
|
103
|
+
// Debug mode in production
|
|
104
|
+
{
|
|
105
|
+
name: 'Debug mode enabled',
|
|
106
|
+
category: 'config',
|
|
107
|
+
severity: 'medium',
|
|
108
|
+
pattern: /DEBUG\s*=\s*True|debug\s*:\s*true|app\.debug\s*=\s*True/,
|
|
109
|
+
recommendation: 'Ensure debug mode is disabled in production environments.',
|
|
110
|
+
},
|
|
111
|
+
// Empty catch blocks
|
|
112
|
+
{
|
|
113
|
+
name: 'Swallowed security exception',
|
|
114
|
+
category: 'error-handling',
|
|
115
|
+
severity: 'low',
|
|
116
|
+
pattern: /catch\s*\([^)]*\)\s*\{\s*\}|except:\s*pass/,
|
|
117
|
+
recommendation: 'Log exceptions properly. Swallowed exceptions can hide security issues.',
|
|
118
|
+
},
|
|
119
|
+
// Path traversal
|
|
120
|
+
{
|
|
121
|
+
name: 'Path traversal risk',
|
|
122
|
+
category: 'injection',
|
|
123
|
+
severity: 'high',
|
|
124
|
+
pattern: /path\.join\s*\([^)]*req\.|path\.resolve\s*\([^)]*req\.|os\.path\.join\s*\([^)]*request\./,
|
|
125
|
+
recommendation: 'Validate and sanitize file paths. Use path.resolve() and check against base directory.',
|
|
126
|
+
},
|
|
127
|
+
// JWT without verification
|
|
128
|
+
{
|
|
129
|
+
name: 'JWT without verification',
|
|
130
|
+
category: 'auth',
|
|
131
|
+
severity: 'high',
|
|
132
|
+
pattern: /jwt\.decode\s*\([^)]*verify\s*=\s*False|algorithms\s*=\s*\[\s*['"]none['"]/,
|
|
133
|
+
recommendation: 'Always verify JWT signatures. Never allow "none" algorithm.',
|
|
134
|
+
},
|
|
135
|
+
];
|
|
136
|
+
/**
|
|
137
|
+
* Run security scan on codebase.
|
|
138
|
+
* @param cwd - The working directory
|
|
139
|
+
* @param options - Scan options
|
|
140
|
+
* @param options.category - Filter by finding category
|
|
141
|
+
* @param options.severity - Filter by severity level
|
|
142
|
+
* @param options.fileGlob - Glob pattern for files to scan
|
|
143
|
+
* @returns Security report with findings and dependency info
|
|
144
|
+
*/
|
|
145
|
+
export async function securityScan(cwd, options = {}) {
|
|
146
|
+
const findings = [];
|
|
147
|
+
// Find all source files
|
|
148
|
+
const files = await glob(options.fileGlob || '**/*.{ts,tsx,js,jsx,py,java,go,rs,rb,php,cs}', {
|
|
149
|
+
cwd,
|
|
150
|
+
ignore: ['node_modules/**', 'dist/**', 'build/**', '.git/**', 'vendor/**', '__pycache__/**'],
|
|
151
|
+
});
|
|
152
|
+
// Scan each file against SAST patterns
|
|
153
|
+
for (const file of files.slice(0, 1000)) {
|
|
154
|
+
try {
|
|
155
|
+
const content = await readFile(path.join(cwd, file), 'utf-8');
|
|
156
|
+
const lines = content.split('\n');
|
|
157
|
+
for (const pattern of SAST_PATTERNS) {
|
|
158
|
+
if (options.category && pattern.category !== options.category)
|
|
159
|
+
continue;
|
|
160
|
+
if (options.severity && pattern.severity !== options.severity)
|
|
161
|
+
continue;
|
|
162
|
+
for (let i = 0; i < lines.length; i++) {
|
|
163
|
+
if (pattern.pattern.test(lines[i])) {
|
|
164
|
+
// Skip if in a comment
|
|
165
|
+
const trimmed = lines[i].trim();
|
|
166
|
+
if (trimmed.startsWith('//') || trimmed.startsWith('#') || trimmed.startsWith('*'))
|
|
167
|
+
continue;
|
|
168
|
+
findings.push({
|
|
169
|
+
severity: pattern.severity,
|
|
170
|
+
category: pattern.category,
|
|
171
|
+
message: pattern.name,
|
|
172
|
+
file,
|
|
173
|
+
line: i + 1,
|
|
174
|
+
snippet: lines[i].trim().slice(0, 120),
|
|
175
|
+
recommendation: pattern.recommendation,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
/* skip unreadable files */
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// Check for common insecure files
|
|
186
|
+
const insecureFiles = [
|
|
187
|
+
{ file: '.env', message: '.env file should not be committed to version control' },
|
|
188
|
+
{ file: 'id_rsa', message: 'Private SSH key should not be in repository' },
|
|
189
|
+
{ file: 'id_ed25519', message: 'Private SSH key should not be in repository' },
|
|
190
|
+
{ file: '.npmrc', message: 'npm config may contain auth tokens' },
|
|
191
|
+
{ file: '.pypirc', message: 'PyPI config may contain auth tokens' },
|
|
192
|
+
];
|
|
193
|
+
for (const check of insecureFiles) {
|
|
194
|
+
try {
|
|
195
|
+
await access(path.join(cwd, check.file));
|
|
196
|
+
findings.push({
|
|
197
|
+
severity: 'high',
|
|
198
|
+
category: 'secrets',
|
|
199
|
+
message: check.message,
|
|
200
|
+
file: check.file,
|
|
201
|
+
recommendation: `Add ${check.file} to .gitignore and remove from version control.`,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
/* not present, good */
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// Check dependency info
|
|
209
|
+
const depInfo = await analyzeDependencies(cwd);
|
|
210
|
+
// Build severity counts
|
|
211
|
+
const bySeverity = {};
|
|
212
|
+
for (const f of findings) {
|
|
213
|
+
bySeverity[f.severity] = (bySeverity[f.severity] || 0) + 1;
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
scanDate: new Date().toISOString(),
|
|
217
|
+
totalFindings: findings.length,
|
|
218
|
+
bySeverity,
|
|
219
|
+
findings: findings.sort((a, b) => {
|
|
220
|
+
const order = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };
|
|
221
|
+
return (order[a.severity] || 4) - (order[b.severity] || 4);
|
|
222
|
+
}),
|
|
223
|
+
dependencyInfo: depInfo,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Analyze dependency files for basic info.
|
|
228
|
+
* @param cwd - The working directory
|
|
229
|
+
* @returns Dependency count information and lockfile presence
|
|
230
|
+
*/
|
|
231
|
+
async function analyzeDependencies(cwd) {
|
|
232
|
+
// Check for lockfiles
|
|
233
|
+
const lockfiles = [
|
|
234
|
+
'package-lock.json',
|
|
235
|
+
'yarn.lock',
|
|
236
|
+
'pnpm-lock.yaml',
|
|
237
|
+
'Pipfile.lock',
|
|
238
|
+
'poetry.lock',
|
|
239
|
+
'Cargo.lock',
|
|
240
|
+
'go.sum',
|
|
241
|
+
];
|
|
242
|
+
let lockfileFound = false;
|
|
243
|
+
for (const lf of lockfiles) {
|
|
244
|
+
try {
|
|
245
|
+
await access(path.join(cwd, lf));
|
|
246
|
+
lockfileFound = true;
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
// Count deps from package.json / requirements.txt / etc.
|
|
254
|
+
let directDeps = 0;
|
|
255
|
+
let totalDeps = 0;
|
|
256
|
+
try {
|
|
257
|
+
const pkgJson = JSON.parse(await readFile(path.join(cwd, 'package.json'), 'utf-8'));
|
|
258
|
+
directDeps = Object.keys(pkgJson.dependencies || {}).length + Object.keys(pkgJson.devDependencies || {}).length;
|
|
259
|
+
// Rough total from lock file
|
|
260
|
+
try {
|
|
261
|
+
const lockContent = await readFile(path.join(cwd, 'package-lock.json'), 'utf-8');
|
|
262
|
+
const lockData = JSON.parse(lockContent);
|
|
263
|
+
totalDeps = Object.keys(lockData.packages || lockData.dependencies || {}).length;
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
totalDeps = directDeps;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
catch {
|
|
270
|
+
try {
|
|
271
|
+
const reqs = await readFile(path.join(cwd, 'requirements.txt'), 'utf-8');
|
|
272
|
+
directDeps = reqs.split('\n').filter((l) => l.trim() && !l.startsWith('#')).length;
|
|
273
|
+
totalDeps = directDeps;
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
/* no deps file found */
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return { total: totalDeps, directDeps, lockfileFound };
|
|
280
|
+
}
|
|
281
|
+
//# sourceMappingURL=security.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.js","sourceRoot":"","sources":["../../src/analyzers/security.ts"],"names":[],"mappings":"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"}
|