wiggum-cli 0.1.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 +341 -0
- package/bin/ralph.js +8 -0
- package/dist/ai/enhancer.d.ts +100 -0
- package/dist/ai/enhancer.d.ts.map +1 -0
- package/dist/ai/enhancer.js +233 -0
- package/dist/ai/enhancer.js.map +1 -0
- package/dist/ai/index.d.ts +8 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +11 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/prompts.d.ts +26 -0
- package/dist/ai/prompts.d.ts.map +1 -0
- package/dist/ai/prompts.js +201 -0
- package/dist/ai/prompts.js.map +1 -0
- package/dist/ai/providers.d.ts +35 -0
- package/dist/ai/providers.d.ts.map +1 -0
- package/dist/ai/providers.js +104 -0
- package/dist/ai/providers.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +196 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/init.d.ts +16 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +124 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/monitor.d.ts +17 -0
- package/dist/commands/monitor.d.ts.map +1 -0
- package/dist/commands/monitor.js +342 -0
- package/dist/commands/monitor.js.map +1 -0
- package/dist/commands/new.d.ts +19 -0
- package/dist/commands/new.d.ts.map +1 -0
- package/dist/commands/new.js +272 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/run.d.ts +16 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +175 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/generator/config.d.ts +59 -0
- package/dist/generator/config.d.ts.map +1 -0
- package/dist/generator/config.js +68 -0
- package/dist/generator/config.js.map +1 -0
- package/dist/generator/index.d.ts +64 -0
- package/dist/generator/index.d.ts.map +1 -0
- package/dist/generator/index.js +147 -0
- package/dist/generator/index.js.map +1 -0
- package/dist/generator/templates.d.ts +70 -0
- package/dist/generator/templates.d.ts.map +1 -0
- package/dist/generator/templates.js +296 -0
- package/dist/generator/templates.js.map +1 -0
- package/dist/generator/writer.d.ts +93 -0
- package/dist/generator/writer.d.ts.map +1 -0
- package/dist/generator/writer.js +213 -0
- package/dist/generator/writer.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/scanner/detectors/core/framework.d.ts +11 -0
- package/dist/scanner/detectors/core/framework.d.ts.map +1 -0
- package/dist/scanner/detectors/core/framework.js +275 -0
- package/dist/scanner/detectors/core/framework.js.map +1 -0
- package/dist/scanner/detectors/core/packageManager.d.ts +11 -0
- package/dist/scanner/detectors/core/packageManager.d.ts.map +1 -0
- package/dist/scanner/detectors/core/packageManager.js +74 -0
- package/dist/scanner/detectors/core/packageManager.js.map +1 -0
- package/dist/scanner/detectors/core/styling.d.ts +12 -0
- package/dist/scanner/detectors/core/styling.d.ts.map +1 -0
- package/dist/scanner/detectors/core/styling.js +230 -0
- package/dist/scanner/detectors/core/styling.js.map +1 -0
- package/dist/scanner/detectors/core/testing.d.ts +12 -0
- package/dist/scanner/detectors/core/testing.d.ts.map +1 -0
- package/dist/scanner/detectors/core/testing.js +190 -0
- package/dist/scanner/detectors/core/testing.js.map +1 -0
- package/dist/scanner/detectors/data/api.d.ts +12 -0
- package/dist/scanner/detectors/data/api.d.ts.map +1 -0
- package/dist/scanner/detectors/data/api.js +261 -0
- package/dist/scanner/detectors/data/api.js.map +1 -0
- package/dist/scanner/detectors/data/database.d.ts +12 -0
- package/dist/scanner/detectors/data/database.d.ts.map +1 -0
- package/dist/scanner/detectors/data/database.js +213 -0
- package/dist/scanner/detectors/data/database.js.map +1 -0
- package/dist/scanner/detectors/data/orm.d.ts +12 -0
- package/dist/scanner/detectors/data/orm.d.ts.map +1 -0
- package/dist/scanner/detectors/data/orm.js +160 -0
- package/dist/scanner/detectors/data/orm.js.map +1 -0
- package/dist/scanner/detectors/frontend/formHandling.d.ts +12 -0
- package/dist/scanner/detectors/frontend/formHandling.d.ts.map +1 -0
- package/dist/scanner/detectors/frontend/formHandling.js +211 -0
- package/dist/scanner/detectors/frontend/formHandling.js.map +1 -0
- package/dist/scanner/detectors/frontend/stateManagement.d.ts +12 -0
- package/dist/scanner/detectors/frontend/stateManagement.d.ts.map +1 -0
- package/dist/scanner/detectors/frontend/stateManagement.js +221 -0
- package/dist/scanner/detectors/frontend/stateManagement.js.map +1 -0
- package/dist/scanner/detectors/frontend/uiComponents.d.ts +12 -0
- package/dist/scanner/detectors/frontend/uiComponents.d.ts.map +1 -0
- package/dist/scanner/detectors/frontend/uiComponents.js +285 -0
- package/dist/scanner/detectors/frontend/uiComponents.js.map +1 -0
- package/dist/scanner/detectors/infra/deployment.d.ts +12 -0
- package/dist/scanner/detectors/infra/deployment.d.ts.map +1 -0
- package/dist/scanner/detectors/infra/deployment.js +301 -0
- package/dist/scanner/detectors/infra/deployment.js.map +1 -0
- package/dist/scanner/detectors/infra/monorepo.d.ts +12 -0
- package/dist/scanner/detectors/infra/monorepo.d.ts.map +1 -0
- package/dist/scanner/detectors/infra/monorepo.js +219 -0
- package/dist/scanner/detectors/infra/monorepo.js.map +1 -0
- package/dist/scanner/detectors/mcp/mcpProject.d.ts +12 -0
- package/dist/scanner/detectors/mcp/mcpProject.d.ts.map +1 -0
- package/dist/scanner/detectors/mcp/mcpProject.js +154 -0
- package/dist/scanner/detectors/mcp/mcpProject.js.map +1 -0
- package/dist/scanner/detectors/mcp/mcpServers.d.ts +17 -0
- package/dist/scanner/detectors/mcp/mcpServers.d.ts.map +1 -0
- package/dist/scanner/detectors/mcp/mcpServers.js +193 -0
- package/dist/scanner/detectors/mcp/mcpServers.js.map +1 -0
- package/dist/scanner/detectors/services/analytics.d.ts +12 -0
- package/dist/scanner/detectors/services/analytics.d.ts.map +1 -0
- package/dist/scanner/detectors/services/analytics.js +236 -0
- package/dist/scanner/detectors/services/analytics.js.map +1 -0
- package/dist/scanner/detectors/services/auth.d.ts +12 -0
- package/dist/scanner/detectors/services/auth.d.ts.map +1 -0
- package/dist/scanner/detectors/services/auth.js +217 -0
- package/dist/scanner/detectors/services/auth.js.map +1 -0
- package/dist/scanner/detectors/services/email.d.ts +12 -0
- package/dist/scanner/detectors/services/email.d.ts.map +1 -0
- package/dist/scanner/detectors/services/email.js +211 -0
- package/dist/scanner/detectors/services/email.js.map +1 -0
- package/dist/scanner/detectors/services/payments.d.ts +12 -0
- package/dist/scanner/detectors/services/payments.d.ts.map +1 -0
- package/dist/scanner/detectors/services/payments.js +185 -0
- package/dist/scanner/detectors/services/payments.js.map +1 -0
- package/dist/scanner/detectors/utils.d.ts +160 -0
- package/dist/scanner/detectors/utils.d.ts.map +1 -0
- package/dist/scanner/detectors/utils.js +222 -0
- package/dist/scanner/detectors/utils.js.map +1 -0
- package/dist/scanner/index.d.ts +42 -0
- package/dist/scanner/index.d.ts.map +1 -0
- package/dist/scanner/index.js +282 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/scanner/registry.d.ts +43 -0
- package/dist/scanner/registry.d.ts.map +1 -0
- package/dist/scanner/registry.js +243 -0
- package/dist/scanner/registry.js.map +1 -0
- package/dist/scanner/types.d.ts +112 -0
- package/dist/scanner/types.d.ts.map +1 -0
- package/dist/scanner/types.js +6 -0
- package/dist/scanner/types.js.map +1 -0
- package/dist/templates/config/ralph.config.js.tmpl +38 -0
- package/dist/templates/guides/AGENTS.md.tmpl +100 -0
- package/dist/templates/guides/FRONTEND.md.tmpl +523 -0
- package/dist/templates/guides/PERFORMANCE.md.tmpl +264 -0
- package/dist/templates/guides/SECURITY.md.tmpl +100 -0
- package/dist/templates/prompts/PROMPT.md.tmpl +77 -0
- package/dist/templates/prompts/PROMPT_e2e.md.tmpl +234 -0
- package/dist/templates/prompts/PROMPT_feature.md.tmpl +83 -0
- package/dist/templates/prompts/PROMPT_review.md.tmpl +167 -0
- package/dist/templates/prompts/PROMPT_verify.md.tmpl +72 -0
- package/dist/templates/root/.gitignore.tmpl +5 -0
- package/dist/templates/root/LEARNINGS.md.tmpl +24 -0
- package/dist/templates/root/README.md.tmpl +61 -0
- package/dist/templates/scripts/feature-loop.sh.tmpl +267 -0
- package/dist/templates/scripts/loop.sh.tmpl +59 -0
- package/dist/templates/scripts/ralph-monitor.sh.tmpl +244 -0
- package/dist/templates/specs/README.md.tmpl +57 -0
- package/dist/templates/specs/_example.md.tmpl +71 -0
- package/dist/utils/config.d.ts +95 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +148 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/header.d.ts +5 -0
- package/dist/utils/header.d.ts.map +1 -0
- package/dist/utils/header.js +15 -0
- package/dist/utils/header.js.map +1 -0
- package/dist/utils/logger.d.ts +11 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +24 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +44 -0
- package/src/ai/enhancer.ts +350 -0
- package/src/ai/index.ts +38 -0
- package/src/ai/prompts.ts +217 -0
- package/src/ai/providers.ts +136 -0
- package/src/cli.ts +255 -0
- package/src/commands/init.ts +149 -0
- package/src/commands/monitor.ts +412 -0
- package/src/commands/new.ts +312 -0
- package/src/commands/run.ts +214 -0
- package/src/generator/config.ts +116 -0
- package/src/generator/index.ts +227 -0
- package/src/generator/templates.ts +412 -0
- package/src/generator/writer.ts +293 -0
- package/src/index.ts +41 -0
- package/src/scanner/detectors/core/framework.ts +332 -0
- package/src/scanner/detectors/core/packageManager.ts +91 -0
- package/src/scanner/detectors/core/styling.ts +261 -0
- package/src/scanner/detectors/core/testing.ts +221 -0
- package/src/scanner/detectors/data/api.ts +303 -0
- package/src/scanner/detectors/data/database.ts +245 -0
- package/src/scanner/detectors/data/orm.ts +180 -0
- package/src/scanner/detectors/frontend/formHandling.ts +244 -0
- package/src/scanner/detectors/frontend/stateManagement.ts +261 -0
- package/src/scanner/detectors/frontend/uiComponents.ts +328 -0
- package/src/scanner/detectors/infra/deployment.ts +343 -0
- package/src/scanner/detectors/infra/monorepo.ts +251 -0
- package/src/scanner/detectors/mcp/mcpProject.ts +176 -0
- package/src/scanner/detectors/mcp/mcpServers.ts +237 -0
- package/src/scanner/detectors/services/analytics.ts +273 -0
- package/src/scanner/detectors/services/auth.ts +254 -0
- package/src/scanner/detectors/services/email.ts +244 -0
- package/src/scanner/detectors/services/payments.ts +213 -0
- package/src/scanner/detectors/utils.ts +251 -0
- package/src/scanner/index.ts +354 -0
- package/src/scanner/registry.ts +301 -0
- package/src/scanner/types.ts +152 -0
- package/src/templates/config/ralph.config.js.tmpl +38 -0
- package/src/templates/guides/AGENTS.md.tmpl +100 -0
- package/src/templates/guides/FRONTEND.md.tmpl +523 -0
- package/src/templates/guides/PERFORMANCE.md.tmpl +264 -0
- package/src/templates/guides/SECURITY.md.tmpl +100 -0
- package/src/templates/prompts/PROMPT.md.tmpl +77 -0
- package/src/templates/prompts/PROMPT_e2e.md.tmpl +234 -0
- package/src/templates/prompts/PROMPT_feature.md.tmpl +83 -0
- package/src/templates/prompts/PROMPT_review.md.tmpl +167 -0
- package/src/templates/prompts/PROMPT_verify.md.tmpl +72 -0
- package/src/templates/root/.gitignore.tmpl +5 -0
- package/src/templates/root/LEARNINGS.md.tmpl +24 -0
- package/src/templates/root/README.md.tmpl +61 -0
- package/src/templates/scripts/feature-loop.sh.tmpl +267 -0
- package/src/templates/scripts/loop.sh.tmpl +59 -0
- package/src/templates/scripts/ralph-monitor.sh.tmpl +244 -0
- package/src/templates/specs/README.md.tmpl +57 -0
- package/src/templates/specs/_example.md.tmpl +71 -0
- package/src/utils/config.ts +221 -0
- package/src/utils/header.ts +15 -0
- package/src/utils/logger.ts +28 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Pattern Detector
|
|
3
|
+
* Detects: tRPC, GraphQL, TanStack Query, REST patterns
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import type { Detector, DetectionResult } from '../../types.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Read and parse package.json from a directory
|
|
12
|
+
*/
|
|
13
|
+
function readPackageJson(projectRoot: string): Record<string, unknown> | null {
|
|
14
|
+
const packageJsonPath = join(projectRoot, 'package.json');
|
|
15
|
+
if (!existsSync(packageJsonPath)) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
const content = readFileSync(packageJsonPath, 'utf-8');
|
|
20
|
+
return JSON.parse(content);
|
|
21
|
+
} catch {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get all dependencies from package.json (deps + devDeps)
|
|
28
|
+
*/
|
|
29
|
+
function getDependencies(pkg: Record<string, unknown>): Record<string, string> {
|
|
30
|
+
const deps = (pkg.dependencies as Record<string, string>) || {};
|
|
31
|
+
const devDeps = (pkg.devDependencies as Record<string, string>) || {};
|
|
32
|
+
return { ...deps, ...devDeps };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Find all matching dependencies by pattern
|
|
37
|
+
*/
|
|
38
|
+
function findMatchingDeps(deps: Record<string, string>, pattern: string): string[] {
|
|
39
|
+
return Object.keys(deps).filter(name => name.startsWith(pattern) || name === pattern);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Detect tRPC
|
|
44
|
+
*/
|
|
45
|
+
function detectTRPC(projectRoot: string, deps: Record<string, string>): DetectionResult | null {
|
|
46
|
+
const evidence: string[] = [];
|
|
47
|
+
let confidence = 0;
|
|
48
|
+
|
|
49
|
+
// Check for @trpc/* packages
|
|
50
|
+
const trpcPackages = findMatchingDeps(deps, '@trpc/');
|
|
51
|
+
if (trpcPackages.length > 0) {
|
|
52
|
+
const mainVersion = deps['@trpc/server'] || deps['@trpc/client'];
|
|
53
|
+
evidence.push(`tRPC packages found: ${trpcPackages.join(', ')}`);
|
|
54
|
+
confidence += 70;
|
|
55
|
+
|
|
56
|
+
// Check for specific packages
|
|
57
|
+
if (deps['@trpc/server'] && deps['@trpc/client']) {
|
|
58
|
+
confidence += 20;
|
|
59
|
+
}
|
|
60
|
+
if (deps['@trpc/react-query'] || deps['@trpc/next']) {
|
|
61
|
+
evidence.push('tRPC React/Next integration detected');
|
|
62
|
+
confidence += 10;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
name: 'tRPC',
|
|
67
|
+
version: mainVersion,
|
|
68
|
+
confidence: Math.min(confidence, 100),
|
|
69
|
+
evidence,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Detect GraphQL
|
|
78
|
+
*/
|
|
79
|
+
function detectGraphQL(projectRoot: string, deps: Record<string, string>): DetectionResult | null {
|
|
80
|
+
const evidence: string[] = [];
|
|
81
|
+
let confidence = 0;
|
|
82
|
+
|
|
83
|
+
// Check for graphql package
|
|
84
|
+
if (deps.graphql) {
|
|
85
|
+
evidence.push(`graphql@${deps.graphql} in dependencies`);
|
|
86
|
+
confidence += 40;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Check for Apollo packages
|
|
90
|
+
const apolloPackages = findMatchingDeps(deps, '@apollo/');
|
|
91
|
+
if (apolloPackages.length > 0) {
|
|
92
|
+
evidence.push(`Apollo packages found: ${apolloPackages.join(', ')}`);
|
|
93
|
+
confidence += 40;
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
name: 'GraphQL',
|
|
97
|
+
version: deps.graphql,
|
|
98
|
+
variant: 'apollo',
|
|
99
|
+
confidence: Math.min(confidence, 100),
|
|
100
|
+
evidence,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Check for urql
|
|
105
|
+
if (deps.urql || deps['@urql/core']) {
|
|
106
|
+
evidence.push('urql client detected');
|
|
107
|
+
confidence += 40;
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
name: 'GraphQL',
|
|
111
|
+
version: deps.graphql,
|
|
112
|
+
variant: 'urql',
|
|
113
|
+
confidence: Math.min(confidence, 100),
|
|
114
|
+
evidence,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Check for relay
|
|
119
|
+
if (deps['react-relay'] || deps['relay-runtime']) {
|
|
120
|
+
evidence.push('Relay detected');
|
|
121
|
+
confidence += 40;
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
name: 'GraphQL',
|
|
125
|
+
version: deps.graphql,
|
|
126
|
+
variant: 'relay',
|
|
127
|
+
confidence: Math.min(confidence, 100),
|
|
128
|
+
evidence,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Check for schema files
|
|
133
|
+
const schemaFiles = ['schema.graphql', 'schema.gql'];
|
|
134
|
+
for (const file of schemaFiles) {
|
|
135
|
+
if (existsSync(join(projectRoot, file))) {
|
|
136
|
+
evidence.push(`${file} found`);
|
|
137
|
+
confidence += 20;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (confidence === 0) return null;
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
name: 'GraphQL',
|
|
145
|
+
version: deps.graphql,
|
|
146
|
+
confidence: Math.min(confidence, 100),
|
|
147
|
+
evidence,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Detect TanStack Query (React Query, Vue Query)
|
|
153
|
+
*/
|
|
154
|
+
function detectTanStackQuery(projectRoot: string, deps: Record<string, string>): DetectionResult | null {
|
|
155
|
+
const evidence: string[] = [];
|
|
156
|
+
let confidence = 0;
|
|
157
|
+
let variant: string | undefined;
|
|
158
|
+
|
|
159
|
+
// Check for @tanstack/react-query
|
|
160
|
+
if (deps['@tanstack/react-query']) {
|
|
161
|
+
evidence.push(`@tanstack/react-query@${deps['@tanstack/react-query']} in dependencies`);
|
|
162
|
+
confidence += 80;
|
|
163
|
+
variant = 'react';
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Check for @tanstack/vue-query
|
|
167
|
+
if (deps['@tanstack/vue-query']) {
|
|
168
|
+
evidence.push(`@tanstack/vue-query@${deps['@tanstack/vue-query']} in dependencies`);
|
|
169
|
+
confidence += 80;
|
|
170
|
+
variant = 'vue';
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Check for @tanstack/svelte-query
|
|
174
|
+
if (deps['@tanstack/svelte-query']) {
|
|
175
|
+
evidence.push(`@tanstack/svelte-query@${deps['@tanstack/svelte-query']} in dependencies`);
|
|
176
|
+
confidence += 80;
|
|
177
|
+
variant = 'svelte';
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Check for old react-query package (v3)
|
|
181
|
+
if (deps['react-query']) {
|
|
182
|
+
evidence.push(`react-query@${deps['react-query']} in dependencies (legacy)`);
|
|
183
|
+
confidence += 70;
|
|
184
|
+
variant = 'react-legacy';
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Check for devtools
|
|
188
|
+
if (deps['@tanstack/react-query-devtools'] || deps['@tanstack/vue-query-devtools']) {
|
|
189
|
+
evidence.push('TanStack Query devtools detected');
|
|
190
|
+
confidence += 10;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (confidence === 0) return null;
|
|
194
|
+
|
|
195
|
+
const version = deps['@tanstack/react-query'] || deps['@tanstack/vue-query'] ||
|
|
196
|
+
deps['@tanstack/svelte-query'] || deps['react-query'];
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
name: 'TanStack Query',
|
|
200
|
+
version,
|
|
201
|
+
variant,
|
|
202
|
+
confidence: Math.min(confidence, 100),
|
|
203
|
+
evidence,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Detect REST patterns (axios, fetch wrappers)
|
|
209
|
+
*/
|
|
210
|
+
function detectREST(projectRoot: string, deps: Record<string, string>): DetectionResult | null {
|
|
211
|
+
const evidence: string[] = [];
|
|
212
|
+
let confidence = 0;
|
|
213
|
+
let variant: string | undefined;
|
|
214
|
+
|
|
215
|
+
// Check for axios
|
|
216
|
+
if (deps.axios) {
|
|
217
|
+
evidence.push(`axios@${deps.axios} in dependencies`);
|
|
218
|
+
confidence += 60;
|
|
219
|
+
variant = 'axios';
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Check for ky (modern fetch wrapper)
|
|
223
|
+
if (deps.ky) {
|
|
224
|
+
evidence.push(`ky@${deps.ky} in dependencies`);
|
|
225
|
+
confidence += 60;
|
|
226
|
+
variant = 'ky';
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Check for got (Node.js HTTP client)
|
|
230
|
+
if (deps.got) {
|
|
231
|
+
evidence.push(`got@${deps.got} in dependencies`);
|
|
232
|
+
confidence += 50;
|
|
233
|
+
variant = 'got';
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Check for node-fetch
|
|
237
|
+
if (deps['node-fetch']) {
|
|
238
|
+
evidence.push(`node-fetch@${deps['node-fetch']} in dependencies`);
|
|
239
|
+
confidence += 40;
|
|
240
|
+
variant = 'node-fetch';
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Check for SWR (while not strictly REST, often used with REST)
|
|
244
|
+
if (deps.swr) {
|
|
245
|
+
evidence.push(`swr@${deps.swr} in dependencies`);
|
|
246
|
+
confidence += 50;
|
|
247
|
+
variant = 'swr';
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (confidence === 0) return null;
|
|
251
|
+
|
|
252
|
+
return {
|
|
253
|
+
name: 'REST',
|
|
254
|
+
version: deps.axios || deps.ky || deps.got || deps['node-fetch'] || deps.swr,
|
|
255
|
+
variant,
|
|
256
|
+
confidence: Math.min(confidence, 100),
|
|
257
|
+
evidence,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* API pattern detector
|
|
263
|
+
* Returns all detected API patterns
|
|
264
|
+
*/
|
|
265
|
+
export const apiDetector: Detector = {
|
|
266
|
+
category: 'api',
|
|
267
|
+
name: 'API Pattern Detector',
|
|
268
|
+
|
|
269
|
+
async detect(projectRoot: string): Promise<DetectionResult[] | null> {
|
|
270
|
+
const pkg = readPackageJson(projectRoot);
|
|
271
|
+
if (!pkg) {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const deps = getDependencies(pkg);
|
|
276
|
+
const results: DetectionResult[] = [];
|
|
277
|
+
|
|
278
|
+
// Detect all API patterns (project can use multiple)
|
|
279
|
+
const trpc = detectTRPC(projectRoot, deps);
|
|
280
|
+
if (trpc && trpc.confidence >= 40) {
|
|
281
|
+
results.push(trpc);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const graphql = detectGraphQL(projectRoot, deps);
|
|
285
|
+
if (graphql && graphql.confidence >= 40) {
|
|
286
|
+
results.push(graphql);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const tanstack = detectTanStackQuery(projectRoot, deps);
|
|
290
|
+
if (tanstack && tanstack.confidence >= 40) {
|
|
291
|
+
results.push(tanstack);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const rest = detectREST(projectRoot, deps);
|
|
295
|
+
if (rest && rest.confidence >= 40) {
|
|
296
|
+
results.push(rest);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return results.length > 0 ? results : null;
|
|
300
|
+
},
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
export default apiDetector;
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Detector
|
|
3
|
+
* Detects databases: Supabase, Firebase, MongoDB, PostgreSQL
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import type { Detector, DetectionResult } from '../../types.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Read and parse package.json from a directory
|
|
12
|
+
*/
|
|
13
|
+
function readPackageJson(projectRoot: string): Record<string, unknown> | null {
|
|
14
|
+
const packageJsonPath = join(projectRoot, 'package.json');
|
|
15
|
+
if (!existsSync(packageJsonPath)) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
const content = readFileSync(packageJsonPath, 'utf-8');
|
|
20
|
+
return JSON.parse(content);
|
|
21
|
+
} catch {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get all dependencies from package.json (deps + devDeps)
|
|
28
|
+
*/
|
|
29
|
+
function getDependencies(pkg: Record<string, unknown>): Record<string, string> {
|
|
30
|
+
const deps = (pkg.dependencies as Record<string, string>) || {};
|
|
31
|
+
const devDeps = (pkg.devDependencies as Record<string, string>) || {};
|
|
32
|
+
return { ...deps, ...devDeps };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Check if any dependency matches a pattern
|
|
37
|
+
*/
|
|
38
|
+
function hasDependencyPattern(deps: Record<string, string>, pattern: string): string | undefined {
|
|
39
|
+
for (const [name, version] of Object.entries(deps)) {
|
|
40
|
+
if (name.startsWith(pattern) || name === pattern) {
|
|
41
|
+
return version;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Find all matching dependencies by pattern
|
|
49
|
+
*/
|
|
50
|
+
function findMatchingDeps(deps: Record<string, string>, pattern: string): string[] {
|
|
51
|
+
return Object.keys(deps).filter(name => name.startsWith(pattern) || name === pattern);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Detect Supabase
|
|
56
|
+
*/
|
|
57
|
+
function detectSupabase(projectRoot: string, deps: Record<string, string>): DetectionResult | null {
|
|
58
|
+
const evidence: string[] = [];
|
|
59
|
+
let confidence = 0;
|
|
60
|
+
|
|
61
|
+
// Check for @supabase/* packages
|
|
62
|
+
if (deps['@supabase/supabase-js']) {
|
|
63
|
+
evidence.push(`@supabase/supabase-js@${deps['@supabase/supabase-js']} in dependencies`);
|
|
64
|
+
confidence += 70;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const supabasePackages = findMatchingDeps(deps, '@supabase/');
|
|
68
|
+
if (supabasePackages.length > 1) {
|
|
69
|
+
evidence.push(`Multiple @supabase packages found: ${supabasePackages.join(', ')}`);
|
|
70
|
+
confidence += 10;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Check for supabase directory
|
|
74
|
+
const supabaseDir = join(projectRoot, 'supabase');
|
|
75
|
+
if (existsSync(supabaseDir)) {
|
|
76
|
+
evidence.push('supabase/ directory found');
|
|
77
|
+
confidence += 20;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Check for supabase config
|
|
81
|
+
const configPath = join(supabaseDir, 'config.toml');
|
|
82
|
+
if (existsSync(configPath)) {
|
|
83
|
+
evidence.push('supabase/config.toml found');
|
|
84
|
+
confidence += 10;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (confidence === 0) return null;
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
name: 'Supabase',
|
|
91
|
+
version: deps['@supabase/supabase-js'],
|
|
92
|
+
confidence: Math.min(confidence, 100),
|
|
93
|
+
evidence,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Detect Firebase
|
|
99
|
+
*/
|
|
100
|
+
function detectFirebase(projectRoot: string, deps: Record<string, string>): DetectionResult | null {
|
|
101
|
+
const evidence: string[] = [];
|
|
102
|
+
let confidence = 0;
|
|
103
|
+
|
|
104
|
+
// Check for firebase package
|
|
105
|
+
if (deps.firebase) {
|
|
106
|
+
evidence.push(`firebase@${deps.firebase} in dependencies`);
|
|
107
|
+
confidence += 70;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Check for @firebase/* packages
|
|
111
|
+
const firebasePackages = findMatchingDeps(deps, '@firebase/');
|
|
112
|
+
if (firebasePackages.length > 0) {
|
|
113
|
+
evidence.push(`Firebase packages found: ${firebasePackages.slice(0, 3).join(', ')}${firebasePackages.length > 3 ? '...' : ''}`);
|
|
114
|
+
confidence += 20;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Check for firebase admin
|
|
118
|
+
if (deps['firebase-admin']) {
|
|
119
|
+
evidence.push(`firebase-admin@${deps['firebase-admin']} in dependencies`);
|
|
120
|
+
confidence += 20;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Check for firebase.json config
|
|
124
|
+
const firebaseConfig = join(projectRoot, 'firebase.json');
|
|
125
|
+
if (existsSync(firebaseConfig)) {
|
|
126
|
+
evidence.push('firebase.json found');
|
|
127
|
+
confidence += 10;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (confidence === 0) return null;
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
name: 'Firebase',
|
|
134
|
+
version: deps.firebase || deps['firebase-admin'],
|
|
135
|
+
confidence: Math.min(confidence, 100),
|
|
136
|
+
evidence,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Detect MongoDB (via mongoose or mongodb driver)
|
|
142
|
+
*/
|
|
143
|
+
function detectMongoDB(projectRoot: string, deps: Record<string, string>): DetectionResult | null {
|
|
144
|
+
const evidence: string[] = [];
|
|
145
|
+
let confidence = 0;
|
|
146
|
+
|
|
147
|
+
// Check for mongoose (ODM)
|
|
148
|
+
if (deps.mongoose) {
|
|
149
|
+
evidence.push(`mongoose@${deps.mongoose} in dependencies`);
|
|
150
|
+
confidence += 80;
|
|
151
|
+
return {
|
|
152
|
+
name: 'MongoDB',
|
|
153
|
+
version: deps.mongoose,
|
|
154
|
+
variant: 'mongoose',
|
|
155
|
+
confidence: Math.min(confidence, 100),
|
|
156
|
+
evidence,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Check for native mongodb driver
|
|
161
|
+
if (deps.mongodb) {
|
|
162
|
+
evidence.push(`mongodb@${deps.mongodb} in dependencies`);
|
|
163
|
+
confidence += 80;
|
|
164
|
+
return {
|
|
165
|
+
name: 'MongoDB',
|
|
166
|
+
version: deps.mongodb,
|
|
167
|
+
variant: 'native-driver',
|
|
168
|
+
confidence: Math.min(confidence, 100),
|
|
169
|
+
evidence,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Detect PostgreSQL
|
|
178
|
+
*/
|
|
179
|
+
function detectPostgreSQL(projectRoot: string, deps: Record<string, string>): DetectionResult | null {
|
|
180
|
+
const evidence: string[] = [];
|
|
181
|
+
let confidence = 0;
|
|
182
|
+
|
|
183
|
+
// Check for pg (node-postgres)
|
|
184
|
+
if (deps.pg) {
|
|
185
|
+
evidence.push(`pg@${deps.pg} in dependencies`);
|
|
186
|
+
confidence += 70;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Check for postgres (modern driver)
|
|
190
|
+
if (deps.postgres) {
|
|
191
|
+
evidence.push(`postgres@${deps.postgres} in dependencies`);
|
|
192
|
+
confidence += 70;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Note: Supabase and Prisma also use Postgres, but they're separate categories
|
|
196
|
+
// This detector is for direct Postgres usage
|
|
197
|
+
|
|
198
|
+
if (confidence === 0) return null;
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
name: 'PostgreSQL',
|
|
202
|
+
version: deps.pg || deps.postgres,
|
|
203
|
+
variant: deps.pg ? 'node-postgres' : 'postgres.js',
|
|
204
|
+
confidence: Math.min(confidence, 100),
|
|
205
|
+
evidence,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Database detector
|
|
211
|
+
* Returns the primary database detected
|
|
212
|
+
*/
|
|
213
|
+
export const databaseDetector: Detector = {
|
|
214
|
+
category: 'database',
|
|
215
|
+
name: 'Database Detector',
|
|
216
|
+
|
|
217
|
+
async detect(projectRoot: string): Promise<DetectionResult | null> {
|
|
218
|
+
const pkg = readPackageJson(projectRoot);
|
|
219
|
+
if (!pkg) {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const deps = getDependencies(pkg);
|
|
224
|
+
|
|
225
|
+
// Priority: Supabase > Firebase > MongoDB > PostgreSQL
|
|
226
|
+
// (BaaS solutions take precedence as they encompass more)
|
|
227
|
+
const detectors = [
|
|
228
|
+
() => detectSupabase(projectRoot, deps),
|
|
229
|
+
() => detectFirebase(projectRoot, deps),
|
|
230
|
+
() => detectMongoDB(projectRoot, deps),
|
|
231
|
+
() => detectPostgreSQL(projectRoot, deps),
|
|
232
|
+
];
|
|
233
|
+
|
|
234
|
+
for (const detector of detectors) {
|
|
235
|
+
const result = detector();
|
|
236
|
+
if (result && result.confidence >= 40) {
|
|
237
|
+
return result;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return null;
|
|
242
|
+
},
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
export default databaseDetector;
|